Merge branch 'renesas-drivers-2016-01-19-v4.4/dts-rcar-gen3' into v4.4/rcar-3.2.x

* renesas-drivers-2016-01-19-v4.4/dts-rcar-gen3: (78 commits)
  arm64: renesas: r8a7795: Use polling mode for thermal driver
  arm64: dts: r8a7795: Add UHS-I(SDR104) support
  arm64: dts: r8a7795: Delete IO voltate setting
  arm64: dts: salvator-x: Add a voltage setting of MMC by pinctrl
  arm64: dts: salvator-x: Add a voltage setting of SDHI by pinctrl
  arm64: dts: salvator-x: Add restrictions of 100Mbps for H3 WS1.1 EthernetAVB
  arm64: renesas: r8a7795: Add sustainable-power for thermal zone 0 & 1
  arm64: renesas: r8a7795: Create thermal zone to support IPA
  arm64: renesas: r8a7795: Add cpu-supply to regulator node
  arm64: renesas: salvator-x: Add regulator for DVFS
  arm64: renesas: salvator-x: Enable I2C for DVFS device
  arm64: renesas: r8a7795: Add I2C for DVFS core to dtsi
  arm64: renesas: r8a7795: Add OPPs table for cpu devices
  arm64: dts: r8a7795: Fix iVDP1C and VCP4 node
  arm64: dts: salvator-x: enable usb3.0 host channel 0
  arm64: dts: r8a7795: Add USB3.0 host device nodes
  arm64: dts: r8a7795: add HS-USB device node
  arm64: dts: r8a7795: add usb2_phy device nodes
  arm64: dts: salvator-x: Add programmable clock generator node
  arm64: dts: salvator-x: Add eMMC support to 8-bit bus width
  arm64: dts: r8a7795: Add eMMC support to 8-bit bus width
  arm64: dts: r8a7795: Fix the power domain of VSP node
  arm64: dts: salvator-x: Add VSPM I/F driver node
  arm64: dts: salvator-x: Add MMNGR driver node
  arm64: dts: salvator-x: Add ADSP support
  arm64: dts: r8a7795: Add ADSP node
  arm64: dts: r8a7795: Add iVDP1C node
  arm64: dts: r8a7795: Add VCP4 node
  arm64: dts: r8a7795: Add FDP1 node
  arm64: dts: r8a7795: Convert VSP Driver into VSP Manager
  ...
diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt
index 9dafe6b..619193c 100644
--- a/Documentation/devicetree/bindings/media/rcar_vin.txt
+++ b/Documentation/devicetree/bindings/media/rcar_vin.txt
@@ -6,6 +6,7 @@
 channel which can be either RGB, YUYV or BT656.
 
  - compatible: Must be one of the following
+   - "renesas,vin-r8a7795" for the R8A7795 device
    - "renesas,vin-r8a7794" for the R8A7794 device
    - "renesas,vin-r8a7793" for the R8A7793 device
    - "renesas,vin-r8a7791" for the R8A7791 device
diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index 400b640..d9b3d11 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -22,6 +22,8 @@
 		"renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
 		"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
 		"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
+		"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
+		"renesas,mmc-r8a7795" - MMC IP on R8A7795 SoC
 
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
index 2390e4e..eaf7e9b 100644
--- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
+++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
@@ -7,33 +7,26 @@
 - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
 	      SoC.
 - reg: offset and length of the partial USB 2.0 Host register block.
-- reg-names: must be "usb2_host".
 - clocks: clock phandle and specifier pair(s).
 - #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
 
 Optional properties:
 To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
-combined, the device tree node should set HSUSB properties to reg and reg-names
-properties. This is because HSUSB has registers to select USB 2.0 host or
-peripheral at that channel:
-- reg: offset and length of the partial HSUSB register block.
-- reg-names: must be "hsusb".
+combined, the device tree node should set interrupt properties to use the
+channel as USB OTG:
 - interrupts: interrupt specifier for the PHY.
 
 Example (R-Car H3):
 
 	usb-phy@ee080200 {
 		compatible = "renesas,usb2-phy-r8a7795";
-		reg = <0 0xee080200 0 0x700>, <0 0xe6590100 0 0x100>;
-		reg-names = "usb2_host", "hsusb";
+		reg = <0 0xee080200 0 0x700>;
 		interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp7_clks R8A7795_CLK_EHCI0>,
-			 <&mstp7_clks R8A7795_CLK_HSUSB>;
+		clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
 	};
 
 	usb-phy@ee0a0200 {
 		compatible = "renesas,usb2-phy-r8a7795";
 		reg = <0 0xee0a0200 0 0x700>;
-		reg-names = "usb2_host";
 		clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
 	};
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index aa005c1..e4ba96c 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -10,6 +10,7 @@
 			 "renesas,msiof-r8a7792" (R-Car V2H)
 			 "renesas,msiof-r8a7793" (R-Car M2-N)
 			 "renesas,msiof-r8a7794" (R-Car E2)
+			 "renesas,msiof-r8a7795" (R-Car H3)
 			 "renesas,msiof-sh73a0" (SH-Mobile AG5)
 - reg                  : A list of offsets and lengths of the register sets for
 			 the device.
diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
new file mode 100644
index 0000000..f5c9430
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
@@ -0,0 +1,48 @@
+* Renesas R-Car Gen3 Thermal
+
+Required properties:
+- compatible		: "renesas,thermal-<soctype>",
+			   "renesas,rcar-gen3-thermal" (with thermal-zone always)
+			  Examples with soctypes are:
+			    - "renesas,thermal-r8a7795" (R-Car H3)
+- reg			: Address range of the thermal registers.
+- #thermal-sensor-cells : Please see ./thermal.txt
+
+Option properties:
+
+- interrupts		: use interrupt
+
+Example (non interrupt support):
+
+thermal: thermal@0xe6198000 {
+                        compatible = "renesas,thermal-r8a7795",
+                                "renesas,rcar-gen3-thermal",
+                        reg = <0 0xe6198000 0 0x5c>;
+                };
+
+thermal-zones {
+	cpu_thermal: cpu-thermal {
+		polling-delay-passive	= <250>;
+		polling-delay		= <1000>;
+
+		thermal-sensors = <&thermal>;
+	};
+};
+
+Example (interrupt support):
+
+thermal: thermal@0xe6198000 {
+                        compatible = "renesas,thermal-r8a7795",
+                                "renesas,rcar-gen3-thermal",
+                        reg = <0 0xe6198000 0 0x5c>;
+			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                };
+
+thermal-zones {
+	cpu_thermal: cpu-thermal {
+		polling-delay-passive	= <250>;
+		polling-delay		= <0>;
+
+		thermal-sensors = <&thermal>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/watchdog/renesas-rwdt.txt b/Documentation/devicetree/bindings/watchdog/renesas-rwdt.txt
new file mode 100644
index 0000000..fd050d5
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/renesas-rwdt.txt
@@ -0,0 +1,18 @@
+Renesas RCLK Watchdog Timer (RWDT) Controller
+
+Required properties:
+- compatible : Should be "renesas,rwdt-r8a7795";
+- reg : Should contain WDT registers location and length
+- clocks : the clock feeding the watchdog timer.
+
+Optional properties:
+- timeout-sec : Contains the watchdog timeout in seconds
+
+Examples:
+
+	wdt0: wdt@e6020000 {
+		compatible = "renesas,rwdt-r8a7795";
+		reg = <0 0xe6020000 0 0x0c>;
+		clocks = <&cpg CPG_MOD 402>;
+		timeout-sec = <60>;
+	};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 18ca9fb..671ab54 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -54,8 +54,8 @@
 CONFIG_ARCH_ZYNQMP=y
 CONFIG_PCI=y
 CONFIG_PCI_MSI=y
-CONFIG_PCI_HOST_GENERIC=y
-CONFIG_PCI_XGENE=y
+# CONFIG_PCI_RCAR_GEN2 is not set
+CONFIG_PCI_RCAR_GEN2_PCIE=y
 CONFIG_SMP=y
 CONFIG_SCHED_MC=y
 CONFIG_PREEMPT=y
@@ -67,6 +67,13 @@
 CONFIG_COMPAT=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -135,21 +142,50 @@
 CONFIG_VIRTIO_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
 CONFIG_I2C_RCAR=y
+CONFIG_I2C_SH_MOBILE=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
+CONFIG_SPI_SH_MSIOF=y
+CONFIG_SPI_SPIDEV=y
 CONFIG_SPI_QUP=y
 CONFIG_PINCTRL_MSM8916=y
 CONFIG_GPIO_PL061=y
 CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_XGENE=y
+CONFIG_POWER_AVS=y
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
+CONFIG_RCAR_GEN3_THERMAL=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_BD9571MWV=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_QCOM_SMD_RPM=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_PLATFORM=y
+CONFIG_VIDEO_RCAR_VIN=y
+CONFIG_VIDEO_RCAR_CSI2=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_RENESAS_VSP1=y
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7482=y
+CONFIG_DRM=y
+CONFIG_DRM_RCAR_DU=y
+CONFIG_DRM_RCAR_HDMI=y
+CONFIG_DRM_RCAR_LVDS=y
+CONFIG_DRM_RCAR_VSP=y
 CONFIG_FB=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -175,6 +211,8 @@
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SPI=y
+CONFIG_MMC_TMIO_CORE=y
+CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_IDMAC=y
 CONFIG_MMC_DW_PLTFM=y
@@ -195,14 +233,20 @@
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
 CONFIG_VIRTIO_MMIO=y
+CONFIG_STAGING=y
+CONFIG_STAGING_BOARD=y
 CONFIG_COMMON_CLK_CS2000_CP=y
+CONFIG_COMMON_CLK_5P49V5923A=y
 CONFIG_COMMON_CLK_QCOM=y
 CONFIG_MSM_GCC_8916=y
 CONFIG_HWSPINLOCK_QCOM=y
 # CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PWM=y
+CONFIG_PWM_RCAR=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
+CONFIG_PHY_RCAR_GEN3_USB2=y
 CONFIG_PHY_XGENE=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 93ed14c..f6a9ad5 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -146,7 +146,7 @@
 	if (dev->pm_domain == pd)
 		return;
 
-	WARN(device_is_bound(dev),
+	WARN(pd && device_is_bound(dev),
 	     "PM domains can only be changed for unbound devices\n");
 	dev->pm_domain = pd;
 	device_pm_check_callbacks(dev);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index ee54e84..3fb04c3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1690,100 +1690,63 @@
 EXPORT_SYMBOL_GPL(regmap_raw_write);
 
 /**
- * regmap_field_write(): Write a value to a single register field
- *
- * @field: Register field to write to
- * @val: Value to be written
- *
- * A value of zero will be returned on success, a negative errno will
- * be returned in error cases.
- */
-int regmap_field_write(struct regmap_field *field, unsigned int val)
-{
-	return regmap_update_bits(field->regmap, field->reg,
-				field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_field_write);
-
-/**
- * regmap_field_update_bits():	Perform a read/modify/write cycle
- *                              on the register field
+ * regmap_field_update_bits_base():
+ *	Perform a read/modify/write cycle on the register field
+ *	with change, async, force option
  *
  * @field: Register field to write to
  * @mask: Bitmask to change
  * @val: Value to be written
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
  *
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
  */
-int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val)
+int regmap_field_update_bits_base(struct regmap_field *field,
+				  unsigned int mask, unsigned int val,
+				  bool *change, bool async, bool force)
 {
 	mask = (mask << field->shift) & field->mask;
 
-	return regmap_update_bits(field->regmap, field->reg,
-				  mask, val << field->shift);
+	return regmap_update_bits_base(field->regmap, field->reg,
+				       mask, val << field->shift,
+				       change, async, force);
 }
-EXPORT_SYMBOL_GPL(regmap_field_update_bits);
+EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
 
 /**
- * regmap_fields_write(): Write a value to a single register field with port ID
- *
- * @field: Register field to write to
- * @id: port ID
- * @val: Value to be written
- *
- * A value of zero will be returned on success, a negative errno will
- * be returned in error cases.
- */
-int regmap_fields_write(struct regmap_field *field, unsigned int id,
-			unsigned int val)
-{
-	if (id >= field->id_size)
-		return -EINVAL;
-
-	return regmap_update_bits(field->regmap,
-				  field->reg + (field->id_offset * id),
-				  field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_fields_write);
-
-int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
-			unsigned int val)
-{
-	if (id >= field->id_size)
-		return -EINVAL;
-
-	return regmap_write_bits(field->regmap,
-				  field->reg + (field->id_offset * id),
-				  field->mask, val << field->shift);
-}
-EXPORT_SYMBOL_GPL(regmap_fields_force_write);
-
-/**
- * regmap_fields_update_bits():	Perform a read/modify/write cycle
- *                              on the register field
+ * regmap_fields_update_bits_base():
+ *	Perform a read/modify/write cycle on the register field
+ *	with change, async, force option
  *
  * @field: Register field to write to
  * @id: port ID
  * @mask: Bitmask to change
  * @val: Value to be written
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
  *
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
  */
-int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
-			      unsigned int mask, unsigned int val)
+int regmap_fields_update_bits_base(struct regmap_field *field,  unsigned int id,
+				   unsigned int mask, unsigned int val,
+				   bool *change, bool async, bool force)
 {
 	if (id >= field->id_size)
 		return -EINVAL;
 
 	mask = (mask << field->shift) & field->mask;
 
-	return regmap_update_bits(field->regmap,
-				  field->reg + (field->id_offset * id),
-				  mask, val << field->shift);
+	return regmap_update_bits_base(field->regmap,
+				       field->reg + (field->id_offset * id),
+				       mask, val << field->shift,
+				       change, async, force);
 }
-EXPORT_SYMBOL_GPL(regmap_fields_update_bits);
+EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base);
 
 /*
  * regmap_bulk_write(): Write multiple registers to the device
@@ -2648,76 +2611,36 @@
 }
 
 /**
- * regmap_update_bits: Perform a read/modify/write cycle on the register map
+ * regmap_update_bits_base:
+ *	Perform a read/modify/write cycle on the
+ *	register map with change, async, force option
  *
  * @map: Register map to update
  * @reg: Register to update
  * @mask: Bitmask to change
  * @val: New value for bitmask
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
  *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits(struct regmap *map, unsigned int reg,
-		       unsigned int mask, unsigned int val)
-{
-	int ret;
-
-	map->lock(map->lock_arg);
-	ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
-	map->unlock(map->lock_arg);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits);
-
-/**
- * regmap_write_bits: Perform a read/modify/write cycle on the register map
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_write_bits(struct regmap *map, unsigned int reg,
-		      unsigned int mask, unsigned int val)
-{
-	int ret;
-
-	map->lock(map->lock_arg);
-	ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
-	map->unlock(map->lock_arg);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_write_bits);
-
-/**
- * regmap_update_bits_async: Perform a read/modify/write cycle on the register
- *                           map asynchronously
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- *
+ * if async was true,
  * With most buses the read must be done synchronously so this is most
  * useful for devices with a cache which do not need to interact with
  * the hardware to determine the current register value.
  *
  * Returns zero for success, a negative number on error.
  */
-int regmap_update_bits_async(struct regmap *map, unsigned int reg,
-			     unsigned int mask, unsigned int val)
+int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+			    unsigned int mask, unsigned int val,
+			    bool *change, bool async, bool force)
 {
 	int ret;
 
 	map->lock(map->lock_arg);
 
-	map->async = true;
+	map->async = async;
 
-	ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
+	ret = _regmap_update_bits(map, reg, mask, val, change, force);
 
 	map->async = false;
 
@@ -2725,69 +2648,7 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(regmap_update_bits_async);
-
-/**
- * regmap_update_bits_check: Perform a read/modify/write cycle on the
- *                           register map and report if updated
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- * @change: Boolean indicating if a write was done
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits_check(struct regmap *map, unsigned int reg,
-			     unsigned int mask, unsigned int val,
-			     bool *change)
-{
-	int ret;
-
-	map->lock(map->lock_arg);
-	ret = _regmap_update_bits(map, reg, mask, val, change, false);
-	map->unlock(map->lock_arg);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits_check);
-
-/**
- * regmap_update_bits_check_async: Perform a read/modify/write cycle on the
- *                                 register map asynchronously and report if
- *                                 updated
- *
- * @map: Register map to update
- * @reg: Register to update
- * @mask: Bitmask to change
- * @val: New value for bitmask
- * @change: Boolean indicating if a write was done
- *
- * With most buses the read must be done synchronously so this is most
- * useful for devices with a cache which do not need to interact with
- * the hardware to determine the current register value.
- *
- * Returns zero for success, a negative number on error.
- */
-int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
-				   unsigned int mask, unsigned int val,
-				   bool *change)
-{
-	int ret;
-
-	map->lock(map->lock_arg);
-
-	map->async = true;
-
-	ret = _regmap_update_bits(map, reg, mask, val, change, false);
-
-	map->async = false;
-
-	map->unlock(map->lock_arg);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regmap_update_bits_check_async);
+EXPORT_SYMBOL_GPL(regmap_update_bits_base);
 
 void regmap_async_complete_cb(struct regmap_async *async, int ret)
 {
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index eca8e01..346c068 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -187,6 +187,13 @@
 	  Adapter driver so that any PWM output can be (mis)used as clock signal
 	  at 50% duty cycle.
 
+config COMMON_CLK_5P49V5923A
+	tristate "Clock driver for 5P49V5923A programmable clock generator"
+	depends on I2C
+	help
+	  If you say yes here you get support for the 5P49V5923A programmable
+	  clock generator.
+
 config COMMON_CLK_PXA
 	def_bool COMMON_CLK && ARCH_PXA
 	---help---
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b038e36..15722ff 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -17,6 +17,7 @@
 
 # hardware specific clock types
 # please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_COMMON_CLK_5P49V5923A)	+= clk-5p49v5923a.o
 obj-$(CONFIG_MACH_ASM9260)		+= clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
diff --git a/drivers/clk/clk-5p49v5923a.c b/drivers/clk/clk-5p49v5923a.c
new file mode 100644
index 0000000..684d544
--- /dev/null
+++ b/drivers/clk/clk-5p49v5923a.c
@@ -0,0 +1,331 @@
+/*
+ * drivers/gpu/drm/i2c/5p49v5923a.c
+ *     This file is programmable clock generator driver.
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * This file is based on the drivers/clk/clk-cs2000-cp.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/module.h>
+
+#define REF_CLK		1
+#define CLK_MAX		5
+
+#define INPUT_CLK	25000000
+
+#define C5P49_FB_INT_DIV_REG1	0x17
+#define C5P49_FB_INT_DIV_REG0	0x18
+
+/* offset address*/
+#define C5P49_DIV_FRAC_29_22	0x02
+#define C5P49_DIV_FRAC_21_14	0x03
+#define C5P49_DIV_FRAC_13_6	0x04
+#define C5P49_DIV_FRAC_5_0	0x05
+#define C5P49_DIV_INTEGER_11_4	0x0d
+#define C5P49_DIV_INTEGER_3_0	0x0e
+
+#define C5P49_CLK_OE_SHUTDOWN	0x68
+
+#define hw_to_priv(_hw)		container_of(_hw, struct clk_5p49_priv, hw)
+#define priv_to_client(priv)	(priv->client)
+#define priv_to_dev(priv)	(&(priv_to_client(priv)->dev))
+
+struct clk_5p49_priv {
+	struct		clk_hw hw;
+	struct		i2c_client *client;
+	struct		clk *clk_out;
+	unsigned long	index;
+	unsigned long	clk_rate;
+};
+
+static const struct of_device_id clk_5p49_of_match[] = {
+	{ .compatible = "idt,5p49v5923a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, clk_5p49_of_match);
+
+static const struct i2c_device_id clk_5p49_id[] = {
+	{ "5p49v5923a",},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, clk_5p49_id);
+
+#define clk_5p49_read(priv, addr) \
+	i2c_smbus_read_byte_data(priv_to_client(priv), \
+	(addr + (0x10 * priv->index)))
+#define clk_5p49_write(priv, addr, val) \
+	i2c_smbus_write_byte_data(priv_to_client(priv), \
+	(addr + (0x10 * priv->index)), val)
+
+static int clk_5p49_set_rate(struct clk_hw *hw,
+			     unsigned long rate, unsigned long parent_rate)
+{
+	return 0;
+}
+
+static void clk_5p49_power(struct clk_hw *hw, bool power)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	u8 reg;
+
+	if (power) {
+		reg = i2c_smbus_read_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN);
+		reg |= (0x80 >> (priv->index - 1));
+		i2c_smbus_write_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN, reg);
+	} else {
+		reg = i2c_smbus_read_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN);
+		reg &= ~(0x80 >> (priv->index - 1));
+		i2c_smbus_write_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN, reg);
+	}
+}
+
+static int clk_5p49_enable(struct clk_hw *hw)
+{
+	clk_5p49_power(hw, true);
+
+	return 0;
+}
+
+static void clk_5p49_disable(struct clk_hw *hw)
+{
+	clk_5p49_power(hw, false);
+}
+
+static unsigned long clk_5p49_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+
+	return priv->clk_rate;
+}
+
+static int clk_5p49_div_calculation(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	int integ_div, frac_div, div, vco_div, vco_clk;
+	u32 shift_1kHz = 1000;
+	u8 frac_0, frac_1, frac_2, frac_3;
+
+	vco_div = ((i2c_smbus_read_byte_data(priv->client,
+			C5P49_FB_INT_DIV_REG0) & 0xF0) >> 4)
+			+ (i2c_smbus_read_byte_data(priv->client,
+			C5P49_FB_INT_DIV_REG1) << 4);
+
+	clk_5p49_power(hw, false);
+
+	vco_clk = INPUT_CLK * vco_div / shift_1kHz;
+	dev_dbg(&priv->client->dev, "vco clock:%d kHz\n", vco_clk);
+
+	vco_clk = (vco_clk / 2);
+	rate = rate / shift_1kHz;
+
+	integ_div = (vco_clk / rate);
+	div = ((vco_clk * shift_1kHz) / rate);
+	frac_div = div - (integ_div * shift_1kHz);
+
+	if (frac_div > 0x3fffffff)
+		return -EINVAL;
+
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_11_4,
+			((0x0ff0 & (u16)integ_div) >> 4));
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_3_0,
+			((0x000f & (u16)integ_div) << 4));
+
+	/* spread = 0.01% */
+	frac_div = frac_div - ((div / (100 * 100 / 1)) / 2);
+	frac_div = ((0x1000000 / shift_1kHz) * frac_div);
+	dev_dbg(&priv->client->dev,
+		"integer:0x%x, fraction:0x%x\n",
+		integ_div, frac_div);
+
+	frac_0 = (frac_div & 0x3fc00000) >> 22;
+	frac_1 = (frac_div & 0x003fc000) >> 14;
+	frac_2 = (frac_div & 0x00003fc0) >> 6;
+	frac_3 = (frac_div & 0x0000003f) << 2;
+
+	clk_5p49_write(priv, C5P49_DIV_FRAC_29_22, frac_0);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_21_14, frac_1);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_13_6,  frac_2);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_5_0,   frac_3);
+
+	clk_5p49_power(hw, true);
+
+	return 0;
+}
+
+static long clk_5p49_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	int ret;
+
+	priv->clk_rate = 0;
+
+	ret = clk_5p49_div_calculation(hw, rate);
+	if (ret < 0)
+		return ret;
+
+	priv->clk_rate = rate;
+
+	return 0;
+}
+
+static u8 clk_5p49_get_parent(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static const struct clk_ops clk_5p49_ops = {
+	.get_parent	= clk_5p49_get_parent,
+	.set_rate	= clk_5p49_set_rate,
+	.prepare	= clk_5p49_enable,
+	.unprepare	= clk_5p49_disable,
+	.recalc_rate	= clk_5p49_recalc_rate,
+	.round_rate	= clk_5p49_round_rate,
+};
+
+static int clk_5p49_clk_register(struct clk_5p49_priv *priv,
+				 struct device_node *np)
+{
+	struct clk_init_data init;
+	struct clk *clk;
+	const char *name;
+	static const char *parent_names[REF_CLK];
+	int ret = 0;
+
+	parent_names[0]	= __clk_get_name(of_clk_get(np, 0));
+	name = np->name;
+
+	init.name		= name;
+	init.ops		= &clk_5p49_ops;
+	init.flags		= CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	init.parent_names	= parent_names;
+	init.num_parents	= ARRAY_SIZE(parent_names);
+
+	priv->hw.init = &init;
+
+	clk = clk_register(NULL, &priv->hw);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		clk_unregister(clk);
+		return ret;
+	}
+
+	priv->clk_out = clk;
+
+	return 0;
+}
+
+static int clk_5p49_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct clk_5p49_priv *priv = NULL;
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node, *ch_np;
+	int ret, i, ch = 1;	/* ch = 0 reserved.*/
+	u32 probe_cnt = 0;
+
+	for (i = ch; i < CLK_MAX; i++) {
+		char name[20];
+
+		sprintf(name, "5p49v5923a_clk%u", i);
+		ch_np = of_get_child_by_name(np, name);
+		if (!ch_np)
+			continue;
+
+		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+		if (!priv)
+			return -ENOMEM;
+
+		priv->client = client;
+		priv->index = i + 1;
+		i2c_set_clientdata(client, priv);
+
+		ret = clk_5p49_clk_register(priv, ch_np);
+		if (ret < 0)
+			return ret;
+		probe_cnt++;
+	}
+
+	if (probe_cnt == 0) {
+		dev_err(dev, "Device tree error.\n");
+		return -EINVAL;
+	}
+
+	dev_info(dev, "Rev.0x%x, probed\n",
+		i2c_smbus_read_byte_data(priv->client, 0x01));
+
+	return 0;
+}
+
+static int clk_5p49_remove(struct i2c_client *client)
+{
+	struct clk_5p49_priv *priv = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+
+	of_clk_del_provider(np);
+
+	clk_unregister(priv->clk_out);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int clk_5p49_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int clk_5p49_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(clk_5p49_pm_ops,
+			clk_5p49_suspend, clk_5p49_resume);
+#define DEV_PM_OPS (&clk_5p49_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct i2c_driver clk_5p49_driver = {
+	.driver = {
+		.name = "5p49v5923a",
+		.pm	= DEV_PM_OPS,
+		.of_match_table = clk_5p49_of_match,
+	},
+	.probe		= clk_5p49_probe,
+	.remove		= clk_5p49_remove,
+	.id_table	= clk_5p49_id,
+};
+
+module_i2c_driver(clk_5p49_driver);
+
+MODULE_DESCRIPTION("5p49v5923a programmable clock generator driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c
index 7379de8..d279d3e 100644
--- a/drivers/clk/clk-cs2000-cp.c
+++ b/drivers/clk/clk-cs2000-cp.c
@@ -493,9 +493,30 @@
 	return ret;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int cs2000_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int cs2000_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cs2000_pm_ops,
+			cs2000_suspend, cs2000_resume);
+#define DEV_PM_OPS (&cs2000_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct i2c_driver cs2000_driver = {
 	.driver = {
 		.name = "cs2000-cp",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = cs2000_of_match,
 	},
 	.probe		= cs2000_probe,
diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
index c824bf5..4fbf800 100644
--- a/drivers/clk/shmobile/r8a7795-cpg-mssr.c
+++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
@@ -121,8 +121,8 @@
 	DEF_BASE("z2",          R8A7795_CLK_Z2,  CLK_TYPE_GEN3_Z2,  CLK_PLL2),
 
 	DEF_DIV6P1("mso",       R8A7795_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
-	DEF_DIV6P1("csi0",      R8A7795_CLK_CSI0,  CLK_PLL1_DIV2, 0x00C),
-	DEF_DIV6P1("hdmi",      R8A7795_CLK_HDMI,  CLK_PLL1_DIV2, 0x250),
+	DEF_DIV6P1("csi0",      R8A7795_CLK_CSI0,  CLK_PLL1_DIV4, 0x00C),
+	DEF_DIV6P1("hdmi",      R8A7795_CLK_HDMI,  CLK_PLL1_DIV4, 0x250),
 };
 
 static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
@@ -154,6 +154,8 @@
 	DEF_MOD("sdhi0",		 314,	R8A7795_CLK_SD0),
 	DEF_MOD("pcie1",		 318,	R8A7795_CLK_S3D1),
 	DEF_MOD("pcie0",		 319,	R8A7795_CLK_S3D1),
+	DEF_MOD("usb3-if1",		 327,	R8A7795_CLK_S3D1),
+	DEF_MOD("usb3-if0",		 328,	R8A7795_CLK_S3D1),
 	DEF_MOD("rwdt",			 402,	R8A7795_CLK_R),
 	DEF_MOD("intc-ap",		 408,	R8A7795_CLK_S3D1),
 	DEF_MOD("audmac0",		 502,	R8A7795_CLK_S3D4),
@@ -165,6 +167,7 @@
 	DEF_MOD("hscif1",		 519,	R8A7795_CLK_S3D1),
 	DEF_MOD("hscif0",		 520,	R8A7795_CLK_S3D1),
 	DEF_MOD("thermal",		 522,	R8A7795_CLK_CP),
+	DEF_MOD("pwm",			 523,	R8A7795_CLK_S3D4),
 	DEF_MOD("fcpvd3",		 600,	R8A7795_CLK_S2D1),
 	DEF_MOD("fcpvd2",		 601,	R8A7795_CLK_S2D1),
 	DEF_MOD("fcpvd1",		 602,	R8A7795_CLK_S2D1),
@@ -224,6 +227,7 @@
 	DEF_MOD("gpio0",		 912,	R8A7795_CLK_CP),
 	DEF_MOD("i2c6",			 918,	R8A7795_CLK_S3D2),
 	DEF_MOD("i2c5",			 919,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c-dvfs",		 926,	R8A7795_CLK_CP),
 	DEF_MOD("i2c4",			 927,	R8A7795_CLK_S3D2),
 	DEF_MOD("i2c3",			 928,	R8A7795_CLK_S3D2),
 	DEF_MOD("i2c2",			 929,	R8A7795_CLK_S3D2),
@@ -271,28 +275,15 @@
 #define CPG_SD3CKCR	0x026c
 #define CPG_RCKCR	0x0240
 
-/** Modify for Z-clock
- * -----------------------------------------------------------------------------
- * Z Clock & Z2 Clock
- *
- * Traits of this clock:
- * prepare - clk_prepare only ensures that parents are prepared
- * enable - clk_enable only ensures that parents are enabled
- * rate - rate is adjustable.  clk->rate = parent->rate * mult / 32
- * parent - fixed parent.  No clk_set_parent support
- */
-#define CPG_FRQCRB			0x00000004
-#define CPG_FRQCRB_KICK			BIT(31)
-#define CPG_FRQCRC			0x000000e0
-#define CPG_FRQCRC_ZFC_MASK		(0x1f << 8)
-#define CPG_FRQCRC_ZFC_SHIFT		8
-#define CPG_FRQCRC_Z2FC_MASK		0x1f
+/* Implementation for customized clocks (Z-clk, Z2-clk, PLL0-clk) for CPUFreq */
+#define CPG_PLLECR	0x00D0
+#define CPG_PLLECR_PLL0ST (1 << 8)
 
 #define GEN3_PRR		0xFFF00044  /* Product register */
 #define PRODUCT_ID_MASK		(0x7f << 8) /* R-Car H3: PRODUCT[14:8] bits */
 #define RCAR_H3_PRODUCT_ID	(0x4f << 8) /* 0b1001111 */
 #define PRODUCT_VERSION_MASK	0xff        /* R-Car H3: CUT[7:0] bits*/
-#define PRODUCT_VERSION_WS1_0	0
+#define PRODUCT_VERSION_WS1_0	0	/* WS1.0: 0b0000000 */
 
 int check_product_version(u32 product_bits)
 {
@@ -314,6 +305,165 @@
 	return ret;
 }
 
+/* Define for PLL0 clk driver */
+#define CPG_PLL0CR_STC_MASK             0x7f000000
+#define CPG_PLL0CR_STC_SHIFT            24
+
+#ifdef CONFIG_RCAR_Z_CLK_MAX_THRESHOLD
+#define Z_CLK_MAX_THRESHOLD     CONFIG_RCAR_Z_CLK_MAX_THRESHOLD
+#else
+#define Z_CLK_MAX_THRESHOLD             1500000000
+#endif
+
+struct cpg_pll0_clk {
+	struct clk_hw hw;
+	void __iomem *reg;
+	void __iomem *pllecr_reg;
+};
+
+#define to_pll0_clk(_hw)   container_of(_hw, struct cpg_pll0_clk, hw)
+
+static int cpg_pll0_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long prate)
+{
+	struct cpg_pll0_clk *pll0_clk = to_pll0_clk(hw);
+	unsigned int stc_val;
+	u32 val;
+	int i;
+
+	/* Start clock issue W/A */
+	if (check_product_version(
+			RCAR_H3_PRODUCT_ID | PRODUCT_VERSION_WS1_0) == 0) {
+		prate *= 2; /* Because PLL0 output is not divided for 2 */
+	}
+	/* End clock issue W/A */
+
+	stc_val = DIV_ROUND_CLOSEST(rate, prate);
+	stc_val = clamp(stc_val, 90U, 120U);/*Lowest value is 1.5G (stc == 90)*/
+	pr_debug("%s(): prate: %lu, rate: %lu, pll0-mult: %d\n",
+		__func__, prate, rate, stc_val);
+
+	stc_val -= 1;
+	val = clk_readl(pll0_clk->reg);
+	val &= ~CPG_PLL0CR_STC_MASK;
+	val |= stc_val << CPG_PLL0CR_STC_SHIFT;
+	clk_writel(val, pll0_clk->reg);
+
+	i = 0;
+	while (!(clk_readl(pll0_clk->pllecr_reg) & CPG_PLLECR_PLL0ST)) {
+		cpu_relax();
+		i++;
+	}
+
+	if (i > 1000)
+		pr_warn("%s(): PLL0: long settled time: %d\n", __func__, i);
+
+	return 0;
+}
+
+static long cpg_pll0_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	unsigned long prate = *parent_rate;
+	unsigned int mult;
+
+	if (rate < Z_CLK_MAX_THRESHOLD)
+		rate = Z_CLK_MAX_THRESHOLD; /* Set lowest value: 1.5GHz */
+
+	/* Start clock issue W/A */
+	if (check_product_version(
+		RCAR_H3_PRODUCT_ID | PRODUCT_VERSION_WS1_0) == 0) {
+		prate *= 2;
+	}
+	/* End clock issue W/A */
+
+	mult = DIV_ROUND_CLOSEST(rate, prate);
+	mult = clamp(mult, 90U, 120U); /* 1.5G => (stc == 90)*/
+
+	rate = prate * mult;
+
+	/* Round to closest value at 100MHz unit */
+	rate = 100000000 * DIV_ROUND_CLOSEST(rate, 100000000);
+	pr_debug("%s(): output rate: %lu, parent_rate: %lu, pll0-mult: %d\n",
+		__func__, rate, prate, mult);
+	return rate;
+}
+
+static unsigned long cpg_pll0_clk_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct cpg_pll0_clk *pll0_clk = to_pll0_clk(hw);
+	unsigned int val;
+	unsigned long rate;
+
+	val = (clk_readl(pll0_clk->reg) & CPG_PLL0CR_STC_MASK)
+		>> CPG_PLL0CR_STC_SHIFT;
+
+	rate = (u64)parent_rate * (val + 1);
+
+	/* Start clock issue W/A */
+	if (check_product_version(
+		RCAR_H3_PRODUCT_ID|PRODUCT_VERSION_WS1_0) == 0) {
+		rate *= 2; /* Don't divide PLL0 output for 2 */
+	}
+	/* End clock issue W/A */
+
+	/* Round to closest value at 100MHz unit */
+	rate = 100000000 * DIV_ROUND_CLOSEST(rate, 100000000);
+	return rate;
+}
+
+static const struct clk_ops cpg_pll0_clk_ops = {
+	.recalc_rate = cpg_pll0_clk_recalc_rate,
+	.round_rate = cpg_pll0_clk_round_rate,
+	.set_rate = cpg_pll0_clk_set_rate,
+};
+
+static struct clk * __init cpg_pll0_clk_register(const char *name,
+				const char *parent_name,
+				void __iomem *cpg_base)
+{
+	struct clk_init_data init;
+	struct cpg_pll0_clk *pll0_clk;
+	struct clk *clk;
+
+	pll0_clk = kzalloc(sizeof(*pll0_clk), GFP_KERNEL);
+	if (!pll0_clk)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &cpg_pll0_clk_ops;
+	init.flags = 0;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	pll0_clk->reg = cpg_base + CPG_PLL0CR;
+	pll0_clk->pllecr_reg = cpg_base + CPG_PLLECR;
+	pll0_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &pll0_clk->hw);
+	if (IS_ERR(clk))
+		kfree(pll0_clk);
+
+	return clk;
+}
+
+/* Modify for Z-clock and Z2-clock
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.  clk->rate = parent->rate * mult / 32
+ * parent - fixed parent.  No clk_set_parent support
+ */
+#define CPG_FRQCRB			0x00000004
+#define CPG_FRQCRB_KICK			BIT(31)
+#define CPG_FRQCRC			0x000000e0
+#define CPG_FRQCRC_ZFC_MASK		(0x1f << 8)
+#define CPG_FRQCRC_ZFC_SHIFT		8
+#define CPG_FRQCRC_Z2FC_MASK		0x1f
+
+/* Z clk driver code */
 struct cpg_z_clk {
 	struct clk_hw hw;
 	void __iomem *reg;
@@ -336,24 +486,7 @@
 
 	rate = div_u64((u64)parent_rate * mult + 16, 32);
 	/* Round to closest value at 100MHz unit */
-	rate = 100000000*DIV_ROUND_CLOSEST(rate, 100000000);
-	return rate;
-}
-
-static unsigned long cpg_z2_clk_recalc_rate(struct clk_hw *hw,
-					   unsigned long parent_rate)
-{
-	struct cpg_z_clk *zclk = to_z_clk(hw);
-	unsigned int mult;
-	unsigned int val;
-	unsigned long rate;
-
-	val = (clk_readl(zclk->reg) & CPG_FRQCRC_Z2FC_MASK);
-	mult = 32 - val;
-
-	rate = div_u64((u64)parent_rate * mult + 16, 32);
-	/* Round to closest value at 100MHz unit */
-	rate = 100000000*DIV_ROUND_CLOSEST(rate, 100000000);
+	rate = 100000000 * DIV_ROUND_CLOSEST(rate, 100000000);
 	return rate;
 }
 
@@ -366,10 +499,24 @@
 	if (!prate)
 		prate = 1;
 
-	mult = div_u64((u64)rate * 32 + prate/2, prate);
+	if (rate <= Z_CLK_MAX_THRESHOLD) { /* Focus on changing z-clock */
+		prate = Z_CLK_MAX_THRESHOLD; /* Set parent to: 1.5GHz */
+		mult = div_u64((u64)rate * 32 + prate/2, prate);
+	} else {
+		/* Focus on changing parent. Fix z-clock divider is 32/32 */
+		mult = 32;
+	}
+
 	mult = clamp(mult, 1U, 32U);
 
-	return *parent_rate / 32 * mult;
+	/* Re-calculate the parent_rate to propagate new rate for it */
+	prate = div_u64((u64)rate * 32 + mult/2, mult);
+	prate = 100000000 * DIV_ROUND_CLOSEST(prate, 100000000);
+	pr_debug("%s():z-clk mult:%d, re-calculated prate:%lu, return: %lu\n",
+		__func__, mult, prate, prate / 32 * mult);
+	*parent_rate = prate;
+
+	return prate / 32 * mult;
 }
 
 static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -380,9 +527,16 @@
 	u32 val, kick;
 	unsigned int i;
 
-	mult = div_u64((u64)rate * 32 + parent_rate/2, parent_rate);
+	if (rate <= Z_CLK_MAX_THRESHOLD) { /* Focus on changing z-clock */
+		parent_rate = Z_CLK_MAX_THRESHOLD; /* Set parent to: 1.5GHz */
+		mult = div_u64((u64)rate * 32 + parent_rate/2, parent_rate);
+	} else {
+		mult = 32;
+	}
 	mult = clamp(mult, 1U, 32U);
 
+	pr_debug("%s(): rate: %lu, set prate to: %lu, z-clk mult: %d\n",
+		__func__, rate, parent_rate, mult);
 	if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
 		return -EBUSY;
 
@@ -418,25 +572,12 @@
 	return -ETIMEDOUT;
 }
 
-static int cpg_z2_clk_set_rate(struct clk_hw *hw, unsigned long rate,
-			      unsigned long parent_rate)
-{
-	pr_info("Do not support Z2 clock changing\n");
-	return 0;
-}
-
 static const struct clk_ops cpg_z_clk_ops = {
 	.recalc_rate = cpg_z_clk_recalc_rate,
 	.round_rate = cpg_z_clk_round_rate,
 	.set_rate = cpg_z_clk_set_rate,
 };
 
-static const struct clk_ops cpg_z2_clk_ops = {
-	.recalc_rate = cpg_z2_clk_recalc_rate,
-	.round_rate = cpg_z_clk_round_rate,
-	.set_rate = cpg_z2_clk_set_rate,
-};
-
 static struct clk * __init cpg_z_clk_register(const char *name,
 					      const char *parent_name,
 					      void __iomem *reg)
@@ -451,7 +592,7 @@
 
 	init.name = name;
 	init.ops = &cpg_z_clk_ops;
-	init.flags = 0;
+	init.flags = CLK_SET_RATE_PARENT;
 	init.parent_names = &parent_name;
 	init.num_parents = 1;
 
@@ -466,6 +607,49 @@
 	return clk;
 }
 
+/* Z2 clk driver code */
+static unsigned long cpg_z2_clk_recalc_rate(struct clk_hw *hw,
+					   unsigned long parent_rate)
+{
+	struct cpg_z_clk *zclk = to_z_clk(hw);
+	unsigned int mult;
+	unsigned int val;
+	unsigned long rate;
+
+	val = (clk_readl(zclk->reg) & CPG_FRQCRC_Z2FC_MASK);
+	mult = 32 - val;
+
+	rate = div_u64((u64)parent_rate * mult + 16, 32);
+	/* Round to closest value at 100MHz unit */
+	rate = 100000000 * DIV_ROUND_CLOSEST(rate, 100000000);
+	return rate;
+}
+
+static long cpg_z2_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	unsigned long prate  = *parent_rate;
+	unsigned int mult;
+
+	mult = div_u64((u64)rate * 32 + prate/2, prate);
+	mult = clamp(mult, 1U, 32U);
+
+	return prate / 32 * mult;
+}
+
+static int cpg_z2_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long parent_rate)
+{
+	pr_info("Do not support Z2 clock changing\n");
+	return 0;
+}
+
+static const struct clk_ops cpg_z2_clk_ops = {
+	.recalc_rate = cpg_z2_clk_recalc_rate,
+	.round_rate = cpg_z2_clk_round_rate,
+	.set_rate = cpg_z2_clk_set_rate,
+};
+
 static struct clk * __init cpg_z2_clk_register(const char *name,
 					      const char *parent_name,
 					      void __iomem *reg)
@@ -494,7 +678,7 @@
 
 	return clk;
 }
-/** End of modifying for Z-clock */
+/** End of modifying for Z-clock, Z2-clock and PLL0-clock */
 
 /* -----------------------------------------------------------------------------
  * SDn Clock
@@ -786,20 +970,20 @@
 static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
 	/* EXTAL div	PLL1 mult	PLL3 mult */
 	{ 1,		192,		192,	},
-	{ 1,		192,		128,	},
-	{ 0, /* Prohibited setting */		},
+	{ 1,		192,		168,	},
+	{ 1,		192,		144,	},
 	{ 1,		192,		192,	},
 	{ 1,		160,		160,	},
-	{ 1,		160,		106,	},
-	{ 0, /* Prohibited setting */		},
+	{ 1,		160,		140,	},
+	{ 1,		160,		120,	},
 	{ 1,		160,		160,	},
 	{ 1,		128,		128,	},
-	{ 1,		128,		84,	},
-	{ 0, /* Prohibited setting */		},
+	{ 1,		128,		112,	},
+	{ 1,		128,		96,	},
 	{ 1,		128,		128,	},
 	{ 2,		192,		192,	},
-	{ 2,		192,		128,	},
-	{ 0, /* Prohibited setting */		},
+	{ 2,		192,		168,	},
+	{ 2,		192,		144,	},
 	{ 2,		192,		192,	},
 };
 
@@ -828,21 +1012,12 @@
 
 	case CLK_TYPE_GEN3_PLL0:
 		/*
-		 * PLL0 is a configurable multiplier clock. Register it as a
-		 * fixed factor clock for now as there's no generic multiplier
-		 * clock implementation and we currently have no need to change
-		 * the multiplier value.
+		 * The PLL0 is implemented as customized clock,
+		 * it changes the multiplier when cpufreq changes between
+		 * normal and override mode.
 		 */
-		value = readl(base + CPG_PLL0CR);
-		mult = (((value >> 24) & 0x7f) + 1) * 2;
-		/* Start clock issue W/A */
-		if (!check_product_version(
-			RCAR_H3_PRODUCT_ID|PRODUCT_VERSION_WS1_0)) {
-			mult *= 2; /* Don't divide PLL0 output for 2 */
-		}
-		/* End clock issue W/A */
-		break;
-
+		return cpg_pll0_clk_register(core->name,
+				__clk_get_name(parent), base);
 	case CLK_TYPE_GEN3_PLL1:
 		mult = cpg_pll_config->pll1_mult;
 		break;
@@ -855,10 +1030,10 @@
 		 * the multiplier value.
 		 */
 		value = readl(base + CPG_PLL2CR);
-		mult = (((value >> 24) & 0x7f) + 1) * 2;
-		/* Start clock issue W/A */
-		if (!check_product_version(
-			RCAR_H3_PRODUCT_ID|PRODUCT_VERSION_WS1_0)) {
+		mult = ((value >> 24) & 0x7f) + 1;
+		/* Start clock issue W/A (for H3 WS1.0) */
+		if (check_product_version(
+			RCAR_H3_PRODUCT_ID | PRODUCT_VERSION_WS1_0) == 0) {
 			mult *= 2; /* Don't divide PLL2 output for 2 */
 		}
 		/* End clock issue W/A */
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c
index 9a4d888..c7bec26 100644
--- a/drivers/clk/shmobile/renesas-cpg-mssr.c
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.c
@@ -578,9 +578,30 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int cpg_mssr_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int cpg_mssr_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cpg_mssr_pm_ops,
+			cpg_mssr_suspend, cpg_mssr_resume);
+#define DEV_PM_OPS (&cpg_mssr_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver cpg_mssr_driver = {
 	.driver		= {
 		.name	= "renesas-cpg-mssr",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = cpg_mssr_match,
 	},
 };
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0031069..6847b49 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -102,6 +102,15 @@
 	help
 	  Internal configuration node for common cpufreq on Samsung SoC
 
+config ARM_RCAR_CPUFREQ
+	bool "Renesas R-Car Gen3 CPUfreq driver"
+	depends on ARCH_RENESAS
+	default y
+	help
+	  This enables CPUfreq driver for R-Car Gen3.
+	  It needs to be enabled to control for both
+	  CPU frequency and voltage scaling.
+
 config ARM_S3C24XX_CPUFREQ
 	bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)"
 	depends on ARCH_S3C24XX
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 9e63fb1..4d854c6 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -61,6 +61,7 @@
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)	+= pxa2xx-cpufreq.o
 obj-$(CONFIG_PXA3xx)			+= pxa3xx-cpufreq.o
+obj-$(CONFIG_ARM_RCAR_CPUFREQ)		+= rcar-cpufreq.o
 obj-$(CONFIG_ARM_S3C24XX_CPUFREQ)	+= s3c24xx-cpufreq.o
 obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
 obj-$(CONFIG_ARM_S3C2410_CPUFREQ)	+= s3c2410-cpufreq.o
diff --git a/drivers/cpufreq/rcar-cpufreq.c b/drivers/cpufreq/rcar-cpufreq.c
new file mode 100644
index 0000000..4cb3907
--- /dev/null
+++ b/drivers/cpufreq/rcar-cpufreq.c
@@ -0,0 +1,106 @@
+/*
+ * Renesas R-Car CPUFreq Support
+ *
+ *  Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * 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
+ *
+ * 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/platform_device.h>
+
+#ifdef CONFIG_POWER_AVS
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+/* Change the default opp_table pattern in device tree.
+ * Set opp_pattern_num is default.
+ */
+
+int change_default_opp_pattern(unsigned int opp_pattern_num)
+{
+	struct device_node *cpu_node = NULL;
+
+	__be32 *list, *pp_val;
+	int size;
+	struct property *pp;
+
+	for_each_node_with_property(cpu_node, "operating-points-v2") {
+		pp = of_find_property(cpu_node, "operating-points-v2", &size);
+		if (!pp || !pp->value)
+			return -ENOENT;
+
+		pp_val = pp->value;
+		size = size / sizeof(*pp_val);
+		if (size > opp_pattern_num) {
+			list = kzalloc(sizeof(*pp_val), GFP_KERNEL);
+			if (!list) {
+				pr_debug("%s(): kzalloc fail, return -ENOMEM\n",
+						__func__);
+				return -ENOMEM;
+			}
+			*list = *(pp_val + opp_pattern_num);
+			pp->value = list;
+		}
+		pp->length = sizeof(*list); /* opp fw only accept 1 opp_tb */
+
+		pr_debug("rcar-cpufreq: %s is running with: %s\n",
+			of_node_full_name(cpu_node),
+			of_node_full_name(of_find_node_by_phandle(
+				be32_to_cpup(pp->value))));
+	}
+
+	return 0;
+}
+
+/* Get AVS value */
+#define ADVFS_BASE		0xE60A0000
+#define KSEN_ADJCNTS		(ADVFS_BASE + 0x13C)
+#define VOLCOND_MASK_0_3	0x0f	/* VOLCOND[3:0] */
+
+#define AVS_TABLE_NUM	7
+
+unsigned int get_avs_value(void)
+{
+	unsigned int ret;
+	void __iomem *ksen_adjcnts = ioremap_nocache(KSEN_ADJCNTS, 4);
+	u32 ksen_adjcnts_value = ioread32(ksen_adjcnts);
+
+	ksen_adjcnts_value &= VOLCOND_MASK_0_3;
+	if (ksen_adjcnts_value >= 0 && ksen_adjcnts_value < AVS_TABLE_NUM) {
+		ret = ksen_adjcnts_value;
+	} else {
+		ret = 0;
+		pr_debug("rcar-cpufreq: hw get invalid avs value, use avs_tb0\n");
+	}
+	pr_debug("rcar-cpufreq: use avs value: %d\n", ksen_adjcnts_value);
+	iounmap(ksen_adjcnts);
+
+	return ret;
+}
+#endif /* CONFIG_POWER_AVS */
+
+int __init rcar_cpufreq_init(void)
+{
+#ifdef CONFIG_POWER_AVS
+	int avs_val = get_avs_value();
+
+	change_default_opp_pattern(avs_val);
+#endif /* CONFIG_POWER_AVS */
+	platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+	return 0;
+}
+
+module_init(rcar_cpufreq_init);
+
+MODULE_AUTHOR("Renesas Electronics Corporation");
+MODULE_DESCRIPTION("R-Car CPUFreq driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index f25cd79..b26c537 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -365,6 +365,13 @@
 	psci_0_2_set_functions();
 
 	psci_init_migrate();
+	/*
+	 * psci_init_migrate() might fail to get needed information due to
+	 * incomplete firmware support.
+	 * TODO: Let's assume that Trusted OS services (e.g DDR training)
+	 * always run in CPU0.
+	 */
+	resident_cpu = 0;
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
 		psci_init_cpu_suspend();
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index cf41440..f1cf84d 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -494,11 +494,32 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpio_rcar_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int gpio_rcar_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops,
+			gpio_rcar_suspend, gpio_rcar_resume);
+#define DEV_PM_OPS (&gpio_rcar_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver gpio_rcar_device_driver = {
 	.probe		= gpio_rcar_probe,
 	.remove		= gpio_rcar_remove,
 	.driver		= {
 		.name	= "gpio_rcar",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = of_match_ptr(gpio_rcar_of_table),
 	}
 };
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index b0aac473..ab266b9 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1,14 +1,16 @@
 /*
+ * DesignWare High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Mentor Graphics Inc.
  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski at gmx.de>
  *
  * 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.
  *
- * Designware High-Definition Multimedia Interface (HDMI) driver
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  */
 #include <linux/module.h>
 #include <linux/irq.h>
@@ -20,6 +22,7 @@
 #include <linux/of_device.h>
 #include <linux/spinlock.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
@@ -31,6 +34,26 @@
 #include "dw-hdmi.h"
 #include "dw-hdmi-audio.h"
 
+/* HDMI_IH_I2CM_STAT0 and HDMI_IH_MUTE_I2CM_STAT0 register bits */
+#define HDMI_IH_I2CM_STAT0_ERROR		BIT(0)
+#define HDMI_IH_I2CM_STAT0_DONE			BIT(1)
+
+/* HDMI_I2CM_OPERATION register bits */
+#define HDMI_I2CM_OPERATION_READ		BIT(0)
+#define HDMI_I2CM_OPERATION_READ_EXT		BIT(1)
+#define HDMI_I2CM_OPERATION_WRITE		BIT(4)
+
+/* HDMI_I2CM_INT register bits */
+#define HDMI_I2CM_INT_DONE_MASK			BIT(2)
+#define HDMI_I2CM_INT_DONE_POL			BIT(3)
+
+/* HDMI_I2CM_CTLINT register bits */
+#define HDMI_I2CM_CTLINT_ARB_MASK		BIT(2)
+#define HDMI_I2CM_CTLINT_ARB_POL		BIT(3)
+#define HDMI_I2CM_CTLINT_NAC_MASK		BIT(6)
+#define HDMI_I2CM_CTLINT_NAC_POL		BIT(7)
+
+
 #define HDMI_EDID_LEN		512
 
 #define RGB			0
@@ -101,6 +124,17 @@
 	struct hdmi_vmode video_mode;
 };
 
+struct dw_hdmi_i2c {
+	struct i2c_adapter	adap;
+
+	spinlock_t		lock;
+	struct completion	cmp;
+	u8			stat;
+
+	u8			slave_reg;
+	bool			is_regaddr;
+};
+
 struct dw_hdmi {
 	struct drm_connector connector;
 	struct drm_encoder *encoder;
@@ -112,6 +146,8 @@
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
 
+	struct dw_hdmi_i2c *i2c;
+
 	struct hdmi_data_info hdmi_data;
 	const struct dw_hdmi_plat_data *plat_data;
 
@@ -142,6 +178,10 @@
 	unsigned int audio_n;
 	bool audio_enable;
 
+	bool isfr_use;
+	bool iahb_use;
+	int num;
+
 	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
 	u8 (*read)(struct dw_hdmi *hdmi, int offset);
 };
@@ -198,6 +238,242 @@
 	hdmi_modb(hdmi, data << shift, mask, reg);
 }
 
+static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hdmi->i2c->lock, flags);
+
+	/* Set Fast Mode speed */
+	hdmi_writeb(hdmi, 0x0b, HDMI_I2CM_DIV);
+
+	/* Software reset */
+	hdmi_writeb(hdmi, 0x00, HDMI_I2CM_SOFTRSTZ);
+
+	/* Set done, not acknowledged and arbitration interrupt polarities */
+	hdmi_writeb(hdmi, HDMI_I2CM_INT_DONE_POL, HDMI_I2CM_INT);
+	hdmi_writeb(hdmi, HDMI_I2CM_CTLINT_NAC_POL | HDMI_I2CM_CTLINT_ARB_POL,
+		    HDMI_I2CM_CTLINT);
+
+	/* Clear DONE and ERROR interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE,
+		    HDMI_IH_I2CM_STAT0);
+
+	/* Mute DONE and ERROR interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE,
+		    HDMI_IH_MUTE_I2CM_STAT0);
+
+	spin_unlock_irqrestore(&hdmi->i2c->lock, flags);
+}
+
+static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
+			    unsigned char *buf, int length)
+{
+	int stat;
+	unsigned long flags;
+	struct dw_hdmi_i2c *i2c = hdmi->i2c;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	if (!i2c->is_regaddr) {
+		dev_dbg(hdmi->dev, "set read register address to 0\n");
+		i2c->slave_reg = 0x00;
+		i2c->is_regaddr = true;
+	}
+
+	while (length--) {
+		hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS);
+		hdmi_writeb(hdmi,
+			    HDMI_I2CM_OPERATION_READ, HDMI_I2CM_OPERATION);
+		i2c->stat = 0;
+
+		spin_unlock_irqrestore(&i2c->lock, flags);
+
+		stat = wait_for_completion_interruptible_timeout(&i2c->cmp,
+								 HZ / 10);
+		if (!stat)
+			return -ETIMEDOUT;
+		if (stat < 0)
+			return stat;
+
+		spin_lock_irqsave(&i2c->lock, flags);
+
+		/* Check for error condition on the bus */
+		if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) {
+			spin_unlock_irqrestore(&i2c->lock, flags);
+			return -EIO;
+		}
+
+		*buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
+	}
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	return 0;
+}
+
+static int dw_hdmi_i2c_write(struct dw_hdmi *hdmi,
+				  unsigned char *buf, int length)
+{
+	int stat;
+	unsigned long flags;
+	struct dw_hdmi_i2c *i2c = hdmi->i2c;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	if (!i2c->is_regaddr) {
+		if (length) {
+			/* Use the first write byte as register address */
+			i2c->slave_reg = buf[0];
+			length--;
+			buf++;
+		} else {
+			dev_dbg(hdmi->dev, "set write register address to 0\n");
+			i2c->slave_reg = 0x00;
+		}
+		i2c->is_regaddr = true;
+	}
+
+	while (length--) {
+		hdmi_writeb(hdmi, *buf++, HDMI_I2CM_DATAO);
+		hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS);
+		hdmi_writeb(hdmi,
+			    HDMI_I2CM_OPERATION_WRITE, HDMI_I2CM_OPERATION);
+		i2c->stat = 0;
+
+		spin_unlock_irqrestore(&i2c->lock, flags);
+
+		stat = wait_for_completion_interruptible_timeout(&i2c->cmp,
+								 HZ / 10);
+		if (!stat)
+			return -ETIMEDOUT;
+		if (stat < 0)
+			return stat;
+
+		spin_lock_irqsave(&i2c->lock, flags);
+
+		/* Check for error condition on the bus */
+		if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) {
+			spin_unlock_irqrestore(&i2c->lock, flags);
+			return -EIO;
+		}
+	}
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	return 0;
+}
+
+static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct dw_hdmi *hdmi = i2c_get_adapdata(adap);
+	struct dw_hdmi_i2c *i2c = hdmi->i2c;
+
+	int i, ret;
+	u8 addr;
+	unsigned long flags;
+
+	dev_dbg(hdmi->dev, "xfer: num: %d, addr: 0x%x\n", num, msgs[0].addr);
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	hdmi_writeb(hdmi, 0x00, HDMI_IH_MUTE_I2CM_STAT0);
+
+	/* Set slave device address from the first transaction */
+	addr = msgs[0].addr;
+	hdmi_writeb(hdmi, addr, HDMI_I2CM_SLAVE);
+
+	/* Set slave device register address on transfer */
+	i2c->is_regaddr = false;
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	for (i = 0; i < num; i++) {
+		dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: 0x%x\n",
+			i + 1, num, msgs[i].len, msgs[i].flags);
+
+		if (msgs[i].addr != addr) {
+			dev_warn(hdmi->dev,
+				 "unsupported transaction, changed slave address\n");
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		if (msgs[i].len == 0) {
+			dev_dbg(hdmi->dev,
+				 "unsupported transaction %d/%d, no data\n",
+				 i + 1, num);
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		if (msgs[i].flags & I2C_M_RD)
+			ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, msgs[i].len);
+		else
+			ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, msgs[i].len);
+
+		if (ret < 0)
+			break;
+	}
+
+	if (!ret)
+		ret = num;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	/* Mute DONE and ERROR interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE,
+		    HDMI_IH_MUTE_I2CM_STAT0);
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	return ret;
+}
+
+static u32 dw_hdmi_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm dw_hdmi_algorithm = {
+	.master_xfer	= dw_hdmi_i2c_xfer,
+	.functionality	= dw_hdmi_i2c_func,
+};
+
+static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi)
+{
+	struct i2c_adapter *adap;
+	int ret;
+
+	hdmi->i2c = devm_kzalloc(hdmi->dev, sizeof(*hdmi->i2c), GFP_KERNEL);
+	if (!hdmi->i2c)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&hdmi->i2c->lock);
+	init_completion(&hdmi->i2c->cmp);
+
+	adap = &hdmi->i2c->adap;
+	adap->class = I2C_CLASS_DDC;
+	adap->owner = THIS_MODULE;
+	adap->dev.parent = hdmi->dev;
+	adap->algo = &dw_hdmi_algorithm;
+	strlcpy(adap->name, "DesignWare HDMI", sizeof(adap->name));
+	i2c_set_adapdata(adap, hdmi);
+
+	ret = i2c_add_adapter(adap);
+	if (ret) {
+		dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
+		devm_kfree(hdmi->dev, hdmi->i2c);
+		hdmi->i2c = NULL;
+		return ERR_PTR(ret);
+	}
+
+	dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
+
+	return adap;
+}
+
 static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
 			   unsigned int n)
 {
@@ -739,6 +1015,7 @@
 	const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
 	const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
 	const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
+	const struct dw_hdmi_multi_div *multi_div = pdata->multi_div;
 
 	if (prep)
 		return -EINVAL;
@@ -774,6 +1051,13 @@
 		    phy_config->mpixelclock)
 			break;
 
+	if (hdmi->dev_type == RCAR_HDMI) {
+		for (; multi_div->mpixelclock != (~0UL); multi_div++)
+			if (hdmi->hdmi_data.video_mode.mpixelclock <=
+			    multi_div->mpixelclock)
+				break;
+	}
+
 	if (mpll_config->mpixelclock == ~0UL ||
 	    curr_ctrl->mpixelclock == ~0UL ||
 	    phy_config->mpixelclock == ~0UL) {
@@ -808,21 +1092,27 @@
 	hdmi_phy_test_clear(hdmi, 0);
 
 	hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06);
-	hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
+	if (hdmi->dev_type != RCAR_HDMI)
+		hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
 
 	/* CURRCTRL */
 	hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
 
-	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
-	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+	if (hdmi->dev_type == RCAR_HDMI)
+		hdmi_phy_i2c_write(hdmi, multi_div->multi[res_idx], 0x11);
 
-	hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19);  /* TXTERM */
-	hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
-	hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
+	if (hdmi->dev_type != RCAR_HDMI) {
+		hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
+		hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
 
-	/* REMOVE CLK TERM */
-	hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
-
+		hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19);  /* TXTERM */
+		hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+						 0x09); /* CKSYMTXCTRL */
+		hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+						 0x0E); /* VLEVCTRL */
+		/* REMOVE CLK TERM */
+		hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+	}
 	dw_hdmi_phy_enable_powerdown(hdmi, false);
 
 	/* toggle TMDS enable */
@@ -833,7 +1123,8 @@
 	dw_hdmi_phy_gen2_txpwron(hdmi, 1);
 	dw_hdmi_phy_gen2_pddq(hdmi, 0);
 
-	if (hdmi->dev_type == RK3288_HDMI)
+	if ((hdmi->dev_type == RK3288_HDMI) ||
+		(hdmi->dev_type == RCAR_HDMI))
 		dw_hdmi_phy_enable_spare(hdmi, 1);
 
 	/*Wait for PHY PLL lock */
@@ -1015,13 +1306,23 @@
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
 		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
 
-	inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
-		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
-		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW;
+	if (hdmi->dev_type == RCAR_HDMI) {
+		inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+			HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW :
+			HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH;
 
-	inv_val |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
-		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
-		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW;
+		inv_val |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
+			HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW :
+			HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH;
+	} else {
+		inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+			HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+			HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW;
+
+		inv_val |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
+			HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+			HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW;
+	}
 
 	inv_val |= (vmode->mdataenablepolarity ?
 		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
@@ -1549,16 +1850,47 @@
 	.mode_fixup = dw_hdmi_bridge_mode_fixup,
 };
 
+static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi)
+{
+	struct dw_hdmi_i2c *i2c = hdmi->i2c;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	i2c->stat = hdmi_readb(hdmi, HDMI_IH_I2CM_STAT0);
+	if (!i2c->stat) {
+		spin_unlock_irqrestore(&i2c->lock, flags);
+		return IRQ_NONE;
+	}
+
+	hdmi_writeb(hdmi, i2c->stat, HDMI_IH_I2CM_STAT0);
+	complete(&i2c->cmp);
+
+	dev_dbg(hdmi->dev, "i2cm_stat: 0x%02x, addr: 0x%02x, reg: 0x%02x\n",
+		i2c->stat, hdmi_readb(hdmi, HDMI_I2CM_SLAVE),
+		hdmi_readb(hdmi, HDMI_I2CM_ADDRESS));
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
 {
 	struct dw_hdmi *hdmi = dev_id;
 	u8 intr_stat;
+	irqreturn_t ret = IRQ_NONE;
+
+	if (hdmi->i2c)
+		ret = dw_hdmi_i2c_irq(hdmi);
 
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-	if (intr_stat)
+	if (intr_stat) {
 		hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+		return IRQ_WAKE_THREAD;
+	}
 
-	return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+	return ret;
 }
 
 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
@@ -1738,30 +2070,68 @@
 	if (IS_ERR(hdmi->regs))
 		return PTR_ERR(hdmi->regs);
 
-	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
-	if (IS_ERR(hdmi->isfr_clk)) {
-		ret = PTR_ERR(hdmi->isfr_clk);
-		dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret);
-		return ret;
+	if (of_property_read_u32(np, "clock-isfr", &val) == 0)
+		hdmi->isfr_use = val;
+	else
+		hdmi->isfr_use = true;
+
+	if (hdmi->isfr_use) {
+		if (of_property_read_u32(np, "hdmi-num", &val) == 0)
+			hdmi->num = val;
+		else
+			hdmi->num = -1;
+
+		if (hdmi->num > 1) {
+			char name[7];
+
+			sprintf(name, "isfr.%u", hdmi->plat_data->index);
+			hdmi->isfr_clk = devm_clk_get(hdmi->dev, name);
+		} else
+			hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+		if (IS_ERR(hdmi->isfr_clk)) {
+			ret = PTR_ERR(hdmi->isfr_clk);
+			dev_err(hdmi->dev,
+				 "Unable to get HDMI isfr clk: %d\n", ret);
+			return ret;
+		}
+
+		ret = clk_prepare_enable(hdmi->isfr_clk);
+		if (ret) {
+			dev_err(hdmi->dev,
+				 "Cannot enable HDMI isfr clock: %d\n", ret);
+			return ret;
+		}
+
+		if (of_property_read_u32(np, "hdmi-ifclk", &val) == 0) {
+			ret = clk_set_rate(hdmi->isfr_clk, val);
+			if (ret) {
+				dev_err(hdmi->dev,
+				 "Cannot set HDMI isfr clock rate: %d\n", ret);
+				return ret;
+			}
+		}
 	}
 
-	ret = clk_prepare_enable(hdmi->isfr_clk);
-	if (ret) {
-		dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret);
-		return ret;
-	}
+	if (of_property_read_u32(np, "clock-iahb", &val) == 0)
+		hdmi->iahb_use = val;
+	else
+		hdmi->iahb_use = true;
 
-	hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
-	if (IS_ERR(hdmi->iahb_clk)) {
-		ret = PTR_ERR(hdmi->iahb_clk);
-		dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret);
-		goto err_isfr;
-	}
+	if (hdmi->iahb_use) {
+		hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+		if (IS_ERR(hdmi->iahb_clk)) {
+			ret = PTR_ERR(hdmi->iahb_clk);
+			dev_err(hdmi->dev,
+				 "Unable to get HDMI iahb clk: %d\n", ret);
+			goto err_isfr;
+		}
 
-	ret = clk_prepare_enable(hdmi->iahb_clk);
-	if (ret) {
-		dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret);
-		goto err_isfr;
+		ret = clk_prepare_enable(hdmi->iahb_clk);
+		if (ret) {
+			dev_err(hdmi->dev,
+				 "Cannot enable HDMI iahb clock: %d\n", ret);
+			goto err_isfr;
+		}
 	}
 
 	/* Product and revision IDs */
@@ -1786,6 +2156,13 @@
 	 */
 	hdmi_init_clk_regenerator(hdmi);
 
+	/* If DDC bus is not specified, try to register HDMI I2C bus */
+	if (!hdmi->ddc) {
+		hdmi->ddc = dw_hdmi_i2c_adapter(hdmi);
+		if (IS_ERR(hdmi->ddc))
+			hdmi->ddc = NULL;
+	}
+
 	/*
 	 * Configure registers related to HDMI interrupt
 	 * generation before registering IRQ.
@@ -1826,14 +2203,23 @@
 		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
+	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
+	if (hdmi->i2c)
+		dw_hdmi_i2c_init(hdmi);
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
 
 err_iahb:
-	clk_disable_unprepare(hdmi->iahb_clk);
+	if (hdmi->i2c)
+		i2c_del_adapter(&hdmi->i2c->adap);
+
+	if (hdmi->iahb_use)
+		clk_disable_unprepare(hdmi->iahb_clk);
 err_isfr:
-	clk_disable_unprepare(hdmi->isfr_clk);
+	if (hdmi->isfr_use)
+		clk_disable_unprepare(hdmi->isfr_clk);
 
 	return ret;
 }
@@ -1852,15 +2238,23 @@
 	hdmi->connector.funcs->destroy(&hdmi->connector);
 	hdmi->encoder->funcs->destroy(hdmi->encoder);
 
-	clk_disable_unprepare(hdmi->iahb_clk);
-	clk_disable_unprepare(hdmi->isfr_clk);
-	i2c_put_adapter(hdmi->ddc);
+	if (hdmi->iahb_use)
+		clk_disable_unprepare(hdmi->iahb_clk);
+
+	if (hdmi->isfr_use)
+		clk_disable_unprepare(hdmi->isfr_clk);
+
+	if (hdmi->i2c)
+		i2c_del_adapter(&hdmi->i2c->adap);
+	else
+		i2c_put_adapter(hdmi->ddc);
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_AUTHOR("Vladimir Zapolskiy <vladimir_zapolskiy at mentor.com>");
 MODULE_DESCRIPTION("DW HDMI transmitter driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 971ab01..8609e43 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -15,6 +15,7 @@
 config DRM_RCAR_HDMI
 	bool "R-Car DU HDMI Encoder Support"
 	depends on DRM_RCAR_DU
+	select DRM_DW_HDMI
 	help
 	  Enable support for external HDMI encoders.
 
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 827711e..7074a98 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -3,13 +3,14 @@
 		 rcar_du_encoder.o \
 		 rcar_du_group.o \
 		 rcar_du_kms.o \
-		 rcar_du_lvdscon.o \
 		 rcar_du_plane.o \
 		 rcar_du_vgacon.o
 
 rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI)	+= rcar_du_hdmicon.o \
 					   rcar_du_hdmienc.o
-rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o
+
+rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdscon.o \
+					   rcar_du_lvdsenc.o
 
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index e6eca8e..1dfb3a4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_crtc.c  --  R-Car Display Unit CRTCs
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/mutex.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -106,14 +107,70 @@
  * Hardware Setup
  */
 
+static void rcar_du_dpll_divider(struct dpll_info *dpll, unsigned int extclk,
+				 unsigned int mode_clock)
+{
+	unsigned long dpllclk;
+	unsigned long diff;
+	unsigned long n, m, fdpll;
+	bool match_flag = false;
+	bool clk_diff_set = true;
+
+	for (n = 39; n < 120; n++) {
+		for (m = 0; m < 4; m++) {
+			for (fdpll = 1; fdpll < 32; fdpll++) {
+				if (RCAR_PRR_IS_PRODUCT(H3) &&
+					(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+					/* 1/2 (FRQSEL=1) for duty rate 50% */
+					dpllclk = extclk * (n + 1) / (m + 1)
+						 / (fdpll + 1) / 2;
+				else
+					dpllclk = extclk * (n + 1) / (m + 1)
+						 / (fdpll + 1);
+				if (dpllclk >= 400000000)
+					continue;
+
+				diff = abs((long)dpllclk - (long)mode_clock);
+				if (clk_diff_set ||
+					((diff == 0) || (dpll->diff > diff))) {
+					dpll->diff = diff;
+					dpll->n = n;
+					dpll->m = m;
+					dpll->fdpll = fdpll;
+					dpll->dpllclk = dpllclk;
+
+					if (clk_diff_set)
+						clk_diff_set = false;
+
+					if (diff == 0) {
+						match_flag = true;
+						break;
+					}
+				}
+			}
+			if (match_flag)
+				break;
+		}
+		if (match_flag)
+			break;
+	}
+}
+
 static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 {
 	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
+	struct rcar_du_device *rcdu = rcrtc->group->dev;
 	unsigned long mode_clock = mode->clock * 1000;
 	unsigned long clk;
 	u32 value;
 	u32 escr;
 	u32 div;
+	u32 dpll_reg = 0;
+	struct dpll_info *dpll;
+
+	dpll = kzalloc(sizeof(*dpll), GFP_KERNEL);
+	if (dpll == NULL)
+		return;
 
 	/* Compute the clock divisor and select the internal or external dot
 	 * clock based on the requested frequency.
@@ -129,7 +186,17 @@
 		unsigned long rate;
 		u32 extdiv;
 
+		clk_set_rate(rcrtc->extclock, mode_clock);
 		extclk = clk_get_rate(rcrtc->extclock);
+
+		if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) {
+			rcar_du_dpll_divider(dpll, extclk, mode_clock);
+			extclk = dpll->dpllclk;
+			dev_dbg(rcrtc->group->dev->dev,
+				"dpllclk:%d, fdpll:%d, n:%d, m:%d, diff:%d\n",
+				 dpll->dpllclk, dpll->fdpll, dpll->n, dpll->m,
+				 dpll->diff);
+		}
 		extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
 		extdiv = clamp(extdiv, 1U, 64U) - 1;
 
@@ -140,7 +207,32 @@
 		    abs((long)rate - (long)mode_clock)) {
 			dev_dbg(rcrtc->group->dev->dev,
 				"crtc%u: using external clock\n", rcrtc->index);
-			escr = extdiv | ESCR_DCLKSEL_DCLKIN;
+			if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) {
+				if (RCAR_PRR_IS_PRODUCT(H3) &&
+					(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+					escr = ESCR_DCLKSEL_DCLKIN | 0x01;
+				else
+					escr = ESCR_DCLKSEL_DCLKIN;
+				dpll_reg =  DPLLCR_CODE | DPLLCR_M(dpll->m) |
+					DPLLCR_FDPLL(dpll->fdpll) |
+					DPLLCR_CLKE | DPLLCR_N(dpll->n) |
+					DPLLCR_STBY;
+
+				if (rcrtc->index == DU_CH_1)
+					dpll_reg |= (DPLLCR_PLCS1 |
+						DPLLCR_INCS_DPLL01_DOTCLKIN13);
+				if (rcrtc->index == DU_CH_2) {
+					dpll_reg |= (DPLLCR_PLCS0 |
+						DPLLCR_INCS_DPLL01_DOTCLKIN02);
+					if (RCAR_PRR_IS_PRODUCT(H3) &&
+					   (RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+						dpll_reg |= (0x01 << 21);
+				}
+
+				rcar_du_group_write(rcrtc->group, DPLLCR,
+								  dpll_reg);
+			} else
+				escr = extdiv | ESCR_DCLKSEL_DCLKIN;
 		}
 	}
 
@@ -453,6 +545,20 @@
 	rcrtc->started = false;
 }
 
+void rcar_du_crtc_remove_suspend(struct rcar_du_crtc *rcrtc)
+{
+	if (!rcrtc->started)
+		return;
+
+	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+
+	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
+
+	rcar_du_group_start_stop(rcrtc->group, false);
+
+	rcrtc->started = false;
+}
+
 void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
 {
 	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
@@ -649,6 +755,7 @@
 	rcrtc->mmio_offset = mmio_offsets[index];
 	rcrtc->index = index;
 	rcrtc->enabled = false;
+	rcrtc->lvds_ch = -1;
 
 	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
 		primary = &rcrtc->vsp->planes[0].plane;
@@ -687,6 +794,12 @@
 		return ret;
 	}
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(rcdu->dev, "product register init fail.\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index c7ab467..064fb48 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_crtc.h  --  R-Car Display Unit CRTCs
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -54,6 +54,15 @@
 
 	struct rcar_du_group *group;
 	struct rcar_du_vsp *vsp;
+	int lvds_ch;
+};
+
+struct dpll_info {
+	unsigned int dpllclk;
+	unsigned int diff;
+	unsigned int fdpll;
+	unsigned int n;
+	unsigned int m;
 };
 
 #define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
@@ -63,6 +72,8 @@
 	RCAR_DU_OUTPUT_DPAD1,
 	RCAR_DU_OUTPUT_LVDS0,
 	RCAR_DU_OUTPUT_LVDS1,
+	RCAR_DU_OUTPUT_HDMI0,
+	RCAR_DU_OUTPUT_HDMI1,
 	RCAR_DU_OUTPUT_TCON,
 	RCAR_DU_OUTPUT_MAX,
 };
@@ -72,6 +83,7 @@
 void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
 				   struct drm_file *file);
 void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
+void rcar_du_crtc_remove_suspend(struct rcar_du_crtc *rcrtc);
 void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
 
 void rcar_du_crtc_route_output(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 03fc576..344c7fb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_drv.c  --  R-Car Display Unit DRM driver
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -23,12 +23,20 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/rcar_du_drm.h>
+
+#include <media/vsp1.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
+#include "rcar_du_hdmicon.h"
+#include "rcar_du_hdmienc.h"
 #include "rcar_du_kms.h"
+#include "rcar_du_lvdsenc.h"
 #include "rcar_du_regs.h"
 
 /* -----------------------------------------------------------------------------
@@ -55,6 +63,7 @@
 		},
 	},
 	.num_lvds = 0,
+	.dpll_ch =  0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
@@ -84,6 +93,7 @@
 		},
 	},
 	.num_lvds = 2,
+	.dpll_ch =  0,
 };
 
 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
@@ -108,6 +118,7 @@
 		},
 	},
 	.num_lvds = 1,
+	.dpll_ch =  0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
@@ -131,6 +142,7 @@
 		},
 	},
 	.num_lvds = 0,
+	.dpll_ch =  0,
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
@@ -141,13 +153,23 @@
 	.num_crtcs = 4,
 	.routes = {
 		/* R8A7795 has one RGB output, one LVDS output and two
-		 * (currently unsupported) HDMI outputs.
+		 * HDMI outputs.
 		 */
 		[RCAR_DU_OUTPUT_DPAD0] = {
 			.possible_crtcs = BIT(3),
 			.encoder_type = DRM_MODE_ENCODER_NONE,
 			.port = 0,
 		},
+		[RCAR_DU_OUTPUT_HDMI0] = {
+			.possible_crtcs = BIT(1),
+			.encoder_type = DRM_MODE_ENCODER_TMDS,
+			.port = 1,
+		},
+		[RCAR_DU_OUTPUT_HDMI1] = {
+			.possible_crtcs = BIT(2),
+			.encoder_type = DRM_MODE_ENCODER_TMDS,
+			.port = 2,
+		},
 		[RCAR_DU_OUTPUT_LVDS0] = {
 			.possible_crtcs = BIT(0),
 			.encoder_type = DRM_MODE_ENCODER_LVDS,
@@ -155,6 +177,7 @@
 		},
 	},
 	.num_lvds = 1,
+	.dpll_ch =  BIT(1) | BIT(2),
 };
 
 static const struct of_device_id rcar_du_of_table[] = {
@@ -172,7 +195,6 @@
 /* -----------------------------------------------------------------------------
  * DRM operations
  */
-
 static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file)
 {
 	struct rcar_du_device *rcdu = dev->dev_private;
@@ -205,6 +227,37 @@
 	rcar_du_crtc_enable_vblank(&rcdu->crtcs[pipe], false);
 }
 
+int rcar_du_set_vmute(struct drm_device *dev, void *data,
+		struct drm_file *file_priv)
+{
+	struct rcar_du_vmute *vmute =
+		(struct rcar_du_vmute *)data;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+	struct rcar_du_crtc *rcrtc;
+
+	dev_dbg(dev->dev, "CRTC[%d], display:%s\n",
+		vmute->crtc_id, vmute->on ? "off":"on");
+
+	obj = drm_mode_object_find(dev, vmute->crtc_id,
+					DRM_MODE_OBJECT_CRTC);
+	if (!obj)
+		return -EINVAL;
+	crtc = obj_to_crtc(obj);
+
+	rcrtc = to_rcar_crtc(crtc);
+
+	vsp1_du_if_set_mute(rcrtc->vsp->vsp, vmute->on);
+
+	return 0;
+}
+
+static const struct drm_ioctl_desc rcar_du_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(DRM_RCAR_DU_SET_VMUTE, rcar_du_set_vmute,
+		DRM_UNLOCKED | DRM_CONTROL_ALLOW),
+};
+
+
 static const struct file_operations rcar_du_fops = {
 	.owner		= THIS_MODULE,
 	.open		= drm_open,
@@ -247,19 +300,42 @@
 	.date			= "20130110",
 	.major			= 1,
 	.minor			= 0,
+	.ioctls			= rcar_du_ioctls,
+	.num_ioctls		= ARRAY_SIZE(rcar_du_ioctls),
 };
 
 /* -----------------------------------------------------------------------------
  * Power management
  */
-
 #ifdef CONFIG_PM_SLEEP
 static int rcar_du_pm_suspend(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+	int i;
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+	struct drm_encoder *encoder;
+#endif
 
 	drm_kms_helper_poll_disable(rcdu->ddev);
-	/* TODO Suspend the CRTC */
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+	list_for_each_entry(encoder,
+		 &rcdu->ddev->mode_config.encoder_list, head) {
+		if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+			rcar_du_hdmienc_disable(encoder);
+	}
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
+	for (i = 0; i < rcdu->info->num_lvds; ++i) {
+		if (rcdu->lvds[i])
+			rcar_du_lvdsenc_stop_suspend(rcdu->lvds[i]);
+	}
+#endif
+	for (i = 0; i < rcdu->num_crtcs; ++i) {
+		if (rcdu->crtcs[i].started)
+			rcar_du_crtc_suspend(&rcdu->crtcs[i]);
+	}
 
 	return 0;
 }
@@ -267,9 +343,32 @@
 static int rcar_du_pm_resume(struct device *dev)
 {
 	struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+	struct drm_encoder *encoder;
+	int i;
 
-	/* TODO Resume the CRTC */
+	encoder = NULL;
 
+	for (i = 0; i < rcdu->num_crtcs; ++i) {
+		if (!rcdu->crtcs[i].started)
+			rcar_du_crtc_resume(&rcdu->crtcs[i]);
+	}
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
+	for (i = 0; i < rcdu->num_crtcs; ++i) {
+		if (rcdu->crtcs[i].lvds_ch >= 0)
+			rcar_du_lvdsenc_start(
+				rcdu->lvds[rcdu->crtcs[i].lvds_ch],
+				&rcdu->crtcs[i]);
+	}
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+	list_for_each_entry(encoder,
+		&rcdu->ddev->mode_config.encoder_list, head) {
+		if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+			rcar_du_hdmienc_enable(encoder);
+	}
+#endif
 	drm_kms_helper_poll_enable(rcdu->ddev);
 	return 0;
 }
@@ -282,18 +381,52 @@
 /* -----------------------------------------------------------------------------
  * Platform driver
  */
+static void rcar_du_remove_suspend(struct rcar_du_device *rcdu)
+{
+	int i;
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+	struct drm_encoder *encoder;
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+	list_for_each_entry(encoder,
+		&rcdu->ddev->mode_config.encoder_list, head) {
+		if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+			rcar_du_hdmienc_disable(encoder);
+	}
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
+	for (i = 0; i < rcdu->info->num_lvds; ++i) {
+		if (rcdu->lvds[i])
+			rcar_du_lvdsenc_stop_suspend(rcdu->lvds[i]);
+	}
+#endif
+	for (i = 0; i < rcdu->num_crtcs; ++i) {
+		if (rcdu->crtcs[i].started)
+			rcar_du_crtc_remove_suspend(&rcdu->crtcs[i]);
+	}
+}
 
 static int rcar_du_remove(struct platform_device *pdev)
 {
 	struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
 	struct drm_device *ddev = rcdu->ddev;
+	int i;
 
 	mutex_lock(&ddev->mode_config.mutex);
 	drm_connector_unplug_all(ddev);
 	mutex_unlock(&ddev->mode_config.mutex);
 
+	for (i = 0; i < rcdu->num_crtcs; ++i) {
+		if (rcdu->crtcs[i].started)
+			drm_crtc_vblank_off(&rcdu->crtcs[i].crtc);
+	}
+
 	drm_dev_unregister(ddev);
 
+	rcar_du_remove_suspend(rcdu);
+
 	if (rcdu->fbdev)
 		drm_fbdev_cma_fini(rcdu->fbdev);
 
@@ -339,8 +472,6 @@
 	rcdu->ddev = ddev;
 	ddev->dev_private = rcdu;
 
-	platform_set_drvdata(pdev, rcdu);
-
 	/* I/O resources */
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
@@ -361,6 +492,7 @@
 	/* DRM/KMS objects */
 	ret = rcar_du_modeset_init(rcdu);
 	if (ret < 0) {
+		platform_set_drvdata(pdev, rcdu);
 		dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
 		goto error;
 	}
@@ -385,6 +517,8 @@
 	if (ret < 0)
 		goto error;
 
+	platform_set_drvdata(pdev, rcdu);
+
 	DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
 
 	return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index ed35467..ebf3a55 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_drv.h  --  R-Car Display Unit DRM driver
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -67,6 +67,7 @@
 	unsigned int num_crtcs;
 	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
 	unsigned int num_lvds;
+	unsigned int dpll_ch;
 };
 
 #define RCAR_DU_MAX_CRTCS		4
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 4e939e4..bf95bef 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_encoder.c  --  R-Car Display Unit Encoder
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -119,7 +119,8 @@
 			 enum rcar_du_encoder_type type,
 			 enum rcar_du_output output,
 			 struct device_node *enc_node,
-			 struct device_node *con_node)
+			 struct device_node *con_node,
+			 const char *device_name)
 {
 	struct rcar_du_encoder *renc;
 	struct drm_encoder *encoder;
@@ -163,8 +164,12 @@
 		break;
 	}
 
+	renc->device_name = device_name;
+
 	if (type == RCAR_DU_ENCODER_HDMI) {
 		ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
+		if (of_device_is_compatible(enc_node, "rockchip,rcar-dw-hdmi"))
+			goto done;
 		if (ret < 0)
 			goto done;
 	} else {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 719b6f2a..2766dd3 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_encoder.h  --  R-Car Display Unit Encoder
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -34,6 +34,7 @@
 	enum rcar_du_output output;
 	struct rcar_du_hdmienc *hdmi;
 	struct rcar_du_lvdsenc *lvds;
+	const char *device_name;
 };
 
 #define to_rcar_encoder(e) \
@@ -56,6 +57,7 @@
 			 enum rcar_du_encoder_type type,
 			 enum rcar_du_output output,
 			 struct device_node *enc_node,
-			 struct device_node *con_node);
+			 struct device_node *con_node,
+			 const char *device_name);
 
 #endif /* __RCAR_DU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index 461662d..40b315d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -1,7 +1,7 @@
 /*
  * R-Car Display Unit HDMI Encoder
  *
- * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -13,11 +13,14 @@
 
 #include <linux/slab.h>
 
+#include <drm/bridge/dw_hdmi.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_encoder_slave.h>
 
+#include <linux/of_platform.h>
+
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_hdmienc.h"
@@ -27,17 +30,23 @@
 	struct rcar_du_encoder *renc;
 	struct device *dev;
 	bool enabled;
+	unsigned int index;
 };
 
 #define to_rcar_hdmienc(e)	(to_rcar_encoder(e)->hdmi)
 #define to_slave_funcs(e)	(to_rcar_encoder(e)->slave.slave_funcs)
 
-static void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
+void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
 {
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
-	if (sfuncs->dpms)
+	const struct drm_bridge_funcs *bfuncs = encoder->bridge->funcs;
+
+	if ((bfuncs) && (bfuncs->post_disable))
+		bfuncs->post_disable(encoder->bridge);
+
+	if ((sfuncs) && (sfuncs->dpms))
 		sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
 
 	if (hdmienc->renc->lvds)
@@ -47,16 +56,20 @@
 	hdmienc->enabled = false;
 }
 
-static void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
+void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
 {
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+	const struct drm_bridge_funcs *bfuncs = encoder->bridge->funcs;
 
 	if (hdmienc->renc->lvds)
 		rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
 				       true);
 
-	if (sfuncs->dpms)
+	if ((bfuncs) && (bfuncs->enable))
+		bfuncs->enable(encoder->bridge);
+
+	if ((sfuncs) && (sfuncs->dpms))
 		sfuncs->dpms(encoder, DRM_MODE_DPMS_ON);
 
 	hdmienc->enabled = true;
@@ -68,17 +81,26 @@
 {
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+	const struct drm_bridge_funcs *bfuncs = encoder->bridge->funcs;
 	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
 	const struct drm_display_mode *mode = &crtc_state->mode;
+	int ret = 0;
 
 	if (hdmienc->renc->lvds)
 		rcar_du_lvdsenc_atomic_check(hdmienc->renc->lvds,
 					     adjusted_mode);
 
-	if (sfuncs->mode_fixup == NULL)
+	if ((sfuncs) && (sfuncs->mode_fixup == NULL))
 		return 0;
 
-	return sfuncs->mode_fixup(encoder, mode, adjusted_mode) ? 0 : -EINVAL;
+	if ((sfuncs) && (sfuncs->mode_fixup))
+		ret = sfuncs->mode_fixup(encoder, mode,
+				adjusted_mode) ? 0 : -EINVAL;
+
+	if ((bfuncs) && (bfuncs->mode_fixup))
+		ret = bfuncs->mode_fixup(encoder->bridge, mode,
+				adjusted_mode) ? 0 : -EINVAL;
+	return ret;
 }
 
 static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
@@ -87,10 +109,14 @@
 {
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	const struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+	const struct drm_bridge_funcs *bfuncs = encoder->bridge->funcs;
 
-	if (sfuncs->mode_set)
+	if ((sfuncs) && (sfuncs->mode_set))
 		sfuncs->mode_set(encoder, mode, adjusted_mode);
 
+	if ((bfuncs) && (bfuncs->mode_set))
+		bfuncs->mode_set(encoder->bridge, mode, adjusted_mode);
+
 	rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output);
 }
 
@@ -116,6 +142,139 @@
 	.destroy = rcar_du_hdmienc_cleanup,
 };
 
+static const struct dw_hdmi_mpll_config rcar_du_hdmienc_mpll_cfg[] = {
+	{
+		44900000, {
+			{ 0x0003, 0x0000},
+			{ 0x0003, 0x0000},
+			{ 0x0003, 0x0000}
+		},
+	}, {
+		90000000, {
+			{ 0x0002, 0x0000},
+			{ 0x0002, 0x0000},
+			{ 0x0002, 0x0000}
+		},
+	}, {
+		182750000, {
+			{ 0x0001, 0x0000},
+			{ 0x0001, 0x0000},
+			{ 0x0001, 0x0000}
+		},
+	}, {
+		297000000, {
+			{ 0x0000, 0x0000},
+			{ 0x0000, 0x0000},
+			{ 0x0000, 0x0000}
+		},
+	}, {
+		~0UL, {
+			{ 0xFFFF, 0xFFFF },
+			{ 0xFFFF, 0xFFFF },
+			{ 0xFFFF, 0xFFFF },
+		},
+	}
+};
+static const struct dw_hdmi_curr_ctrl rcar_du_hdmienc_cur_ctr[] = {
+	/*      pixelclk    bpp8    bpp10   bpp12 */
+	{
+		35500000,  { 0x0344, 0x0000, 0x0000 },
+	}, {
+		44900000,  { 0x0285, 0x0000, 0x0000 },
+	}, {
+		71000000,  { 0x1184, 0x0000, 0x0000 },
+	}, {
+		90000000,  { 0x1144, 0x0000, 0x0000 },
+	}, {
+		140250000, { 0x20c4, 0x0000, 0x0000 },
+	}, {
+		182750000, { 0x2084, 0x0000, 0x0000 },
+	}, {
+		297000000, { 0x0084, 0x0000, 0x0000 },
+	}, {
+		~0UL,      { 0x0000, 0x0000, 0x0000 },
+	}
+};
+
+static const struct dw_hdmi_multi_div rcar_du_hdmienc_multi_div[] = {
+	/*      pixelclk    bpp8    bpp10   bpp12 */
+	{
+		35500000,  { 0x0328, 0x0000, 0x0000 },
+	}, {
+		44900000,  { 0x0128, 0x0000, 0x0000 },
+	}, {
+		71000000,  { 0x0314, 0x0000, 0x0000 },
+	}, {
+		90000000,  { 0x0114, 0x0000, 0x0000 },
+	}, {
+		140250000, { 0x030a, 0x0000, 0x0000 },
+	}, {
+		182750000, { 0x010a, 0x0000, 0x0000 },
+	}, {
+		281250000, { 0x0305, 0x0000, 0x0000 },
+	}, {
+		297000000, { 0x0105, 0x0000, 0x0000 },
+	}, {
+		~0UL,      { 0x0000, 0x0000, 0x0000 },
+	}
+};
+
+static const struct dw_hdmi_phy_config rcar_du_hdmienc_phy_config[] = {
+	/*pixelclk   symbol   term   vlev*/
+	{ 74250000,  0x8009, 0x0004, 0x0272},
+	{ 148500000, 0x802b, 0x0004, 0x028d},
+	{ 297000000, 0x8039, 0x0005, 0x028d},
+	{ ~0UL,	     0x0000, 0x0000, 0x0000}
+};
+
+static enum drm_mode_status
+rcar_du_hdmienc_mode_valid(struct drm_connector *connector,
+			    struct drm_display_mode *mode)
+{
+	if ((mode->hdisplay > 3840) || (mode->vdisplay > 2160))
+		return MODE_BAD;
+
+	if (((mode->hdisplay == 3840) && (mode->vdisplay == 2160))
+		&& (mode->vrefresh > 30))
+		return MODE_BAD;
+
+	if (mode->clock > 297000)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static const struct dw_hdmi_plat_data rcar_du_hdmienc_hdmi0_drv_data = {
+	.mode_valid = rcar_du_hdmienc_mode_valid,
+	.mpll_cfg   = rcar_du_hdmienc_mpll_cfg,
+	.cur_ctr    = rcar_du_hdmienc_cur_ctr,
+	.multi_div  = rcar_du_hdmienc_multi_div,
+	.phy_config = rcar_du_hdmienc_phy_config,
+	.dev_type   = RCAR_HDMI,
+	.index      = 0,
+};
+
+static const struct dw_hdmi_plat_data rcar_du_hdmienc_hdmi1_drv_data = {
+	.mode_valid = rcar_du_hdmienc_mode_valid,
+	.mpll_cfg   = rcar_du_hdmienc_mpll_cfg,
+	.cur_ctr    = rcar_du_hdmienc_cur_ctr,
+	.multi_div  = rcar_du_hdmienc_multi_div,
+	.phy_config = rcar_du_hdmienc_phy_config,
+	.dev_type   = RCAR_HDMI,
+	.index      = 1,
+};
+
+static const struct of_device_id rcar_du_hdmienc_dt_ids[] = {
+	{
+		.data = &rcar_du_hdmienc_hdmi0_drv_data
+	},
+	{
+		.data = &rcar_du_hdmienc_hdmi1_drv_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_du_hdmienc_dt_ids);
+
 int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
 			 struct rcar_du_encoder *renc, struct device_node *np)
 {
@@ -123,37 +282,71 @@
 	struct drm_i2c_encoder_driver *driver;
 	struct i2c_client *i2c_slave;
 	struct rcar_du_hdmienc *hdmienc;
-	int ret;
+	struct resource *iores;
+	struct platform_device *pdev;
+	const struct dw_hdmi_plat_data *plat_data;
+	int ret, irq;
+	bool dw_hdmi_use = false;
 
 	hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);
 	if (hdmienc == NULL)
 		return -ENOMEM;
 
-	/* Locate the slave I2C device and driver. */
-	i2c_slave = of_find_i2c_device_by_node(np);
-	if (!i2c_slave || !i2c_get_clientdata(i2c_slave)) {
-		dev_dbg(rcdu->dev,
-			"can't get I2C slave for %s, deferring probe\n",
-			of_node_full_name(np));
-		return -EPROBE_DEFER;
+	if (strcmp(renc->device_name, "rockchip,rcar-dw-hdmi") == 0)
+		dw_hdmi_use = true;
+
+	if (dw_hdmi_use) {
+		if (renc->output == RCAR_DU_OUTPUT_HDMI0)
+			hdmienc->index = 0;
+		else if (renc->output == RCAR_DU_OUTPUT_HDMI1)
+			hdmienc->index = 1;
+		else
+			return -EINVAL;
+
+		np = of_parse_phandle(rcdu->dev->of_node, "hdmi",
+							hdmienc->index);
+		if (!np) {
+			dev_err(rcdu->dev, "hdmi node not found\n");
+			return -ENXIO;
+		}
+
+		pdev = of_find_device_by_node(np);
+		of_node_put(np);
+		if (!pdev)
+			return -ENXIO;
+
+		plat_data = rcar_du_hdmienc_dt_ids[hdmienc->index].data;
+		hdmienc->dev = &pdev->dev;
+
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0)
+			return irq;
+
+		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!iores)
+			return -ENXIO;
+
+	} else {
+		/* Locate the slave I2C device and driver. */
+		i2c_slave = of_find_i2c_device_by_node(np);
+		if (!i2c_slave || !i2c_get_clientdata(i2c_slave))
+			return -EPROBE_DEFER;
+
+		hdmienc->dev = &i2c_slave->dev;
+
+		if (hdmienc->dev->driver == NULL) {
+			ret = -EPROBE_DEFER;
+			goto error;
+		}
+
+		/* Initialize the slave encoder. */
+		driver = to_drm_i2c_encoder_driver
+			(to_i2c_driver(hdmienc->dev->driver));
+		ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave);
+		if (ret < 0)
+			goto error;
 	}
 
-	hdmienc->dev = &i2c_slave->dev;
-
-	if (hdmienc->dev->driver == NULL) {
-		dev_dbg(rcdu->dev,
-			"I2C slave %s not probed yet, deferring probe\n",
-			dev_name(hdmienc->dev));
-		ret = -EPROBE_DEFER;
-		goto error;
-	}
-
-	/* Initialize the slave encoder. */
-	driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver));
-	ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave);
-	if (ret < 0)
-		goto error;
-
 	ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
 			       DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret < 0)
@@ -164,7 +357,11 @@
 	renc->hdmi = hdmienc;
 	hdmienc->renc = renc;
 
-	return 0;
+	if (dw_hdmi_use)
+		ret = dw_hdmi_bind(rcdu->dev, NULL, rcdu->ddev, encoder,
+				iores, irq, plat_data);
+
+	return ret;
 
 error:
 	put_device(hdmienc->dev);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h
index 2ff0128..ad32651 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h
@@ -1,7 +1,7 @@
 /*
  * R-Car Display Unit HDMI Encoder
  *
- * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -23,6 +23,8 @@
 #if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
 int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
 			 struct rcar_du_encoder *renc, struct device_node *np);
+void rcar_du_hdmienc_disable(struct drm_encoder *encoder);
+void rcar_du_hdmienc_enable(struct drm_encoder *encoder);
 #else
 static inline int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
 				       struct rcar_du_encoder *renc,
@@ -30,6 +32,12 @@
 {
 	return -ENOSYS;
 }
+static inline void rcar_du_hdmienc_disable(struct drm_encoder *encoder)
+{
+}
+static inline void rcar_du_hdmienc_enable(struct drm_encoder *encoder)
+{
+}
 #endif
 
 #endif /* __RCAR_DU_HDMIENC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 7d65251..c52ee77 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_kms.c  --  R-Car Display Unit Mode Setting
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -96,6 +96,40 @@
 		.planes = 2,
 		.pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
 		.edf = PnDDCR4_EDF_NONE,
+	}, {
+		.fourcc = DRM_FORMAT_NV61,
+		.bpp = 16,
+		.planes = 2,
+		.pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+		.edf = PnDDCR4_EDF_NONE,
+	},
+};
+
+static const struct rcar_du_format_info rcar_vsp_format_infos[] = {
+	{
+		.fourcc = DRM_FORMAT_RGB332,
+		.bpp = 8,
+	}, {
+		.fourcc = DRM_FORMAT_ARGB4444,
+		.bpp = 16,
+	}, {
+		.fourcc = DRM_FORMAT_XRGB4444,
+		.bpp = 16,
+	}, {
+		.fourcc = DRM_FORMAT_BGR888,
+		.bpp = 24,
+	}, {
+		.fourcc = DRM_FORMAT_RGB888,
+		.bpp = 24,
+	}, {
+		.fourcc = DRM_FORMAT_BGRA8888,
+		.bpp = 32,
+	}, {
+		.fourcc = DRM_FORMAT_BGRX8888,
+		.bpp = 32,
+	}, {
+		.fourcc = DRM_FORMAT_YVYU,
+		.bpp = 16,
 	},
 };
 
@@ -111,6 +145,18 @@
 	return NULL;
 }
 
+const struct rcar_du_format_info *rcar_vsp_format_info(u32 fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rcar_vsp_format_infos); ++i) {
+		if (rcar_vsp_format_infos[i].fourcc == fourcc)
+			return &rcar_vsp_format_infos[i];
+	}
+
+	return NULL;
+}
+
 /* -----------------------------------------------------------------------------
  * Frame buffer
  */
@@ -146,6 +192,15 @@
 	unsigned int bpp;
 
 	format = rcar_du_format_info(mode_cmd->pixel_format);
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) &&
+		(format == NULL)) {
+		format = rcar_vsp_format_info(mode_cmd->pixel_format);
+	}
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) && (format != NULL))
+		goto done;
+
 	if (format == NULL) {
 		dev_dbg(dev->dev, "unsupported pixel format %08x\n",
 			mode_cmd->pixel_format);
@@ -179,6 +234,7 @@
 		}
 	}
 
+done:
 	return drm_fb_cma_create(dev, file_priv, mode_cmd);
 }
 
@@ -329,6 +385,7 @@
 	} encoders[] = {
 		{ "adi,adv7123", RCAR_DU_ENCODER_VGA },
 		{ "adi,adv7511w", RCAR_DU_ENCODER_HDMI },
+		{ "rockchip,rcar-dw-hdmi", RCAR_DU_ENCODER_HDMI },
 		{ "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS },
 	};
 
@@ -339,6 +396,7 @@
 	struct device_node *entity_ep_node;
 	struct device_node *entity;
 	int ret;
+	const char *enc_name = NULL;
 
 	/*
 	 * Locate the connected entity and infer its type from the number of
@@ -390,6 +448,7 @@
 			if (of_device_is_compatible(encoder,
 						    encoders[i].compatible)) {
 				enc_type = encoders[i].type;
+				enc_name = encoders[i].compatible;
 				break;
 			}
 		}
@@ -410,7 +469,8 @@
 		connector = entity;
 	}
 
-	ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
+	ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector,
+					enc_name);
 	of_node_put(encoder);
 	of_node_put(connector);
 
@@ -520,8 +580,8 @@
 
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
-	dev->mode_config.max_width = 4095;
-	dev->mode_config.max_height = 2047;
+	dev->mode_config.max_width = 4096;
+	dev->mode_config.max_height = 2160;
 	dev->mode_config.funcs = &rcar_du_mode_config_funcs;
 
 	rcdu->num_crtcs = rcdu->info->num_crtcs;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
index 07951d5..14c81ba 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_kms.h  --  R-Car Display Unit Mode Setting
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -30,6 +30,7 @@
 };
 
 const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc);
+const struct rcar_du_format_info *rcar_vsp_format_info(u32 fourcc);
 
 int rcar_du_modeset_init(struct rcar_du_device *rcdu);
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
index d4881ee..3d653cb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdscon.h  --  R-Car Display Unit LVDS Connector
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -17,8 +17,17 @@
 struct rcar_du_device;
 struct rcar_du_encoder;
 
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
 				struct rcar_du_encoder *renc,
 				struct device_node *np);
+#else
+static inline int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
+				struct rcar_du_encoder *renc,
+				struct device_node *np)
+{
+	return -ENOSYS;
+}
+#endif
 
 #endif /* __RCAR_DU_LVDSCON_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index ef3a503..421554a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdsenc.c  --  R-Car Display Unit LVDS Encoder
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -31,6 +32,7 @@
 	bool enabled;
 
 	enum rcar_lvds_input input;
+	int gpio_pd;
 };
 
 static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
@@ -125,7 +127,7 @@
 			LVDCR1_CLKSTBY_GEN3);
 }
 
-static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
+int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 				 struct rcar_du_crtc *rcrtc)
 {
 	u32 lvdhcr;
@@ -134,6 +136,9 @@
 	if (lvds->enabled)
 		return 0;
 
+	if (gpio_is_valid(lvds->gpio_pd))
+		gpio_set_value(lvds->gpio_pd, 1);
+
 	ret = clk_prepare_enable(lvds->clock);
 	if (ret < 0)
 		return ret;
@@ -164,15 +169,16 @@
 	else
 		rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
 
+	rcrtc->lvds_ch = lvds->index;
 	lvds->enabled = true;
 
 	return 0;
 }
 
-static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
+int rcar_du_lvdsenc_stop_suspend(struct rcar_du_lvdsenc *lvds)
 {
 	if (!lvds->enabled)
-		return;
+		return -1;
 
 	rcar_lvds_write(lvds, LVDCR0, 0);
 	rcar_lvds_write(lvds, LVDCR1, 0);
@@ -180,6 +186,30 @@
 	clk_disable_unprepare(lvds->clock);
 
 	lvds->enabled = false;
+
+	return 0;
+}
+
+static void rcar_du_lvdsenc_stop(struct rcar_du_lvdsenc *lvds)
+{
+	int ret;
+	unsigned int i;
+
+	if (!lvds->enabled)
+		return;
+
+	ret = rcar_du_lvdsenc_stop_suspend(lvds);
+	if (ret < 0)
+		return;
+
+	for (i = 0; i < lvds->dev->num_crtcs; ++i)
+		if (lvds->index == lvds->dev->crtcs[i].lvds_ch)
+			lvds->dev->crtcs[i].lvds_ch = -1;
+
+	if (gpio_is_valid(lvds->gpio_pd))
+		gpio_set_value(lvds->gpio_pd, 0);
+
+	return;
 }
 
 int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
@@ -238,6 +268,7 @@
 	struct rcar_du_lvdsenc *lvds;
 	unsigned int i;
 	int ret;
+	char name[16];
 
 	for (i = 0; i < rcdu->info->num_lvds; ++i) {
 		lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
@@ -250,12 +281,18 @@
 		lvds->index = i;
 		lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
 		lvds->enabled = false;
+		lvds->gpio_pd = of_get_named_gpio(rcdu->dev->of_node,
+						 "backlight-pin", 0);
 
 		ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
 		if (ret < 0)
 			return ret;
 
 		rcdu->lvds[i] = lvds;
+
+		sprintf(name, "lvds%u", i);
+		devm_gpio_request_one(&pdev->dev, lvds->gpio_pd,
+					GPIOF_OUT_INIT_LOW, name);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
index dfdba74..9fcfcee 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdsenc.h  --  R-Car Display Unit LVDS Encoder
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -32,6 +32,9 @@
 			   struct drm_crtc *crtc, bool enable);
 void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
 				  struct drm_display_mode *mode);
+int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
+				 struct rcar_du_crtc *rcrtc);
+int rcar_du_lvdsenc_stop_suspend(struct rcar_du_lvdsenc *lvds);
 #else
 static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
 {
@@ -46,6 +49,15 @@
 						struct drm_display_mode *mode)
 {
 }
+static inline int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
+					struct rcar_du_crtc *rcrtc)
+{
+	return 0;
+}
+static inline int rcar_du_lvdsenc_stop_suspend(struct rcar_du_lvdsenc *lvds)
+{
+	return 0;
+}
 #endif
 
 #endif /* __RCAR_DU_LVDSENC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
index b18b7b2..a627c56 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_plane.h  --  R-Car Display Unit Planes
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -34,6 +34,11 @@
 	RCAR_DU_PLANE_VSPD1,
 };
 
+#define DU_CH_0		0
+#define DU_CH_1		1
+#define DU_CH_2		2
+#define DU_CH_3		3
+
 struct rcar_du_plane {
 	struct drm_plane plane;
 	struct rcar_du_group *group;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index d2f6606..2fc1455 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_regs.h  --  R-Car Display Unit Registers Definitions
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -276,6 +276,25 @@
 #define DEFR10_TSEL_H3_TCON1	(0 << 1) /* DEFR102 register only (DU2/DU3) */
 #define DEFR10_DEFE10		(1 << 0)
 
+#define DPLLCR			0x20044
+#define DPLLCR_CODE		(0x95 << 24)
+#define DPLLCR_PLCS1		(1 << 23)
+#define DPLLCR_PLCS0		(1 << 20)
+#define DPLLCR_CLKE		(1 << 18)
+#define DPLLCR_FDPLL(n)		((n) << 12)	/* n=0 Setting prohibited */
+/* H'00 to H'26, H'78 to H'7F: Setting prohibited.*/
+#define DPLLCR_N(n)		((n) << 5)
+#define DPLLCR_M(n)		((n) << 3)
+#define DPLLCR_STBY		(1 << 2)
+#define DPLLCR_INCS_DPLL01_DOTCLKIN02	(0 << 0)
+#define DPLLCR_INCS_DPLL01_DOTCLKIN13	(1 << 1)
+
+#define DPLLC2R			0x20048
+#define DPLLC2R_CODE		(0x95 << 24)
+#define DPLLC2R_SELC		(1 << 12)
+#define DPLLC2R_M(n)		((n) << 8)
+#define DPLLC2R_FDPLL(n)	((n) << 0)	/* n=0 Setting prohibited */
+
 /* -----------------------------------------------------------------------------
  * Display Timing Generation Registers
  */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
index a03bab1..1279c98 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_vgacon.c  --  R-Car Display Unit VGA Connector
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -23,7 +23,7 @@
 
 static int rcar_du_vga_connector_get_modes(struct drm_connector *connector)
 {
-	return drm_add_modes_noedid(connector, 1280, 768);
+	return drm_add_modes_noedid(connector, 1024, 768);
 }
 
 static const struct drm_connector_helper_funcs connector_helper_funcs = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 24acee1..268f29f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -99,7 +99,6 @@
 	DRM_FORMAT_ARGB8888,
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_UYVY,
-	DRM_FORMAT_VYUY,
 	DRM_FORMAT_YUYV,
 	DRM_FORMAT_YVYU,
 	DRM_FORMAT_NV12,
@@ -117,12 +116,11 @@
 	V4L2_PIX_FMT_RGB565,
 	V4L2_PIX_FMT_RGB24,
 	V4L2_PIX_FMT_BGR24,
-	V4L2_PIX_FMT_ARGB32,
-	V4L2_PIX_FMT_XRGB32,
 	V4L2_PIX_FMT_ABGR32,
 	V4L2_PIX_FMT_XBGR32,
+	V4L2_PIX_FMT_ARGB32,
+	V4L2_PIX_FMT_XRGB32,
 	V4L2_PIX_FMT_UYVY,
-	V4L2_PIX_FMT_VYUY,
 	V4L2_PIX_FMT_YUYV,
 	V4L2_PIX_FMT_YVYU,
 	V4L2_PIX_FMT_NV12M,
@@ -171,7 +169,7 @@
 	WARN_ON(!pixelformat);
 
 	vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat,
-			      fb->pitches[0], paddr, &src, &dst);
+			      fb->pitches[0], paddr, &src, &dst, state->alpha);
 }
 
 static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
@@ -193,6 +191,11 @@
 	}
 
 	rstate->format = rcar_du_format_info(state->fb->pixel_format);
+
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) &&
+			 (rstate->format == NULL))
+		rstate->format = rcar_vsp_format_info(state->fb->pixel_format);
+
 	if (rstate->format == NULL) {
 		dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
 			state->fb->pixel_format);
@@ -211,7 +214,7 @@
 		rcar_du_vsp_plane_setup(rplane);
 	else
 		vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0,
-				      NULL, NULL);
+				      NULL, NULL, 255);
 }
 
 static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 1abeadc..6c32d90 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -680,9 +680,30 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rcar_i2c_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_i2c_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_i2c_pm_ops,
+			rcar_i2c_suspend, rcar_i2c_resume);
+#define DEV_PM_OPS (&rcar_i2c_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rcar_i2c_driver = {
 	.driver	= {
 		.name	= "i2c-rcar",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = rcar_i2c_dt_ids,
 	},
 	.probe		= rcar_i2c_probe,
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 7d2bd3e..522d79a 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -1013,7 +1013,27 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sh_mobile_i2c_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int sh_mobile_i2c_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+#else
+#define sh_mobile_i2c_suspend	NULL
+#define sh_mobile_i2c_resume	NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
+	.suspend = sh_mobile_i2c_suspend,
+	.resume = sh_mobile_i2c_resume,
 	.runtime_suspend = sh_mobile_i2c_runtime_nop,
 	.runtime_resume = sh_mobile_i2c_runtime_nop,
 };
@@ -1032,7 +1052,7 @@
 {
 	return platform_driver_register(&sh_mobile_i2c_driver);
 }
-subsys_initcall(sh_mobile_i2c_adap_init);
+subsys_initcall_sync(sh_mobile_i2c_adap_init);
 
 static void __exit sh_mobile_i2c_adap_exit(void)
 {
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 993dc50..19acc7d 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -204,6 +204,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called adv7183.
 
+config VIDEO_ADV7482
+	tristate "Analog Devices ADV7482 HDMI receiver and video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Analog Devices ADV7482 HDMI receiver.
+	  Support for the Analog Devices ADV7482 video decoder.
+	  Video capture data is the HD digital signal that is
+	  received by the Analog Devices ADV7482 HDMI receiver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7482.
+
 config VIDEO_ADV7604
 	tristate "Analog Devices ADV7604 decoder"
 	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 94f2c99..a39ee28 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
 obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
+obj-$(CONFIG_VIDEO_ADV7482) += adv7482.o
 obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
 obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
 obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
diff --git a/drivers/media/i2c/adv7482.c b/drivers/media/i2c/adv7482.c
new file mode 100644
index 0000000..a59ab90
--- /dev/null
+++ b/drivers/media/i2c/adv7482.c
@@ -0,0 +1,2118 @@
+/*
+ * drivers/media/i2c/adv7482.c
+ *     This file is Analog Devices ADV7482 HDMI receiver driver.
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
+#include <linux/mutex.h>
+#include <media/soc_camera.h>
+
+#include <linux/delay.h>  /* for msleep() */
+
+#define DRIVER_NAME "adv7482"
+
+/****************************************/
+/* ADV7482 I2C slave address definition */
+/****************************************/
+#define ADV7482_I2C_IO			0x70	/* IO Map */
+#define ADV7482_I2C_DPLL		0x26	/* DPLL Map */
+#define ADV7482_I2C_CP			0x22	/* CP Map */
+#define ADV7482_I2C_HDMI		0x34	/* HDMI Map */
+#define ADV7482_I2C_EDID		0x36	/* EDID Map */
+#define ADV7482_I2C_REPEATER		0x32	/* HDMI RX Repeater Map */
+#define ADV7482_I2C_INFOFRAME		0x31	/* HDMI RX InfoFrame Map */
+#define ADV7482_I2C_CEC			0x41	/* CEC Map */
+#define ADV7482_I2C_SDP			0x79	/* SDP Map */
+#define ADV7482_I2C_TXB			0x48	/* CSI-TXB Map */
+#define ADV7482_I2C_TXA			0x4A	/* CSI-TXA Map */
+#define ADV7482_I2C_WAIT		0xFE	/* Wait x mesec */
+#define ADV7482_I2C_EOR			0xFF	/* End Mark */
+
+/****************************************/
+/* ADV7482 IO register definition       */
+/****************************************/
+
+/* Revision */
+#define ADV7482_IO_RD_INFO1_REG	0xDF	/* chip version register */
+#define ADV7482_IO_RD_INFO2_REG	0xE0	/* chip version register */
+
+#define ADV7482_IO_CP_DATAPATH_REG	0x03	/* datapath ctrl */
+#define ADV7482_IO_CP_COLORSPACE_REG	0x04
+#define ADV7482_IO_CP_VID_STD_REG	0x05	/* Video Standard */
+
+/* Power Management */
+#define ADV7482_IO_PWR_MAN_REG	0x0C	/* Power management register */
+#define ADV7482_IO_PWR_ON		0xE0	/* Power on */
+#define ADV7482_IO_PWR_OFF		0x00	/* Power down */
+
+#define ADV7482_HDMI_DDC_PWRDN	0x73	/* Power DDC pads control register */
+#define ADV7482_HDMI_DDC_PWR_ON		0x00	/* Power on */
+#define ADV7482_HDMI_DDC_PWR_OFF	0x01	/* Power down */
+
+#define ADV7482_IO_CP_VID_STD_480I	0x40
+#define ADV7482_IO_CP_VID_STD_576I	0x41
+#define ADV7482_IO_CP_VID_STD_480P	0x4A
+#define ADV7482_IO_CP_VID_STD_576P	0x4B
+#define ADV7482_IO_CP_VID_STD_720P	0x53
+#define ADV7482_IO_CP_VID_STD_1080I	0x54
+#define ADV7482_IO_CP_VID_STD_1080P	0x5E
+#define ADV7482_IO_CP_VID_STD_SVGA56	0x80
+#define ADV7482_IO_CP_VID_STD_SVGA60	0x81
+#define ADV7482_IO_CP_VID_STD_SVGA72	0x82
+#define ADV7482_IO_CP_VID_STD_SVGA75	0x83
+#define ADV7482_IO_CP_VID_STD_SVGA85	0x84
+#define ADV7482_IO_CP_VID_STD_SXGA60	0x85
+#define ADV7482_IO_CP_VID_STD_SXGA75	0x86
+#define ADV7482_IO_CP_VID_STD_VGA60	0x88
+#define ADV7482_IO_CP_VID_STD_VGA72	0x89
+#define ADV7482_IO_CP_VID_STD_VGA75	0x8A
+#define ADV7482_IO_CP_VID_STD_VGA85	0x8B
+#define ADV7482_IO_CP_VID_STD_XGA60	0x8C
+#define ADV7482_IO_CP_VID_STD_XGA70	0x8D
+#define ADV7482_IO_CP_VID_STD_XGA75	0x8E
+#define ADV7482_IO_CP_VID_STD_XGA85	0x8F
+#define ADV7482_IO_CP_VID_STD_UXGA60	0x96
+
+#define ADV7482_IO_CSI4_EN_ENABLE       0x80
+#define ADV7482_IO_CSI4_EN_DISABLE      0x00
+
+#define ADV7482_IO_CSI1_EN_ENABLE       0x40
+#define ADV7482_IO_CSI1_EN_DISABLE      0x00
+
+/****************************************/
+/* ADV7482 CP register definition       */
+/****************************************/
+
+/* Contrast Control */
+#define ADV7482_CP_CON_REG	0x3a	/* Contrast (unsigned) */
+#define ADV7482_CP_CON_MIN	0	/* Minimum contrast */
+#define ADV7482_CP_CON_DEF	128	/* Default */
+#define ADV7482_CP_CON_MAX	255	/* Maximum contrast */
+
+/* Saturation Control */
+#define ADV7482_CP_SAT_REG	0x3b	/* Saturation (unsigned) */
+#define ADV7482_CP_SAT_MIN	0	/* Minimum saturation */
+#define ADV7482_CP_SAT_DEF	128	/* Default */
+#define ADV7482_CP_SAT_MAX	255	/* Maximum saturation */
+
+/* Brightness Control */
+#define ADV7482_CP_BRI_REG	0x3c	/* Brightness (signed) */
+#define ADV7482_CP_BRI_MIN	-128	/* Luma is -512d */
+#define ADV7482_CP_BRI_DEF	0	/* Luma is 0 */
+#define ADV7482_CP_BRI_MAX	127	/* Luma is 508d */
+
+/* Hue Control */
+#define ADV7482_CP_HUE_REG	0x3d	/* Hue (unsigned) */
+#define ADV7482_CP_HUE_MIN	0	/* -90 degree */
+#define ADV7482_CP_HUE_DEF	0	/* -90 degree */
+#define ADV7482_CP_HUE_MAX	255	/* +90 degree */
+
+/* Video adjustment register */
+#define ADV7482_CP_VID_ADJ_REG		0x3e
+/* Video adjustment mask */
+#define ADV7482_CP_VID_ADJ_MASK		0x7F
+/* Enable color controls */
+#define ADV7482_CP_VID_ADJ_ENABLE	0x80
+
+/****************************************/
+/* ADV7482 HDMI register definition     */
+/****************************************/
+
+/* HDMI status register */
+#define ADV7482_HDMI_STATUS1_REG		0x07
+/* VERT_FILTER_LOCKED flag */
+#define ADV7482_HDMI_VF_LOCKED_FLG		0x80
+/* DE_REGEN_FILTER_LOCKED flag */
+#define ADV7482_HDMI_DERF_LOCKED_FLG		0x20
+/* LINE_WIDTH[12:8] mask */
+#define ADV7482_HDMI_LWIDTH_MSBS_MASK		0x1F
+
+/* LINE_WIDTH[7:0] register */
+#define ADV7482_HDMI_LWIDTH_REG			0x08
+
+/* FIELD0_HEIGHT[12:8] register */
+#define ADV7482_HDMI_F0HEIGHT_MSBS_REG		0x09
+/* FIELD0_HEIGHT[12:8] mask */
+#define ADV7482_HDMI_F0HEIGHT_MSBS_MASK		0x1F
+
+/* FIELD0_HEIGHT[7:0] register */
+#define ADV7482_HDMI_F0HEIGHT_LSBS_REG		0x0A
+
+/* HDMI status register */
+#define ADV7482_HDMI_STATUS2_REG		0x0B
+/* DEEP_COLOR_MODE[1:0] mask */
+#define ADV7482_HDMI_DCM_MASK			0xC0
+/* HDMI_INTERLACED flag */
+#define ADV7482_HDMI_IP_FLAG			0x20
+/* FIELD1_HEIGHT[12:8] mask */
+#define ADV7482_HDMI_F1HEIGHT_MSBS_MASK		0x1F
+
+/* FIELD1_HEIGHT[7:0] register */
+#define ADV7482_HDMI_F1HEIGHT_REG		0x0C
+
+struct adv7482_sdp_main_info {
+	u8			status_reg_10;
+};
+
+/****************************************/
+/* ADV7482 SDP register definition      */
+/****************************************/
+
+#define ADV7482_SDP_MAIN_MAP	0x00
+#define ADV7482_SDP_SUB_MAP1	0x20
+#define ADV7482_SDP_SUB_MAP2	0x40
+
+#define ADV7482_SDP_NO_RO_MAIN_MAP	0x00
+#define ADV7482_SDP_RO_MAIN_MAP		0x01
+#define ADV7482_SDP_RO_SUB_MAP1		0x02
+#define ADV7482_SDP_RO_SUB_MAP2		0x03
+
+#define ADV7482_SDP_MAIN_MAP_RW \
+			(ADV7482_SDP_MAIN_MAP | ADV7482_SDP_NO_RO_MAIN_MAP)
+
+#define ADV7482_SDP_STD_AD_PAL_BG_NTSC_J_SECAM		0x0
+#define ADV7482_SDP_STD_AD_PAL_BG_NTSC_J_SECAM_PED	0x1
+#define ADV7482_SDP_STD_AD_PAL_N_NTSC_J_SECAM		0x2
+#define ADV7482_SDP_STD_AD_PAL_N_NTSC_M_SECAM		0x3
+#define ADV7482_SDP_STD_NTSC_J				0x4
+#define ADV7482_SDP_STD_NTSC_M				0x5
+#define ADV7482_SDP_STD_PAL60				0x6
+#define ADV7482_SDP_STD_NTSC_443			0x7
+#define ADV7482_SDP_STD_PAL_BG				0x8
+#define ADV7482_SDP_STD_PAL_N				0x9
+#define ADV7482_SDP_STD_PAL_M				0xa
+#define ADV7482_SDP_STD_PAL_M_PED			0xb
+#define ADV7482_SDP_STD_PAL_COMB_N			0xc
+#define ADV7482_SDP_STD_PAL_COMB_N_PED			0xd
+#define ADV7482_SDP_STD_PAL_SECAM			0xe
+#define ADV7482_SDP_STD_PAL_SECAM_PED			0xf
+
+#define ADV7482_SDP_REG_INPUT_CONTROL		0x00
+#define ADV7482_SDP_INPUT_CONTROL_INSEL_MASK	0x0f
+
+#define ADV7482_SDP_REG_INPUT_VIDSEL		0x02
+
+#define ADV7482_SDP_REG_CTRL			0x0e
+
+#define ADV7482_SDP_REG_PWR_MAN		0x0f
+#define ADV7482_SDP_PWR_MAN_ON		0x00
+#define ADV7482_SDP_PWR_MAN_OFF		0x20
+#define ADV7482_SDP_PWR_MAN_RES		0x80
+
+/* Contrast */
+#define ADV7482_SDP_REG_CON		0x08	/*Unsigned */
+#define ADV7482_SDP_CON_MIN		0
+#define ADV7482_SDP_CON_DEF		128
+#define ADV7482_SDP_CON_MAX		255
+/* Brightness*/
+#define ADV7482_SDP_REG_BRI		0x0a	/*Signed */
+#define ADV7482_SDP_BRI_MIN		-128
+#define ADV7482_SDP_BRI_DEF		0
+#define ADV7482_SDP_BRI_MAX		127
+/* Hue */
+#define ADV7482_SDP_REG_HUE		0x0b	/*Signed, inverted */
+#define ADV7482_SDP_HUE_MIN		-127
+#define ADV7482_SDP_HUE_DEF		0
+#define ADV7482_SDP_HUE_MAX		128
+
+/* Saturation */
+#define ADV7482_SDP_REG_SD_SAT_CB	0xe3
+#define ADV7482_SDP_REG_SD_SAT_CR	0xe4
+#define ADV7482_SDP_SAT_MIN		0
+#define ADV7482_SDP_SAT_DEF		128
+#define ADV7482_SDP_SAT_MAX		255
+
+#define ADV7482_SDP_INPUT_CVBS_AIN1		0x00
+#define ADV7482_SDP_INPUT_CVBS_AIN2		0x01
+#define ADV7482_SDP_INPUT_CVBS_AIN3		0x02
+#define ADV7482_SDP_INPUT_CVBS_AIN4		0x03
+#define ADV7482_SDP_INPUT_CVBS_AIN5		0x04
+#define ADV7482_SDP_INPUT_CVBS_AIN6		0x05
+#define ADV7482_SDP_INPUT_CVBS_AIN7		0x06
+#define ADV7482_SDP_INPUT_CVBS_AIN8		0x07
+#define ADV7482_SDP_INPUT_SVIDEO_AIN1_AIN2	0x08
+#define ADV7482_SDP_INPUT_SVIDEO_AIN3_AIN4	0x09
+#define ADV7482_SDP_INPUT_SVIDEO_AIN5_AIN6	0x0a
+#define ADV7482_SDP_INPUT_SVIDEO_AIN7_AIN8	0x0b
+#define ADV7482_SDP_INPUT_YPRPB_AIN1_AIN2_AIN3	0x0c
+#define ADV7482_SDP_INPUT_YPRPB_AIN4_AIN5_AIN6	0x0d
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN1_AIN2	0x0e
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN3_AIN4	0x0f
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN5_AIN6	0x10
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN7_AIN8	0x11
+
+#define ADV7482_SDP_R_REG_10			0x10
+#define ADV7482_SDP_R_REG_10_IN_LOCK		0x01
+#define ADV7482_SDP_R_REG_10_FSC_LOCK		0x04
+
+#define ADV7482_SDP_R_REG_10_AUTOD_MASK		0x70
+#define ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J	0x00
+#define ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43	0x10
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_M	0x20
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_60	0x30
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G	0x40
+#define ADV7482_SDP_R_REG_10_AUTOD_SECAM	0x50
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB	0x60
+#define ADV7482_SDP_R_REG_10_AUTOD_SECAM_525	0x70
+
+#define ADV7482_MAX_WIDTH		1920
+#define ADV7482_MAX_HEIGHT		1080
+
+/****************************************/
+/* ADV7482 structure definition         */
+/****************************************/
+
+/* Structure for register values */
+struct adv7482_reg_value {
+	u8 addr;				/* i2c slave address */
+	u8 reg;					/* sub (register) address */
+	u8 value;				/* register value */
+};
+
+#define END_REGISTER_TABLE \
+{ADV7482_I2C_EOR, 0xFF, 0xFF} /* End of register table */
+
+/* Register default values */
+
+static const struct adv7482_reg_value adv7482_sw_reset[] = {
+
+	{ADV7482_I2C_IO, 0xFF, 0xFF},	/* SW reset */
+	{ADV7482_I2C_WAIT, 0x00, 0x05},	/* delay 5 */
+	{ADV7482_I2C_IO, 0x01, 0x76},	/* ADI Required Write */
+	{ADV7482_I2C_IO, 0xF2, 0x01},	/* Enable I2C Read Auto-Increment */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_slave_address[] = {
+
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+/* Supported Formats For Script Below */
+/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */
+static const struct adv7482_reg_value adv7482_init_txa_4lane[] = {
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	/* Disable chip powerdown & Enable HDMI Rx block */
+	{ADV7482_I2C_IO, 0x00, 0x40},
+
+	{ADV7482_I2C_REPEATER, 0x40, 0x83},	/* Enable HDCP 1.1 */
+
+	{ADV7482_I2C_HDMI, 0x00, 0x08},	/* Foreground Channel = A */
+	{ADV7482_I2C_HDMI, 0x98, 0xFF},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x99, 0xA3},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9A, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9B, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9D, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0xCB, 0x09},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3D, 0x10},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3E, 0x7B},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3F, 0x5E},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x4E, 0xFE},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x4F, 0x18},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x57, 0xA3},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x58, 0x04},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x85, 0x10},	/* ADI Required Write */
+
+	{ADV7482_I2C_HDMI, 0x83, 0x00},	/* Enable All Terminations */
+	{ADV7482_I2C_HDMI, 0xA3, 0x01},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0xBE, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_HDMI, 0x6C, 0x01},	/* HPA Manual Enable */
+	{ADV7482_I2C_HDMI, 0xF8, 0x01},	/* HPA Asserted */
+	{ADV7482_I2C_HDMI, 0x0F, 0x00},	/* Audio Mute Speed Set to Fastest */
+					/* (Smallest Step Size) */
+
+	{ADV7482_I2C_IO, 0x04, 0x02},	/* RGB Out of CP */
+	{ADV7482_I2C_IO, 0x12, 0xF0},
+		/* CSC Depends on ip Packets - SDR 444 */
+	{ADV7482_I2C_IO, 0x17, 0x80},
+		/* Luma & Chroma Values Can Reach 254d */
+	{ADV7482_I2C_IO, 0x03, 0x86},	/* CP-Insert_AV_Code */
+
+	{ADV7482_I2C_CP, 0x7C, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_IO, 0x0C, 0xE0},	/* Enable LLC_DLL & Double LLC Timing */
+	{ADV7482_I2C_IO, 0x0E, 0xDD},	/* LLC/PIX/SPI PINS TRISTATED AUD */
+					/* Outputs Enabled */
+	{ADV7482_I2C_IO, 0x10, 0xA0},	/* Enable 4-lane CSI Tx & Pixel Port */
+
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0x00, 0xA4},	/* Set Auto DPHY Timing */
+	{ADV7482_I2C_TXA, 0xDB, 0x10},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD6, 0x07},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC4, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x71, 0x33},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x72, 0x11},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xF0, 0x00},	/* i2c_dphy_pwdn - 1'b0 */
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXA, 0x00, 0x24 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0x31, 0x80},	/* ADI Required Write */
+
+	/* for debug */
+#ifdef REL_DGB_FORCE_TO_SEND_COLORBAR
+	{ADV7482_I2C_CP, 0x37, 0x81},	/* Output Colorbars Pattern */
+#endif
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+/* 02-01 Analog CVBS to MIPI TX-B CSI 1-Lane - */
+/* Autodetect CVBS Single Ended In Ain 1 - MIPI Out */
+static const struct adv7482_reg_value adv7482_init_txb_1lane[] = {
+
+	{ADV7482_I2C_IO, 0x00, 0x30},
+		/* Disable chip powerdown - powerdown Rx */
+	{ADV7482_I2C_IO, 0xF2, 0x01},	/* Enable I2C Read Auto-Increment */
+
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	{ADV7482_I2C_IO, 0x0E, 0xFF},	/* LLC/PIX/AUD/SPI PINS TRISTATED */
+
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_PWR_MAN, ADV7482_SDP_PWR_MAN_ON},
+		/* Exit Power Down Mode */
+	{ADV7482_I2C_SDP, 0x52, 0xCD},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_INPUT_CONTROL,
+		ADV7482_SDP_INPUT_CVBS_AIN8},	/* INSEL = CVBS in on Ain 8 */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_CTRL, 0x80},
+		/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x9C, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x9C, 0xFF},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_CTRL, ADV7482_SDP_MAIN_MAP_RW},
+		/* ADI Required Write */
+
+	/* ADI recommended writes for improved video quality */
+	{ADV7482_I2C_SDP, 0x80, 0x51},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x81, 0x51},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x82, 0x68},	/* ADI Required Write */
+
+	{ADV7482_I2C_SDP, 0x03, 0x42},
+		/* Tri-S Output Drivers, PwrDwn 656 pads */
+	{ADV7482_I2C_SDP, 0x04, 0xB5},	/* ITU-R BT.656-4 compatible */
+	{ADV7482_I2C_SDP, 0x13, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_SDP, 0x17, 0x41},	/* Select SH1 */
+	{ADV7482_I2C_SDP, 0x31, 0x12},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0xE6, 0x4F},
+		/* Set V bit end position manually in NTSC mode */
+
+#ifdef REL_DGB_FORCE_TO_SEND_COLORBAR
+	{ADV7482_I2C_SDP, 0x0C, 0x01},	/* ColorBar */
+	{ADV7482_I2C_SDP, 0x14, 0x01},	/* ColorBar */
+#endif
+	/* Enable 1-Lane MIPI Tx, */
+	/* enable pixel output and route SD through Pixel port */
+	{ADV7482_I2C_IO, 0x10, 0x70},
+
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 1-lane MIPI */
+	{ADV7482_I2C_TXB, 0x00, 0xA1},	/* Set Auto DPHY Timing */
+#if 0 /* If CVBS input only is used, please enable this code. */
+	{ADV7482_I2C_TXA, 0xF0, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD6, 0x07},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC0, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC3, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC6, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC9, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xCC, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD5, 0x03},	/* ADI Required Write */
+#endif
+	{ADV7482_I2C_TXB, 0xD2, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xC4, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x71, 0x33},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x72, 0x11},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xF0, 0x00},	/* i2c_dphy_pwdn - 1'b0 */
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXB, 0x00, 0x21 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_txa_4lane[] = {
+
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0x00, 0xA4},	/* Set Auto DPHY Timing */
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXA, 0x00, 0x24 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_txa_4lane[] = {
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x3B},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_txb_1lane[] = {
+
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 1-lane MIPI */
+	{ADV7482_I2C_TXB, 0x00, 0xA1},	/* Set Auto DPHY Timing */
+
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXB, 0x00, 0x21 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_txb_1lane[] = {
+
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x3B},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_hdmi_rx[] = {
+
+	/* Disable chip powerdown & Enable HDMI Rx block */
+	{ADV7482_I2C_IO, 0x00, 0x40},
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_hdmi_rx[] = {
+
+	{ADV7482_I2C_IO, 0x00, 0x30},	/* Disable chip powerdown */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_enable_csi4_csi1[] = {
+
+	{ADV7482_I2C_IO, 0x10, 0xE0},	/* Enable 4-lane CSI Tx & Pixel Port */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel0[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x00},	/* Set virtual channel 0 */
+	{ADV7482_I2C_TXA, 0x0D, 0x00},	/* Set virtual channel 0 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel1[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x40},	/* Set virtual channel 1 */
+	{ADV7482_I2C_TXA, 0x0D, 0x40},	/* Set virtual channel 1 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel2[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x80},	/* Set virtual channel 2 */
+	{ADV7482_I2C_TXA, 0x0D, 0x80},	/* Set virtual channel 2 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel3[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0xC0},	/* Set virtual channel 3 */
+	{ADV7482_I2C_TXA, 0x0D, 0xC0},	/* Set virtual channel 3 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+enum decoder_input_interface {
+	DECODER_INPUT_INTERFACE_RGB888,
+	DECODER_INPUT_INTERFACE_YCBCR422,
+};
+
+/**
+ * struct adv7482_link_config - Describes adv7482 hardware configuration
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ */
+struct adv7482_link_config {
+	enum decoder_input_interface	input_interface;
+	struct adv7482_reg_value	*regs;
+
+	struct adv7482_reg_value	*power_up;
+	struct adv7482_reg_value	*power_down;
+
+	int (*init_device)(void *);
+	int (*init_controls)(void *);
+	int (*s_power)(void *);
+	int (*s_ctrl)(void *);
+	int (*enum_mbus_code)(void *);
+	int (*set_pad_format)(void *);
+	int (*get_pad_format)(void *);
+	int (*s_std)(void *);
+	int (*querystd)(void *);
+	int (*g_input_status)(void *);
+	int (*s_routing)(void *);
+	int (*g_mbus_config)(void *);
+
+	struct device	*dev;
+	bool		sw_reset;
+	bool		hdmi_in;
+	bool		sdp_in;
+	int		vc_ch;
+};
+
+struct adv7482_state {
+	struct v4l2_ctrl_handler		ctrl_hdl;
+	struct v4l2_subdev			sd;
+	struct media_pad			pad;
+	 /* mutual excl. when accessing chip */
+	struct mutex				mutex;
+	int					irq;
+	v4l2_std_id				curr_norm;
+	bool					autodetect;
+	bool					powered;
+	const struct adv7482_color_format	*cfmt;
+	u32					width;
+	u32					height;
+
+	struct i2c_client			*client;
+	unsigned int				register_page;
+	struct i2c_client			*csi_client;
+	enum v4l2_field				field;
+
+	struct device				*dev;
+	struct adv7482_link_config		mipi_csi2_link[2];
+};
+
+/*****************************************************************************/
+/*  Private functions                                                        */
+/*****************************************************************************/
+
+#define to_adv7482_sd(_ctrl) (&container_of(_ctrl->handler,		\
+					    struct adv7482_state,	\
+					    ctrl_hdl)->sd)
+
+static inline struct adv7482_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7482_state, sd);
+}
+
+/*
+ * adv7482_write_registers() - Write adv7482 device registers
+ * @client: pointer to i2c_client structure
+ * @regs: pointer to adv7482_reg_value structure
+ *
+ * Write the specified adv7482 register's values.
+ */
+static int adv7482_write_registers(struct i2c_client *client,
+					const struct adv7482_reg_value *regs)
+{
+	struct i2c_msg msg;
+	u8 data_buf[2];
+	int ret = -EINVAL;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &data_buf[0];
+
+	while (regs->addr != ADV7482_I2C_EOR) {
+
+		if (regs->addr == ADV7482_I2C_WAIT)
+			msleep(regs->value);
+		else {
+			msg.addr = regs->addr;
+			data_buf[0] = regs->reg;
+			data_buf[1] = regs->value;
+
+			ret = i2c_transfer(client->adapter, &msg, 1);
+			if (ret < 0)
+				break;
+		}
+		regs++;
+	}
+
+	return (ret < 0) ? ret : 0;
+}
+
+/*
+ * adv7482_write_register() - Write adv7482 device register
+ * @client: pointer to i2c_client structure
+ * @addr: i2c slave address of adv7482 device
+ * @reg: adv7482 device register address
+ * @value: the value to be written
+ *
+ * Write the specified adv7482 register's value.
+ */
+static int adv7482_write_register(struct i2c_client *client,
+		u8 addr, u8 reg, u8 value)
+{
+	struct adv7482_reg_value regs[2];
+	int ret;
+
+	regs[0].addr = addr;
+	regs[0].reg = reg;
+	regs[0].value = value;
+	regs[1].addr = ADV7482_I2C_EOR;
+	regs[1].reg = 0xFF;
+	regs[1].value = 0xFF;
+
+	ret = adv7482_write_registers(client, regs);
+
+	return ret;
+}
+
+/*
+ * adv7482_read_register() - Read adv7482 device register
+ * @client: pointer to i2c_client structure
+ * @addr: i2c slave address of adv7482 device
+ * @reg: adv7482 device register address
+ * @value: pointer to the value
+ *
+ * Read the specified adv7482 register's value.
+ */
+static int adv7482_read_register(struct i2c_client *client,
+		u8 addr, u8 reg, u8 *value)
+{
+	struct i2c_msg msg[2];
+	u8 reg_buf, data_buf;
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg[0].addr = addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &reg_buf;
+	msg[1].addr = addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 1;
+	msg[1].buf = &data_buf;
+
+	reg_buf = reg;
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	*value = data_buf;
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int adv7482_read_sdp_main_info(struct i2c_client *client,
+		struct adv7482_sdp_main_info *info)
+{
+	int ret;
+	u8 value;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+				ADV7482_SDP_REG_CTRL, ADV7482_SDP_RO_MAIN_MAP);
+	if (ret < 0)
+		return ret;
+
+	/* status_reg_10 */
+	ret = adv7482_read_register(client, ADV7482_I2C_SDP,
+			ADV7482_SDP_R_REG_10, &value);
+	if (ret < 0)
+		return ret;
+
+	info->status_reg_10 = value;
+
+	return ret;
+}
+
+static v4l2_std_id adv7482_std_to_v4l2(u8 status_reg_10)
+{
+	/* in case V4L2_IN_ST_NO_SIGNAL */
+	if (!(status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK))
+		return V4L2_STD_UNKNOWN;
+
+	switch (status_reg_10 & ADV7482_SDP_R_REG_10_AUTOD_MASK) {
+	case ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J:
+		return V4L2_STD_NTSC;
+	case ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43:
+		return V4L2_STD_NTSC_443;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_M:
+		return V4L2_STD_PAL_M;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_60:
+		return V4L2_STD_PAL_60;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G:
+		return V4L2_STD_PAL;
+	case ADV7482_SDP_R_REG_10_AUTOD_SECAM:
+		return V4L2_STD_SECAM;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB:
+		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
+	case ADV7482_SDP_R_REG_10_AUTOD_SECAM_525:
+		return V4L2_STD_SECAM;
+	default:
+		return V4L2_STD_UNKNOWN;
+	}
+}
+
+static u32 adv7482_status_to_v4l2(u8 status_reg_10)
+{
+	if (!(status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK))
+		return V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int __adv7482_status(struct adv7482_state *state, u32 *status,
+			    v4l2_std_id *std)
+{
+	int ret;
+	u8 status_reg_10;
+	struct adv7482_sdp_main_info sdp_info;
+
+	ret = adv7482_read_sdp_main_info(state->client, &sdp_info);
+	if (ret < 0)
+		return ret;
+
+	status_reg_10 = sdp_info.status_reg_10;
+
+	if (status_reg_10 < 0)
+		return (int)status_reg_10;
+
+	if (status)
+		*status = adv7482_status_to_v4l2(status_reg_10);
+	if (std)
+		*std = adv7482_std_to_v4l2(status_reg_10);
+
+	return 0;
+}
+
+/*
+ * adv7482_get_vid_info() - Get video information
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @progressive: progressive or interlace
+ * @width: line width
+ * @height: lines per frame
+ *
+ * Get video information.
+ */
+static int adv7482_get_vid_info(struct v4l2_subdev *sd, u8 *progressive,
+				u32 *width, u32 *height, u8 *signal)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 hdmi_int;
+	u8 msb;
+	u8 lsb;
+	int ret;
+
+	if (signal)
+		*signal = 0;
+
+	/* decide line width */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_STATUS1_REG, &msb);
+	if (ret < 0)
+		return ret;
+
+	if (!(msb & ADV7482_HDMI_VF_LOCKED_FLG) ||
+	    !(msb & ADV7482_HDMI_DERF_LOCKED_FLG))
+		return -EIO;
+
+	if (signal)
+		*signal = 1;
+
+	/* decide interlaced or progressive */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_STATUS2_REG, &hdmi_int);
+	if (ret < 0)
+		return ret;
+
+	*progressive =  1;
+	if ((hdmi_int & ADV7482_HDMI_IP_FLAG) != 0)
+		*progressive =  0;
+
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_LWIDTH_REG, &lsb);
+	if (ret < 0)
+		return ret;
+
+	*width = (u32)(ADV7482_HDMI_LWIDTH_MSBS_MASK & msb);
+	*width = (lsb | (*width << 8));
+
+	/* decide lines per frame */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_F0HEIGHT_MSBS_REG, &msb);
+	if (ret < 0)
+		return ret;
+
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_F0HEIGHT_LSBS_REG, &lsb);
+	if (ret < 0)
+		return ret;
+
+	*height = (u32)(ADV7482_HDMI_F0HEIGHT_MSBS_MASK & msb);
+	*height = (lsb | (*height << 8));
+	if (!(*progressive))
+		*height = *height * 2;
+
+	if (*width == 0 || *height == 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int adv7482_set_vid_info(struct v4l2_subdev *sd)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	u8 progressive;
+	u8 signal;
+	u8 val = ADV7482_IO_CP_VID_STD_480P;
+	u32 width;
+	u32 height;
+	int ret;
+
+	/* Get video information */
+	ret = adv7482_get_vid_info(sd, &progressive, &width, &height, &signal);
+	if (ret < 0) {
+		width		= ADV7482_MAX_WIDTH;
+		height		= ADV7482_MAX_HEIGHT;
+		progressive	= 1;
+	} else {
+		if ((width == 640) &&
+			(height == 480) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_VGA60;
+			dev_info(state->dev,
+				 "Changed active resolution to 640x480p\n");
+		} else if ((width == 720) &&
+			(height == 480) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_480P;
+			dev_info(state->dev,
+				 "Changed active resolution to 720x480p\n");
+		} else if ((width == 720) &&
+			(height == 576) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_576P;
+			dev_info(state->dev,
+				 "Changed active resolution to 720x576p\n");
+		} else if ((width == 1280) &&
+			(height == 720) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_720P;
+			dev_info(state->dev,
+				 "Changed active resolution to 1280x720p\n");
+		} else if ((width == 1920) &&
+			(height == 1080) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_1080P;
+			dev_info(state->dev,
+				 "Changed active resolution to 1920x1080p\n");
+		} else if ((width == 1920) &&
+			(height == 1080) && (progressive == 0)) {
+			val = ADV7482_IO_CP_VID_STD_1080I;
+			dev_info(state->dev,
+				 "Changed active resolution to 1920x1080i\n");
+		} else {
+			dev_err(state->dev,
+				 "Not support resolution %dx%d%c\n",
+				  width, height, (progressive) ? 'p' : 'i');
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * The resolution of 720p, 1080i and 1080p is Hsync width of 40 pixel
+	 * clock cycles. These resolutions must be shifted horizontally to
+	 * the left in active video mode.
+	 */
+	if ((val == ADV7482_IO_CP_VID_STD_1080I) ||
+		(val == ADV7482_IO_CP_VID_STD_1080P)) {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x43);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0xD4);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x4F);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0xD4);
+	} else if (val == ADV7482_IO_CP_VID_STD_720P) {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x43);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0xD8);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x4F);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0xD8);
+	} else {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x40);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0x00);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x40);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0x00);
+	}
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_CP_VID_STD_REG, val);
+
+	return ret;
+}
+
+/*****************************************************************************/
+/*  V4L2 decoder i/f handler for v4l2_subdev_core_ops                        */
+/*****************************************************************************/
+
+/*
+ * adv7482_querystd() - V4L2 decoder i/f handler for querystd
+ * @sd: ptr to v4l2_subdev struct
+ * @std: standard input video id
+ *
+ * Obtains the video standard input id
+ */
+static int adv7482_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	int err = mutex_lock_interruptible(&state->mutex);
+
+	if (err)
+		return err;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		/* when we are interrupt driven we know the state */
+		if (!state->autodetect)
+			*std = state->curr_norm;
+		else
+			err = __adv7482_status(state, NULL, std);
+	else
+		*std = V4L2_STD_ATSC;
+
+	mutex_unlock(&state->mutex);
+
+	return err;
+}
+
+/*
+ * adv7482_g_input_status() - V4L2 decoder i/f handler for g_input_status
+ * @sd: ptr to v4l2_subdev struct
+ * @status: video input status flag
+ *
+ * Obtains the video input status flags.
+ */
+static int adv7482_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	u8 status1 = 0;
+	int ret = mutex_lock_interruptible(&state->mutex);
+
+	if (ret)
+		return ret;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = __adv7482_status(state, status, NULL);
+	else {
+		ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+				ADV7482_HDMI_STATUS1_REG, &status1);
+		if (ret < 0)
+			goto out;
+
+		if (!(status1 & ADV7482_HDMI_VF_LOCKED_FLG))
+			*status = V4L2_IN_ST_NO_SIGNAL;
+		else if (!(status1 & ADV7482_HDMI_DERF_LOCKED_FLG))
+			*status = V4L2_IN_ST_NO_SIGNAL;
+		else
+			*status = 0;
+	}
+
+	ret = 0;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7482_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (code->index != 0)
+		return -EINVAL;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		code->code = MEDIA_BUS_FMT_YUYV8_2X8;
+	else
+		code->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+	return 0;
+}
+
+static int adv7482_mbus_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7482_state *state = to_state(sd);
+
+	u8 progressive;
+	u8 signal;
+	u32 width;
+	u32 height;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	u8 status_reg_10;
+	struct adv7482_sdp_main_info sdp_info;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
+		fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+		fmt->width = 720;
+		fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
+
+		/* Get video information */
+		ret = adv7482_read_sdp_main_info(client, &sdp_info);
+		if (ret < 0)
+			return ret;
+
+		status_reg_10 = sdp_info.status_reg_10;
+
+		if (status_reg_10 < 0)
+			dev_info(state->dev,
+				"Not detect any video input signal\n");
+		else {
+			if ((status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK) &&
+				(status_reg_10 & ADV7482_SDP_R_REG_10_FSC_LOCK)
+				&& (((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_M) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_M) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_60) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_60) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB)))
+				dev_info(state->dev,
+				   "Detected the PAL video input signal\n");
+			else if ((status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK)
+				&& (status_reg_10 &
+				ADV7482_SDP_R_REG_10_FSC_LOCK) &&
+				(((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43) ==
+				ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_MASK) ==
+				ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J)))
+				dev_info(state->dev,
+				   "Detected the NTSC video input signal\n");
+			else
+				dev_info(state->dev,
+				   "Not detect any video input signal\n");
+		}
+
+		state->width = fmt->width;
+		state->height = fmt->height;
+		state->field = V4L2_FIELD_INTERLACED;
+
+	} else {
+		fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+		fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+			&width, &height, &signal);
+		if (ret < 0) {
+			width		= ADV7482_MAX_WIDTH;
+			height		= ADV7482_MAX_HEIGHT;
+			progressive	= 1;
+		}
+
+		if (signal)
+			dev_info(state->dev,
+			 "Detected the HDMI video input signal (%dx%d%c)\n",
+			  width, height, (progressive) ? 'p' : 'i');
+		else
+			dev_info(state->dev,
+				"Not detect any video input signal\n");
+
+		state->width = width;
+		state->height = height;
+		state->field =
+		      (progressive) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+
+		fmt->width = state->width;
+		fmt->height = state->height;
+	}
+
+	return 0;
+}
+
+/*
+ * adv7482_cropcap() - V4L2 decoder i/f handler for cropcap
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 cropcap structure
+ *
+ * Gets cropping limits, default cropping rectangle and pixel aspect.
+ */
+static int adv7482_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct adv7482_state *state = to_state(sd);
+	u8 progressive;
+	u32 width;
+	u32 height;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	/* cropping limits */
+	a->bounds.left = 0;
+	a->bounds.top  = 0;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		a->bounds.width  = 720;
+		a->bounds.height = state->curr_norm & V4L2_STD_525_60
+							 ? 480 : 576;
+	} else {
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+						 &width, &height, NULL);
+		if (ret < 0) {
+			a->bounds.width  = ADV7482_MAX_WIDTH;
+			a->bounds.height = ADV7482_MAX_HEIGHT;
+		} else {
+			a->bounds.width  = width;
+			a->bounds.height = height;
+		}
+	}
+
+	/* default cropping rectangle */
+	a->defrect = a->bounds;
+
+	/* does not support scaling */
+	a->pixelaspect.numerator   = 1;
+	a->pixelaspect.denominator = 1;
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+/*
+ * adv7482_g_crop() - V4L2 decoder i/f handler for g_crop
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 cropcap structure
+ *
+ * Gets current cropping rectangle.
+ */
+static int adv7482_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct adv7482_state *state = to_state(sd);
+	u8 progressive;
+	u32 width;
+	u32 height;
+	int ret;
+
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	a->c.left = 0;
+	a->c.top  = 0;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		a->c.width  = 720;
+		a->c.height = state->curr_norm & V4L2_STD_525_60
+							 ? 480 : 576;
+	} else {
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+						 &width, &height, NULL);
+		if (ret < 0) {
+			a->c.width  = ADV7482_MAX_WIDTH;
+			a->c.height = ADV7482_MAX_HEIGHT;
+		} else {
+			a->c.width  = width;
+			a->c.height = height;
+		}
+	}
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int adv7482_set_field_mode(struct adv7482_state *state)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static int adv7482_set_power(struct adv7482_state *state, bool on)
+{
+	u8 val;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = adv7482_read_register(state->client, ADV7482_I2C_TXB,
+				0x1E, &val);
+		if (ret < 0)
+			return ret;
+
+		if (on && ((val & 0x40) == 0)) {
+			/* Power up */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_up_txb_1lane);
+			if (ret < 0)
+				goto fail;
+		} else {
+			/* Power down */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_down_txb_1lane);
+			if (ret < 0)
+				goto fail;
+		}
+	} else {
+		/* set active resolution */
+		ret = adv7482_set_vid_info(&state->sd);
+		ret = adv7482_read_register(state->client, ADV7482_I2C_TXA,
+				0x1E, &val);
+		if (ret < 0)
+			return ret;
+
+		if (on && ((val & 0x40) == 0)) {
+			/* Power up */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_up_txa_4lane);
+			if (ret < 0)
+				goto fail;
+		} else {
+			/* Power down */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_down_txa_4lane);
+			if (ret < 0)
+				goto fail;
+		}
+	}
+
+	return 0;
+fail:
+	pr_info("%s: Failed set power operation, ret = %d\n", __func__, ret);
+	return ret;
+}
+
+static int adv7482_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct adv7482_state *state = to_state(sd);
+	int ret;
+
+	ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	ret = adv7482_set_power(state, on);
+	if (ret == 0)
+		state->powered = on;
+
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7482_get_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7482_state *state = to_state(sd);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+	else {
+		adv7482_mbus_fmt(sd, &format->format);
+		format->format.field = state->field;
+	}
+
+	return 0;
+}
+
+static int adv7482_set_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct v4l2_mbus_framefmt *framefmt;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		framefmt = &format->format;
+		if (state->field != format->format.field) {
+			state->field = format->format.field;
+			adv7482_set_power(state, false);
+			adv7482_set_field_mode(state);
+			adv7482_set_power(state, true);
+		}
+	} else {
+		adv7482_mbus_fmt(sd, &format->format);
+
+		if (format->format.field == V4L2_FIELD_ANY)
+			format->format.field = state->field;
+
+		return 0;
+	}
+
+	return adv7482_mbus_fmt(sd, framefmt);
+}
+
+/*
+ * adv7482_g_mbus_config() - V4L2 decoder i/f handler for g_mbus_config
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @cfg: pointer to V4L2 mbus_config structure
+ *
+ * Get mbus configuration.
+ */
+static int adv7482_g_mbus_config(struct v4l2_subdev *sd,
+					struct v4l2_mbus_config *cfg)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		cfg->flags = V4L2_MBUS_CSI2_1_LANE |
+				V4L2_MBUS_CSI2_CHANNEL_0 |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	else
+		cfg->flags = V4L2_MBUS_CSI2_LANES |
+				V4L2_MBUS_CSI2_CHANNELS |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	cfg->type = V4L2_MBUS_CSI2;
+
+	return 0;
+}
+
+
+/*****************************************************************************/
+/*  V4L2 decoder i/f handler for v4l2_ctrl_ops                               */
+/*****************************************************************************/
+static int adv7482_cp_s_ctrl(struct v4l2_ctrl *ctrl, struct i2c_client *client)
+{
+	u8 val;
+	int ret;
+
+	/* Enable video adjustment first */
+	ret = adv7482_read_register(client, ADV7482_I2C_CP,
+			ADV7482_CP_VID_ADJ_REG, &val);
+	if (ret < 0)
+		return ret;
+	val |= ADV7482_CP_VID_ADJ_ENABLE;
+	ret = adv7482_write_register(client, ADV7482_I2C_CP,
+			ADV7482_CP_VID_ADJ_REG, val);
+	if (ret < 0)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctrl->val < ADV7482_CP_BRI_MIN) ||
+					(ctrl->val > ADV7482_CP_BRI_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_BRI_REG, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		if ((ctrl->val < ADV7482_CP_HUE_MIN) ||
+					(ctrl->val > ADV7482_CP_HUE_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_HUE_REG, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->val < ADV7482_CP_CON_MIN) ||
+					(ctrl->val > ADV7482_CP_CON_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_CON_REG, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		if ((ctrl->val < ADV7482_CP_SAT_MIN) ||
+					(ctrl->val > ADV7482_CP_SAT_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_SAT_REG, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int adv7482_sdp_s_ctrl(struct v4l2_ctrl *ctrl, struct i2c_client *client)
+{
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+			ADV7482_SDP_REG_CTRL, ADV7482_SDP_MAIN_MAP_RW);
+	if (ret < 0)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctrl->val < ADV7482_SDP_BRI_MIN) ||
+					(ctrl->val > ADV7482_SDP_BRI_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_BRI, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		if ((ctrl->val < ADV7482_SDP_HUE_MIN) ||
+					(ctrl->val > ADV7482_SDP_HUE_MAX))
+			ret = -ERANGE;
+		else
+			/*Hue is inverted according to HSL chart */
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_HUE, -ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->val < ADV7482_SDP_CON_MIN) ||
+					(ctrl->val > ADV7482_SDP_CON_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_CON, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		/*
+		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
+		 *Let's not confuse the user, everybody understands saturation
+		 */
+		if ((ctrl->val < ADV7482_SDP_SAT_MIN) ||
+					(ctrl->val > ADV7482_SDP_SAT_MAX))
+			ret = -ERANGE;
+		else {
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_SD_SAT_CB, ctrl->val);
+			if (ret < 0)
+				break;
+
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_SD_SAT_CR, ctrl->val);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * adv7482_s_ctrl() - V4L2 decoder i/f handler for s_ctrl
+ * @ctrl: pointer to standard V4L2 control structure
+ *
+ * Set a control in ADV7482 decoder device.
+ */
+static int adv7482_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_adv7482_sd(ctrl);
+	struct adv7482_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (ret)
+		return ret;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = adv7482_sdp_s_ctrl(ctrl, client);
+	else
+		ret = adv7482_cp_s_ctrl(ctrl, client);
+
+	mutex_unlock(&state->mutex);
+
+	return ret;
+}
+
+
+static const struct v4l2_subdev_core_ops adv7482_core_ops = {
+	.queryctrl = v4l2_subdev_queryctrl,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_power = adv7482_s_power,
+};
+
+static const struct v4l2_subdev_video_ops adv7482_video_ops = {
+	.querystd	= adv7482_querystd,
+	.g_input_status = adv7482_g_input_status,
+	.cropcap	= adv7482_cropcap,
+	.g_crop		= adv7482_g_crop,
+	.g_mbus_config	= adv7482_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops adv7482_pad_ops = {
+	.enum_mbus_code = adv7482_enum_mbus_code,
+	.set_fmt = adv7482_set_pad_format,
+	.get_fmt = adv7482_get_pad_format,
+};
+
+static const struct v4l2_subdev_ops adv7482_ops = {
+	.core = &adv7482_core_ops,
+	.video = &adv7482_video_ops,
+	.pad = &adv7482_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops adv7482_ctrl_ops = {
+	.s_ctrl = adv7482_s_ctrl,
+};
+
+/*
+ * adv7482_init_controls() - Init controls
+ * @state: pointer to private state structure
+ *
+ * Init ADV7482 supported control handler.
+ */
+static int adv7482_cp_init_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, ADV7482_CP_BRI_MIN,
+			  ADV7482_CP_BRI_MAX, 1, ADV7482_CP_BRI_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_CONTRAST, ADV7482_CP_CON_MIN,
+			  ADV7482_CP_CON_MAX, 1, ADV7482_CP_CON_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_SATURATION, ADV7482_CP_SAT_MIN,
+			  ADV7482_CP_SAT_MAX, 1, ADV7482_CP_SAT_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_HUE, ADV7482_CP_HUE_MIN,
+			  ADV7482_CP_HUE_MAX, 1, ADV7482_CP_HUE_DEF);
+	state->sd.ctrl_handler = &state->ctrl_hdl;
+	if (state->ctrl_hdl.error) {
+		int err = state->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&state->ctrl_hdl);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+	return 0;
+}
+
+static int adv7482_sdp_init_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, ADV7482_SDP_BRI_MIN,
+			  ADV7482_SDP_BRI_MAX, 1, ADV7482_SDP_BRI_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_CONTRAST, ADV7482_SDP_CON_MIN,
+			  ADV7482_SDP_CON_MAX, 1, ADV7482_SDP_CON_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_SATURATION, ADV7482_SDP_SAT_MIN,
+			  ADV7482_SDP_SAT_MAX, 1, ADV7482_SDP_SAT_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_HUE, ADV7482_SDP_HUE_MIN,
+			  ADV7482_SDP_HUE_MAX, 1, ADV7482_SDP_HUE_DEF);
+
+	state->sd.ctrl_handler = &state->ctrl_hdl;
+	if (state->ctrl_hdl.error) {
+		int err = state->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&state->ctrl_hdl);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+	return 0;
+}
+
+static void adv7482_exit_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_free(&state->ctrl_hdl);
+}
+
+/*****************************************************************************/
+/*  i2c driver interface handlers                                            */
+/*****************************************************************************/
+
+static int adv7482_parse_dt(struct device_node *np,
+			    struct adv7482_link_config *config)
+{
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *endpoint;
+	const char *str;
+	int ret;
+	int ch;
+
+	/* Parse the endpoint. */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint)
+		return -EINVAL;
+
+	v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+	of_node_put(endpoint);
+
+	/* check input-interface */
+	ret = of_property_read_string(np, "adi,input-interface", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "rgb888")) {
+		config->input_interface = DECODER_INPUT_INTERFACE_RGB888;
+		config->regs =
+		(struct adv7482_reg_value *)adv7482_init_txa_4lane;
+		config->power_up =
+		(struct adv7482_reg_value *)adv7482_power_up_txa_4lane;
+		config->power_down =
+		(struct adv7482_reg_value *)adv7482_power_down_txa_4lane;
+		config->init_controls =
+		(int (*)(void *))adv7482_cp_init_controls;
+	} else {
+		config->input_interface = DECODER_INPUT_INTERFACE_YCBCR422;
+		config->regs =
+		(struct adv7482_reg_value *)adv7482_init_txb_1lane;
+		config->power_up =
+		(struct adv7482_reg_value *)adv7482_power_up_txb_1lane;
+		config->power_down =
+		(struct adv7482_reg_value *)adv7482_power_down_txb_1lane;
+		config->init_controls =
+		(int (*)(void *))adv7482_sdp_init_controls;
+	}
+
+	ret = of_property_read_string(np, "adi,input-hdmi", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->hdmi_in = 1;
+	else
+		config->hdmi_in = 0;
+
+	ret = of_property_read_string(np, "adi,input-sdp", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->sdp_in = 1;
+	else
+		config->sdp_in = 0;
+
+	ret = of_property_read_string(np, "adi,sw-reset", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->sw_reset = 1;
+	else
+		config->sw_reset = 0;
+
+	ret = of_property_read_u32(np, "adi,virtual-channel", &ch);
+	if (ret < 0)
+		return ret;
+
+	if ((ch < 0) || (ch > 3))
+		return -EINVAL;
+
+	config->vc_ch = ch;
+
+	config->init_device    = NULL;
+	config->s_power        = NULL;
+	config->s_ctrl         = NULL;
+	config->enum_mbus_code = NULL;
+	config->set_pad_format = NULL;
+	config->get_pad_format = NULL;
+	config->s_std          = NULL;
+	config->querystd       = NULL;
+	config->g_input_status = NULL;
+	config->s_routing      = NULL;
+	config->g_mbus_config  = NULL;
+
+	return 0;
+}
+
+/*
+ * adv7482_probe - Probe a ADV7482 device
+ * @client: pointer to i2c_client structure
+ * @id: pointer to i2c_device_id structure
+ *
+ * Initialize the ADV7482 device
+ */
+static int adv7482_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct adv7482_state *state;
+	struct adv7482_link_config link_config;
+	struct device *dev = &client->dev;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7482_state), GFP_KERNEL);
+	if (state == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	state->client = client;
+	state->irq = client->irq;
+
+	ret = adv7482_parse_dt(dev->of_node, &link_config);
+	if (ret) {
+		dev_err(&client->dev, "adv7482 parse error\n");
+		return ret;
+	}
+
+	state->mipi_csi2_link[0].input_interface = link_config.input_interface;
+
+	mutex_init(&state->mutex);
+	state->autodetect = true;
+	state->powered = true;
+	sd = &state->sd;
+	state->width = ADV7482_MAX_WIDTH;
+	state->height = ADV7482_MAX_HEIGHT;
+	state->field = V4L2_FIELD_NONE;
+
+	v4l2_i2c_subdev_init(sd, client, &adv7482_ops);
+
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	state->dev		= dev;
+	state->mipi_csi2_link[0].dev = dev;
+
+	/* SW reset AVD7482 to its default values */
+	if (link_config.sw_reset) {
+		ret = adv7482_write_registers(client, adv7482_sw_reset);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* check rd_info */
+		{
+			u8 msb;
+			u8 lsb;
+
+			ret = adv7482_read_register(client, ADV7482_I2C_IO,
+					ADV7482_IO_RD_INFO1_REG, &lsb);
+			if (ret < 0)
+				return ret;
+
+			ret = adv7482_read_register(client, ADV7482_I2C_IO,
+					ADV7482_IO_RD_INFO2_REG, &msb);
+			if (ret < 0)
+				return ret;
+
+			v4l_info(client, "adv7482 revision is %02x%02x\n",
+					lsb, msb);
+		}
+	}
+
+	if (link_config.hdmi_in) {
+		ret = adv7482_write_registers(client,
+				adv7482_init_txa_4lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Power down */
+		ret = adv7482_write_registers(client,
+				adv7482_power_down_txa_4lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 txa power down\n");
+	} else
+		v4l_info(client, "adv7482 hdmi_in is disabled.\n");
+
+	/* Initializes AVD7482 to its default values */
+	if (link_config.sdp_in) {
+		ret = adv7482_write_registers(client,
+						adv7482_init_txb_1lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Power down */
+		ret = adv7482_write_registers(client,
+						adv7482_power_down_txb_1lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 txb power down\n");
+	} else
+		v4l_info(client, "adv7482 sdp_in is disabled.\n");
+
+	if (link_config.sdp_in && link_config.hdmi_in) {
+		/* Power up hdmi rx */
+		ret = adv7482_write_registers(client,
+						adv7482_power_up_hdmi_rx);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Enable csi4 and sci1 */
+		ret = adv7482_write_registers(client,
+						adv7482_enable_csi4_csi1);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 enable csi1 and csi4\n");
+	}
+
+	if (link_config.input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = adv7482_sdp_init_controls(state);
+	else
+		ret = adv7482_cp_init_controls(state);
+	if (ret)
+		goto err_unreg_subdev;
+
+	/* Setting virtual channel for ADV7482 */
+	if (link_config.vc_ch == 0)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel0);
+	else if (link_config.vc_ch == 1)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel1);
+	else if (link_config.vc_ch == 2)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel2);
+	else if (link_config.vc_ch == 3)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel3);
+	if (ret < 0)
+		goto err_unreg_subdev;
+
+	state->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+	ret = media_entity_init(&sd->entity, 1, &state->pad, 0);
+	if (ret)
+		goto err_free_ctrl;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret)
+		goto err_free_ctrl;
+
+	return 0;
+
+err_free_ctrl:
+	adv7482_exit_controls(state);
+
+err_unreg_subdev:
+	mutex_destroy(&state->mutex);
+	v4l2_device_unregister_subdev(sd);
+	kfree(state);
+err:
+	dev_err(&client->dev, ": Failed to probe: %d\n", ret);
+	return ret;
+}
+
+/*
+ * adv7482_remove - Remove ADV7482 device support
+ * @client: pointer to i2c_client structure
+ *
+ * Reset the ADV7482 device
+ */
+static int adv7482_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7482_state *state = to_state(sd);
+
+	v4l2_async_unregister_subdev(sd);
+
+	media_entity_cleanup(&sd->entity);
+	adv7482_exit_controls(state);
+
+	mutex_destroy(&state->mutex);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id adv7482_id[] = {
+	{DRIVER_NAME, 0},
+	{},
+};
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * adv7482_suspend - Suspend ADV7482 device
+ * @client: pointer to i2c_client structure
+ * @state: power management state
+ *
+ * Power down the ADV7482 device
+ */
+static int adv7482_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_PWR_MAN_REG, ADV7482_IO_PWR_OFF);
+
+	return ret;
+}
+
+/*
+ * adv7482_resume - Resume ADV7482 device
+ * @client: pointer to i2c_client structure
+ *
+ * Power on and initialize the ADV7482 device
+ */
+static int adv7482_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adv7482_link_config link_config;
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_PWR_MAN_REG, ADV7482_IO_PWR_ON);
+	if (ret < 0)
+		return ret;
+
+	ret = adv7482_parse_dt(dev->of_node, &link_config);
+	if (ret)
+		return ret;
+
+	/* Initializes AVD7482 to its default values */
+	ret = adv7482_write_registers(client, link_config.regs);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(adv7482_pm_ops, adv7482_suspend, adv7482_resume);
+#define ADV7482_PM_OPS (&adv7482_pm_ops)
+
+#else
+#define ADV7482_PM_OPS NULL
+#endif
+
+MODULE_DEVICE_TABLE(i2c, adv7482_id);
+
+static const struct of_device_id adv7482_of_ids[] = {
+	{ .compatible = "adi,adv7482", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7482_of_ids);
+
+static struct i2c_driver adv7482_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.pm = ADV7482_PM_OPS,
+		.of_match_table = adv7482_of_ids,
+	},
+	.probe		= adv7482_probe,
+	.remove		= adv7482_remove,
+	.id_table	= adv7482_id,
+};
+
+module_i2c_driver(adv7482_driver);
+
+MODULE_DESCRIPTION("HDMI Receiver ADV7482 video decoder driver");
+MODULE_ALIAS("platform:adv7482");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 0c53805..77d1195 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -254,6 +254,27 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called vsp1.
 
+config VIDEO_RENESAS_DEBUG
+	bool "Renesas VSP1 underrun debug messages"
+	depends on VIDEO_RENESAS_VSP1
+	---help---
+	  Enable debug underrun messages on Renesas VSP1 Video Processing
+	  Engine driver.
+	  If you set to enable, When an underrun occurred, a debug underrun
+	  message is output.
+
+config VIDEO_RENESAS_VSP_ALPHA_BIT_ARGB1555
+	int "Renesas VSP alpha bit function of ARGB1555"
+	depends on VIDEO_RENESAS_VSP1
+	range 0 1
+	default 0
+	help
+	  Choose this option if you select A bit function of ARGB1555.
+	  If you set value to 0, pixel alpha blending is performed
+	  when the value of A is 0.
+	  If you set value to 1, pixel alpha blending is performed
+	  when the value of A is 1.
+
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index f2776cd..f1c3646 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -43,6 +43,22 @@
 	---help---
 	  This is a v4l2 driver for the R-Car VIN Interface
 
+config VIDEO_RCAR_VIN_DEBUG
+	bool "Renesas VIN overflow debug messages"
+	depends on VIDEO_RCAR_VIN
+	---help---
+	  Enable debug overflow messages on R-Car Video
+	  Input driver.
+	  If you set to enable, When an overflow occurred,
+	  a debug overflow message is output.
+
+config VIDEO_RCAR_CSI2
+	tristate "R-Car MIPI CSI-2 Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+	depends on ARCH_R8A7795 || COMPILE_TEST
+	---help---
+	  This is a v4l2 driver for the R-Car CSI-2 Interface
+
 config VIDEO_SH_MOBILE_CSI2
 	tristate "SuperH Mobile MIPI CSI-2 Interface driver"
 	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index 2826382..8bcd617 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -13,4 +13,5 @@
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)	+= sh_mobile_csi2.o
+obj-$(CONFIG_VIDEO_RCAR_CSI2)		+= rcar_csi2.o
 obj-$(CONFIG_VIDEO_RCAR_VIN)		+= rcar_vin.o
diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
new file mode 100644
index 0000000..888ecc8
--- /dev/null
+++ b/drivers/media/platform/soc_camera/rcar_csi2.c
@@ -0,0 +1,706 @@
+/*
+ * drivers/media/platform/soc_camera/rcar_csi2.c
+ *     This file is the driver for the R-Car MIPI CSI-2 unit.
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ *
+ * This file is based on the drivers/media/platform/soc_camera/sh_mobile_csi2.c
+ *
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/rcar_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#include <media/v4l2-of.h>
+
+#define DRV_NAME "rcar_csi2"
+#define CONNECT_SLAVE_NAME "adv7482"
+#define VC_MAX_CHANNEL		4
+
+#define RCAR_CSI2_TREF		0x00
+#define RCAR_CSI2_SRST		0x04
+#define RCAR_CSI2_PHYCNT	0x08
+#define RCAR_CSI2_CHKSUM	0x0C
+#define RCAR_CSI2_VCDT		0x10
+
+#define RCAR_CSI2_VCDT2			0x14 /* Channel Data Type Select */
+#define RCAR_CSI2_FRDT			0x18 /* Frame Data Type Select */
+#define RCAR_CSI2_FLD			0x1C /* Field Detection Control */
+#define RCAR_CSI2_ASTBY			0x20 /* Automatic standby control */
+#define RCAR_CSI2_LNGDT0		0x28
+#define RCAR_CSI2_LNGDT1		0x2C
+#define RCAR_CSI2_INTEN			0x30
+#define RCAR_CSI2_INTCLOSE		0x34
+#define RCAR_CSI2_INTSTATE		0x38
+#define RCAR_CSI2_INTERRSTATE		0x3C
+
+#define RCAR_CSI2_SHPDAT		0x40
+#define RCAR_CSI2_SHPCNT		0x44
+
+#define RCAR_CSI2_LINKCNT		0x48
+#define RCAR_CSI2_LSWAP			0x4C
+#define RCAR_CSI2_PHTC			0x58
+#define RCAR_CSI2_PHYPLL		0x68
+
+#define RCAR_CSI2_PHEERM		0x74
+#define RCAR_CSI2_PHCLM			0x78
+#define RCAR_CSI2_PHDLM			0x7C
+
+#define RCAR_CSI2_PHYCNT_SHUTDOWNZ		(1 << 17)
+#define RCAR_CSI2_PHYCNT_RSTZ			(1 << 16)
+#define RCAR_CSI2_PHYCNT_ENABLECLK		(1 << 4)
+#define RCAR_CSI2_PHYCNT_ENABLE_3		(1 << 3)
+#define RCAR_CSI2_PHYCNT_ENABLE_2		(1 << 2)
+#define RCAR_CSI2_PHYCNT_ENABLE_1		(1 << 1)
+#define RCAR_CSI2_PHYCNT_ENABLE_0		(1 << 0)
+
+#define RCAR_CSI2_VCDT_VCDTN_EN			(1 << 15)
+#define RCAR_CSI2_VCDT_SEL_VCN			(1 << 8)
+#define RCAR_CSI2_VCDT_SEL_DTN_ON		(1 << 6)
+#define RCAR_CSI2_VCDT_SEL_DTN			(1 << 0)
+
+#define RCAR_CSI2_LINKCNT_MONITOR_EN		(1 << 31)
+#define RCAR_CSI2_LINKCNT_REG_MONI_PACT_EN	(1 << 25)
+
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE0		(0 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE1		(1 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE2		(2 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE3		(3 << 6)
+
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE0		(0 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE1		(1 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE2		(2 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE3		(3 << 4)
+
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE0		(0 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE1		(1 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE2		(2 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE3		(3 << 2)
+
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE0		(0 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE1		(1 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE2		(2 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE3		(3 << 0)
+
+#define RCAR_CSI2_PHTC_TESTCLR			(1 << 0)
+
+/* interrupt status registers */
+#define RCAR_CSI2_INTSTATE_EBD_CH1		(1 << 29)
+#define RCAR_CSI2_INTSTATE_LESS_THAN_WC		(1 << 28)
+#define RCAR_CSI2_INTSTATE_AFIFO_OF		(1 << 27)
+#define RCAR_CSI2_INTSTATE_VD4_START		(1 << 26)
+#define RCAR_CSI2_INTSTATE_VD4_END		(1 << 25)
+#define RCAR_CSI2_INTSTATE_VD3_START		(1 << 24)
+#define RCAR_CSI2_INTSTATE_VD3_END		(1 << 23)
+#define RCAR_CSI2_INTSTATE_VD2_START		(1 << 22)
+#define RCAR_CSI2_INTSTATE_VD2_END		(1 << 21)
+#define RCAR_CSI2_INTSTATE_VD1_START		(1 << 20)
+#define RCAR_CSI2_INTSTATE_VD1_END		(1 << 19)
+#define RCAR_CSI2_INTSTATE_SHP			(1 << 18)
+#define RCAR_CSI2_INTSTATE_FSFE			(1 << 17)
+#define RCAR_CSI2_INTSTATE_LNP			(1 << 16)
+#define RCAR_CSI2_INTSTATE_CRC_ERR		(1 << 15)
+#define RCAR_CSI2_INTSTATE_HD_WC_ZERO		(1 << 14)
+#define RCAR_CSI2_INTSTATE_FRM_SEQ_ERR1		(1 << 13)
+#define RCAR_CSI2_INTSTATE_FRM_SEQ_ERR2		(1 << 12)
+#define RCAR_CSI2_INTSTATE_ECC_ERR		(1 << 11)
+#define RCAR_CSI2_INTSTATE_ECC_CRCT_ERR		(1 << 10)
+#define RCAR_CSI2_INTSTATE_LPDT_START		(1 << 9)
+#define RCAR_CSI2_INTSTATE_LPDT_END		(1 << 8)
+#define RCAR_CSI2_INTSTATE_ULPS_START		(1 << 7)
+#define RCAR_CSI2_INTSTATE_ULPS_END		(1 << 6)
+#define RCAR_CSI2_INTSTATE_RESERVED		(1 << 5)
+#define RCAR_CSI2_INTSTATE_ERRSOTHS		(1 << 4)
+#define RCAR_CSI2_INTSTATE_ERRSOTSYNCCHS	(1 << 3)
+#define RCAR_CSI2_INTSTATE_ERRESC		(1 << 2)
+#define RCAR_CSI2_INTSTATE_ERRSYNCESC		(1 << 1)
+#define RCAR_CSI2_INTSTATE_ERRCONTROL		(1 << 0)
+
+/* monitoring registers of interrupt error status */
+#define RCAR_CSI2_INTSTATE_ECC_ERR		(1 << 11)
+#define RCAR_CSI2_INTSTATE_ECC_CRCT_ERR		(1 << 10)
+#define RCAR_CSI2_INTSTATE_LPDT_START		(1 << 9)
+#define RCAR_CSI2_INTSTATE_LPDT_END		(1 << 8)
+#define RCAR_CSI2_INTSTATE_ULPS_START		(1 << 7)
+#define RCAR_CSI2_INTSTATE_ULPS_END		(1 << 6)
+#define RCAR_CSI2_INTSTATE_RESERVED		(1 << 5)
+#define RCAR_CSI2_INTSTATE_ERRSOTHS		(1 << 4)
+#define RCAR_CSI2_INTSTATE_ERRSOTSYNCCHS	(1 << 3)
+#define RCAR_CSI2_INTSTATE_ERRESC		(1 << 2)
+#define RCAR_CSI2_INTSTATE_ERRSYNCESC		(1 << 1)
+#define RCAR_CSI2_INTSTATE_ERRCONTROL		(1 << 0)
+
+enum chip_id {
+	RCAR_GEN3,
+	RCAR_GEN2,
+};
+
+enum decoder_input_interface {
+	DECODER_INPUT_INTERFACE_RGB888,
+	DECODER_INPUT_INTERFACE_YCBCR422,
+	DECODER_INPUT_INTERFACE_NONE,
+};
+
+/**
+ * struct rcar_csi2_link_config - Describes rcar_csi2 hardware configuration
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ */
+struct rcar_csi2_link_config {
+	enum decoder_input_interface input_interface;
+	unsigned char lanes;
+	unsigned long vcdt;
+	unsigned long vcdt2;
+};
+
+#define INIT_RCAR_CSI2_LINK_CONFIG(m) \
+{	\
+	m.input_interface = DECODER_INPUT_INTERFACE_NONE; \
+	m.lanes = 0; \
+}
+
+struct rcar_csi_irq_counter_log {
+	unsigned long crc_err;
+};
+
+struct rcar_csi2 {
+	struct v4l2_subdev		subdev;
+	struct v4l2_mbus_framefmt	*mf;
+	unsigned int			irq;
+	unsigned long			mipi_flags;
+	void __iomem			*base;
+	struct platform_device		*pdev;
+	struct rcar_csi2_client_config	*client;
+	unsigned long			vcdt;
+	unsigned long			vcdt2;
+
+	unsigned int			field;
+	unsigned int			code;
+	unsigned int			lanes;
+	spinlock_t			lock;
+};
+
+#define RCAR_CSI_80MBPS		0
+#define RCAR_CSI_90MBPS		1
+#define RCAR_CSI_100MBPS	2
+#define RCAR_CSI_110MBPS	3
+#define RCAR_CSI_120MBPS	4
+#define RCAR_CSI_130MBPS	5
+#define RCAR_CSI_140MBPS	6
+#define RCAR_CSI_150MBPS	7
+#define RCAR_CSI_160MBPS	8
+#define RCAR_CSI_170MBPS	9
+#define RCAR_CSI_180MBPS	10
+#define RCAR_CSI_190MBPS	11
+#define RCAR_CSI_205MBPS	12
+#define RCAR_CSI_220MBPS	13
+#define RCAR_CSI_235MBPS	14
+#define RCAR_CSI_250MBPS	15
+#define RCAR_CSI_275MBPS	16
+#define RCAR_CSI_300MBPS	17
+#define RCAR_CSI_325MBPS	18
+#define RCAR_CSI_350MBPS	19
+#define RCAR_CSI_400MBPS	20
+#define RCAR_CSI_450MBPS	21
+#define RCAR_CSI_500MBPS	22
+#define RCAR_CSI_550MBPS	23
+#define RCAR_CSI_600MBPS	24
+#define RCAR_CSI_650MBPS	25
+#define RCAR_CSI_700MBPS	26
+#define RCAR_CSI_750MBPS	27
+#define RCAR_CSI_800MBPS	28
+#define RCAR_CSI_850MBPS	29
+#define RCAR_CSI_900MBPS	30
+#define RCAR_CSI_950MBPS	31
+#define RCAR_CSI_1000MBPS	32
+#define RCAR_CSI_1050MBPS	33
+#define RCAR_CSI_1100MBPS	34
+#define RCAR_CSI_1150MBPS	35
+#define RCAR_CSI_1200MBPS	36
+#define RCAR_CSI_1250MBPS	37
+#define RCAR_CSI_1300MBPS	38
+#define RCAR_CSI_1350MBPS	39
+#define RCAR_CSI_1400MBPS	40
+#define RCAR_CSI_1450MBPS	41
+#define RCAR_CSI_1500MBPS	42
+
+static int rcar_csi2_set_phy_freq(struct rcar_csi2 *priv)
+{
+	const uint32_t const hs_freq_range[43] = {
+		0x00, 0x10, 0x20, 0x30, 0x01,  /* 0-4   */
+		0x11, 0x21, 0x31, 0x02, 0x12,  /* 5-9   */
+		0x22, 0x32, 0x03, 0x13, 0x23,  /* 10-14 */
+		0x33, 0x04, 0x14, 0x05, 0x15,  /* 15-19 */
+		0x25, 0x06, 0x16, 0x07, 0x17,  /* 20-24 */
+		0x08, 0x18, 0x09, 0x19, 0x29,  /* 25-29 */
+		0x39, 0x0A, 0x1A, 0x2A, 0x3A,  /* 30-34 */
+		0x0B, 0x1B, 0x2B, 0x3B, 0x0C,  /* 35-39 */
+		0x1C, 0x2C, 0x3C               /* 40-42 */
+	};
+	uint32_t bps_per_lane = RCAR_CSI_190MBPS;
+
+	dev_dbg(&priv->pdev->dev, "Input size (%dx%d%c)\n",
+			 priv->mf->width, priv->mf->height,
+			 (priv->mf->field == V4L2_FIELD_NONE) ? 'p' : 'i');
+
+	switch (priv->lanes) {
+	case 1:
+		bps_per_lane = RCAR_CSI_400MBPS;
+		break;
+	case 4:
+		if (priv->mf->field == V4L2_FIELD_NONE) {
+			if ((priv->mf->width == 1920) &&
+				(priv->mf->height == 1080))
+				bps_per_lane = RCAR_CSI_900MBPS;
+			else if ((priv->mf->width == 1280) &&
+				 (priv->mf->height == 720))
+				bps_per_lane = RCAR_CSI_450MBPS;
+			else if ((priv->mf->width == 720) &&
+				 (priv->mf->height == 480))
+				bps_per_lane = RCAR_CSI_190MBPS;
+			else if ((priv->mf->width == 720) &&
+				 (priv->mf->height == 576))
+				bps_per_lane = RCAR_CSI_190MBPS;
+			else if ((priv->mf->width == 640) &&
+				 (priv->mf->height == 480))
+				bps_per_lane = RCAR_CSI_100MBPS;
+			else
+				goto error;
+		} else {
+			if ((priv->mf->width == 1920) &&
+				(priv->mf->height == 1080))
+				bps_per_lane = RCAR_CSI_450MBPS;
+			else
+				goto error;
+		}
+		break;
+	default:
+		dev_err(&priv->pdev->dev, "ERROR: lanes is invalid (%d)\n",
+								 priv->lanes);
+		return -EINVAL;
+	}
+
+	dev_dbg(&priv->pdev->dev, "bps_per_lane (%d)\n", bps_per_lane);
+
+	iowrite32((hs_freq_range[bps_per_lane] << 16),
+				priv->base + RCAR_CSI2_PHYPLL);
+	return 0;
+
+error:
+	dev_err(&priv->pdev->dev, "Not support resolution (%dx%d%c)\n",
+		 priv->mf->width, priv->mf->height,
+		 (priv->mf->field == V4L2_FIELD_NONE) ? 'p' : 'i');
+	return -EINVAL;
+}
+
+static irqreturn_t rcar_csi2_irq(int irq, void *data)
+{
+	struct rcar_csi2 *priv = data;
+	u32 int_status;
+	unsigned int handled = 0;
+
+	spin_lock(&priv->lock);
+
+	int_status = ioread32(priv->base + RCAR_CSI2_INTSTATE);
+	if (!int_status)
+		goto done;
+
+	/* ack interrupts */
+	iowrite32(int_status, priv->base + RCAR_CSI2_INTSTATE);
+	handled = 1;
+
+done:
+	spin_unlock(&priv->lock);
+
+	return IRQ_RETVAL(handled);
+
+}
+
+static void rcar_csi2_hwdeinit(struct rcar_csi2 *priv)
+{
+	iowrite32(0, priv->base + RCAR_CSI2_PHYCNT);
+
+	/* reset CSI2 hardware */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_SRST);
+}
+
+static int rcar_csi2_hwinit(struct rcar_csi2 *priv)
+{
+	int ret;
+	__u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+	/* Reflect registers immediately */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_TREF);
+	/* reset CSI2 hardware */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_SRST);
+
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_PHTC);
+
+	/* setting HS reception frequency */
+	{
+		switch (priv->lanes) {
+		case 1:
+			/* First field number setting */
+			iowrite32(0x0001000f, priv->base + RCAR_CSI2_FLD);
+			tmp |= 0x1;
+			break;
+		case 4:
+			/* First field number setting */
+			iowrite32(0x0002000f, priv->base + RCAR_CSI2_FLD);
+			tmp |= 0xF;
+			break;
+		default:
+			dev_err(&priv->pdev->dev,
+				"ERROR: lanes is invalid (%d)\n",
+				priv->lanes);
+			return -EINVAL;
+		}
+
+		/* set PHY frequency */
+		ret = rcar_csi2_set_phy_freq(priv);
+		if (ret < 0)
+			return ret;
+
+		/* Enable lanes */
+		iowrite32(tmp, priv->base + RCAR_CSI2_PHYCNT);
+
+		iowrite32(tmp | RCAR_CSI2_PHYCNT_SHUTDOWNZ,
+					priv->base + RCAR_CSI2_PHYCNT);
+		iowrite32(tmp | (RCAR_CSI2_PHYCNT_SHUTDOWNZ |
+					RCAR_CSI2_PHYCNT_RSTZ),
+					priv->base + RCAR_CSI2_PHYCNT);
+	}
+
+	iowrite32(0x00000003, priv->base + RCAR_CSI2_CHKSUM);
+	iowrite32(priv->vcdt, priv->base + RCAR_CSI2_VCDT);
+	iowrite32(priv->vcdt2, priv->base + RCAR_CSI2_VCDT2);
+	iowrite32(0x00010000, priv->base + RCAR_CSI2_FRDT);
+	udelay(10);
+	iowrite32(0x83000000, priv->base + RCAR_CSI2_LINKCNT);
+	iowrite32(0x000000e4, priv->base + RCAR_CSI2_LSWAP);
+
+	dev_dbg(&priv->pdev->dev, "CSI2 VCDT:  0x%x\n",
+			 ioread32(priv->base + RCAR_CSI2_VCDT));
+	dev_dbg(&priv->pdev->dev, "CSI2 VCDT2: 0x%x\n",
+			 ioread32(priv->base + RCAR_CSI2_VCDT2));
+
+	/* wait until video decoder power off */
+	msleep(10);
+	{
+		int timeout = 100;
+
+		/* Read the PHY clock lane monitor register (PHCLM). */
+		while (!(ioread32(priv->base + RCAR_CSI2_PHCLM) & 0x01)
+			&& timeout) {
+			timeout--;
+		}
+		if (timeout == 0)
+			dev_err(&priv->pdev->dev,
+				"Timeout of reading the PHY clock lane\n");
+		else
+			dev_dbg(&priv->pdev->dev,
+				"Detected the PHY clock lane\n");
+
+		timeout = 100;
+
+		/* Read the PHY data lane monitor register (PHDLM). */
+		while (!(ioread32(priv->base + RCAR_CSI2_PHDLM) & 0x01)
+			&& timeout) {
+			timeout--;
+		}
+		if (timeout == 0)
+			dev_err(&priv->pdev->dev,
+				"Timeout of reading the PHY data lane\n");
+		else
+			dev_dbg(&priv->pdev->dev,
+				"Detected the PHY data lane\n");
+	}
+
+	return 0;
+}
+
+static int rcar_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct rcar_csi2 *priv = container_of(sd, struct rcar_csi2, subdev);
+	struct v4l2_subdev *tmp_sd;
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_mbus_framefmt *mf = &fmt.format;
+	int ret = 0;
+
+	if (on) {
+		v4l2_device_for_each_subdev(tmp_sd, sd->v4l2_dev) {
+			if (strncmp(tmp_sd->name, CONNECT_SLAVE_NAME,
+				sizeof(CONNECT_SLAVE_NAME) - 1) == 0) {
+				v4l2_subdev_call(tmp_sd, pad, get_fmt,
+							 NULL, &fmt);
+				if (ret < 0)
+					return ret;
+			}
+		}
+		priv->mf = mf;
+		pm_runtime_get_sync(&priv->pdev->dev);
+		ret = rcar_csi2_hwinit(priv);
+		if (ret < 0)
+			return ret;
+	} else {
+		rcar_csi2_hwdeinit(priv);
+		pm_runtime_put_sync(&priv->pdev->dev);
+	}
+
+	return ret;
+}
+
+static struct v4l2_subdev_core_ops rcar_csi2_subdev_core_ops = {
+	.s_power	= rcar_csi2_s_power,
+};
+
+static struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
+	.core	= &rcar_csi2_subdev_core_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rcar_csi2_of_table[] = {
+	{ .compatible = "renesas,csi2-r8a7795", .data = (void *)RCAR_GEN3 },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
+#endif
+
+static struct platform_device_id rcar_csi2_id_table[] = {
+	{ "r8a7795-csi2",  RCAR_GEN3 },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, rcar_csi2_id_table);
+
+static int rcar_csi2_parse_dt(struct device_node *np,
+			struct rcar_csi2_link_config *config)
+{
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *endpoint;
+	struct device_node *vc_np, *vc_ch;
+	const char *str;
+	char csi_name[9];
+	int ret;
+	int i, ch;
+
+	/* Parse the endpoint. */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint)
+		return -EINVAL;
+
+	v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+	of_node_put(endpoint);
+
+	config->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+
+	ret = of_property_read_string(np, "adi,input-interface", &str);
+	if (ret < 0)
+		return ret;
+
+	vc_np = of_get_child_by_name(np, "virtual,channel");
+
+	config->vcdt = 0;
+	config->vcdt2 = 0;
+	for (i = 0; i < VC_MAX_CHANNEL; i++) {
+		sprintf(csi_name, "csi2_vc%d", i);
+
+		vc_ch = of_get_child_by_name(vc_np, csi_name);
+		if (!vc_ch)
+			continue;
+		ret = of_property_read_string(vc_ch, "data,type", &str);
+		if (ret < 0)
+			return ret;
+		ret = of_property_read_u32(vc_ch, "receive,vc", &ch);
+		if (ret < 0)
+			return ret;
+
+		if (i < 2) {
+			if (!strcmp(str, "rgb888"))
+				config->vcdt |= (0x24 << (i * 16));
+			else if (!strcmp(str, "ycbcr422"))
+				config->vcdt |= (0x1e << (i * 16));
+			else
+				config->vcdt |= 0;
+
+			config->vcdt |= (ch << (8 + (i * 16)));
+			config->vcdt |= (RCAR_CSI2_VCDT_VCDTN_EN << (i * 16)) |
+					(RCAR_CSI2_VCDT_SEL_DTN_ON << (i * 16));
+		}
+		if (i >= 2) {
+			int j = (i - 2);
+
+			if (!strcmp(str, "rgb888"))
+				config->vcdt2 |= (0x24 << (j * 16));
+			else if (!strcmp(str, "ycbcr422"))
+				config->vcdt2 |= (0x1e << (j * 16));
+			else
+				config->vcdt2 |= 0;
+
+			config->vcdt2 |= (ch << (8 + (j * 16)));
+			config->vcdt2 |= (RCAR_CSI2_VCDT_VCDTN_EN << (j * 16)) |
+					(RCAR_CSI2_VCDT_SEL_DTN_ON << (j * 16));
+		}
+	}
+
+	return 0;
+}
+
+static int rcar_csi2_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned int irq;
+	int ret;
+	struct rcar_csi2 *priv;
+	/* Platform data specify the PHY, lanes, ECC, CRC */
+	struct rcar_csi2_pdata *pdata;
+	struct rcar_csi2_link_config link_config;
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	INIT_RCAR_CSI2_LINK_CONFIG(link_config);
+
+	if (pdev->dev.of_node) {
+		ret = rcar_csi2_parse_dt(pdev->dev.of_node, &link_config);
+		if (ret)
+			return ret;
+
+		if (link_config.lanes == 4)
+			dev_info(&pdev->dev,
+				"Detected rgb888 in rcar_csi2_parse_dt\n");
+		else
+			dev_info(&pdev->dev,
+				"Detected YCbCr422 in rcar_csi2_parse_dt\n");
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdata)
+			return -EINVAL;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct rcar_csi2), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* Interrupt unused so far */
+	irq = platform_get_irq(pdev, 0);
+
+	if (!res || (int)irq <= 0) {
+		dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+		return -ENODEV;
+	}
+
+	priv->irq = irq;
+
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	ret = devm_request_irq(&pdev->dev, irq, rcar_csi2_irq, IRQF_SHARED,
+			       dev_name(&pdev->dev), priv);
+	if (ret)
+		return ret;
+
+	priv->pdev = pdev;
+	priv->subdev.owner = THIS_MODULE;
+	priv->subdev.dev = &pdev->dev;
+	priv->lanes = link_config.lanes;
+	priv->vcdt = link_config.vcdt;
+	priv->vcdt2 = link_config.vcdt2;
+
+	platform_set_drvdata(pdev, &priv->subdev);
+
+	v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+	snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "rcar_csi2.%s",
+		 dev_name(&pdev->dev));
+
+	ret = v4l2_async_register_subdev(&priv->subdev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_init(&priv->lock);
+
+	pm_runtime_enable(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	return 0;
+}
+
+static int rcar_csi2_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct rcar_csi2 *priv = container_of(subdev, struct rcar_csi2, subdev);
+
+	v4l2_async_unregister_subdev(&priv->subdev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_csi2_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_csi2_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_csi2_pm_ops,
+			rcar_csi2_suspend, rcar_csi2_resume);
+#define DEV_PM_OPS (&rcar_csi2_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver __refdata rcar_csi2_pdrv = {
+	.remove	= rcar_csi2_remove,
+	.probe	= rcar_csi2_probe,
+	.driver	= {
+		.name	= DRV_NAME,
+		.pm	= DEV_PM_OPS,
+		.of_match_table	= of_match_ptr(rcar_csi2_of_table),
+	},
+	.id_table	= rcar_csi2_id_table,
+};
+
+module_platform_driver(rcar_csi2_pdrv);
+
+MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:rcar-csi2");
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index b7fd695..cde52ce 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -1,6 +1,7 @@
 /*
  * SoC-camera host driver for Renesas R-Car VIN unit
  *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2011-2013 Renesas Solutions Corp.
  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
  *
@@ -14,6 +15,10 @@
  * option) any later version.
  */
 
+#ifdef CONFIG_VIDEO_RCAR_VIN_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -25,6 +30,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <linux/list.h>
 
 #include <media/soc_camera.h>
 #include <media/drv-intf/soc_mediabus.h>
@@ -36,6 +42,8 @@
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-dma-contig.h>
 
+#include <media/rcar_csi2.h>
+
 #include "soc_scale_crop.h"
 
 #define DRV_NAME "rcar_vin"
@@ -90,6 +98,8 @@
 
 /* Register bit fields for R-Car VIN */
 /* Video n Main Control Register bits */
+#define VNMC_DPINE		(1 << 27)
+#define VNMC_SCLE		(1 << 26)
 #define VNMC_FOC		(1 << 21)
 #define VNMC_YCAL		(1 << 19)
 #define VNMC_INF_YUV8_BT656	(0 << 16)
@@ -98,6 +108,7 @@
 #define VNMC_INF_YUV10_BT601	(3 << 16)
 #define VNMC_INF_YUV16		(5 << 16)
 #define VNMC_INF_RGB888		(6 << 16)
+#define VNMC_INF_MASK		(7 << 16)
 #define VNMC_VUP		(1 << 10)
 #define VNMC_IM_ODD		(0 << 3)
 #define VNMC_IM_ODD_EVEN	(1 << 3)
@@ -119,12 +130,19 @@
 /* Video n Interrupt Enable Register bits */
 #define VNIE_FIE		(1 << 4)
 #define VNIE_EFE		(1 << 1)
+#define VNIE_FOE		(1 << 0)
+
+/* Video n Interrupt Status Register bits */
+#define VNINTS_FIS		(1 << 4)
+#define VNINTS_EFS		(1 << 1)
+#define VNINTS_FOS		(1 << 0)
 
 /* Video n Data Mode Register bits */
 #define VNDMR_EXRGB		(1 << 8)
 #define VNDMR_BPSM		(1 << 4)
 #define VNDMR_DTMD_YCSEP	(1 << 1)
-#define VNDMR_DTMD_ARGB1555	(1 << 0)
+#define VNDMR_DTMD_ARGB		(1 << 0)
+#define VNDMR_DTMD_YCSEP_YCBCR420	(3 << 0)
 
 /* Video n Data Mode Register 2 bits */
 #define VNDMR2_VPS		(1 << 30)
@@ -132,8 +150,25 @@
 #define VNDMR2_FTEV		(1 << 17)
 #define VNDMR2_VLV(n)		((n & 0xf) << 12)
 
-#define VIN_MAX_WIDTH		2048
-#define VIN_MAX_HEIGHT		2048
+/* setting CSI2 on R-Car Gen3*/
+#define VNCSI_IFMD_REG	0x20	/* Video n CSI2 Interface Mode Register */
+
+#define VNCSI_IFMD_DES2		(1 << 27) /* CSI40/CSI41 Input Data */
+#define VNCSI_IFMD_DES1		(1 << 26) /* CSI20 Input Data) */
+#define VNCSI_IFMD_DES0		(1 << 25) /* CSI21 Input Data) */
+
+#define VNCSI_IFMD_CSI_CHSEL(n)	(n << 0)
+
+/* UDS */
+#define VNUDS_CTRL_REG		0x80	/* Scaling Control Registers */
+#define VNUDS_CTRL_AMD		(1 << 30)
+#define VNUDS_CTRL_BC		(1 << 20)
+#define VNUDS_CTRL_TDIPC	(1 << 1)
+
+#define VNUDS_SCALE_REG		0x84	/* Scaling Factor Register */
+#define VNUDS_PASS_BWIDTH_REG	0x90	/* Passband Registers */
+#define VNUDS_IPC_REG		0x98	/* 2D IPC Setting Register */
+#define VNUDS_CLIP_SIZE_REG	0xA4	/* UDS Output Size Clipping Register */
 
 #define TIMEOUT_MS		100
 
@@ -141,14 +176,143 @@
 #define RCAR_VIN_VSYNC_ACTIVE_LOW	(1 << 1)
 #define RCAR_VIN_BT601			(1 << 2)
 #define RCAR_VIN_BT656			(1 << 3)
+#define RCAR_VIN_CSI2			(1 << 4)
+
+static int ifmd0_reg_match[6];
+static int ifmd4_reg_match[6];
+static int ifmd0_init = true;
+static int ifmd4_init = true;
 
 enum chip_id {
+	RCAR_GEN3,
 	RCAR_GEN2,
 	RCAR_H1,
 	RCAR_M1,
 	RCAR_E1,
 };
 
+enum csi2_ch {
+	RCAR_CSI_CH_NONE = -1,
+	RCAR_CSI40,
+	RCAR_CSI20,
+	RCAR_CSI41,
+	RCAR_CSI21,
+	RCAR_CSI_MAX,
+};
+
+enum gen3_vin_ch {
+	RCAR_VIN_CH_NONE = -1,
+	RCAR_VIDEO_0,
+	RCAR_VIDEO_1,
+	RCAR_VIDEO_2,
+	RCAR_VIDEO_3,
+	RCAR_VIDEO_4,
+	RCAR_VIDEO_5,
+	RCAR_VIDEO_6,
+	RCAR_VIDEO_7,
+	RCAR_VIDEO_MAX,
+};
+
+enum virtual_ch {
+	RCAR_VIRTUAL_NONE = -1,
+	RCAR_VIRTUAL_CH0,
+	RCAR_VIRTUAL_CH1,
+	RCAR_VIRTUAL_CH2,
+	RCAR_VIRTUAL_CH3,
+	RCAR_VIRTUAL_MAX,
+};
+
+struct vin_gen3_virtual_sel {
+	enum csi2_ch csi2_ch;
+	enum virtual_ch vc;
+};
+
+struct vin_gen3_ifmd {
+	unsigned int set_reg;
+	struct vin_gen3_virtual_sel v_sel[8];
+};
+
+static const struct vin_gen3_ifmd vin_vc_ifmd[] = {
+	{ 0x0000,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0001,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0002,
+		{
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0003,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH3},
+		}
+	},
+	{ 0x0004,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+		}
+	},
+	{ 0x0005,
+		{
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI21, RCAR_VIRTUAL_CH3},
+		}
+	},
+};
+
+enum csi2_fmt {
+	RCAR_CSI_FMT_NONE = -1,
+	RCAR_CSI_RGB888,
+	RCAR_CSI_YCBCR422,
+};
+
 struct vin_coeff {
 	unsigned short xs_value;
 	u32 coeff_set[24];
@@ -473,6 +637,19 @@
 	STOPPING,
 };
 
+struct rcar_vin_async_client {
+	struct v4l2_async_subdev *sensor;
+	struct v4l2_async_notifier notifier;
+	struct platform_device *pdev;
+	struct list_head list;		/* needed for clean up */
+};
+
+struct soc_of_info {
+	struct soc_camera_async_subdev	sasd;
+	struct rcar_vin_async_client	sasc;
+	struct v4l2_async_subdev	*subdev;
+};
+
 struct rcar_vin_priv {
 	void __iomem			*base;
 	spinlock_t			lock;
@@ -491,6 +668,21 @@
 	bool				request_to_stop;
 	struct completion		capture_stop;
 	enum chip_id			chip;
+	unsigned int			max_width;
+	unsigned int			max_height;
+	bool				error_flag;
+	enum csi2_ch			csi_ch;
+	enum csi2_fmt			csi_fmt;
+	enum virtual_ch			vc;
+	bool				csi_sync;
+
+	struct rcar_vin_async_client	*async_client;
+	/* Asynchronous CSI2 linking */
+	struct v4l2_subdev		*csi2_sd;
+	/* Synchronous probing compatibility */
+	struct platform_device		*csi2_pdev;
+
+	unsigned int			index;
 };
 
 #define is_continuous_transfer(priv)	(priv->vb_count > MAX_BUFFER_NUM)
@@ -525,6 +717,69 @@
 	const struct soc_mbus_pixelfmt	*extra_fmt;
 };
 
+#define VIN_UT_IRQ	0x01
+
+static unsigned int vin_debug;
+module_param_named(debug, vin_debug, int, 0600);
+static int overflow_video[RCAR_VIDEO_MAX];
+module_param_array(overflow_video, int, NULL, 0600);
+
+#ifdef CONFIG_VIDEO_RCAR_VIN_DEBUG
+#define VIN_IRQ_DEBUG(fmt, args...)					\
+	do {								\
+		if (unlikely(vin_debug & VIN_UT_IRQ))			\
+			vin_ut_debug_printk(__func__, fmt, ##args);	\
+	} while (0)
+#else
+#define VIN_IRQ_DEBUG(fmt, args...)
+#endif
+
+void vin_ut_debug_printk(const char *function_name, const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	pr_debug("[" DRV_NAME ":%s] %pV", function_name, &vaf);
+
+	va_end(args);
+}
+
+static void rcar_vin_cpg_enable_for_ifmd(unsigned int ch, bool enable)
+{
+	void __iomem *smstpcr8;
+
+	smstpcr8 = ioremap(0xE6150990, 0x04);
+
+	if (enable) {
+		if (ch < RCAR_VIDEO_4)
+			iowrite32((ioread32(smstpcr8) & 0xFFFFF7FF), smstpcr8);
+		else
+			iowrite32((ioread32(smstpcr8) & 0xFFFFFF7F), smstpcr8);
+	} else {
+		if (ch < RCAR_VIDEO_4)
+			iowrite32((ioread32(smstpcr8) | 0x00000800), smstpcr8);
+		else
+			iowrite32((ioread32(smstpcr8) | 0x00000080), smstpcr8);
+	}
+
+	iounmap(smstpcr8);
+}
+
+static inline int is_scaling(struct rcar_vin_cam *cam)
+{
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+
+	if ((cam_subrect->width != cam->out_width) ||
+		(cam_subrect->height != cam->out_height))
+		return 1;
+
+	return 0;
+}
+
 /*
  * .queue_setup() is called to check whether the driver can accept the requested
  * number of buffers and to fill in plane sizes for the current frame format if
@@ -538,6 +793,18 @@
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct rcar_vin_priv *priv = ici->priv;
+	struct rcar_vin_cam *cam = icd->host_priv;
+
+	if (priv->chip == RCAR_GEN3) {
+		if (is_scaling(cam) && (cam->out_width % 32)) {
+			dev_err(icd->parent, "Scaling parameter error\n");
+			return -EINVAL;
+		}
+		if (!is_scaling(cam) && (cam->out_width % 16)) {
+			dev_err(icd->parent, "Image stride parameter error\n");
+			return -EINVAL;
+		}
+	}
 
 	alloc_ctxs[0] = priv->alloc_ctx;
 
@@ -627,8 +894,19 @@
 
 	/* output format */
 	switch (icd->current_fmt->host_fmt->fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		if (priv->chip == RCAR_GEN3) {
+			iowrite32(ALIGN((cam->out_width * cam->out_height),
+					 0x80), priv->base + VNUVAOF_REG);
+			dmr = VNDMR_DTMD_YCSEP_YCBCR420;
+			output_is_yuv = true;
+		} else {
+			dev_warn(icd->parent, "Not support format\n");
+			return -EINVAL;
+		}
+		break;
 	case V4L2_PIX_FMT_NV16:
-		iowrite32(ALIGN(cam->width * cam->height, 0x80),
+		iowrite32(ALIGN((cam->out_width * cam->out_height), 0x80),
 			  priv->base + VNUVAOF_REG);
 		dmr = VNDMR_DTMD_YCSEP;
 		output_is_yuv = true;
@@ -641,18 +919,27 @@
 		dmr = 0;
 		output_is_yuv = true;
 		break;
-	case V4L2_PIX_FMT_RGB555X:
-		dmr = VNDMR_DTMD_ARGB1555;
+	case V4L2_PIX_FMT_ARGB555:
+		dmr = VNDMR_DTMD_ARGB;
 		break;
 	case V4L2_PIX_FMT_RGB565:
 		dmr = 0;
 		break;
 	case V4L2_PIX_FMT_RGB32:
-		if (priv->chip == RCAR_GEN2 || priv->chip == RCAR_H1 ||
+		if (priv->chip == RCAR_GEN3 ||
+		    priv->chip == RCAR_GEN2 || priv->chip == RCAR_H1 ||
 		    priv->chip == RCAR_E1) {
 			dmr = VNDMR_EXRGB;
 			break;
 		}
+	case V4L2_PIX_FMT_ARGB32:
+		if (priv->chip == RCAR_GEN3)
+			dmr = VNDMR_EXRGB | VNDMR_DTMD_ARGB;
+		else {
+			dev_err(icd->parent, "Not support format\n");
+			return -EINVAL;
+		}
+		break;
 	default:
 		dev_warn(icd->parent, "Invalid fourcc format (0x%x)\n",
 			 icd->current_fmt->host_fmt->fourcc);
@@ -666,9 +953,24 @@
 	if (input_is_yuv == output_is_yuv)
 		vnmc |= VNMC_BPS;
 
+	if (priv->chip == RCAR_GEN3) {
+		if (priv->pdata_flags & RCAR_VIN_CSI2)
+			vnmc &= ~VNMC_DPINE;
+		else
+			vnmc |= VNMC_DPINE;
+
+		if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+			&& is_scaling(cam))
+			vnmc |= VNMC_SCLE;
+	}
+
 	/* progressive or interlaced mode */
 	interrupts = progressive ? VNIE_FIE : VNIE_EFE;
 
+	/* Enable Overflow */
+	if (vin_debug)
+		interrupts |= VNIE_FOE;
+
 	/* ack interrupts */
 	iowrite32(interrupts, priv->base + VNINTS_REG);
 	/* enable interrupts */
@@ -863,16 +1165,25 @@
 	bool can_run = false, hw_stopped;
 	int slot;
 	unsigned int handled = 0;
+	int vin_ovr_cnt = 0;
 
 	spin_lock(&priv->lock);
 
 	int_status = ioread32(priv->base + VNINTS_REG);
 	if (!int_status)
 		goto done;
+
 	/* ack interrupts */
 	iowrite32(int_status, priv->base + VNINTS_REG);
 	handled = 1;
 
+	/* overflow occurs */
+	if (vin_debug && (int_status & VNINTS_FOS)) {
+		vin_ovr_cnt = ++overflow_video[priv->index];
+		VIN_IRQ_DEBUG("overflow occurrs num[%d] at VIN (%s)\n",
+				vin_ovr_cnt, dev_name(priv->ici.v4l2_dev.dev));
+	}
+
 	/* nothing to do if capture status is 'STOPPED' */
 	if (priv->state == STOPPED)
 		goto done;
@@ -923,6 +1234,21 @@
 	return IRQ_RETVAL(handled);
 }
 
+static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev)
+{
+	struct v4l2_subdev *sd;
+	char name[] = "rcar_csi2";
+
+	v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) {
+		if (!strncmp(name, sd->name, sizeof(name) - 1)) {
+			pcdev->csi2_sd = sd;
+			return sd;
+		}
+	}
+
+	return NULL;
+}
+
 static int rcar_vin_add_device(struct soc_camera_device *icd)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -934,8 +1260,40 @@
 
 	pm_runtime_get_sync(ici->v4l2_dev.dev);
 
-	dev_dbg(icd->parent, "R-Car VIN driver attached to camera %d\n",
-		icd->devnum);
+	if (priv->chip == RCAR_GEN3) {
+		struct v4l2_subdev *csi2_sd = find_csi2(priv);
+		int ret;
+
+		if (csi2_sd) {
+			csi2_sd->grp_id = soc_camera_grp_id(icd);
+			v4l2_set_subdev_hostdata(csi2_sd, icd);
+
+			ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
+			priv->csi_sync = true;
+
+			if (ret < 0 && ret != -EINVAL)
+				priv->csi_sync = false;
+
+			if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+				return ret;
+		}
+		/*
+		 * -ENODEV is special:
+		 * either csi2_sd == NULL or the CSI-2 driver
+		 * has not found this soc-camera device among its clients
+		 */
+		if (csi2_sd && ret == -ENODEV)
+			csi2_sd->grp_id = 0;
+
+		dev_dbg(icd->parent,
+			"R-Car VIN/CSI-2 driver attached to camera %d\n",
+			icd->devnum);
+
+	} else
+		dev_dbg(icd->parent, "R-Car VIN driver attached to camera %d\n",
+			icd->devnum);
+
+	priv->error_flag = false;
 
 	return 0;
 }
@@ -945,6 +1303,7 @@
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct rcar_vin_priv *priv = ici->priv;
 	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_subdev *csi2_sd = find_csi2(priv);
 	int i;
 
 	/* disable capture, disable interrupts */
@@ -954,6 +1313,7 @@
 
 	priv->state = STOPPED;
 	priv->request_to_stop = false;
+	priv->error_flag = false;
 
 	/* make sure active buffer is cancelled */
 	spin_lock_irq(&priv->lock);
@@ -968,10 +1328,78 @@
 
 	pm_runtime_put(ici->v4l2_dev.dev);
 
+	if ((csi2_sd) && (priv->csi_sync))
+		v4l2_subdev_call(csi2_sd, core, s_power, 0);
+
 	dev_dbg(icd->parent, "R-Car VIN driver detached from camera %d\n",
 		icd->devnum);
 }
 
+struct rcar_vin_uds_regs {
+	unsigned long ctrl;
+	unsigned long scale;
+	unsigned long pass_bwidth;
+	unsigned long clip_size;
+};
+
+static unsigned long rcar_vin_get_bwidth(unsigned long ratio)
+{
+	unsigned long bwidth;
+	unsigned long mant, frac;
+
+	mant = (ratio & 0xF000) >> 12;
+	frac = ratio & 0x0FFF;
+	if (mant)
+		bwidth = 64 * 4096 * mant / (4096 * mant + frac);
+	else
+		bwidth = 64;
+
+	return bwidth;
+}
+
+static unsigned long rcar_vin_compute_ratio(unsigned int input,
+		unsigned int output)
+{
+	if (output > input)
+		return input * 4096 / output;
+	else
+		return (input - 1) * 4096 / (output - 1);
+}
+
+int rcar_vin_uds_set(struct rcar_vin_priv *priv, struct rcar_vin_cam *cam)
+{
+	struct rcar_vin_uds_regs regs;
+	unsigned long ratio_h, ratio_v;
+	unsigned long bwidth_h, bwidth_v;
+	unsigned long ctrl;
+	unsigned long clip_size;
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+	u32 vnmc;
+
+	ratio_h = rcar_vin_compute_ratio(cam_subrect->width, cam->out_width);
+	ratio_v = rcar_vin_compute_ratio(cam_subrect->height, cam->out_height);
+
+	bwidth_h = rcar_vin_get_bwidth(ratio_h);
+	bwidth_v = rcar_vin_get_bwidth(ratio_v);
+
+	ctrl = VNUDS_CTRL_AMD;
+	clip_size = (cam->out_width << 16) | cam->out_height;
+
+	regs.ctrl = ctrl;
+	regs.scale = (ratio_h << 16) | ratio_v;
+	regs.pass_bwidth = (bwidth_h << 16) | bwidth_v;
+	regs.clip_size = clip_size;
+
+	vnmc = ioread32(priv->base + VNMC_REG);
+	iowrite32(vnmc | VNMC_SCLE, priv->base + VNMC_REG);
+	iowrite32(regs.ctrl, priv->base + VNUDS_CTRL_REG);
+	iowrite32(regs.scale, priv->base + VNUDS_SCALE_REG);
+	iowrite32(regs.pass_bwidth, priv->base + VNUDS_PASS_BWIDTH_REG);
+	iowrite32(regs.clip_size, priv->base + VNUDS_CLIP_SIZE_REG);
+
+	return 0;
+}
+
 static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs)
 {
 	int i;
@@ -1036,6 +1464,7 @@
 	unsigned char dsize = 0;
 	struct v4l2_rect *cam_subrect = &cam->subrect;
 	u32 value;
+	int ret = 0;
 
 	dev_dbg(icd->parent, "Crop %ux%u@%u:%u\n",
 		icd->user_width, icd->user_height, cam->vin_left, cam->vin_top);
@@ -1072,49 +1501,69 @@
 		break;
 	}
 
-	/* Set scaling coefficient */
-	value = 0;
-	if (cam_subrect->height != cam->out_height)
-		value = (4096 * cam_subrect->height) / cam->out_height;
-	dev_dbg(icd->parent, "YS Value: %x\n", value);
-	iowrite32(value, priv->base + VNYS_REG);
+	if (priv->chip == RCAR_GEN3) {
+		if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+			&& is_scaling(cam)) {
+			ret = rcar_vin_uds_set(priv, cam);
+			if (ret < 0)
+				return ret;
+		}
+		if (is_scaling(cam) ||
+		   (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV16) ||
+		   (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV12))
+			iowrite32(ALIGN(cam->out_width, 0x20),
+				 priv->base + VNIS_REG);
+		else
+			iowrite32(ALIGN(cam->out_width, 0x10),
+				 priv->base + VNIS_REG);
+	} else {
+		/* Set scaling coefficient */
+		value = 0;
+		if (cam_subrect->height != cam->out_height)
+			value = (4096 * cam_subrect->height) / cam->out_height;
+		dev_dbg(icd->parent, "YS Value: %x\n", value);
+		iowrite32(value, priv->base + VNYS_REG);
 
-	value = 0;
-	if (cam_subrect->width != cam->out_width)
-		value = (4096 * cam_subrect->width) / cam->out_width;
+		value = 0;
+		if (cam_subrect->width != cam->out_width)
+			value = (4096 * cam_subrect->width) / cam->out_width;
 
-	/* Horizontal upscaling is up to double size */
-	if (0 < value && value < 2048)
-		value = 2048;
+		/* Horizontal upscaling is up to double size */
+		if (value < 2048)
+			value = 2048;
 
-	dev_dbg(icd->parent, "XS Value: %x\n", value);
-	iowrite32(value, priv->base + VNXS_REG);
+		dev_dbg(icd->parent, "XS Value: %x\n", value);
+		iowrite32(value, priv->base + VNXS_REG);
 
-	/* Horizontal upscaling is carried out by scaling down from double size */
-	if (value < 4096)
-		value *= 2;
+		/* Horizontal upscaling is carried out */
+		/* by scaling down from double size */
+		if (value < 4096)
+			value *= 2;
 
-	set_coeff(priv, value);
+		set_coeff(priv, value);
 
-	/* Set Start/End Pixel/Line Post-Clip */
-	iowrite32(0, priv->base + VNSPPOC_REG);
-	iowrite32(0, priv->base + VNSLPOC_REG);
-	iowrite32((cam->out_width - 1) << dsize, priv->base + VNEPPOC_REG);
-	switch (priv->field) {
-	case V4L2_FIELD_INTERLACED:
-	case V4L2_FIELD_INTERLACED_TB:
-	case V4L2_FIELD_INTERLACED_BT:
-		iowrite32(cam->out_height / 2 - 1,
-			  priv->base + VNELPOC_REG);
-		break;
-	default:
-		iowrite32(cam->out_height - 1, priv->base + VNELPOC_REG);
-		break;
+		/* Set Start/End Pixel/Line Post-Clip */
+		iowrite32(0, priv->base + VNSPPOC_REG);
+		iowrite32(0, priv->base + VNSLPOC_REG);
+		iowrite32((cam->out_width - 1) << dsize,
+			priv->base + VNEPPOC_REG);
+		switch (priv->field) {
+		case V4L2_FIELD_INTERLACED:
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+			iowrite32(cam->out_height / 2 - 1,
+				  priv->base + VNELPOC_REG);
+			break;
+		default:
+			iowrite32(cam->out_height - 1,
+				priv->base + VNELPOC_REG);
+			break;
+		}
+
+		iowrite32(ALIGN(cam->out_width, 0x10), priv->base + VNIS_REG);
 	}
 
-	iowrite32(ALIGN(cam->out_width, 0x10), priv->base + VNIS_REG);
-
-	return 0;
+	return ret;
 }
 
 static void capture_stop_preserve(struct rcar_vin_priv *priv, u32 *vnmc)
@@ -1203,7 +1652,17 @@
 	if (ret < 0 && ret != -ENOIOCTLCMD)
 		return ret;
 
-	val = VNDMR2_FTEV | VNDMR2_VLV(1);
+	if (priv->chip == RCAR_GEN3) {
+		if (cfg.type == V4L2_MBUS_CSI2)
+			vnmc &= ~VNMC_DPINE;
+		else
+			vnmc |= VNMC_DPINE;
+	}
+
+	if (priv->chip == RCAR_GEN3)
+		val = VNDMR2_FTEV;
+	else
+		val = VNDMR2_FTEV | VNDMR2_VLV(1);
 	if (!(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
 		val |= VNDMR2_VPS;
 	if (!(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
@@ -1256,6 +1715,14 @@
 
 static const struct soc_mbus_pixelfmt rcar_vin_formats[] = {
 	{
+		.fourcc			= V4L2_PIX_FMT_NV12,
+		.name			= "NV12",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+	},
+	{
 		.fourcc			= V4L2_PIX_FMT_NV16,
 		.name			= "NV16",
 		.bits_per_sample	= 8,
@@ -1288,7 +1755,7 @@
 		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 	{
-		.fourcc			= V4L2_PIX_FMT_RGB555X,
+		.fourcc			= V4L2_PIX_FMT_ARGB555,
 		.name			= "ARGB1555",
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_NONE,
@@ -1303,6 +1770,14 @@
 		.order			= SOC_MBUS_ORDER_LE,
 		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
+	{
+		.fourcc			= V4L2_PIX_FMT_ARGB32,
+		.name			= "ARGB8888",
+		.bits_per_sample	= 32,
+		.packing		= SOC_MBUS_PACKING_NONE,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PACKED,
+	},
 };
 
 static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
@@ -1313,6 +1788,8 @@
 	int ret, k, n;
 	int formats = 0;
 	struct rcar_vin_cam *cam;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct rcar_vin_priv *priv = ici->priv;
 	struct v4l2_subdev_mbus_code_enum code = {
 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 		.index = idx,
@@ -1363,8 +1840,8 @@
 		 * 1280x960, 640x480, 320x240
 		 */
 		for (shift = 0; shift < 3; shift++) {
-			if (mf->width <= VIN_MAX_WIDTH &&
-			    mf->height <= VIN_MAX_HEIGHT)
+			if (mf->width <= priv->max_width &&
+			    mf->height <= priv->max_height)
 				break;
 
 			mf->width = 1280 >> shift;
@@ -1455,6 +1932,294 @@
 	icd->host_priv = NULL;
 }
 
+static bool rcar_vin_is_smaller(const struct v4l2_rect *r1,
+				const struct v4l2_rect *r2)
+{
+	return r1->width < r2->width || r1->height < r2->height;
+}
+
+static bool rcar_vin_is_inside(const struct v4l2_rect *r1,
+			       const struct v4l2_rect *r2)
+{
+	return r1->left > r2->left || r1->top > r2->top ||
+		r1->left + r1->width < r2->left + r2->width ||
+		r1->top + r1->height < r2->top + r2->height;
+}
+
+static void rcar_vin_update_subrect(struct v4l2_rect *rect,
+				    struct v4l2_rect *subrect)
+{
+	if (rect->width < subrect->width)
+		subrect->width = rect->width;
+
+	if (rect->height < subrect->height)
+		subrect->height = rect->height;
+
+	if (rect->left > subrect->left)
+		subrect->left = rect->left;
+	else if (rect->left + rect->width <
+		 subrect->left + subrect->width)
+		subrect->left = rect->left + rect->width -
+			subrect->width;
+
+	if (rect->top > subrect->top)
+		subrect->top = rect->top;
+	else if (rect->top + rect->height <
+		 subrect->top + subrect->height)
+		subrect->top = rect->top + rect->height -
+			subrect->height;
+}
+
+/* Iterative set_fmt, also updates cached client crop on success */
+static int rcar_vin_client_set_fmt(struct soc_camera_device *icd,
+			struct v4l2_rect *rect, struct v4l2_rect *subrect,
+			unsigned int max_width, unsigned int max_height,
+			struct v4l2_subdev_format *format, bool host_can_scale)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
+	struct v4l2_cropcap cap;
+	bool host_1to1;
+	int ret;
+
+	ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					 soc_camera_grp_id(icd), pad,
+					 set_fmt, NULL, format);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+	if (width == mf->width && height == mf->height) {
+		/* Perfect! The client has done it all. */
+		host_1to1 = true;
+		goto update_cache;
+	}
+
+	host_1to1 = false;
+	if (!host_can_scale)
+		goto update_cache;
+
+	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	if (max_width > cap.bounds.width)
+		max_width = cap.bounds.width;
+	if (max_height > cap.bounds.height)
+		max_height = cap.bounds.height;
+
+	/* Camera set a format, but geometry is not precise, try to improve */
+	tmp_w = mf->width;
+	tmp_h = mf->height;
+
+	/* width <= max_width && height <= max_height - guaranteed by try_fmt */
+	while ((width > tmp_w || height > tmp_h) &&
+	       tmp_w < max_width && tmp_h < max_height) {
+		tmp_w = min(2 * tmp_w, max_width);
+		tmp_h = min(2 * tmp_h, max_height);
+		mf->width = tmp_w;
+		mf->height = tmp_h;
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), pad,
+					set_fmt, NULL, format);
+		dev_dbg(dev, "Camera scaled to %ux%u\n",
+			mf->width, mf->height);
+		if (ret < 0) {
+			/* This shouldn't happen */
+			dev_err(dev, "Client failed to set format: %d\n", ret);
+			return ret;
+		}
+	}
+
+update_cache:
+	/* Update cache */
+	ret = soc_camera_client_g_rect(sd, rect);
+	if (ret < 0)
+		return ret;
+
+	if (!host_1to1)
+		rcar_vin_update_subrect(rect, subrect);
+
+	return 0;
+}
+
+int rcar_vin_client_scale(struct soc_camera_device *icd,
+			struct v4l2_rect *rect, struct v4l2_rect *subrect,
+			struct v4l2_mbus_framefmt *mf,
+			unsigned int *width, unsigned int *height,
+			bool host_can_scale, unsigned int shift)
+{
+	struct device *dev = icd->parent;
+	struct v4l2_subdev_format fmt_tmp = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.format = *mf,
+	};
+	struct v4l2_mbus_framefmt *mf_tmp = &fmt_tmp.format;
+	unsigned int scale_h, scale_v;
+	int ret;
+
+	/*
+	 * 5. Apply iterative camera S_FMT for camera user window (also updates
+	 *    client crop cache and the imaginary sub-rectangle).
+	 */
+	ret = rcar_vin_client_set_fmt(icd, rect, subrect, *width, *height,
+			   &fmt_tmp, host_can_scale);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "5: camera scaled to %ux%u\n",
+		mf_tmp->width, mf_tmp->height);
+
+	/* 6. Retrieve camera output window (g_fmt) */
+
+	/* unneeded - it is already in "mf_tmp" */
+
+	/* 7. Calculate new client scales. */
+	scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp->width);
+	scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp->height);
+
+	mf->width	= mf_tmp->width;
+	mf->height	= mf_tmp->height;
+	mf->colorspace	= mf_tmp->colorspace;
+
+	/*
+	 * 8. Calculate new host crop - apply camera scales to previously
+	 *    updated "effective" crop.
+	 */
+	*width = soc_camera_shift_scale(subrect->width, shift, scale_h);
+	*height = soc_camera_shift_scale(subrect->height, shift, scale_v);
+
+	dev_dbg(dev, "8: new client sub-window %ux%u\n", *width, *height);
+
+	return 0;
+}
+
+int rcar_vin_client_s_crop(struct v4l2_subdev *sd,
+			struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+			struct v4l2_rect *target_rect,
+			struct v4l2_rect *subrect)
+{
+	struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+	struct device *dev = sd->v4l2_dev->dev;
+	struct v4l2_cropcap cap;
+	int ret;
+	unsigned int width, height;
+
+	v4l2_subdev_call(sd, video, s_crop, crop);
+	ret = soc_camera_client_g_rect(sd, cam_rect);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Now cam_crop contains the current camera input rectangle, and it must
+	 * be within camera cropcap bounds
+	 */
+	if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+		/* Even if camera S_CROP failed, but camera rectangle matches */
+		dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+			rect->width, rect->height, rect->left, rect->top);
+		*target_rect = *cam_rect;
+		*subrect = *rect;
+		return 0;
+	}
+
+	/* Try to fix cropping, that camera hasn't managed to set */
+	dev_dbg(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+		cam_rect->width, cam_rect->height,
+		cam_rect->left, cam_rect->top,
+		rect->width, rect->height, rect->left, rect->top);
+
+	/* We need sensor maximum rectangle */
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	/* Put user requested rectangle within sensor bounds */
+	soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+			      cap.bounds.width);
+	soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+			      cap.bounds.height);
+
+	/*
+	 * Popular special case - some cameras can only handle fixed sizes like
+	 * QVGA, VGA,... Take care to avoid infinite loop.
+	 */
+	width = max_t(unsigned int, cam_rect->width, 2);
+	height = max_t(unsigned int, cam_rect->height, 2);
+
+	/*
+	 * Loop as long as sensor is not covering the requested rectangle and
+	 * is still within its bounds
+	 */
+	while (!ret && (rcar_vin_is_smaller(cam_rect, rect) ||
+			rcar_vin_is_inside(cam_rect, rect)) &&
+	       (cap.bounds.width > width || cap.bounds.height > height)) {
+
+		width *= 2;
+		height *= 2;
+
+		cam_rect->width = width;
+		cam_rect->height = height;
+
+		/*
+		 * We do not know what capabilities the camera has to set up
+		 * left and top borders. We could try to be smarter in iterating
+		 * them, e.g., if camera current left is to the right of the
+		 * target left, set it to the middle point between the current
+		 * left and minimum left. But that would add too much
+		 * complexity: we would have to iterate each border separately.
+		 * Instead we just drop to the left and top bounds.
+		 */
+		if (cam_rect->left > rect->left)
+			cam_rect->left = cap.bounds.left;
+
+		if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+			cam_rect->width = rect->left + rect->width -
+				cam_rect->left;
+
+		if (cam_rect->top > rect->top)
+			cam_rect->top = cap.bounds.top;
+
+		if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+			cam_rect->height = rect->top + rect->height -
+				cam_rect->top;
+
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = soc_camera_client_g_rect(sd, cam_rect);
+		dev_dbg(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	/* S_CROP must not modify the rectangle */
+	if (rcar_vin_is_smaller(cam_rect, rect) ||
+		rcar_vin_is_inside(cam_rect, rect)) {
+		/*
+		 * The camera failed to configure a suitable cropping,
+		 * we cannot use the current rectangle, set to max
+		 */
+		*cam_rect = cap.bounds;
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = soc_camera_client_g_rect(sd, cam_rect);
+		dev_dbg(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	if (!ret) {
+		*target_rect = *cam_rect;
+		*subrect = *rect;
+		rcar_vin_update_subrect(target_rect, subrect);
+	}
+
+	return ret;
+}
+
 static int rcar_vin_set_crop(struct soc_camera_device *icd,
 			     const struct v4l2_crop *a)
 {
@@ -1482,7 +2247,7 @@
 	dev_dbg(dev, "VNMC_REG 0x%x\n", vnmc);
 
 	/* Apply iterative camera S_CROP for new input window. */
-	ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+	ret = rcar_vin_client_s_crop(sd, &a_writable, &cam_crop,
 				       &cam->rect, &cam->subrect);
 	if (ret < 0)
 		return ret;
@@ -1498,26 +2263,21 @@
 	if (ret < 0)
 		return ret;
 
-	if (mf->width > VIN_MAX_WIDTH || mf->height > VIN_MAX_HEIGHT)
+	if (mf->width > priv->max_width || mf->height > priv->max_height)
 		return -EINVAL;
 
 	/* Cache camera output window */
 	cam->width = mf->width;
 	cam->height = mf->height;
 
-	icd->user_width  = cam->width;
-	icd->user_height = cam->height;
-
-	cam->vin_left = rect->left & ~1;
-	cam->vin_top = rect->top & ~1;
+	cam->vin_left = rect->left;
+	cam->vin_top = rect->top;
 
 	/* Use VIN cropping to crop to the new window. */
 	ret = rcar_vin_set_rect(icd);
 	if (ret < 0)
 		return ret;
 
-	cam->subrect = *rect;
-
 	dev_dbg(dev, "VIN cropped to %ux%u@%u:%u\n",
 		icd->user_width, icd->user_height,
 		cam->vin_left, cam->vin_top);
@@ -1568,6 +2328,20 @@
 	dev_dbg(dev, "S_FMT(pix=0x%x, %ux%u)\n",
 		pixfmt, pix->width, pix->height);
 
+	/* At the time of NV16 capture format, the user has to specify */
+	/* the width of the multiple of 32 for H/W specification. */
+	if (priv->error_flag == false)
+		priv->error_flag = true;
+	else {
+		if (((pixfmt == V4L2_PIX_FMT_NV16) ||
+			(pixfmt == V4L2_PIX_FMT_NV12)) &&
+			(pix->width & 0x1F)) {
+			dev_dbg(icd->parent,
+			 "specify width of 32 multiple in separate format.\n");
+			return -EINVAL;
+		}
+	}
+
 	switch (pix->field) {
 	default:
 		pix->field = V4L2_FIELD_NONE;
@@ -1610,12 +2384,15 @@
 	case V4L2_PIX_FMT_RGB32:
 		can_scale = priv->chip != RCAR_E1;
 		break;
+	case V4L2_PIX_FMT_ARGB32:
 	case V4L2_PIX_FMT_UYVY:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_RGB565:
-	case V4L2_PIX_FMT_RGB555X:
+	case V4L2_PIX_FMT_ARGB555:
+	case V4L2_PIX_FMT_NV16:
 		can_scale = true;
 		break;
+	case V4L2_PIX_FMT_NV12:
 	default:
 		can_scale = false;
 		break;
@@ -1623,7 +2400,7 @@
 
 	dev_dbg(dev, "request camera output %ux%u\n", mf.width, mf.height);
 
-	ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect,
+	ret = rcar_vin_client_scale(icd, &cam->rect, &cam->subrect,
 				      &mf, &vin_sub_width, &vin_sub_height,
 				      can_scale, 12);
 
@@ -1681,6 +2458,8 @@
 			    struct v4l2_format *f)
 {
 	const struct soc_camera_format_xlate *xlate;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct rcar_vin_priv *priv = ici->priv;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct v4l2_subdev_pad_config pad_cfg;
@@ -1702,9 +2481,16 @@
 		pix->colorspace = icd->colorspace;
 	}
 
-	/* FIXME: calculate using depth and bus width */
-	v4l_bound_align_image(&pix->width, 2, VIN_MAX_WIDTH, 1,
-			      &pix->height, 4, VIN_MAX_HEIGHT, 2, 0);
+	/* When performing a YCbCr-422 format output, even if it performs */
+	/* odd number clipping by pixel post clip processing, */
+	/* it is outputted to a memory per even pixels. */
+	if ((pixfmt == V4L2_PIX_FMT_NV16) || (pixfmt == V4L2_PIX_FMT_NV12) ||
+		(pixfmt == V4L2_PIX_FMT_YUYV) || (pixfmt == V4L2_PIX_FMT_UYVY))
+		v4l_bound_align_image(&pix->width, 5, priv->max_width, 1,
+				      &pix->height, 2, priv->max_height, 0, 0);
+	else
+		v4l_bound_align_image(&pix->width, 5, priv->max_width, 0,
+				      &pix->height, 2, priv->max_height, 0, 0);
 
 	width = pix->width;
 	height = pix->height;
@@ -1725,11 +2511,19 @@
 	if (ret < 0)
 		return ret;
 
-	/* Adjust only if VIN cannot scale */
-	if (pix->width > mf->width * 2)
-		pix->width = mf->width * 2;
-	if (pix->height > mf->height * 3)
-		pix->height = mf->height * 3;
+	if (priv->chip == RCAR_GEN3) {
+		/* Adjust max scaling size for Gen3 */
+		if (pix->width > 4096)
+			pix->width = priv->max_width;
+		if (pix->height > 4096)
+			pix->height = priv->max_height;
+	} else {
+		/* Adjust only if VIN cannot scale */
+		if (pix->width > mf->width * 2)
+			pix->width = mf->width * 2;
+		if (pix->height > mf->height * 3)
+			pix->height = mf->height * 3;
+	}
 
 	pix->field = mf->field;
 	pix->colorspace = mf->colorspace;
@@ -1743,8 +2537,8 @@
 			 * requested a bigger rectangle, it will not return a
 			 * smaller one.
 			 */
-			mf->width = VIN_MAX_WIDTH;
-			mf->height = VIN_MAX_HEIGHT;
+			mf->width = priv->max_width;
+			mf->height = priv->max_height;
 			ret = v4l2_device_call_until_err(sd->v4l2_dev,
 							 soc_camera_grp_id(icd),
 							 pad, set_fmt, &pad_cfg,
@@ -1800,6 +2594,39 @@
 	return vb2_queue_init(vq);
 }
 
+static int rcar_vin_get_selection(struct soc_camera_device *icd,
+				  struct v4l2_selection *sel)
+{
+	/* TODO */
+	return 0;
+}
+
+static int rcar_vin_cropcap(struct soc_camera_device *icd,
+			    struct v4l2_cropcap *crop)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_mbus_framefmt *mf = &fmt.format;
+	int ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+	if (ret < 0)
+		return ret;
+
+	crop->bounds.left = 0;
+	crop->bounds.top  = 0;
+	crop->bounds.width = mf->width;
+	crop->bounds.height = mf->height;
+
+	/* default cropping rectangle */
+	crop->defrect = crop->bounds;
+	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
 static struct soc_camera_host_ops rcar_vin_host_ops = {
 	.owner		= THIS_MODULE,
 	.add		= rcar_vin_add_device,
@@ -1814,10 +2641,13 @@
 	.querycap	= rcar_vin_querycap,
 	.set_bus_param	= rcar_vin_set_bus_param,
 	.init_videobuf2	= rcar_vin_init_videobuf2,
+	.get_selection	= rcar_vin_get_selection,
+	.cropcap	= rcar_vin_cropcap,
 };
 
 #ifdef CONFIG_OF
 static const struct of_device_id rcar_vin_of_table[] = {
+	{ .compatible = "renesas,vin-r8a7795", .data = (void *)RCAR_GEN3 },
 	{ .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 },
@@ -1829,6 +2659,184 @@
 MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
 #endif
 
+#define MAP_MAX_NUM 32
+static DECLARE_BITMAP(device_map, MAP_MAX_NUM);
+static DEFINE_MUTEX(list_lock);
+
+static int rcar_vin_dyn_pdev(struct soc_camera_desc *sdesc,
+			       struct rcar_vin_async_client *sasc)
+{
+	struct platform_device *pdev;
+	int ret, i;
+
+	mutex_lock(&list_lock);
+	i = find_first_zero_bit(device_map, MAP_MAX_NUM);
+	if (i < MAP_MAX_NUM)
+		set_bit(i, device_map);
+	mutex_unlock(&list_lock);
+	if (i >= MAP_MAX_NUM)
+		return -ENOMEM;
+
+	pdev = platform_device_alloc("soc-camera-pdrv", ((2 * i) + 1));
+	if (!pdev)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc));
+	if (ret < 0) {
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	sasc->pdev = pdev;
+
+	return 0;
+}
+
+static int rcar_vin_async_bound(struct v4l2_async_notifier *notifier,
+				  struct v4l2_subdev *sd,
+				  struct v4l2_async_subdev *asd)
+{
+	/* None. */
+	return 0;
+}
+
+static void rcar_vin_async_unbind(struct v4l2_async_notifier *notifier,
+				    struct v4l2_subdev *sd,
+				    struct v4l2_async_subdev *asd)
+{
+	/* None. */
+}
+
+static int rcar_vin_async_probe(struct soc_camera_host *ici,
+			    struct soc_camera_device *icd)
+{
+	struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+	struct soc_camera_host_desc *shd = &sdesc->host_desc;
+	struct device *control = NULL;
+	int ret;
+
+	ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
+	if (ret < 0)
+		return ret;
+
+	if (shd->module_name)
+		ret = request_module(shd->module_name);
+
+	ret = shd->add_device(icd);
+
+	control = to_soc_camera_control(icd);
+	if (!control || !control->driver || !dev_get_drvdata(control) ||
+		!try_module_get(control->driver->owner)) {
+		shd->del_device(icd);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int rcar_vin_async_complete(struct v4l2_async_notifier *notifier)
+{
+	struct rcar_vin_async_client *sasc = container_of(notifier,
+					struct rcar_vin_async_client, notifier);
+	struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+	if (to_soc_camera_control(icd)) {
+		struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+		int ret;
+
+		mutex_lock(&list_lock);
+		ret = rcar_vin_async_probe(ici, icd);
+		mutex_unlock(&list_lock);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct soc_camera_device *rcar_vin_add_pdev(
+				struct rcar_vin_async_client *sasc)
+{
+	struct platform_device *pdev = sasc->pdev;
+	int ret;
+
+	ret = platform_device_add(pdev);
+
+	if (ret < 0 || !pdev->dev.driver)
+		return NULL;
+
+	return platform_get_drvdata(pdev);
+}
+
+static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv,
+		       struct soc_camera_host *ici,
+		       struct device_node *ep,
+		       struct device_node *remote)
+{
+	struct soc_camera_device *icd;
+	struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
+	struct rcar_vin_async_client *sasc;
+	struct soc_of_info *info;
+	struct i2c_client *client;
+	char clk_name[V4L2_SUBDEV_NAME_SIZE];
+	int ret;
+
+	/* allocate a new subdev and add match info to it */
+	info = devm_kzalloc(ici->v4l2_dev.dev, sizeof(struct soc_of_info),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->sasd.asd.match.of.node = remote;
+	info->sasd.asd.match_type = V4L2_ASYNC_MATCH_OF;
+	info->subdev = &info->sasd.asd;
+
+	/* Or shall this be managed by the soc-camera device? */
+	sasc = &info->sasc;
+
+	ret = rcar_vin_dyn_pdev(&sdesc, sasc);
+	if (ret < 0)
+		goto eallocpdev;
+
+	sasc->sensor = &info->sasd.asd;
+
+	icd = rcar_vin_add_pdev(sasc);
+	if (!icd) {
+		ret = -ENOMEM;
+		goto eaddpdev;
+	}
+
+	sasc->notifier.subdevs = &info->subdev;
+	sasc->notifier.num_subdevs = 1;
+	sasc->notifier.bound = rcar_vin_async_bound;
+	sasc->notifier.unbind = rcar_vin_async_unbind;
+	sasc->notifier.complete = rcar_vin_async_complete;
+
+	priv->async_client = sasc;
+
+	client = of_find_i2c_device_by_node(remote);
+
+	if (client)
+		snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+			 client->adapter->nr, client->addr);
+	else
+		snprintf(clk_name, sizeof(clk_name), "of-%s",
+			 of_node_full_name(remote));
+
+	ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
+	if (!ret)
+		return 0;
+
+	platform_device_del(sasc->pdev);
+eaddpdev:
+	platform_device_put(sasc->pdev);
+eallocpdev:
+	devm_kfree(ici->v4l2_dev.dev, info);
+	dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
+
+	return ret;
+}
+
 static int rcar_vin_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match = NULL;
@@ -1838,6 +2846,11 @@
 	struct resource *mem;
 	unsigned int pdata_flags;
 	int irq, ret;
+	const char *str;
+	unsigned int i;
+	struct device_node *epn = NULL, *ren = NULL;
+	bool csi_use = false;
+	int vc, num;
 
 	match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
 
@@ -1847,6 +2860,32 @@
 		return -EINVAL;
 	}
 
+	for (i = 0; ; i++) {
+		epn = of_graph_get_next_endpoint(pdev->dev.of_node,
+								epn);
+		if (!epn)
+			break;
+
+		ren = of_graph_get_remote_port(epn);
+		if (!ren) {
+			dev_notice(&pdev->dev, "no remote for %s\n",
+					of_node_full_name(epn));
+			continue;
+		}
+
+		/* so we now have a remote node to connect */
+		dev_dbg(&pdev->dev, "node name:%s\n",
+			of_node_full_name(ren->parent));
+
+		if (strcmp(ren->parent->name, "csi2") == 0)
+			csi_use = true;
+
+		of_node_put(ren);
+
+		if (i)
+			break;
+	}
+
 	ret = v4l2_of_parse_endpoint(np, &ep);
 	if (ret) {
 		dev_err(&pdev->dev, "could not parse endpoint\n");
@@ -1855,6 +2894,8 @@
 
 	if (ep.bus_type == V4L2_MBUS_BT656)
 		pdata_flags = RCAR_VIN_BT656;
+	else if (ep.bus_type == V4L2_MBUS_CSI2)
+		pdata_flags = RCAR_VIN_BT656 | RCAR_VIN_CSI2;
 	else {
 		pdata_flags = 0;
 		if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
@@ -1897,6 +2938,164 @@
 	priv->ici.v4l2_dev.dev = &pdev->dev;
 	priv->ici.drv_name = dev_name(&pdev->dev);
 	priv->ici.ops = &rcar_vin_host_ops;
+	priv->csi_sync = false;
+
+	if (priv->chip <= RCAR_GEN3) {
+		priv->max_width = 4096;
+		priv->max_height = 4096;
+	} else {
+		priv->max_width = 2048;
+		priv->max_height = 2048;
+	}
+
+	if (priv->chip == RCAR_GEN3) {
+		u32 ifmd = 0;
+		bool match_flag = false;
+
+		if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef0000.video") == 0)
+			priv->index = RCAR_VIDEO_0;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef1000.video") == 0)
+			priv->index = RCAR_VIDEO_1;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef2000.video") == 0)
+			priv->index = RCAR_VIDEO_2;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef3000.video") == 0)
+			priv->index = RCAR_VIDEO_3;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef4000.video") == 0)
+			priv->index = RCAR_VIDEO_4;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef5000.video") == 0)
+			priv->index = RCAR_VIDEO_5;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef6000.video") == 0)
+			priv->index = RCAR_VIDEO_6;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef7000.video") == 0)
+			priv->index = RCAR_VIDEO_7;
+		else
+			priv->index = RCAR_VIN_CH_NONE;
+
+		ret = of_property_read_string(np, "csi,select", &str);
+		if (ret) {
+			dev_err(&pdev->dev, "could not parse csi,select\n");
+			return ret;
+		}
+
+		if (strcmp(str, "csi40") == 0)
+			priv->csi_ch = RCAR_CSI40;
+		else if (strcmp(str, "csi20") == 0)
+			priv->csi_ch = RCAR_CSI20;
+		else if (strcmp(str, "csi41") == 0)
+			priv->csi_ch = RCAR_CSI41;
+		else if (strcmp(str, "csi21") == 0)
+			priv->csi_ch = RCAR_CSI21;
+		else
+			priv->csi_ch = RCAR_CSI_CH_NONE;
+
+		ret = of_property_read_u32(np, "virtual,channel", &vc);
+		if (ret) {
+			dev_err(&pdev->dev,
+			"could not parse virtual,channel\n");
+			return ret;
+		}
+
+		if (vc == 0)
+			priv->vc = RCAR_VIRTUAL_CH0;
+		else if (vc == 1)
+			priv->vc = RCAR_VIRTUAL_CH1;
+		else if (vc == 2)
+			priv->vc = RCAR_VIRTUAL_CH2;
+		else if (vc == 3)
+			priv->vc = RCAR_VIRTUAL_CH3;
+		else
+			priv->vc = RCAR_VIRTUAL_NONE;
+
+		dev_dbg(&pdev->dev, "csi_ch:%d, vc:%d\n",
+					priv->csi_ch, priv->vc);
+
+		num = sizeof(vin_vc_ifmd) / sizeof(struct vin_gen3_ifmd);
+		for (i = 0; i < num; i++) {
+			if ((vin_vc_ifmd[i].v_sel[priv->index].csi2_ch
+				== priv->csi_ch) &&
+				(vin_vc_ifmd[i].v_sel[priv->index].vc
+				== priv->vc)) {
+				if (priv->index < RCAR_VIDEO_4) {
+					if (ifmd0_init) {
+						ifmd0_reg_match[i] = true;
+						match_flag = true;
+					} else if (ifmd0_reg_match[i])
+						match_flag = true;
+				} else {
+					if (ifmd4_init) {
+						ifmd4_reg_match[i] = true;
+						match_flag = true;
+					} else if (ifmd4_reg_match[i])
+						match_flag = true;
+				}
+			} else {
+				if (priv->index < RCAR_VIDEO_4)
+					ifmd0_reg_match[i] = false;
+				else
+					ifmd4_reg_match[i] = false;
+			}
+		}
+		if (priv->index < RCAR_VIDEO_4)
+			ifmd0_init = false;
+		else
+			ifmd4_init = false;
+
+		if (!match_flag) {
+			dev_err(&pdev->dev,
+			"Not match, virtual channel pattern error.\n");
+			return -EINVAL;
+		}
+
+		ifmd = VNCSI_IFMD_DES2 | VNCSI_IFMD_DES1 | VNCSI_IFMD_DES0;
+
+		rcar_vin_cpg_enable_for_ifmd(priv->index, true);
+
+		if (priv->index < RCAR_VIDEO_4) {
+			void __iomem *ifmd0_mem;
+			int i, num;
+
+			num = sizeof(vin_vc_ifmd) /
+				 sizeof(struct vin_gen3_ifmd);
+
+			for (i = 0; i < num; i++) {
+				if (ifmd0_reg_match[i]) {
+					ifmd |= vin_vc_ifmd[i].set_reg;
+					break;
+				}
+			}
+
+			ifmd0_mem = ioremap(0xe6ef0000 + VNCSI_IFMD_REG, 0x04);
+			iowrite32(ifmd, ifmd0_mem);
+			iounmap(ifmd0_mem);
+		} else {
+			void __iomem *ifmd4_mem;
+			int i, num;
+
+			num = sizeof(vin_vc_ifmd) /
+				 sizeof(struct vin_gen3_ifmd);
+
+			for (i = 0; i < num; i++) {
+				if (ifmd4_reg_match[i]) {
+					ifmd |= vin_vc_ifmd[i].set_reg;
+					break;
+				}
+			}
+
+			ifmd4_mem = ioremap(0xe6ef4000 + VNCSI_IFMD_REG, 0x04);
+			iowrite32(ifmd, ifmd4_mem);
+			iounmap(ifmd4_mem);
+		}
+
+		rcar_vin_cpg_enable_for_ifmd(priv->index, false);
+	}
 
 	priv->pdata_flags = pdata_flags;
 	if (!match) {
@@ -1919,6 +3118,14 @@
 	if (ret)
 		goto cleanup;
 
+	if (csi_use) {
+		ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ren->parent);
+		if (ret)
+			goto cleanup;
+	}
+
+	vin_debug = 0;
+
 	return 0;
 
 cleanup:
@@ -1934,6 +3141,11 @@
 	struct rcar_vin_priv *priv = container_of(soc_host,
 						  struct rcar_vin_priv, ici);
 
+	platform_device_del(priv->async_client->pdev);
+	platform_device_put(priv->async_client->pdev);
+
+	v4l2_async_notifier_unregister(&priv->async_client->notifier);
+
 	soc_camera_host_unregister(soc_host);
 	pm_runtime_disable(&pdev->dev);
 	vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
@@ -1941,11 +3153,32 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rcar_vin_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_vin_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_vin_pm_ops,
+			rcar_vin_suspend, rcar_vin_resume);
+#define DEV_PM_OPS (&rcar_vin_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rcar_vin_driver = {
 	.probe		= rcar_vin_probe,
 	.remove		= rcar_vin_remove,
 	.driver		= {
 		.name		= DRV_NAME,
+		.pm		= DEV_PM_OPS,
 		.of_match_table	= of_match_ptr(rcar_vin_of_table),
 	},
 };
@@ -1955,3 +3188,4 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rcar_vin");
 MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index bda29bc..673491a 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -1,6 +1,7 @@
 /*
  * soc-camera generic scaling-cropping manipulation functions
  *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -405,3 +406,5 @@
 	mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
 }
 EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 910d6b8..06cbab6 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -1,7 +1,7 @@
 /*
  * vsp1.h  --  R-Car VSP1 Driver
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -55,6 +55,7 @@
 	unsigned int wpf_count;
 	unsigned int num_bru_inputs;
 	bool uapi;
+	bool fcpvd;
 };
 
 struct vsp1_device {
@@ -63,6 +64,7 @@
 
 	void __iomem *mmio;
 	struct clk *clock;
+	struct clk *fcpvd_clock;
 
 	struct mutex lock;
 	int ref_count;
@@ -87,10 +89,15 @@
 	struct vsp1_drm *drm;
 
 	bool use_dl;
+	int index;
+
+	dma_addr_t dl_addr;
+	unsigned int dl_body;
 };
 
 int vsp1_device_get(struct vsp1_device *vsp1);
 void vsp1_device_put(struct vsp1_device *vsp1);
+void vsp1_underrun_workaround(struct vsp1_device *vsp1, bool reset);
 
 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index);
 
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index a4dcccf..be890e3 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_dl.h  --  R-Car VSP1 Display List
  *
- * Copyright (C) 2015 Renesas Corporation
+ * Copyright (C) 2015-2016 Renesas Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include "vsp1.h"
 #include "vsp1_dl.h"
@@ -171,6 +172,12 @@
 	vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
 		   (list->reg_count * 8));
 
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+		dl->vsp1->dl_addr = list->dma;
+		dl->vsp1->dl_body = VI6_DL_BODY_SIZE_UPD |
+					   (list->reg_count * 8);
+	}
 	vsp1_dl_free_list(dl->lists.queued);
 	dl->lists.queued = list;
 
@@ -230,7 +237,12 @@
 		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
 		vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
 			   (list->reg_count * 8));
-
+		if (RCAR_PRR_IS_PRODUCT(H3) &&
+			(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+			dl->vsp1->dl_addr = list->dma;
+			dl->vsp1->dl_body = VI6_DL_BODY_SIZE_UPD |
+						   (list->reg_count * 8);
+		}
 		dl->lists.queued = list;
 		dl->lists.pending = NULL;
 	}
@@ -267,6 +279,7 @@
 {
 	struct vsp1_dl *dl;
 	unsigned int i;
+	int ret;
 
 	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
 	if (!dl)
@@ -294,6 +307,12 @@
 		list->body = dl->mem + VSP1_DL_BODY_SIZE * i;
 	}
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(dl->vsp1->dev, "product register init fail.\n");
+		return NULL;
+	}
+
 	return dl;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 302d02a..4f27df6 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_drm.c  --  R-Car VSP1 DRM API
  *
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -55,6 +55,20 @@
 }
 EXPORT_SYMBOL_GPL(vsp1_du_init);
 
+int vsp1_du_if_set_mute(struct device *dev, bool on)
+{
+	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+	struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+
+	if (on)
+		vsp1_pipeline_stop(pipe);
+	else
+		vsp1_pipeline_run(pipe);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_if_set_mute);
+
 /**
  * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
  * @dev: the VSP device
@@ -273,7 +287,7 @@
 int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 			  u32 pixelformat, unsigned int pitch,
 			  dma_addr_t mem[2], const struct v4l2_rect *src,
-			  const struct v4l2_rect *dst)
+			  const struct v4l2_rect *dst, u8 alpha)
 {
 	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 	struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
@@ -289,6 +303,7 @@
 		return -EINVAL;
 
 	rpf = vsp1->rpf[rpf_index];
+	rpf->alpha->cur.val = alpha;
 
 	if (pixelformat == 0) {
 		dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 7ecdaba..3fe711a 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_drv.c  --  R-Car VSP1 Driver
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -11,6 +11,10 @@
  * (at your option) any later version.
  */
 
+#ifdef CONFIG_VIDEO_RENESAS_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -20,6 +24,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/videodev2.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <media/v4l2-subdev.h>
 
@@ -35,17 +40,124 @@
 #include "vsp1_uds.h"
 #include "vsp1_video.h"
 
+#define VSP1_UT_IRQ	0x01
+
+static unsigned int vsp1_debug;	/* 1 to enable debug output */
+module_param_named(debug, vsp1_debug, int, 0600);
+static int underrun_vspd[4];
+module_param_array(underrun_vspd, int, NULL, 0600);
+
+#ifdef CONFIG_VIDEO_RENESAS_DEBUG
+#define VSP1_IRQ_DEBUG(fmt, args...)					\
+	do {								\
+		if (unlikely(vsp1_debug & VSP1_UT_IRQ))			\
+			vsp1_ut_debug_printk(__func__, fmt, ##args);	\
+	} while (0)
+#else
+#define VSP1_IRQ_DEBUG(fmt, args...)
+#endif
+
+void vsp1_ut_debug_printk(const char *function_name, const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	pr_debug("[vsp1 :%s] %pV", function_name, &vaf);
+
+	va_end(args);
+}
+
+#define SRCR7_REG		0xe61501cc
+#define	FCPVD0_REG		0xfea27000
+#define	FCPVD1_REG		0xfea2f000
+#define	FCPVD2_REG		0xfea37000
+#define	FCPVD3_REG		0xfea3f000
+
+#define FCP_RST_REG		0x0010
+#define FCP_RST_SOFTRST		0x00000001
+#define FCP_RST_WORKAROUND	0x00000010
+
+#define FCP_STA_REG		0x0018
+#define FCP_STA_ACT		0x00000001
+
+static void __iomem *fcpv_reg[4];
+static const unsigned int fcpvd_offset[] = {
+	FCPVD0_REG, FCPVD1_REG, FCPVD2_REG, FCPVD3_REG
+};
+
+void vsp1_underrun_workaround(struct vsp1_device *vsp1, bool reset)
+{
+	unsigned int timeout = 0;
+
+	/* 1. Disable clock stop of VSP */
+	vsp1_write(vsp1, VI6_CLK_CTRL0, VI6_CLK_CTRL0_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_CTRL1, VI6_CLK_CTRL1_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_DCSWT, VI6_CLK_DCSWT_WORKAROUND1);
+	vsp1_write(vsp1, VI6_CLK_DCSM0, VI6_CLK_DCSM0_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_DCSM1, VI6_CLK_DCSM1_WORKAROUND);
+
+	/* 2. Stop operation of VSP except bus access with module reset */
+	vsp1_write(vsp1, VI6_MRESET_ENB0, VI6_MRESET_ENB0_WORKAROUND1);
+	vsp1_write(vsp1, VI6_MRESET_ENB1, VI6_MRESET_ENB1_WORKAROUND);
+	vsp1_write(vsp1, VI6_MRESET, VI6_MRESET_WORKAROUND);
+
+	/* 3. Stop operation of FCPV with software reset */
+	iowrite32(FCP_RST_SOFTRST, fcpv_reg[vsp1->index] + FCP_RST_REG);
+
+	/* 4. Wait until FCP_STA.ACT become 0. */
+	while (1) {
+		if ((ioread32(fcpv_reg[vsp1->index] + FCP_STA_REG) &
+			FCP_STA_ACT) != FCP_STA_ACT)
+			break;
+
+		if (timeout == 100)
+			break;
+
+		timeout++;
+		udelay(1);
+	}
+
+	/* 5. Initialize the whole FCPV with module reset */
+	iowrite32(FCP_RST_WORKAROUND, fcpv_reg[vsp1->index] + FCP_RST_REG);
+
+	/* 6. Stop the whole operation of VSP with module reset */
+	/*    (note that register setting is not cleared) */
+	vsp1_write(vsp1, VI6_MRESET_ENB0, VI6_MRESET_ENB0_WORKAROUND2);
+	vsp1_write(vsp1, VI6_MRESET_ENB1, VI6_MRESET_ENB1_WORKAROUND);
+	vsp1_write(vsp1, VI6_MRESET, VI6_MRESET_WORKAROUND);
+
+	/* 7. Enable clock stop of VSP */
+	vsp1_write(vsp1, VI6_CLK_CTRL0, 0);
+	vsp1_write(vsp1, VI6_CLK_CTRL1, 0);
+	vsp1_write(vsp1, VI6_CLK_DCSWT, VI6_CLK_DCSWT_WORKAROUND2);
+	vsp1_write(vsp1, VI6_CLK_DCSM0, 0);
+	vsp1_write(vsp1, VI6_CLK_DCSM1, 0);
+
+	/* 8. Restart VSPD */
+	if (!reset) {
+		/* Necessary when headerless display list */
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), vsp1->dl_addr);
+		vsp1_write(vsp1, VI6_DL_BODY_SIZE, vsp1->dl_body);
+		vsp1_write(vsp1, VI6_CMD(0), VI6_CMD_STRCMD);
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * Interrupt Handling
  */
-
 static irqreturn_t vsp1_irq_handler(int irq, void *data)
 {
-	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
+	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE
+				       | VI6_WFP_IRQ_STA_UND;
 	struct vsp1_device *vsp1 = data;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned int i;
 	u32 status;
+	unsigned int vsp_und_cnt = 0;
 
 	for (i = 0; i < vsp1->info->wpf_count; ++i) {
 		struct vsp1_rwpf *wpf = vsp1->wpf[i];
@@ -58,6 +170,14 @@
 		status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
 		vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
 
+		if (vsp1_debug && (status & VI6_WFP_IRQ_STA_UND)) {
+			vsp_und_cnt = ++underrun_vspd[vsp1->index];
+
+			VSP1_IRQ_DEBUG(
+				"Underrun occurred num[%d] at VSPD (%s)\n",
+				vsp_und_cnt, dev_name(vsp1->dev));
+		}
+
 		if (status & VI6_WFP_IRQ_STA_FRE) {
 			vsp1_pipeline_frame_end(pipe);
 			ret = IRQ_HANDLED;
@@ -79,6 +199,11 @@
 		ret = IRQ_HANDLED;
 	}
 
+	if ((RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) &&
+		(status & VI6_WFP_IRQ_STA_UND))
+		vsp1_underrun_workaround(vsp1, false);
+
 	return ret;
 }
 
@@ -200,6 +325,8 @@
 	struct vsp1_entity *entity, *_entity;
 	struct vsp1_video *video, *_video;
 
+	v4l2_device_unregister(&vsp1->v4l2_dev);
+
 	list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
 		list_del(&entity->list_dev);
 		vsp1_entity_destroy(entity);
@@ -210,7 +337,6 @@
 		vsp1_video_cleanup(video);
 	}
 
-	v4l2_device_unregister(&vsp1->v4l2_dev);
 	media_device_unregister(&vsp1->media_dev);
 
 	if (!vsp1->info->uapi)
@@ -411,7 +537,12 @@
 	if (!(status & VI6_STATUS_SYS_ACT(index)))
 		return 0;
 
-	vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		vsp1_underrun_workaround(vsp1, true);
+	else
+		vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
+
 	for (timeout = 10; timeout > 0; --timeout) {
 		status = vsp1_read(vsp1, VI6_STATUS);
 		if (!(status & VI6_STATUS_SYS_ACT(index)))
@@ -487,9 +618,19 @@
 	if (ret < 0)
 		goto done;
 
+	if (vsp1->info->fcpvd) {
+		ret = clk_prepare_enable(vsp1->fcpvd_clock);
+		if (ret < 0) {
+			clk_disable_unprepare(vsp1->clock);
+			goto done;
+		}
+	}
+
 	ret = vsp1_device_init(vsp1);
 	if (ret < 0) {
 		clk_disable_unprepare(vsp1->clock);
+		if (vsp1->info->fcpvd)
+			clk_disable_unprepare(vsp1->fcpvd_clock);
 		goto done;
 	}
 
@@ -509,11 +650,16 @@
  */
 void vsp1_device_put(struct vsp1_device *vsp1)
 {
+	if (vsp1->ref_count == 0)
+		return;
+
 	mutex_lock(&vsp1->lock);
 
-	if (--vsp1->ref_count == 0)
+	if (--vsp1->ref_count == 0) {
 		clk_disable_unprepare(vsp1->clock);
-
+		if (vsp1->info->fcpvd)
+			clk_disable_unprepare(vsp1->fcpvd_clock);
+	}
 	mutex_unlock(&vsp1->lock);
 }
 
@@ -534,6 +680,8 @@
 	vsp1_pipelines_suspend(vsp1);
 
 	clk_disable_unprepare(vsp1->clock);
+	if (vsp1->info->fcpvd)
+		clk_disable_unprepare(vsp1->fcpvd_clock);
 
 	return 0;
 }
@@ -548,6 +696,8 @@
 		return 0;
 
 	clk_prepare_enable(vsp1->clock);
+	if (vsp1->info->fcpvd)
+		clk_prepare_enable(vsp1->fcpvd_clock);
 
 	vsp1_pipelines_resume(vsp1);
 
@@ -572,6 +722,7 @@
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPR_H2,
 		.features = VSP1_HAS_BRU | VSP1_HAS_SRU,
@@ -580,6 +731,7 @@
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
 		.features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
@@ -588,6 +740,7 @@
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPS_M2,
 		.features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
@@ -596,6 +749,7 @@
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
 		.features = VSP1_HAS_LUT | VSP1_HAS_SRU,
@@ -603,6 +757,7 @@
 		.uds_count = 1,
 		.wpf_count = 1,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
 		.features = VSP1_HAS_BRU,
@@ -610,6 +765,7 @@
 		.wpf_count = 1,
 		.num_bru_inputs = 5,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
 		.features = VSP1_HAS_BRU | VSP1_HAS_LUT,
@@ -617,12 +773,15 @@
 		.wpf_count = 1,
 		.num_bru_inputs = 5,
 		.uapi = true,
+		.fcpvd = false,
 	}, {
 		.version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
 		.features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
 		.rpf_count = 5,
 		.wpf_count = 2,
 		.num_bru_inputs = 5,
+		.uapi = false,
+		.fcpvd = true,
 	},
 };
 
@@ -650,7 +809,7 @@
 	if (IS_ERR(vsp1->mmio))
 		return PTR_ERR(vsp1->mmio);
 
-	vsp1->clock = devm_clk_get(&pdev->dev, NULL);
+	vsp1->clock = of_clk_get(vsp1->dev->of_node, 0);
 	if (IS_ERR(vsp1->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		return PTR_ERR(vsp1->clock);
@@ -692,6 +851,14 @@
 
 	dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
 
+	if (vsp1->info->fcpvd) {
+		vsp1->fcpvd_clock = of_clk_get(vsp1->dev->of_node, 1);
+		if (IS_ERR(vsp1->fcpvd_clock)) {
+			dev_err(&pdev->dev, "failed to get fcpvd clock\n");
+			return PTR_ERR(vsp1->fcpvd_clock);
+		}
+	}
+
 	/* Instanciate entities */
 	ret = vsp1_create_entities(vsp1);
 	if (ret < 0) {
@@ -699,8 +866,28 @@
 		return ret;
 	}
 
+	if (strcmp(dev_name(vsp1->dev), "fea20000.vsp") == 0)
+		vsp1->index = 0;
+	else if (strcmp(dev_name(vsp1->dev), "fea28000.vsp") == 0)
+		vsp1->index = 1;
+	else if (strcmp(dev_name(vsp1->dev), "fea30000.vsp") == 0)
+		vsp1->index = 2;
+	else if (strcmp(dev_name(vsp1->dev), "fea38000.vsp") == 0)
+		vsp1->index = 3;
+
 	platform_set_drvdata(pdev, vsp1);
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(vsp1->dev, "product register init fail.\n");
+		return ret;
+	}
+
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		fcpv_reg[vsp1->index] =
+			 ioremap(fcpvd_offset[vsp1->index], 0x20);
+
 	return 0;
 }
 
@@ -708,8 +895,13 @@
 {
 	struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
 
+	vsp1_device_put(vsp1);
 	vsp1_destroy_entities(vsp1);
 
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		iounmap(fcpv_reg[vsp1->index]);
+
 	return 0;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 433853c..b8af06f 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_lif.c  --  R-Car VSP1 LCD Controller Interface
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -20,7 +20,7 @@
 #include "vsp1_lif.h"
 
 #define LIF_MIN_SIZE				2U
-#define LIF_MAX_SIZE				2048U
+#define LIF_MAX_SIZE				4096U
 
 /* -----------------------------------------------------------------------------
  * Device Access
@@ -39,9 +39,9 @@
 {
 	const struct v4l2_mbus_framefmt *format;
 	struct vsp1_lif *lif = to_lif(subdev);
-	unsigned int hbth = 1300;
-	unsigned int obth = 400;
-	unsigned int lbth = 200;
+	unsigned int hbth = 0;
+	unsigned int obth = 3000;
+	unsigned int lbth = 0;
 
 	if (!enable) {
 		vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 96f0e7d..69124ac 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_pipe.c  --  R-Car VSP1 Pipeline
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -63,17 +63,17 @@
 	  VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
 	  1, { 24, 0, 0 }, false, false, 1, 1, false },
-	{ V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
+	{ V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
 	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
 	  1, { 32, 0, 0 }, false, false, 1, 1, true },
-	{ V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
+	{ V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
 	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
 	  1, { 32, 0, 0 }, false, false, 1, 1, false },
-	{ V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
+	{ V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
 	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
 	  1, { 32, 0, 0 }, false, false, 1, 1, true },
-	{ V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
+	{ V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
 	  VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
 	  1, { 32, 0, 0 }, false, false, 1, 1, false },
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 069216f..9cb74cc 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -1,7 +1,7 @@
 /*
  * vsp1_regs.h  --  R-Car VSP1 Registers Definitions
  *
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -20,23 +20,49 @@
 #define VI6_CMD(n)			(0x0000 + (n) * 4)
 #define VI6_CMD_STRCMD			(1 << 0)
 
+#define VI6_CLK_CTRL0			0x0010
+#define VI6_CLK_CTRL0_WORKAROUND	0x10010F1F
+
+#define VI6_CLK_CTRL1			0x0014
+#define VI6_CLK_CTRL1_WORKAROUND	0xFF00FFFF
+
 #define VI6_CLK_DCSWT			0x0018
 #define VI6_CLK_DCSWT_CSTPW_MASK	(0xff << 8)
 #define VI6_CLK_DCSWT_CSTPW_SHIFT	8
 #define VI6_CLK_DCSWT_CSTRW_MASK	(0xff << 0)
 #define VI6_CLK_DCSWT_CSTRW_SHIFT	0
+#define VI6_CLK_DCSWT_WORKAROUND1	0x00130808
+#define VI6_CLK_DCSWT_WORKAROUND2	0x00000808
+
+#define VI6_CLK_DCSM0			0x001C
+#define VI6_CLK_DCSM0_WORKAROUND	0x1FFF0F1F
+
+#define VI6_CLK_DCSM1			0x0020
+#define VI6_CLK_DCSM1_WORKAROUND	0xFF00FFFF
 
 #define VI6_SRESET			0x0028
 #define VI6_SRESET_SRTS(n)		(1 << (n))
 
+#define VI6_MRESET_ENB0			0x002C
+#define VI6_MRESET_ENB0_WORKAROUND1	0x0000001F
+#define VI6_MRESET_ENB0_WORKAROUND2	0x30000F1F
+
+#define VI6_MRESET_ENB1			0x0030
+#define VI6_MRESET_ENB1_WORKAROUND	0xFF00FFFF
+
+#define VI6_MRESET			0x0034
+#define VI6_MRESET_WORKAROUND		0x00000001
+
 #define VI6_STATUS			0x0038
 #define VI6_STATUS_SYS_ACT(n)		(1 << ((n) + 8))
 
 #define VI6_WPF_IRQ_ENB(n)		(0x0048 + (n) * 12)
+#define VI6_WFP_IRQ_ENB_UNDE		(1 << 16)
 #define VI6_WFP_IRQ_ENB_DFEE		(1 << 1)
 #define VI6_WFP_IRQ_ENB_FREE		(1 << 0)
 
 #define VI6_WPF_IRQ_STA(n)		(0x004c + (n) * 12)
+#define VI6_WFP_IRQ_STA_UND		(1 << 16)
 #define VI6_WFP_IRQ_STA_DFE		(1 << 1)
 #define VI6_WFP_IRQ_STA_FRE		(1 << 0)
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 5bc1d15..c2665c5 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_rpf.c  --  R-Car VSP1 Read Pixel Formatter
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -76,6 +76,7 @@
 	const struct v4l2_rect *crop = &rpf->crop;
 	u32 pstride;
 	u32 infmt;
+	u32 alph_sel, laya;
 	int ret;
 
 	ret = vsp1_entity_set_streaming(&rpf->entity, enable);
@@ -147,14 +148,34 @@
 	 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
 	 * otherwise. Disable color keying.
 	 */
-	vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
-		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
-				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
-
+	switch (fmtinfo->fourcc) {
+	case V4L2_PIX_FMT_ARGB555:
+		if (CONFIG_VIDEO_RENESAS_VSP_ALPHA_BIT_ARGB1555 == 1)
+			alph_sel = (2 << 28) | (1 << 18) |
+				   (0xFF << 8) | (rpf->alpha->cur.val & 0xFF);
+		else
+			alph_sel = (2 << 28) | (1 << 18) |
+				   ((rpf->alpha->cur.val & 0xFF) << 8) | 0xFF;
+		laya = 0;
+		break;
+	case V4L2_PIX_FMT_ARGB32:
+	case V4L2_PIX_FMT_ABGR32:
+		alph_sel = (1 << 18);
+		laya = 0;
+		break;
+	case V4L2_PIX_FMT_ARGB444:
+		alph_sel = (0 << 28) | (2 << 18);
+		laya = 0;
+		break;
+	default:
+		alph_sel = (4 << 28) | (1 << 18);
+		laya = (rpf->alpha->cur.val & 0xFF) << 24;
+		break;
+	}
+	vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, alph_sel);
 	if (vsp1->info->uapi)
 		mutex_lock(rpf->ctrls.lock);
-	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-		       rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET, laya);
 	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val);
 	if (vsp1->info->uapi)
 		mutex_unlock(rpf->ctrls.lock);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c78d4af..c90528b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_wpf.c  --  R-Car VSP1 Write Pixel Formatter
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -19,8 +19,8 @@
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
-#define WPF_MAX_WIDTH				2048
-#define WPF_MAX_HEIGHT				2048
+#define WPF_MAX_WIDTH				4096
+#define WPF_MAX_HEIGHT				4096
 
 /* -----------------------------------------------------------------------------
  * Device Access
@@ -170,7 +170,7 @@
 	/* Enable interrupts */
 	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
 	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-		   VI6_WFP_IRQ_ENB_FREE);
+		   VI6_WFP_IRQ_ENB_FREE | VI6_WFP_IRQ_ENB_UNDE);
 
 	return 0;
 }
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 1526b8a..dd1499b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -560,7 +560,7 @@
 
 config MMC_SDHI
 	tristate "SH-Mobile SDHI SD/SDIO controller support"
-	depends on SUPERH || ARM
+	depends on SUPERH || ARM || ARM64
 	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
 	select MMC_TMIO_CORE
 	help
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 3595f83..3aa3587f 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -37,7 +37,13 @@
 obj-$(CONFIG_MMC_TMIO)		+= tmio_mmc.o
 obj-$(CONFIG_MMC_TMIO_CORE)	+= tmio_mmc_core.o
 tmio_mmc_core-y			:= tmio_mmc_pio.o
+ifeq ($(CONFIG_ARM64),y)
+# if CONFIG_ARM64, we assume it is gen3
+tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI))	+= tmio_mmc_dma_gen3.o
+else
+# if no, We assume it is gen2 or older
 tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI))	+= tmio_mmc_dma.o
+endif
 obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
 obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 354f4f3..e48748f 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -1,6 +1,7 @@
 /*
  * SuperH Mobile SDHI
  *
+ * Copyright (C) 2015 Renesas Electronics Corporation
  * Copyright (C) 2009 Magnus Damm
  *
  * This program is free software; you can redistribute it and/or modify
@@ -30,19 +31,31 @@
 #include <linux/mfd/tmio.h>
 #include <linux/sh_dma.h>
 #include <linux/delay.h>
+#include <linux/regulator/consumer.h>
 
 #include "tmio_mmc.h"
 
-#define EXT_ACC           0xe4
+#define HOST_MODE           0xe4
 
 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
 
+struct sh_mobile_sdhi_scc {
+	unsigned long clk;	/* clock for SDR104 */
+	u32 tap;		/* sampling clock position for SDR104 */
+};
+
 struct sh_mobile_sdhi_of_data {
 	unsigned long tmio_flags;
 	unsigned long capabilities;
 	unsigned long capabilities2;
 	enum dma_slave_buswidth dma_buswidth;
 	dma_addr_t dma_rx_offset;
+	unsigned int max_blk_count;
+	unsigned short max_segs;
+	bool sdbuf_64bit;
+	int scc_offset;
+	struct sh_mobile_sdhi_scc *taps;
+	int taps_num;
 };
 
 static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@@ -57,12 +70,48 @@
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
 };
 
+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = {
+	{
+		.clk = 156000000,
+		.tap = 0x00000703,
+	},
+	{
+		.clk = 0,
+		.tap = 0x00000300,
+	},
+};
+
 static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
 	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
 			  TMIO_MMC_CLK_ACTUAL,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
 	.dma_buswidth	= DMA_SLAVE_BUSWIDTH_4_BYTES,
 	.dma_rx_offset	= 0x2000,
+	.scc_offset = 0x0300,
+	.taps = rcar_gen2_scc_taps,
+	.taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = {
+	{
+		.clk = 0,
+		.tap = 0x00000300,
+	},
+};
+
+static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
+	.tmio_flags	= TMIO_MMC_CLK_NO_SLEEP | TMIO_MMC_HAS_IDLE_WAIT |
+			  TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL,
+	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_CMD23,
+	/* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
+	.max_blk_count	= 0xffffffff,
+	.max_segs = 1,
+	.sdbuf_64bit = true,
+	.scc_offset = 0x1000,
+	.taps = rcar_gen3_scc_taps,
+	.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
 };
 
 static const struct of_device_id sh_mobile_sdhi_of_match[] = {
@@ -78,6 +127,8 @@
 	{ .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
 	{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
 	{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
+	{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
+	{ .compatible = "renesas,mmc-r8a7795", .data = &of_rcar_gen3_compatible, },
 	{},
 };
 MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@@ -86,6 +137,8 @@
 	struct clk *clk;
 	struct tmio_mmc_data mmc_data;
 	struct tmio_mmc_dma dma_priv;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pinctrl_3v3, *pinctrl_1v8;
 };
 
 static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
@@ -103,12 +156,21 @@
 	case 0xCB0D:
 		val = (width == 32) ? 0x0000 : 0x0001;
 		break;
+	case 0xCC10:
+	case 0xCD10:
+		if (width == 64)
+			val = 0x0000;
+		else if (width == 32)
+			val = 0x0101;
+		else	/* width = 16 */
+			val = 0x0001;
+		break;
 	default:
 		/* nothing to do */
 		return;
 	}
 
-	sd_ctrl_write16(host, EXT_ACC, val);
+	sd_ctrl_write16(host, HOST_MODE, val);
 }
 
 static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
@@ -136,6 +198,316 @@
 	clk_disable_unprepare(priv->clk);
 }
 
+static void sh_mobile_sdhi_set_clk_div(struct platform_device *pdev,
+				       int state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+
+	if (state) {
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+				sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x00ff);
+	}
+}
+
+#define SH_MOBILE_SDHI_DAT0	0x0080
+static int sh_mobile_sdhi_card_busy(struct tmio_mmc_host *host)
+{
+	u16 dat0;
+
+	/* check to see DAT[3:0] */
+	dat0 = sd_ctrl_read16(host, CTL_STATUS2);
+	return !(dat0 & SH_MOBILE_SDHI_DAT0);
+}
+
+#define SH_MOBILE_SDHI_SIGNAL_180V	0
+#define SH_MOBILE_SDHI_SIGNAL_330V	1
+
+static int sh_mobile_sdhi_set_ioctrl(struct tmio_mmc_host *host, int state)
+{
+	struct platform_device *pdev = host->pdev;
+	struct sh_mobile_sdhi *priv =
+		container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+	struct pinctrl_state *pstate;
+	int ret;
+
+	if (state == SH_MOBILE_SDHI_SIGNAL_330V) {
+		pstate = priv->pinctrl_3v3;
+	} else if (state == SH_MOBILE_SDHI_SIGNAL_180V) {
+		pstate = priv->pinctrl_1v8;
+	} else {
+		dev_err(&pdev->dev, "update_ioctrl: unknown state\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!pstate) {
+		ret = -EIO;
+		goto err;
+	}
+
+	ret = pinctrl_select_state(priv->pinctrl, pstate);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int sh_mobile_sdhi_start_signal_voltage_switch(
+	struct tmio_mmc_host *host, unsigned char signal_voltage)
+{
+	struct mmc_host *mmc = host->mmc;
+	int ret;
+
+	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		/* Enable 3.3V Signal */
+		if (!IS_ERR(mmc->supply.vqmmc)) {
+			/* ioctrl */
+			ret = sh_mobile_sdhi_set_ioctrl(host,
+						SH_MOBILE_SDHI_SIGNAL_330V);
+			if (ret) {
+				dev_err(&host->pdev->dev,
+					"3.3V pin function control failed\n");
+				return -EIO;
+			}
+
+			ret = regulator_set_voltage(mmc->supply.vqmmc,
+						    3300000, 3300000);
+			if (ret) {
+				dev_warn(&host->pdev->dev,
+					 "3.3V signalling voltage failed\n");
+				return -EIO;
+			}
+		} else {
+			return -EIO;
+		}
+		usleep_range(5000, 10000);
+	} else if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		/* Enable 1.8V Signal */
+		if (!IS_ERR(mmc->supply.vqmmc)) {
+			ret = regulator_set_voltage(mmc->supply.vqmmc,
+						    1800000, 1800000);
+			if (ret) {
+				dev_warn(&host->pdev->dev,
+					 "1.8V signalling voltage failed\n");
+				return -EIO;
+			}
+			/* ioctrl */
+			ret = sh_mobile_sdhi_set_ioctrl(host,
+						SH_MOBILE_SDHI_SIGNAL_180V);
+			if (ret) {
+				dev_err(&host->pdev->dev,
+					"1.8V pin function control failed\n");
+				return -EIO;
+			}
+		} else {
+			return -EIO;
+		}
+		/* Wait for 5ms */
+		usleep_range(5000, 10000);
+	} else {
+		/* No signal voltage switch required */
+	}
+
+	return 0;
+}
+
+/* SCC registers */
+#define SH_MOBILE_SDHI_SCC_DTCNTL	0x000
+#define SH_MOBILE_SDHI_SCC_TAPSET	0x002
+#define SH_MOBILE_SDHI_SCC_DT2FF	0x004
+#define SH_MOBILE_SDHI_SCC_CKSEL	0x006
+#define SH_MOBILE_SDHI_SCC_RVSCNTL	0x008
+#define SH_MOBILE_SDHI_SCC_RVSREQ	0x00A
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN		(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */
+#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL		(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */
+#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN	(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
+#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR	(1 << 2)
+
+static inline u32 sd_scc_read32(struct tmio_mmc_host *host, int addr)
+{
+	struct platform_device *pdev = host->pdev;
+	const struct of_device_id *of_id =
+		of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+	const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+
+	return readl(host->ctl + of_data->scc_offset +
+		     (addr << host->bus_shift));
+}
+
+static inline void sd_scc_write32(struct tmio_mmc_host *host, int addr,
+				  u32 val)
+{
+	struct platform_device *pdev = host->pdev;
+	const struct of_device_id *of_id =
+		of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+	const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+
+	writel(val, host->ctl + of_data->scc_offset +
+	       (addr << host->bus_shift));
+}
+
+static bool sh_mobile_sdhi_inquiry_tuning(struct tmio_mmc_host *host)
+{
+	/* SDHI should be tuning only SDR104 and HS200 */
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
+		return true;
+
+	return false;
+}
+
+static void sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host,
+							unsigned long *num)
+{
+	/* set sampling clock selection range */
+	if (host->scc_tapnum)
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DTCNTL,
+				host->scc_tapnum << 16);
+
+	/* Initialize SCC */
+	sd_ctrl_write32(host, CTL_STATUS, 0x00000000);
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DTCNTL,
+		SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_DTCNTL));
+
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_CKSEL,
+		SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_CKSEL));
+
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+		~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
+
+	/* Read TAPNUM */
+	*num = (sd_scc_read32(host, SH_MOBILE_SDHI_SCC_DTCNTL) >> 16) & 0xff;
+}
+
+static int sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
+							unsigned long tap)
+{
+	/* Set sampling clock position */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TAPSET, tap);
+
+	return 0;
+}
+
+#define SH_MOBILE_SDHI_MAX_TAP	3
+static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host,
+							unsigned long *tap)
+{
+	unsigned long tap_num;	/* total number of taps */
+	unsigned long tap_cnt;	/* counter of tuning success */
+	unsigned long tap_set;	/* tap position */
+	unsigned long tap_start;	/* start position of tuning success */
+	unsigned long tap_end;	/* end position of tuning success */
+	unsigned long ntap;	/* temporary counter of tuning success */
+	unsigned long i;
+
+	/* Clear SCC_RVSREQ */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+
+	/* Select SCC */
+	tap_num = (sd_scc_read32(host,
+				 SH_MOBILE_SDHI_SCC_DTCNTL) >> 16) & 0xff;
+
+	tap_cnt = 0;
+	ntap = 0;
+	tap_start = 0;
+	tap_end = 0;
+	for (i = 0; i < tap_num * 2; i++) {
+		if (tap[i] == 0)
+			ntap++;
+		else {
+			if (ntap > tap_cnt) {
+				tap_start = i - ntap;
+				tap_end = i - 1;
+				tap_cnt = ntap;
+			}
+			ntap = 0;
+		}
+	}
+
+	if (ntap > tap_cnt) {
+		tap_start = i - ntap;
+		tap_end = i - 1;
+		tap_cnt = ntap;
+	}
+
+	if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP)
+		tap_set = (tap_start + tap_end) / 2 % tap_num;
+	else
+		return -EIO;
+
+	/* Set SCC */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
+
+	/* Enable auto re-tuning */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+		SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+	return 0;
+}
+
+static bool sh_mobile_sdhi_retuning(struct tmio_mmc_host *host)
+{
+	/* Check SCC error */
+	if (sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL) &
+	    SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
+	    sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSREQ) &
+	    SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
+		/* Clear SCC error */
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+		return true;
+	}
+	return false;
+}
+
+static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
+{
+	struct tmio_mmc_data *pdata = host->pdata;
+
+	if (pdata->flags & TMIO_MMC_HAS_UHS_SCC) {
+		/* Reset SCC */
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_CKSEL,
+			~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_CKSEL));
+
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+			~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+			~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+	}
+}
+
 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
 {
 	int timeout = 1000;
@@ -163,6 +535,7 @@
 	case CTL_SD_MEM_CARD_OPT:
 	case CTL_TRANSACTION_CTL:
 	case CTL_DMA_ENABLE:
+	case HOST_MODE:
 		return sh_mobile_sdhi_wait_idle(host);
 	}
 
@@ -189,10 +562,12 @@
 
 static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
 {
+	int dma_width = host->dma->sdbuf_64bit ? 64 : 32;
+
 	sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
 
 	/* enable 32bit access if DMA mode if possibile */
-	sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
+	sh_mobile_sdhi_sdbuf_width(host, enable ? dma_width : 16);
 }
 
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
@@ -204,9 +579,12 @@
 	struct tmio_mmc_data *mmd = pdev->dev.platform_data;
 	struct tmio_mmc_host *host;
 	struct resource *res;
-	int irq, ret, i = 0;
+	struct device_node *np = pdev->dev.of_node;
+	int irq, ret, i;
 	bool multiplexed_isr = true;
 	struct tmio_mmc_dma *dma_priv;
+	int clk_rate;
+	u32 num, tapnum = 0, tappos;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -228,6 +606,58 @@
 		goto eprobe;
 	}
 
+	if (np && !of_property_read_u32(np, "renesas,clk-rate", &clk_rate)) {
+		if (clk_rate) {
+			clk_prepare_enable(priv->clk);
+			ret = clk_set_rate(priv->clk, clk_rate);
+			if (ret < 0)
+				dev_err(&pdev->dev,
+					"cannot set clock rate: %d\n", ret);
+
+			clk_disable_unprepare(priv->clk);
+		}
+	}
+
+	if (np && !of_property_read_u32(np, "renesas,mmc-scc-tapnum", &num))
+		tapnum = num;
+
+	priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (!IS_ERR(priv->pinctrl)) {
+		const char *p;
+		struct pinctrl_state *pstate;
+
+		num = of_property_count_strings(np, "pinctrl-names");
+		if (num < 1) {
+			dev_err(&pdev->dev,
+				"not find pinctrl for voltage switch\n");
+			ret =  -ENODEV;
+			goto eprobe;
+		}
+
+		for (i = 0; i < num; i++) {
+			ret = of_property_read_string_index(np, "pinctrl-names",
+							    i, &p);
+			if (ret)
+				continue;
+
+			pstate = pinctrl_lookup_state(priv->pinctrl, p);
+			if (IS_ERR(pstate))
+				continue;
+
+			if (!strcmp(p, "3v3"))
+				priv->pinctrl_3v3 = pstate;
+			else if (!strcmp(p, "1v8"))
+				priv->pinctrl_1v8 = pstate;
+		}
+
+		if (!priv->pinctrl_3v3 && !priv->pinctrl_1v8) {
+			dev_err(&pdev->dev,
+				"not find pinctrl state for voltage switch\n");
+			ret =  -ENODEV;
+			goto eprobe;
+		}
+	}
+
 	host = tmio_mmc_host_alloc(pdev);
 	if (!host) {
 		ret = -ENOMEM;
@@ -238,9 +668,22 @@
 	host->write16_hook	= sh_mobile_sdhi_write16_hook;
 	host->clk_enable	= sh_mobile_sdhi_clk_enable;
 	host->clk_disable	= sh_mobile_sdhi_clk_disable;
+	host->card_busy		= sh_mobile_sdhi_card_busy;
 	host->multi_io_quirk	= sh_mobile_sdhi_multi_io_quirk;
-	/* SD control register space size is 0x100, 0x200 for bus_shift=1 */
-	if (resource_size(res) > 0x100)
+	host->set_clk_div	= sh_mobile_sdhi_set_clk_div;
+	host->start_signal_voltage_switch =
+			sh_mobile_sdhi_start_signal_voltage_switch;
+	host->inquiry_tuning = sh_mobile_sdhi_inquiry_tuning;
+	host->init_tuning = sh_mobile_sdhi_init_tuning;
+	host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+	host->select_tuning = sh_mobile_sdhi_select_tuning;
+	host->retuning = sh_mobile_sdhi_retuning;
+	host->hw_reset = sh_mobile_sdhi_hw_reset;
+	host->scc_tapnum = tapnum;
+	/* SD control register space size */
+	if (resource_size(res) > 0x400) /* 0x400 for bus_shift=2 */
+		host->bus_shift = 2;
+	else if (resource_size(res) > 0x100) /* 0x100, 0x200 for bus_shift=1 */
 		host->bus_shift = 1;
 	else
 		host->bus_shift = 0;
@@ -277,11 +720,39 @@
 
 	if (of_id && of_id->data) {
 		const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+		const struct sh_mobile_sdhi_scc *taps = of_data->taps;
 		mmc_data->flags |= of_data->tmio_flags;
 		mmc_data->capabilities |= of_data->capabilities;
 		mmc_data->capabilities2 |= of_data->capabilities2;
 		mmc_data->dma_rx_offset = of_data->dma_rx_offset;
+		mmc_data->max_blk_count	= of_data->max_blk_count;
+		mmc_data->max_segs = of_data->max_segs;
 		dma_priv->dma_buswidth = of_data->dma_buswidth;
+		dma_priv->sdbuf_64bit = of_data->sdbuf_64bit;
+		if (np && !of_property_read_u32(np, "renesas,mmc-scc-tappos",
+						&tappos)) {
+			host->scc_tappos = tappos;
+		} else {
+			for (i = 0, taps = of_data->taps;
+			     i < of_data->taps_num; i++, taps++) {
+				if (taps->clk == 0 || taps->clk == clk_rate) {
+					host->scc_tappos = taps->tap;
+					break;
+				}
+			}
+			if (taps->clk != 0 && taps->clk != clk_rate)
+				dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104 and HS200\n");
+		}
+	}
+
+	if (of_find_property(np, "sd-uhs-sdr50", NULL))
+		mmc_data->capabilities |= MMC_CAP_UHS_SDR50;
+	if (of_find_property(np, "sd-uhs-sdr104", NULL))
+		mmc_data->capabilities |= MMC_CAP_UHS_SDR104;
+
+	if (mmc_data->capabilities & MMC_CAP_UHS_SDR104) {
+		mmc_data->capabilities |= MMC_CAP_HW_RESET;
+		mmc_data->flags |= TMIO_MMC_HAS_UHS_SCC;
 	}
 
 	ret = tmio_mmc_host_probe(host, mmc_data);
@@ -326,6 +797,7 @@
 	}
 
 	if (multiplexed_isr) {
+		i = 0;
 		while (1) {
 			irq = platform_get_irq(pdev, i);
 			if (irq < 0)
@@ -370,8 +842,8 @@
 }
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-			pm_runtime_force_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend,
+			tmio_mmc_host_resume)
 	SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
 			tmio_mmc_host_runtime_resume,
 			NULL)
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index e897e7f..17ac517 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -30,7 +30,7 @@
 	const struct mfd_cell *cell = mfd_get_cell(pdev);
 	int ret;
 
-	ret = pm_runtime_force_suspend(dev);
+	ret = tmio_mmc_host_suspend(dev);
 
 	/* Tell MFD core it can disable us now.*/
 	if (!ret && cell->disable)
@@ -50,7 +50,7 @@
 		ret = cell->resume(pdev);
 
 	if (!ret)
-		ret = pm_runtime_force_resume(dev);
+		ret = tmio_mmc_host_resume(dev);
 
 	return ret;
 }
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 4a597f5a..2710344 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -1,6 +1,7 @@
 /*
  * linux/drivers/mmc/host/tmio_mmc.h
  *
+ * Copyright (C) 2015 Renesas Electronics Corporation
  * Copyright (C) 2007 Ian Molton
  * Copyright (C) 2004 Ian Molton
  *
@@ -17,6 +18,7 @@
 #define TMIO_MMC_H
 
 #include <linux/dmaengine.h>
+#include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/mmc/tmio.h>
 #include <linux/mutex.h>
@@ -44,6 +46,7 @@
 
 struct tmio_mmc_dma {
 	enum dma_slave_buswidth dma_buswidth;
+	bool sdbuf_64bit;
 	bool (*filter)(struct dma_chan *chan, void *arg);
 	void (*enable)(struct tmio_mmc_host *host, bool enable);
 };
@@ -93,12 +96,25 @@
 	struct mutex		ios_lock;	/* protect set_ios() context */
 	bool			native_hotplug;
 	bool			sdio_irq_enabled;
+	u32			scc_tapnum;
+	u32			scc_tappos;
+	bool			done_tuning;
+	struct completion	completion;
 
 	int (*write16_hook)(struct tmio_mmc_host *host, int addr);
 	int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
 	void (*clk_disable)(struct platform_device *pdev);
 	int (*multi_io_quirk)(struct mmc_card *card,
 			      unsigned int direction, int blk_size);
+	int (*card_busy)(struct tmio_mmc_host *host);
+	int (*start_signal_voltage_switch)(struct tmio_mmc_host *host,
+						unsigned char signal_voltage);
+	bool (*inquiry_tuning)(struct tmio_mmc_host *host);
+	void (*init_tuning)(struct tmio_mmc_host *host, unsigned long *num);
+	int (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
+	int (*select_tuning)(struct tmio_mmc_host *host, unsigned long *tap);
+	bool (*retuning)(struct tmio_mmc_host *host);
+	void (*hw_reset)(struct tmio_mmc_host *host);
 };
 
 struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
@@ -166,6 +182,11 @@
 int tmio_mmc_host_runtime_resume(struct device *dev);
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+int tmio_mmc_host_suspend(struct device *dev);
+int tmio_mmc_host_resume(struct device *dev);
+#endif
+
 static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
 {
 	return readw(host->ctl + (addr << host->bus_shift));
diff --git a/drivers/mmc/host/tmio_mmc_dma_gen3.c b/drivers/mmc/host/tmio_mmc_dma_gen3.c
new file mode 100644
index 0000000..fbf0d02
--- /dev/null
+++ b/drivers/mmc/host/tmio_mmc_dma_gen3.c
@@ -0,0 +1,190 @@
+/*
+ * linux/drivers/mmc/tmio_mmc_dma_gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * R-Car Gen3 DMA function for TMIO MMC implementations
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/tmio.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+
+#include "tmio_mmc.h"
+
+#define DM_CM_DTRAN_MODE	0x820
+#define DM_CM_DTRAN_CTRL	0x828
+#define DM_CM_RST		0x830
+#define DM_CM_INFO1		0x840
+#define DM_CM_INFO1_MASK	0x848
+#define DM_CM_INFO2		0x850
+#define DM_CM_INFO2_MASK	0x858
+#define DM_DTRAN_ADDR		0x880
+
+/* DM_CM_DTRAN_MODE */
+#define DTRAN_MODE_CH_NUM_CH0	0	/* "downstream" = for write commands */
+#define DTRAN_MODE_CH_NUM_CH1	BIT(16)	/* "uptream" = for read commands */
+#define DTRAN_MODE_BUS_WID_TH	(BIT(5) | BIT(4))
+#define DTRAN_MODE_ADDR_MODE	BIT(0)	/* 1 = Increment address */
+
+/* DM_CM_DTRAN_CTRL */
+#define DTRAN_CTRL_DM_START	BIT(0)
+
+/* DM_CM_RST */
+#define RST_DTRANRST1		BIT(9)
+#define RST_DTRANRST0		BIT(8)
+#define RST_RESERVED_BITS	GENMASK_ULL(32, 0)
+
+/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
+#define INFO1_CLEAR		0
+#define INFO1_DTRANEND1		BIT(17)
+#define INFO1_DTRANEND0		BIT(16)
+
+/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
+#define INFO2_DTRANERR1		BIT(17)
+#define INFO2_DTRANERR0		BIT(16)
+
+/*
+ * Specification of this driver:
+ * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
+ * - Since this SDHI DMAC register set has actual 32-bit and "bus_shift" is 2,
+ *   this driver cannot use original sd_ctrl_{write,read}32 functions.
+ */
+
+static void tmio_dm_write(struct tmio_mmc_host *host, int addr, u64 val)
+{
+	writeq(val, host->ctl + addr);
+}
+
+void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+	if (!host->chan_tx || !host->chan_rx)
+		return;
+
+	if (!enable)
+		tmio_dm_write(host, DM_CM_INFO1, INFO1_CLEAR);
+
+	if (host->dma->enable)
+		host->dma->enable(host, enable);
+}
+
+void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+{
+	u64 val = RST_DTRANRST1 | RST_DTRANRST0;
+
+	dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+	tmio_mmc_enable_dma(host, false);
+
+	tmio_dm_write(host, DM_CM_RST, RST_RESERVED_BITS & ~val);
+	tmio_dm_write(host, DM_CM_RST, RST_RESERVED_BITS | val);
+
+	tmio_mmc_enable_dma(host, true);
+}
+
+void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data)
+{
+	struct scatterlist *sg = host->sg_ptr;
+	u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
+	enum dma_data_direction dir;
+	int ret;
+	u32 irq_mask;
+
+	/* This DMAC cannot handle if sg_len is not 1 */
+	WARN_ON(host->sg_len > 1);
+
+	dev_dbg(&host->pdev->dev, "%s: %d, %x\n", __func__, host->sg_len,
+		data->flags);
+
+	/* This DMAC cannot handle if buffer is not 8-bytes alignment */
+	if (!IS_ALIGNED(sg->offset, 8)) {
+		host->force_pio = true;
+		tmio_mmc_enable_dma(host, false);
+		return;
+	}
+
+	if (data->flags & MMC_DATA_READ) {
+		dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
+		dir = DMA_FROM_DEVICE;
+		irq_mask = TMIO_STAT_RXRDY;
+	} else {
+		dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
+		dir = DMA_TO_DEVICE;
+		irq_mask = TMIO_STAT_TXRQ;
+	}
+
+	ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
+	if (ret < 0) {
+		dev_err(&host->pdev->dev, "%s: dma_map_sg failed\n", __func__);
+		return;
+	}
+
+	tmio_mmc_enable_dma(host, true);
+
+	/* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */
+	tmio_mmc_disable_mmc_irqs(host, irq_mask);
+
+	/* set dma parameters */
+	tmio_dm_write(host, DM_CM_DTRAN_MODE, dtran_mode);
+	tmio_dm_write(host, DM_DTRAN_ADDR, sg->dma_address);
+}
+
+static void tmio_mmc_issue_tasklet_fn(unsigned long arg)
+{
+	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+	dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+	tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+
+	/* start the DMAC */
+	tmio_dm_write(host, DM_CM_DTRAN_CTRL, DTRAN_CTRL_DM_START);
+}
+
+static void tmio_mmc_complete_tasklet_fn(unsigned long arg)
+{
+	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+	enum dma_data_direction dir;
+
+	dev_dbg(&host->pdev->dev, "%s: %p\n", __func__, host->data);
+
+	if (!host->data)
+		return;
+
+	if (host->data->flags & MMC_DATA_READ)
+		dir = DMA_FROM_DEVICE;
+	else
+		dir = DMA_TO_DEVICE;
+
+	tmio_mmc_enable_dma(host, false);
+	dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
+	tmio_mmc_do_data_irq(host);
+}
+
+void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+			  struct tmio_mmc_data *pdata)
+{
+	/* Each value is set to non-zero to assume "enabling" each DMA */
+	host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
+
+	tasklet_init(&host->dma_complete, tmio_mmc_complete_tasklet_fn,
+		     (unsigned long)host);
+	tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn,
+		     (unsigned long)host);
+}
+
+void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+	/* Each value is set to zero to assume "disabling" each DMA */
+	host->chan_rx = host->chan_tx = NULL;
+}
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index a10fde4..a959fc8 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1,6 +1,7 @@
 /*
  * linux/drivers/mmc/host/tmio_mmc_pio.c
  *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2011 Guennadi Liakhovetski
  * Copyright (C) 2007 Ian Molton
  * Copyright (C) 2004 Ian Molton
@@ -34,6 +35,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/mfd/tmio.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/slot-gpio.h>
@@ -51,6 +53,12 @@
 
 #include "tmio_mmc.h"
 
+static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode);
+static int tmio_mmc_start_data(struct tmio_mmc_host *host,
+	struct mmc_data *data);
+static int tmio_mmc_start_command(struct tmio_mmc_host *host,
+	struct mmc_command *cmd);
+
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
 {
 	host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
@@ -158,7 +166,8 @@
 	u32 clk = 0, clock;
 
 	if (new_clock) {
-		for (clock = host->mmc->f_min, clk = 0x80000080;
+		clk = 0x80000080;
+		for (clock = host->mmc->f_min;
 			new_clock >= (clock<<1); clk >>= 1)
 			clock <<= 1;
 
@@ -180,24 +189,28 @@
 	/* implicit BUG_ON(!res) */
 	if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
 		sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
-		msleep(10);
+		if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+			msleep(10);
 	}
 
 	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
 		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-	msleep(10);
+	if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+		msleep(10);
 }
 
 static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
 {
 	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
 		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-	msleep(10);
+	if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+		msleep(10);
 
 	/* implicit BUG_ON(!res) */
 	if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
 		sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
-		msleep(10);
+		if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+			msleep(10);
 	}
 }
 
@@ -221,6 +234,7 @@
 						  delayed_reset_work.work);
 	struct mmc_request *mrq;
 	unsigned long flags;
+	u16 clk;
 
 	spin_lock_irqsave(&host->lock, flags);
 	mrq = host->mrq;
@@ -254,7 +268,9 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	clk = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL) & 0x0ff;
 	tmio_mmc_reset(host);
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk | 0x100);
 
 	/* Ready for new calls */
 	host->mrq = NULL;
@@ -271,6 +287,8 @@
 {
 	struct mmc_request *mrq;
 	unsigned long flags;
+	bool result;
+	struct mmc_command *cmd = host->cmd;
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -284,7 +302,9 @@
 	host->data = NULL;
 	host->force_pio = false;
 
-	cancel_delayed_work(&host->delayed_reset_work);
+	if (!(host->inquiry_tuning && host->inquiry_tuning(host) &&
+	      !host->done_tuning) || cmd != mrq->sbc)
+		cancel_delayed_work(&host->delayed_reset_work);
 
 	host->mrq = NULL;
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -292,6 +312,29 @@
 	if (mrq->cmd->error || (mrq->data && mrq->data->error))
 		tmio_mmc_abort_dma(host);
 
+	if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+	     !host->done_tuning) {
+		/* call retuning() to clear SCC error bit */
+		if (host->retuning)
+			host->retuning(host);
+		/* finish processing tuning request */
+		complete(&host->completion);
+		return;
+	}
+
+	/* Check retuning */
+	if (host->retuning && host->done_tuning) {
+		result = host->retuning(host);
+		if (result || (mrq->cmd->error == -EILSEQ))
+			host->done_tuning = false;
+	}
+
+	if (cmd == mrq->sbc) {
+		/* finish SET_BLOCK_COUNT request */
+		complete(&host->completion);
+		return;
+	}
+
 	mmc_request_done(host->mmc, mrq);
 
 	pm_runtime_mark_last_busy(mmc_dev(host->mmc));
@@ -305,6 +348,165 @@
 	tmio_mmc_finish_request(host);
 }
 
+#define TMIO_MMC_MAX_TUNING_LOOP 40
+
+static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct mmc_ios *ios = &mmc->ios;
+
+	unsigned long timeout, val, num;
+	unsigned long *tap;
+	int tuning_loop_counter = TMIO_MMC_MAX_TUNING_LOOP;
+	int ret, timeleft;
+
+	struct mmc_request mrq = {NULL};
+	struct mmc_command cmd = {0};
+	struct mmc_data data = {0};
+	struct scatterlist sg;
+	u8 *data_buf;
+	unsigned int tm = CMDREQ_TIMEOUT;
+	unsigned long flags;
+	u8 data_size = 64;
+
+	if (ios->timing != MMC_TIMING_UHS_SDR50 &&
+	    ios->timing != MMC_TIMING_UHS_SDR104 &&
+	    ios->timing != MMC_TIMING_MMC_HS200 &&
+	    ios->timing != MMC_TIMING_MMC_HS400)
+		return 0;
+
+	if ((host->inquiry_tuning && !host->inquiry_tuning(host)) ||
+	    host->done_tuning)
+		return 0;
+
+	host->init_tuning(host, &num);
+
+	tap = kmalloc(num * 2, GFP_KERNEL);
+	if (tap == NULL) {
+		ret = -ENOMEM;
+		goto err_tap;
+	}
+
+	if (ios->timing == MMC_TIMING_MMC_HS200)
+		data_size = 128;
+
+	data_buf = kmalloc(data_size, GFP_KERNEL);
+	if (data_buf == NULL) {
+		ret = -ENOMEM;
+		goto err_data;
+	}
+
+	val = 0;
+
+	/*
+	 * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+	 * of loops reaches 40 times or a timeout of 150ms occurs.
+	 */
+	timeout = 150;
+	do {
+		if (host->prepare_tuning)
+			host->prepare_tuning(host, val % num);
+
+		if (!tuning_loop_counter && !timeout)
+			break;
+
+		/*
+		 * In response to CMD19, the card sends 64 bytes of tuning
+		 * block to the Host Controller. So we set the block size
+		 * to 64 here.
+		 */
+
+		spin_lock_irqsave(&host->lock, flags);
+		init_completion(&host->completion);
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+
+		cmd.opcode = opcode;
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		cmd.retries = 0;
+		cmd.error = 0;
+
+		data.blksz = data_size;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+		data.sg = &sg;
+		data.sg_len = 1;
+		data.error = 0;
+
+		sg_init_one(&sg, data_buf, data_size);
+
+		host->mrq = &mrq;
+
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		ret = tmio_mmc_start_data(host, mrq.data);
+		if (ret)
+			goto out;
+
+		ret = tmio_mmc_start_command(host, mrq.cmd);
+		if (ret)
+			goto out;
+
+		timeleft = wait_for_completion_timeout(&host->completion,
+						       msecs_to_jiffies(tm));
+		if (timeleft < 0) {
+			ret = timeleft;
+			goto out;
+		}
+
+		if (!timeleft) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+
+		/* Check CRC error */
+		if (cmd.error && cmd.error != -EILSEQ) {
+			ret = cmd.error;
+			goto out;
+		}
+		if (data.error && data.error != -EILSEQ) {
+			ret = data.error;
+			goto out;
+		}
+
+		tap[val] = (cmd.error | data.error);
+
+		val++;
+		tuning_loop_counter--;
+		timeout--;
+		mdelay(1);
+	} while ((val < (num * 2)) && (tuning_loop_counter || timeout));
+
+	/*
+	 * The Host Driver has exhausted the maximum number of loops allowed,
+	 * so use fixed sampling frequency.
+	 */
+	if (tuning_loop_counter || timeout) {
+		if (host->select_tuning) {
+			ret = host->select_tuning(host, tap);
+			if (ret < 0)
+				goto out;
+		}
+		host->done_tuning = true;
+	} else {
+		dev_warn(&host->pdev->dev, ": Tuning procedure failed\n");
+		ret = -EIO;
+		goto out;
+	}
+
+out:
+	kfree(data_buf);
+err_data:
+	kfree(tap);
+err_tap:
+	if (ret < 0 && host->hw_reset)
+		host->hw_reset(host);
+
+	return ret;
+
+}
+
 /* These are the bitmasks the tmio chip requires to implement the MMC response
  * types. Note that R1 and R6 are the same in this scheme. */
 #define APP_CMD        0x0040
@@ -334,6 +536,8 @@
 	switch (mmc_resp_type(cmd)) {
 	case MMC_RSP_NONE: c |= RESP_NONE; break;
 	case MMC_RSP_R1:   c |= RESP_R1;   break;
+	case MMC_RSP_R1 & ~MMC_RSP_CRC:
+			   c |= RESP_R1;   break;
 	case MMC_RSP_R1B:  c |= RESP_R1B;  break;
 	case MMC_RSP_R2:   c |= RESP_R2;   break;
 	case MMC_RSP_R3:   c |= RESP_R3;   break;
@@ -360,7 +564,8 @@
 			 * multiple block transfer
 			 */
 			if ((host->pdata->flags & TMIO_MMC_HAVE_CMD12_CTRL) &&
-			    (cmd->opcode == SD_IO_RW_EXTENDED))
+			    ((cmd->opcode == SD_IO_RW_EXTENDED) ||
+			     host->mrq->sbc))
 				c |= NO_CMD12_ISSUE;
 		}
 		if (data->flags & MMC_DATA_READ)
@@ -517,7 +722,7 @@
 	schedule_work(&host->done);
 }
 
-static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
+static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
 {
 	struct mmc_data *data;
 	spin_lock(&host->lock);
@@ -526,6 +731,9 @@
 	if (!data)
 		goto out;
 
+	if (stat & TMIO_STAT_CRCFAIL || stat & TMIO_STAT_STOPBIT_ERR ||
+	    stat & TMIO_STAT_TXUNDERRUN)
+		data->error = -EILSEQ;
 	if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
 		u32 status = sd_ctrl_read32(host, CTL_STATUS);
 		bool done = false;
@@ -574,8 +782,6 @@
 		goto out;
 	}
 
-	host->cmd = NULL;
-
 	/* This controller is sicker than the PXA one. Not only do we need to
 	 * drop the top 8 bits of the first response word, we also need to
 	 * modify the order of the response for short response command types.
@@ -595,14 +801,16 @@
 
 	if (stat & TMIO_STAT_CMDTIMEOUT)
 		cmd->error = -ETIMEDOUT;
-	else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
+	else if ((stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) ||
+		 stat & TMIO_STAT_STOPBIT_ERR ||
+		 stat & TMIO_STAT_CMD_IDX_ERR)
 		cmd->error = -EILSEQ;
 
 	/* If there is data to handle we enable data IRQs here, and
 	 * we will ultimatley finish the request in the data_end handler.
 	 * If theres no data or we encountered an error, finish now.
 	 */
-	if (host->data && !cmd->error) {
+	if (host->data && (!cmd->error || cmd->error == -EILSEQ)) {
 		if (host->data->flags & MMC_DATA_READ) {
 			if (host->force_pio || !host->chan_rx)
 				tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
@@ -688,7 +896,7 @@
 	/* Data transfer completion */
 	if (ireg & TMIO_STAT_DATAEND) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
-		tmio_mmc_data_irq(host);
+		tmio_mmc_data_irq(host, status);
 		return true;
 	}
 
@@ -790,6 +998,7 @@
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 	unsigned long flags;
 	int ret;
+	u32 opcode;
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -811,6 +1020,50 @@
 
 	pm_runtime_get_sync(mmc_dev(mmc));
 
+	if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+	    !host->done_tuning) {
+		if (mmc_card_mmc(host->mmc->card))
+			opcode = MMC_SEND_TUNING_BLOCK_HS200;
+		else
+			opcode = MMC_SEND_TUNING_BLOCK;
+		/* Start retuning */
+		ret = tmio_mmc_execute_tuning(mmc, opcode);
+		if (ret)
+			goto fail;
+		/* Restore request */
+		host->mrq = mrq;
+	}
+
+	if (mrq->sbc) {
+		init_completion(&host->completion);
+		ret = tmio_mmc_start_command(host, mrq->sbc);
+		if (ret)
+			goto fail;
+		ret = wait_for_completion_timeout(&host->completion,
+					msecs_to_jiffies(CMDREQ_TIMEOUT));
+		if (ret < 0)
+			goto fail;
+		if (!ret) {
+			ret = -ETIMEDOUT;
+			goto fail;
+		}
+		host->last_req_ts = jiffies;
+		host->mrq = mrq;
+		if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+		    !host->done_tuning) {
+			if (mmc_card_mmc(host->mmc->card))
+				opcode = MMC_SEND_TUNING_BLOCK_HS200;
+			else
+				opcode = MMC_SEND_TUNING_BLOCK;
+			/* Start retuning */
+			ret = tmio_mmc_execute_tuning(mmc, opcode);
+			if (ret)
+				goto fail;
+			/* Restore request */
+			host->mrq = mrq;
+		}
+	}
+
 	if (mrq->data) {
 		ret = tmio_mmc_start_data(host, mrq->data);
 		if (ret)
@@ -900,12 +1153,21 @@
 static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
 				unsigned char bus_width)
 {
+	sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, ~0xa000 &
+		sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
+
 	switch (bus_width) {
 	case MMC_BUS_WIDTH_1:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x8000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
 		break;
 	case MMC_BUS_WIDTH_4:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x0000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
+		break;
+	case MMC_BUS_WIDTH_8:
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x2000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
 		break;
 	}
 }
@@ -1013,6 +1275,45 @@
 	return blk_size;
 }
 
+static int tmio_mmc_start_signal_voltage_switch(struct mmc_host *mmc,
+	struct mmc_ios *ios)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	int ret;
+
+	if (host->start_signal_voltage_switch) {
+		ret = host->start_signal_voltage_switch(host,
+							 ios->signal_voltage);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int tmio_mmc_card_busy(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	int ret;
+
+	if (host->card_busy) {
+		ret = host->card_busy(host);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static void tmio_mmc_hw_reset(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+
+	if (host->hw_reset)
+		host->hw_reset(host);
+
+	host->done_tuning = false;
+}
+
 static const struct mmc_host_ops tmio_mmc_ops = {
 	.request	= tmio_mmc_request,
 	.set_ios	= tmio_mmc_set_ios,
@@ -1020,6 +1321,11 @@
 	.get_cd		= mmc_gpio_get_cd,
 	.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 	.multi_io_quirk	= tmio_multi_io_quirk,
+	.start_signal_voltage_switch
+		= tmio_mmc_start_signal_voltage_switch,
+	.card_busy	= tmio_mmc_card_busy,
+	.execute_tuning = tmio_mmc_execute_tuning,
+	.hw_reset	= tmio_mmc_hw_reset,
 };
 
 static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
@@ -1120,13 +1426,14 @@
 	mmc->ops = &tmio_mmc_ops;
 	mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
 	mmc->caps2 |= pdata->capabilities2;
-	mmc->max_segs = 32;
+	mmc->max_segs = pdata->max_segs ? pdata->max_segs : 32;
 	mmc->max_blk_size = 512;
-	mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
-		mmc->max_segs;
+	mmc->max_blk_count = pdata->max_blk_count ? :
+		(PAGE_CACHE_SIZE / mmc->max_blk_size) * mmc->max_segs;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_req_size;
 
+	_host->done_tuning = false;
 	_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
 				  mmc->caps & MMC_CAP_NEEDS_POLL ||
 				  mmc->caps & MMC_CAP_NONREMOVABLE ||
@@ -1274,4 +1581,20 @@
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+int tmio_mmc_host_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_suspend);
+
+int tmio_mmc_host_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_resume);
+#endif /* CONFIG_PM_SLEEP */
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 9fbe92a..6455bdd 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -76,6 +76,7 @@
 	CDAR20	= 0x0060,
 	CDAR21	= 0x0064,
 	ESR	= 0x0088,
+	APSR	= 0x008C,
 	RCR	= 0x0090,
 	RQC0	= 0x0094,
 	RQC1	= 0x0098,
@@ -83,6 +84,7 @@
 	RQC3	= 0x00A0,
 	RQC4	= 0x00A4,
 	RPC	= 0x00B0,
+	RTC	= 0x00B4,
 	UFCW	= 0x00BC,
 	UFCS	= 0x00C0,
 	UFCV0	= 0x00C4,
@@ -128,11 +130,52 @@
 	SFP29	= 0x0174,
 	SFP30	= 0x0178,
 	SFP31	= 0x017C,
+	SFV0	= 0x01B8,
+	SFV1	= 0x01BC,
 	SFM0	= 0x01C0,
 	SFM1	= 0x01C4,
+	SFL	= 0x01C8,
+	PCRC	= 0x01CC,
+	CIAR0	= 0x0200,
+	CIAR1	= 0x0204,
+	CIAR2	= 0x0208,
+	CIAR3	= 0x020C,
+	CIAR4	= 0x0210,
+	CIAR5	= 0x0214,
+	CIAR6	= 0x0218,
+	CIAR7	= 0x021C,
+	CIAR8	= 0x0220,
+	CIAR9	= 0x0224,
+	CIAR10	= 0x0228,
+	CIAR11	= 0x022C,
+	CIAR12	= 0x0230,
+	CIAR13	= 0x0234,
+	CIAR14	= 0x0238,
+	CIAR15	= 0x023C,
+	CIAR16	= 0x0240,
+	CIAR17	= 0x0244,
+	LIAR0	= 0x0280,
+	LIAR1	= 0x0284,
+	LIAR2	= 0x0288,
+	LIAR3	= 0x028C,
+	LIAR4	= 0x0290,
+	LIAR5	= 0x0294,
+	LIAR6	= 0x0298,
+	LIAR7	= 0x029C,
+	LIAR8	= 0x02A0,
+	LIAR9	= 0x02A4,
+	LIAR10	= 0x02A8,
+	LIAR11	= 0x02AC,
+	LIAR12	= 0x02B0,
+	LIAR13	= 0x02B4,
+	LIAR14	= 0x02B8,
+	LIAR15	= 0x02BC,
+	LIAR16	= 0x02C0,
+	LIAR17	= 0x02C4,
 	TGC	= 0x0300,
 	TCCR	= 0x0304,
 	TSR	= 0x0308,
+	MFA	= 0x030C,
 	TFA0	= 0x0310,
 	TFA1	= 0x0314,
 	TFA2	= 0x0318,
@@ -157,6 +200,9 @@
 	TIC	= 0x0378,
 	TIS	= 0x037C,
 	ISS	= 0x0380,
+	CIE	= 0x0384,
+	RIC3	= 0x0388,
+	RIS3	= 0x038C,
 	GCCR	= 0x0390,
 	GMTT	= 0x0394,
 	GPTC	= 0x0398,
@@ -170,6 +216,48 @@
 	GCT0	= 0x03B8,
 	GCT1	= 0x03BC,
 	GCT2	= 0x03C0,
+	GSR	= 0x03C4,
+	GIE	= 0x03CC,
+	GID	= 0x03D0,
+	GIL	= 0x03D4,
+	GACP	= 0x03DC,
+	GPTF0	= 0x03E0,
+	GPTF1	= 0x03E4,
+	GPTF2	= 0x03E8,
+	GPTF3	= 0x03EC,
+	GCAT0	= 0x0400,
+	GCAT1	= 0x0404,
+	GCAT2	= 0x0408,
+	GCAT3	= 0x040C,
+	GCAT4	= 0x0410,
+	GCAT5	= 0x0414,
+	GCAT6	= 0x0418,
+	GCAT7	= 0x041C,
+	GCAT8	= 0x0420,
+	GCAT9	= 0x0424,
+	GCAT10	= 0x0428,
+	GCAT11	= 0x042C,
+	GCAT12	= 0x0430,
+	GCAT13	= 0x0434,
+	GCAT14	= 0x0438,
+	GCAT15	= 0x043C,
+	DIL	= 0x0440,
+	EIL	= 0x0444,
+	TIL	= 0x0448,
+	DIE	= 0x0450,
+	DID	= 0x0454,
+	EIE	= 0x0458,
+	EID	= 0x045C,
+	RIE0	= 0x0460,
+	RID0	= 0x0464,
+	RIE1	= 0x0468,
+	RID1	= 0x046c,
+	RIE2	= 0x0470,
+	RID2	= 0x0474,
+	TIE	= 0x0478,
+	TID	= 0x047c,
+	RIE3	= 0x0488,
+	RID3	= 0x048C,
 
 	/* E-MAC registers */
 	ECMR	= 0x0500,
@@ -179,9 +267,12 @@
 	PIR	= 0x0520,
 	PSR	= 0x0528,
 	PIPR	= 0x052c,
+	APR	= 0x0554,
 	MPR	= 0x0558,
 	PFTCR	= 0x055c,
 	PFRCR	= 0x0560,
+	PFTTLR	= 0x0564,
+	PFTTCR	= 0x0568,
 	GECMR	= 0x05b0,
 	MAHR	= 0x05c0,
 	MALR	= 0x05c8,
@@ -309,6 +400,13 @@
 	RTC_MFL1	= 0x0FFF0000,
 };
 
+enum SFL_BIT {
+	SFL_LC		= 0x0000001F,
+	SFL_LC_SFM	= 0x0000001D,
+	SFL_LC_SFO	= 0x0000001E,
+	SFL_LC_LOADABLE	= 0x0000001F,
+};
+
 /* TGC */
 enum TGC_BIT {
 	TGC_TSM0	= 0x00000001,
@@ -556,6 +654,16 @@
 	ISS_DPS15	= 0x80000000,
 };
 
+/* CIE */
+enum CIE_BIT {
+	CIE_CRIE	= 0x00000001, /* Common Receive Interrupt Enable */
+	CIE_CTIE	= 0x00000100, /* Common Transmit Interrupt Enable */
+	CIE_RQFM	= 0x00010000, /* Reception Queue Full Mode */
+	CIE_CL0M	= 0x00020000, /* Common Line 0 Mode */
+	CIE_RFWL	= 0x00040000, /* Rx-FIFO Warning interrupt Line */
+	CIE_RFFL	= 0x00080000, /* Rx-FIFO Full interrupt Line */
+};
+
 /* GCCR */
 enum GCCR_BIT {
 	GCCR_TCR	= 0x00000003,
@@ -592,6 +700,18 @@
 	GIS_PTMF	= 0x00000004,
 };
 
+/* GIx */
+#define RAVB_GIx_ALL	0xffff03ff
+
+/* RIx0 */
+#define RAVB_RIx0_ALL	0x0003ffff
+
+/* RIx2 */
+#define RAVB_RIx2_ALL	0x8003ffff
+
+/* TIx */
+#define RAVB_TIx_ALL	0x000fffff
+
 /* ECMR */
 enum ECMR_BIT {
 	ECMR_PRM	= 0x00000001,
@@ -745,7 +865,6 @@
 #define RX_QUEUE_OFFSET	4
 #define NUM_RX_QUEUE	2
 #define NUM_TX_QUEUE	2
-#define NUM_TX_DESC	2	/* TX descriptors per packet */
 
 struct ravb_tstamp_skb {
 	struct list_head list;
@@ -820,6 +939,9 @@
 
 	unsigned no_avb_link:1;
 	unsigned avb_link_active_low:1;
+	int rx_irqs[NUM_RX_QUEUE];
+	int tx_irqs[NUM_TX_QUEUE];
+	int num_tx_desc;	/* TX descriptors per packet */
 };
 
 static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index c9794bf..5851405 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1,6 +1,6 @@
 /* Renesas Ethernet AVB device driver
  *
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2016 Renesas Electronics Corporation
  * Copyright (C) 2015 Renesas Solutions Corp.
  * Copyright (C) 2015 Cogent Embedded, Inc. <source@cogentembedded.com>
  *
@@ -33,6 +33,7 @@
 #include <linux/spinlock.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <asm/div64.h>
 
@@ -44,6 +45,16 @@
 		 NETIF_MSG_RX_ERR | \
 		 NETIF_MSG_TX_ERR)
 
+static const char *ravb_rx_irqs[NUM_RX_QUEUE] = {
+	"ch0", /* RAVB_BE */
+	"ch1", /* RAVB_NC */
+};
+
+static const char *ravb_tx_irqs[NUM_TX_QUEUE] = {
+	"ch18", /* RAVB_BE */
+	"ch19", /* RAVB_NC */
+};
+
 int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask, u32 value)
 {
 	int i;
@@ -184,6 +195,7 @@
 	struct ravb_private *priv = netdev_priv(ndev);
 	int ring_size;
 	int i;
+	int num_tx_desc = priv->num_tx_desc;
 
 	/* Free RX skb ringbuffer */
 	if (priv->rx_skb[q]) {
@@ -215,7 +227,7 @@
 
 	if (priv->tx_ring[q]) {
 		ring_size = sizeof(struct ravb_tx_desc) *
-			    (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+			    (priv->num_tx_ring[q] * num_tx_desc + 1);
 		dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q],
 				  priv->tx_desc_dma[q]);
 		priv->tx_ring[q] = NULL;
@@ -229,9 +241,10 @@
 	struct ravb_ex_rx_desc *rx_desc;
 	struct ravb_tx_desc *tx_desc;
 	struct ravb_desc *desc;
+	int num_tx_desc = priv->num_tx_desc;
 	int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
 	int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] *
-			   NUM_TX_DESC;
+			   num_tx_desc;
 	dma_addr_t dma_addr;
 	int i;
 
@@ -245,10 +258,10 @@
 	for (i = 0; i < priv->num_rx_ring[q]; i++) {
 		/* RX descriptor */
 		rx_desc = &priv->rx_ring[q][i];
-		/* The size of the buffer should be on 16-byte boundary. */
-		rx_desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
-		dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data,
-					  ALIGN(PKT_BUF_SZ, 16),
+		rx_desc->ds_cc = cpu_to_le16(PKT_BUF_SZ);
+		dma_addr = dma_map_single(ndev->dev.parent,
+					  priv->rx_skb[q][i]->data,
+					  PKT_BUF_SZ,
 					  DMA_FROM_DEVICE);
 		/* We just set the data size to 0 for a failed mapping which
 		 * should prevent DMA from happening...
@@ -267,8 +280,10 @@
 	for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q];
 	     i++, tx_desc++) {
 		tx_desc->die_dt = DT_EEMPTY;
-		tx_desc++;
-		tx_desc->die_dt = DT_EEMPTY;
+		if (num_tx_desc >= 2) {
+			tx_desc++;
+			tx_desc->die_dt = DT_EEMPTY;
+		}
 	}
 	tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
 	tx_desc->die_dt = DT_LINKFIX; /* type */
@@ -291,6 +306,7 @@
 	struct sk_buff *skb;
 	int ring_size;
 	int i;
+	int num_tx_desc = priv->num_tx_desc;
 
 	/* Allocate RX and TX skb rings */
 	priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
@@ -326,7 +342,7 @@
 
 	/* Allocate all TX descriptors. */
 	ring_size = sizeof(struct ravb_tx_desc) *
-		    (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+		    (priv->num_tx_ring[q] * num_tx_desc + 1);
 	priv->tx_ring[q] = dma_alloc_coherent(ndev->dev.parent, ring_size,
 					      &priv->tx_desc_dma[q],
 					      GFP_KERNEL);
@@ -362,8 +378,6 @@
 	ravb_write(ndev,
 		   (ndev->dev_addr[4] << 8)  | (ndev->dev_addr[5]), MALR);
 
-	ravb_write(ndev, 1, MPR);
-
 	/* E-MAC status register clear */
 	ravb_write(ndev, ECSR_ICD | ECSR_MPD, ECSR);
 
@@ -375,6 +389,7 @@
 static int ravb_dmac_init(struct net_device *ndev)
 {
 	int error;
+	struct ravb_private *priv = netdev_priv(ndev);
 
 	/* Set CONFIG mode */
 	error = ravb_config(ndev);
@@ -401,7 +416,8 @@
 #endif
 
 	/* Set AVB RX */
-	ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
+	ravb_write(ndev,
+		   RCR_EFFS | RCR_ENCF | RCR_ETS0 | RCR_ESF | 0x18000000, RCR);
 
 	/* Set FIFO size */
 	ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
@@ -410,14 +426,30 @@
 	ravb_write(ndev, TCCR_TFEN, TCCR);
 
 	/* Interrupt init: */
-	/* Frame receive */
-	ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
-	/* Disable FIFO full warning */
-	ravb_write(ndev, 0, RIC1);
-	/* Receive FIFO full error, descriptor empty */
-	ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
-	/* Frame transmitted, timestamp FIFO updated */
-	ravb_write(ndev, TIC_FTE0 | TIC_FTE1 | TIC_TFUE, TIC);
+	if (priv->chip_id == RCAR_GEN2) {
+		/* Frame receive */
+		ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
+		/* Disable FIFO full warning */
+		ravb_write(ndev, 0, RIC1);
+		/* Receive FIFO full error, descriptor empty */
+		ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
+		/* Frame transmitted, timestamp FIFO updated */
+		ravb_write(ndev, TIC_FTE0 | TIC_FTE1 | TIC_TFUE, TIC);
+	} else {
+		/* Clear CIE.CTIE, CIE.CRIE, DIL.DPLx */
+		ravb_write(ndev, 0, CIE);
+		ravb_write(ndev, 0, DIL);
+		/* Set queue specific interrupt */
+		ravb_write(ndev, CIE_CRIE | CIE_CTIE | CIE_CL0M, CIE);
+		/* Frame receive */
+		ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIE0);
+		/* Disable FIFO full warning */
+		ravb_write(ndev, 0, RID1);
+		/* Receive FIFO full error, descriptor empty */
+		ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIE2);
+		/* Frame transmitted, timestamp FIFO updated */
+		ravb_write(ndev, TIC_FTE0 | TIC_FTE1 | TIC_TFUE, TIE);
+	}
 
 	/* Setting the control will start the AVB-DMAC process. */
 	ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_OPERATION,
@@ -435,10 +467,11 @@
 	int free_num = 0;
 	int entry;
 	u32 size;
+	int num_tx_desc = priv->num_tx_desc;
 
 	for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
 		entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
-					     NUM_TX_DESC);
+					     num_tx_desc);
 		desc = &priv->tx_ring[q][entry];
 		if (desc->die_dt != DT_FEMPTY)
 			break;
@@ -446,12 +479,12 @@
 		dma_rmb();
 		size = le16_to_cpu(desc->ds_tagl) & TX_DS;
 		/* Free the original skb. */
-		if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
+		if (priv->tx_skb[q][entry / num_tx_desc]) {
 			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
 					 size, DMA_TO_DEVICE);
 			/* Last packet descriptor? */
-			if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
-				entry /= NUM_TX_DESC;
+			if (entry % num_tx_desc == num_tx_desc - 1) {
+				entry /= num_tx_desc;
 				dev_kfree_skb_any(priv->tx_skb[q][entry]);
 				priv->tx_skb[q][entry] = NULL;
 				stats->tx_packets++;
@@ -550,8 +583,9 @@
 
 			skb = priv->rx_skb[q][entry];
 			priv->rx_skb[q][entry] = NULL;
-			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
-					 ALIGN(PKT_BUF_SZ, 16),
+			dma_unmap_single(ndev->dev.parent,
+					 le32_to_cpu(desc->dptr),
+					 PKT_BUF_SZ,
 					 DMA_FROM_DEVICE);
 			get_ts &= (q == RAVB_NC) ?
 					RAVB_RXTSTAMP_TYPE_V2_L2_EVENT :
@@ -581,8 +615,7 @@
 	for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) {
 		entry = priv->dirty_rx[q] % priv->num_rx_ring[q];
 		desc = &priv->rx_ring[q][entry];
-		/* The size of the buffer should be on 16-byte boundary. */
-		desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
+		desc->ds_cc = cpu_to_le16(PKT_BUF_SZ);
 
 		if (!priv->rx_skb[q][entry]) {
 			skb = netdev_alloc_skb(ndev,
@@ -653,7 +686,7 @@
 }
 
 /* E-MAC interrupt handler */
-static void ravb_emac_interrupt(struct net_device *ndev)
+static void _ravb_emac_interrupt(struct net_device *ndev)
 {
 	struct ravb_private *priv = netdev_priv(ndev);
 	u32 ecsr, psr;
@@ -679,6 +712,18 @@
 	}
 }
 
+static irqreturn_t ravb_emac_interrupt(int irq, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct ravb_private *priv = netdev_priv(ndev);
+
+	spin_lock(&priv->lock);
+	_ravb_emac_interrupt(ndev);
+	mmiowb();
+	spin_unlock(&priv->lock);
+	return IRQ_HANDLED;
+}
+
 /* Error interrupt handler */
 static void ravb_error_interrupt(struct net_device *ndev)
 {
@@ -689,7 +734,10 @@
 	ravb_write(ndev, ~EIS_QFS, EIS);
 	if (eis & EIS_QFS) {
 		ris2 = ravb_read(ndev, RIS2);
-		ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF), RIS2);
+		if (priv->chip_id == RCAR_GEN2)
+			ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF), RIS2);
+		else
+			ravb_write(ndev, RIS2_QFF0 | RIS2_RFFF, RID2);
 
 		/* Receive Descriptor Empty int */
 		if (ris2 & RIS2_QFF0)
@@ -757,7 +805,7 @@
 
 	/* E-MAC status summary */
 	if (iss & ISS_MS) {
-		ravb_emac_interrupt(ndev);
+		_ravb_emac_interrupt(ndev);
 		result = IRQ_HANDLED;
 	}
 
@@ -775,6 +823,83 @@
 	return result;
 }
 
+/* Descriptor IRQ/ Error/ Management interrupt handler */
+static irqreturn_t ravb_multi_interrupt(int irq, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct ravb_private *priv = netdev_priv(ndev);
+	irqreturn_t result = IRQ_NONE;
+	u32 iss, tis;
+
+	spin_lock(&priv->lock);
+	/* Get interrupt status */
+	iss = ravb_read(ndev, ISS);
+
+	/* Timestamp updated */
+	tis  = ravb_read(ndev, TIS);
+	if (tis & TIS_TFUF) {
+		ravb_write(ndev, ~TIS_TFUF, TIS);
+		ravb_get_tx_tstamp(ndev);
+		result = IRQ_HANDLED;
+	}
+
+	/* Error status summary */
+	if (iss & ISS_ES) {
+		ravb_error_interrupt(ndev);
+		result = IRQ_HANDLED;
+	}
+
+	/* Management */
+	if (iss & ISS_CGIS)
+		result = ravb_ptp_interrupt(ndev);
+
+	mmiowb();
+	spin_unlock(&priv->lock);
+	return result;
+}
+
+static irqreturn_t ravb_dmaq_interrupt(int irq, void *dev_id, int ravb_queue)
+{
+	struct net_device *ndev = dev_id;
+	struct ravb_private *priv = netdev_priv(ndev);
+	irqreturn_t result = IRQ_NONE;
+	u32 ris0, ric0, tis, tic;
+	int q = ravb_queue;
+
+	spin_lock(&priv->lock);
+
+	ris0 = ravb_read(ndev, RIS0);
+	ric0 = ravb_read(ndev, RIC0);
+	tis  = ravb_read(ndev, TIS);
+	tic  = ravb_read(ndev, TIC);
+
+	/* Best effort queue RX/TX */
+	if (((ris0 & ric0) & BIT(q)) ||
+	    ((tis  & tic)  & BIT(q))) {
+		if (napi_schedule_prep(&priv->napi[q])) {
+			/* Mask RX and TX interrupts */
+			ravb_write(ndev, BIT(q), RID0);
+			ravb_write(ndev, BIT(q), TID);
+			__napi_schedule(&priv->napi[q]);
+		}
+		result = IRQ_HANDLED;
+	}
+
+	mmiowb();
+	spin_unlock(&priv->lock);
+	return result;
+}
+
+static irqreturn_t ravb_be_interrupt(int irq, void *dev_id)
+{
+	return ravb_dmaq_interrupt(irq, dev_id, RAVB_BE);
+}
+
+static irqreturn_t ravb_nc_interrupt(int irq, void *dev_id)
+{
+	return ravb_dmaq_interrupt(irq, dev_id, RAVB_NC);
+}
+
 static int ravb_poll(struct napi_struct *napi, int budget)
 {
 	struct net_device *ndev = napi->dev;
@@ -814,8 +939,13 @@
 
 	/* Re-enable RX/TX interrupts */
 	spin_lock_irqsave(&priv->lock, flags);
-	ravb_write(ndev, ravb_read(ndev, RIC0) | mask, RIC0);
-	ravb_write(ndev, ravb_read(ndev, TIC)  | mask,  TIC);
+	if (priv->chip_id == RCAR_GEN2) {
+		ravb_write(ndev, ravb_read(ndev, RIC0) | mask, RIC0);
+		ravb_write(ndev, ravb_read(ndev, TIC)  | mask,  TIC);
+	} else {
+		ravb_write(ndev, mask, RIE0);
+		ravb_write(ndev, mask, TIE);
+	}
 	mmiowb();
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -916,11 +1046,19 @@
 		enum of_gpio_flags flags;
 		int err, gpio;
 
-		err = phy_set_max_speed(phydev, SPEED_100);
-		if (err) {
-			netdev_err(ndev, "failed to limit PHY to 100Mbit/s\n");
-			phy_disconnect(phydev);
+		err = RCAR_PRR_INIT();
+		if (err)
 			return err;
+
+		if (RCAR_PRR_IS_PRODUCT(H3) &&
+		    (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+			err = phy_set_max_speed(phydev, SPEED_100);
+			if (err) {
+				netdev_err(ndev, "failed to limit PHY to 100Mbit/s\n");
+				phy_disconnect(phydev);
+				return err;
+			}
+			netdev_info(ndev, "limited PHY to 100Mbit/s\n");
 		}
 
 		gpio = of_get_named_gpio_flags(np, "phy-int-gpio", 0, &flags);
@@ -937,7 +1075,6 @@
 			}
 		}
 
-		netdev_info(ndev, "limited PHY to 100Mbit/s\n");
 	}
 
 	/* 10BASE is not supported */
@@ -1239,30 +1376,79 @@
 {
 	struct ravb_private *priv = netdev_priv(ndev);
 	int error;
+	struct platform_device *pdev = priv->pdev;
+	struct device *dev = &pdev->dev;
+	char *name;
 
 	napi_enable(&priv->napi[RAVB_BE]);
 	napi_enable(&priv->napi[RAVB_NC]);
 
-	error = request_irq(ndev->irq, ravb_interrupt, IRQF_SHARED, ndev->name,
-			    ndev);
-	if (error) {
-		netdev_err(ndev, "cannot request IRQ\n");
-		goto out_napi_off;
-	}
-
-	if (priv->chip_id == RCAR_GEN3) {
-		error = request_irq(priv->emac_irq, ravb_interrupt,
-				    IRQF_SHARED, ndev->name, ndev);
+	if (priv->chip_id == RCAR_GEN2) {
+		error = request_irq(ndev->irq, ravb_interrupt, IRQF_SHARED,
+				    ndev->name, ndev);
 		if (error) {
 			netdev_err(ndev, "cannot request IRQ\n");
+			goto out_napi_off;
+		}
+	} else {
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch22:multi",
+				      ndev->name);
+		error = request_irq(ndev->irq, ravb_multi_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
+			goto out_napi_off;
+		}
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch24:emac",
+				      ndev->name);
+		error = request_irq(priv->emac_irq, ravb_emac_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
 			goto out_free_irq;
 		}
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch0:rx_be",
+				      ndev->name);
+		error = request_irq(priv->rx_irqs[RAVB_BE], ravb_be_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
+			goto out_free_irq2;
+		}
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch18:tx_be",
+				      ndev->name);
+		error = request_irq(priv->tx_irqs[RAVB_BE], ravb_be_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
+			goto out_free_irq3;
+		}
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch1:rx_nc",
+				      ndev->name);
+		error = request_irq(priv->rx_irqs[RAVB_NC], ravb_nc_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
+			goto out_free_irq4;
+		}
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:ch19:tx_nc",
+				      ndev->name);
+		error = request_irq(priv->tx_irqs[RAVB_NC], ravb_nc_interrupt,
+				    IRQF_SHARED, name, ndev);
+		if (error) {
+			netdev_err(ndev, "cannot request IRQ %s\n", name);
+			goto out_free_irq5;
+		}
 	}
 
 	/* Device init */
 	error = ravb_dmac_init(ndev);
-	if (error)
-		goto out_free_irq2;
+	if (error) {
+		if (priv->chip_id == RCAR_GEN2)
+			goto out_free_irq;
+		else
+			goto out_free_irq6;
+	}
 	ravb_emac_init(ndev);
 
 	/* Initialise PTP Clock driver */
@@ -1280,11 +1466,20 @@
 
 out_ptp_stop:
 	/* Stop PTP Clock driver */
-	if (priv->chip_id == RCAR_GEN2)
+	if (priv->chip_id == RCAR_GEN2) {
 		ravb_ptp_stop(ndev);
+		goto out_free_irq;
+	}
+out_free_irq6:
+	free_irq(priv->tx_irqs[RAVB_NC], ndev);
+out_free_irq5:
+	free_irq(priv->rx_irqs[RAVB_NC], ndev);
+out_free_irq4:
+	free_irq(priv->tx_irqs[RAVB_BE], ndev);
+out_free_irq3:
+	free_irq(priv->rx_irqs[RAVB_BE], ndev);
 out_free_irq2:
-	if (priv->chip_id == RCAR_GEN3)
-		free_irq(priv->emac_irq, ndev);
+	free_irq(priv->emac_irq, ndev);
 out_free_irq:
 	free_irq(ndev->irq, ndev);
 out_napi_off:
@@ -1347,41 +1542,56 @@
 	void *buffer;
 	u32 entry;
 	u32 len;
+	int num_tx_desc = priv->num_tx_desc;
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) *
-	    NUM_TX_DESC) {
+	    num_tx_desc) {
 		netif_err(priv, tx_queued, ndev,
 			  "still transmitting with the full ring!\n");
 		netif_stop_subqueue(ndev, q);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return NETDEV_TX_BUSY;
 	}
-	entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC);
-	priv->tx_skb[q][entry / NUM_TX_DESC] = skb;
+	entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * num_tx_desc);
+	priv->tx_skb[q][entry / num_tx_desc] = skb;
 
 	if (skb_put_padto(skb, ETH_ZLEN))
 		goto drop;
 
-	buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
-		 entry / NUM_TX_DESC * DPTR_ALIGN;
-	len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
-	memcpy(buffer, skb->data, len);
-	dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(ndev->dev.parent, dma_addr))
-		goto drop;
+	if (num_tx_desc >= 2) {
+		buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
+			 entry / num_tx_desc * DPTR_ALIGN;
+		len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
+		/* quick fix */
+		if (len == 0)
+			len = 4;
+		memcpy(buffer, skb->data, len);
+		dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto drop;
 
-	desc = &priv->tx_ring[q][entry];
-	desc->ds_tagl = cpu_to_le16(len);
-	desc->dptr = cpu_to_le32(dma_addr);
+		desc = &priv->tx_ring[q][entry];
+		desc->ds_tagl = cpu_to_le16(len);
+		desc->dptr = cpu_to_le32(dma_addr);
 
-	buffer = skb->data + len;
-	len = skb->len - len;
-	dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(ndev->dev.parent, dma_addr))
-		goto unmap;
+		buffer = skb->data + len;
+		len = skb->len - len;
+		dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto unmap;
 
-	desc++;
+		desc++;
+	} else {
+		desc = &priv->tx_ring[q][entry];
+		len = skb->len;
+		dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto drop;
+	}
 	desc->ds_tagl = cpu_to_le16(len);
 	desc->dptr = cpu_to_le32(dma_addr);
 
@@ -1389,9 +1599,11 @@
 	if (q == RAVB_NC) {
 		ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC);
 		if (!ts_skb) {
-			desc--;
-			dma_unmap_single(ndev->dev.parent, dma_addr, len,
-					 DMA_TO_DEVICE);
+			if (num_tx_desc >= 2) {
+				desc--;
+				dma_unmap_single(ndev->dev.parent, dma_addr,
+						 len, DMA_TO_DEVICE);
+			}
 			goto unmap;
 		}
 		ts_skb->skb = skb;
@@ -1408,15 +1620,19 @@
 
 	/* Descriptor type must be set after all the above writes */
 	dma_wmb();
-	desc->die_dt = DT_FEND;
-	desc--;
-	desc->die_dt = DT_FSTART;
+	if (num_tx_desc >= 2) {
+		desc->die_dt = DT_FEND;
+		desc--;
+		desc->die_dt = DT_FSTART;
+	} else {
+		desc->die_dt = DT_FSINGLE;
+	}
 
 	ravb_write(ndev, ravb_read(ndev, TCCR) | (TCCR_TSRQ0 << q), TCCR);
 
-	priv->cur_tx[q] += NUM_TX_DESC;
+	priv->cur_tx[q] += num_tx_desc;
 	if (priv->cur_tx[q] - priv->dirty_tx[q] >
-	    (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q))
+	    (priv->num_tx_ring[q] - 1) * num_tx_desc && !ravb_tx_free(ndev, q))
 		netif_stop_subqueue(ndev, q);
 
 exit:
@@ -1429,7 +1645,7 @@
 			 le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE);
 drop:
 	dev_kfree_skb_any(skb);
-	priv->tx_skb[q][entry / NUM_TX_DESC] = NULL;
+	priv->tx_skb[q][entry / num_tx_desc] = NULL;
 	goto exit;
 }
 
@@ -1509,9 +1725,15 @@
 	netif_tx_stop_all_queues(ndev);
 
 	/* Disable interrupts by clearing the interrupt masks. */
-	ravb_write(ndev, 0, RIC0);
-	ravb_write(ndev, 0, RIC2);
-	ravb_write(ndev, 0, TIC);
+	if (priv->chip_id == RCAR_GEN2) {
+		ravb_write(ndev, 0, RIC0);
+		ravb_write(ndev, 0, RIC2);
+		ravb_write(ndev, 0, TIC);
+	} else {
+		ravb_write(ndev, RAVB_RIx0_ALL, RID0);
+		ravb_write(ndev, RAVB_RIx2_ALL, RID2);
+		ravb_write(ndev, RAVB_TIx_ALL, TID);
+	}
 
 	/* Stop PTP Clock driver */
 	if (priv->chip_id == RCAR_GEN2)
@@ -1536,6 +1758,13 @@
 	}
 
 	free_irq(ndev->irq, ndev);
+	if (priv->chip_id != RCAR_GEN2) {
+		free_irq(priv->tx_irqs[RAVB_NC], ndev);
+		free_irq(priv->rx_irqs[RAVB_NC], ndev);
+		free_irq(priv->tx_irqs[RAVB_BE], ndev);
+		free_irq(priv->rx_irqs[RAVB_BE], ndev);
+		free_irq(priv->emac_irq, ndev);
+	}
 
 	napi_disable(&priv->napi[RAVB_NC]);
 	napi_disable(&priv->napi[RAVB_BE]);
@@ -1743,6 +1972,7 @@
 	struct net_device *ndev;
 	int error, irq, q;
 	struct resource *res;
+	int i;
 
 	if (!np) {
 		dev_err(&pdev->dev,
@@ -1813,19 +2043,39 @@
 			goto out_release;
 		}
 		priv->emac_irq = irq;
+		for (i = 0; i < NUM_RX_QUEUE; i++) {
+			irq = platform_get_irq_byname(pdev, ravb_rx_irqs[i]);
+			if (irq < 0) {
+				error = irq;
+				goto out_release;
+			}
+			priv->rx_irqs[i] = irq;
+		}
+		for (i = 0; i < NUM_TX_QUEUE; i++) {
+			irq = platform_get_irq_byname(pdev, ravb_tx_irqs[i]);
+			if (irq < 0) {
+				error = irq;
+				goto out_release;
+			}
+			priv->tx_irqs[i] = irq;
+		}
 	}
 
 	priv->chip_id = chip_id;
 
+	if (chip_id == RCAR_GEN2)
+		priv->num_tx_desc = 2;
+	else
+		priv->num_tx_desc = 1;
+
 	/* Set function */
 	ndev->netdev_ops = &ravb_netdev_ops;
 	ndev->ethtool_ops = &ravb_ethtool_ops;
 
-	/* Set AVB config mode */
+	/* Set AVB config mode and CSEL value */
 	if (chip_id == RCAR_GEN2) {
 		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) |
 			   CCC_OPC_CONFIG, CCC);
-		/* Set CSEL value */
 		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) |
 			   CCC_CSEL_HPB, CCC);
 	} else {
@@ -1833,10 +2083,6 @@
 			   CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB, CCC);
 	}
 
-	/* Set CSEL value */
-	ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB,
-		   CCC);
-
 	/* Set GTI value */
 	error = ravb_set_gti(ndev);
 	if (error)
@@ -1947,6 +2193,66 @@
 }
 
 #ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+static int ravb_suspend(struct device *dev)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct ravb_private *priv = netdev_priv(ndev);
+	int ret = 0;
+
+	if (netif_running(ndev)) {
+		netif_device_detach(ndev);
+		ret = ravb_close(ndev);
+		if (priv->chip_id != RCAR_GEN2)
+			ravb_ptp_stop(ndev);
+	}
+
+	return ret;
+}
+
+static int ravb_resume(struct device *dev)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct ravb_private *priv = netdev_priv(ndev);
+	struct platform_device *pdev = priv->pdev;
+	int ret = 0;
+
+	if (netif_running(ndev)) {
+		/* Set AVB config mode */
+		if (priv->chip_id == RCAR_GEN2) {
+			ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) |
+				   CCC_OPC_CONFIG, CCC);
+		} else {
+			ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) |
+				   CCC_OPC_CONFIG | CCC_GAC, CCC);
+		}
+
+		/* Set CSEL value */
+		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) |
+			   CCC_CSEL_HPB, CCC);
+
+		/* Set GTI value */
+		ravb_set_gti(ndev);
+
+		/* Request GTI loading */
+		ravb_write(ndev, ravb_read(ndev, GCCR) | GCCR_LTI, GCCR);
+
+		/* Set DBAT value */
+		ravb_write(ndev, priv->desc_bat_dma, DBAT);
+
+		if (priv->chip_id != RCAR_GEN2)
+			ravb_ptp_init(ndev, pdev);
+
+		ret = ravb_open(ndev);
+		if (ret < 0)
+			return ret;
+		netif_device_attach(ndev);
+	}
+
+	return ret;
+}
+#endif
+
 static int ravb_runtime_nop(struct device *dev)
 {
 	/* Runtime PM callback shared between ->runtime_suspend()
@@ -1960,8 +2266,8 @@
 }
 
 static const struct dev_pm_ops ravb_dev_pm_ops = {
-	.runtime_suspend = ravb_runtime_nop,
-	.runtime_resume = ravb_runtime_nop,
+	SET_SYSTEM_SLEEP_PM_OPS(ravb_suspend, ravb_resume)
+	SET_RUNTIME_PM_OPS(ravb_runtime_nop, ravb_runtime_nop, NULL)
 };
 
 #define RAVB_PM_OPS (&ravb_dev_pm_ops)
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
index 7a8ce92..a789c7c 100644
--- a/drivers/net/ethernet/renesas/ravb_ptp.c
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -196,11 +196,15 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 	gic = ravb_read(ndev, GIC);
-	if (on)
-		gic |= GIC_PTCE;
-	else
-		gic &= ~GIC_PTCE;
-	ravb_write(ndev, gic, GIC);
+	if (priv->chip_id == RCAR_GEN2) {
+		if (on)
+			gic |= GIC_PTCE;
+		else
+			gic &= ~GIC_PTCE;
+		ravb_write(ndev, gic, GIC);
+	} else {
+		ravb_write(ndev, GIC_PTCE, (on) ? GIE : GID);
+	}
 	mmiowb();
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -216,7 +220,7 @@
 	struct ravb_ptp_perout *perout;
 	unsigned long flags;
 	int error = 0;
-	u32 gic;
+	u32 gic = 0;
 
 	if (req->index)
 		return -EINVAL;
@@ -248,9 +252,13 @@
 		error = ravb_ptp_update_compare(priv, (u32)start_ns);
 		if (!error) {
 			/* Unmask interrupt */
-			gic = ravb_read(ndev, GIC);
-			gic |= GIC_PTME;
-			ravb_write(ndev, gic, GIC);
+			if (priv->chip_id == RCAR_GEN2) {
+				gic = ravb_read(ndev, GIC);
+				gic |= GIC_PTME;
+				ravb_write(ndev, gic, GIC);
+			} else {
+				ravb_write(ndev, GIC_PTME, GIE);
+			}
 		}
 	} else	{
 		spin_lock_irqsave(&priv->lock, flags);
@@ -259,9 +267,13 @@
 		perout->period = 0;
 
 		/* Mask interrupt */
-		gic = ravb_read(ndev, GIC);
-		gic &= ~GIC_PTME;
-		ravb_write(ndev, gic, GIC);
+		if (priv->chip_id == RCAR_GEN2) {
+			gic = ravb_read(ndev, GIC);
+			gic &= ~GIC_PTME;
+			ravb_write(ndev, gic, GIC);
+		} else {
+			ravb_write(ndev, GIC_PTME, GID);
+		}
 	}
 	mmiowb();
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -352,7 +364,11 @@
 {
 	struct ravb_private *priv = netdev_priv(ndev);
 
-	ravb_write(ndev, 0, GIC);
+	if (priv->chip_id == RCAR_GEN2)
+		ravb_write(ndev, 0, GIC);
+	else
+		ravb_write(ndev, RAVB_GIx_ALL, GID);
+
 	ravb_write(ndev, 0, GIS);
 
 	ptp_clock_unregister(priv->ptp.clock);
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 4edb518..de147fe 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -84,6 +84,14 @@
 #define MACSR			0x011054
 #define MACCTLR			0x011058
 #define  SCRAMBLE_DISABLE	(1 << 27)
+#define PMSR			0x01105c
+#define  L1FAEG			(1 << 31)
+#define  PM_ENTER_L1RX		(1 << 23)
+#define  PMSTATE		(7 << 16)
+#define  PMSTATE_L1		(3 << 16)
+#define PMCTLR			0x011060
+#define  L1_INIT		(1 << 31)
+
 
 /* R-Car H1 PHY */
 #define H1_PCIEPHYADRR		0x04000c
@@ -181,6 +189,7 @@
 		unsigned int devfn, int where, u32 *data)
 {
 	int dev, func, reg, index;
+	u32 val;
 
 	dev = PCI_SLOT(devfn);
 	func = PCI_FUNC(devfn);
@@ -222,6 +231,22 @@
 	if (pcie->root_bus_nr < 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
+	/*
+	 * If we are not in L1 link state and we have received PM_ENTER_L1 DLLP,
+	 * transition to L1 link state. The HW will handle coming of of L1.
+	 */
+	val = rcar_pci_read_reg(pcie, PMSR);
+	if ((val & PM_ENTER_L1RX) && ((val & PMSTATE) != PMSTATE_L1)) {
+		rcar_pci_write_reg(pcie, L1_INIT, PMCTLR);
+
+		/* Wait until we are in L1 */
+		while (!(val & L1FAEG))
+			val = rcar_pci_read_reg(pcie, PMSR);
+
+		/* Clear flags indicating link has transitioned to L1 */
+		rcar_pci_write_reg(pcie, L1FAEG | PM_ENTER_L1RX, PMSR);
+	}
+
 	/* Clear errors */
 	rcar_pci_write_reg(pcie, rcar_pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
 
@@ -1069,9 +1094,32 @@
 	return err;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rcar_pcie_suspend(struct device *dev)
+{
+	/* Empty functino for now */
+	return 0;
+}
+
+static int rcar_pcie_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_pcie_pm_ops,
+			rcar_pcie_suspend,
+			rcar_pcie_resume);
+
+#define DEV_PM_OPS (&rcar_pcie_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rcar_pcie_driver = {
 	.driver = {
 		.name = DRV_NAME,
+		.pm	= DEV_PM_OPS,
 		.of_match_table = rcar_pcie_of_match,
 		.suppress_bind_attrs = true,
 	},
@@ -1079,6 +1127,34 @@
 };
 module_platform_driver(rcar_pcie_driver);
 
+static int rcar_pcie_pci_notifier(struct notifier_block *nb,
+			    unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	switch (action) {
+	case BUS_NOTIFY_BOUND_DRIVER:
+		/* Force the DMA mask to lower 32-bits */
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block device_nb = {
+	.notifier_call = rcar_pcie_pci_notifier,
+};
+
+static int __init register_rcar_pcie_pci_notifier(void)
+{
+	return bus_register_notifier(&pci_bus_type, &device_nb);
+}
+
+arch_initcall(register_rcar_pcie_pci_notifier);
+
 MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
 MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index ef332ef..70a9297 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -74,20 +74,6 @@
 #define USB2_ADPCTRL_IDPULLUP		BIT(5)	/* 1 = ID sampling is enabled */
 #define USB2_ADPCTRL_DRVVBUS		BIT(4)
 
-/******* HSUSB registers (original offset is +0x100) *******/
-#define HSUSB_LPSTS			0x02
-#define HSUSB_UGCTRL2			0x84
-
-/* Low Power Status register (LPSTS) */
-#define HSUSB_LPSTS_SUSPM		0x4000
-
-/* USB General control register 2 (UGCTRL2) */
-#define HSUSB_UGCTRL2_MASK		0x00000031 /* bit[31:6] should be 0 */
-#define HSUSB_UGCTRL2_USB0SEL		0x00000030
-#define HSUSB_UGCTRL2_USB0SEL_HOST	0x00000010
-#define HSUSB_UGCTRL2_USB0SEL_HS_USB	0x00000020
-#define HSUSB_UGCTRL2_USB0SEL_OTG	0x00000030
-
 struct rcar_gen3_data {
 	void __iomem *base;
 	struct clk *clk;
@@ -95,8 +81,8 @@
 
 struct rcar_gen3_chan {
 	struct rcar_gen3_data usb2;
-	struct rcar_gen3_data hsusb;
 	struct phy *phy;
+	bool has_otg;
 };
 
 static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
@@ -202,24 +188,15 @@
 {
 	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 	void __iomem *usb2_base = channel->usb2.base;
-	void __iomem *hsusb_base = channel->hsusb.base;
-	u32 val;
 
 	/* Initialize USB2 part */
 	writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
 	writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
 	writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
 
-	/* Initialize HSUSB part */
-	if (hsusb_base) {
-		val = readl(hsusb_base + HSUSB_UGCTRL2);
-		val = (val & ~HSUSB_UGCTRL2_USB0SEL) |
-		      HSUSB_UGCTRL2_USB0SEL_OTG;
-		writel(val & HSUSB_UGCTRL2_MASK, hsusb_base + HSUSB_UGCTRL2);
-
-		/* Initialize otg part */
+	/* Initialize otg part */
+	if (channel->has_otg)
 		rcar_gen3_init_otg(channel);
-	}
 
 	return 0;
 }
@@ -237,7 +214,6 @@
 {
 	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
 	void __iomem *usb2_base = channel->usb2.base;
-	void __iomem *hsusb_base = channel->hsusb.base;
 	u32 val;
 
 	val = readl(usb2_base + USB2_USBCTR);
@@ -246,33 +222,6 @@
 	val &= ~USB2_USBCTR_PLL_RST;
 	writel(val, usb2_base + USB2_USBCTR);
 
-	/*
-	 * TODO: To reduce power consuming, this driver should set the SUSPM
-	 *	after the PHY detects ID pin as peripheral.
-	 */
-	if (hsusb_base) {
-		/* Power on HSUSB PHY */
-		val = readw(hsusb_base + HSUSB_LPSTS);
-		val |= HSUSB_LPSTS_SUSPM;
-		writew(val, hsusb_base + HSUSB_LPSTS);
-	}
-
-	return 0;
-}
-
-static int rcar_gen3_phy_usb2_power_off(struct phy *p)
-{
-	struct rcar_gen3_chan *channel = phy_get_drvdata(p);
-	void __iomem *hsusb_base = channel->hsusb.base;
-	u32 val;
-
-	if (hsusb_base) {
-		/* Power off HSUSB PHY */
-		val = readw(hsusb_base + HSUSB_LPSTS);
-		val &= ~HSUSB_LPSTS_SUSPM;
-		writew(val, hsusb_base + HSUSB_LPSTS);
-	}
-
 	return 0;
 }
 
@@ -280,7 +229,6 @@
 	.init		= rcar_gen3_phy_usb2_init,
 	.exit		= rcar_gen3_phy_usb2_exit,
 	.power_on	= rcar_gen3_phy_usb2_power_on,
-	.power_off	= rcar_gen3_phy_usb2_power_off,
 	.owner		= THIS_MODULE,
 };
 
@@ -313,6 +261,7 @@
 	struct rcar_gen3_chan *channel;
 	struct phy_provider *provider;
 	struct resource *res;
+	int irq;
 
 	if (!dev->of_node) {
 		dev_err(dev, "This driver needs device tree\n");
@@ -323,29 +272,19 @@
 	if (!channel)
 		return -ENOMEM;
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2_host");
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	channel->usb2.base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(channel->usb2.base))
 		return PTR_ERR(channel->usb2.base);
 
-	/* "hsusb" memory resource is optional */
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsusb");
-
-	/* To avoid error message by devm_ioremap_resource() */
-	if (res) {
-		int irq;
-
-		channel->hsusb.base = devm_ioremap_resource(dev, res);
-		if (IS_ERR(channel->hsusb.base))
-			channel->hsusb.base = NULL;
-		/* call request_irq for OTG */
-		irq = platform_get_irq(pdev, 0);
-		if (irq >= 0)
-			irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
-					       IRQF_SHARED, dev_name(dev),
-					       channel);
+	/* call request_irq for OTG */
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0) {
+		irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
+				       IRQF_SHARED, dev_name(dev), channel);
 		if (irq < 0)
 			dev_err(dev, "No irq handler (%d)\n", irq);
+		channel->has_otg = true;
 	}
 
 	/* devm_phy_create() will call pm_runtime_enable(dev); */
@@ -364,9 +303,30 @@
 	return PTR_ERR_OR_ZERO(provider);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rcar_gen3_phy_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_gen3_phy_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_gen3_phy_pm_ops,
+			rcar_gen3_phy_suspend, rcar_gen3_phy_resume);
+#define DEV_PM_OPS (&rcar_gen3_phy_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rcar_gen3_phy_usb2_driver = {
 	.driver = {
 		.name		= "phy_rcar_gen3_usb2",
+		.pm		= DEV_PM_OPS,
 		.of_match_table	= rcar_gen3_phy_usb2_match_table,
 	},
 	.probe	= rcar_gen3_phy_usb2_probe,
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 181ea98..3942773 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -634,12 +634,37 @@
 };
 MODULE_DEVICE_TABLE(platform, sh_pfc_id_table);
 
+#ifdef CONFIG_PM_SLEEP
+static int sh_pfc_suspend(struct device *dev)
+{
+#ifdef CONFIG_PINCTRL_PFC_R8A7795
+	/* Empty function for now */
+#endif
+	return 0;
+}
+
+static int sh_pfc_resume(struct device *dev)
+{
+#ifdef CONFIG_PINCTRL_PFC_R8A7795
+	/* Empty function for now */
+#endif
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sh_pfc_pm_ops,
+			sh_pfc_suspend, sh_pfc_resume);
+#define DEV_PM_OPS (&sh_pfc_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver sh_pfc_driver = {
 	.probe		= sh_pfc_probe,
 	.remove		= sh_pfc_remove,
 	.id_table	= sh_pfc_id_table,
 	.driver		= {
 		.name	= DRV_NAME,
+		.pm	= DEV_PM_OPS,
 		.of_match_table = of_match_ptr(sh_pfc_of_table),
 	},
 };
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index d2250d2..1cc2b78 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -8,17 +8,22 @@
  * the Free Software Foundation; version 2 of the License.
  */
 
+#include <linux/io.h>
 #include <linux/kernel.h>
 
 #include "core.h"
 #include "sh_pfc.h"
 
+/*
+* All pins assigned to GPIO bank 3 and 4 can be used for SD interfaces in
+* which case they support both 3.3V and 1.8V signalling.
+*/
 #define CPU_ALL_PORT(fn, sfx)						\
 	PORT_GP_16(0, fn, sfx),						\
 	PORT_GP_28(1, fn, sfx),						\
 	PORT_GP_15(2, fn, sfx),						\
-	PORT_GP_16(3, fn, sfx),						\
-	PORT_GP_18(4, fn, sfx),						\
+	PORT_GP_CFG_16(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),		\
+	PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),		\
 	PORT_GP_26(5, fn, sfx),						\
 	PORT_GP_32(6, fn, sfx),						\
 	PORT_GP_4(7, fn, sfx)
@@ -4379,6 +4384,67 @@
 	"vin5_clk",
 };
 
+#define POCCTRL0	0x380
+#define PIN2POCCTRL0_SHIFT(a) ({ \
+	int _gp = (a) >> 5; \
+	int _bit = (a) & 0x1f; \
+	((_gp == 3) && (_bit < 12)) ? _bit : \
+	((_gp == 4) && (_bit < 18)) ? _bit + 12 : -1; \
+})
+
+static int r8a7795_get_io_voltage(struct sh_pfc *pfc, unsigned int pin)
+{
+	void __iomem *reg;
+	u32 data, mask;
+	int shift;
+
+	/* Bits in POCCTRL0 are numbered in opposite order to pins */
+	shift = PIN2POCCTRL0_SHIFT(pin);
+
+	if (WARN(shift < 0, "invalid pin %#x", pin))
+		return -EINVAL;
+
+	reg = pfc->windows->virt + POCCTRL0;
+	data = ioread32(reg);
+
+	mask = 0x1 << shift;
+
+	return (data & mask) ? 3300 : 1800;
+}
+
+static int r8a7795_set_io_voltage(struct sh_pfc *pfc, unsigned int pin, u16 mV)
+{
+	void __iomem *reg;
+	u32 data, mask;
+	int shift;
+
+	/* Bits in POCCTRL0 are numbered in opposite order to pins */
+	shift = PIN2POCCTRL0_SHIFT(pin);
+
+	if (WARN(shift < 0, "invalid pin %#x", pin))
+		return -EINVAL;
+
+	if (mV != 1800 && mV != 3300)
+		return -EINVAL;
+
+	reg = pfc->windows->virt + POCCTRL0;
+	data = ioread32(reg);
+
+	mask = 0x1 << shift;
+
+	if (mV == 3300)
+		data |= mask;
+	else
+		data &= ~mask;
+
+
+	iowrite32(~data, pfc->windows->virt +
+				(pfc->info->unlock_reg - pfc->windows->phys));
+	iowrite32(data, reg);
+
+	return 0;
+}
+
 static const struct sh_pfc_function pinmux_functions[] = {
 	SH_PFC_FUNCTION(audio_clk),
 	SH_PFC_FUNCTION(avb),
@@ -4981,8 +5047,14 @@
 	{ },
 };
 
+static const struct sh_pfc_soc_operations pinmux_ops = {
+	.get_io_voltage = r8a7795_get_io_voltage,
+	.set_io_voltage = r8a7795_set_io_voltage,
+};
+
 const struct sh_pfc_soc_info r8a7795_pinmux_info = {
 	.name = "r8a77950_pfc",
+	.ops = &pinmux_ops,
 	.unlock_reg = 0xe6060000, /* PMMR */
 
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 8cf0dae..9a93740 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -305,7 +305,7 @@
 
 config PWM_RCAR
 	tristate "Renesas R-Car PWM support"
-	depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST
+	depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || ARCH_RENESAS  || COMPILE_TEST
 	depends on HAS_IOMEM
 	help
 	  This driver exposes the PWM Timer controller found in Renesas
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 7b8ac06..00c8fd1 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 
 #define RCAR_PWM_MAX_DIVISION	24
+#define RCAR_PWM_MIN_CYCLE	2
 #define RCAR_PWM_MAX_CYCLE	1023
 
 #define RCAR_PWMCR		0x00
@@ -71,12 +72,17 @@
 static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
 {
 	unsigned long clk_rate = clk_get_rate(rp->clk);
-	unsigned long long max; /* max cycle / nanoseconds */
+	unsigned long long min, max; /* min, max cycle / nanoseconds */
 	unsigned int div;
 
 	if (clk_rate == 0)
 		return -EINVAL;
 
+	min = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MIN_CYCLE;
+	do_div(min, clk_rate);
+	if (period_ns < min)
+		return -ERANGE;
+
 	for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
 		max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
 			(1 << div);
@@ -157,7 +163,7 @@
 		return div;
 
 	/* Let the core driver set pwm->period if disabled and duty_ns == 0 */
-	if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns)
+	if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns && !pwm->duty_cycle)
 		return 0;
 
 	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
@@ -258,11 +264,32 @@
 };
 MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
 
+#ifdef CONFIG_PM_SLEEP
+static int rcar_pwm_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_pwm_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops,
+			rcar_pwm_suspend, rcar_pwm_resume);
+#define DEV_PM_OPS (&rcar_pwm_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rcar_pwm_driver = {
 	.probe = rcar_pwm_probe,
 	.remove = rcar_pwm_remove,
 	.driver = {
 		.name = "pwm-rcar",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = of_match_ptr(rcar_pwm_of_table),
 	}
 };
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8155e80..158c391 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -154,6 +154,13 @@
 	  BCM590xx PMUs. This will enable support for the software
 	  controllable LDO/Switching regulators.
 
+config REGULATOR_BD9571MWV
+	tristate "ROHM BD9571MWV PMIC regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports the voltage regulators of BD9571MWV-M.
+
 config REGULATOR_DA903X
 	tristate "Dialog Semiconductor DA9030/DA9034 regulators"
 	depends on PMIC_DA903X
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 980b194..a31804a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -22,6 +22,7 @@
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
+obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DA9055)	+= da9055-regulator.o
diff --git a/drivers/regulator/bd9571mwv.c b/drivers/regulator/bd9571mwv.c
new file mode 100644
index 0000000..4cff812
--- /dev/null
+++ b/drivers/regulator/bd9571mwv.c
@@ -0,0 +1,140 @@
+/*
+ * Power Management IC for BD9571MWV-M.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct bd9571mwv {
+	struct regulator_dev *rdev;
+	struct regmap *regmap;
+};
+
+static const struct regmap_config bd9571mwv_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static struct regulator_ops bd9571mwv_ops = {
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+/* Default limits measured in millivolts and milliamps */
+#define BD9571MWV_MIN_MV		600
+#define BD9571MWV_MAX_MV		1100
+#define BD9571MWV_STEP_MV		10
+#define BD9571MWV_SLEWRATE		10000
+
+/* Define Register */
+#define BD9571_DVFS_SETVID		0x54
+#define BD9571_DVFS_SETVID_MASK		0x7F
+
+static const struct regulator_desc bd9571mwv_reg = {
+	.name = "BD9571MWV",
+	.id = 0,
+	.ops = &bd9571mwv_ops,
+	.type = REGULATOR_VOLTAGE,
+	.n_voltages = BD9571MWV_MAX_MV / BD9571MWV_STEP_MV + 1,
+	.min_uV = BD9571MWV_MIN_MV * 1000,
+	.uV_step = BD9571MWV_STEP_MV * 1000,
+	.ramp_delay = BD9571MWV_SLEWRATE,
+	.vsel_reg = BD9571_DVFS_SETVID,
+	.vsel_mask = BD9571_DVFS_SETVID_MASK,
+	.linear_min_sel = BD9571MWV_MIN_MV / BD9571MWV_STEP_MV,
+	.owner = THIS_MODULE,
+};
+
+/*
+ * I2C driver interface functions
+ */
+static int bd9571mwv_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct bd9571mwv *chip;
+	struct device *dev = &i2c->dev;
+	struct regulator_dev *rdev = NULL;
+	struct regulator_config config = { };
+	int error;
+
+	chip = devm_kzalloc(&i2c->dev, sizeof(struct bd9571mwv), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->regmap = devm_regmap_init_i2c(i2c, &bd9571mwv_regmap_config);
+	if (IS_ERR(chip->regmap)) {
+		error = PTR_ERR(chip->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			error);
+		return error;
+	}
+
+	config.dev = &i2c->dev;
+	config.init_data = of_get_regulator_init_data(dev,
+				dev->of_node, &bd9571mwv_reg);
+	config.driver_data = chip;
+	config.regmap = chip->regmap;
+	config.of_node = dev->of_node;
+
+	rdev = devm_regulator_register(&i2c->dev, &bd9571mwv_reg, &config);
+	if (IS_ERR(rdev)) {
+		dev_err(&i2c->dev, "Failed to register BD9571MWV\n");
+		return PTR_ERR(rdev);
+	}
+
+	chip->rdev = rdev;
+
+	i2c_set_clientdata(i2c, chip);
+
+	dev_info(dev, "bd9571mwv probed\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id bd9571mwv_dt_ids[] = {
+	{ .compatible = "rohm,bd9571mwv" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bd9571mwv_dt_ids);
+#endif
+
+static const struct i2c_device_id bd9571mwv_i2c_id[] = {
+	{"bd9571mwv", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, bd9571mwv_i2c_id);
+
+static struct i2c_driver bd9571mwv_regulator_driver = {
+	.driver = {
+		.name = "bd9571mwv",
+		.of_match_table	= of_match_ptr(bd9571mwv_dt_ids),
+	},
+	.probe = bd9571mwv_i2c_probe,
+	.id_table = bd9571mwv_i2c_id,
+};
+
+module_i2c_driver(bd9571mwv_regulator_driver);
+
+MODULE_AUTHOR("Keita Kobayashi <keita.kobayashi.ym@renesas.com");
+MODULE_DESCRIPTION("Power Management IC for BD9571MWV-M");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/renesas/rcar_pm_sysc.c b/drivers/soc/renesas/rcar_pm_sysc.c
index 656dee46..f85104e 100644
--- a/drivers/soc/renesas/rcar_pm_sysc.c
+++ b/drivers/soc/renesas/rcar_pm_sysc.c
@@ -192,7 +192,7 @@
 				if (ret != -EAGAIN)
 					break;
 			}
-			udelay(SYSCISR_DELAY_US);
+			udelay(SYSCSR_DELAY_US);
 		}
 
 		spin_unlock_irqrestore(&sysc_lock, sysc_lock_flags);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7706416..d73ce13 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -505,6 +505,26 @@
 	help
 	  SPI driver for SuperH and SH Mobile MSIOF blocks.
 
+config SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+	bool "Transfer Synchronization Debug support for MSIOF"
+	depends on SPI_SH_MSIOF
+	default n
+	help
+	  In data transfer, the slave needs to have completed
+	  a transfer preparation before the master.
+	  As a test environment, it was to be able to put a sleep wait
+	  before the data transfer of the master.
+
+config SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG_MSLEEP
+	int "Master of sleep latency (msec time)"
+	default 1
+	depends on SPI_SH_MSIOF && SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+	help
+	  Select Sleep latency of the previous data transfer
+	  at the time of master mode.
+	  Examples:
+	    N => N msec
+
 config SPI_SH
 	tristate "SuperH SPI controller"
 	depends on SUPERH || COMPILE_TEST
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index a7934ab..dd4d071 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1,6 +1,7 @@
 /*
  * SuperH MSIOF SPI Master Interface
  *
+ * Copyright (C) 2014-2016 Renesas Electronics Corporation
  * Copyright (c) 2009 Magnus Damm
  * Copyright (C) 2014 Glider bvba
  *
@@ -28,11 +29,14 @@
 #include <linux/pm_runtime.h>
 #include <linux/sh_dma.h>
 
+#include <linux/soc/renesas/rcar_prr.h>
 #include <linux/spi/sh_msiof.h>
 #include <linux/spi/spi.h>
 
 #include <asm/unaligned.h>
 
+#undef HZ
+#define HZ MAX_SCHEDULE_TIMEOUT
 
 struct sh_msiof_chipdata {
 	u16 tx_fifo_size;
@@ -40,6 +44,9 @@
 	u16 master_flags;
 };
 
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+#define TRANSFAR_SYNC_DELAY (CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG_MSLEEP)
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
 struct sh_msiof_spi_priv {
 	struct spi_master *master;
 	void __iomem *mapbase;
@@ -48,8 +55,10 @@
 	const struct sh_msiof_chipdata *chipdata;
 	struct sh_msiof_spi_info *info;
 	struct completion done;
+	struct completion done_dma_tx, done_dma_rx;
 	unsigned int tx_fifo_size;
 	unsigned int rx_fifo_size;
+	int mode;
 	void *tx_dma_page;
 	void *rx_dma_page;
 	dma_addr_t tx_dma_addr;
@@ -82,6 +91,7 @@
 #define MDR1_SYNCMD_LR	 0x30000000 /*   L/R mode */
 #define MDR1_SYNCAC_SHIFT	 25 /* Sync Polarity (1 = Active-low) */
 #define MDR1_BITLSB_SHIFT	 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_DTDL_MASK  0x00700000 /* Data Pin Bit Delay Mask */
 #define MDR1_DTDL_SHIFT		 20 /* Data Pin Bit Delay for MSIOF_SYNC */
 #define MDR1_SYNCDL_SHIFT	 16 /* Frame Sync Signal Timing Delay */
 #define MDR1_FLD_MASK	 0x0000000c /* Frame Sync Signal Interval (0-3) */
@@ -335,7 +345,34 @@
 	tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
 	tmp |= lsb_first << MDR1_BITLSB_SHIFT;
 	tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
-	sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 0 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 1 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (p->mode == SPI_MSIOF_MASTER)
+		sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+	else
+		sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 2 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 1 << MDR1_DTDL_SHIFT;
+		}
+	}
 	if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
 		/* These bits are reserved if RX needs TX */
 		tmp &= ~0x0000ffff;
@@ -343,8 +380,18 @@
 	sh_msiof_write(p, RMDR1, tmp);
 
 	tmp = 0;
-	tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
-	tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp |= 0 << CTR_TSCKIZ_POL_SHIFT;
+			tmp |= 0 << CTR_RSCKIZ_POL_SHIFT;
+		} else {
+			tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+			tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+		}
+	} else {
+		tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+		tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+	}
 
 	edge = cpol ^ !cpha;
 
@@ -562,17 +609,18 @@
 
 static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
 {
-	int ret;
+	int ret = 0;
 
 	/* setup clock and rx/tx signals */
-	ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
+	if (p->mode == SPI_MSIOF_MASTER)
+		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
 	if (rx_buf && !ret)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE);
 	if (!ret)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE);
 
 	/* start by setting frame bit */
-	if (!ret)
+	if (!ret && p->mode == SPI_MSIOF_MASTER)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE);
 
 	return ret;
@@ -580,15 +628,16 @@
 
 static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf)
 {
-	int ret;
+	int ret = 0;
 
 	/* shut down frame, rx/tx and clock signals */
-	ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
+	if (p->mode == SPI_MSIOF_MASTER)
+		ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
 	if (!ret)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
 	if (rx_buf && !ret)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0);
-	if (!ret)
+	if (!ret && p->mode == SPI_MSIOF_MASTER)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0);
 
 	return ret;
@@ -663,12 +712,18 @@
 	return ret;
 }
 
-static void sh_msiof_dma_complete(void *arg)
+static void sh_msiof_tx_dma_complete(void *arg)
 {
 	struct sh_msiof_spi_priv *p = arg;
 
-	sh_msiof_write(p, IER, 0);
-	complete(&p->done);
+	complete(&p->done_dma_tx);
+}
+
+static void sh_msiof_rx_dma_complete(void *arg)
+{
+	struct sh_msiof_spi_priv *p = arg;
+
+	complete(&p->done_dma_rx);
 }
 
 static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
@@ -688,7 +743,7 @@
 		if (!desc_rx)
 			return -EAGAIN;
 
-		desc_rx->callback = sh_msiof_dma_complete;
+		desc_rx->callback = sh_msiof_rx_dma_complete;
 		desc_rx->callback_param = p;
 		cookie = dmaengine_submit(desc_rx);
 		if (dma_submit_error(cookie))
@@ -707,13 +762,8 @@
 			goto no_dma_tx;
 		}
 
-		if (rx) {
-			/* No callback */
-			desc_tx->callback = NULL;
-		} else {
-			desc_tx->callback = sh_msiof_dma_complete;
-			desc_tx->callback_param = p;
-		}
+		desc_tx->callback = sh_msiof_tx_dma_complete;
+		desc_tx->callback_param = p;
 		cookie = dmaengine_submit(desc_tx);
 		if (dma_submit_error(cookie)) {
 			ret = cookie;
@@ -730,6 +780,8 @@
 	sh_msiof_write(p, IER, ier_bits);
 
 	reinit_completion(&p->done);
+	reinit_completion(&p->done_dma_tx);
+	reinit_completion(&p->done_dma_rx);
 
 	/* Now start DMA */
 	if (rx)
@@ -743,12 +795,37 @@
 		goto stop_dma;
 	}
 
-	/* wait for tx fifo to be emptied / rx fifo to be filled */
-	if (!wait_for_completion_timeout(&p->done, HZ)) {
-		dev_err(&p->pdev->dev, "DMA timeout\n");
-		ret = -ETIMEDOUT;
-		goto stop_reset;
+	/* wait for Tx/Rx DMA completion */
+	if (tx) {
+		ret = wait_for_completion_timeout(&p->done_dma_tx, HZ);
+		if (!ret) {
+			dev_err(&p->pdev->dev, "Tx DMA timeout\n");
+			ret = -ETIMEDOUT;
+			goto stop_reset;
+		}
+		if (!rx) {
+			ier_bits = IER_TEOFE;
+			sh_msiof_write(p, IER, ier_bits);
+
+			/* wait for tx fifo to be emptied */
+			if (!wait_for_completion_timeout(&p->done, HZ)) {
+				dev_err(&p->pdev->dev,
+					"Tx fifo to be emptied timeout\n");
+				ret = -ETIMEDOUT;
+				goto stop_reset;
+			}
+		}
 	}
+	if (rx) {
+		ret = wait_for_completion_timeout(&p->done_dma_rx, HZ);
+		if (!ret) {
+			dev_err(&p->pdev->dev, "Rx DMA timeout\n");
+			ret = -ETIMEDOUT;
+			goto stop_reset;
+		}
+	}
+
+	sh_msiof_write(p, IER, 0);
 
 	/* clear status bits */
 	sh_msiof_reset_str(p);
@@ -841,7 +918,8 @@
 	int ret;
 
 	/* setup clocks (clock already enabled in chipselect()) */
-	sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
+	if (p->mode == SPI_MSIOF_MASTER)
+		sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
 
 	while (master->dma_tx && len > 15) {
 		/*
@@ -860,7 +938,7 @@
 				break;
 			copy32 = copy_bswap32;
 		} else if (bits <= 16) {
-			if (l & 1)
+			if (l & 3)
 				break;
 			copy32 = copy_wswap32;
 		} else {
@@ -870,6 +948,11 @@
 		if (tx_buf)
 			copy32(p->tx_dma_page, tx_buf, l / 4);
 
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+		if (p->mode == 0)
+			msleep(TRANSFAR_SYNC_DELAY);
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
+
 		ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
 		if (ret == -EAGAIN) {
 			pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
@@ -943,6 +1026,12 @@
 	words = len / bytes_per_word;
 
 	while (words > 0) {
+
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+		if (p->mode == 0)
+			msleep(TRANSFAR_SYNC_DELAY);
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
+
 		n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf,
 					   words, bits);
 		if (n < 0)
@@ -978,6 +1067,7 @@
 	{ .compatible = "renesas,msiof-r8a7792",   .data = &r8a779x_data },
 	{ .compatible = "renesas,msiof-r8a7793",   .data = &r8a779x_data },
 	{ .compatible = "renesas,msiof-r8a7794",   .data = &r8a779x_data },
+	{ .compatible = "renesas,msiof-r8a7795",   .data = &r8a779x_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, sh_msiof_match);
@@ -1002,6 +1092,11 @@
 	of_property_read_u32(np, "renesas,dtdl", &info->dtdl);
 	of_property_read_u32(np, "renesas,syncdl", &info->syncdl);
 
+	if (of_property_read_bool(np, "slave"))
+		info->mode = SPI_MSIOF_SLAVE;
+	else
+		info->mode = SPI_MSIOF_MASTER;
+
 	info->num_chipselect = num_cs;
 
 	return info;
@@ -1074,10 +1169,7 @@
 		return 0;
 	}
 
-	/* The DMA engine uses the second register set, if present */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res)
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	master = p->master;
 	master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
@@ -1184,6 +1276,8 @@
 	}
 
 	init_completion(&p->done);
+	init_completion(&p->done_dma_tx);
+	init_completion(&p->done_dma_rx);
 
 	p->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(p->clk)) {
@@ -1223,6 +1317,7 @@
 		p->tx_fifo_size = p->info->tx_fifo_override;
 	if (p->info->rx_fifo_override)
 		p->rx_fifo_size = p->info->rx_fifo_override;
+	p->mode = p->info->mode;
 
 	/* init master code */
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1247,6 +1342,12 @@
 		goto err2;
 	}
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_err(&pdev->dev, "rcar workaround init error.\n");
+		goto err2;
+	}
+
 	return 0;
 
  err2:
@@ -1272,12 +1373,33 @@
 };
 MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 
+#ifdef CONFIG_PM_SLEEP
+static int sh_msiof_spi_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int sh_msiof_spi_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops,
+			sh_msiof_spi_suspend, sh_msiof_spi_resume);
+#define DEV_PM_OPS (&sh_msiof_spi_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct platform_driver sh_msiof_spi_drv = {
 	.probe		= sh_msiof_spi_probe,
 	.remove		= sh_msiof_spi_remove,
 	.id_table	= spi_driver_ids,
 	.driver		= {
 		.name		= "spi_sh_msiof",
+		.pm		= DEV_PM_OPS,
 		.of_match_table = of_match_ptr(sh_msiof_match),
 	},
 };
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index e3c19f3..b016a5a 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2006 SWAPP
  *	Andrea Paterniani <a.paterniani@swapp-eng.it>
  * Copyright (C) 2007 David Brownell (simplification, cleanup)
+ * Copyright (C) 2015 Renesas Electronics Corporation
  *
  * 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
@@ -695,6 +696,7 @@
 static const struct of_device_id spidev_dt_ids[] = {
 	{ .compatible = "rohm,dh2228fv" },
 	{ .compatible = "lineartechnology,ltc2488" },
+	{ .compatible = "renesas,sh-msiof" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/staging/board/Makefile b/drivers/staging/board/Makefile
index 6842745..7a6fa98 100644
--- a/drivers/staging/board/Makefile
+++ b/drivers/staging/board/Makefile
@@ -1,3 +1,4 @@
 obj-y	:= board.o
 obj-$(CONFIG_ARCH_EMEV2)	+= kzm9d.o
 obj-$(CONFIG_ARCH_R8A7740)	+= armadillo800eva.o
+obj-$(CONFIG_ARCH_R8A7795)	+= salvator-x.o
diff --git a/drivers/staging/board/salvator-x.c b/drivers/staging/board/salvator-x.c
new file mode 100644
index 0000000..313cc94
--- /dev/null
+++ b/drivers/staging/board/salvator-x.c
@@ -0,0 +1,67 @@
+/*
+ * Staging board support for Salvator-X.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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/kernel.h>
+#include <linux/cma.h>
+#include <linux/dma-contiguous.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include "board.h"
+#include "../../../mm/cma.h"
+
+struct cma *find_largest_nondefault_cma(void)
+{
+	unsigned long largest_size;
+	int k, largest_idx;
+
+	largest_size = 0;
+	largest_idx = -ENOENT;
+
+	for (k = 0; k < cma_area_count; k++) {
+		if (&cma_areas[k] == dma_contiguous_default_area)
+			continue;
+
+		if (cma_get_size(&cma_areas[k]) > largest_size) {
+			largest_size = cma_get_size(&cma_areas[k]);
+			largest_idx = k;
+		}
+	}
+
+	if (largest_idx != -ENOENT)
+		return &cma_areas[largest_idx];
+
+	return NULL;
+}
+
+struct cma *rcar_gen3_dma_contiguous;
+EXPORT_SYMBOL(rcar_gen3_dma_contiguous);
+
+static void __init salvator_x_board_staging_init(void)
+{
+	phys_addr_t cma_base;
+	unsigned long cma_size;
+
+	rcar_gen3_dma_contiguous = find_largest_nondefault_cma();
+
+	if (rcar_gen3_dma_contiguous) {
+		cma_base = cma_get_base(rcar_gen3_dma_contiguous);
+		cma_size = cma_get_size(rcar_gen3_dma_contiguous) / SZ_1M;
+
+		pr_info("%s: Located CMA at %pa, size %ld MiB\n",
+			__func__, &cma_base, cma_size);
+	}
+}
+
+board_staging("renesas,salvator-x", salvator_x_board_staging_init);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 68487c2..4f5a22e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -232,6 +232,16 @@
 	  Enable this to plug the R-Car thermal sensor driver into the Linux
 	  thermal framework.
 
+config RCAR_GEN3_THERMAL
+	tristate "Renesas R-Car Gen3 thermal driver"
+	depends on ARCH_RENESAS || COMPILE_TEST
+	depends on HAS_IOMEM
+	select CPU_THERMAL
+	select THERMAL_GOV_POWER_ALLOCATOR
+	help
+	  Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux
+	  thermal framework.
+
 config KIRKWOOD_THERMAL
 	tristate "Temperature sensor on Marvell Kirkwood SoCs"
 	depends on MACH_KIRKWOOD || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 44736f6..2af1557 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
 obj-$(CONFIG_ROCKCHIP_THERMAL)	+= rockchip_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
+obj-$(CONFIG_RCAR_GEN3_THERMAL)	+= rcar_gen3_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y				+= samsung/
 obj-$(CONFIG_DOVE_THERMAL)  	+= dove_thermal.o
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
new file mode 100644
index 0000000..82abe2d
--- /dev/null
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -0,0 +1,638 @@
+/*
+ *  R-Car Gen3 THS/CIVM thermal sensor driver
+ *  Based on drivers/thermal/rcar_thermal.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation.
+ *
+ *  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; version 2 of the License.
+ *
+ *  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/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+/* Register offset */
+#define REG_GEN3_CTSR		0x20
+#define REG_GEN3_IRQSTR		0x04
+#define REG_GEN3_IRQMSK		0x08
+#define REG_GEN3_IRQCTL		0x0C
+#define REG_GEN3_IRQEN		0x10
+#define REG_GEN3_IRQTEMP1	0x14
+#define REG_GEN3_IRQTEMP2	0x18
+#define REG_GEN3_IRQTEMP3	0x1C
+#define REG_GEN3_TEMP		0x28
+#define REG_GEN3_FTHCODEH	0x48
+#define REG_GEN3_FTHCODET	0x4C
+#define REG_GEN3_FTHCODEL	0x50
+#define REG_GEN3_FPTATH		0x54
+#define REG_GEN3_FPTATT		0x58
+#define REG_GEN3_FPTATL		0x5C
+
+/* CTSR bit */
+#define PONSEQSTOP      (0x1 << 27)
+#define PONM            (0x1 << 8)
+#define AOUT            (0x1 << 7)
+#define THBGR           (0x1 << 5)
+#define VMEN            (0x1 << 4)
+#define VMST            (0x1 << 1)
+#define THSST           (0x1 << 0)
+
+#define CTEMP_MASK	0xFFF
+
+#define POWERON		0
+
+#define MCELSIUS(temp)			((temp) * 1000)
+#define TEMP_IRQ_SHIFT(tsc_id)	(0x1 << tsc_id)
+#define TEMPD_IRQ_SHIFT(tsc_id)	(0x1 << (tsc_id + 3))
+#define GEN3_FUSE_MASK	0xFFF
+
+#define RCAR_H3_WS10		0x4F00
+#define RCAR_H3_WS11		0x4F01
+
+/* Product register */
+#define GEN3_PRR	0xFFF00044
+#define GEN3_PRR_MASK	0x4FFF
+
+/* Quadratic and linear equation config
+ * Default is using quadratic equation.
+ * To switch to linear formula calculation,
+ * please comment out APPLY_QUADRATIC_EQUATION macro.
+*/
+/* #define APPLY_QUADRATIC_EQUATION */
+
+#ifdef APPLY_QUADRATIC_EQUATION
+/* This struct is for quadratic equation.
+ * y = ax^2 + bx + c
+*/
+struct equation_coefs {
+	long a;
+	long b;
+	long c;
+};
+#else
+/* This struct is for linear equation.
+ * y = a1*x + b1
+ * y = a2*x + b2
+*/
+struct equation_coefs {
+	long a1;
+	long b1;
+	long a2;
+	long b2;
+};
+#endif /* APPLY_QUADRATIC_EQUATION  */
+
+struct fuse_factors {
+	int fthcode_h;
+	int fthcode_t;
+	int fthcode_l;
+	int fptat_h;
+	int fptat_t;
+	int fptat_l;
+};
+
+struct rcar_thermal_priv {
+	void __iomem *base;
+	struct device *dev;
+	struct thermal_zone_device *zone;
+	struct delayed_work work;
+	struct fuse_factors factor;
+	struct equation_coefs coef;
+	spinlock_t lock;
+	int id;
+	int irq;
+	u32 ctemp;
+};
+
+#define rcar_priv_to_dev(priv)		((priv)->dev)
+#define rcar_has_irq_support(priv)	((priv)->irq)
+
+/* Temperature calculation  */
+#define CODETSD(x)		((x) * 1000)
+#define TJ_H 96000L
+#define TJ_L (-41000L)
+#define PW2(x) ((x)*(x))
+
+#define rcar_thermal_read(p, r) _rcar_thermal_read(p, r)
+static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
+{
+	return ioread32(priv->base + reg);
+}
+
+#define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, r, d)
+static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
+				u32 reg, u32 data)
+{
+	iowrite32(data, priv->base + reg);
+}
+
+static int round_temp(int temp)
+{
+	int tmp1, tmp2;
+	int result = 0;
+
+	tmp1 = abs(temp) % 1000;
+	tmp2 = abs(temp) / 1000;
+
+	if (tmp1 < 250)
+		result = CODETSD(tmp2);
+	else if (tmp1 < 750 && tmp1 >= 250)
+		result = CODETSD(tmp2) + 500;
+	else
+		result = CODETSD(tmp2) + 1000;
+
+	return ((temp < 0) ? (result * (-1)) : result);
+}
+
+static void thermal_read_fuse_factor(struct rcar_thermal_priv *priv)
+{
+	u32  lsi_id;
+	void __iomem *product_register = ioremap_nocache(GEN3_PRR, 4);
+
+	/* For H3 WS1.0 and H3 WS1.1,
+	 * these registers have not been programmed yet.
+	 * We will use fixed value as temporary solution.
+	 */
+	lsi_id = ioread32(product_register) & GEN3_PRR_MASK;
+	if ((lsi_id != RCAR_H3_WS10) && (lsi_id != RCAR_H3_WS11)) {
+		priv->factor.fthcode_h = rcar_thermal_read(priv,
+						REG_GEN3_FTHCODEH)
+				& GEN3_FUSE_MASK;
+		priv->factor.fthcode_t = rcar_thermal_read(priv,
+						REG_GEN3_FTHCODET)
+				& GEN3_FUSE_MASK;
+		priv->factor.fthcode_l = rcar_thermal_read(priv,
+						REG_GEN3_FTHCODEL)
+				& GEN3_FUSE_MASK;
+		priv->factor.fptat_h = rcar_thermal_read(priv, REG_GEN3_FPTATH)
+				& GEN3_FUSE_MASK;
+		priv->factor.fptat_t = rcar_thermal_read(priv, REG_GEN3_FPTATT)
+				& GEN3_FUSE_MASK;
+		priv->factor.fptat_l = rcar_thermal_read(priv, REG_GEN3_FPTATL)
+				& GEN3_FUSE_MASK;
+	} else {
+		priv->factor.fptat_h = 2351;
+		priv->factor.fptat_t = 1509;
+		priv->factor.fptat_l = 435;
+		switch (priv->id) {
+		case 0:
+			priv->factor.fthcode_h = 3248;
+			priv->factor.fthcode_t = 2800;
+			priv->factor.fthcode_l = 2221;
+			break;
+		case 1:
+			priv->factor.fthcode_h = 3245;
+			priv->factor.fthcode_t = 2795;
+			priv->factor.fthcode_l = 2216;
+			break;
+		case 2:
+			priv->factor.fthcode_h = 3250;
+			priv->factor.fthcode_t = 2805;
+			priv->factor.fthcode_l = 2237;
+			break;
+		}
+	}
+	iounmap(product_register);
+}
+
+#ifdef APPLY_QUADRATIC_EQUATION
+static void _quadratic_coef_calc(struct rcar_thermal_priv *priv)
+{
+	long tj_t = 0;
+	long a, b, c;
+	long num_a, num_a1, num_a2;
+	long den_a, den_a1, den_a2;
+	long num_b1, num_b2, num_b, den_b;
+	long para_c1, para_c2, para_c3;
+
+	tj_t = (CODETSD((priv->factor.fptat_t - priv->factor.fptat_l) * 137)
+		/ (priv->factor.fptat_h - priv->factor.fptat_l)) - CODETSD(41);
+
+	/*
+	 * The following code is to calculate coefficients
+	 * for quadratic equation.
+	 */
+	/* Coefficient a */
+	num_a1 = (CODETSD(priv->factor.fthcode_t)
+			- CODETSD(priv->factor.fthcode_l)) * (TJ_H - TJ_L);
+	num_a2 = (CODETSD(priv->factor.fthcode_h)
+		- CODETSD(priv->factor.fthcode_l)) * (tj_t - TJ_L);
+	num_a = num_a1 - num_a2;
+	den_a1 = (PW2(tj_t) - PW2(TJ_L)) * (TJ_H - TJ_L);
+	den_a2 = (PW2(TJ_H) - PW2(TJ_L)) * (tj_t - TJ_L);
+	den_a = (den_a1 - den_a2) / 1000;
+	a = (100000 * num_a) / den_a;
+
+	/* Coefficient b */
+	num_b1 = (CODETSD(priv->factor.fthcode_t)
+		- CODETSD(priv->factor.fthcode_l))
+			* (TJ_H - TJ_L);
+	num_b2 = ((PW2(tj_t) - PW2(TJ_L)) * (TJ_H - TJ_L) * a) / 1000;
+	num_b = 100000 * num_b1 - num_b2;
+	den_b = ((tj_t - TJ_L) * (TJ_H - TJ_L));
+	b = num_b / den_b;
+
+	/* Coefficient c */
+	para_c1 = 100000 * priv->factor.fthcode_l;
+	para_c2 = (PW2(TJ_L) * a) / PW2(1000);
+	para_c3 = (TJ_L * b) / 1000;
+	c = para_c1 - para_c2 - para_c3;
+
+	priv->coef.a = a;
+	priv->coef.b = b;
+	priv->coef.c = c;
+}
+#else
+static void _linear_coef_calc(struct rcar_thermal_priv *priv)
+{
+	int tj_t = 0;
+	long a1, b1;
+	long a2, b2;
+	long a1_num, a1_den;
+	long a2_num, a2_den;
+
+	tj_t = (CODETSD((priv->factor.fptat_t - priv->factor.fptat_l) * 137)
+		/ (priv->factor.fptat_h - priv->factor.fptat_l)) - CODETSD(41);
+
+	/*
+	 * The following code is to calculate coefficients for linear equation.
+	 */
+	/* Coefficient a1 and b1 */
+	a1_num = CODETSD(priv->factor.fthcode_t - priv->factor.fthcode_l);
+	a1_den = tj_t - TJ_L;
+	a1 = (10000 * a1_num) / a1_den;
+	b1 = (10000 * priv->factor.fthcode_l) - ((a1 * TJ_L) / 1000);
+
+	/* Coefficient a2 and b2 */
+	a2_num = CODETSD(priv->factor.fthcode_t - priv->factor.fthcode_h);
+	a2_den = tj_t - TJ_H;
+	a2 = (10000 * a2_num) / a2_den;
+	b2 = (10000 * priv->factor.fthcode_h) - ((a2 * TJ_H) / 1000);
+
+	priv->coef.a1 = DIV_ROUND_CLOSEST(a1, 10);
+	priv->coef.b1 = DIV_ROUND_CLOSEST(b1, 10);
+	priv->coef.a2 = DIV_ROUND_CLOSEST(a2, 10);
+	priv->coef.b2 = DIV_ROUND_CLOSEST(b2, 10);
+}
+#endif /* APPLY_QUADRATIC_EQUATION */
+
+static void thermal_coefficient_calculation(struct rcar_thermal_priv *priv)
+{
+#ifdef APPLY_QUADRATIC_EQUATION
+	_quadratic_coef_calc(priv);
+#else
+	_linear_coef_calc(priv);
+#endif /* APPLY_QUADRATIC_EQUATION */
+}
+
+#ifdef APPLY_QUADRATIC_EQUATION
+int _quadratic_temp_converter(struct equation_coefs coef, int temp_code)
+{
+	int temp, temp1, temp2;
+	long delta;
+
+	/* Multiply with 100000 to sync with coef a, coef b and coef c. */
+	delta = coef.b * coef.b - 4 * coef.a * (coef.c - 100000 * temp_code);
+
+	/* Multiply temp with 1000 to convert to Mili-Celsius */
+	temp1 = (CODETSD(-coef.b) + int_sqrt(1000000 * delta)) / 2;
+	temp1 = temp1 / coef.a;
+	temp2 = (CODETSD(-coef.b) - int_sqrt(1000000 * delta)) / 2;
+	temp2 = temp2 / coef.a;
+
+	if (temp1 > -45000000)
+		temp = temp1;
+	else
+		temp = temp2;
+
+	return round_temp(temp);
+}
+#else
+int _linear_temp_converter(struct equation_coefs coef,
+					int temp_code)
+{
+	int temp, temp1, temp2;
+
+	temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1;
+	temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2;
+	temp = (temp1 + temp2) / 2;
+
+	return round_temp(temp);
+}
+#endif /* APPLY_QUADRATIC_EQUATION */
+
+int thermal_temp_converter(struct equation_coefs coef,
+					int temp_code)
+{
+	int ctemp = 0;
+#ifdef APPLY_QUADRATIC_EQUATION
+	ctemp = _quadratic_temp_converter(coef, temp_code);
+#else
+	ctemp = _linear_temp_converter(coef, temp_code);
+#endif /* APPLY_QUADRATIC_EQUATION */
+
+	return ctemp;
+}
+
+/*
+ *		Zone device functions
+ */
+static int rcar_gen3_thermal_update_temp(struct rcar_thermal_priv *priv)
+{
+	u32 ctemp;
+	int i;
+	unsigned long flags;
+	u32 reg = REG_GEN3_IRQTEMP1 + (priv->id * 4);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (i = 0; i < 256; i++) {
+		ctemp = rcar_thermal_read(priv, REG_GEN3_TEMP) & CTEMP_MASK;
+		if (rcar_has_irq_support(priv)) {
+			rcar_thermal_write(priv, reg, ctemp);
+			if (rcar_thermal_read(priv, REG_GEN3_IRQSTR) != 0)
+				break;
+		} else
+			break;
+
+		udelay(150);
+	}
+
+	priv->ctemp = ctemp;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
+{
+	struct rcar_thermal_priv *priv = devdata;
+	int ctemp;
+	unsigned long flags;
+
+	rcar_gen3_thermal_update_temp(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ctemp = thermal_temp_converter(priv->coef, priv->ctemp);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if ((ctemp < MCELSIUS(-40)) || (ctemp > MCELSIUS(125))) {
+		struct device *dev = rcar_priv_to_dev(priv);
+
+		dev_err(dev, "Temperature is not measured correclty!\n");
+
+		return -EIO;
+	}
+
+	*temp = ctemp;
+
+	return 0;
+}
+
+static int rcar_gen3_thermal_init(struct rcar_thermal_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rcar_thermal_write(priv, REG_GEN3_CTSR,  0x0);
+
+	rcar_thermal_write(priv, REG_GEN3_CTSR,
+			PONM | AOUT | THBGR | VMEN);
+	udelay(100);
+	rcar_thermal_write(priv, REG_GEN3_CTSR,
+			PONM | AOUT | THBGR | VMEN | VMST | THSST);
+	udelay(1000);
+
+	rcar_thermal_write(priv, REG_GEN3_IRQCTL, 0x3F);
+	rcar_thermal_write(priv, REG_GEN3_IRQEN, TEMP_IRQ_SHIFT(priv->id) |
+						TEMPD_IRQ_SHIFT(priv->id));
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+/*
+ *		Interrupt
+ */
+#define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
+#define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
+static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
+{
+	unsigned long flags;
+
+	if (!rcar_has_irq_support(priv))
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rcar_thermal_write(priv, REG_GEN3_IRQMSK,
+		enable ? (TEMP_IRQ_SHIFT(priv->id) |
+			TEMPD_IRQ_SHIFT(priv->id)) : 0);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void rcar_gen3_thermal_work(struct work_struct *work)
+{
+	struct rcar_thermal_priv *priv;
+
+	priv = container_of(work, struct rcar_thermal_priv, work.work);
+
+	thermal_zone_device_update(priv->zone, THERMAL_DEVICE_EVENT_NONE);
+
+	rcar_thermal_irq_enable(priv);
+}
+
+static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
+{
+	struct rcar_thermal_priv *priv = data;
+	unsigned long flags;
+	int status;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	status = rcar_thermal_read(priv, REG_GEN3_IRQSTR);
+	rcar_thermal_write(priv, REG_GEN3_IRQSTR, 0);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if ((status & TEMP_IRQ_SHIFT(priv->id)) ||
+		(status & TEMPD_IRQ_SHIFT(priv->id))) {
+		rcar_thermal_irq_disable(priv);
+		schedule_delayed_work(&priv->work,
+				      msecs_to_jiffies(300));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
+	.get_temp	= rcar_gen3_thermal_get_temp,
+};
+
+/*
+ *		Platform functions
+ */
+static int rcar_gen3_thermal_remove(struct platform_device *pdev)
+{
+	struct rcar_thermal_priv *priv = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	rcar_thermal_irq_disable(priv);
+	thermal_zone_device_unregister(priv->zone);
+
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+
+	return 0;
+}
+
+static const struct of_device_id rcar_thermal_dt_ids[] = {
+	{ .compatible = "renesas,rcar-gen3-thermal"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
+
+static int rcar_gen3_thermal_probe(struct platform_device *pdev)
+{
+	struct rcar_thermal_priv *priv;
+	struct device *dev = &pdev->dev;
+	struct resource *res, *irq;
+	int ret = -ENODEV;
+	int idle;
+	struct device_node *tz_nd, *tmp_nd;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->dev = dev;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	priv->irq = 0;
+	if (irq) {
+		priv->irq = 1;
+		for_each_node_with_property(tz_nd, "polling-delay") {
+			tmp_nd = of_parse_phandle(tz_nd,
+					"thermal-sensors", 0);
+			if (tmp_nd && !strcmp(tmp_nd->full_name,
+					dev->of_node->full_name)) {
+				of_property_read_u32(tz_nd, "polling-delay",
+					&idle);
+				(idle > 0) ? (priv->irq = 0) :
+						(priv->irq = 1);
+				break;
+			}
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto error_unregister;
+
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base)) {
+		ret = PTR_ERR(priv->base);
+		goto error_unregister;
+	}
+
+	spin_lock_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, rcar_gen3_thermal_work);
+
+	priv->id = of_alias_get_id(dev->of_node, "tsc");
+
+	priv->zone = thermal_zone_of_sensor_register(dev, 0, priv,
+				&rcar_gen3_tz_of_ops);
+
+
+	rcar_gen3_thermal_init(priv);
+	thermal_read_fuse_factor(priv);
+	thermal_coefficient_calculation(priv);
+	ret = rcar_gen3_thermal_update_temp(priv);
+
+	if (ret < 0)
+		goto error_unregister;
+
+	if (IS_ERR(priv->zone)) {
+		dev_err(dev, "Can't register thermal zone\n");
+		ret = PTR_ERR(priv->zone);
+		goto error_unregister;
+	}
+
+	rcar_thermal_irq_enable(priv);
+
+	/* Interrupt */
+	if (irq) {
+		ret = devm_request_irq(dev, irq->start,
+					rcar_gen3_thermal_irq, 0,
+				       dev_name(dev), priv);
+		if (ret) {
+			dev_err(dev, "IRQ request failed\n ");
+			goto error_unregister;
+		}
+	}
+
+	dev_info(dev, "Thermal sensor probed\n");
+
+	return 0;
+
+error_unregister:
+	rcar_gen3_thermal_remove(pdev);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_gen3_thermal_suspend(struct device *dev)
+{
+	/* Empty functino for now */
+	return 0;
+}
+
+static int rcar_gen3_thermal_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops,
+			rcar_gen3_thermal_suspend,
+			rcar_gen3_thermal_resume);
+
+#define DEV_PM_OPS (&rcar_gen3_thermal_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver rcar_gen3_thermal_driver = {
+	.driver	= {
+		.name	= "rcar_gen3_thermal",
+		.pm	= DEV_PM_OPS,
+		.of_match_table = rcar_thermal_dt_ids,
+	},
+	.probe		= rcar_gen3_thermal_probe,
+	.remove		= rcar_gen3_thermal_remove,
+};
+module_platform_driver(rcar_gen3_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("R-Car Gen3 THS/CIVM driver");
+MODULE_AUTHOR("Renesas Electronics Corporation");
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4678d8f..7aa25d4 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1459,8 +1459,7 @@
 
 	dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
 
-	if (!port->dev->of_node &&
-	    (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0))
+	if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
 		return;
 
 	s->cookie_tx = -EINVAL;
@@ -1833,11 +1832,17 @@
 
 static unsigned int sci_get_mctrl(struct uart_port *port)
 {
+	struct sci_port *s = to_sci_port(port);
+	unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
+
 	/*
 	 * CTS/RTS is handled in hardware when supported, while nothing
 	 * else is wired up. Keep it simple and simply assert DSR/CAR.
 	 */
-	return TIOCM_DSR | TIOCM_CAR;
+	if (s->cfg->capabilities & SCIx_HAVE_RTSCTS)
+		mctrl |= TIOCM_CTS;
+
+	return mctrl;
 }
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
@@ -2863,7 +2868,8 @@
 	struct device_node *np = pdev->dev.of_node;
 	const struct of_device_id *match;
 	struct plat_sci_port *p;
-	int id;
+	int id, index;
+	struct of_phandle_args dma_spec;
 
 	if (!IS_ENABLED(CONFIG_OF) || !np)
 		return NULL;
@@ -2889,6 +2895,22 @@
 	p->type = SCI_OF_TYPE(match->data);
 	p->regtype = SCI_OF_REGTYPE(match->data);
 	p->scscr = SCSCR_RE | SCSCR_TE;
+	if (of_property_read_bool(np, "ctsrts"))
+		p->capabilities = SCIx_HAVE_RTSCTS;
+
+	index = of_property_match_string(np, "dma-names", "tx");
+	if (index >= 0)
+		index = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+						   index, &dma_spec);
+	if (index >= 0)
+		p->dma_slave_tx = dma_spec.args[0];
+
+	index = of_property_match_string(np, "dma-names", "rx");
+	if (index >= 0)
+		index = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+						   index, &dma_spec);
+	if (index >= 0)
+		p->dma_slave_rx = dma_spec.args[0];
 
 	return p;
 }
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 770b6b0..afbbaa0 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -1,6 +1,7 @@
 /*
  * xhci-plat.c - xHCI host controller driver platform Bus Glue.
  *
+ * Copyright (C) 2015 Renesas Electronics Corporation
  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
  * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
@@ -39,12 +40,18 @@
 
 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
+	struct usb_hcd *hcd = xhci->main_hcd;
+
 	/*
 	 * As of now platform drivers don't provide MSI support so we ensure
 	 * here that the generic code does not try to make a pci_dev from our
 	 * dev struct in order to setup MSI
 	 */
 	xhci->quirks |= XHCI_PLAT;
+
+	if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
+	    xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
+		xhci->quirks |= XHCI_NO_64BIT;
 }
 
 /* called during probe() after chip reset completes */
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 26a44c0..f652625 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1,6 +1,7 @@
 /*
  * xHCI host controller driver
  *
+ * Copyright (C) 2015 Renesas Electronics Corporation
  * Copyright (C) 2008 Intel Corp.
  *
  * Author: Sarah Sharp
@@ -4945,6 +4946,7 @@
 	/* Set dma_mask and coherent_dma_mask to 64-bits,
 	 * if xHC supports 64-bit addressing */
 	if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+			!(xhci->quirks & XHCI_NO_64BIT) &&
 			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
 		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
 		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 9be7348..04ce102 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2,6 +2,7 @@
 /*
  * xHCI host controller driver
  *
+ * Copyright (C) 2015 Renesas Electronics Corporation
  * Copyright (C) 2008 Intel Corp.
  *
  * Author: Sarah Sharp
@@ -1631,6 +1632,7 @@
 #define XHCI_BROKEN_STREAMS	(1 << 19)
 #define XHCI_PME_STUCK_QUIRK	(1 << 20)
 #define XHCI_MTK_HOST		(1 << 21)
+#define XHCI_NO_64BIT		(1 << 22)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
index 9e47f47..d787d05 100644
--- a/drivers/usb/renesas_usbhs/Makefile
+++ b/drivers/usb/renesas_usbhs/Makefile
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs.o
 
-renesas_usbhs-y			:= common.o mod.o pipe.o fifo.o rcar2.o
+renesas_usbhs-y			:= common.o mod.o pipe.o fifo.o rcar2.o rcar3.o
 
 ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
 	renesas_usbhs-y		+= mod_host.o
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 5af9ca5..baeb7d2 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -25,6 +25,7 @@
 #include <linux/sysfs.h>
 #include "common.h"
 #include "rcar2.h"
+#include "rcar3.h"
 
 /*
  *		image of renesas_usbhs
@@ -477,18 +478,16 @@
 		.data = (void *)USBHS_TYPE_RCAR_GEN2,
 	},
 	{
-		/* Gen3 is compatible with Gen2 */
 		.compatible = "renesas,usbhs-r8a7795",
-		.data = (void *)USBHS_TYPE_RCAR_GEN2,
+		.data = (void *)USBHS_TYPE_RCAR_GEN3,
 	},
 	{
 		.compatible = "renesas,rcar-gen2-usbhs",
 		.data = (void *)USBHS_TYPE_RCAR_GEN2,
 	},
 	{
-		/* Gen3 is compatible with Gen2 */
 		.compatible = "renesas,rcar-gen3-usbhs",
-		.data = (void *)USBHS_TYPE_RCAR_GEN2,
+		.data = (void *)USBHS_TYPE_RCAR_GEN3,
 	},
 	{ },
 };
@@ -578,6 +577,13 @@
 			priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
 		}
 		break;
+	case USBHS_TYPE_RCAR_GEN3:
+		priv->pfunc = usbhs_rcar3_ops;
+		if (!priv->dparam.pipe_configs) {
+			priv->dparam.pipe_configs = usbhsc_new_pipe;
+			priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
+		}
+		break;
 	default:
 		if (!info->platform_callback.get_id) {
 			dev_err(&pdev->dev, "no platform callbacks");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 657f967..664b263 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -561,7 +561,7 @@
 		if (!pkt)
 			break;
 
-		usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);
+		usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ESHUTDOWN);
 	}
 
 	usbhs_pipe_disable(pipe);
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
new file mode 100644
index 0000000..38b01f2
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -0,0 +1,54 @@
+/*
+ * Renesas USB driver R-Car Gen. 3 initialization and power control
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include "common.h"
+#include "rcar3.h"
+
+#define LPSTS		0x102
+#define UGCTRL2		0x184	/* 32-bit register */
+
+/* Low Power Status register (LPSTS) */
+#define LPSTS_SUSPM	0x4000
+
+/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */
+#define UGCTRL2_RESERVED_3	0x00000001	/* bit[3:0] should be B'0001 */
+#define UGCTRL2_USB0SEL_OTG	0x00000030
+
+void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
+{
+	iowrite32(data, priv->base + reg);
+}
+
+static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
+				void __iomem *base, int enable)
+{
+	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+	usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
+
+	if (enable)
+		usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
+	else
+		usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
+
+	return 0;
+}
+
+static int usbhs_rcar3_get_id(struct platform_device *pdev)
+{
+	return USBHS_GADGET;
+}
+
+const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
+	.power_ctrl = usbhs_rcar3_power_ctrl,
+	.get_id = usbhs_rcar3_get_id,
+};
diff --git a/drivers/usb/renesas_usbhs/rcar3.h b/drivers/usb/renesas_usbhs/rcar3.h
new file mode 100644
index 0000000..5f850b2
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rcar3.h
@@ -0,0 +1,3 @@
+#include "common.h"
+
+extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4f0e7be..e698d43 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -636,6 +636,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called atlas7_wdt.
 
+config RENESAS_RWDT
+	tristate "Renesas RWDT Watchdog"
+	depends on ARCH_SHMOBILE || COMPILE_TEST
+	select WATCHDOG_CORE
+	help
+	  This driver adds watchdog support for the integrated watchdog in the
+	  Renesas RCar and other SH Mobile SoCs.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index f566753..1524585 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -72,6 +72,7 @@
 obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
 obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
 obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
+obj-$(CONFIG_RENESAS_RWDT) += renesas_rwdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/renesas_rwdt.c b/drivers/watchdog/renesas_rwdt.c
new file mode 100644
index 0000000..e925eea
--- /dev/null
+++ b/drivers/watchdog/renesas_rwdt.c
@@ -0,0 +1,251 @@
+/*
+ * Watchdog driver for Renesas RWDT watchdog
+ *
+ * Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
+ * Copyright (C) 2015-16 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/pm_runtime.h>
+
+#define RWTCNT		0
+#define RWTCSRA		4
+#define RWTCSRA_WOVF	BIT(4)
+#define RWTCSRA_WRFLG	BIT(5)
+#define RWTCSRA_TME	BIT(7)
+
+#define RWDT_DEFAULT_TIMEOUT 60
+
+static const unsigned clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024 };
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct rwdt_priv {
+	void __iomem *base;
+	struct watchdog_device wdev;
+	struct clk *clk;
+	unsigned clks_per_sec;
+	u8 cks;
+};
+
+static void rwdt_write(struct rwdt_priv *priv, u32 val, unsigned reg)
+{
+	if (reg == RWTCNT)
+		val |= 0x5a5a0000;
+	else
+		val |= 0xa5a5a500;
+
+	writel_relaxed(val, priv->base + reg);
+}
+
+static int rwdt_init_timeout(struct watchdog_device *wdev)
+{
+	struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
+
+	rwdt_write(priv, 65536 - wdev->timeout * priv->clks_per_sec, RWTCNT);
+
+	return 0;
+}
+
+static int rwdt_set_timeout(struct watchdog_device *wdev, unsigned new_timeout)
+{
+	wdev->timeout = new_timeout;
+	rwdt_init_timeout(wdev);
+
+	return 0;
+}
+
+static int rwdt_start(struct watchdog_device *wdev)
+{
+	struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
+
+	pm_runtime_get_sync(wdev->parent);
+
+	rwdt_write(priv, priv->cks, RWTCSRA);
+	rwdt_init_timeout(wdev);
+
+	while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG)
+		cpu_relax();
+
+	rwdt_write(priv, priv->cks | RWTCSRA_TME, RWTCSRA);
+
+	return 0;
+}
+
+static int rwdt_stop(struct watchdog_device *wdev)
+{
+	struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
+
+	rwdt_write(priv, priv->cks, RWTCSRA);
+	pm_runtime_put(wdev->parent);
+
+	return 0;
+}
+
+static int rwdt_restart_handler(struct watchdog_device *wdev)
+{
+	struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
+
+	rwdt_start(wdev);
+	rwdt_write(priv, 0xffff, RWTCNT);
+
+	return 0;
+}
+
+static const struct watchdog_info rwdt_ident = {
+	.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+	.identity = "Renesas RWDT Watchdog",
+};
+
+static const struct watchdog_ops rwdt_ops = {
+	.owner = THIS_MODULE,
+	.start = rwdt_start,
+	.stop = rwdt_stop,
+	.ping = rwdt_init_timeout,
+	.set_timeout = rwdt_set_timeout,
+	.restart = rwdt_restart_handler,
+};
+
+static int rwdt_probe(struct platform_device *pdev)
+{
+	struct rwdt_priv *priv;
+	struct resource *res;
+	unsigned long rate;
+	unsigned clks_per_sec;
+	int ret, i;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	rate = clk_get_rate(priv->clk);
+	if (!rate) {
+		ret = -ENOENT;
+		goto err_clk;
+	}
+
+	for (i = ARRAY_SIZE(clk_divs); i >= 0; i--) {
+		clks_per_sec = rate / clk_divs[i];
+		if (clks_per_sec) {
+			priv->clks_per_sec = clks_per_sec;
+			priv->cks = i;
+			break;
+		}
+	}
+
+	if (!clks_per_sec) {
+		dev_err(&pdev->dev, "Can't find suitable clock divider!\n");
+		ret = -ERANGE;
+		goto err_clk;
+	}
+
+	priv->wdev.info = &rwdt_ident,
+	priv->wdev.ops = &rwdt_ops,
+	priv->wdev.parent = &pdev->dev;
+	priv->wdev.min_timeout = 1;
+	priv->wdev.max_timeout = 65536 / clks_per_sec;
+	priv->wdev.timeout = min_t(unsigned, priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);
+
+	platform_set_drvdata(pdev, priv);
+	watchdog_set_drvdata(&priv->wdev, priv);
+	watchdog_set_nowayout(&priv->wdev, nowayout);
+	watchdog_set_restart_priority(&priv->wdev, 192);
+
+	/* This overrides the default timeout only if DT configuration was found */
+	ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
+	if (ret)
+		dev_warn(&pdev->dev, "Specified timeout value invalid, using default\n");
+
+	ret = watchdog_register_device(&priv->wdev);
+	if (ret < 0)
+		goto err_register;
+
+	pm_runtime_put(&pdev->dev);
+	return 0;
+
+err_register:
+err_clk:
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	return ret;
+}
+
+static int rwdt_remove(struct platform_device *pdev)
+{
+	struct rwdt_priv *priv = platform_get_drvdata(pdev);
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	watchdog_unregister_device(&priv->wdev);
+	return 0;
+}
+
+/*
+ * This driver does also fit for RCar Gen2 (r8a779[0-4]) RWDT. However, for SMP
+ * to work there, one also needs a RESET (RST) driver which does not exist yet
+ * due to HW issues. This needs to be solved before adding compatibles here.
+ */
+static const struct of_device_id rwdt_ids[] = {
+	{ .compatible = "renesas,rwdt-r8a7795", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rwdt_ids);
+
+#ifdef CONFIG_PM_SLEEP
+static int rwdt_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rwdt_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rwdt_pm_ops,
+			rwdt_suspend, rwdt_resume);
+#define DEV_PM_OPS (&rwdt_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver rwdt_driver = {
+	.driver = {
+		.name = "renesas_rwdt",
+		.pm	= DEV_PM_OPS,
+		.of_match_table = rwdt_ids,
+	},
+	.probe = rwdt_probe,
+	.remove = rwdt_remove,
+};
+module_platform_driver(rwdt_driver);
+
+MODULE_DESCRIPTION("Renesas RWDT Watchdog Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bae79f3..3c3442a 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2011 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,6 +26,7 @@
 	IMX6Q_HDMI,
 	IMX6DL_HDMI,
 	RK3288_HDMI,
+	RCAR_HDMI,
 };
 
 struct dw_hdmi_mpll_config {
@@ -40,6 +42,11 @@
 	u16 curr[DW_HDMI_RES_MAX];
 };
 
+struct dw_hdmi_multi_div {
+	unsigned long mpixelclock;
+	u16 multi[DW_HDMI_RES_MAX];
+};
+
 struct dw_hdmi_phy_config {
 	unsigned long mpixelclock;
 	u16 sym_ctr;    /*clock symbol and transmitter control*/
@@ -51,9 +58,11 @@
 	enum dw_hdmi_devtype dev_type;
 	const struct dw_hdmi_mpll_config *mpll_cfg;
 	const struct dw_hdmi_curr_ctrl *cur_ctr;
+	const struct dw_hdmi_multi_div *multi_div;
 	const struct dw_hdmi_phy_config *phy_config;
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
+	u32 index;
 };
 
 void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 24b86d5..30d518d 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -95,11 +95,17 @@
  */
 #define TMIO_MMC_SDIO_STATUS_QUIRK	(1 << 8)
 
+/* The start or stop of SD clock don't wait 10msec. */
+#define TMIO_MMC_CLK_NO_SLEEP		(1 << 9)
+
 /*
  * Some controllers allows to set SDx actual clock
  */
 #define TMIO_MMC_CLK_ACTUAL		(1 << 10)
 
+/* Some controllers have UHS-I sampling clock controller */
+#define TMIO_MMC_HAS_UHS_SCC		(1 << 11)
+
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
@@ -121,6 +127,8 @@
 	unsigned int			cd_gpio;
 	int				alignment_shift;
 	dma_addr_t			dma_rx_offset;
+	unsigned int			max_blk_count;
+	unsigned short			max_segs;
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
 };
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 1839434..5315ff0 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -65,6 +65,33 @@
 	unsigned int delay_us;
 };
 
+#define	regmap_update_bits(map, reg, mask, val) \
+	regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
+#define	regmap_update_bits_async(map, reg, mask, val)\
+	regmap_update_bits_base(map, reg, mask, val, NULL, true, false)
+#define	regmap_update_bits_check(map, reg, mask, val, change)\
+	regmap_update_bits_base(map, reg, mask, val, change, false, false)
+#define	regmap_update_bits_check_async(map, reg, mask, val, change)\
+	regmap_update_bits_base(map, reg, mask, val, change, true, false)
+
+#define	regmap_field_write(field, val) \
+	regmap_field_update_bits_base(field, ~0, val, NULL, false, false)
+#define	regmap_field_force_write(field, val) \
+	regmap_field_update_bits_base(field, ~0, val, NULL, false, true)
+#define	regmap_field_update_bits(field, mask, val)\
+	regmap_field_update_bits_base(field, mask, val, NULL, false, false)
+#define	regmap_field_force_update_bits(field, mask, val) \
+	regmap_field_update_bits_base(field, mask, val, NULL, false, true)
+
+#define	regmap_fields_write(field, id, val) \
+	regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, false)
+#define	regmap_fields_force_write(field, id, val) \
+	regmap_fields_update_bits_base(field, id, ~0, val, NULL, false, true)
+#define	regmap_fields_update_bits(field, id, mask, val)\
+	regmap_fields_update_bits_base(field, id, mask, val, NULL, false, false)
+#define	regmap_fields_force_update_bits(field, id, mask, val) \
+	regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true)
+
 #ifdef CONFIG_REGMAP
 
 enum regmap_endian {
@@ -691,18 +718,9 @@
 		    void *val, size_t val_len);
 int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 		     size_t val_count);
-int regmap_update_bits(struct regmap *map, unsigned int reg,
-		       unsigned int mask, unsigned int val);
-int regmap_write_bits(struct regmap *map, unsigned int reg,
-		       unsigned int mask, unsigned int val);
-int regmap_update_bits_async(struct regmap *map, unsigned int reg,
-			     unsigned int mask, unsigned int val);
-int regmap_update_bits_check(struct regmap *map, unsigned int reg,
-			     unsigned int mask, unsigned int val,
-			     bool *change);
-int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
-				   unsigned int mask, unsigned int val,
-				   bool *change);
+int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+			    unsigned int mask, unsigned int val,
+			    bool *change, bool async, bool force);
 int regmap_get_val_bytes(struct regmap *map);
 int regmap_get_max_register(struct regmap *map);
 int regmap_get_reg_stride(struct regmap *map);
@@ -770,18 +788,14 @@
 void devm_regmap_field_free(struct device *dev,	struct regmap_field *field);
 
 int regmap_field_read(struct regmap_field *field, unsigned int *val);
-int regmap_field_write(struct regmap_field *field, unsigned int val);
-int regmap_field_update_bits(struct regmap_field *field,
-			     unsigned int mask, unsigned int val);
-
-int regmap_fields_write(struct regmap_field *field, unsigned int id,
-			unsigned int val);
-int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
-			unsigned int val);
+int regmap_field_update_bits_base(struct regmap_field *field,
+				  unsigned int mask, unsigned int val,
+				  bool *change, bool async, bool force);
 int regmap_fields_read(struct regmap_field *field, unsigned int id,
 		       unsigned int *val);
-int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
-			      unsigned int mask, unsigned int val);
+int regmap_fields_update_bits_base(struct regmap_field *field,  unsigned int id,
+				   unsigned int mask, unsigned int val,
+				   bool *change, bool async, bool force);
 
 /**
  * Description of an IRQ for the generic regmap irq_chip.
@@ -937,42 +951,26 @@
 	return -EINVAL;
 }
 
-static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
-				     unsigned int mask, unsigned int val)
+static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+					  unsigned int mask, unsigned int val,
+					  bool *change, bool async, bool force)
 {
 	WARN_ONCE(1, "regmap API is disabled");
 	return -EINVAL;
 }
 
-static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
-				     unsigned int mask, unsigned int val)
+static inline int regmap_field_update_bits_base(struct regmap_field *field,
+					unsigned int mask, unsigned int val,
+					bool *change, bool async, bool force)
 {
 	WARN_ONCE(1, "regmap API is disabled");
 	return -EINVAL;
 }
 
-static inline int regmap_update_bits_async(struct regmap *map,
-					   unsigned int reg,
-					   unsigned int mask, unsigned int val)
-{
-	WARN_ONCE(1, "regmap API is disabled");
-	return -EINVAL;
-}
-
-static inline int regmap_update_bits_check(struct regmap *map,
-					   unsigned int reg,
-					   unsigned int mask, unsigned int val,
-					   bool *change)
-{
-	WARN_ONCE(1, "regmap API is disabled");
-	return -EINVAL;
-}
-
-static inline int regmap_update_bits_check_async(struct regmap *map,
-						 unsigned int reg,
-						 unsigned int mask,
-						 unsigned int val,
-						 bool *change)
+static inline int regmap_fields_update_bits_base(struct regmap_field *field,
+				   unsigned int id,
+				   unsigned int mask, unsigned int val,
+				   bool *change, bool async, bool force)
 {
 	WARN_ONCE(1, "regmap API is disabled");
 	return -EINVAL;
diff --git a/include/linux/soc/renesas/rcar_prr.h b/include/linux/soc/renesas/rcar_prr.h
new file mode 100644
index 0000000..59ec0f1
--- /dev/null
+++ b/include/linux/soc/renesas/rcar_prr.h
@@ -0,0 +1,61 @@
+/*
+ * Renesas R-Car Product Register (PRR) helpers
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Gereral Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#ifndef __SOC_RCAR_PRR_H
+#define __SOC_RCAR_PRR_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define PRR				(0xfff00044ul) /* Product Register */
+
+/* PRR PRODUCT for RCAR */
+#define PRR_PRODUCT_RCAR_H3		(0x4f00ul)
+#define PRR_PRODUCT_MASK		(0x7f00ul)
+
+/* PRR PRODUCT and CUT for RCAR */
+#define PRR_PRODUCT_CUT_RCAR_H3_WS10	(PRR_PRODUCT_RCAR_H3   | 0x00ul)
+#define PRR_PRODUCT_CUT_RCAR_H3_WS11	(PRR_PRODUCT_RCAR_H3   | 0x01ul)
+#define PRR_PRODUCT_CUT_MASK		(PRR_PRODUCT_MASK      | 0xfful)
+
+#define RCAR_PRR_INIT()			rcar_prr_init()
+
+#define RCAR_PRR_IS_PRODUCT(a) \
+		rcar_prr_compare_product(PRR_PRODUCT_RCAR_##a)
+
+#define RCAR_PRR_CHK_CUT(a, b) \
+		rcar_prr_check_product_cut(PRR_PRODUCT_CUT_RCAR_##a##_##b)
+
+static u32 rcar_prr = 0xffffffff;
+
+static inline int rcar_prr_compare_product(u32 id)
+{
+	return (rcar_prr & PRR_PRODUCT_MASK) == (id & PRR_PRODUCT_MASK);
+}
+
+static inline int rcar_prr_check_product_cut(u32 id)
+{
+	return (rcar_prr & PRR_PRODUCT_CUT_MASK) - (id & PRR_PRODUCT_CUT_MASK);
+}
+
+static inline int rcar_prr_init(void)
+{
+	void __iomem *reg;
+
+	reg = ioremap(PRR, 0x04);
+	if (!reg)
+		return -ENOMEM;
+
+	rcar_prr = ioread32(reg);
+	iounmap(reg);
+
+	return 0;
+}
+#endif /* __SOC_RCAR_PRR_H */
diff --git a/include/linux/spi/sh_msiof.h b/include/linux/spi/sh_msiof.h
index b087a85..f723aa4 100644
--- a/include/linux/spi/sh_msiof.h
+++ b/include/linux/spi/sh_msiof.h
@@ -1,10 +1,16 @@
 #ifndef __SPI_SH_MSIOF_H__
 #define __SPI_SH_MSIOF_H__
 
+enum {
+	SPI_MSIOF_MASTER,
+	SPI_MSIOF_SLAVE,
+};
+
 struct sh_msiof_spi_info {
 	int tx_fifo_override;
 	int rx_fifo_override;
 	u16 num_chipselect;
+	int mode;
 	unsigned int dma_tx_id;
 	unsigned int dma_rx_id;
 	u32 dtdl;
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index 4db191f..00a47d0 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -184,6 +184,7 @@
 };
 
 #define USBHS_TYPE_RCAR_GEN2	1
+#define USBHS_TYPE_RCAR_GEN3	2
 
 /*
  * option:
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 0e32bc7..ca73c50 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -311,6 +311,7 @@
 
 	__WQ_DRAINING		= 1 << 16, /* internal: workqueue is draining */
 	__WQ_ORDERED		= 1 << 17, /* internal: workqueue is ordered */
+	__WQ_LEGACY		= 1 << 18, /* internal: create*_workqueue() */
 
 	WQ_MAX_ACTIVE		= 512,	  /* I like 512, better ideas? */
 	WQ_MAX_UNBOUND_PER_CPU	= 4,	  /* 4 * #cpus for unbound wq */
@@ -411,12 +412,12 @@
 	alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
 
 #define create_workqueue(name)						\
-	alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))
+	alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
 #define create_freezable_workqueue(name)				\
-	alloc_workqueue("%s", WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, \
-			1, (name))
+	alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND |	\
+			WQ_MEM_RECLAIM, 1, (name))
 #define create_singlethread_workqueue(name)				\
-	alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name)
+	alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
diff --git a/include/media/rcar_csi2.h b/include/media/rcar_csi2.h
new file mode 100644
index 0000000..1a040fa
--- /dev/null
+++ b/include/media/rcar_csi2.h
@@ -0,0 +1,66 @@
+/*
+ * include/media/rcar_csi2.h
+ *     This file is the driver header
+ *     for the Renesas R-Car MIPI CSI-2 unit.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This file is based on the include/media/sh_mobile_csi2.h
+ *
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RCAR_MIPI_CSI
+#define RCAR_MIPI_CSI
+
+#include <linux/list.h>
+
+enum rcar_csi2_phy {
+	RCAR_CSI2_PHY_CSI40,  /* CSI0 */
+	RCAR_CSI2_PHY_CSI20,  /* CSI1 */
+	RCAR_CSI2_PHY_CSI41,  /* CSI2 */
+	RCAR_CSI2_PHY_CSI21,  /* CSI3 */
+};
+
+enum rcar_csi2_link {
+	RCAR_CSI2_LINK_CSI40,
+	RCAR_CSI2_LINK_CSI20,
+	RCAR_CSI2_LINK_CSI41,
+	RCAR_CSI2_LINK_CSI21,
+};
+
+enum rcar_csi2_type {
+	RCAR_CSI2_CSI4X,
+	RCAR_CSI2_CSI2X,
+};
+
+#define RCAR_CSI2_CRC	(1 << 0)
+#define RCAR_CSI2_ECC	(1 << 1)
+
+struct platform_device;
+
+struct rcar_csi2_client_config {
+	enum rcar_csi2_phy phy;
+	enum rcar_csi2_link link;
+	unsigned char lanes;		/* bitmask[3:0] */
+	unsigned char channel;		/* 0..3 */
+	struct platform_device *pdev;	/* client platform device */
+	const char *name;		/* async matching: client name */
+};
+
+struct v4l2_device;
+
+struct rcar_csi2_pdata {
+	enum rcar_csi2_type type;
+	unsigned int flags;
+	struct rcar_csi2_client_config *clients;
+	int num_clients;
+};
+
+#endif
diff --git a/include/media/vsp1.h b/include/media/vsp1.h
index cc54175..a1d4f2a 100644
--- a/include/media/vsp1.h
+++ b/include/media/vsp1.h
@@ -1,7 +1,7 @@
 /*
  * vsp1.h  --  R-Car VSP1 API
  *
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -27,7 +27,8 @@
 int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, u32 pixelformat,
 			  unsigned int pitch, dma_addr_t mem[2],
 			  const struct v4l2_rect *src,
-			  const struct v4l2_rect *dst);
+			  const struct v4l2_rect *dst, u8 alpha);
 int vsp1_du_atomic_flush(struct device *dev);
+int vsp1_du_if_set_mute(struct device *dev, bool on);
 
 #endif /* __MEDIA_VSP1_H__ */
diff --git a/include/uapi/drm/rcar_du_drm.h b/include/uapi/drm/rcar_du_drm.h
new file mode 100644
index 0000000..8ac0296
--- /dev/null
+++ b/include/uapi/drm/rcar_du_drm.h
@@ -0,0 +1,27 @@
+/*
+ * rcar_du_drm.h  --  R-Car Display Unit DRM driver
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * 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.
+ */
+
+#ifndef __RCAR_DU_DRM_H__
+#define __RCAR_DU_DRM_H__
+
+struct rcar_du_vmute {
+	int crtc_id;	/* CRTCs ID */
+	int on;		/* Vmute function ON/OFF */
+};
+
+/* rcar-du + vspd specific ioctls */
+#define DRM_RCAR_DU_SET_VMUTE		0
+
+#define DRM_IOCTL_DRM_RCAR_DU_SET_VMUTE \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RCAR_DU_SET_VMUTE, \
+		struct rcar_du_vmute)
+
+#endif /* __RCAR_DU_DRM_H__ */
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 61a0264..dc7faad 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2355,7 +2355,8 @@
 	WARN_ONCE(current->flags & PF_MEMALLOC,
 		  "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%pf",
 		  current->pid, current->comm, target_wq->name, target_func);
-	WARN_ONCE(worker && (worker->current_pwq->wq->flags & WQ_MEM_RECLAIM),
+	WARN_ONCE(worker && ((worker->current_pwq->wq->flags &
+			      (WQ_MEM_RECLAIM | __WQ_LEGACY)) == WQ_MEM_RECLAIM),
 		  "workqueue: WQ_MEM_RECLAIM %s:%pf is flushing !WQ_MEM_RECLAIM %s:%pf",
 		  worker->current_pwq->wq->name, worker->current_func,
 		  target_wq->name, target_func);
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 647f69d..92b67e2 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -444,7 +444,14 @@
 	return regcache_sync(regmap);
 }
 
+static int ak4613_suspend(struct snd_soc_codec *codec)
+{
+	/* Empty function for now */
+	return 0;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+	.suspend		= ak4613_suspend,
 	.resume			= ak4613_resume,
 	.set_bias_level		= ak4613_set_bias_level,
 	.controls		= ak4613_snd_controls,
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 6d3ef36..d74e1cc 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -518,13 +518,8 @@
 		return -ENOMEM;
 	}
 
-	/*
-	 * ADG is special module.
-	 * Use ADG mod without rsnd_mod_init() to make debug easy
-	 * for rsnd_write/rsnd_read
-	 */
-	adg->mod.ops = &adg_ops;
-	adg->mod.priv = priv;
+	rsnd_mod_init(priv, &adg->mod, &adg_ops,
+		      NULL, NULL, 0, 0);
 
 	rsnd_adg_get_clkin(priv, adg);
 	rsnd_adg_get_clkout(priv, adg);
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index cd1f064..abb5eaa 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -29,7 +29,6 @@
 {
 	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
 	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
-	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	u32 data;
 
@@ -38,6 +37,8 @@
 
 	if (mix) {
 		struct rsnd_dai *rdai;
+		struct rsnd_mod *src;
+		struct rsnd_dai_stream *tio;
 		int i;
 		u32 path[] = {
 			[0] = 0,
@@ -55,16 +56,20 @@
 		 */
 		data = 0;
 		for_each_rsnd_dai(rdai, priv, i) {
-			io = &rdai->playback;
-			if (mix == rsnd_io_to_mod_mix(io))
+			tio = &rdai->playback;
+			src = rsnd_io_to_mod_src(tio);
+			if (mix == rsnd_io_to_mod_mix(tio))
 				data |= path[rsnd_mod_id(src)];
 
-			io = &rdai->capture;
-			if (mix == rsnd_io_to_mod_mix(io))
+			tio = &rdai->capture;
+			src = rsnd_io_to_mod_src(tio);
+			if (mix == rsnd_io_to_mod_mix(tio))
 				data |= path[rsnd_mod_id(src)];
 		}
 
 	} else {
+		struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
 		u32 path[] = {
 			[0] = 0x30000,
 			[1] = 0x30001,
@@ -152,7 +157,8 @@
 
 	for_each_rsnd_cmd(cmd, priv, i) {
 		ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
-				    &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+				    &rsnd_cmd_ops, NULL,
+				    rsnd_mod_get_status, RSND_MOD_CMD, i);
 		if (ret)
 			return ret;
 	}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 02b4b08..d9b98f2 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -138,12 +138,22 @@
 	return mod->ops->dma_req(io, mod);
 }
 
+u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
+			 struct rsnd_mod *mod,
+			 enum rsnd_mod_type type)
+{
+	return &mod->status;
+}
+
 int rsnd_mod_init(struct rsnd_priv *priv,
 		  struct rsnd_mod *mod,
-		   struct rsnd_mod_ops *ops,
-		   struct clk *clk,
-		   enum rsnd_mod_type type,
-		   int id)
+		  struct rsnd_mod_ops *ops,
+		  struct clk *clk,
+		  u32* (*get_status)(struct rsnd_dai_stream *io,
+				     struct rsnd_mod *mod,
+				     enum rsnd_mod_type type),
+		  enum rsnd_mod_type type,
+		  int id)
 {
 	int ret = clk_prepare(clk);
 
@@ -155,6 +165,7 @@
 	mod->type	= type;
 	mod->clk	= clk;
 	mod->priv	= priv;
+	mod->get_status	= get_status;
 
 	return ret;
 }
@@ -163,6 +174,7 @@
 {
 	if (mod->clk)
 		clk_unprepare(mod->clk);
+	mod->clk = NULL;
 }
 
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
@@ -218,7 +230,7 @@
 	int chan = runtime->channels;
 
 	/* Multi channel Mode */
-	if (rsnd_ssi_multi_slaves(io))
+	if (rsnd_ssi_multi_slaves_runtime(io))
 		chan /= rsnd_get_slot_num(io);
 
 	/* TDM Extend Mode needs 8ch */
@@ -324,31 +336,73 @@
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);		\
 	struct rsnd_mod *mod = (io)->mod[idx];			\
 	struct device *dev = rsnd_priv_to_dev(priv);		\
-	u32 *status = (io)->mod_status + idx;			\
+	u32 *status = mod->get_status(io, mod, idx);			\
 	u32 mask = 0xF << __rsnd_mod_shift_##func;			\
 	u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;		\
 	u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);		\
 	int ret = 0;							\
 	int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func;	\
-	*status = (*status & ~mask) +					\
-		(add << __rsnd_mod_shift_##func);			\
+	if (add == 0xF)							\
+		call = 0;						\
+	else								\
+		*status = (*status & ~mask) +				\
+			(add << __rsnd_mod_shift_##func);		\
 	dev_dbg(dev, "%s[%d]\t0x%08x %s\n",				\
 		rsnd_mod_name(mod), rsnd_mod_id(mod),			\
 		*status, call ? #func : "");				\
 	if (call)							\
 		ret = (mod)->ops->func(mod, io, param);			\
+	if (ret)							\
+		dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n",	\
+			rsnd_mod_name(mod), rsnd_mod_id(mod), ret);	\
 	ret;								\
 })
 
+static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
+	{
+		/* CAPTURE */
+		RSND_MOD_AUDMAPP,
+		RSND_MOD_AUDMA,
+		RSND_MOD_DVC,
+		RSND_MOD_MIX,
+		RSND_MOD_CTU,
+		RSND_MOD_CMD,
+		RSND_MOD_SRC,
+		RSND_MOD_SSIU,
+		RSND_MOD_SSIM3,
+		RSND_MOD_SSIM2,
+		RSND_MOD_SSIM1,
+		RSND_MOD_SSIP,
+		RSND_MOD_SSI,
+	}, {
+		/* PLAYBACK */
+		RSND_MOD_AUDMAPP,
+		RSND_MOD_AUDMA,
+		RSND_MOD_SSIM3,
+		RSND_MOD_SSIM2,
+		RSND_MOD_SSIM1,
+		RSND_MOD_SSIP,
+		RSND_MOD_SSI,
+		RSND_MOD_SSIU,
+		RSND_MOD_DVC,
+		RSND_MOD_MIX,
+		RSND_MOD_CTU,
+		RSND_MOD_CMD,
+		RSND_MOD_SRC,
+	},
+};
+
 #define rsnd_dai_call(fn, io, param...)				\
 ({								\
 	struct rsnd_mod *mod;					\
+	int type, is_play = rsnd_io_is_play(io);		\
 	int ret = 0, i;						\
 	for (i = 0; i < RSND_MOD_MAX; i++) {			\
-		mod = (io)->mod[i];				\
+		type = rsnd_mod_sequence[is_play][i];		\
+		mod = (io)->mod[type];				\
 		if (!mod)					\
 			continue;				\
-		ret |= rsnd_mod_call(i, io, fn, param);		\
+		ret |= rsnd_mod_call(type, io, fn, param);	\
 	}							\
 	ret;							\
 })
@@ -363,6 +417,9 @@
 	if (!mod)
 		return -EIO;
 
+	if (io->mod[type] == mod)
+		return 0;
+
 	if (io->mod[type])
 		return -EINVAL;
 
@@ -511,9 +568,16 @@
 		ret = rsnd_dai_call(start, io, priv);
 		if (ret < 0)
 			goto dai_trigger_end;
+
+		ret = rsnd_dai_call(irq, io, priv, 1);
+		if (ret < 0)
+			goto dai_trigger_end;
+
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		ret = rsnd_dai_call(stop, io, priv);
+		ret = rsnd_dai_call(irq, io, priv, 0);
+
+		ret |= rsnd_dai_call(stop, io, priv);
 
 		ret |= rsnd_dai_call(quit, io, priv);
 
@@ -923,7 +987,7 @@
 		     int ch_size,
 		     u32 max)
 {
-	if (ch_size > RSND_DVC_CHANNELS)
+	if (ch_size > RSND_MAX_CHANNELS)
 		return -EINVAL;
 
 	_cfg->cfg.max	= max;
@@ -1169,9 +1233,30 @@
 	return ret;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rsnd_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rsnd_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rsnd_pm_ops,
+			rsnd_suspend, rsnd_resume);
+#define DEV_PM_OPS (&rsnd_pm_ops)
+#else
+#define DEV_PM_OPS NUL
+#endif  /* CONFIG_PM_SLEEP */
+
 static struct platform_driver rsnd_driver = {
 	.driver	= {
 		.name	= "rcar_sound",
+		.pm	= DEV_PM_OPS,
 		.of_match_table = rsnd_of_match,
 	},
 	.probe		= rsnd_probe,
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index d53a225..a10d0f7 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -24,11 +24,17 @@
 	     i++)
 
 #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
-#define rsnd_ctu_initialize_lock(mod)	__rsnd_ctu_initialize_lock(mod, 1)
-#define rsnd_ctu_initialize_unlock(mod)	__rsnd_ctu_initialize_lock(mod, 0)
-static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
+
+static void rsnd_ctu_activation(struct rsnd_mod *mod)
 {
-	rsnd_mod_write(mod, CTU_CTUIR, enable);
+	rsnd_mod_write(mod, CTU_SWRSR, 0);
+	rsnd_mod_write(mod, CTU_SWRSR, 1);
+}
+
+static void rsnd_ctu_halt(struct rsnd_mod *mod)
+{
+	rsnd_mod_write(mod, CTU_CTUIR, 1);
+	rsnd_mod_write(mod, CTU_SWRSR, 0);
 }
 
 static int rsnd_ctu_probe_(struct rsnd_mod *mod,
@@ -38,17 +44,63 @@
 	return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
 }
 
+static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
+			       struct rsnd_mod *mod)
+{
+	rsnd_mod_write(mod, CTU_CTUIR, 1);
+
+	rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
+
+	rsnd_mod_write(mod, CTU_CPMDR, 0);
+	rsnd_mod_write(mod, CTU_SCMDR, 0);
+	rsnd_mod_write(mod, CTU_SV00R, 0);
+	rsnd_mod_write(mod, CTU_SV01R, 0);
+	rsnd_mod_write(mod, CTU_SV02R, 0);
+	rsnd_mod_write(mod, CTU_SV03R, 0);
+	rsnd_mod_write(mod, CTU_SV04R, 0);
+	rsnd_mod_write(mod, CTU_SV05R, 0);
+	rsnd_mod_write(mod, CTU_SV06R, 0);
+	rsnd_mod_write(mod, CTU_SV07R, 0);
+
+	rsnd_mod_write(mod, CTU_SV10R, 0);
+	rsnd_mod_write(mod, CTU_SV11R, 0);
+	rsnd_mod_write(mod, CTU_SV12R, 0);
+	rsnd_mod_write(mod, CTU_SV13R, 0);
+	rsnd_mod_write(mod, CTU_SV14R, 0);
+	rsnd_mod_write(mod, CTU_SV15R, 0);
+	rsnd_mod_write(mod, CTU_SV16R, 0);
+	rsnd_mod_write(mod, CTU_SV17R, 0);
+
+	rsnd_mod_write(mod, CTU_SV20R, 0);
+	rsnd_mod_write(mod, CTU_SV21R, 0);
+	rsnd_mod_write(mod, CTU_SV22R, 0);
+	rsnd_mod_write(mod, CTU_SV23R, 0);
+	rsnd_mod_write(mod, CTU_SV24R, 0);
+	rsnd_mod_write(mod, CTU_SV25R, 0);
+	rsnd_mod_write(mod, CTU_SV26R, 0);
+	rsnd_mod_write(mod, CTU_SV27R, 0);
+
+	rsnd_mod_write(mod, CTU_SV30R, 0);
+	rsnd_mod_write(mod, CTU_SV31R, 0);
+	rsnd_mod_write(mod, CTU_SV32R, 0);
+	rsnd_mod_write(mod, CTU_SV33R, 0);
+	rsnd_mod_write(mod, CTU_SV34R, 0);
+	rsnd_mod_write(mod, CTU_SV35R, 0);
+	rsnd_mod_write(mod, CTU_SV36R, 0);
+	rsnd_mod_write(mod, CTU_SV37R, 0);
+
+	rsnd_mod_write(mod, CTU_CTUIR, 0);
+}
+
 static int rsnd_ctu_init(struct rsnd_mod *mod,
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
 	rsnd_mod_power_on(mod);
 
-	rsnd_ctu_initialize_lock(mod);
+	rsnd_ctu_activation(mod);
 
-	rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
-
-	rsnd_ctu_initialize_unlock(mod);
+	rsnd_ctu_value_init(io, mod);
 
 	return 0;
 }
@@ -57,6 +109,8 @@
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
+	rsnd_ctu_halt(mod);
+
 	rsnd_mod_power_off(mod);
 
 	return 0;
@@ -129,7 +183,7 @@
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
-				    clk, RSND_MOD_CTU, i);
+				    clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
 		if (ret)
 			goto rsnd_ctu_probe_done;
 
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 418e6fd..7658e8f 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -622,15 +622,13 @@
 	}
 }
 
-struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
-				 struct rsnd_mod *mod, int id)
+int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+		    struct rsnd_mod **dma_mod, int id)
 {
-	struct rsnd_mod *dma_mod;
 	struct rsnd_mod *mod_from = NULL;
 	struct rsnd_mod *mod_to = NULL;
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-	struct rsnd_dma *dma;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_mod_ops *ops;
 	enum rsnd_mod_type type;
@@ -646,17 +644,10 @@
 	 *	rsnd_rdai_continuance_probe()
 	 */
 	if (!dmac)
-		return ERR_PTR(-EAGAIN);
-
-	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
-	if (!dma)
-		return ERR_PTR(-ENOMEM);
+		return -EAGAIN;
 
 	rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
 
-	dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
-	dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
-
 	/* for Gen2 */
 	if (mod_from && mod_to) {
 		ops	= &rsnd_dmapp_ops;
@@ -678,27 +669,38 @@
 		type	= RSND_MOD_AUDMA;
 	}
 
-	dma_mod = rsnd_mod_get(dma);
+	if (!(*dma_mod)) {
+		struct rsnd_dma *dma;
 
-	ret = rsnd_mod_init(priv, dma_mod,
-			    ops, NULL, type, dma_id);
+		dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+		if (!dma)
+			return -ENOMEM;
+
+		*dma_mod = rsnd_mod_get(dma);
+
+		dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+		dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
+
+		ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
+				    rsnd_mod_get_status, type, dma_id);
+		if (ret < 0)
+			return ret;
+
+		dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
+			rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
+			rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
+			rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
+
+		ret = attach(io, dma, id, mod_from, mod_to);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rsnd_dai_connect(*dma_mod, io, type);
 	if (ret < 0)
-		return ERR_PTR(ret);
+		return ret;
 
-	dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
-		rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
-		rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
-		rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
-
-	ret = attach(io, dma, id, mod_from, mod_to);
-	if (ret < 0)
-		return ERR_PTR(ret);
-
-	ret = rsnd_dai_connect(dma_mod, io, type);
-	if (ret < 0)
-		return ERR_PTR(ret);
-
-	return rsnd_mod_get(dma);
+	return 0;
 }
 
 int rsnd_dma_probe(struct rsnd_priv *priv)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index d45ffe4..d757f13 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -83,15 +83,15 @@
 					      struct rsnd_mod *mod)
 {
 	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-	u32 val[RSND_DVC_CHANNELS];
+	u32 val[RSND_MAX_CHANNELS];
 	int i;
 
 	/* Enable Ramp */
 	if (dvc->ren.val)
-		for (i = 0; i < RSND_DVC_CHANNELS; i++)
+		for (i = 0; i < RSND_MAX_CHANNELS; i++)
 			val[i] = dvc->volume.cfg.max;
 	else
-		for (i = 0; i < RSND_DVC_CHANNELS; i++)
+		for (i = 0; i < RSND_MAX_CHANNELS; i++)
 			val[i] = dvc->volume.val[i];
 
 	/* Enable Digital Volume */
@@ -373,7 +373,7 @@
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
-			      clk, RSND_MOD_DVC, i);
+				    clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
 		if (ret)
 			goto rsnd_dvc_probe_done;
 
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index ea24247..46c0ba7 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -104,23 +104,6 @@
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
-	regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
-
-	dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod),
-		rsnd_reg_name(gen, reg), reg, data);
-}
-
-void rsnd_force_write(struct rsnd_priv *priv,
-		      struct rsnd_mod *mod,
-		      enum rsnd_reg reg, u32 data)
-{
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-	if (!rsnd_is_accessible_reg(priv, gen, reg))
-		return;
-
 	regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
 
 	dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
@@ -137,8 +120,8 @@
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
-	regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
-				  mask, data);
+	regmap_fields_force_update_bits(gen->regs[reg],
+					rsnd_mod_id(mod), mask, data);
 
 	dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
 		rsnd_mod_name(mod), rsnd_mod_id(mod),
@@ -260,8 +243,43 @@
 		RSND_GEN_M_REG(SRC_SRCCR,	0x224,	0x40),
 		RSND_GEN_M_REG(SRC_BSDSR,	0x22c,	0x40),
 		RSND_GEN_M_REG(SRC_BSISR,	0x238,	0x40),
+		RSND_GEN_M_REG(CTU_SWRSR,	0x500,	0x100),
 		RSND_GEN_M_REG(CTU_CTUIR,	0x504,	0x100),
 		RSND_GEN_M_REG(CTU_ADINR,	0x508,	0x100),
+		RSND_GEN_M_REG(CTU_CPMDR,	0x510,	0x100),
+		RSND_GEN_M_REG(CTU_SCMDR,	0x514,	0x100),
+		RSND_GEN_M_REG(CTU_SV00R,	0x518,	0x100),
+		RSND_GEN_M_REG(CTU_SV01R,	0x51c,	0x100),
+		RSND_GEN_M_REG(CTU_SV02R,	0x520,	0x100),
+		RSND_GEN_M_REG(CTU_SV03R,	0x524,	0x100),
+		RSND_GEN_M_REG(CTU_SV04R,	0x528,	0x100),
+		RSND_GEN_M_REG(CTU_SV05R,	0x52c,	0x100),
+		RSND_GEN_M_REG(CTU_SV06R,	0x530,	0x100),
+		RSND_GEN_M_REG(CTU_SV07R,	0x534,	0x100),
+		RSND_GEN_M_REG(CTU_SV10R,	0x538,	0x100),
+		RSND_GEN_M_REG(CTU_SV11R,	0x53c,	0x100),
+		RSND_GEN_M_REG(CTU_SV12R,	0x540,	0x100),
+		RSND_GEN_M_REG(CTU_SV13R,	0x544,	0x100),
+		RSND_GEN_M_REG(CTU_SV14R,	0x548,	0x100),
+		RSND_GEN_M_REG(CTU_SV15R,	0x54c,	0x100),
+		RSND_GEN_M_REG(CTU_SV16R,	0x550,	0x100),
+		RSND_GEN_M_REG(CTU_SV17R,	0x554,	0x100),
+		RSND_GEN_M_REG(CTU_SV20R,	0x558,	0x100),
+		RSND_GEN_M_REG(CTU_SV21R,	0x55c,	0x100),
+		RSND_GEN_M_REG(CTU_SV22R,	0x560,	0x100),
+		RSND_GEN_M_REG(CTU_SV23R,	0x564,	0x100),
+		RSND_GEN_M_REG(CTU_SV24R,	0x568,	0x100),
+		RSND_GEN_M_REG(CTU_SV25R,	0x56c,	0x100),
+		RSND_GEN_M_REG(CTU_SV26R,	0x570,	0x100),
+		RSND_GEN_M_REG(CTU_SV27R,	0x574,	0x100),
+		RSND_GEN_M_REG(CTU_SV30R,	0x578,	0x100),
+		RSND_GEN_M_REG(CTU_SV31R,	0x57c,	0x100),
+		RSND_GEN_M_REG(CTU_SV32R,	0x580,	0x100),
+		RSND_GEN_M_REG(CTU_SV33R,	0x584,	0x100),
+		RSND_GEN_M_REG(CTU_SV34R,	0x588,	0x100),
+		RSND_GEN_M_REG(CTU_SV35R,	0x58c,	0x100),
+		RSND_GEN_M_REG(CTU_SV36R,	0x590,	0x100),
+		RSND_GEN_M_REG(CTU_SV37R,	0x594,	0x100),
 		RSND_GEN_M_REG(MIX_SWRSR,	0xd00,	0x40),
 		RSND_GEN_M_REG(MIX_MIXIR,	0xd04,	0x40),
 		RSND_GEN_M_REG(MIX_ADINR,	0xd08,	0x40),
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 65542b6..e0e337a 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -172,7 +172,7 @@
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
-				    clk, RSND_MOD_MIX, i);
+				    clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
 		if (ret)
 			goto rsnd_mix_probe_done;
 
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 317dd79..305cc08 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -86,8 +86,43 @@
 	RSND_REG_CMD_BUSIF_DALIGN,	/* Gen2 only */
 	RSND_REG_CMD_ROUTE_SLCT,
 	RSND_REG_CMDOUT_TIMSEL,		/* Gen2 only */
+	RSND_REG_CTU_SWRSR,
 	RSND_REG_CTU_CTUIR,
 	RSND_REG_CTU_ADINR,
+	RSND_REG_CTU_CPMDR,
+	RSND_REG_CTU_SCMDR,
+	RSND_REG_CTU_SV00R,
+	RSND_REG_CTU_SV01R,
+	RSND_REG_CTU_SV02R,
+	RSND_REG_CTU_SV03R,
+	RSND_REG_CTU_SV04R,
+	RSND_REG_CTU_SV05R,
+	RSND_REG_CTU_SV06R,
+	RSND_REG_CTU_SV07R,
+	RSND_REG_CTU_SV10R,
+	RSND_REG_CTU_SV11R,
+	RSND_REG_CTU_SV12R,
+	RSND_REG_CTU_SV13R,
+	RSND_REG_CTU_SV14R,
+	RSND_REG_CTU_SV15R,
+	RSND_REG_CTU_SV16R,
+	RSND_REG_CTU_SV17R,
+	RSND_REG_CTU_SV20R,
+	RSND_REG_CTU_SV21R,
+	RSND_REG_CTU_SV22R,
+	RSND_REG_CTU_SV23R,
+	RSND_REG_CTU_SV24R,
+	RSND_REG_CTU_SV25R,
+	RSND_REG_CTU_SV26R,
+	RSND_REG_CTU_SV27R,
+	RSND_REG_CTU_SV30R,
+	RSND_REG_CTU_SV31R,
+	RSND_REG_CTU_SV32R,
+	RSND_REG_CTU_SV33R,
+	RSND_REG_CTU_SV34R,
+	RSND_REG_CTU_SV35R,
+	RSND_REG_CTU_SV36R,
+	RSND_REG_CTU_SV37R,
 	RSND_REG_MIX_SWRSR,
 	RSND_REG_MIX_MIXIR,
 	RSND_REG_MIX_ADINR,
@@ -147,8 +182,6 @@
 	rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
 #define rsnd_mod_write(m, r, d) \
 	rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
-#define rsnd_mod_force_write(m, r, d) \
-	rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
 #define rsnd_mod_bset(m, r, s, d) \
 	rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
 
@@ -166,8 +199,8 @@
 /*
  *	R-Car DMA
  */
-struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
-			       struct rsnd_mod *mod, int id);
+int rsnd_dma_attach(struct rsnd_dai_stream *io,
+		    struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id);
 int rsnd_dma_probe(struct rsnd_priv *priv);
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
 					  struct rsnd_mod *mod, char *name);
@@ -214,6 +247,9 @@
 	int (*stop)(struct rsnd_mod *mod,
 		    struct rsnd_dai_stream *io,
 		    struct rsnd_priv *priv);
+	int (*irq)(struct rsnd_mod *mod,
+		   struct rsnd_dai_stream *io,
+		   struct rsnd_priv *priv, int enable);
 	int (*pcm_new)(struct rsnd_mod *mod,
 		       struct rsnd_dai_stream *io,
 		       struct snd_soc_pcm_runtime *rtd);
@@ -233,47 +269,54 @@
 	struct rsnd_mod_ops *ops;
 	struct rsnd_priv *priv;
 	struct clk *clk;
+	u32 *(*get_status)(struct rsnd_dai_stream *io,
+			   struct rsnd_mod *mod,
+			   enum rsnd_mod_type type);
+	u32 status;
 };
 /*
  * status
  *
- * 0xH0000CBA
+ * 0xH0000CB0
  *
- * A	0: probe	1: remove
  * B	0: init		1: quit
  * C	0: start	1: stop
  *
  * H is always called (see __rsnd_mod_call)
+ * H	0: probe	1: remove
  * H	0: pcm_new
  * H	0: fallback
  * H	0: hw_params
  */
-#define __rsnd_mod_shift_probe		0
-#define __rsnd_mod_shift_remove		0
 #define __rsnd_mod_shift_init		4
 #define __rsnd_mod_shift_quit		4
 #define __rsnd_mod_shift_start		8
 #define __rsnd_mod_shift_stop		8
+#define __rsnd_mod_shift_probe		28 /* always called */
+#define __rsnd_mod_shift_remove		28 /* always called */
+#define __rsnd_mod_shift_irq		28 /* always called */
 #define __rsnd_mod_shift_pcm_new	28 /* always called */
 #define __rsnd_mod_shift_fallback	28 /* always called */
 #define __rsnd_mod_shift_hw_params	28 /* always called */
 
-#define __rsnd_mod_add_probe		 1
-#define __rsnd_mod_add_remove		-1
+#define __rsnd_mod_add_probe		0
+#define __rsnd_mod_add_remove		0
 #define __rsnd_mod_add_init		 1
 #define __rsnd_mod_add_quit		-1
 #define __rsnd_mod_add_start		 1
 #define __rsnd_mod_add_stop		-1
+#define __rsnd_mod_add_irq		0
 #define __rsnd_mod_add_pcm_new		0
 #define __rsnd_mod_add_fallback		0
 #define __rsnd_mod_add_hw_params	0
 
 #define __rsnd_mod_call_probe		0
-#define __rsnd_mod_call_remove		1
+#define __rsnd_mod_call_remove		0
 #define __rsnd_mod_call_init		0
 #define __rsnd_mod_call_quit		1
 #define __rsnd_mod_call_start		0
 #define __rsnd_mod_call_stop		1
+#define __rsnd_mod_call_irq		0
 #define __rsnd_mod_call_pcm_new		0
 #define __rsnd_mod_call_fallback	0
 #define __rsnd_mod_call_hw_params	0
@@ -286,10 +329,13 @@
 
 int rsnd_mod_init(struct rsnd_priv *priv,
 		  struct rsnd_mod *mod,
-		   struct rsnd_mod_ops *ops,
-		   struct clk *clk,
-		   enum rsnd_mod_type type,
-		   int id);
+		  struct rsnd_mod_ops *ops,
+		  struct clk *clk,
+		  u32* (*get_status)(struct rsnd_dai_stream *io,
+				     struct rsnd_mod *mod,
+				     enum rsnd_mod_type type),
+		  enum rsnd_mod_type type,
+		  int id);
 void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
 struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
@@ -297,6 +343,10 @@
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
 			void (*callback)(struct rsnd_mod *mod,
 					 struct rsnd_dai_stream *io));
+u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
+			 struct rsnd_mod *mod,
+			 enum rsnd_mod_type type);
+
 void rsnd_parse_connect_common(struct rsnd_dai *rdai,
 		struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
 		struct device_node *node,
@@ -319,7 +369,7 @@
 	struct rsnd_mod *mod[RSND_MOD_MAX];
 	struct rsnd_dai_path_info *info; /* rcar_snd.h */
 	struct rsnd_dai *rdai;
-	u32 mod_status[RSND_MOD_MAX];
+	u32 parent_ssi_status;
 	int byte_pos;
 	int period_pos;
 	int byte_per_period;
@@ -498,10 +548,10 @@
 	struct snd_kcontrol *kctrl;
 };
 
-#define RSND_DVC_CHANNELS	8
+#define RSND_MAX_CHANNELS	8
 struct rsnd_kctrl_cfg_m {
 	struct rsnd_kctrl_cfg cfg;
-	u32 val[RSND_DVC_CHANNELS];
+	u32 val[RSND_MAX_CHANNELS];
 };
 
 struct rsnd_kctrl_cfg_s {
@@ -547,7 +597,7 @@
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io);
+u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
 
 #define rsnd_ssi_is_pin_sharing(io)	\
 	__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 5eda056..03c6314 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -25,7 +25,6 @@
 	struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
 	struct rsnd_kctrl_cfg_s sync; /* sync convert */
 	u32 convert_rate; /* sampling rate convert */
-	int err;
 	int irq;
 };
 
@@ -250,6 +249,8 @@
 		break;
 	}
 
+	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+
 	rsnd_mod_write(mod, SRC_SRCIR, 1);	/* initialize */
 	rsnd_mod_write(mod, SRC_ADINR, adinr);
 	rsnd_mod_write(mod, SRC_IFSCR, ifscr);
@@ -259,7 +260,6 @@
 	rsnd_mod_write(mod, SRC_BSISR, bsisr);
 	rsnd_mod_write(mod, SRC_SRCIR, 0);	/* cancel initialize */
 
-	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
 	rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
 	rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
 	rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
@@ -272,9 +272,10 @@
 		rsnd_adg_set_convert_timing_gen2(mod, io);
 }
 
-#define rsnd_src_irq_enable(mod)  rsnd_src_irq_ctrol(mod, 1)
-#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0)
-static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable)
+static int rsnd_src_irq(struct rsnd_mod *mod,
+			struct rsnd_dai_stream *io,
+			struct rsnd_priv *priv,
+			int enable)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 sys_int_val, int_val, sys_int_mask;
@@ -306,6 +307,8 @@
 	rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
 	rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
 	rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
+
+	return 0;
 }
 
 static void rsnd_src_status_clear(struct rsnd_mod *mod)
@@ -316,7 +319,7 @@
 	rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
 }
 
-static bool rsnd_src_record_error(struct rsnd_mod *mod)
+static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 val0, val1;
@@ -333,12 +336,8 @@
 		val0 = val0 & 0xffff;
 
 	if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
-	    (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) {
-		struct rsnd_src *src = rsnd_mod_to_src(mod);
-
-		src->err++;
+	    (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1))
 		ret = true;
-	}
 
 	return ret;
 }
@@ -367,11 +366,7 @@
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
-	/*
-	 * stop SRC output only
-	 * see rsnd_src_quit
-	 */
-	rsnd_mod_write(mod, SRC_CTRL, 0x01);
+	rsnd_mod_write(mod, SRC_CTRL, 0);
 
 	return 0;
 }
@@ -390,10 +385,6 @@
 
 	rsnd_src_status_clear(mod);
 
-	rsnd_src_irq_enable(mod);
-
-	src->err = 0;
-
 	/* reset sync convert_rate */
 	src->sync.val = 0;
 
@@ -405,21 +396,11 @@
 			 struct rsnd_priv *priv)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
-
-	rsnd_src_irq_disable(mod);
-
-	/* stop both out/in */
-	rsnd_mod_write(mod, SRC_CTRL, 0);
 
 	rsnd_src_halt(mod);
 
 	rsnd_mod_power_off(mod);
 
-	if (src->err)
-		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-			 rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-
 	src->convert_rate = 0;
 
 	/* reset sync convert_rate */
@@ -432,8 +413,7 @@
 				 struct rsnd_dai_stream *io)
 {
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
+	bool stop = false;
 
 	spin_lock(&priv->lock);
 
@@ -441,26 +421,16 @@
 	if (!rsnd_io_is_working(io))
 		goto rsnd_src_interrupt_out;
 
-	if (rsnd_src_record_error(mod)) {
-
-		dev_dbg(dev, "%s[%d] restart\n",
-			rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-		rsnd_src_stop(mod, io, priv);
-		rsnd_src_start(mod, io, priv);
-	}
-
-	if (src->err > 1024) {
-		rsnd_src_irq_disable(mod);
-
-		dev_warn(dev, "no more %s[%d] restart\n",
-			 rsnd_mod_name(mod), rsnd_mod_id(mod));
-	}
+	if (rsnd_src_error_occurred(mod))
+		stop = true;
 
 	rsnd_src_status_clear(mod);
 rsnd_src_interrupt_out:
 
 	spin_unlock(&priv->lock);
+
+	if (stop)
+		snd_pcm_stop_xrun(io->substream);
 }
 
 static irqreturn_t rsnd_src_interrupt(int irq, void *data)
@@ -485,7 +455,7 @@
 		/*
 		 * IRQ is not supported on non-DT
 		 * see
-		 *	rsnd_src_irq_enable()
+		 *	rsnd_src_irq()
 		 */
 		ret = devm_request_irq(dev, irq,
 				       rsnd_src_interrupt,
@@ -495,9 +465,7 @@
 			return ret;
 	}
 
-	src->dma = rsnd_dma_attach(io, mod, 0);
-	if (IS_ERR(src->dma))
-		return PTR_ERR(src->dma);
+	ret = rsnd_dma_attach(io, mod, &src->dma, 0);
 
 	return ret;
 }
@@ -557,6 +525,7 @@
 	.quit	= rsnd_src_quit,
 	.start	= rsnd_src_start,
 	.stop	= rsnd_src_stop,
+	.irq	= rsnd_src_irq,
 	.hw_params = rsnd_src_hw_params,
 	.pcm_new = rsnd_src_pcm_new,
 };
@@ -622,7 +591,8 @@
 		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(src),
-				    &rsnd_src_ops, clk, RSND_MOD_SRC, i);
+				    &rsnd_src_ops, clk, rsnd_mod_get_status,
+				    RSND_MOD_SRC, i);
 		if (ret)
 			goto rsnd_src_probe_done;
 
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 7ee89da..0979db8 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -64,7 +64,6 @@
 #define SSI_NAME "ssi"
 
 struct rsnd_ssi {
-	struct rsnd_ssi *parent;
 	struct rsnd_mod mod;
 	struct rsnd_mod *dma;
 
@@ -75,7 +74,6 @@
 	u32 wsr;
 	int chan;
 	int rate;
-	int err;
 	int irq;
 	unsigned int usrcnt;
 };
@@ -96,7 +94,10 @@
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
 #define rsnd_ssi_mode_flags(p) ((p)->flags)
 #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
-#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io))
+#define rsnd_ssi_is_multi_slave(mod, io) \
+	(rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_is_run_mods(mod, io) \
+	(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
 
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 {
@@ -141,43 +142,13 @@
 		udelay(50);
 	}
 
-	dev_warn(dev, "status check failed\n");
+	dev_warn(dev, "%s[%d] status check failed\n",
+		 rsnd_mod_name(mod), rsnd_mod_id(mod));
 }
 
-static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod)
-{
-	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	/* enable SSI interrupt if Gen2 */
-	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
-		       rsnd_ssi_is_dma_mode(ssi_mod) ?
-		       0x0e000000 : 0x0f000000);
-
-	return 0;
-}
-
-static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod)
-{
-	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	/* disable SSI interrupt if Gen2 */
-	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
-
-	return 0;
-}
-
-u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
+static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
 {
 	struct rsnd_mod *mod;
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	struct rsnd_priv *priv = rsnd_io_to_priv(io);
-	struct device *dev = rsnd_priv_to_dev(priv);
 	enum rsnd_mod_type types[] = {
 		RSND_MOD_SSIM1,
 		RSND_MOD_SSIM2,
@@ -185,16 +156,6 @@
 	};
 	int i, mask;
 
-	switch (runtime->channels) {
-	case 2: /* Multi channel is not needed for Stereo */
-		return 0;
-	case 6:
-		break;
-	default:
-		dev_err(dev, "unsupported channel\n");
-		return 0;
-	}
-
 	mask = 0;
 	for (i = 0; i < ARRAY_SIZE(types); i++) {
 		mod = rsnd_io_to_mod(io, types[i]);
@@ -207,14 +168,35 @@
 	return mask;
 }
 
-static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
+{
+	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+
+	return rsnd_ssi_multi_slaves_runtime(io) |
+		1 << rsnd_mod_id(ssi_mod) |
+		1 << rsnd_mod_id(ssi_parent_mod);
+}
+
+u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
+{
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	u32 mask = rsnd_ssi_multi_slaves(io);
+
+	if (mask && (runtime->channels >= 6))
+		return mask;
+
+	return 0;
+}
+
+static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
 				     struct rsnd_dai_stream *io)
 {
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 	int slots = rsnd_get_slot_width(io);
 	int j, ret;
@@ -274,11 +256,11 @@
 	return -EIO;
 }
 
-static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi,
+static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
 				     struct rsnd_dai_stream *io)
 {
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 
 	if (!rsnd_rdai_is_clk_master(rdai))
@@ -296,11 +278,12 @@
 	rsnd_adg_ssi_clk_stop(mod);
 }
 
-static int rsnd_ssi_config_init(struct rsnd_ssi *ssi,
+static void rsnd_ssi_config_init(struct rsnd_mod *mod,
 				struct rsnd_dai_stream *io)
 {
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	u32 cr_own;
 	u32 cr_mode;
 	u32 wsr;
@@ -332,11 +315,9 @@
 	case 32:
 		cr_own |= DWL_24;
 		break;
-	default:
-		return -EINVAL;
 	}
 
-	if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) {
+	if (rsnd_ssi_is_dma_mode(mod)) {
 		cr_mode = UIEN | OIEN |	/* over/under run */
 			  DMEN;		/* DMA : enable DMA */
 	} else {
@@ -357,8 +338,16 @@
 	ssi->cr_own	= cr_own;
 	ssi->cr_mode	= cr_mode;
 	ssi->wsr	= wsr;
+}
 
-	return 0;
+static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+	rsnd_mod_write(mod, SSIWSR,	ssi->wsr);
+	rsnd_mod_write(mod, SSICR,	ssi->cr_own	|
+					ssi->cr_clk	|
+					ssi->cr_mode); /* without EN */
 }
 
 /*
@@ -371,28 +360,25 @@
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	int ret;
 
+	if (!rsnd_ssi_is_run_mods(mod, io))
+		return 0;
+
 	ssi->usrcnt++;
 
 	rsnd_mod_power_on(mod);
 
-	ret = rsnd_ssi_master_clk_start(ssi, io);
+	ret = rsnd_ssi_master_clk_start(mod, io);
 	if (ret < 0)
 		return ret;
 
-	if (rsnd_ssi_is_parent(mod, io))
-		return 0;
+	if (!rsnd_ssi_is_parent(mod, io))
+		rsnd_ssi_config_init(mod, io);
 
-	ret = rsnd_ssi_config_init(ssi, io);
-	if (ret < 0)
-		return ret;
-
-	ssi->err	= -1; /* ignore 1st error */
+	rsnd_ssi_register_setup(mod);
 
 	/* clear error status */
 	rsnd_ssi_status_clear(mod);
 
-	rsnd_ssi_irq_enable(mod);
-
 	return 0;
 }
 
@@ -403,25 +389,19 @@
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct device *dev = rsnd_priv_to_dev(priv);
 
+	if (!rsnd_ssi_is_run_mods(mod, io))
+		return 0;
+
 	if (!ssi->usrcnt) {
 		dev_err(dev, "%s[%d] usrcnt error\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
 		return -EIO;
 	}
 
-	if (!rsnd_ssi_is_parent(mod, io)) {
-		if (ssi->err > 0)
-			dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-				 rsnd_mod_name(mod), rsnd_mod_id(mod),
-				 ssi->err);
-
+	if (!rsnd_ssi_is_parent(mod, io))
 		ssi->cr_own	= 0;
-		ssi->err	= 0;
 
-		rsnd_ssi_irq_disable(mod);
-	}
-
-	rsnd_ssi_master_clk_stop(ssi, io);
+	rsnd_ssi_master_clk_stop(mod, io);
 
 	rsnd_mod_power_off(mod);
 
@@ -456,62 +436,44 @@
 	return 0;
 }
 
-static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
+static int rsnd_ssi_start(struct rsnd_mod *mod,
+			  struct rsnd_dai_stream *io,
+			  struct rsnd_priv *priv)
 {
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
-	u32 status = rsnd_ssi_status_get(mod);
-
-	/* under/over flow error */
-	if (status & (UIRQ | OIRQ))
-		ssi->err++;
-
-	return status;
-}
-
-static int __rsnd_ssi_start(struct rsnd_mod *mod,
-			    struct rsnd_dai_stream *io,
-			    struct rsnd_priv *priv)
-{
-	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	u32 cr;
-
-	cr  =	ssi->cr_own	|
-		ssi->cr_clk	|
-		ssi->cr_mode;
+	if (!rsnd_ssi_is_run_mods(mod, io))
+		return 0;
 
 	/*
 	 * EN will be set via SSIU :: SSI_CONTROL
 	 * if Multi channel mode
 	 */
-	if (!rsnd_ssi_multi_slaves(io))
-		cr |= EN;
+	if (rsnd_ssi_multi_slaves_runtime(io))
+		return 0;
 
-	rsnd_mod_write(mod, SSICR, cr);
-	rsnd_mod_write(mod, SSIWSR, ssi->wsr);
+	rsnd_mod_bset(mod, SSICR, EN, EN);
 
 	return 0;
 }
 
-static int rsnd_ssi_start(struct rsnd_mod *mod,
-			  struct rsnd_dai_stream *io,
-			  struct rsnd_priv *priv)
-{
-	/*
-	 * no limit to start
-	 * see also
-	 *	rsnd_ssi_stop
-	 *	rsnd_ssi_interrupt
-	 */
-	return __rsnd_ssi_start(mod, io, priv);
-}
-
-static int __rsnd_ssi_stop(struct rsnd_mod *mod,
-			   struct rsnd_dai_stream *io,
-			   struct rsnd_priv *priv)
+static int rsnd_ssi_stop(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	u32 cr;
 
+	if (!rsnd_ssi_is_run_mods(mod, io))
+		return 0;
+
+	/*
+	 * don't stop if not last user
+	 * see also
+	 *	rsnd_ssi_start
+	 *	rsnd_ssi_interrupt
+	 */
+	if (ssi->usrcnt > 1)
+		return 0;
+
 	/*
 	 * disable all IRQ,
 	 * and, wait all data was sent
@@ -532,33 +494,38 @@
 	return 0;
 }
 
-static int rsnd_ssi_stop(struct rsnd_mod *mod,
-			 struct rsnd_dai_stream *io,
-			 struct rsnd_priv *priv)
+static int rsnd_ssi_irq(struct rsnd_mod *mod,
+			struct rsnd_dai_stream *io,
+			struct rsnd_priv *priv,
+			int enable)
 {
-	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	u32 val = 0;
 
-	/*
-	 * don't stop if not last user
-	 * see also
-	 *	rsnd_ssi_start
-	 *	rsnd_ssi_interrupt
-	 */
-	if (ssi->usrcnt > 1)
+	if (rsnd_is_gen1(priv))
 		return 0;
 
-	return __rsnd_ssi_stop(mod, io, priv);
+	if (rsnd_ssi_is_parent(mod, io))
+		return 0;
+
+	if (!rsnd_ssi_is_run_mods(mod, io))
+		return 0;
+
+	if (enable)
+		val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
+
+	rsnd_mod_write(mod, SSI_INT_ENABLE, val);
+
+	return 0;
 }
 
 static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 				 struct rsnd_dai_stream *io)
 {
-	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
 	int is_dma = rsnd_ssi_is_dma_mode(mod);
 	u32 status;
 	bool elapsed = false;
+	bool stop = false;
 
 	spin_lock(&priv->lock);
 
@@ -566,7 +533,7 @@
 	if (!rsnd_io_is_working(io))
 		goto rsnd_ssi_interrupt_out;
 
-	status = rsnd_ssi_record_error(ssi);
+	status = rsnd_ssi_status_get(mod);
 
 	/* PIO only */
 	if (!is_dma && (status & DIRQ)) {
@@ -588,23 +555,8 @@
 	}
 
 	/* DMA only */
-	if (is_dma && (status & (UIRQ | OIRQ))) {
-		/*
-		 * restart SSI
-		 */
-		dev_dbg(dev, "%s[%d] restart\n",
-			rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-		__rsnd_ssi_stop(mod, io, priv);
-		__rsnd_ssi_start(mod, io, priv);
-	}
-
-	if (ssi->err > 1024) {
-		rsnd_ssi_irq_disable(mod);
-
-		dev_warn(dev, "no more %s[%d] restart\n",
-			 rsnd_mod_name(mod), rsnd_mod_id(mod));
-	}
+	if (is_dma && (status & (UIRQ | OIRQ)))
+		stop = true;
 
 	rsnd_ssi_status_clear(mod);
 rsnd_ssi_interrupt_out:
@@ -612,6 +564,10 @@
 
 	if (elapsed)
 		rsnd_dai_period_elapsed(io);
+
+	if (stop)
+		snd_pcm_stop_xrun(io->substream);
+
 }
 
 static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
@@ -627,12 +583,17 @@
  *		SSI PIO
  */
 static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
-				   struct rsnd_dai_stream *io,
-				   struct rsnd_priv *priv)
+				   struct rsnd_dai_stream *io)
 {
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
 	if (!__rsnd_ssi_is_pin_sharing(mod))
 		return;
 
+	if (!rsnd_rdai_is_clk_master(rdai))
+		return;
+
 	switch (rsnd_mod_id(mod)) {
 	case 1:
 	case 2:
@@ -647,6 +608,20 @@
 	}
 }
 
+static int rsnd_ssi_pcm_new(struct rsnd_mod *mod,
+			    struct rsnd_dai_stream *io,
+			    struct snd_soc_pcm_runtime *rtd)
+{
+	/*
+	 * rsnd_rdai_is_clk_master() will be enabled after set_fmt,
+	 * and, pcm_new will be called after it.
+	 * This function reuse pcm_new at this point.
+	 */
+	rsnd_ssi_parent_attach(mod, io);
+
+	return 0;
+}
+
 static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
 				 struct rsnd_dai_stream *io,
 				 struct rsnd_priv *priv)
@@ -662,7 +637,10 @@
 	if (rsnd_ssi_is_multi_slave(mod, io))
 		return 0;
 
-	rsnd_ssi_parent_attach(mod, io, priv);
+	/*
+	 * It can't judge ssi parent at this point
+	 * see rsnd_ssi_pcm_new()
+	 */
 
 	ret = rsnd_ssiu_attach(io, mod);
 	if (ret < 0)
@@ -683,6 +661,8 @@
 	.quit	= rsnd_ssi_quit,
 	.start	= rsnd_ssi_start,
 	.stop	= rsnd_ssi_stop,
+	.irq	= rsnd_ssi_irq,
+	.pcm_new = rsnd_ssi_pcm_new,
 	.hw_params = rsnd_ssi_hw_params,
 };
 
@@ -705,9 +685,8 @@
 	if (ret)
 		return ret;
 
-	ssi->dma = rsnd_dma_attach(io, mod, dma_id);
-	if (IS_ERR(ssi->dma))
-		return PTR_ERR(ssi->dma);
+	/* SSI probe might be called many times in MUX multi path */
+	ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id);
 
 	return ret;
 }
@@ -772,6 +751,8 @@
 	.quit	= rsnd_ssi_quit,
 	.start	= rsnd_ssi_start,
 	.stop	= rsnd_ssi_stop,
+	.irq	= rsnd_ssi_irq,
+	.pcm_new = rsnd_ssi_pcm_new,
 	.fallback = rsnd_ssi_fallback,
 	.hw_params = rsnd_ssi_hw_params,
 };
@@ -858,6 +839,41 @@
 	return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
 }
 
+static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
+				struct rsnd_mod *mod,
+				enum rsnd_mod_type type)
+{
+	/*
+	 * SSIP (= SSI parent) needs to be special, otherwise,
+	 * 2nd SSI might doesn't start. see also rsnd_mod_call()
+	 *
+	 * We can't include parent SSI status on SSI, because we don't know
+	 * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+	 * ex) trouble case
+	 *	Playback: SSI0
+	 *	Capture : SSI1 (needs SSI0)
+	 *
+	 * 1) start Capture  ->	SSI0/SSI1 are started.
+	 * 2) start Playback ->	SSI0 doesn't work, because it is already
+	 *			marked as "started" on 1)
+	 *
+	 * OTOH, using each mod's status is good for MUX case.
+	 * It doesn't need to start in 2nd start
+	 * ex)
+	 *	IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+	 *			    |
+	 *	IO-1: SRC1 -> CTU2 -+
+	 *
+	 * 1) start IO-0 ->	start SSI0
+	 * 2) start IO-1 ->	SSI0 doesn't need to start, because it is
+	 *			already started on 1)
+	 */
+	if (type == RSND_MOD_SSIP)
+		return &io->parent_ssi_status;
+
+	return rsnd_mod_get_status(io, mod, type);
+}
+
 int rsnd_ssi_probe(struct rsnd_priv *priv)
 {
 	struct device_node *node;
@@ -920,7 +936,7 @@
 			ops = &rsnd_ssi_dma_ops;
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
-				    RSND_MOD_SSI, i);
+				    rsnd_ssi_get_status, RSND_MOD_SSI, i);
 		if (ret)
 			goto rsnd_ssi_probe_done;
 
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 06d7282..1b8ea0e 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -27,7 +27,7 @@
 			  struct rsnd_priv *priv)
 {
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io);
+	u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io);
 	int use_busif = rsnd_ssi_use_busif(io);
 	int id = rsnd_mod_id(mod);
 	u32 mask1, val1;
@@ -136,7 +136,7 @@
 
 	rsnd_mod_write(mod, SSI_CTRL, 0x1);
 
-	if (rsnd_ssi_multi_slaves(io))
+	if (rsnd_ssi_multi_slaves_runtime(io))
 		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
 
 	return 0;
@@ -151,7 +151,7 @@
 
 	rsnd_mod_write(mod, SSI_CTRL, 0);
 
-	if (rsnd_ssi_multi_slaves(io))
+	if (rsnd_ssi_multi_slaves_runtime(io))
 		rsnd_mod_write(mod, SSI_CONTROL, 0);
 
 	return 0;
@@ -206,7 +206,8 @@
 
 	for_each_rsnd_ssiu(ssiu, priv, i) {
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
-				    ops, NULL, RSND_MOD_SSIU, i);
+				    ops, NULL, rsnd_mod_get_status,
+				    RSND_MOD_SSIU, i);
 		if (ret)
 			return ret;
 	}