|
23 | 23 | #include <sound/pcm_params.h>
|
24 | 24 | #include <sound/soc.h>
|
25 | 25 | #include <sound/jack.h>
|
| 26 | +#include <linux/gpio/consumer.h> |
26 | 27 |
|
27 | 28 | #include "../codecs/wm8804.h"
|
28 | 29 |
|
29 | 30 | static short int auto_shutdown_output = 0;
|
30 | 31 | module_param(auto_shutdown_output, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
31 | 32 | MODULE_PARM_DESC(auto_shutdown_output, "Shutdown SP/DIF output if playback is stopped");
|
32 | 33 |
|
| 34 | +#define CLK_44EN_RATE 22579200UL |
| 35 | +#define CLK_48EN_RATE 24576000UL |
| 36 | + |
| 37 | +static bool snd_rpi_hifiberry_is_digipro; |
| 38 | +static struct gpio_desc *snd_rpi_hifiberry_clk44gpio; |
| 39 | +static struct gpio_desc *snd_rpi_hifiberry_clk48gpio; |
33 | 40 |
|
34 | 41 | static int samplerate=44100;
|
35 | 42 |
|
| 43 | +static uint32_t snd_rpi_hifiberry_digi_enable_clock(int sample_rate) |
| 44 | +{ |
| 45 | + switch (sample_rate) { |
| 46 | + case 11025: |
| 47 | + case 22050: |
| 48 | + case 44100: |
| 49 | + case 88200: |
| 50 | + case 176400: |
| 51 | + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk44gpio, 1); |
| 52 | + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk48gpio, 0); |
| 53 | + return CLK_44EN_RATE; |
| 54 | + default: |
| 55 | + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk48gpio, 1); |
| 56 | + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk44gpio, 0); |
| 57 | + return CLK_48EN_RATE; |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | + |
36 | 62 | static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd)
|
37 | 63 | {
|
38 | 64 | struct snd_soc_codec *codec = rtd->codec;
|
39 | 65 |
|
40 | 66 | /* enable TX output */
|
41 | 67 | snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
|
42 | 68 |
|
| 69 | + /* Initialize Digi+ Pro hardware */ |
| 70 | + if (snd_rpi_hifiberry_is_digipro) { |
| 71 | + struct snd_soc_dai_link *dai = rtd->dai_link; |
| 72 | + |
| 73 | + dai->name = "HiFiBerry Digi+ Pro"; |
| 74 | + dai->stream_name = "HiFiBerry Digi+ Pro HiFi"; |
| 75 | + } |
| 76 | + |
43 | 77 | return 0;
|
44 | 78 | }
|
45 | 79 |
|
@@ -87,6 +121,9 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream,
|
87 | 121 | mclk_freq=samplerate*128;
|
88 | 122 | mclk_div=WM8804_MCLKDIV_128FS;
|
89 | 123 | }
|
| 124 | + |
| 125 | + if (snd_rpi_hifiberry_is_digipro) |
| 126 | + sysclk = snd_rpi_hifiberry_digi_enable_clock(samplerate); |
90 | 127 |
|
91 | 128 | switch (samplerate) {
|
92 | 129 | case 32000:
|
@@ -121,6 +158,7 @@ static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream,
|
121 | 158 |
|
122 | 159 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
|
123 | 160 | sysclk, SND_SOC_CLOCK_OUT);
|
| 161 | + |
124 | 162 | if (ret < 0) {
|
125 | 163 | dev_err(codec->dev,
|
126 | 164 | "Failed to set WM8804 SYSCLK: %d\n", ret);
|
@@ -187,6 +225,19 @@ static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev)
|
187 | 225 | dai->platform_name = NULL;
|
188 | 226 | dai->platform_of_node = i2s_node;
|
189 | 227 | }
|
| 228 | + |
| 229 | + snd_rpi_hifiberry_is_digipro = 1; |
| 230 | + |
| 231 | + snd_rpi_hifiberry_clk44gpio = |
| 232 | + devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW); |
| 233 | + if (IS_ERR(snd_rpi_hifiberry_clk44gpio)) |
| 234 | + snd_rpi_hifiberry_is_digipro = 0; |
| 235 | + |
| 236 | + snd_rpi_hifiberry_clk48gpio = |
| 237 | + devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW); |
| 238 | + if (IS_ERR(snd_rpi_hifiberry_clk48gpio)) |
| 239 | + snd_rpi_hifiberry_is_digipro = 0; |
| 240 | + |
190 | 241 | }
|
191 | 242 |
|
192 | 243 | ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
|
|
0 commit comments