diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch | 801 |
1 files changed, 0 insertions, 801 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch b/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch deleted file mode 100644 index 6b9a6bd29c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch +++ /dev/null @@ -1,801 +0,0 @@ -From 221b442eb7e5b4ed16151b5501f4b905a9b8455c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= - <j-schambacher@users.noreply.github.com> -Date: Tue, 21 Jan 2020 15:58:39 +0100 -Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version - -This adds the driver for the DAC+HD version supporting HiFiBerry's -PCM179x based DACs. It also adds PLL control for clock generation. - -Signed-off-by: Joerg Schambacher <joerg@i2audio.com> ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 6 + - .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++ - drivers/clk/Kconfig | 3 + - drivers/clk/Makefile | 1 + - drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++ - sound/soc/bcm/Kconfig | 9 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_dacplushd.c | 238 +++++++++++++ - 14 files changed, 704 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts - create mode 100644 drivers/clk/clk-hifiberry-dachd.c - create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - hifiberry-dacplusadc.dtbo \ - hifiberry-dacplusadcpro.dtbo \ - hifiberry-dacplusdsp.dtbo \ -+ hifiberry-dacplushd.dtbo \ - hifiberry-digi.dtbo \ - hifiberry-digi-pro.dtbo \ - hy28a.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp - Params: <None> - - -+Name: hifiberry-dacplushd -+Info: Configures the HifiBerry DAC+ HD audio card -+Load: dtoverlay=hifiberry-dacplushd -+Params: <None> -+ -+ - Name: hifiberry-digi - Info: Configures the HifiBerry Digi and Digi+ audio card - Load: dtoverlay=hifiberry-digi ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -@@ -0,0 +1,106 @@ -+// Definitions for HiFiBerry DAC+ HD -+/dts-v1/; -+/plugin/; -+ -+#include <dt-bindings/gpio/gpio.h> -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target-path = "/clocks"; -+ __overlay__ { -+ dachd_osc: pll_dachd_osc { -+ compatible = "hifiberry,dachd-clk"; -+ #clock-cells = <0>; -+ }; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&i2s>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&i2c1>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ pcm1792a@4c { -+ compatible = "ti,pcm1792a"; -+ #sound-dai-cells = <0>; -+ #clock-cells = <0>; -+ clocks = <&dachd_osc>; -+ reg = <0x4c>; -+ status = "okay"; -+ }; -+ pll: pll@62 { -+ compatible = "hifiberry,dachd-clk"; -+ #clock-cells = <0>; -+ reg = <0x62>; -+ clocks = <&dachd_osc>; -+ status = "okay"; -+ common_pll_regs = [ -+ 02 53 03 00 07 20 0F 00 -+ 10 0D 11 1D 12 0D 13 8C -+ 14 8C 15 8C 16 8C 17 8C -+ 18 2A 1C 00 1D 0F 1F 00 -+ 2A 00 2C 00 2F 00 30 00 -+ 31 00 32 00 34 00 37 00 -+ 38 00 39 00 3A 00 3B 01 -+ 3E 00 3F 00 40 00 41 00 -+ 5A 00 5B 00 95 00 96 00 -+ 97 00 98 00 99 00 9A 00 -+ 9B 00 A2 00 A3 00 A4 00 -+ B7 92 ]; -+ 192k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 22 36 80 3C 22 -+ 3D 46 ]; -+ 96k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 47 36 00 3C 32 -+ 3D 46 ]; -+ 48k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 90 36 00 3C 42 -+ 3D 46 ]; -+ 176k4_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 02 35 25 36 C0 3C 22 -+ 3D 7A ]; -+ 88k2_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 01 35 4D 36 80 3C 32 -+ 3D 7A ]; -+ 44k1_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 01 35 9D 36 00 3C 42 -+ 3D 7A ]; -+ }; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "hifiberry,hifiberry-dacplushd"; -+ i2s-controller = <&i2s>; -+ clocks = <&pll 0>; -+ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>; -+ status = "okay"; -+ }; -+ }; -+ -+}; ---- a/drivers/clk/Kconfig -+++ b/drivers/clk/Kconfig -@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X - multi-function device has one fixed-rate oscillator, clocked - at 32KHz. - -+config COMMON_CLK_HIFIBERRY_DACPLUSHD -+ tristate -+ - config COMMON_CLK_HIFIBERRY_DACPRO - tristate - ---- a/drivers/clk/Makefile -+++ b/drivers/clk/Makefile -@@ -36,6 +36,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-high - obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o - obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o - obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o -+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o - obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o - obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o - obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o ---- /dev/null -+++ b/drivers/clk/clk-hifiberry-dachd.c -@@ -0,0 +1,333 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Clock Driver for HiFiBerry DAC+ HD -+ * -+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry -+ * Copyright 2020 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include <linux/clk-provider.h> -+#include <linux/clk.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/slab.h> -+#include <linux/platform_device.h> -+#include <linux/i2c.h> -+#include <linux/regmap.h> -+ -+#define NO_PLL_RESET 0 -+#define PLL_RESET 1 -+#define HIFIBERRY_PLL_MAX_REGISTER 256 -+#define DEFAULT_RATE 44100 -+ -+static struct reg_default hifiberry_pll_reg_defaults[] = { -+ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00}, -+ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C}, -+ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C}, -+ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00}, -+ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00}, -+ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00}, -+ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01}, -+ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00}, -+ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00}, -+ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00}, -+ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00}, -+ {0xB7, 0x92}, -+ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13}, -+ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0}, -+ {0x3D, 0x7A}, -+ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42}, -+ { 177, 0xAC}, -+}; -+static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_common_pll_regs; -+static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_192k_pll_regs; -+static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_96k_pll_regs; -+static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_48k_pll_regs; -+static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_176k4_pll_regs; -+static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_88k2_pll_regs; -+static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_44k1_pll_regs; -+ -+/** -+ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk -+ * @hw: clk_hw for the common clk framework -+ */ -+struct clk_hifiberry_drvdata { -+ struct regmap *regmap; -+ struct clk *clk; -+ struct clk_hw hw; -+ unsigned long rate; -+}; -+ -+#define to_hifiberry_clk(_hw) \ -+ container_of(_hw, struct clk_hifiberry_drvdata, hw) -+ -+static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap, -+ struct reg_default *regs, -+ int num, int do_pll_reset) -+{ -+ int i; -+ int ret = 0; -+ char pll_soft_reset[] = { 177, 0xAC, }; -+ -+ for (i = 0; i < num; i++) { -+ ret |= regmap_write(regmap, regs[i].reg, regs[i].def); -+ if (ret) -+ return ret; -+ } -+ if (do_pll_reset) { -+ ret |= regmap_write(regmap, pll_soft_reset[0], -+ pll_soft_reset[1]); -+ mdelay(10); -+ } -+ return ret; -+} -+ -+static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return to_hifiberry_clk(hw)->rate; -+} -+ -+static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw, -+ unsigned long rate, unsigned long *parent_rate) -+{ -+ return rate; -+} -+ -+static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw, -+ unsigned long rate, unsigned long parent_rate) -+{ -+ int ret; -+ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw); -+ -+ switch (rate) { -+ case 44100: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs, -+ PLL_RESET); -+ break; -+ case 88200: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs, -+ PLL_RESET); -+ break; -+ case 176400: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs, -+ PLL_RESET); -+ break; -+ case 48000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs, -+ PLL_RESET); -+ break; -+ case 96000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs, -+ PLL_RESET); -+ break; -+ case 192000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs, -+ PLL_RESET); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ to_hifiberry_clk(hw)->rate = rate; -+ -+ return ret; -+} -+ -+const struct clk_ops clk_hifiberry_dachd_rate_ops = { -+ .recalc_rate = clk_hifiberry_dachd_recalc_rate, -+ .round_rate = clk_hifiberry_dachd_round_rate, -+ .set_rate = clk_hifiberry_dachd_set_rate, -+}; -+ -+static int clk_hifiberry_get_prop_values(struct device *dev, -+ char *prop_name, -+ struct reg_default *regs) -+{ -+ int ret; -+ int i; -+ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER]; -+ -+ ret = of_property_read_variable_u8_array(dev->of_node, prop_name, -+ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER); -+ if (ret < 0) -+ return ret; -+ if (ret & 1) { -+ dev_err(dev, -+ "%s <%s> -> #%i odd number of bytes for reg/val pairs!", -+ __func__, -+ prop_name, -+ ret); -+ return -EINVAL; -+ } -+ ret /= 2; -+ for (i = 0; i < ret; i++) { -+ regs[i].reg = (u32)tmp[2 * i]; -+ regs[i].def = (u32)tmp[2 * i + 1]; -+ } -+ return ret; -+} -+ -+ -+static int clk_hifiberry_dachd_dt_parse(struct device *dev) -+{ -+ num_common_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "common_pll_regs", common_pll_regs); -+ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "44k1_pll_regs", dedicated_44k1_pll_regs); -+ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "88k2_pll_regs", dedicated_88k2_pll_regs); -+ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "176k4_pll_regs", dedicated_176k4_pll_regs); -+ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "48k_pll_regs", dedicated_48k_pll_regs); -+ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "96k_pll_regs", dedicated_96k_pll_regs); -+ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "192k_pll_regs", dedicated_192k_pll_regs); -+ return 0; -+} -+ -+ -+static int clk_hifiberry_dachd_remove(struct device *dev) -+{ -+ of_clk_del_provider(dev->of_node); -+ return 0; -+} -+ -+const struct regmap_config hifiberry_pll_regmap = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = HIFIBERRY_PLL_MAX_REGISTER, -+ .reg_defaults = hifiberry_pll_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults), -+ .cache_type = REGCACHE_RBTREE, -+}; -+EXPORT_SYMBOL_GPL(hifiberry_pll_regmap); -+ -+ -+static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ struct clk_hifiberry_drvdata *hdclk; -+ int ret = 0; -+ struct clk_init_data init; -+ struct device *dev = &i2c->dev; -+ struct device_node *dev_node = dev->of_node; -+ struct regmap_config config = hifiberry_pll_regmap; -+ -+ hdclk = devm_kzalloc(&i2c->dev, -+ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL); -+ if (!hdclk) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(i2c, hdclk); -+ -+ hdclk->regmap = devm_regmap_init_i2c(i2c, &config); -+ -+ if (IS_ERR(hdclk->regmap)) -+ return PTR_ERR(hdclk->regmap); -+ -+ /* start PLL to allow detection of DAC */ -+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, -+ hifiberry_pll_reg_defaults, -+ ARRAY_SIZE(hifiberry_pll_reg_defaults), -+ PLL_RESET); -+ if (ret) -+ return ret; -+ -+ clk_hifiberry_dachd_dt_parse(dev); -+ -+ /* restart PLL with configs from DTB */ -+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs, -+ num_common_pll_regs, PLL_RESET); -+ if (ret) -+ return ret; -+ -+ init.name = "clk-hifiberry-dachd"; -+ init.ops = &clk_hifiberry_dachd_rate_ops; -+ init.flags = 0; -+ init.parent_names = NULL; -+ init.num_parents = 0; -+ -+ hdclk->hw.init = &init; -+ -+ hdclk->clk = devm_clk_register(dev, &hdclk->hw); -+ if (IS_ERR(hdclk->clk)) { -+ dev_err(dev, "unable to register %s\n", init.name); -+ return PTR_ERR(hdclk->clk); -+ } -+ -+ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk); -+ if (ret != 0) { -+ dev_err(dev, "Cannot of_clk_add_provider"); -+ return ret; -+ } -+ -+ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE); -+ if (ret != 0) { -+ dev_err(dev, "Cannot set rate : %d\n", ret); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c) -+{ -+ clk_hifiberry_dachd_remove(&i2c->dev); -+ return 0; -+} -+ -+static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = { -+ { "dachd-clk", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id); -+ -+static const struct of_device_id clk_hifiberry_dachd_of_match[] = { -+ { .compatible = "hifiberry,dachd-clk", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match); -+ -+static struct i2c_driver clk_hifiberry_dachd_i2c_driver = { -+ .probe = clk_hifiberry_dachd_i2c_probe, -+ .remove = clk_hifiberry_dachd_i2c_remove, -+ .id_table = clk_hifiberry_dachd_i2c_id, -+ .driver = { -+ .name = "dachd-clk", -+ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match), -+ }, -+}; -+ -+module_i2c_driver(clk_hifiberry_dachd_i2c_driver); -+ -+ -+MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver"); -+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:clk-hifiberry-dachd"); ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -42,6 +42,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - help - Say Y or M if you want to add support for HifiBerry DAC+. - -+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD -+ tristate "Support for HifiBerry DAC+ HD" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_PCM179X_I2C -+ select COMMON_CLK_HIFIBERRY_DACPLUSHD -+ help -+ Say Y or M if you want to add support for HifiBerry DAC+ HD. -+ - config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC - tristate "Support for HifiBerry DAC+ADC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -@@ -56,6 +64,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S - select SND_SOC_PCM512x_I2C - select SND_SOC_PCM186X_I2C -+ select COMMON_CLK_HIFIBERRY_DACPRO - help - Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. - ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo - - # BCM2708 Machine Support - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o -+snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o - snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o - snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o - snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o -@@ -41,6 +42,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi - - obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_dacplushd.c -@@ -0,0 +1,238 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ASoC Driver for HiFiBerry DAC+ HD -+ * -+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry -+ * Copyright 2020 -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ */ -+ -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/delay.h> -+#include <linux/gpio.h> -+#include <linux/gpio/consumer.h> -+#include <sound/core.h> -+#include <sound/pcm.h> -+#include <sound/pcm_params.h> -+#include <sound/soc.h> -+#include <linux/i2c.h> -+#include <linux/clk.h> -+ -+#include "../codecs/pcm179x.h" -+ -+#define DEFAULT_RATE 44100 -+ -+struct brd_drv_data { -+ struct regmap *regmap; -+ struct clk *sclk; -+}; -+ -+static struct brd_drv_data drvdata; -+static struct gpio_desc *reset_gpio; -+static const unsigned int hb_dacplushd_rates[] = { -+ 192000, 96000, 48000, 176400, 88200, 44100, -+}; -+ -+static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = { -+ .list = hb_dacplushd_rates, -+ .count = ARRAY_SIZE(hb_dacplushd_rates), -+}; -+ -+static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream) -+{ -+ /* constraints for standard sample rates */ -+ snd_pcm_hw_constraint_list(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_RATE, -+ &hb_dacplushd_constraints); -+ return 0; -+} -+ -+static void snd_rpi_hifiberry_dacplushd_set_sclk( -+ struct snd_soc_component *component, -+ int sample_rate) -+{ -+ if (!IS_ERR(drvdata.sclk)) -+ clk_set_rate(drvdata.sclk, sample_rate); -+} -+ -+static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_dai_link *dai = rtd->dai_link; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ dai->name = "HiFiBerry DAC+ HD"; -+ dai->stream_name = "HiFiBerry DAC+ HD HiFi"; -+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM; -+ -+ /* allow only fixed 32 clock counts per channel */ -+ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2); -+ -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplushd_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ int ret = 0; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ -+ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params)); -+ return ret; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = { -+ .startup = snd_rpi_hb_dacplushd_startup, -+ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params, -+}; -+ -+SND_SOC_DAILINK_DEFS(hifi, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); -+ -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = { -+{ -+ .name = "HiFiBerry DAC+ HD", -+ .stream_name = "HiFiBerry DAC+ HD HiFi", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_dacplushd_ops, -+ .init = snd_rpi_hifiberry_dacplushd_init, -+ SND_SOC_DAILINK_REG(hifi), -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_hifiberry_dacplushd = { -+ .name = "snd_rpi_hifiberry_dacplushd", -+ .driver_name = "HifiberryDacplusHD", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_dacplushd_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai), -+}; -+ -+static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ static int dac_reset_done; -+ struct device *dev = &pdev->dev; -+ struct device_node *dev_node = dev->of_node; -+ -+ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev; -+ -+ /* get GPIO and release DAC from RESET */ -+ if (!dac_reset_done) { -+ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); -+ if (IS_ERR(reset_gpio)) { -+ dev_err(&pdev->dev, "gpiod_get() failed\n"); -+ return -EINVAL; -+ } -+ dac_reset_done = 1; -+ } -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 0); -+ msleep(1); -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 1); -+ msleep(1); -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 0); -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai; -+ -+ dai = &snd_rpi_hifiberry_dacplushd_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ -+ if (i2s_node) { -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->of_node = i2s_node; -+ dai->cpus->dai_name = NULL; -+ dai->platforms->name = NULL; -+ } else { -+ return -EPROBE_DEFER; -+ } -+ -+ } -+ -+ ret = devm_snd_soc_register_card(&pdev->dev, -+ &snd_rpi_hifiberry_dacplushd); -+ if (ret && ret != -EPROBE_DEFER) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ return ret; -+ } -+ if (ret == -EPROBE_DEFER) -+ return ret; -+ -+ dev_set_drvdata(dev, &drvdata); -+ if (dev_node == NULL) { -+ dev_err(&pdev->dev, "Device tree node not found\n"); -+ return -ENODEV; -+ } -+ -+ drvdata.sclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(drvdata.sclk)) { -+ drvdata.sclk = ERR_PTR(-ENOENT); -+ return -ENODEV; -+ } -+ -+ clk_set_rate(drvdata.sclk, DEFAULT_RATE); -+ -+ return ret; -+} -+ -+static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev) -+{ -+ if (IS_ERR(reset_gpio)) -+ return -EINVAL; -+ -+ /* put DAC into RESET and release GPIO */ -+ gpiod_set_value(reset_gpio, 0); -+ gpiod_put(reset_gpio); -+ -+ return 0; -+} -+ -+static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-dacplushd", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match); -+ -+static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = { -+ .driver = { -+ .name = "snd-rpi-hifiberry-dacplushd", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_dacplushd_probe, -+ .remove = snd_rpi_hifiberry_dacplushd_remove, -+}; -+ -+module_platform_driver(snd_rpi_hifiberry_dacplushd_driver); -+ -+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>"); -+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD"); -+MODULE_LICENSE("GPL v2"); |