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