brcm63xx: rename target to bcm63xx
[openwrt/staging/mkresin.git] / target / linux / brcm2708 / patches-4.19 / 950-0792-sound-Add-the-HiFiBerry-DAC-HD-version.patch
1 From bb4781b1dac98688a3cf64cf728a64d811ca6add Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
3 <j-schambacher@users.noreply.github.com>
4 Date: Tue, 21 Jan 2020 15:58:39 +0100
5 Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version
6
7 This adds the driver for the DAC+HD version supporting HiFiBerry's
8 PCM179x based DACs. It also adds PLL control for clock generation.
9
10 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
11 ---
12 arch/arm/boot/dts/overlays/Makefile | 1 +
13 arch/arm/boot/dts/overlays/README | 6 +
14 .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++
15 drivers/clk/Makefile | 1 +
16 drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++
17 sound/soc/bcm/Kconfig | 7 +
18 sound/soc/bcm/Makefile | 2 +
19 sound/soc/bcm/hifiberry_dacplushd.c | 235 ++++++++++++
20 13 files changed, 696 insertions(+)
21 create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
22 create mode 100644 drivers/clk/clk-hifiberry-dachd.c
23 create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
24
25 --- a/arch/arm/boot/dts/overlays/Makefile
26 +++ b/arch/arm/boot/dts/overlays/Makefile
27 @@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
28 hifiberry-dacplusadc.dtbo \
29 hifiberry-dacplusadcpro.dtbo \
30 hifiberry-dacplusdsp.dtbo \
31 + hifiberry-dacplushd.dtbo \
32 hifiberry-digi.dtbo \
33 hifiberry-digi-pro.dtbo \
34 hy28a.dtbo \
35 --- a/arch/arm/boot/dts/overlays/README
36 +++ b/arch/arm/boot/dts/overlays/README
37 @@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp
38 Params: <None>
39
40
41 +Name: hifiberry-dacplushd
42 +Info: Configures the HifiBerry DAC+ HD audio card
43 +Load: dtoverlay=hifiberry-dacplushd
44 +Params: <None>
45 +
46 +
47 Name: hifiberry-digi
48 Info: Configures the HifiBerry Digi and Digi+ audio card
49 Load: dtoverlay=hifiberry-digi
50 --- /dev/null
51 +++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
52 @@ -0,0 +1,106 @@
53 +// Definitions for HiFiBerry DAC+ HD
54 +/dts-v1/;
55 +/plugin/;
56 +
57 +#include <dt-bindings/gpio/gpio.h>
58 +
59 +/ {
60 + compatible = "brcm,bcm2835";
61 +
62 + fragment@0 {
63 + target-path = "/clocks";
64 + __overlay__ {
65 + dachd_osc: pll_dachd_osc {
66 + compatible = "hifiberry,dachd-clk";
67 + #clock-cells = <0>;
68 + };
69 + };
70 + };
71 +
72 + fragment@1 {
73 + target = <&i2s>;
74 + __overlay__ {
75 + status = "okay";
76 + };
77 + };
78 +
79 + fragment@2 {
80 + target = <&i2c1>;
81 + __overlay__ {
82 + #address-cells = <1>;
83 + #size-cells = <0>;
84 + status = "okay";
85 +
86 + pcm1792a@4c {
87 + compatible = "ti,pcm1792a";
88 + #sound-dai-cells = <0>;
89 + #clock-cells = <0>;
90 + clocks = <&dachd_osc>;
91 + reg = <0x4c>;
92 + status = "okay";
93 + };
94 + pll: pll@62 {
95 + compatible = "hifiberry,dachd-clk";
96 + #clock-cells = <0>;
97 + reg = <0x62>;
98 + clocks = <&dachd_osc>;
99 + status = "okay";
100 + common_pll_regs = [
101 + 02 53 03 00 07 20 0F 00
102 + 10 0D 11 1D 12 0D 13 8C
103 + 14 8C 15 8C 16 8C 17 8C
104 + 18 2A 1C 00 1D 0F 1F 00
105 + 2A 00 2C 00 2F 00 30 00
106 + 31 00 32 00 34 00 37 00
107 + 38 00 39 00 3A 00 3B 01
108 + 3E 00 3F 00 40 00 41 00
109 + 5A 00 5B 00 95 00 96 00
110 + 97 00 98 00 99 00 9A 00
111 + 9B 00 A2 00 A3 00 A4 00
112 + B7 92 ];
113 + 192k_pll_regs = [
114 + 1A 0C 1B 35 1E F0 20 09
115 + 21 50 2B 02 2D 10 2E 40
116 + 33 01 35 22 36 80 3C 22
117 + 3D 46 ];
118 + 96k_pll_regs = [
119 + 1A 0C 1B 35 1E F0 20 09
120 + 21 50 2B 02 2D 10 2E 40
121 + 33 01 35 47 36 00 3C 32
122 + 3D 46 ];
123 + 48k_pll_regs = [
124 + 1A 0C 1B 35 1E F0 20 09
125 + 21 50 2B 02 2D 10 2E 40
126 + 33 01 35 90 36 00 3C 42
127 + 3D 46 ];
128 + 176k4_pll_regs = [
129 + 1A 3D 1B 09 1E F3 20 13
130 + 21 75 2B 04 2D 11 2E E0
131 + 33 02 35 25 36 C0 3C 22
132 + 3D 7A ];
133 + 88k2_pll_regs = [
134 + 1A 3D 1B 09 1E F3 20 13
135 + 21 75 2B 04 2D 11 2E E0
136 + 33 01 35 4D 36 80 3C 32
137 + 3D 7A ];
138 + 44k1_pll_regs = [
139 + 1A 3D 1B 09 1E F3 20 13
140 + 21 75 2B 04 2D 11 2E E0
141 + 33 01 35 9D 36 00 3C 42
142 + 3D 7A ];
143 + };
144 + };
145 + };
146 +
147 + fragment@3 {
148 + target = <&sound>;
149 + __overlay__ {
150 + compatible = "hifiberry,hifiberry-dacplushd";
151 + i2s-controller = <&i2s>;
152 + clocks = <&pll 0>;
153 + reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
154 + status = "okay";
155 + };
156 + };
157 +
158 +};
159 --- a/drivers/clk/Makefile
160 +++ b/drivers/clk/Makefile
161 @@ -32,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-
162 obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
163 obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
164 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += clk-hifiberry-dacpro.o
165 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
166 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
167 obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
168 obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
169 --- /dev/null
170 +++ b/drivers/clk/clk-hifiberry-dachd.c
171 @@ -0,0 +1,333 @@
172 +// SPDX-License-Identifier: GPL-2.0
173 +/*
174 + * Clock Driver for HiFiBerry DAC+ HD
175 + *
176 + * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
177 + * Copyright 2020
178 + *
179 + * This program is free software; you can redistribute it and/or
180 + * modify it under the terms of the GNU General Public License
181 + * version 2 as published by the Free Software Foundation.
182 + *
183 + * This program is distributed in the hope that it will be useful, but
184 + * WITHOUT ANY WARRANTY; without even the implied warranty of
185 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
186 + * General Public License for more details.
187 + */
188 +
189 +#include <linux/clk-provider.h>
190 +#include <linux/clk.h>
191 +#include <linux/kernel.h>
192 +#include <linux/module.h>
193 +#include <linux/of.h>
194 +#include <linux/slab.h>
195 +#include <linux/platform_device.h>
196 +#include <linux/i2c.h>
197 +#include <linux/regmap.h>
198 +
199 +#define NO_PLL_RESET 0
200 +#define PLL_RESET 1
201 +#define HIFIBERRY_PLL_MAX_REGISTER 256
202 +#define DEFAULT_RATE 44100
203 +
204 +static struct reg_default hifiberry_pll_reg_defaults[] = {
205 + {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
206 + {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
207 + {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
208 + {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
209 + {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
210 + {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
211 + {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
212 + {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
213 + {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
214 + {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
215 + {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
216 + {0xB7, 0x92},
217 + {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
218 + {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
219 + {0x3D, 0x7A},
220 + {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
221 + { 177, 0xAC},
222 +};
223 +static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
224 +static int num_common_pll_regs;
225 +static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
226 +static int num_dedicated_192k_pll_regs;
227 +static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
228 +static int num_dedicated_96k_pll_regs;
229 +static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
230 +static int num_dedicated_48k_pll_regs;
231 +static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
232 +static int num_dedicated_176k4_pll_regs;
233 +static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
234 +static int num_dedicated_88k2_pll_regs;
235 +static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
236 +static int num_dedicated_44k1_pll_regs;
237 +
238 +/**
239 + * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
240 + * @hw: clk_hw for the common clk framework
241 + */
242 +struct clk_hifiberry_drvdata {
243 + struct regmap *regmap;
244 + struct clk *clk;
245 + struct clk_hw hw;
246 + unsigned long rate;
247 +};
248 +
249 +#define to_hifiberry_clk(_hw) \
250 + container_of(_hw, struct clk_hifiberry_drvdata, hw)
251 +
252 +static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
253 + struct reg_default *regs,
254 + int num, int do_pll_reset)
255 +{
256 + int i;
257 + int ret = 0;
258 + char pll_soft_reset[] = { 177, 0xAC, };
259 +
260 + for (i = 0; i < num; i++) {
261 + ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
262 + if (ret)
263 + return ret;
264 + }
265 + if (do_pll_reset) {
266 + ret |= regmap_write(regmap, pll_soft_reset[0],
267 + pll_soft_reset[1]);
268 + mdelay(10);
269 + }
270 + return ret;
271 +}
272 +
273 +static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
274 + unsigned long parent_rate)
275 +{
276 + return to_hifiberry_clk(hw)->rate;
277 +}
278 +
279 +static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
280 + unsigned long rate, unsigned long *parent_rate)
281 +{
282 + return rate;
283 +}
284 +
285 +static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
286 + unsigned long rate, unsigned long parent_rate)
287 +{
288 + int ret;
289 + struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
290 +
291 + switch (rate) {
292 + case 44100:
293 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
294 + dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
295 + PLL_RESET);
296 + break;
297 + case 88200:
298 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
299 + dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
300 + PLL_RESET);
301 + break;
302 + case 176400:
303 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
304 + dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
305 + PLL_RESET);
306 + break;
307 + case 48000:
308 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
309 + dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
310 + PLL_RESET);
311 + break;
312 + case 96000:
313 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
314 + dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
315 + PLL_RESET);
316 + break;
317 + case 192000:
318 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
319 + dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
320 + PLL_RESET);
321 + break;
322 + default:
323 + ret = -EINVAL;
324 + break;
325 + }
326 + to_hifiberry_clk(hw)->rate = rate;
327 +
328 + return ret;
329 +}
330 +
331 +const struct clk_ops clk_hifiberry_dachd_rate_ops = {
332 + .recalc_rate = clk_hifiberry_dachd_recalc_rate,
333 + .round_rate = clk_hifiberry_dachd_round_rate,
334 + .set_rate = clk_hifiberry_dachd_set_rate,
335 +};
336 +
337 +static int clk_hifiberry_get_prop_values(struct device *dev,
338 + char *prop_name,
339 + struct reg_default *regs)
340 +{
341 + int ret;
342 + int i;
343 + u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
344 +
345 + ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
346 + tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
347 + if (ret < 0)
348 + return ret;
349 + if (ret & 1) {
350 + dev_err(dev,
351 + "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
352 + __func__,
353 + prop_name,
354 + ret);
355 + return -EINVAL;
356 + }
357 + ret /= 2;
358 + for (i = 0; i < ret; i++) {
359 + regs[i].reg = (u32)tmp[2 * i];
360 + regs[i].def = (u32)tmp[2 * i + 1];
361 + }
362 + return ret;
363 +}
364 +
365 +
366 +static int clk_hifiberry_dachd_dt_parse(struct device *dev)
367 +{
368 + num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
369 + "common_pll_regs", common_pll_regs);
370 + num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
371 + "44k1_pll_regs", dedicated_44k1_pll_regs);
372 + num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
373 + "88k2_pll_regs", dedicated_88k2_pll_regs);
374 + num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
375 + "176k4_pll_regs", dedicated_176k4_pll_regs);
376 + num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
377 + "48k_pll_regs", dedicated_48k_pll_regs);
378 + num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
379 + "96k_pll_regs", dedicated_96k_pll_regs);
380 + num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
381 + "192k_pll_regs", dedicated_192k_pll_regs);
382 + return 0;
383 +}
384 +
385 +
386 +static int clk_hifiberry_dachd_remove(struct device *dev)
387 +{
388 + of_clk_del_provider(dev->of_node);
389 + return 0;
390 +}
391 +
392 +const struct regmap_config hifiberry_pll_regmap = {
393 + .reg_bits = 8,
394 + .val_bits = 8,
395 + .max_register = HIFIBERRY_PLL_MAX_REGISTER,
396 + .reg_defaults = hifiberry_pll_reg_defaults,
397 + .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
398 + .cache_type = REGCACHE_RBTREE,
399 +};
400 +EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
401 +
402 +
403 +static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
404 + const struct i2c_device_id *id)
405 +{
406 + struct clk_hifiberry_drvdata *hdclk;
407 + int ret = 0;
408 + struct clk_init_data init;
409 + struct device *dev = &i2c->dev;
410 + struct device_node *dev_node = dev->of_node;
411 + struct regmap_config config = hifiberry_pll_regmap;
412 +
413 + hdclk = devm_kzalloc(&i2c->dev,
414 + sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
415 + if (!hdclk)
416 + return -ENOMEM;
417 +
418 + i2c_set_clientdata(i2c, hdclk);
419 +
420 + hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
421 +
422 + if (IS_ERR(hdclk->regmap))
423 + return PTR_ERR(hdclk->regmap);
424 +
425 + /* start PLL to allow detection of DAC */
426 + ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
427 + hifiberry_pll_reg_defaults,
428 + ARRAY_SIZE(hifiberry_pll_reg_defaults),
429 + PLL_RESET);
430 + if (ret)
431 + return ret;
432 +
433 + clk_hifiberry_dachd_dt_parse(dev);
434 +
435 + /* restart PLL with configs from DTB */
436 + ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
437 + num_common_pll_regs, PLL_RESET);
438 + if (ret)
439 + return ret;
440 +
441 + init.name = "clk-hifiberry-dachd";
442 + init.ops = &clk_hifiberry_dachd_rate_ops;
443 + init.flags = CLK_IS_BASIC;
444 + init.parent_names = NULL;
445 + init.num_parents = 0;
446 +
447 + hdclk->hw.init = &init;
448 +
449 + hdclk->clk = devm_clk_register(dev, &hdclk->hw);
450 + if (IS_ERR(hdclk->clk)) {
451 + dev_err(dev, "unable to register %s\n", init.name);
452 + return PTR_ERR(hdclk->clk);
453 + }
454 +
455 + ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
456 + if (ret != 0) {
457 + dev_err(dev, "Cannot of_clk_add_provider");
458 + return ret;
459 + }
460 +
461 + ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
462 + if (ret != 0) {
463 + dev_err(dev, "Cannot set rate : %d\n", ret);
464 + return -EINVAL;
465 + }
466 +
467 + return ret;
468 +}
469 +
470 +static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
471 +{
472 + clk_hifiberry_dachd_remove(&i2c->dev);
473 + return 0;
474 +}
475 +
476 +static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
477 + { "dachd-clk", },
478 + { }
479 +};
480 +MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
481 +
482 +static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
483 + { .compatible = "hifiberry,dachd-clk", },
484 + { }
485 +};
486 +MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
487 +
488 +static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
489 + .probe = clk_hifiberry_dachd_i2c_probe,
490 + .remove = clk_hifiberry_dachd_i2c_remove,
491 + .id_table = clk_hifiberry_dachd_i2c_id,
492 + .driver = {
493 + .name = "dachd-clk",
494 + .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
495 + },
496 +};
497 +
498 +module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
499 +
500 +
501 +MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
502 +MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
503 +MODULE_LICENSE("GPL v2");
504 +MODULE_ALIAS("platform:clk-hifiberry-dachd");
505 --- a/sound/soc/bcm/Kconfig
506 +++ b/sound/soc/bcm/Kconfig
507 @@ -40,6 +40,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
508 help
509 Say Y or M if you want to add support for HifiBerry DAC+.
510
511 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
512 + tristate "Support for HifiBerry DAC+ HD"
513 + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
514 + select SND_SOC_PCM179X_I2C
515 + help
516 + Say Y or M if you want to add support for HifiBerry DAC+ HD.
517 +
518 config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
519 tristate "Support for HifiBerry DAC+ADC"
520 depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
521 --- a/sound/soc/bcm/Makefile
522 +++ b/sound/soc/bcm/Makefile
523 @@ -13,6 +13,7 @@ snd-soc-googlevoicehat-codec-objs := goo
524
525 # BCM2708 Machine Support
526 snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
527 +snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
528 snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
529 snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
530 snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
531 @@ -40,6 +41,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
532
533 obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
534 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
535 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
536 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
537 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
538 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
539 --- /dev/null
540 +++ b/sound/soc/bcm/hifiberry_dacplushd.c
541 @@ -0,0 +1,235 @@
542 +// SPDX-License-Identifier: GPL-2.0
543 +/*
544 + * ASoC Driver for HiFiBerry DAC+ HD
545 + *
546 + * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
547 + * Copyright 2020
548 + *
549 + * This program is free software; you can redistribute it and/or
550 + * modify it under the terms of the GNU General Public License
551 + * version 2 as published by the Free Software Foundation.
552 + *
553 + * This program is distributed in the hope that it will be useful, but
554 + * WITHOUT ANY WARRANTY; without even the implied warranty of
555 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
556 + * General Public License for more details.
557 + */
558 +
559 +#include <linux/module.h>
560 +#include <linux/platform_device.h>
561 +#include <linux/kernel.h>
562 +#include <linux/delay.h>
563 +#include <linux/module.h>
564 +#include <linux/of.h>
565 +#include <linux/delay.h>
566 +#include <linux/gpio.h>
567 +#include <linux/gpio/consumer.h>
568 +#include <sound/core.h>
569 +#include <sound/pcm.h>
570 +#include <sound/pcm_params.h>
571 +#include <sound/soc.h>
572 +#include <linux/i2c.h>
573 +#include <linux/clk.h>
574 +
575 +#include "../codecs/pcm179x.h"
576 +
577 +#define DEFAULT_RATE 44100
578 +
579 +struct brd_drv_data {
580 + struct regmap *regmap;
581 + struct clk *sclk;
582 +};
583 +
584 +static struct brd_drv_data drvdata;
585 +static struct gpio_desc *reset_gpio;
586 +static const unsigned int hb_dacplushd_rates[] = {
587 + 192000, 96000, 48000, 176400, 88200, 44100,
588 +};
589 +
590 +static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
591 + .list = hb_dacplushd_rates,
592 + .count = ARRAY_SIZE(hb_dacplushd_rates),
593 +};
594 +
595 +static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
596 +{
597 + /* constraints for standard sample rates */
598 + snd_pcm_hw_constraint_list(substream->runtime, 0,
599 + SNDRV_PCM_HW_PARAM_RATE,
600 + &hb_dacplushd_constraints);
601 + return 0;
602 +}
603 +
604 +static void snd_rpi_hifiberry_dacplushd_set_sclk(
605 + struct snd_soc_component *component,
606 + int sample_rate)
607 +{
608 + if (!IS_ERR(drvdata.sclk))
609 + clk_set_rate(drvdata.sclk, sample_rate);
610 +}
611 +
612 +static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
613 +{
614 + struct snd_soc_dai_link *dai = rtd->dai_link;
615 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
616 +
617 + dai->name = "HiFiBerry DAC+ HD";
618 + dai->stream_name = "HiFiBerry DAC+ HD HiFi";
619 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
620 + | SND_SOC_DAIFMT_CBM_CFM;
621 +
622 + /* allow only fixed 32 clock counts per channel */
623 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
624 +
625 + return 0;
626 +}
627 +
628 +static int snd_rpi_hifiberry_dacplushd_hw_params(
629 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
630 +{
631 + int ret = 0;
632 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
633 +
634 + struct snd_soc_component *component = rtd->codec_dai->component;
635 +
636 + snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
637 + return ret;
638 +}
639 +
640 +/* machine stream operations */
641 +static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
642 + .startup = snd_rpi_hb_dacplushd_startup,
643 + .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
644 +};
645 +
646 +static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
647 +{
648 + .name = "HiFiBerry DAC+ HD",
649 + .stream_name = "HiFiBerry DAC+ HD HiFi",
650 + .cpu_dai_name = "bcm2708-i2s.0",
651 + .codec_dai_name = "pcm179x-hifi",
652 + .platform_name = "bcm2708-i2s.0",
653 + .codec_name = "pcm179x.1-004c",
654 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
655 + SND_SOC_DAIFMT_CBS_CFS,
656 + .ops = &snd_rpi_hifiberry_dacplushd_ops,
657 + .init = snd_rpi_hifiberry_dacplushd_init,
658 +},
659 +};
660 +
661 +/* audio machine driver */
662 +static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
663 + .name = "snd_rpi_hifiberry_dacplushd",
664 + .driver_name = "HifiberryDacplusHD",
665 + .owner = THIS_MODULE,
666 + .dai_link = snd_rpi_hifiberry_dacplushd_dai,
667 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
668 +};
669 +
670 +static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
671 +{
672 + int ret = 0;
673 + static int dac_reset_done;
674 + struct device *dev = &pdev->dev;
675 + struct device_node *dev_node = dev->of_node;
676 +
677 + snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
678 +
679 + /* get GPIO and release DAC from RESET */
680 + if (!dac_reset_done) {
681 + reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
682 + if (IS_ERR(reset_gpio)) {
683 + dev_err(&pdev->dev, "gpiod_get() failed\n");
684 + return -EINVAL;
685 + }
686 + dac_reset_done = 1;
687 + }
688 + if (!IS_ERR(reset_gpio))
689 + gpiod_set_value(reset_gpio, 0);
690 + msleep(1);
691 + if (!IS_ERR(reset_gpio))
692 + gpiod_set_value(reset_gpio, 1);
693 + msleep(1);
694 + if (!IS_ERR(reset_gpio))
695 + gpiod_set_value(reset_gpio, 0);
696 +
697 + if (pdev->dev.of_node) {
698 + struct device_node *i2s_node;
699 + struct snd_soc_dai_link *dai;
700 +
701 + dai = &snd_rpi_hifiberry_dacplushd_dai[0];
702 + i2s_node = of_parse_phandle(pdev->dev.of_node,
703 + "i2s-controller", 0);
704 +
705 + if (i2s_node) {
706 + dai->cpu_dai_name = NULL;
707 + dai->cpu_of_node = i2s_node;
708 + dai->platform_name = NULL;
709 + dai->platform_of_node = i2s_node;
710 + } else {
711 + return -EPROBE_DEFER;
712 + }
713 +
714 + }
715 +
716 + ret = devm_snd_soc_register_card(&pdev->dev,
717 + &snd_rpi_hifiberry_dacplushd);
718 + if (ret && ret != -EPROBE_DEFER) {
719 + dev_err(&pdev->dev,
720 + "snd_soc_register_card() failed: %d\n", ret);
721 + return ret;
722 + }
723 + if (ret == -EPROBE_DEFER)
724 + return ret;
725 +
726 + dev_set_drvdata(dev, &drvdata);
727 + if (dev_node == NULL) {
728 + dev_err(&pdev->dev, "Device tree node not found\n");
729 + return -ENODEV;
730 + }
731 +
732 + drvdata.sclk = devm_clk_get(dev, NULL);
733 + if (IS_ERR(drvdata.sclk)) {
734 + drvdata.sclk = ERR_PTR(-ENOENT);
735 + return -ENODEV;
736 + }
737 +
738 + clk_set_rate(drvdata.sclk, DEFAULT_RATE);
739 +
740 + return ret;
741 +}
742 +
743 +static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
744 +{
745 + if (IS_ERR(reset_gpio))
746 + return -EINVAL;
747 +
748 + /* put DAC into RESET and release GPIO */
749 + gpiod_set_value(reset_gpio, 0);
750 + gpiod_put(reset_gpio);
751 +
752 + return 0;
753 +}
754 +
755 +static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
756 + { .compatible = "hifiberry,hifiberry-dacplushd", },
757 + {},
758 +};
759 +
760 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
761 +
762 +static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
763 + .driver = {
764 + .name = "snd-rpi-hifiberry-dacplushd",
765 + .owner = THIS_MODULE,
766 + .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
767 + },
768 + .probe = snd_rpi_hifiberry_dacplushd_probe,
769 + .remove = snd_rpi_hifiberry_dacplushd_remove,
770 +};
771 +
772 +module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
773 +
774 +MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
775 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
776 +MODULE_LICENSE("GPL v2");