diff options
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas/porter')
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", ®); ++ 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"; ++ }; ++}; ++ ++ðer { ++ pinctrl-0 = <ðer_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 = <&_en_reg>; ++ VCCDA2-supply = <&_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 = <&_en_reg>; +-- +1.7.10.4 |