aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter')
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0002-Porter-adapt-max9272-ov10635-driver-for-porter-exp-b.patch60
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0003-Porter-add-LVDS-camera.patch88
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0004-GPIO-CPLD-gpio-extender-driver.patch248
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0012-regmap-Implemented-default-cache-sync-operation.patch102
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0013-regmap-cache-Don-t-attempt-to-sync-non-writeable-reg.patch34
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0014-ASoC-Add-SOC_DOUBLE_STS-macro.patch35
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0015-ASoC-pcm3168a-Add-binding-document-for-pcm3168a-code.patch72
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0016-ASoC-pcm3168a-Add-driver-for-pcm3168a-codec.patch1108
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0017-ASoC-PCM3168A-add-TDM-modes.patch298
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0018-ASoC-PCM3168A-disable-16-bit-format.patch26
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0019-ASoC-PCM3168A-enable-on-power-on.patch27
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0020-ASoC-PCM3168A-merge-ADC-and-DAC-to-single-DAI.patch276
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0021-ASoC-PCM3168A-disable-PM.patch43
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0022-ASoC-fix-simple-card-do-not-respect-device-id.patch37
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0023-SPI-GPIO-get-master-fix.patch26
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0024-SPIDEV-extend-maximum-transfer-size.patch26
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0025-Radio-add-si468x-to-spidev.patch25
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0026-ASoC-add-dummy-Si468x-driver.patch122
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0027-ASoC-R-Car-initial-TDM-support.patch354
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0028-ASoC-rcar-correct-32bit-to-24-bit-sample-conv.patch45
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0029-ASoC-R-Car-fix-debug-output.patch57
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0030-R-Car-sound-disable-clock-hack.patch24
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0031-ASoC-R-car-SSI-fix-SSI-slave-mode-setup-while-TDM-an.patch48
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0032-mmc-Add-SDIO-function-devicetree-subnode-parsing.patch160
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0038-Porter-LVDS-display-LQ123K1LG03.patch48
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0060-Remove-delay-at-LVDS-camera-initialization.patch25
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0099-Porter-add-separate-dts-for-ext01-extension-board.patch805
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0100-Porter-ext01-add-dummy-regulator-to-select-48000-sou.patch53
28 files changed, 4272 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0002-Porter-adapt-max9272-ov10635-driver-for-porter-exp-b.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0002-Porter-adapt-max9272-ov10635-driver-for-porter-exp-b.patch
new file mode 100644
index 0000000..eef5751
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0002-Porter-adapt-max9272-ov10635-driver-for-porter-exp-b.patch
@@ -0,0 +1,60 @@
+From f54cc5cd6059fd65d88040805a5da72e894ad9de Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 28 Jan 2016 19:46:49 +0300
+Subject: [PATCH 02/10] Porter: adapt max9272-ov10635 driver for porter exp
+ board
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9272_ov10635.h | 4 ++--
+ drivers/media/i2c/soc_camera/max9272_ov10635_setup.c | 12 ++++++------
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9272_ov10635.h b/drivers/media/i2c/soc_camera/max9272_ov10635.h
+index de1d351..80e9af4 100644
+--- a/drivers/media/i2c/soc_camera/max9272_ov10635.h
++++ b/drivers/media/i2c/soc_camera/max9272_ov10635.h
+@@ -17,8 +17,8 @@
+ #define dev_dbg dev_info
+ #endif
+
+-#define MAX9275_PRESENT /* MAX9275 presents on I2C bus */
+-#define MAXIM_NUM 4 /* number of cameras */
++//#define MAX9275_PRESENT /* MAX9275 presents on I2C bus */
++#define MAXIM_NUM 1 /* number of cameras */
+ #define MAXIM_NUM_RETRIES 1 /* number of read/write retries */
+
+ #define MAXIM_I2C_I2C_SPEED_400KHZ (0x5 << 2) /* 339 kbps */
+diff --git a/drivers/media/i2c/soc_camera/max9272_ov10635_setup.c b/drivers/media/i2c/soc_camera/max9272_ov10635_setup.c
+index 0d4db0f..d01eb5c 100644
+--- a/drivers/media/i2c/soc_camera/max9272_ov10635_setup.c
++++ b/drivers/media/i2c/soc_camera/max9272_ov10635_setup.c
+@@ -39,6 +39,12 @@ static int maxim_probe(struct i2c_client *client,
+ }
+ }
+
++ tmp_addr = client->addr;
++
++ /* power up camera */
++ client->addr = 0x48; /* MAX9272-CAM0 I2C */
++ maxim_reg8_write(client, 0x0e, 0x00); /* GP0 low - enable power for camera */
++
+ /*
+ * Powered MCU IMI cameras need delay between power-on and R-Car access to avoid
+ * i2c bus conflicts since linux kernel does not support i2c multi-mastering,
+@@ -47,12 +53,6 @@ static int maxim_probe(struct i2c_client *client,
+ */
+ mdelay(MAXIM_IMI_MCU_DELAY);
+
+- tmp_addr = client->addr;
+-
+- /* power down cascaded MAX9272 chips */
+- client->addr = 0x48; /* MAX9272-CAM0 I2C */
+- maxim_reg8_write(client, 0x0e, 0x02); /* GP0 high */
+-
+ #ifdef MAX9275_PRESENT
+ /*
+ * SETUP MAX9275 I2C
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0003-Porter-add-LVDS-camera.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0003-Porter-add-LVDS-camera.patch
new file mode 100644
index 0000000..45a93cf
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0003-Porter-add-LVDS-camera.patch
@@ -0,0 +1,88 @@
+From 106ac216eb15205cdcbbd681662b3d018670ca54 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Mon, 30 May 2016 16:16:58 +0300
+Subject: [PATCH] Porter: add LVDS camera
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ arch/arm/mach-shmobile/board-porter-reference.c | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-shmobile/board-porter-reference.c b/arch/arm/mach-shmobile/board-porter-reference.c
+index a286a80..a3af264 100644
+--- a/arch/arm/mach-shmobile/board-porter-reference.c
++++ b/arch/arm/mach-shmobile/board-porter-reference.c
+@@ -148,6 +148,7 @@ static const struct clk_name clk_names[] __initconst = {
+ { "lvds0", "lvds.0", "rcar-du-r8a7791" },
+ { "hsusb", NULL, "usb_phy_rcar_gen2" },
+ { "vin0", NULL, "r8a7791-vin.0" },
++ { "vin2", NULL, "r8a7791-vin.2" },
+ { "vsps", NULL, NULL },
+ #if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) && \
+ !defined(CONFIG_DRM_RCAR_DU_CONNECT_VSP)
+@@ -673,6 +674,9 @@ static const struct resource vin_resources[] __initconst = {
+ /* VIN1 */
+ DEFINE_RES_MEM(0xe6ef1000, 0x1000),
+ DEFINE_RES_IRQ(gic_spi(189)),
++ /* VIN2 */
++ DEFINE_RES_MEM(0xe6ef2000, 0x1000),
++ DEFINE_RES_IRQ(gic_spi(190)),
+ };
+
+ static void __init porter_add_vin_device(unsigned idx,
+@@ -689,12 +693,12 @@ static void __init porter_add_vin_device(unsigned idx,
+ .size_data = sizeof(*pdata),
+ };
+
+- BUG_ON(idx > 1);
++ BUG_ON(idx > 2);
+
+ platform_device_register_full(&vin_info);
+ }
+
+-#define PORTER_CAMERA(idx, name, addr, pdata, flag) \
++#define PORTER_CAMERA(idx, name, bus, addr, pdata, flag) \
+ static struct i2c_board_info i2c_cam##idx##_device = { \
+ I2C_BOARD_INFO(name, addr), \
+ }; \
+@@ -706,12 +710,13 @@ static struct rcar_vin_platform_data vin##idx##_pdata = { \
+ static struct soc_camera_link cam##idx##_link = { \
+ .bus_id = idx, \
+ .board_info = &i2c_cam##idx##_device, \
+- .i2c_adapter_id = 2, \
++ .i2c_adapter_id = bus, \
+ .module_name = name, \
+ .priv = pdata, \
+ }
+
+-PORTER_CAMERA(0, "adv7180", 0x20, NULL, RCAR_VIN_BT656);
++PORTER_CAMERA(0, "adv7180", 2, 0x20, NULL, RCAR_VIN_BT656);
++PORTER_CAMERA(2, "max9272-ov10635", 0, 0x30 + 1, NULL, RCAR_VIN_BT656);
+
+ static void __init porter_add_camera0_device(void)
+ {
+@@ -720,6 +725,13 @@ static void __init porter_add_camera0_device(void)
+ porter_add_vin_device(0, &vin0_pdata);
+ }
+
++static void __init porter_add_camera2_device(void)
++{
++ platform_device_register_data(&platform_bus, "soc-camera-pdrv", 2,
++ &cam2_link, sizeof(cam2_link));
++ porter_add_vin_device(2, &vin2_pdata);
++}
++
+ /* VSP1 */
+ #if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) && \
+ !defined(CONFIG_DRM_RCAR_DU_CONNECT_VSP)
+@@ -911,6 +923,7 @@ static void __init porter_add_standard_devices(void)
+ porter_add_du_device();
+ porter_add_usb_devices();
+ porter_add_camera0_device();
++ porter_add_camera2_device();
+ #if IS_ENABLED(CONFIG_VIDEO_RENESAS_VSP1) && \
+ !defined(CONFIG_DRM_RCAR_DU_CONNECT_VSP)
+ porter_add_vsp1_devices();
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0004-GPIO-CPLD-gpio-extender-driver.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0004-GPIO-CPLD-gpio-extender-driver.patch
new file mode 100644
index 0000000..5efac9f
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0004-GPIO-CPLD-gpio-extender-driver.patch
@@ -0,0 +1,248 @@
+From 2a3918e3dc0cd00c7abf52a0d13dafb458f22acd Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Fri, 29 Jan 2016 15:50:00 +0300
+Subject: [PATCH 04/10] GPIO: CPLD gpio extender driver
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/gpio/Kconfig | 7 ++
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-cpld.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 203 insertions(+)
+ create mode 100644 drivers/gpio/gpio-cpld.c
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 4389778..12a2f8a 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -209,6 +209,13 @@ config GPIO_RCAR
+ help
+ Say yes here to support GPIO on Renesas R-Car SoCs.
+
++config GPIO_PORTER_CPLD
++ bool "Renesas Porter extension board CPLD gpios"
++ depends on ARM
++ help
++ Say yes here to support GPIOs on Renesas Porter
++ extension board from CogentEmbedded.
++
+ config GPIO_SPEAR_SPICS
+ bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+ depends on PLAT_SPEAR
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 2636985..8e66571 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -59,6 +59,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+ obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
+ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
+ obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
++obj-$(CONFIG_GPIO_PORTER_CPLD) += gpio-cpld.o
+ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
+ obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
+ obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
+diff --git a/drivers/gpio/gpio-cpld.c b/drivers/gpio/gpio-cpld.c
+new file mode 100644
+index 0000000..25b57a3
+--- /dev/null
++++ b/drivers/gpio/gpio-cpld.c
+@@ -0,0 +1,195 @@
++/*
++ * r8a7791-porter extension board CPLD access driver
++ *
++ * Copyright (C) 2016 Cogent Embedded, Inc.
++ *
++ * 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/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/gpio.h>
++
++struct porter_cpld_gpio_priv {
++ unsigned data_gpio; /* data gpio */
++ unsigned ptrc_gpio; /* pointer clock gpio */
++ unsigned bufc_gpio; /* buffer clock gpio */
++
++ struct gpio_chip gpio_chip;
++
++ uint16_t state; /* saved gpios state */
++};
++
++static int porter_cpld_gpio_clock_val(struct porter_cpld_gpio_priv *priv,
++ int bit, int val)
++{
++ int i;
++
++ /* reset pointer */
++ gpio_set_value(priv->data_gpio, 1);
++ gpio_set_value(priv->ptrc_gpio, 1);
++ gpio_set_value(priv->data_gpio, 0);
++ gpio_set_value(priv->ptrc_gpio, 0);
++
++ for (i = 0; i < bit; i++) {
++ gpio_set_value(priv->ptrc_gpio, 1);
++ gpio_set_value(priv->ptrc_gpio, 0);
++ }
++
++ gpio_set_value(priv->data_gpio, val);
++ gpio_set_value(priv->bufc_gpio, 1);
++ gpio_set_value(priv->bufc_gpio, 0);
++
++ if (val)
++ priv->state |= (1 << bit);
++ else
++ priv->state &= ~(1 << bit);
++
++ return 0;
++}
++
++static int porter_cpld_gpio_get_value(struct gpio_chip *gc, unsigned off)
++{
++ struct porter_cpld_gpio_priv *priv;
++
++ priv = container_of(gc, struct porter_cpld_gpio_priv, gpio_chip);
++
++ return !!(priv->state & (1 << off));
++}
++
++static void porter_cpld_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
++{
++ struct porter_cpld_gpio_priv *priv;
++
++ priv = container_of(gc, struct porter_cpld_gpio_priv, gpio_chip);
++
++ porter_cpld_gpio_clock_val(priv, off, val);
++}
++
++static int porter_cpld_gpio_direction_input(struct gpio_chip *gc, unsigned off)
++{
++ return -EPERM;
++}
++
++static int porter_cpld_gpio_direction_output(struct gpio_chip *gc, unsigned off,
++ int val)
++{
++ struct porter_cpld_gpio_priv *priv;
++
++ priv = container_of(gc, struct porter_cpld_gpio_priv, gpio_chip);
++
++ return porter_cpld_gpio_clock_val(priv, off, val);
++}
++
++static struct porter_cpld_gpio_priv *porter_cpld_gpio_parse_dt(struct device *dev)
++{
++ struct device_node *np = dev->of_node;
++ struct porter_cpld_gpio_priv *priv;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return NULL;
++
++ priv->data_gpio = of_get_named_gpio(np, "porter-cpld-gpio,data-gpio", 0);
++ if (priv->data_gpio < 0)
++ return NULL;
++
++ priv->ptrc_gpio = of_get_named_gpio(np, "porter-cpld-gpio,ptrc-gpio", 0);
++ if (priv->ptrc_gpio < 0)
++ return NULL;
++
++ priv->bufc_gpio = of_get_named_gpio(np, "porter-cpld-gpio,bufc-gpio", 0);
++ if (priv->bufc_gpio < 0)
++ return NULL;
++
++ return priv;
++}
++
++static void porter_cpld_gpio_init(struct porter_cpld_gpio_priv *priv)
++{
++ gpio_request_one(priv->data_gpio, GPIOF_OUT_INIT_HIGH, "cpld-data");
++ gpio_request_one(priv->ptrc_gpio, GPIOF_OUT_INIT_HIGH, "cpld-ptrc");
++ gpio_request_one(priv->bufc_gpio, GPIOF_OUT_INIT_HIGH, "cpld-bufc");
++}
++
++static int porter_cpld_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct porter_cpld_gpio_priv *priv;
++ struct gpio_chip *gc;
++ int ret;
++
++ priv = porter_cpld_gpio_parse_dt(dev);
++ if (!priv)
++ return -EPROBE_DEFER;
++
++ /* request gpios */
++ porter_cpld_gpio_init(priv);
++
++ priv->state = 0x0;
++ gc = &priv->gpio_chip;
++ gc->of_node = pdev->dev.of_node;
++ gc->direction_input = porter_cpld_gpio_direction_input;
++ gc->direction_output = porter_cpld_gpio_direction_output;
++ gc->get = porter_cpld_gpio_get_value;
++ gc->set = porter_cpld_gpio_set_value;
++
++ gc->base = -1;
++ gc->ngpio = 16;
++ gc->label = "porter-gpio";
++ gc->owner = THIS_MODULE;
++
++ ret = gpiochip_add(&priv->gpio_chip);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int porter_cpld_gpio_remove(struct platform_device *pdev)
++{
++ int ret;
++ struct device *dev = &pdev->dev;
++ struct porter_cpld_gpio_priv *priv = dev_get_drvdata(dev);
++
++ ret = gpiochip_remove(&priv->gpio_chip);
++ if (ret) {
++ dev_err(dev, "gpiochip_remove failed %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id porter_cpld_gpio_dt_ids[] = {
++ { .compatible = "porter-cpld-gpio" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, porter_cpld_gpio_dt_ids);
++
++static struct platform_driver porter_cpld_gpio_driver = {
++ .driver = {
++ .name = "porter-cpld-gpio",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(porter_cpld_gpio_dt_ids),
++ },
++ .probe = porter_cpld_gpio_probe,
++ .remove = porter_cpld_gpio_remove,
++};
++
++static int __init porter_cpld_gpio_driver_init(void)
++{
++ return platform_driver_register(&porter_cpld_gpio_driver);
++}
++
++static void __exit porter_cpld_gpio_driver_exit(void)
++{
++ platform_driver_unregister(&porter_cpld_gpio_driver);
++}
++
++subsys_initcall_sync(porter_cpld_gpio_driver_init);
++module_exit(porter_cpld_gpio_driver_exit);
+\ No newline at end of file
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0012-regmap-Implemented-default-cache-sync-operation.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0012-regmap-Implemented-default-cache-sync-operation.patch
new file mode 100644
index 0000000..b00cfc8
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0012-regmap-Implemented-default-cache-sync-operation.patch
@@ -0,0 +1,102 @@
+From 2de1db4a592a5f18d1b3082fb93deb761b7477fb Mon Sep 17 00:00:00 2001
+From: Maarten ter Huurne <maarten@treewalker.org>
+Date: Mon, 3 Jun 2013 00:15:26 +0200
+Subject: [PATCH 12/16] regmap: Implemented default cache sync operation
+
+This can be used for cache types for which syncing values one by one is
+equally efficient as syncing a range, such as the flat cache.
+
+Signed-off-by: Maarten ter Huurne <maarten@treewalker.org>
+Signed-off-by: Mark Brown <broonie@linaro.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/base/regmap/regcache.c | 46 ++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 42 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
+index 46283fd..ffd8db6 100644
+--- a/drivers/base/regmap/regcache.c
++++ b/drivers/base/regmap/regcache.c
+@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
+ return 0;
+ }
+
++static int regcache_default_sync(struct regmap *map, unsigned int min,
++ unsigned int max)
++{
++ unsigned int reg;
++
++ for (reg = min; reg <= max; reg++) {
++ unsigned int val;
++ int ret;
++
++ if (regmap_volatile(map, reg))
++ continue;
++
++ ret = regcache_read(map, reg, &val);
++ if (ret)
++ return ret;
++
++ /* Is this the hardware default? If so skip. */
++ ret = regcache_lookup_reg(map, reg);
++ if (ret >= 0 && val == map->reg_defaults[ret].def)
++ continue;
++
++ map->cache_bypass = 1;
++ ret = _regmap_write(map, reg, val);
++ map->cache_bypass = 0;
++ if (ret)
++ return ret;
++ dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
++ }
++
++ return 0;
++}
++
+ /**
+ * regcache_sync: Sync the register cache with the hardware.
+ *
+@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
+ const char *name;
+ unsigned int bypass;
+
+- BUG_ON(!map->cache_ops || !map->cache_ops->sync);
++ BUG_ON(!map->cache_ops);
+
+ map->lock(map->lock_arg);
+ /* Remember the initial bypass state */
+@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
+ }
+ map->cache_bypass = 0;
+
+- ret = map->cache_ops->sync(map, 0, map->max_register);
++ if (map->cache_ops->sync)
++ ret = map->cache_ops->sync(map, 0, map->max_register);
++ else
++ ret = regcache_default_sync(map, 0, map->max_register);
+
+ if (ret == 0)
+ map->cache_dirty = false;
+@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
+ const char *name;
+ unsigned int bypass;
+
+- BUG_ON(!map->cache_ops || !map->cache_ops->sync);
++ BUG_ON(!map->cache_ops);
+
+ map->lock(map->lock_arg);
+
+@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
+ if (!map->cache_dirty)
+ goto out;
+
+- ret = map->cache_ops->sync(map, min, max);
++ if (map->cache_ops->sync)
++ ret = map->cache_ops->sync(map, min, max);
++ else
++ ret = regcache_default_sync(map, min, max);
+
+ out:
+ trace_regcache_sync(map->dev, name, "stop region");
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0013-regmap-cache-Don-t-attempt-to-sync-non-writeable-reg.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0013-regmap-cache-Don-t-attempt-to-sync-non-writeable-reg.patch
new file mode 100644
index 0000000..c97928d
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0013-regmap-cache-Don-t-attempt-to-sync-non-writeable-reg.patch
@@ -0,0 +1,34 @@
+From 20f963cde94f375c8f587b3866e6ef3ca6e3218c Mon Sep 17 00:00:00 2001
+From: Dylan Reid <dgreid@chromium.org>
+Date: Tue, 18 Mar 2014 13:45:09 -0700
+Subject: [PATCH 13/16] regmap: cache: Don't attempt to sync non-writeable
+ registers
+
+In the regcache_default_sync, if a register isn't writeable, then
+_regmap_write will return an error and the rest of the sync will be
+aborted. Avoid this by checking if a register is writeable before
+trying to sync it.
+
+Signed-off-by: Dylan Reid <dgreid@chromium.org>
+Signed-off-by: Mark Brown <broonie@linaro.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/base/regmap/regcache.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
+index ffd8db6..3ec0bfd 100644
+--- a/drivers/base/regmap/regcache.c
++++ b/drivers/base/regmap/regcache.c
+@@ -259,7 +259,8 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
+ unsigned int val;
+ int ret;
+
+- if (regmap_volatile(map, reg))
++ if (regmap_volatile(map, reg) ||
++ !regmap_writeable(map, reg))
+ continue;
+
+ ret = regcache_read(map, reg, &val);
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0014-ASoC-Add-SOC_DOUBLE_STS-macro.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0014-ASoC-Add-SOC_DOUBLE_STS-macro.patch
new file mode 100644
index 0000000..58d8d28
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0014-ASoC-Add-SOC_DOUBLE_STS-macro.patch
@@ -0,0 +1,35 @@
+From 563ca49681d5393ed295310a7835660642f59677 Mon Sep 17 00:00:00 2001
+From: "Damien.Horsley" <Damien.Horsley@imgtec.com>
+Date: Tue, 8 Dec 2015 15:58:58 +0000
+Subject: [PATCH 14/16] ASoC: Add SOC_DOUBLE_STS macro
+
+Add SOC_DOUBLE_STS macro for read-only volatile status controls
+
+Signed-off-by: Damien.Horsley <Damien.Horsley@imgtec.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ include/sound/soc.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/include/sound/soc.h b/include/sound/soc.h
+index 645bea2..936bddb 100644
+--- a/include/sound/soc.h
++++ b/include/sound/soc.h
+@@ -99,6 +99,14 @@
+ .put = snd_soc_put_volsw, \
+ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
+ max, invert) }
++#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \
++{ \
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
++ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
++ .access = SNDRV_CTL_ELEM_ACCESS_READ | \
++ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
++ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
++ max, invert) }
+ #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_volsw, \
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0015-ASoC-pcm3168a-Add-binding-document-for-pcm3168a-code.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0015-ASoC-pcm3168a-Add-binding-document-for-pcm3168a-code.patch
new file mode 100644
index 0000000..f4b8e53
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0015-ASoC-pcm3168a-Add-binding-document-for-pcm3168a-code.patch
@@ -0,0 +1,72 @@
+From c4b652e226dbd995041addeb934f2a65c82b5bef Mon Sep 17 00:00:00 2001
+From: "Damien.Horsley" <Damien.Horsley@imgtec.com>
+Date: Tue, 8 Dec 2015 15:58:59 +0000
+Subject: [PATCH 15/16] ASoC: pcm3168a: Add binding document for pcm3168a
+ codec
+
+Add binding document for Texas Instruments pcm3168a codec
+
+Signed-off-by: Damien.Horsley <Damien.Horsley@imgtec.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ .../devicetree/bindings/sound/ti,pcm3168a.txt | 48 ++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
+
+diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
+new file mode 100644
+index 0000000..5d9cb84
+--- /dev/null
++++ b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
+@@ -0,0 +1,48 @@
++Texas Instruments pcm3168a DT bindings
++
++This driver supports both SPI and I2C bus access for this codec
++
++Required properties:
++
++ - compatible: "ti,pcm3168a"
++
++ - clocks : Contains an entry for each entry in clock-names
++
++ - clock-names : Includes the following entries:
++ "scki" The system clock
++
++ - VDD1-supply : Digital power supply regulator 1 (+3.3V)
++
++ - VDD2-supply : Digital power supply regulator 2 (+3.3V)
++
++ - VCCAD1-supply : ADC power supply regulator 1 (+5V)
++
++ - VCCAD2-supply : ADC power supply regulator 2 (+5V)
++
++ - VCCDA1-supply : DAC power supply regulator 1 (+5V)
++
++ - VCCDA2-supply : DAC power supply regulator 2 (+5V)
++
++For required properties on SPI/I2C, consult SPI/I2C device tree documentation
++
++Examples:
++
++i2c0: i2c0@0 {
++
++ ...
++
++ pcm3168a: audio-codec@44 {
++ compatible = "ti,pcm3168a";
++ reg = <0x44>;
++ clocks = <&clk_core CLK_AUDIO>;
++ clock-names = "scki";
++ VDD1-supply = <&supply3v3>;
++ VDD2-supply = <&supply3v3>;
++ VCCAD1-supply = <&supply5v0>;
++ VCCAD2-supply = <&supply5v0>;
++ VCCDA1-supply = <&supply5v0>;
++ VCCDA2-supply = <&supply5v0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&dac_clk_pin>;
++ };
++};
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0016-ASoC-pcm3168a-Add-driver-for-pcm3168a-codec.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0016-ASoC-pcm3168a-Add-driver-for-pcm3168a-codec.patch
new file mode 100644
index 0000000..24582bf
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0016-ASoC-pcm3168a-Add-driver-for-pcm3168a-codec.patch
@@ -0,0 +1,1108 @@
+From 3fa260164b3f5b8f3faa6ada700a3e7addd88c87 Mon Sep 17 00:00:00 2001
+From: "Damien.Horsley" <Damien.Horsley@imgtec.com>
+Date: Tue, 8 Dec 2015 15:59:00 +0000
+Subject: [PATCH 16/16] ASoC: pcm3168a: Add driver for pcm3168a codec
+
+Add driver for Texas Instruments pcm3168a codec
+
+Signed-off-by: Damien.Horsley <Damien.Horsley@imgtec.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/Kconfig | 19 +
+ sound/soc/codecs/Makefile | 6 +
+ sound/soc/codecs/pcm3168a-i2c.c | 66 ++++
+ sound/soc/codecs/pcm3168a-spi.c | 65 ++++
+ sound/soc/codecs/pcm3168a.c | 767 +++++++++++++++++++++++++++++++++++++++
+ sound/soc/codecs/pcm3168a.h | 100 +++++
+ 6 files changed, 1023 insertions(+)
+ create mode 100644 sound/soc/codecs/pcm3168a-i2c.c
+ create mode 100644 sound/soc/codecs/pcm3168a-spi.c
+ create mode 100644 sound/soc/codecs/pcm3168a.c
+ create mode 100644 sound/soc/codecs/pcm3168a.h
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 2f45f00..4f0c01a 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -55,6 +55,8 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_ML26124 if I2C
+ select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
+ select SND_SOC_PCM3008
++ select SND_SOC_PCM3168A_I2C if I2C
++ select SND_SOC_PCM3168A_SPI if SPI_MASTER
+ select SND_SOC_RT5631 if I2C
+ select SND_SOC_SGTL5000 if I2C
+ select SND_SOC_SI476X if MFD_SI476X_CORE
+@@ -293,6 +295,23 @@ config SND_SOC_OMAP_HDMI_CODEC
+ config SND_SOC_PCM3008
+ tristate
+
++config SND_SOC_PCM3168A
++ tristate
++
++config SND_SOC_PCM3168A_I2C
++ tristate "Texas Instruments PCM3168A CODEC - I2C"
++ depends on I2C
++ select SND_SOC_PCM3168A
++ select REGMAP_I2C
++
++config SND_SOC_PCM3168A_SPI
++ tristate "Texas Instruments PCM3168A CODEC - SPI"
++ depends on SPI_MASTER
++ select SND_SOC_PCM3168A
++ select REGMAP_SPI
++
++ config SND_SOC_PCM512x
++ tristate
+ config SND_SOC_RT5631
+ tristate
+
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index b9e41c9..513d895 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -43,6 +43,9 @@ snd-soc-mc13783-objs := mc13783.o
+ snd-soc-ml26124-objs := ml26124.o
+ snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
+ snd-soc-pcm3008-objs := pcm3008.o
++snd-soc-pcm3168a-objs := pcm3168a.o
++snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
++snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
+ snd-soc-rt5631-objs := rt5631.o
+ snd-soc-sgtl5000-objs := sgtl5000.o
+ snd-soc-alc5623-objs := alc5623.o
+@@ -170,6 +173,9 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
+ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
+ obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
+ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
++obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
++obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
++obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o
+ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
+ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
+ obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
+diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
+new file mode 100644
+index 0000000..6feb090
+--- /dev/null
++++ b/sound/soc/codecs/pcm3168a-i2c.c
+@@ -0,0 +1,66 @@
++/*
++ * PCM3168A codec i2c driver
++ *
++ * Copyright (C) 2015 Imagination Technologies Ltd.
++ *
++ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ */
++
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include <sound/soc.h>
++
++#include "pcm3168a.h"
++
++static int pcm3168a_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct regmap *regmap;
++
++ regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap);
++ if (IS_ERR(regmap))
++ return PTR_ERR(regmap);
++
++ return pcm3168a_probe(&i2c->dev, regmap);
++}
++
++static int pcm3168a_i2c_remove(struct i2c_client *i2c)
++{
++ pcm3168a_remove(&i2c->dev);
++
++ return 0;
++}
++
++static const struct i2c_device_id pcm3168a_i2c_id[] = {
++ { "pcm3168a", },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
++
++static const struct of_device_id pcm3168a_of_match[] = {
++ { .compatible = "ti,pcm3168a", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
++
++static struct i2c_driver pcm3168a_i2c_driver = {
++ .probe = pcm3168a_i2c_probe,
++ .remove = pcm3168a_i2c_remove,
++ .id_table = pcm3168a_i2c_id,
++ .driver = {
++ .name = "pcm3168a",
++ .of_match_table = pcm3168a_of_match,
++ .pm = &pcm3168a_pm_ops,
++ },
++};
++module_i2c_driver(pcm3168a_i2c_driver);
++
++MODULE_DESCRIPTION("PCM3168A I2C codec driver");
++MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
+new file mode 100644
+index 0000000..03945a2
+--- /dev/null
++++ b/sound/soc/codecs/pcm3168a-spi.c
+@@ -0,0 +1,65 @@
++/*
++ * PCM3168A codec spi driver
++ *
++ * Copyright (C) 2015 Imagination Technologies Ltd.
++ *
++ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/spi/spi.h>
++
++#include <sound/soc.h>
++
++#include "pcm3168a.h"
++
++static int pcm3168a_spi_probe(struct spi_device *spi)
++{
++ struct regmap *regmap;
++
++ regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap);
++ if (IS_ERR(regmap))
++ return PTR_ERR(regmap);
++
++ return pcm3168a_probe(&spi->dev, regmap);
++}
++
++static int pcm3168a_spi_remove(struct spi_device *spi)
++{
++ pcm3168a_remove(&spi->dev);
++
++ return 0;
++}
++
++static const struct spi_device_id pcm3168a_spi_id[] = {
++ { "pcm3168a", },
++ { },
++};
++MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id);
++
++static const struct of_device_id pcm3168a_of_match[] = {
++ { .compatible = "ti,pcm3168a", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
++
++static struct spi_driver pcm3168a_spi_driver = {
++ .probe = pcm3168a_spi_probe,
++ .remove = pcm3168a_spi_remove,
++ .id_table = pcm3168a_spi_id,
++ .driver = {
++ .name = "pcm3168a",
++ .of_match_table = pcm3168a_of_match,
++ .pm = &pcm3168a_pm_ops,
++ },
++};
++module_spi_driver(pcm3168a_spi_driver);
++
++MODULE_DESCRIPTION("PCM3168A SPI codec driver");
++MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+new file mode 100644
+index 0000000..0ee7ae8
+--- /dev/null
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -0,0 +1,767 @@
++/*
++ * PCM3168A codec driver
++ *
++ * Copyright (C) 2015 Imagination Technologies Ltd.
++ *
++ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <linux/regulator/consumer.h>
++
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/tlv.h>
++
++#include "pcm3168a.h"
++
++#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
++ SNDRV_PCM_FMTBIT_S24_3LE | \
++ SNDRV_PCM_FMTBIT_S24_LE | \
++ SNDRV_PCM_FMTBIT_S32_LE)
++
++#define PCM3168A_FMT_I2S 0x0
++#define PCM3168A_FMT_LEFT_J 0x1
++#define PCM3168A_FMT_RIGHT_J 0x2
++#define PCM3168A_FMT_RIGHT_J_16 0x3
++#define PCM3168A_FMT_DSP_A 0x4
++#define PCM3168A_FMT_DSP_B 0x5
++#define PCM3168A_FMT_DSP_MASK 0x4
++
++#define PCM3168A_NUM_SUPPLIES 6
++static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
++ "VDD1",
++ "VDD2",
++ "VCCAD1",
++ "VCCAD2",
++ "VCCDA1",
++ "VCCDA2"
++};
++
++struct pcm3168a_priv {
++ struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
++ struct regmap *regmap;
++ struct clk *scki;
++ bool adc_master_mode;
++ bool dac_master_mode;
++ unsigned long sysclk;
++ unsigned int adc_fmt;
++ unsigned int dac_fmt;
++};
++
++static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
++static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
++static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
++static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
++
++static const char *const pcm3168a_volume_type[] = {
++ "Individual", "Master + Individual" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
++ PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
++
++static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
++ PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
++
++static const char *const pcm3168a_demp[] = {
++ "Disabled", "48khz", "44.1khz", "32khz" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
++ PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
++
++static const char *const pcm3168a_zf_func[] = {
++ "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
++ "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
++ PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
++
++static const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
++ PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
++
++static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
++
++static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
++ 0, 1, pcm3168a_con);
++static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
++ 2, 3, pcm3168a_con);
++static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
++ 4, 5, pcm3168a_con);
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
++ PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
++ PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
++
++static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
++ PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
++
++/* -100db to 0db, register values 0-54 cause mute */
++static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
++
++/* -100db to 20db, register values 0-14 cause mute */
++static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
++
++static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
++ SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
++ PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
++ SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
++ SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
++ SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
++ SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
++ SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
++ SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
++ SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
++ SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
++ SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
++ SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
++ SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
++ SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
++ SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
++ SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
++ SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
++ SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
++ SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
++ SOC_SINGLE_RANGE_TLV("Master Playback Volume",
++ PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
++ pcm3168a_dac_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
++ PCM3168A_DAC_VOL_CHAN_START,
++ PCM3168A_DAC_VOL_CHAN_START + 1,
++ 0, 54, 255, 0, pcm3168a_dac_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
++ PCM3168A_DAC_VOL_CHAN_START + 2,
++ PCM3168A_DAC_VOL_CHAN_START + 3,
++ 0, 54, 255, 0, pcm3168a_dac_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
++ PCM3168A_DAC_VOL_CHAN_START + 4,
++ PCM3168A_DAC_VOL_CHAN_START + 5,
++ 0, 54, 255, 0, pcm3168a_dac_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
++ PCM3168A_DAC_VOL_CHAN_START + 6,
++ PCM3168A_DAC_VOL_CHAN_START + 7,
++ 0, 54, 255, 0, pcm3168a_dac_tlv),
++ SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_BYP_SHIFT, 1, 1),
++ SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
++ SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
++ SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
++ SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
++ SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
++ SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
++ SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
++ SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
++ SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
++ SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
++ SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
++ SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
++ SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
++ SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
++ SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
++ SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
++ SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
++ SOC_SINGLE_RANGE_TLV("Master Capture Volume",
++ PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
++ pcm3168a_adc_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
++ PCM3168A_ADC_VOL_CHAN_START,
++ PCM3168A_ADC_VOL_CHAN_START + 1,
++ 0, 14, 255, 0, pcm3168a_adc_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
++ PCM3168A_ADC_VOL_CHAN_START + 2,
++ PCM3168A_ADC_VOL_CHAN_START + 3,
++ 0, 14, 255, 0, pcm3168a_adc_tlv),
++ SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
++ PCM3168A_ADC_VOL_CHAN_START + 4,
++ PCM3168A_ADC_VOL_CHAN_START + 5,
++ 0, 14, 255, 0, pcm3168a_adc_tlv)
++};
++
++static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
++ SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_OPEDA_SHIFT, 1),
++ SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
++ SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
++ SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
++ PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
++
++ SND_SOC_DAPM_OUTPUT("AOUT1L"),
++ SND_SOC_DAPM_OUTPUT("AOUT1R"),
++ SND_SOC_DAPM_OUTPUT("AOUT2L"),
++ SND_SOC_DAPM_OUTPUT("AOUT2R"),
++ SND_SOC_DAPM_OUTPUT("AOUT3L"),
++ SND_SOC_DAPM_OUTPUT("AOUT3R"),
++ SND_SOC_DAPM_OUTPUT("AOUT4L"),
++ SND_SOC_DAPM_OUTPUT("AOUT4R"),
++
++ SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_PSVAD_SHIFT, 1),
++ SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
++ SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
++ PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
++
++ SND_SOC_DAPM_INPUT("AIN1L"),
++ SND_SOC_DAPM_INPUT("AIN1R"),
++ SND_SOC_DAPM_INPUT("AIN2L"),
++ SND_SOC_DAPM_INPUT("AIN2R"),
++ SND_SOC_DAPM_INPUT("AIN3L"),
++ SND_SOC_DAPM_INPUT("AIN3R")
++};
++
++static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
++ /* Playback */
++ { "AOUT1L", NULL, "DAC1" },
++ { "AOUT1R", NULL, "DAC1" },
++
++ { "AOUT2L", NULL, "DAC2" },
++ { "AOUT2R", NULL, "DAC2" },
++
++ { "AOUT3L", NULL, "DAC3" },
++ { "AOUT3R", NULL, "DAC3" },
++
++ { "AOUT4L", NULL, "DAC4" },
++ { "AOUT4R", NULL, "DAC4" },
++
++ /* Capture */
++ { "ADC1", NULL, "AIN1L" },
++ { "ADC1", NULL, "AIN1R" },
++
++ { "ADC2", NULL, "AIN2L" },
++ { "ADC2", NULL, "AIN2R" },
++
++ { "ADC3", NULL, "AIN3L" },
++ { "ADC3", NULL, "AIN3R" }
++};
++
++static unsigned int pcm3168a_scki_ratios[] = {
++ 768,
++ 512,
++ 384,
++ 256,
++ 192,
++ 128
++};
++
++#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios)
++#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
++
++#define PCM1368A_MAX_SYSCLK 36864000
++
++static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
++{
++ int ret;
++
++ ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
++ if (ret)
++ return ret;
++
++ /* Internal reset is de-asserted after 3846 SCKI cycles */
++ msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
++
++ return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
++ PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
++}
++
++static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
++{
++ struct snd_soc_codec *codec = dai->codec;
++ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
++
++ regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
++
++ return 0;
++}
++
++static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
++ int clk_id, unsigned int freq, int dir)
++{
++ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
++
++ if (freq > PCM1368A_MAX_SYSCLK)
++ return -EINVAL;
++
++ pcm3168a->sysclk = freq;
++
++ return 0;
++}
++
++static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
++ unsigned int format, bool dac)
++{
++ struct snd_soc_codec *codec = dai->codec;
++ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
++ u32 fmt, reg, mask, shift;
++ bool master_mode;
++
++ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_LEFT_J:
++ fmt = PCM3168A_FMT_LEFT_J;
++ break;
++ case SND_SOC_DAIFMT_I2S:
++ fmt = PCM3168A_FMT_I2S;
++ break;
++ case SND_SOC_DAIFMT_RIGHT_J:
++ fmt = PCM3168A_FMT_RIGHT_J;
++ break;
++ case SND_SOC_DAIFMT_DSP_A:
++ fmt = PCM3168A_FMT_DSP_A;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ fmt = PCM3168A_FMT_DSP_B;
++ break;
++ default:
++ dev_err(codec->dev, "unsupported dai format\n");
++ return -EINVAL;
++ }
++
++ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBS_CFS:
++ master_mode = false;
++ break;
++ case SND_SOC_DAIFMT_CBM_CFM:
++ master_mode = true;
++ break;
++ default:
++ dev_err(codec->dev, "unsupported master/slave mode\n");
++ return -EINVAL;
++ }
++
++ switch (format & SND_SOC_DAIFMT_INV_MASK) {
++ case SND_SOC_DAIFMT_NB_NF:
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (dac) {
++ reg = PCM3168A_DAC_PWR_MST_FMT;
++ mask = PCM3168A_DAC_FMT_MASK;
++ shift = PCM3168A_DAC_FMT_SHIFT;
++ pcm3168a->dac_master_mode = master_mode;
++ pcm3168a->dac_fmt = fmt;
++ } else {
++ reg = PCM3168A_ADC_MST_FMT;
++ mask = PCM3168A_ADC_FMTAD_MASK;
++ shift = PCM3168A_ADC_FMTAD_SHIFT;
++ pcm3168a->adc_master_mode = master_mode;
++ pcm3168a->adc_fmt = fmt;
++ }
++
++ regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
++
++ return 0;
++}
++
++static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
++ unsigned int format)
++{
++ return pcm3168a_set_dai_fmt(dai, format, true);
++}
++
++static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
++ unsigned int format)
++{
++ return pcm3168a_set_dai_fmt(dai, format, false);
++}
++
++static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_codec *codec = dai->codec;
++ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
++ bool tx, master_mode;
++ u32 val, mask, shift, reg;
++ unsigned int rate, channels, fmt, ratio, max_ratio;
++ int i, min_frame_size;
++ snd_pcm_format_t format;
++
++ rate = params_rate(params);
++ format = params_format(params);
++ channels = params_channels(params);
++
++ ratio = pcm3168a->sysclk / rate;
++
++ tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
++ if (tx) {
++ max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
++ reg = PCM3168A_DAC_PWR_MST_FMT;
++ mask = PCM3168A_DAC_MSDA_MASK;
++ shift = PCM3168A_DAC_MSDA_SHIFT;
++ master_mode = pcm3168a->dac_master_mode;
++ fmt = pcm3168a->dac_fmt;
++ } else {
++ max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
++ reg = PCM3168A_ADC_MST_FMT;
++ mask = PCM3168A_ADC_MSAD_MASK;
++ shift = PCM3168A_ADC_MSAD_SHIFT;
++ master_mode = pcm3168a->adc_master_mode;
++ fmt = pcm3168a->adc_fmt;
++ }
++
++ for (i = 0; i < max_ratio; i++) {
++ if (pcm3168a_scki_ratios[i] == ratio)
++ break;
++ }
++
++ if (i == max_ratio) {
++ dev_err(codec->dev, "unsupported sysclk ratio\n");
++ return -EINVAL;
++ }
++
++ min_frame_size = snd_pcm_format_width(params_format(params)) * 2;
++ switch (min_frame_size) {
++ case 32:
++ if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
++ dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
++ return -EINVAL;
++ }
++ fmt = PCM3168A_FMT_RIGHT_J_16;
++ break;
++ case 48:
++ if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
++ dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
++ return -EINVAL;
++ }
++ break;
++ case 64:
++ break;
++ default:
++ dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
++ return -EINVAL;
++ }
++
++ if (master_mode)
++ val = ((i + 1) << shift);
++ else
++ val = 0;
++
++ regmap_update_bits(pcm3168a->regmap, reg, mask, val);
++
++ if (tx) {
++ mask = PCM3168A_DAC_FMT_MASK;
++ shift = PCM3168A_DAC_FMT_SHIFT;
++ } else {
++ mask = PCM3168A_ADC_FMTAD_MASK;
++ shift = PCM3168A_ADC_FMTAD_SHIFT;
++ }
++
++ regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
++
++ return 0;
++}
++
++static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
++ .set_fmt = pcm3168a_set_dai_fmt_dac,
++ .set_sysclk = pcm3168a_set_dai_sysclk,
++ .hw_params = pcm3168a_hw_params,
++ .digital_mute = pcm3168a_digital_mute
++};
++
++static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
++ .set_fmt = pcm3168a_set_dai_fmt_adc,
++ .set_sysclk = pcm3168a_set_dai_sysclk,
++ .hw_params = pcm3168a_hw_params
++};
++
++static struct snd_soc_dai_driver pcm3168a_dais[] = {
++ {
++ .name = "pcm3168a-dac",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 8,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = PCM3168A_FORMATS
++ },
++ .ops = &pcm3168a_dac_dai_ops
++ },
++ {
++ .name = "pcm3168a-adc",
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 1,
++ .channels_max = 6,
++ .rates = SNDRV_PCM_RATE_8000_96000,
++ .formats = PCM3168A_FORMATS
++ },
++ .ops = &pcm3168a_adc_dai_ops
++ },
++};
++
++static const struct reg_default pcm3168a_reg_default[] = {
++ { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
++ { PCM3168A_DAC_PWR_MST_FMT, 0x00 },
++ { PCM3168A_DAC_OP_FLT, 0x00 },
++ { PCM3168A_DAC_INV, 0x00 },
++ { PCM3168A_DAC_MUTE, 0x00 },
++ { PCM3168A_DAC_ZERO, 0x00 },
++ { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
++ { PCM3168A_DAC_VOL_MASTER, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
++ { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
++ { PCM3168A_ADC_SMODE, 0x00 },
++ { PCM3168A_ADC_MST_FMT, 0x00 },
++ { PCM3168A_ADC_PWR_HPFB, 0x00 },
++ { PCM3168A_ADC_SEAD, 0x00 },
++ { PCM3168A_ADC_INV, 0x00 },
++ { PCM3168A_ADC_MUTE, 0x00 },
++ { PCM3168A_ADC_OV, 0x00 },
++ { PCM3168A_ADC_ATT_OVF, 0x00 },
++ { PCM3168A_ADC_VOL_MASTER, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
++ { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
++};
++
++static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
++{
++ if (reg >= PCM3168A_RST_SMODE)
++ return true;
++ else
++ return false;
++}
++
++static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case PCM3168A_DAC_ZERO:
++ case PCM3168A_ADC_OV:
++ return true;
++ default:
++ return false;
++ }
++}
++
++static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
++{
++ if (reg < PCM3168A_RST_SMODE)
++ return false;
++
++ switch (reg) {
++ case PCM3168A_DAC_ZERO:
++ case PCM3168A_ADC_OV:
++ return false;
++ default:
++ return true;
++ }
++}
++
++const struct regmap_config pcm3168a_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++
++ .max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
++ .reg_defaults = pcm3168a_reg_default,
++ .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
++ .readable_reg = pcm3168a_readable_register,
++ .volatile_reg = pcm3168a_volatile_register,
++ .writeable_reg = pcm3168a_writeable_register,
++ .cache_type = REGCACHE_FLAT
++};
++EXPORT_SYMBOL_GPL(pcm3168a_regmap);
++
++static const struct snd_soc_codec_driver pcm3168a_driver = {
++ .idle_bias_off = true,
++ .controls = pcm3168a_snd_controls,
++ .num_controls = ARRAY_SIZE(pcm3168a_snd_controls),
++ .dapm_widgets = pcm3168a_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets),
++ .dapm_routes = pcm3168a_dapm_routes,
++ .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes)
++};
++
++int pcm3168a_probe(struct device *dev, struct regmap *regmap)
++{
++ struct pcm3168a_priv *pcm3168a;
++ int ret, i;
++
++ pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
++ if (pcm3168a == NULL)
++ return -ENOMEM;
++
++ dev_set_drvdata(dev, pcm3168a);
++
++ pcm3168a->scki = devm_clk_get(dev, "scki");
++ if (IS_ERR(pcm3168a->scki)) {
++ ret = PTR_ERR(pcm3168a->scki);
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(pcm3168a->scki);
++ if (ret) {
++ dev_err(dev, "Failed to enable mclk: %d\n", ret);
++ return ret;
++ }
++
++ pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
++
++ for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
++ pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
++
++ ret = devm_regulator_bulk_get(dev,
++ ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
++ if (ret) {
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "failed to request supplies: %d\n", ret);
++ goto err_clk;
++ }
++
++ ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++ if (ret) {
++ dev_err(dev, "failed to enable supplies: %d\n", ret);
++ goto err_clk;
++ }
++
++ pcm3168a->regmap = regmap;
++ if (IS_ERR(pcm3168a->regmap)) {
++ ret = PTR_ERR(pcm3168a->regmap);
++ dev_err(dev, "failed to allocate regmap: %d\n", ret);
++ goto err_regulator;
++ }
++
++ ret = pcm3168a_reset(pcm3168a);
++ if (ret) {
++ dev_err(dev, "Failed to reset device: %d\n", ret);
++ goto err_regulator;
++ }
++
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++ pm_runtime_idle(dev);
++
++ ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
++ ARRAY_SIZE(pcm3168a_dais));
++ if (ret) {
++ dev_err(dev, "failed to register codec: %d\n", ret);
++ goto err_regulator;
++ }
++
++ return 0;
++
++err_regulator:
++ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++err_clk:
++ clk_disable_unprepare(pcm3168a->scki);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(pcm3168a_probe);
++
++void pcm3168a_remove(struct device *dev)
++{
++ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
++
++ snd_soc_unregister_codec(dev);
++ pm_runtime_disable(dev);
++ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++ clk_disable_unprepare(pcm3168a->scki);
++}
++EXPORT_SYMBOL_GPL(pcm3168a_remove);
++
++#ifdef CONFIG_PM
++static int pcm3168a_rt_resume(struct device *dev)
++{
++ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
++ int ret;
++
++ ret = clk_prepare_enable(pcm3168a->scki);
++ if (ret) {
++ dev_err(dev, "Failed to enable mclk: %d\n", ret);
++ return ret;
++ }
++
++ ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++ if (ret) {
++ dev_err(dev, "Failed to enable supplies: %d\n", ret);
++ goto err_clk;
++ }
++
++ ret = pcm3168a_reset(pcm3168a);
++ if (ret) {
++ dev_err(dev, "Failed to reset device: %d\n", ret);
++ goto err_regulator;
++ }
++
++ regcache_cache_only(pcm3168a->regmap, false);
++
++ regcache_mark_dirty(pcm3168a->regmap);
++
++ ret = regcache_sync(pcm3168a->regmap);
++ if (ret) {
++ dev_err(dev, "Failed to sync regmap: %d\n", ret);
++ goto err_regulator;
++ }
++
++ return 0;
++
++err_regulator:
++ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++err_clk:
++ clk_disable_unprepare(pcm3168a->scki);
++
++ return ret;
++}
++
++static int pcm3168a_rt_suspend(struct device *dev)
++{
++ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
++
++ regcache_cache_only(pcm3168a->regmap, true);
++
++ regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
++ pcm3168a->supplies);
++
++ clk_disable_unprepare(pcm3168a->scki);
++
++ return 0;
++}
++#endif
++
++const struct dev_pm_ops pcm3168a_pm_ops = {
++ SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
++};
++EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
++
++MODULE_DESCRIPTION("PCM3168A codec driver");
++MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
+new file mode 100644
+index 0000000..56c8332
+--- /dev/null
++++ b/sound/soc/codecs/pcm3168a.h
+@@ -0,0 +1,100 @@
++/*
++ * PCM3168A codec driver header
++ *
++ * Copyright (C) 2015 Imagination Technologies Ltd.
++ *
++ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ */
++
++#ifndef __PCM3168A_H__
++#define __PCM3168A_H__
++
++extern const struct dev_pm_ops pcm3168a_pm_ops;
++extern const struct regmap_config pcm3168a_regmap;
++
++extern int pcm3168a_probe(struct device *dev, struct regmap *regmap);
++extern void pcm3168a_remove(struct device *dev);
++
++#define PCM3168A_RST_SMODE 0x40
++#define PCM3168A_MRST_MASK 0x80
++#define PCM3168A_SRST_MASK 0x40
++#define PCM3168A_DAC_SRDA_SHIFT 0
++#define PCM3168A_DAC_SRDA_MASK 0x3
++
++#define PCM3168A_DAC_PWR_MST_FMT 0x41
++#define PCM3168A_DAC_PSMDA_SHIFT 7
++#define PCM3168A_DAC_PSMDA_MASK 0x80
++#define PCM3168A_DAC_MSDA_SHIFT 4
++#define PCM3168A_DAC_MSDA_MASK 0x70
++#define PCM3168A_DAC_FMT_SHIFT 0
++#define PCM3168A_DAC_FMT_MASK 0xf
++
++#define PCM3168A_DAC_OP_FLT 0x42
++#define PCM3168A_DAC_OPEDA_SHIFT 4
++#define PCM3168A_DAC_OPEDA_MASK 0xf0
++#define PCM3168A_DAC_FLT_SHIFT 0
++#define PCM3168A_DAC_FLT_MASK 0xf
++
++#define PCM3168A_DAC_INV 0x43
++
++#define PCM3168A_DAC_MUTE 0x44
++
++#define PCM3168A_DAC_ZERO 0x45
++
++#define PCM3168A_DAC_ATT_DEMP_ZF 0x46
++#define PCM3168A_DAC_ATMDDA_MASK 0x80
++#define PCM3168A_DAC_ATMDDA_SHIFT 7
++#define PCM3168A_DAC_ATSPDA_MASK 0x40
++#define PCM3168A_DAC_ATSPDA_SHIFT 6
++#define PCM3168A_DAC_DEMP_SHIFT 4
++#define PCM3168A_DAC_DEMP_MASK 0x30
++#define PCM3168A_DAC_AZRO_SHIFT 1
++#define PCM3168A_DAC_AZRO_MASK 0xe
++#define PCM3168A_DAC_ZREV_MASK 0x1
++#define PCM3168A_DAC_ZREV_SHIFT 0
++
++#define PCM3168A_DAC_VOL_MASTER 0x47
++
++#define PCM3168A_DAC_VOL_CHAN_START 0x48
++
++#define PCM3168A_ADC_SMODE 0x50
++#define PCM3168A_ADC_SRAD_SHIFT 0
++#define PCM3168A_ADC_SRAD_MASK 0x3
++
++#define PCM3168A_ADC_MST_FMT 0x51
++#define PCM3168A_ADC_MSAD_SHIFT 4
++#define PCM3168A_ADC_MSAD_MASK 0x70
++#define PCM3168A_ADC_FMTAD_SHIFT 0
++#define PCM3168A_ADC_FMTAD_MASK 0x7
++
++#define PCM3168A_ADC_PWR_HPFB 0x52
++#define PCM3168A_ADC_PSVAD_SHIFT 4
++#define PCM3168A_ADC_PSVAD_MASK 0x70
++#define PCM3168A_ADC_BYP_SHIFT 0
++#define PCM3168A_ADC_BYP_MASK 0x7
++
++#define PCM3168A_ADC_SEAD 0x53
++
++#define PCM3168A_ADC_INV 0x54
++
++#define PCM3168A_ADC_MUTE 0x55
++
++#define PCM3168A_ADC_OV 0x56
++
++#define PCM3168A_ADC_ATT_OVF 0x57
++#define PCM3168A_ADC_ATMDAD_MASK 0x80
++#define PCM3168A_ADC_ATMDAD_SHIFT 7
++#define PCM3168A_ADC_ATSPAD_MASK 0x40
++#define PCM3168A_ADC_ATSPAD_SHIFT 6
++#define PCM3168A_ADC_OVFP_MASK 0x1
++#define PCM3168A_ADC_OVFP_SHIFT 0
++
++#define PCM3168A_ADC_VOL_MASTER 0x58
++
++#define PCM3168A_ADC_VOL_CHAN_START 0x59
++
++#endif
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0017-ASoC-PCM3168A-add-TDM-modes.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0017-ASoC-PCM3168A-add-TDM-modes.patch
new file mode 100644
index 0000000..ff91821
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0017-ASoC-PCM3168A-add-TDM-modes.patch
@@ -0,0 +1,298 @@
+From 7ca8137af6906da63479f5554d28e351218f6aff Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 13 Apr 2016 15:32:38 +0300
+Subject: [PATCH 17/21] ASoC: PCM3168A: add TDM modes
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/pcm3168a.c | 166 +++++++++++++++++++++++++++++++++----------
+ sound/soc/codecs/pcm3168a.h | 2 +-
+ 2 files changed, 131 insertions(+), 37 deletions(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index 0ee7ae8..6287ad9 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -33,7 +33,11 @@
+ #define PCM3168A_FMT_RIGHT_J_16 0x3
+ #define PCM3168A_FMT_DSP_A 0x4
+ #define PCM3168A_FMT_DSP_B 0x5
+-#define PCM3168A_FMT_DSP_MASK 0x4
++#define PCM3168A_FMT_I2S_TDM 0x6
++#define PCM3168A_FMT_LEFT_J_TDM 0x7
++/* High speed */
++#define PCM3168A_FMT_I2S_TDMHS 0x8
++#define PCM3168A_FMT_LEFT_J_TDMHS 0x9
+
+ #define PCM3168A_NUM_SUPPLIES 6
+ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+@@ -45,12 +49,19 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+ "VCCDA2"
+ };
+
++#define TDM_MODE_NONE 0
++#define TDM_MODE_NORM 1
++#define TDM_MODE_HS 2
++
+ struct pcm3168a_priv {
+ struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+ struct regmap *regmap;
+ struct clk *scki;
+ bool adc_master_mode;
+ bool dac_master_mode;
++ unsigned int tdm;
++ unsigned int slots;
++ unsigned int slot_width;
+ unsigned long sysclk;
+ unsigned int adc_fmt;
+ unsigned int dac_fmt;
+@@ -308,32 +319,43 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
+ return 0;
+ }
+
++int format_table[3][6] = {
++ [TDM_MODE_NONE] = {
++ [0] = -1,
++ [SND_SOC_DAIFMT_I2S] = PCM3168A_FMT_I2S,
++ [SND_SOC_DAIFMT_LEFT_J] = PCM3168A_FMT_LEFT_J,
++ [SND_SOC_DAIFMT_RIGHT_J] = PCM3168A_FMT_RIGHT_J,
++ [SND_SOC_DAIFMT_DSP_A] = PCM3168A_FMT_DSP_A,
++ [SND_SOC_DAIFMT_DSP_B] = PCM3168A_FMT_DSP_B},
++ [TDM_MODE_NORM] = {
++ [0] = -1,
++ [SND_SOC_DAIFMT_I2S] = PCM3168A_FMT_I2S_TDM,
++ [SND_SOC_DAIFMT_LEFT_J] = PCM3168A_FMT_LEFT_J_TDM,
++ [SND_SOC_DAIFMT_RIGHT_J] = -1,
++ [SND_SOC_DAIFMT_DSP_A] = -1,
++ [SND_SOC_DAIFMT_DSP_B] = -1},
++ [TDM_MODE_HS] = {
++ [0] = -1,
++ [SND_SOC_DAIFMT_I2S] = PCM3168A_FMT_I2S_TDMHS,
++ [SND_SOC_DAIFMT_LEFT_J] = PCM3168A_FMT_LEFT_J_TDMHS,
++ [SND_SOC_DAIFMT_RIGHT_J] = -1,
++ [SND_SOC_DAIFMT_DSP_A] = -1,
++ [SND_SOC_DAIFMT_DSP_B] = -1},
++};
++
+ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format, bool dac)
+ {
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+- u32 fmt, reg, mask, shift;
++ u32 reg, mask, shift;
++ int fmt;
+ bool master_mode;
+
+- switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+- case SND_SOC_DAIFMT_LEFT_J:
+- fmt = PCM3168A_FMT_LEFT_J;
+- break;
+- case SND_SOC_DAIFMT_I2S:
+- fmt = PCM3168A_FMT_I2S;
+- break;
+- case SND_SOC_DAIFMT_RIGHT_J:
+- fmt = PCM3168A_FMT_RIGHT_J;
+- break;
+- case SND_SOC_DAIFMT_DSP_A:
+- fmt = PCM3168A_FMT_DSP_A;
+- break;
+- case SND_SOC_DAIFMT_DSP_B:
+- fmt = PCM3168A_FMT_DSP_B;
+- break;
+- default:
+- dev_err(codec->dev, "unsupported dai format\n");
++ fmt = format_table[pcm3168a->tdm][format & SND_SOC_DAIFMT_FORMAT_MASK];
++
++ if (fmt < 0) {
++ dev_err(codec->dev, "unsupported dai format of TDM mode\n");
+ return -EINVAL;
+ }
+
+@@ -349,6 +371,16 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ return -EINVAL;
+ }
+
++ if ((pcm3168a->tdm == TDM_MODE_HS) && (master_mode)) {
++ dev_err(codec->dev, "TDM high speed supported only in slave mode\n");
++ return -EINVAL;
++ }
++
++ if ((pcm3168a->tdm == TDM_MODE_HS) && (!dac)) {
++ dev_err(codec->dev, "TDM high speed not supported for ADC\n");
++ return -EINVAL;
++ }
++
+ switch (format & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+@@ -391,10 +423,12 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+ {
++ int bits;
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+ bool tx, master_mode;
+ u32 val, mask, shift, reg;
++ u32 sample_rate = 0; /* auto */
+ unsigned int rate, channels, fmt, ratio, max_ratio;
+ int i, min_frame_size;
+ snd_pcm_format_t format;
+@@ -402,6 +436,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ rate = params_rate(params);
+ format = params_format(params);
+ channels = params_channels(params);
++ bits = params->msbits;
++
++ tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+ ratio = pcm3168a->sysclk / rate;
+
+@@ -432,26 +469,49 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ return -EINVAL;
+ }
+
+- min_frame_size = snd_pcm_format_width(params_format(params)) * 2;
+- switch (min_frame_size) {
+- case 32:
+- if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
+- dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
++ if (pcm3168a->tdm == TDM_MODE_NONE) {
++ /* one stereo frame size */
++ min_frame_size = bits * 2;
++ switch (min_frame_size) {
++ case 32:
++ if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
++ dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
++ return -EINVAL;
++ }
++ fmt = PCM3168A_FMT_RIGHT_J_16;
++ break;
++ case 48:
++ if (master_mode ||
++ (fmt == PCM3168A_FMT_DSP_A) ||
++ (fmt == PCM3168A_FMT_DSP_B)) {
++ dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
++ return -EINVAL;
++ }
++ break;
++ case 64:
++ break;
++ default:
++ dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+ return -EINVAL;
+ }
+- fmt = PCM3168A_FMT_RIGHT_J_16;
+- break;
+- case 48:
+- if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
+- dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
++ }
++ if ((pcm3168a->tdm == TDM_MODE_NORM) ||
++ (pcm3168a->tdm == TDM_MODE_HS)) {
++ /* all channels over one or two line */
++ min_frame_size = bits * channels;
++
++ /* single rate */
++ sample_rate = 1;
++
++ /*
++ * 256fs for single line DIN0/DOUT0
++ * 128fs for two lines DIN01/DOU01
++ */
++ if ((min_frame_size != 256) &&
++ (min_frame_size != 128)) {
++ dev_err(codec->dev, "256/128-bit frames only supported in TDM formats\n");
+ return -EINVAL;
+ }
+- break;
+- case 64:
+- break;
+- default:
+- dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+- return -EINVAL;
+ }
+
+ if (master_mode)
+@@ -460,6 +520,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ val = 0;
+
+ regmap_update_bits(pcm3168a->regmap, reg, mask, val);
++ regmap_update_bits(pcm3168a->regmap, PCM3168A_RST_SMODE,
++ PCM3168A_DAC_SRDA_MASK,
++ sample_rate << PCM3168A_DAC_SRDA_SHIFT);
+
+ if (tx) {
+ mask = PCM3168A_DAC_FMT_MASK;
+@@ -474,9 +537,31 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ return 0;
+ }
+
++static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai,
++ unsigned int tx_mask,
++ unsigned int rx_mask,
++ int slots,
++ int slot_width)
++{
++ struct snd_soc_codec *codec = dai->codec;
++ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
++
++ if ((slots != 8) && (slots != 4))
++ return -EINVAL;
++
++ if ((slot_width != 32) && (slot_width != 24))
++ return -EINVAL;
++
++ pcm3168a->slots = slots;
++ pcm3168a->slot_width = slot_width;
++
++ return 0;
++}
++
+ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+ .set_fmt = pcm3168a_set_dai_fmt_dac,
+ .set_sysclk = pcm3168a_set_dai_sysclk,
++ .set_tdm_slot = pcm3168a_set_tdm_slot,
+ .hw_params = pcm3168a_hw_params,
+ .digital_mute = pcm3168a_digital_mute
+ };
+@@ -484,6 +569,7 @@ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+ static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+ .set_fmt = pcm3168a_set_dai_fmt_adc,
+ .set_sysclk = pcm3168a_set_dai_sysclk,
++ .set_tdm_slot = pcm3168a_set_tdm_slot,
+ .hw_params = pcm3168a_hw_params
+ };
+
+@@ -661,6 +747,14 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+ goto err_regulator;
+ }
+
++ /* get TDM mode */
++ if (dev->of_node) {
++ if (of_get_property(dev->of_node, "tdm", NULL))
++ pcm3168a->tdm = TDM_MODE_NORM;
++ else if (of_get_property(dev->of_node, "tdmhs", NULL))
++ pcm3168a->tdm = TDM_MODE_HS;
++ }
++
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
+index 56c8332..658507f 100644
+--- a/sound/soc/codecs/pcm3168a.h
++++ b/sound/soc/codecs/pcm3168a.h
+@@ -69,7 +69,7 @@ extern void pcm3168a_remove(struct device *dev);
+ #define PCM3168A_ADC_MSAD_SHIFT 4
+ #define PCM3168A_ADC_MSAD_MASK 0x70
+ #define PCM3168A_ADC_FMTAD_SHIFT 0
+-#define PCM3168A_ADC_FMTAD_MASK 0x7
++#define PCM3168A_ADC_FMTAD_MASK 0xf
+
+ #define PCM3168A_ADC_PWR_HPFB 0x52
+ #define PCM3168A_ADC_PSVAD_SHIFT 4
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0018-ASoC-PCM3168A-disable-16-bit-format.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0018-ASoC-PCM3168A-disable-16-bit-format.patch
new file mode 100644
index 0000000..70c9510
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0018-ASoC-PCM3168A-disable-16-bit-format.patch
@@ -0,0 +1,26 @@
+From 4b228271e1276e67d3892aef2e86644c8f382314 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 13 Apr 2016 14:36:14 +0300
+Subject: [PATCH 18/21] ASoC: PCM3168A: disable 16 bit format
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/pcm3168a.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index 6287ad9..06b5d53 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -22,7 +22,7 @@
+
+ #include "pcm3168a.h"
+
+-#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
++#define PCM3168A_FORMATS (/*SNDRV_PCM_FMTBIT_S16_LE | */\
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0019-ASoC-PCM3168A-enable-on-power-on.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0019-ASoC-PCM3168A-enable-on-power-on.patch
new file mode 100644
index 0000000..0159985
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0019-ASoC-PCM3168A-enable-on-power-on.patch
@@ -0,0 +1,27 @@
+From 881838951504feac2f42e771ed2195b305cf22a1 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 13 Apr 2016 14:36:50 +0300
+Subject: [PATCH 19/21] ASoC: PCM3168A: enable on power on
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/pcm3168a.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index 06b5d53..719eca1 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -600,7 +600,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
+
+ static const struct reg_default pcm3168a_reg_default[] = {
+ { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
+- { PCM3168A_DAC_PWR_MST_FMT, 0x00 },
++ { PCM3168A_DAC_PWR_MST_FMT, 0x80 },
+ { PCM3168A_DAC_OP_FLT, 0x00 },
+ { PCM3168A_DAC_INV, 0x00 },
+ { PCM3168A_DAC_MUTE, 0x00 },
+--
+1.7.10.4
+
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0020-ASoC-PCM3168A-merge-ADC-and-DAC-to-single-DAI.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0020-ASoC-PCM3168A-merge-ADC-and-DAC-to-single-DAI.patch
new file mode 100644
index 0000000..9565725
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0020-ASoC-PCM3168A-merge-ADC-and-DAC-to-single-DAI.patch
@@ -0,0 +1,276 @@
+From 45b88347956046b1a75c791254609ca7becdb0bf Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 20 Apr 2016 17:52:12 +0300
+Subject: [PATCH] ASoC: PCM3168A: merge ADC and DAC to single DAI
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/pcm3168a.c | 151 +++++++++++++++++++++----------------------
+ 1 file changed, 72 insertions(+), 79 deletions(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index 719eca1..e1b5feb 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -57,8 +57,7 @@ struct pcm3168a_priv {
+ struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+ struct regmap *regmap;
+ struct clk *scki;
+- bool adc_master_mode;
+- bool dac_master_mode;
++ bool master_mode;
+ unsigned int tdm;
+ unsigned int slots;
+ unsigned int slot_width;
+@@ -343,7 +342,7 @@ int format_table[3][6] = {
+ [SND_SOC_DAIFMT_DSP_B] = -1},
+ };
+
+-static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
++static int __pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format, bool dac)
+ {
+ struct snd_soc_codec *codec = dai->codec;
+@@ -392,31 +391,32 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ reg = PCM3168A_DAC_PWR_MST_FMT;
+ mask = PCM3168A_DAC_FMT_MASK;
+ shift = PCM3168A_DAC_FMT_SHIFT;
+- pcm3168a->dac_master_mode = master_mode;
+ pcm3168a->dac_fmt = fmt;
+ } else {
+ reg = PCM3168A_ADC_MST_FMT;
+ mask = PCM3168A_ADC_FMTAD_MASK;
+ shift = PCM3168A_ADC_FMTAD_SHIFT;
+- pcm3168a->adc_master_mode = master_mode;
+ pcm3168a->adc_fmt = fmt;
+ }
+
++ pcm3168a->master_mode = master_mode;
++
+ regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+ return 0;
+ }
+
+-static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
++static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format)
+ {
+- return pcm3168a_set_dai_fmt(dai, format, true);
+-}
++ int ret;
+
+-static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
+- unsigned int format)
+-{
+- return pcm3168a_set_dai_fmt(dai, format, false);
++ /* dac */
++ ret = __pcm3168a_set_dai_fmt(dai, format, false);
++ if (ret)
++ return ret;
++ /* adc */
++ return __pcm3168a_set_dai_fmt(dai, format, true);
+ }
+
+ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+@@ -426,7 +426,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ int bits;
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+- bool tx, master_mode;
++ bool tx;
+ u32 val, mask, shift, reg;
+ u32 sample_rate = 0; /* auto */
+ unsigned int rate, channels, fmt, ratio, max_ratio;
+@@ -440,33 +440,28 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+
+ tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+- ratio = pcm3168a->sysclk / rate;
+-
+- tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ if (tx) {
+ max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+- reg = PCM3168A_DAC_PWR_MST_FMT;
+- mask = PCM3168A_DAC_MSDA_MASK;
+- shift = PCM3168A_DAC_MSDA_SHIFT;
+- master_mode = pcm3168a->dac_master_mode;
+ fmt = pcm3168a->dac_fmt;
+ } else {
+ max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+- reg = PCM3168A_ADC_MST_FMT;
+- mask = PCM3168A_ADC_MSAD_MASK;
+- shift = PCM3168A_ADC_MSAD_SHIFT;
+- master_mode = pcm3168a->adc_master_mode;
+ fmt = pcm3168a->adc_fmt;
+ }
+
+- for (i = 0; i < max_ratio; i++) {
+- if (pcm3168a_scki_ratios[i] == ratio)
+- break;
+- }
++ if (pcm3168a->master_mode) {
++ ratio = pcm3168a->sysclk / rate;
++ for (i = 0; i < max_ratio; i++)
++ if (pcm3168a_scki_ratios[i] == ratio)
++ break;
+
+- if (i == max_ratio) {
+- dev_err(codec->dev, "unsupported sysclk ratio\n");
+- return -EINVAL;
++ if (i == max_ratio) {
++ dev_err(codec->dev, "unsupported sysclk ratio: %d\n", ratio);
++ return -EINVAL;
++ }
++ val = i + 1;
++ } else {
++ /* slave mode */
++ val = 0;
+ }
+
+ if (pcm3168a->tdm == TDM_MODE_NONE) {
+@@ -474,14 +469,15 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ min_frame_size = bits * 2;
+ switch (min_frame_size) {
+ case 32:
+- if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
++ if (pcm3168a->master_mode ||
++ (fmt != PCM3168A_FMT_RIGHT_J)) {
+ dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
+ return -EINVAL;
+ }
+ fmt = PCM3168A_FMT_RIGHT_J_16;
+ break;
+ case 48:
+- if (master_mode ||
++ if (pcm3168a->master_mode ||
+ (fmt == PCM3168A_FMT_DSP_A) ||
+ (fmt == PCM3168A_FMT_DSP_B)) {
+ dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+@@ -514,26 +510,30 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+ }
+ }
+
+- if (master_mode)
+- val = ((i + 1) << shift);
+- else
++ /* Setup ADC in master mode, couse it drives ADC */
++ if ((pcm3168a->master_mode) || (tx)) {
++ fmt = pcm3168a->dac_fmt;
++ reg = PCM3168A_DAC_PWR_MST_FMT;
++ mask = PCM3168A_DAC_MSDA_MASK | PCM3168A_DAC_FMT_MASK;
++ shift = PCM3168A_DAC_MSDA_SHIFT;
++ /* start DAC */
++ regmap_update_bits(pcm3168a->regmap, reg, mask, (val << shift) | fmt);
++ }
++ /* Do we need also ADC? */
++ if (!tx) {
++ fmt = pcm3168a->adc_fmt;
++ reg = PCM3168A_ADC_MST_FMT;
++ mask = PCM3168A_ADC_MSAD_MASK | PCM3168A_ADC_FMTAD_MASK;
++ shift = PCM3168A_ADC_MSAD_SHIFT;
++ /* ADC slave mode only, driven by DAC or CPU DAI */
+ val = 0;
++ regmap_update_bits(pcm3168a->regmap, reg, mask, (val << shift) | fmt);
++ }
+
+- regmap_update_bits(pcm3168a->regmap, reg, mask, val);
+ regmap_update_bits(pcm3168a->regmap, PCM3168A_RST_SMODE,
+ PCM3168A_DAC_SRDA_MASK,
+ sample_rate << PCM3168A_DAC_SRDA_SHIFT);
+
+- if (tx) {
+- mask = PCM3168A_DAC_FMT_MASK;
+- shift = PCM3168A_DAC_FMT_SHIFT;
+- } else {
+- mask = PCM3168A_ADC_FMTAD_MASK;
+- shift = PCM3168A_ADC_FMTAD_SHIFT;
+- }
+-
+- regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+-
+ return 0;
+ }
+
+@@ -558,44 +558,32 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai,
+ return 0;
+ }
+
+-static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+- .set_fmt = pcm3168a_set_dai_fmt_dac,
++static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
++ .set_fmt = pcm3168a_set_dai_fmt,
+ .set_sysclk = pcm3168a_set_dai_sysclk,
+ .set_tdm_slot = pcm3168a_set_tdm_slot,
+ .hw_params = pcm3168a_hw_params,
+ .digital_mute = pcm3168a_digital_mute
+ };
+
+-static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+- .set_fmt = pcm3168a_set_dai_fmt_adc,
+- .set_sysclk = pcm3168a_set_dai_sysclk,
+- .set_tdm_slot = pcm3168a_set_tdm_slot,
+- .hw_params = pcm3168a_hw_params
+-};
+-
+-static struct snd_soc_dai_driver pcm3168a_dais[] = {
+- {
+- .name = "pcm3168a-dac",
+- .playback = {
+- .stream_name = "Playback",
+- .channels_min = 1,
+- .channels_max = 8,
+- .rates = SNDRV_PCM_RATE_8000_192000,
+- .formats = PCM3168A_FORMATS
+- },
+- .ops = &pcm3168a_dac_dai_ops
++static struct snd_soc_dai_driver pcm3168a_dai = {
++ .name = "pcm3168a",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 8,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = PCM3168A_FORMATS
+ },
+- {
+- .name = "pcm3168a-adc",
+- .capture = {
+- .stream_name = "Capture",
+- .channels_min = 1,
+- .channels_max = 6,
+- .rates = SNDRV_PCM_RATE_8000_96000,
+- .formats = PCM3168A_FORMATS
+- },
+- .ops = &pcm3168a_adc_dai_ops
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 1,
++ .channels_max = 8,
++ .rates = SNDRV_PCM_RATE_8000_96000,
++ .formats = PCM3168A_FORMATS
+ },
++ .ops = &pcm3168a_dai_ops,
++ .symmetric_rates = 1,
+ };
+
+ static const struct reg_default pcm3168a_reg_default[] = {
+@@ -759,8 +747,13 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+- ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
+- ARRAY_SIZE(pcm3168a_dais));
++ if (pcm3168a->tdm != TDM_MODE_NONE) {
++ pcm3168a_dai.playback.channels_min = 8;
++ pcm3168a_dai.capture.channels_min = 8;
++ }
++
++ ret = snd_soc_register_codec(dev, &pcm3168a_driver,
++ &pcm3168a_dai, 1);
+ if (ret) {
+ dev_err(dev, "failed to register codec: %d\n", ret);
+ goto err_regulator;
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0021-ASoC-PCM3168A-disable-PM.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0021-ASoC-PCM3168A-disable-PM.patch
new file mode 100644
index 0000000..13663e9
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0021-ASoC-PCM3168A-disable-PM.patch
@@ -0,0 +1,43 @@
+From 98080a2e34eaf0085c3ea34079dfce89c10d0ee1 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Mon, 30 May 2016 12:30:26 +0300
+Subject: [PATCH] ASoC: PCM3168A: disable PM
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/pcm3168a.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
+index 8113566..2bee442 100644
+--- a/sound/soc/codecs/pcm3168a.c
++++ b/sound/soc/codecs/pcm3168a.c
+@@ -797,7 +797,8 @@ void pcm3168a_remove(struct device *dev)
+ }
+ EXPORT_SYMBOL_GPL(pcm3168a_remove);
+
+-#ifdef CONFIG_PM
++
++#ifdef CONFIG_PM__
+ static int pcm3168a_rt_resume(struct device *dev)
+ {
+ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+@@ -856,6 +857,15 @@ static int pcm3168a_rt_suspend(struct device *dev)
+
+ return 0;
+ }
++#else
++static int pcm3168a_rt_resume(struct device *dev)
++{
++ return 0;
++}
++static int pcm3168a_rt_suspend(struct device *dev)
++{
++ return 0;
++}
+ #endif
+
+ const struct dev_pm_ops pcm3168a_pm_ops = {
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0022-ASoC-fix-simple-card-do-not-respect-device-id.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0022-ASoC-fix-simple-card-do-not-respect-device-id.patch
new file mode 100644
index 0000000..dd1dd3c
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0022-ASoC-fix-simple-card-do-not-respect-device-id.patch
@@ -0,0 +1,37 @@
+From 1bee53bce7b8bf48f70e8b22272dceb47dbfc29e Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 17 Feb 2016 17:45:17 +0300
+Subject: [PATCH 22/31] ASoC: fix simple-card do not respect device id
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/generic/simple-card.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
+index 9556644..0bad6f0 100644
+--- a/sound/soc/generic/simple-card.c
++++ b/sound/soc/generic/simple-card.c
+@@ -435,19 +435,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
+ dev_err(dev, "parse error %d\n", ret);
+ goto err;
+ }
+-
+- /*
+- * soc_bind_dai_link() will check cpu name
+- * after of_node matching if dai_link has cpu_dai_name.
+- * but, it will never match if name was created by fmt_single_name()
+- * remove cpu_dai_name to escape name matching.
+- * see
+- * fmt_single_name()
+- * fmt_multiple_name()
+- */
+- if (num_links == 1)
+- dai_link->cpu_dai_name = NULL;
+-
+ } else {
+ struct asoc_simple_card_info *cinfo;
+
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0023-SPI-GPIO-get-master-fix.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0023-SPI-GPIO-get-master-fix.patch
new file mode 100644
index 0000000..359c7ea
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0023-SPI-GPIO-get-master-fix.patch
@@ -0,0 +1,26 @@
+From 95e2424a054402d712feeebdcb3be5db4c545b5d Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Fri, 12 Feb 2016 17:52:21 +0300
+Subject: [PATCH 23/31] SPI-GPIO: get master fix
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/spi/spi-gpio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
+index 0021fc4..86f2ecc 100644
+--- a/drivers/spi/spi-gpio.c
++++ b/drivers/spi/spi-gpio.c
+@@ -469,7 +469,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
+ }
+ #endif
+
+- spi_gpio->bitbang.master = spi_master_get(master);
++ spi_gpio->bitbang.master = master;
+ spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
+
+ if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0024-SPIDEV-extend-maximum-transfer-size.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0024-SPIDEV-extend-maximum-transfer-size.patch
new file mode 100644
index 0000000..fba1bca
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0024-SPIDEV-extend-maximum-transfer-size.patch
@@ -0,0 +1,26 @@
+From 392890512e63267a76263a5c36657a2c38bed099 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 17 Feb 2016 18:11:55 +0300
+Subject: [PATCH 24/31] SPIDEV: extend maximum transfer size
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/spi/spidev.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index 911e9e0..354fd4b 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -90,7 +90,7 @@ struct spidev_data {
+ static LIST_HEAD(device_list);
+ static DEFINE_MUTEX(device_list_lock);
+
+-static unsigned bufsiz = 4096;
++static unsigned bufsiz = 8192;
+ module_param(bufsiz, uint, S_IRUGO);
+ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
+
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0025-Radio-add-si468x-to-spidev.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0025-Radio-add-si468x-to-spidev.patch
new file mode 100644
index 0000000..749fb89
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0025-Radio-add-si468x-to-spidev.patch
@@ -0,0 +1,25 @@
+From 4474e4919ab324979d736d53d05064d4f10bbd28 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Fri, 12 Feb 2016 17:55:25 +0300
+Subject: [PATCH 25/31] Radio: add si468x to spidev
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/spi/spidev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index 354fd4b..794d8d0 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -646,6 +646,7 @@ static int spidev_remove(struct spi_device *spi)
+
+ static const struct of_device_id spidev_dt_ids[] = {
+ { .compatible = "rohm,dh2228fv" },
++ { .compatible = "si,468x" },
+ {},
+ };
+
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0026-ASoC-add-dummy-Si468x-driver.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0026-ASoC-add-dummy-Si468x-driver.patch
new file mode 100644
index 0000000..58d2769
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0026-ASoC-add-dummy-Si468x-driver.patch
@@ -0,0 +1,122 @@
+From 56f1240b9e418ad1196085397597e2c710a73946 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 18 Feb 2016 18:54:18 +0300
+Subject: [PATCH 26/31] ASoC: add dummy Si468x driver
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ sound/soc/codecs/Kconfig | 3 +++
+ sound/soc/codecs/Makefile | 2 ++
+ sound/soc/codecs/si468x.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 71 insertions(+)
+ create mode 100644 sound/soc/codecs/si468x.c
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 4f0c01a..bf0f022 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -310,6 +310,9 @@ config SND_SOC_PCM3168A_SPI
+ select SND_SOC_PCM3168A
+ select REGMAP_SPI
+
++config SND_SOC_SI468X
++ tristate "Dummy sound driver for Si468x radio"
++
+ config SND_SOC_PCM512x
+ tristate
+ config SND_SOC_RT5631
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 513d895..ba05156 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -51,6 +51,7 @@ snd-soc-sgtl5000-objs := sgtl5000.o
+ snd-soc-alc5623-objs := alc5623.o
+ snd-soc-alc5632-objs := alc5632.o
+ snd-soc-sigmadsp-objs := sigmadsp.o
++snd-soc-si468x-objs := si468x.o
+ snd-soc-si476x-objs := si476x.o
+ snd-soc-sn95031-objs := sn95031.o
+ snd-soc-spdif-tx-objs := spdif_transciever.o
+@@ -180,6 +181,7 @@ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
+ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
+ obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
+ obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
++obj-$(CONFIG_SND_SOC_SI468X) += snd-soc-si468x.o
+ obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
+ obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
+diff --git a/sound/soc/codecs/si468x.c b/sound/soc/codecs/si468x.c
+new file mode 100644
+index 0000000..18b099f
+--- /dev/null
++++ b/sound/soc/codecs/si468x.c
+@@ -0,0 +1,66 @@
++/*
++ * Dummy sound driver for Si468x DAB/FM/AM chips
++ * Copyright 2016 Andrey Gusakov <andrey.gusakov@cogentembedded.com>
++ *
++ * Based on: Driver for the DFBM-CS320 bluetooth module
++ * Copyright 2011 Lars-Peter Clausen <lars@metafoo.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.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/soc.h>
++
++static struct snd_soc_dai_driver si468x_dai = {
++ .name = "si468x-pcm",
++ .capture = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE,
++ },
++};
++
++static struct snd_soc_codec_driver soc_codec_dev_si468x;
++
++static int si468x_probe(struct platform_device *pdev)
++{
++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si468x,
++ &si468x_dai, 1);
++}
++
++static int si468x_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_codec(&pdev->dev);
++
++ return 0;
++}
++
++static const struct of_device_id si468x_of_match[] = {
++ { .compatible = "si,si468x-pcm", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, si468x_of_match);
++
++static struct platform_driver si468x_driver = {
++ .driver = {
++ .name = "si468x",
++ .of_match_table = si468x_of_match,
++ .owner = THIS_MODULE,
++ },
++ .probe = si468x_probe,
++ .remove = si468x_remove,
++};
++
++module_platform_driver(si468x_driver);
++
++MODULE_AUTHOR("Andrey Gusakov <andrey.gusakov@cogentembedded.com>");
++MODULE_DESCRIPTION("ASoC Si468x radio chip driver");
++MODULE_LICENSE("GPL");
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0027-ASoC-R-Car-initial-TDM-support.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0027-ASoC-R-Car-initial-TDM-support.patch
new file mode 100644
index 0000000..b165b44
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0027-ASoC-R-Car-initial-TDM-support.patch
@@ -0,0 +1,354 @@
+From cd5612aeb65de5468f793558d6536d1b90b3dc76 Mon Sep 17 00:00:00 2001
+From: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
+Date: Wed, 15 Jun 2016 21:13:26 +0300
+Subject: [PATCH 1/5] ASoC: R-Car: initial TDM support
+
+---
+ include/sound/rcar_snd.h | 4 ++
+ sound/soc/sh/rcar/core.c | 14 ++++-
+ sound/soc/sh/rcar/src.c | 12 +++-
+ sound/soc/sh/rcar/ssi.c | 148 ++++++++++++++++++++++++++++++++++++++++++++---
+ 4 files changed, 164 insertions(+), 14 deletions(-)
+
+diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
+index e2f1000..37229c1 100644
+--- a/include/sound/rcar_snd.h
++++ b/include/sound/rcar_snd.h
+@@ -35,6 +35,10 @@
+ */
+ #define RSND_SSI_CLK_PIN_SHARE (1 << 31)
+ #define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
++#define RSND_SSI_TDM_4 (1 << 29) /* use 4ch TDM on this SSI */
++#define RSND_SSI_TDM_6 (1 << 28) /* use 6ch TDM on this SSI */
++#define RSND_SSI_TDM_8 (1 << 27) /* use 8ch TDM on this SSI */
++#define RSND_SSI_TDM_MASK (0x7 << 27)
+
+ #define RSND_SSI(_dma_id, _pio_irq, _flags) \
+ { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
+diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
+index ede9b5d..0b5c90e 100644
+--- a/sound/soc/sh/rcar/core.c
++++ b/sound/soc/sh/rcar/core.c
+@@ -426,6 +426,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
+ case 16:
+ adinr |= (8 << 16);
+ break;
++ case 18:
++ adinr |= (6 << 16);
++ break;
++ case 20:
++ adinr |= (4 << 16);
++ break;
++ case 22:
++ adinr |= (2 << 16);
++ break;
++ case 24:
+ case 32:
+ adinr |= (0 << 16);
+ break;
+@@ -1074,7 +1084,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
+ drv[i].playback.rates = RSND_RATES;
+ drv[i].playback.formats = RSND_FMTS;
+ drv[i].playback.channels_min = 2;
+- drv[i].playback.channels_max = 2;
++ drv[i].playback.channels_max = 8;
+
+ rdai[i].playback.info = &info->dai_info[i].playback;
+ rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
+@@ -1083,7 +1093,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
+ drv[i].capture.rates = RSND_RATES;
+ drv[i].capture.formats = RSND_FMTS;
+ drv[i].capture.channels_min = 2;
+- drv[i].capture.channels_max = 2;
++ drv[i].capture.channels_max = 8;
+
+ rdai[i].capture.info = &info->dai_info[i].capture;
+ rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
+diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
+index 426714e..bbd7fe5 100644
+--- a/sound/soc/sh/rcar/src.c
++++ b/sound/soc/sh/rcar/src.c
+@@ -158,6 +158,8 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+ */
+ if (rsnd_ssi_is_pin_sharing(ssi_mod)) {
+ int shift = -1;
++ int sync_34 = 0;
++ int mask = 0;
+ switch (ssi_id) {
+ case 1:
+ shift = 0;
+@@ -165,16 +167,20 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+ case 2:
+ shift = 2;
+ break;
++ case 3:
+ case 4:
+ shift = 16;
++ sync_34 = 1;
++ mask = (1 << 20);
+ break;
+ }
+
+ if (shift >= 0)
+ rsnd_mod_bset(ssi_mod, SSI_MODE1,
+- 0x3 << shift,
+- rsnd_dai_is_clk_master(rdai) ?
+- 0x2 << shift : 0x1 << shift);
++ (0x3 << shift) | mask,
++ (rsnd_dai_is_clk_master(rdai) ?
++ (0x2 << shift) : (0x1 << shift)) |
++ (sync_34 << 20));
+ }
+
+ /*
+diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
+index 49acffe..a55ac91 100644
+--- a/sound/soc/sh/rcar/ssi.c
++++ b/sound/soc/sh/rcar/ssi.c
+@@ -26,6 +26,10 @@
+ #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
+ #define DIEN (1 << 24) /* Data Interrupt Enable */
+
++#define CHNL_TDM_4 (1 << 22) /* A TDM frame consists of four system words */
++#define CHNL_TDM_6 (2 << 22) /* A TDM frame consists of six system words */
++#define CHNL_TDM_8 (3 << 22) /* A TDM frame consists of eight system words */
++
+ #define DWL_8 (0 << 19) /* Data Word Length */
+ #define DWL_16 (1 << 19) /* Data Word Length */
+ #define DWL_18 (2 << 19) /* Data Word Length */
+@@ -58,6 +62,8 @@
+ * SSIWSR
+ */
+ #define CONT (1 << 8) /* WS Continue Function */
++#define MONO (1 << 1) /* Monaural format */
++#define WS_MODE_TDM (1 << 0) /* TDM format, monaural format */
+
+ #define SSI_NAME "ssi"
+
+@@ -92,6 +98,24 @@ struct rsnd_ssi {
+ #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
+ #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
+
++int rsnd_ssi_is_tdm(struct rsnd_ssi *ssi)
++{
++ return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_TDM_MASK);
++}
++
++int rsnd_ssi_channels(struct rsnd_ssi *ssi)
++{
++ if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_TDM_4)
++ return 4;
++ if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_TDM_6)
++ return 6;
++ if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_TDM_8)
++ return 8;
++
++ /* no TDM */
++ return 2;
++}
++
+ static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
+ {
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+@@ -152,22 +176,32 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+ for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+ /*
++ * divider = 1 not allowed in TDM
++ */
++ if ((ssi_clk_mul_table[j] == 1) &&
++ (rsnd_ssi_is_tdm(ssi)))
++ continue;
++
++ /*
+ * this driver is assuming that
+- * system word is 64fs (= 2 x 32bit)
++ * system word n_channels x 32bit
+ * see rsnd_ssi_init()
+ */
+ main_rate = rate / adg_clk_div_table[i]
+- * 32 * 2 * ssi_clk_mul_table[j];
++ * 32 * rsnd_ssi_channels(ssi) \
++ * ssi_clk_mul_table[j];
+
+ ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
+ if (0 == ret) {
+- ssi->rate = rate;
+- ssi->cr_clk = FORCE | SWL_32 |
+- SCKD | SWSD | CKDV(j);
+-
+ dev_dbg(dev, "ssi%d outputs %u Hz\n",
+ rsnd_mod_id(&ssi->mod), rate);
++ dev_dbg(dev, " div %d, mul %d\n",
++ adg_clk_div_table[i], ssi_clk_mul_table[j]);
+
++
++ ssi->rate = rate;
++ ssi->cr_clk = FORCE | SWL_32 |
++ SCKD | SWSD | CKDV(j);
+ return 0;
+ }
+ }
+@@ -203,10 +237,13 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
+ rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+ }
+
+- if (rsnd_ssi_clk_from_parent(ssi))
++ if (rsnd_ssi_clk_from_parent(ssi)) {
++ /* in TDM mode CKDV=0 is invalid */
++ ssi->cr_clk = CKDV(1);
+ rsnd_ssi_hw_start(ssi->parent, rdai, io);
+- else
++ } else {
+ rsnd_ssi_master_clk_start(ssi, io);
++ }
+ }
+ }
+
+@@ -318,14 +355,44 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
+ * see also rsnd_ssi_master_clk_enable()
+ */
+ cr |= SWL_32;
++ if (rsnd_ssi_is_tdm(ssi)) {
++ switch (rsnd_ssi_channels(ssi)) {
++ case 4:
++ cr |= CHNL_TDM_4;
++ break;
++ case 6:
++ cr |= CHNL_TDM_6;
++ break;
++ case 8:
++ cr |= CHNL_TDM_8;
++ break;
++ default:
++ return -EIO;
++ }
++ }
+
+ /*
+ * init clock settings for SSICR
+ */
+ switch (runtime->sample_bits) {
++ case 8:
++ cr |= DWL_8;
++ break;
+ case 16:
+ cr |= DWL_16;
+ break;
++ case 18:
++ cr |= DWL_18;
++ break;
++ case 20:
++ cr |= DWL_20;
++ break;
++ case 22:
++ cr |= DWL_22;
++ break;
++ case 24:
++ cr |= DWL_24;
++ break;
+ case 32:
+ cr |= DWL_24;
+ break;
+@@ -394,17 +461,47 @@ static int rsnd_ssi_init_irq(struct rsnd_mod *mod,
+ * see also rsnd_ssi_master_clk_enable()
+ */
+ cr |= SWL_32;
++ if (rsnd_ssi_is_tdm(ssi)) {
++ switch (rsnd_ssi_channels(ssi)) {
++ case 4:
++ cr |= CHNL_TDM_4;
++ break;
++ case 6:
++ cr |= CHNL_TDM_6;
++ break;
++ case 8:
++ cr |= CHNL_TDM_8;
++ break;
++ default:
++ return -EIO;
++ }
++ }
+
+ /*
+ * init clock settings for SSICR
+ */
+ switch (runtime->sample_bits) {
++ case 8:
++ cr |= DWL_8;
++ break;
+ case 16:
+ cr |= DWL_16;
+ break;
+- case 32:
++ case 18:
++ cr |= DWL_18;
++ break;
++ case 20:
++ cr |= DWL_20;
++ break;
++ case 22:
++ cr |= DWL_22;
++ break;
++ case 24:
+ cr |= DWL_24;
+ break;
++ case 32:
++ cr |= DWL_32;
++ break;
+ default:
+ return -EIO;
+ }
+@@ -693,9 +790,33 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
+ {
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
++ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
++ u32 wsr = 0;
++
++ /* enable DMA transfer */
++ ssi->cr_etc = DMEN;
++
++ /* enable Overflow and Underflow IRQ */
++ ssi->cr_etc |= UIEN | OIEN;
+
+ rsnd_dma_start(dma);
+
++ rsnd_ssi_hw_start(ssi, ssi->rdai, io);
++
++ rsnd_src_enable_dma_ssi_irq(mod, rdai, rsnd_ssi_use_busif(mod));
++
++ /* enable WS continue */
++ if (rsnd_dai_is_clk_master(rdai))
++ wsr |= CONT;
++
++ /* Enable TDM */
++ if (rsnd_ssi_is_tdm(ssi))
++ wsr |= WS_MODE_TDM;
++
++ rsnd_mod_write(&ssi->mod, SSIWSR, wsr);
++
++ rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
++
+ return 0;
+ }
+
+@@ -916,6 +1036,16 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
+
+ if (of_get_property(np, "no-busif", NULL))
+ ssi_info->flags |= RSND_SSI_NO_BUSIF;
++
++ /*
++ * TDM
++ */
++ if (of_get_property(np, "tdm-4ch", NULL))
++ ssi_info->flags |= RSND_SSI_TDM_4;
++ if (of_get_property(np, "tdm-6ch", NULL))
++ ssi_info->flags |= RSND_SSI_TDM_6;
++ if (of_get_property(np, "tdm-8ch", NULL))
++ ssi_info->flags |= RSND_SSI_TDM_8;
+ }
+
+ rsnd_of_parse_ssi_end:
+--
+2.5.0
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0028-ASoC-rcar-correct-32bit-to-24-bit-sample-conv.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0028-ASoC-rcar-correct-32bit-to-24-bit-sample-conv.patch
new file mode 100644
index 0000000..03bc25f
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0028-ASoC-rcar-correct-32bit-to-24-bit-sample-conv.patch
@@ -0,0 +1,45 @@
+From a6c0cc499acddaae73904ca2ae145c7d461e7f37 Mon Sep 17 00:00:00 2001
+From: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
+Date: Wed, 15 Jun 2016 21:42:20 +0300
+Subject: [PATCH] ASoC: rcar: correct 32bit to 24 bit sample conv
+
+---
+ sound/soc/sh/rcar/src.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
+index bbd7fe5..1fae6c2 100644
+--- a/sound/soc/sh/rcar/src.c
++++ b/sound/soc/sh/rcar/src.c
+@@ -145,6 +145,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+ int use_busif)
+ {
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
++ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ int ssi_id = rsnd_mod_id(ssi_mod);
+
+ /*
+@@ -192,7 +193,20 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+ rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val);
+ rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
+ rsnd_get_adinr(ssi_mod));
+- rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1);
++ /*
++ * Bit Length of Output Audio Data is limited to 24 bits
++ * This hack helps to convert (shift) 32 bit samples
++ * to 24 bit data on i2s bus.
++ * Without this hack sound will be too quiet.
++ * Realy not sure why this happens.
++ */
++ if ((runtime->sample_bits == 32) && (ssi_id == 3))
++ rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1 | (8 << 16));
++ else if ((runtime->sample_bits == 32) && (ssi_id == 4))
++ rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1 | (1 << 20) | (8 << 16));
++ else
++ rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1);
++
+ rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
+ }
+
+--
+2.5.0
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0029-ASoC-R-Car-fix-debug-output.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0029-ASoC-R-Car-fix-debug-output.patch
new file mode 100644
index 0000000..4d94719
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0029-ASoC-R-Car-fix-debug-output.patch
@@ -0,0 +1,57 @@
+From bdd78e5d972ec91b756db6aef0eb19f44207d9f6 Mon Sep 17 00:00:00 2001
+From: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
+Date: Wed, 15 Jun 2016 21:18:35 +0300
+Subject: [PATCH 3/5] ASoC: R-Car: fix debug output
+
+---
+ sound/soc/sh/rcar/adg.c | 2 +-
+ sound/soc/sh/rcar/ssi.c | 12 ++++++++----
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
+index 7d2858c..dbeb6a3 100644
+--- a/sound/soc/sh/rcar/adg.c
++++ b/sound/soc/sh/rcar/adg.c
+@@ -463,7 +463,7 @@ int rsnd_adg_probe(struct platform_device *pdev,
+ adg->clk[CLKI] = devm_clk_get(dev, "clk_i");
+
+ for_each_rsnd_clk(clk, adg, i)
+- dev_dbg(dev, "clk %d : %p\n", i, clk);
++ dev_dbg(dev, "clk %d : %ld\n", i, clk_get_rate(clk));
+
+ #ifdef QUICK_HACK
+ np_root = of_find_node_by_path("/");
+diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
+index a55ac91..a69e621 100644
+--- a/sound/soc/sh/rcar/ssi.c
++++ b/sound/soc/sh/rcar/ssi.c
+@@ -146,7 +146,8 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
+ udelay(50);
+ }
+
+- dev_warn(dev, "status check failed\n");
++ dev_warn(dev, "ssi%d status check failed\n",
++ rsnd_mod_id(mod));
+ }
+
+ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+@@ -431,11 +432,14 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ if (ssi->err > 0)
+- dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
++ dev_warn(dev, "ssi%d under/over flow err = %d\n",
++ rsnd_mod_id(mod), ssi->err);
+ if (ssi->err_uirq > 0)
+- dev_warn(dev, "ssi under flow err = %d\n", ssi->err_uirq);
++ dev_warn(dev, "ssi%d under flow err = %d\n",
++ rsnd_mod_id(mod), ssi->err_uirq);
+ if (ssi->err_oirq > 0)
+- dev_warn(dev, "ssi over flow err = %d\n", ssi->err_oirq);
++ dev_warn(dev, "ssi%d over flow err = %d\n",
++ rsnd_mod_id(mod), ssi->err_oirq);
+
+ ssi->rdai = NULL;
+ ssi->cr_own = 0;
+--
+2.5.0
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0030-R-Car-sound-disable-clock-hack.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0030-R-Car-sound-disable-clock-hack.patch
new file mode 100644
index 0000000..b07d7ce
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0030-R-Car-sound-disable-clock-hack.patch
@@ -0,0 +1,24 @@
+From 9f62d868ad64af881f9dc54471ca0410efe01c2e Mon Sep 17 00:00:00 2001
+From: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
+Date: Wed, 15 Jun 2016 21:19:21 +0300
+Subject: [PATCH 4/5] R-Car: sound: disable clock hack
+
+---
+ sound/soc/sh/rcar/rsnd.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
+index d3b544b..1bbd5bc 100644
+--- a/sound/soc/sh/rcar/rsnd.h
++++ b/sound/soc/sh/rcar/rsnd.h
+@@ -492,7 +492,7 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+
+ #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
+
+-#define QUICK_HACK
++/* #define QUICK_HACK */
+ #ifdef QUICK_HACK
+ void rsnd_adg_clk_set_rate(struct rsnd_mod *mod, unsigned int rate);
+ #endif
+--
+2.5.0
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0031-ASoC-R-car-SSI-fix-SSI-slave-mode-setup-while-TDM-an.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0031-ASoC-R-car-SSI-fix-SSI-slave-mode-setup-while-TDM-an.patch
new file mode 100644
index 0000000..6c469d1
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0031-ASoC-R-car-SSI-fix-SSI-slave-mode-setup-while-TDM-an.patch
@@ -0,0 +1,48 @@
+From 9467d97eaa2ede54dc67a0f83eb3cdd30cf9dc15 Mon Sep 17 00:00:00 2001
+From: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
+Date: Wed, 15 Jun 2016 21:23:03 +0300
+Subject: [PATCH 5/5] ASoC: R-car: SSI fix SSI slave mode setup while TDM and
+
+---
+ sound/soc/sh/rcar/ssi.c | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
+index a69e621..65af590 100644
+--- a/sound/soc/sh/rcar/ssi.c
++++ b/sound/soc/sh/rcar/ssi.c
+@@ -231,17 +231,25 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
+ rsnd_mod_hw_start(&ssi->mod);
+
+ if (rsnd_dai_is_clk_master(rdai)) {
+- /* enable WS continue */
+- if (rsnd_dai_is_clk_master(rdai)) {
+- status = rsnd_mod_read(&ssi->mod, SSIWSR);
+- if (!(status & CONT))
+- rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+- }
+-
+ if (rsnd_ssi_clk_from_parent(ssi)) {
++ int wsr;
+ /* in TDM mode CKDV=0 is invalid */
+ ssi->cr_clk = CKDV(1);
++ if (ssi->parent->usrcnt == 0) {
++ ssi->parent->cr_own = ssi->cr_own;
++
++ /* enable WS continue */
++ wsr = CONT;
++
++ /* Enable TDM */
++ if (rsnd_ssi_is_tdm(ssi))
++ wsr |= WS_MODE_TDM;
++ }
+ rsnd_ssi_hw_start(ssi->parent, rdai, io);
++ /* set WSR after master mode is set in CR */
++ if (wsr)
++ rsnd_mod_write(&ssi->parent->mod, SSIWSR, wsr);
++
+ } else {
+ rsnd_ssi_master_clk_start(ssi, io);
+ }
+--
+2.5.0
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0032-mmc-Add-SDIO-function-devicetree-subnode-parsing.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0032-mmc-Add-SDIO-function-devicetree-subnode-parsing.patch
new file mode 100644
index 0000000..a95c7bc
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0032-mmc-Add-SDIO-function-devicetree-subnode-parsing.patch
@@ -0,0 +1,160 @@
+From 882ed046c6383564f09c89a7c53e28a37373fffc Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Mon, 30 Jun 2014 11:07:25 +0200
+Subject: [PATCH 32/33] mmc: Add SDIO function devicetree subnode parsing
+
+This adds SDIO devicetree subnode parsing to the mmc core. While
+SDIO devices are runtime probable they sometimes need nonprobable
+additional information on embedded systems, like an additional gpio
+interrupt or a clock. This patch makes it possible to supply this
+information from the devicetree. SDIO drivers will find a pointer
+to the devicenode in their devices of_node pointer.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+[hdegoede@redhat.com: Misc. cleanups]
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/mmc/core/bus.c | 4 ++++
+ drivers/mmc/core/core.c | 29 +++++++++++++++++++++++++++++
+ drivers/mmc/core/core.h | 3 +++
+ drivers/mmc/core/sdio_bus.c | 11 +++++++++++
+ 4 files changed, 47 insertions(+)
+
+diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
+index 419edfa..87049c6 100644
+--- a/drivers/mmc/core/bus.c
++++ b/drivers/mmc/core/bus.c
+@@ -16,6 +16,7 @@
+ #include <linux/err.h>
+ #include <linux/slab.h>
+ #include <linux/stat.h>
++#include <linux/of.h>
+ #include <linux/pm_runtime.h>
+
+ #include <linux/mmc/card.h>
+@@ -335,6 +336,8 @@ int mmc_add_card(struct mmc_card *card)
+ #endif
+ mmc_init_context_info(card->host);
+
++ card->dev.of_node = mmc_of_find_child_device(card->host, 0);
++
+ ret = device_add(&card->dev);
+ if (ret)
+ return ret;
+@@ -363,6 +366,7 @@ void mmc_remove_card(struct mmc_card *card)
+ mmc_hostname(card->host), card->rca);
+ }
+ device_del(&card->dev);
++ of_node_put(card->dev.of_node);
+ }
+
+ put_device(&card->dev);
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 02a40d0..8c85f20a 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -27,6 +27,7 @@
+ #include <linux/fault-inject.h>
+ #include <linux/random.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
+
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+@@ -1165,6 +1166,34 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
+ }
+ EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
+
++static int mmc_of_get_func_num(struct device_node *node)
++{
++ u32 reg;
++ int ret;
++
++ ret = of_property_read_u32(node, "reg", &reg);
++ if (ret < 0)
++ return ret;
++
++ return reg;
++}
++
++struct device_node *mmc_of_find_child_device(struct mmc_host *host,
++ unsigned func_num)
++{
++ struct device_node *node;
++
++ if (!host->parent || !host->parent->of_node)
++ return NULL;
++
++ for_each_child_of_node(host->parent->of_node, node) {
++ if (mmc_of_get_func_num(node) == func_num)
++ return node;
++ }
++
++ return NULL;
++}
++
+ #ifdef CONFIG_REGULATOR
+
+ /**
+diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
+index b9f18a2..6b01037 100644
+--- a/drivers/mmc/core/core.h
++++ b/drivers/mmc/core/core.h
+@@ -30,6 +30,9 @@ struct mmc_bus_ops {
+ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
+ void mmc_detach_bus(struct mmc_host *host);
+
++struct device_node *mmc_of_find_child_device(struct mmc_host *host,
++ unsigned func_num);
++
+ void mmc_init_erase(struct mmc_card *card);
+
+ void mmc_set_chip_select(struct mmc_host *host, int mode);
+diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
+index 6d67492..b5d8af0 100644
+--- a/drivers/mmc/core/sdio_bus.c
++++ b/drivers/mmc/core/sdio_bus.c
+@@ -21,7 +21,9 @@
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+ #include <linux/mmc/sdio_func.h>
++#include <linux/of.h>
+
++#include "core.h"
+ #include "sdio_cis.h"
+ #include "sdio_bus.h"
+
+@@ -312,6 +314,13 @@ static void sdio_acpi_set_handle(struct sdio_func *func)
+ static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
+ #endif
+
++static void sdio_set_of_node(struct sdio_func *func)
++{
++ struct mmc_host *host = func->card->host;
++
++ func->dev.of_node = mmc_of_find_child_device(host, func->num);
++}
++
+ /*
+ * Register a new SDIO function with the driver model.
+ */
+@@ -321,6 +330,7 @@ int sdio_add_func(struct sdio_func *func)
+
+ dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
+
++ sdio_set_of_node(func);
+ sdio_acpi_set_handle(func);
+ ret = device_add(&func->dev);
+ if (ret == 0) {
+@@ -344,6 +354,7 @@ void sdio_remove_func(struct sdio_func *func)
+
+ acpi_dev_pm_detach(&func->dev, false);
+ device_del(&func->dev);
++ of_node_put(func->dev.of_node);
+ put_device(&func->dev);
+ }
+
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0038-Porter-LVDS-display-LQ123K1LG03.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0038-Porter-LVDS-display-LQ123K1LG03.patch
new file mode 100644
index 0000000..98011f8
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0038-Porter-LVDS-display-LQ123K1LG03.patch
@@ -0,0 +1,48 @@
+From b5d05aa9f2995276fd00213e6a48842292aa5889 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Sat, 21 Mar 2015 20:07:20 +0300
+Subject: [PATCH] Porter LVDS display LQ123K1LG03
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ arch/arm/mach-shmobile/board-porter-reference.c | 23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+diff --git a/arch/arm/mach-shmobile/board-porter-reference.c b/arch/arm/mach-shmobile/board-porter-reference.c
+index d481ecd..6a1110c 100644
+--- a/arch/arm/mach-shmobile/board-porter-reference.c
++++ b/arch/arm/mach-shmobile/board-porter-reference.c
+@@ -64,18 +64,19 @@ static struct rcar_du_encoder_data porter_du_encoders[] = {
+ .type = RCAR_DU_ENCODER_NONE,
+ .output = RCAR_DU_OUTPUT_LVDS0,
+ .connector.lvds.panel = {
+- .width_mm = 229,
+- .height_mm = 149,
++ .width_mm = 291,
++ .height_mm = 109,
++ //.lvds_mode = 4,
+ .mode = {
+- .clock = 69000,
+- .hdisplay = 1280,
+- .hsync_start = 1280 + 48,
+- .hsync_end = 1280 + 48 + 32,
+- .htotal = 1280 + 48 + 32 + 80,
+- .vdisplay = 800,
+- .vsync_start = 800 + 2,
+- .vsync_end = 800 + 2 + 6,
+- .vtotal = 800 + 2 + 6 + 15,
++ .clock = 53000,
++ .hdisplay = 1280,
++ .hsync_start = 1280,
++ .hsync_end = 1688,
++ .htotal = 1688,
++ .vdisplay = 480,
++ .vsync_start = 480,
++ .vsync_end = 525,
++ .vtotal = 525,
+ .flags = 0,
+ },
+ },
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0060-Remove-delay-at-LVDS-camera-initialization.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0060-Remove-delay-at-LVDS-camera-initialization.patch
new file mode 100644
index 0000000..7f29f64
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0060-Remove-delay-at-LVDS-camera-initialization.patch
@@ -0,0 +1,25 @@
+From 4347453d644e81c81317ce256340a3193c129e6a Mon Sep 17 00:00:00 2001
+From: Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>
+Date: Wed, 13 Apr 2016 13:26:25 +0300
+Subject: [PATCH] Remove delay at LVDS camera initialization
+
+Signed-off-by: Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9272_ov10635.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9272_ov10635.h b/drivers/media/i2c/soc_camera/max9272_ov10635.h
+index 80e9af4..49f4d29 100644
+--- a/drivers/media/i2c/soc_camera/max9272_ov10635.h
++++ b/drivers/media/i2c/soc_camera/max9272_ov10635.h
+@@ -31,7 +31,7 @@
+ #define MAXIM_IMI_MCU_V0_DELAY 8000 /* delay for powered MCU firmware v0 */
+ #define MAXIM_IMI_MCU_V1_DELAY 3000 /* delay for powered MCU firmware v1 */
+ #define MAXIM_IMI_MCU_NO_DELAY 0 /* delay for unpowered MCU */
+-#define MAXIM_IMI_MCU_DELAY MAXIM_IMI_MCU_V0_DELAY
++#define MAXIM_IMI_MCU_DELAY MAXIM_IMI_MCU_NO_DELAY
+ //#define MAXIM_IMI_MCU_POWERED /* skip ov10635 setup for IMI powered MCU (only fw later then v1) */
+
+ /*
+--
+2.1.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0099-Porter-add-separate-dts-for-ext01-extension-board.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0099-Porter-add-separate-dts-for-ext01-extension-board.patch
new file mode 100644
index 0000000..d2cac49
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0099-Porter-add-separate-dts-for-ext01-extension-board.patch
@@ -0,0 +1,805 @@
+From ed11e08a736ac8fcdfdcc45b13d68cd688aacd73 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Mon, 23 May 2016 19:48:54 +0300
+Subject: [PATCH] Porter: add separate dts for ext01 extension board
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/r8a7791-porter-ext01.dts | 772 ++++++++++++++++++++++++++++
+ 2 files changed, 773 insertions(+)
+ create mode 100644 arch/arm/boot/dts/r8a7791-porter-ext01.dts
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 5e951fb..68c86f8 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -231,6 +231,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
+ # R-Car Gen2 AVB variants
+ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
+ r8a7791-koelsch-eavb.dtb \
++ r8a7791-porter-ext01.dtb \
+ r8a7791-porter-eavb.dtb \
+ r8a7790-lager-eavb.dtb
+
+diff --git a/arch/arm/boot/dts/r8a7791-porter-ext01.dts b/arch/arm/boot/dts/r8a7791-porter-ext01.dts
+new file mode 100644
+index 0000000..d115b36
+--- /dev/null
++++ b/arch/arm/boot/dts/r8a7791-porter-ext01.dts
+@@ -0,0 +1,772 @@
++/*
++ * Device Tree Source for the Porter board
++ *
++ * Copyright (C) 2015 Renesas Electronics Corporation
++ * Copyright (C) 2015 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++/*
++ * SSI-AK4642
++ *
++ * these commands are required when playback.
++ *
++ * # amixer set "LINEOUT Mixer DACL" on
++ * # amixer set "Digital" 200
++ * # amixer set "DVC Out" 50
++ */
++
++/dts-v1/;
++#include "r8a7791.dtsi"
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++
++/ {
++ model = "Porter";
++ compatible = "renesas,porter", "renesas,r8a7791";
++
++ aliases {
++ serial6 = &scif0;
++ serial7 = &scifa4;
++ serial8 = &scifb2;
++ serial9 = &scif1;
++ };
++
++ chosen {
++ bootargs = "console=ttySC6,38400 ignore_loglevel ip=none rw root=/dev/mmcblk0p1 vmalloc=384M";
++ };
++
++ memory@40000000 {
++ device_type = "memory";
++ reg = <0 0x40000000 0 0x40000000>;
++ };
++
++ memory@200000000 {
++ device_type = "memory";
++ reg = <2 0x00000000 0 0x40000000>;
++ };
++
++
++ snd_clk: snd_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <24576000>;
++ clock-output-names = "scki";
++ };
++
++ leds {
++ compatible = "gpio-leds";
++ led2 {
++ gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
++ };
++ led3 {
++ gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
++ };
++ led4 {
++ gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++
++ button@1 {
++ linux,code = <KEY_1>;
++ label = "SW2-1";
++ gpio-key,wakeup;
++ debounce-interval = <20>;
++ gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
++ };
++ button@2 {
++ linux,code = <KEY_2>;
++ label = "SW2-2";
++ gpio-key,wakeup;
++ debounce-interval = <20>;
++ gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ vccq_sdhi0: regulator@1 {
++ compatible = "regulator-gpio";
++
++ regulator-name = "SDHI0 VccQ";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ gpios-states = <1>;
++ states = <3300000 1
++ 1800000 0>;
++ };
++
++ vcc_sdhi2: regulator@2 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "SDHI2 Vcc";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ vccq_sdhi2: regulator@3 {
++ compatible = "regulator-gpio";
++
++ regulator-name = "SDHI2 VccQ";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++
++ gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
++ gpios-states = <1>;
++ states = <3300000 1
++ 1800000 0>;
++ };
++
++ codec_en_reg: regulator@4 {
++ compatible = "regulator-fixed";
++ regulator-name = "codec-en-regulator";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++
++ /* SND_RST GPIO for this board is CPLD gpio 0 */
++ gpio = <&cpld_gpio 0 0>;
++
++ /* delay - CHECK */
++ startup-delay-us = <70000>;
++ enable-active-high;
++ };
++
++ amp_en_reg: regulator@5 {
++ compatible = "regulator-fixed";
++ regulator-name = "amp-en-regulator";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++
++ /* Phones amps en GPIO for this board is CPLD gpio 1 */
++ gpio = <&cpld_gpio 1 0>;
++
++ startup-delay-us = <0>;
++ enable-active-high;
++ };
++
++ wlan_en_reg: regulator@6 {
++ compatible = "regulator-fixed";
++ regulator-name = "wlan-en-regulator";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++
++ /* WLAN_EN GPIO for this board CPLD gpio 10 */
++ gpio = <&cpld_gpio 10 0>;
++
++ /* WLAN card specific delay */
++ startup-delay-us = <70000>;
++ enable-active-high;
++ };
++
++ kim {
++ compatible = "kim";
++ nshutdown_gpio = <769>; /* FIX! CPLD pin 11 */
++ /* serial8 */
++ dev_name = "/dev/ttySC8";
++ flow_cntrl = <1>;
++ /* maximum clock on scifb@52MHz */
++ baud_rate = <3250000>;
++ };
++
++ btwilink {
++ compatible = "btwilink";
++ };
++
++ sound_ext: sound@0 {
++ compatible = "simple-audio-card";
++ pinctrl-0 = <&sound_0_pins>;
++ pinctrl-names = "default";
++
++ simple-audio-card,format = "left_j";
++ simple-audio-card,name = "pcm3168a";
++
++ simple-audio-card,bitclock-master = <&sound_ext_master>;
++ simple-audio-card,frame-master = <&sound_ext_master>;
++ sound_ext_master: simple-audio-card,cpu@0 {
++ sound-dai = <&rcar_sound 0>;
++ dai-tdm-slot-num = <8>;
++ dai-tdm-slot-width = <32>;
++ };
++
++ simple-audio-card,codec@0 {
++ sound-dai = <&pcm3168a>;
++ dai-tdm-slot-num = <8>;
++ dai-tdm-slot-width = <32>;
++ system-clock-frequency = <24576000>;
++ };
++ };
++
++ sound_onboard: sound@1 {
++ compatible = "simple-audio-card";
++ pinctrl-0 = <&sound_1_pins>;
++ pinctrl-names = "default";
++
++ simple-audio-card,format = "i2s";
++ simple-audio-card,name = "ak464x";
++
++ sndcpu_0: simple-audio-card,cpu@1 {
++ sound-dai = <&rcar_sound 1>;
++ };
++
++ sndcodec_0: simple-audio-card,codec@1 {
++ sound-dai = <&ak4642>;
++ system-clock-frequency = <11289600>;
++ };
++ };
++
++ sound_radio: sound@2 {
++ compatible = "simple-audio-card";
++ pinctrl-0 = <&sound_2_pins>;
++ pinctrl-names = "default";
++
++ simple-audio-card,format = "i2s";
++ simple-audio-card,name = "radio";
++
++ simple-audio-card,bitclock-master = <&sound_radio_master>;
++ simple-audio-card,frame-master = <&sound_radio_master>;
++ simple-audio-card,cpu@2 {
++ sound-dai = <&rcar_sound 2>;
++ };
++
++ sound_radio_master: simple-audio-card,codec@2 {
++ sound-dai = <&radio>;
++ system-clock-frequency = <12288000>;
++ };
++ };
++
++ hdmi_transmitter: adv7511 {
++ compatible = "adi,adv7511";
++ gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
++
++ adi,input-style = <0x02>;
++ adi,input-id = <0x00>;
++ adi,input-color-depth = <0x03>;
++ adi,sync-pulse = <0x03>;
++ adi,bit-justification = <0x01>;
++ adi,up-conversion = <0x00>;
++ adi,timing-generation-sequence = <0x00>;
++ adi,vsync-polarity = <0x02>;
++ adi,hsync-polarity = <0x02>;
++ adi,clock-delay = <0x03>;
++ };
++
++ usbhs_udc {
++ gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>;
++ };
++
++ i2c0_gpio0: i2c@0 {
++ status = "ok";
++ clock-frequency = <400000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "i2c-gpio";
++ gpios = <&gpio6 9 GPIO_ACTIVE_HIGH /* sda */
++ &gpio7 2 GPIO_ACTIVE_HIGH /* scl */
++ >;
++ i2c-gpio,delay-us = <50>;
++
++ maxim_setup@10 {
++ compatible = "maxim,max9272-ov10635-setup";
++ reg = <0x10>; /* fake address */
++ gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
++ cpld_gpio: cpld {
++ compatible = "porter-cpld-gpio";
++ #gpio-cells = <2>;
++
++ porter-cpld-gpio,data-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
++ porter-cpld-gpio,ptrc-gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>;
++ porter-cpld-gpio,bufc-gpio = <&gpio7 5 GPIO_ACTIVE_HIGH>;
++ };
++
++ i2c0_gpio1: i2c@1 {
++ status = "ok";
++ clock-frequency = <400000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "i2c-gpio";
++ gpios = <&gpio4 31 GPIO_ACTIVE_HIGH /* sda */
++ &gpio1 24 GPIO_ACTIVE_HIGH /* scl */
++ >;
++ i2c-gpio,delay-us = <2>; /* ~100 KHz */
++ };
++
++ spi_gpio: spi@0 {
++ compatible = "spi-gpio";
++ status = "okay";
++ gpio-sck = <&gpio4 30 0>;
++ gpio-mosi = <&gpio2 30 0>;
++ gpio-miso = <&gpio7 19 0>;
++ cs-gpios = <&gpio2 18 0>;
++ num-chipselects = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ si4689: si4689@0 {
++ compatible = "si,468x";
++ reg = <0>;
++ spi-max-frequency = <10000000>;
++ };
++ };
++
++ radio: si468x@0 {
++ compatible = "si,si468x-pcm";
++ status = "okay";
++
++ #sound-dai-cells = <0>;
++ };
++};
++
++&extal_clk {
++ clock-frequency = <20000000>;
++};
++
++&pfc {
++ pinctrl-0 = <&du_pins &usb0_pins &usb1_pins &vin0_pins &vin2_pins>;
++ pinctrl-names = "default";
++
++ du_pins: du {
++ renesas,groups = "du_rgb666", "du_sync", "du_clk_out_0";
++ renesas,function = "du";
++ };
++
++ scif0_pins: serial6 {
++ renesas,groups = "scif0_data_d";
++ renesas,function = "scif0";
++ };
++
++ scif1_pins: serial9 {
++ renesas,groups = "scif1_data_d";
++ renesas,function = "scif1";
++ };
++
++ scifa4_pins: serial7 {
++ renesas,groups = "scifa4_data";
++ renesas,function = "scifa4";
++ };
++
++ scifb2_pins: serial8 {
++ renesas,groups = "scifb2_data", "scifb2_ctrl";
++ renesas,function = "scifb2";
++ };
++
++ i2c1_pins: i2c1 {
++ renesas,groups = "i2c1_e";
++ renesas,function = "i2c1";
++ };
++
++ i2c2_pins: i2c2 {
++ renesas,groups = "i2c2";
++ renesas,function = "i2c2";
++ };
++
++ i2c4_pins: i2c4 {
++ renesas,groups = "i2c4_c";
++ renesas,function = "i2c4";
++ };
++
++ ether_pins: ether {
++ renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
++ renesas,function = "eth";
++ };
++
++ avb_pins: avb {
++ renesas,groups = "avb_mdio", "avb_gmii";
++ renesas,function = "avb";
++ };
++
++ mlb3_pins: mlp {
++ renesas,groups = "mlb3pin";
++ renesas,function = "mlb3pin";
++ };
++
++ phy1_pins: phy1 {
++ renesas,groups = "intc_irq0";
++ renesas,function = "intc";
++ };
++
++ sdhi0_pins: sd0 {
++ renesas,groups = "sdhi0_data4", "sdhi0_ctrl";
++ renesas,function = "sdhi0";
++ };
++
++ sdhi2_pins: sd2 {
++ renesas,groups = "sdhi2_data4", "sdhi2_ctrl";
++ renesas,function = "sdhi2";
++ };
++
++ qspi_pins: spi0 {
++ renesas,groups = "qspi_ctrl", "qspi_data4";
++ renesas,function = "qspi";
++ };
++
++ msiof0_pins: spi1 {
++ renesas,groups = "msiof0_clk", "msiof0_sync", "msiof0_rx",
++ "msiof0_tx";
++ renesas,function = "msiof0";
++ };
++
++ sound_clk_pins: sound_clk {
++ renesas,groups = "audio_clk_b_b";
++ renesas,function = "audio_clk";
++ };
++
++ sound_0_pins: sound1 {
++ renesas,groups = "ssi34_ctrl", "ssi3_data", "ssi4_data";
++ renesas,function = "ssi";
++ };
++
++ sound_1_pins: sound0 {
++ renesas,groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data";
++ renesas,function = "ssi";
++ };
++
++ sound_2_pins: sound2 {
++ renesas,groups = "ssi5_ctrl", "ssi5_data";
++ renesas,function = "ssi";
++ };
++
++ usb0_pins: usb0 {
++ renesas,groups = "usb0";
++ renesas,function = "usb0";
++ };
++
++ usb1_pins: usb1 {
++ renesas,groups = "usb1";
++ renesas,function = "usb1";
++ };
++
++ vin0_pins: vin0 {
++ renesas,groups = "vin0_data8", "vin0_clk";
++ renesas,function = "vin0";
++ };
++
++ vin2_pins: vin2 {
++ renesas,groups = "vin2_data8", "vin2_clk";
++ renesas,function = "vin2";
++ };
++
++ can0_pins: can0 {
++ renesas,groups = "can0_data_b";
++ renesas,function = "can0";
++ };
++};
++
++&ether {
++ pinctrl-0 = <&ether_pins &phy1_pins>;
++ pinctrl-names = "default";
++
++ phy-handle = <&phy1>;
++ renesas,ether-link-active-low;
++ status = "disabled";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ interrupt-parent = <&irqc0>;
++ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++ micrel,led-mode = <1>;
++ };
++};
++
++&can0 {
++ pinctrl-0 = <&can0_pins>;
++ pinctrl-names = "default";
++ renesas,can-clock-select = <0x0>;
++ status = "okay";
++};
++
++&avb {
++ pinctrl-0 = <&avb_pins>;
++ pinctrl-names = "default";
++
++ renesas,no-ether-link;
++ renesas,phy = <0>;
++ renesas,mii-lite-ignore-pins = <&gpio5 25 0
++ &gpio5 24 0
++ &gpio5 23 0
++ &gpio5 22 0
++ &gpio5 7 0
++ &gpio5 8 0
++ &gpio5 6 0
++ &gpio5 5 0
++ &gpio5 4 0
++ &gpio5 17 0
++ &gpio5 11 0
++ &gpio5 30 0
++ &gpio5 27 0>;
++ phy-int-gpio = <&gpio5 16 GPIO_ACTIVE_LOW>;
++ status = "okay";
++};
++
++&sata0 {
++ status = "okay";
++};
++
++&scif0 {
++ pinctrl-0 = <&scif0_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&scif1 {
++ pinctrl-0 = <&scif1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&scifa4 {
++ pinctrl-0 = <&scifa4_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&scifb2 {
++ pinctrl-0 = <&scifb2_pins>;
++ pinctrl-names = "default";
++ ctsrts;
++
++ status = "okay";
++};
++
++&sdhi0 {
++ pinctrl-0 = <&sdhi0_pins>;
++ pinctrl-names = "default";
++
++ vmmc-supply = <&wlan_en_reg>;
++ vqmmc-supply = <&vccq_sdhi0>;
++
++ keep-power-in-suspend;
++ enable-sdio-wakeup;
++ non-removable;
++ cap-power-off-card;
++ status = "okay";
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wlcore: wlcore@0 {
++ compatible = "ti,wl1837";
++ reg = <2>;
++ /* GP6_12 */
++ interrupt-parent = <&gpio6>;
++ interrupts = <12 IRQ_TYPE_EDGE_RISING>;
++ platform-quirks = <1>;
++ };
++};
++
++&sdhi2 {
++ pinctrl-0 = <&sdhi2_pins>;
++ pinctrl-names = "default";
++
++ vmmc-supply = <&vcc_sdhi2>;
++ vqmmc-supply = <&vccq_sdhi2>;
++ cd-gpios = <&gpio6 22 GPIO_ACTIVE_LOW>;
++ toshiba,mmc-wrprotect-disable;
++ status = "okay";
++};
++
++&qspi {
++ pinctrl-0 = <&qspi_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ flash: flash@0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "spansion,s25fl512s";
++ reg = <0>;
++ spi-max-frequency = <30000000>;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ m25p,fast-read;
++ spi-cpol;
++ spi-cpha;
++
++ partition@0 {
++ label = "loader";
++ reg = <0x00000000 0x00040000>;
++ read-only;
++ };
++ partition@40000 {
++ label = "user";
++ reg = <0x00040000 0x00400000>;
++ read-only;
++ };
++ partition@440000 {
++ label = "flash";
++ reg = <0x00440000 0x03bc0000>;
++ };
++ };
++};
++
++&msiof0 {
++ pinctrl-0 = <&msiof0_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&i2c1 {
++ pinctrl-0 = <&i2c1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++ clock-frequency = <400000>;
++};
++
++&i2c2 {
++ pinctrl-0 = <&i2c2_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++ clock-frequency = <400000>;
++
++ eeprom@50 {
++ compatible = "renesas,24c02";
++ reg = <0x50>;
++ pagesize = <16>;
++ };
++
++ ak4642: sound-codec@12 {
++ #sound-dai-cells = <0>;
++ compatible = "asahi-kasei,ak4642";
++ reg = <0x12>;
++ };
++};
++
++&i2c4 {
++ pinctrl-0 = <&i2c4_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++ clock-frequency = <400000>;
++};
++
++&i2c5 {
++ status = "okay";
++ clock-frequency = <400000>;
++
++ lsm9ds0_acc_mag@1d {
++ compatible = "st,lsm9ds0_acc_mag";
++ reg = <0x1d>;
++ };
++
++ lsm9ds0_gyr@6b {
++ compatible = "st,lsm9ds0_gyr";
++ reg = <0x6b>;
++ };
++
++ pcm3168a: audio-codec@44 {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm3168a";
++ reg = <0x44>;
++ clocks = <&snd_clk>;
++ clock-names = "scki";
++ tdm;
++ VDD1-supply = <&codec_en_reg>;
++ VDD2-supply = <&codec_en_reg>;
++ VCCAD1-supply = <&codec_en_reg>;
++ VCCAD2-supply = <&codec_en_reg>;
++ VCCDA1-supply = <&amp_en_reg>;
++ VCCDA2-supply = <&amp_en_reg>;
++ };
++};
++
++&i2c6 {
++ status = "okay";
++ clock-frequency = <100000>;
++
++ vdd_dvfs: regulator@68 {
++ compatible = "diasemi,da9210";
++ reg = <0x68>;
++
++ regulator-min-microvolt = <1000000>;
++ regulator-max-microvolt = <1000000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++};
++
++&mlp {
++ pinctrl-names = "default";
++ pinctrl-0 = <&mlb3_pins>;
++ status = "okay";
++};
++
++&pci0 {
++ status = "okay";
++ pinctrl-0 = <&usb0_pins>;
++ pinctrl-names = "default";
++};
++
++&pci1 {
++ status = "okay";
++ pinctrl-0 = <&usb1_pins>;
++ pinctrl-names = "default";
++};
++
++&pcie_bus_clk {
++ status = "okay";
++};
++
++&pciec {
++ status = "okay";
++};
++
++&cpu0 {
++ cpu0-supply = <&vdd_dvfs>;
++};
++
++&rcar_sound {
++ #sound-dai-cells = <1>;
++ pinctrl-0 = <&sound_clk_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++
++ rcar_sound,dai {
++ dai0 {
++ playback = <&ssi3>;
++ capture = <&ssi4>;
++ };
++
++ dai1 {
++ playback = <&ssi0 &src0 &dvc0>;
++ capture = <&ssi1 &src1 &dvc1>;
++ };
++
++ dai2 {
++ capture = <&ssi5>;
++ };
++ };
++};
++
++&ssi1 {
++ shared-pin;
++};
++
++&ssi3 {
++ tdm-8ch;
++ shared-pin;
++};
++
++&ssi4 {
++ tdm-8ch;
++ shared-pin;
++};
++
++&audio_clk_b {
++ clock-frequency = <24576000>;
++};
+--
+1.7.10.4
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0100-Porter-ext01-add-dummy-regulator-to-select-48000-sou.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0100-Porter-ext01-add-dummy-regulator-to-select-48000-sou.patch
new file mode 100644
index 0000000..36313c3
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter/0100-Porter-ext01-add-dummy-regulator-to-select-48000-sou.patch
@@ -0,0 +1,53 @@
+From f682ff4fc2efe30131e683acd2924b7f6ce72735 Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 2 Jun 2016 13:44:14 +0300
+Subject: [PATCH] Porter-ext01: add dummy regulator to select 48000 sound
+ clock
+
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ arch/arm/boot/dts/r8a7791-porter-ext01.dts | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/boot/dts/r8a7791-porter-ext01.dts b/arch/arm/boot/dts/r8a7791-porter-ext01.dts
+index d115b36..62c6417 100644
+--- a/arch/arm/boot/dts/r8a7791-porter-ext01.dts
++++ b/arch/arm/boot/dts/r8a7791-porter-ext01.dts
+@@ -151,7 +151,24 @@
+ enable-active-high;
+ };
+
+- wlan_en_reg: regulator@6 {
++ codec_en_reg_2: regulator@6 {
++ compatible = "regulator-fixed";
++ regulator-name = "audio-clock-set";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++
++ /*
++ * This regulator will just set clock switch to
++ * select 24.576MHz as audio_clk_b
++ * TODO: add clock switch support
++ */
++ gpio = <&cpld_gpio 7 0>;
++
++ startup-delay-us = <0>;
++ enable-active-high;
++ };
++
++ wlan_en_reg: regulator@7 {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan-en-regulator";
+ regulator-min-microvolt = <1800000>;
+@@ -676,7 +693,7 @@
+ clock-names = "scki";
+ tdm;
+ VDD1-supply = <&codec_en_reg>;
+- VDD2-supply = <&codec_en_reg>;
++ VDD2-supply = <&codec_en_reg_2>;
+ VCCAD1-supply = <&codec_en_reg>;
+ VCCAD2-supply = <&codec_en_reg>;
+ VCCDA1-supply = <&amp_en_reg>;
+--
+1.7.10.4