ff638aed61706429c85e71fef38ea43bc3efeb56
[openwrt/staging/ldir.git] /
1 From fb21611efd7cd916646d9ab2988c3af08f139761 Mon Sep 17 00:00:00 2001
2 From: Ben Payne <ben@bluerocksoft.com>
3 Date: Tue, 13 Feb 2024 14:55:14 -0800
4 Subject: [PATCH 1276/1295] Impliment driver support for Interlude Audio
5 Digital Hat
6
7 Implementing driver support for
8 Interlude audio's WM8805 based digital hat
9 by leveraging existing drivers
10 ---
11 sound/soc/bcm/rpi-wm8804-soundcard.c | 139 +++++++++++++++++++++++++++
12 1 file changed, 139 insertions(+)
13
14 --- a/sound/soc/bcm/rpi-wm8804-soundcard.c
15 +++ b/sound/soc/bcm/rpi-wm8804-soundcard.c
16 @@ -34,6 +34,7 @@
17 #include <linux/gpio/consumer.h>
18 #include <linux/platform_device.h>
19 #include <linux/module.h>
20 +#include <linux/delay.h>
21
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 @@ -65,6 +66,10 @@ struct snd_rpi_wm8804_drvdata {
25 static struct gpio_desc *snd_clk44gpio;
26 static struct gpio_desc *snd_clk48gpio;
27 static int wm8804_samplerate = 0;
28 +static struct gpio_desc *led_gpio_1;
29 +static struct gpio_desc *led_gpio_2;
30 +static struct gpio_desc *led_gpio_3;
31 +static struct gpio_desc *custom_reset;
32
33 /* Forward declarations */
34 static struct snd_soc_dai_link snd_allo_digione_dai[];
35 @@ -74,6 +79,37 @@ static struct snd_soc_card snd_rpi_wm880
36 #define CLK_44EN_RATE 22579200UL
37 #define CLK_48EN_RATE 24576000UL
38
39 +static const char * const wm8805_input_select_text[] = {
40 + "Rx 0",
41 + "Rx 1",
42 + "Rx 2",
43 + "Rx 3",
44 + "Rx 4",
45 + "Rx 5",
46 + "Rx 6",
47 + "Rx 7"
48 +};
49 +
50 +static const unsigned int wm8805_input_channel_select_value[] = {
51 + 0, 1, 2, 3, 4, 5, 6, 7
52 +};
53 +
54 +static const struct soc_enum wm8805_input_channel_sel[] = {
55 + SOC_VALUE_ENUM_SINGLE(WM8804_PLL6, 0, 7, ARRAY_SIZE(wm8805_input_select_text),
56 + wm8805_input_select_text, wm8805_input_channel_select_value),
57 +};
58 +
59 +static const struct snd_kcontrol_new wm8805_input_controls_card[] = {
60 + SOC_ENUM("Select Input Channel", wm8805_input_channel_sel[0]),
61 +};
62 +
63 +static int wm8805_add_input_controls(struct snd_soc_component *component)
64 +{
65 + snd_soc_add_component_controls(component, wm8805_input_controls_card,
66 + ARRAY_SIZE(wm8805_input_controls_card));
67 + return 0;
68 +}
69 +
70 static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
71 {
72 switch (samplerate) {
73 @@ -187,6 +223,53 @@ static struct snd_soc_ops snd_rpi_wm8804
74 .hw_params = snd_rpi_wm8804_hw_params,
75 };
76
77 +static int snd_interlude_audio_hw_params(struct snd_pcm_substream *substream,
78 + struct snd_pcm_hw_params *params)
79 +{
80 + int ret = snd_rpi_wm8804_hw_params(substream, params);
81 + int samplerate = params_rate(params);
82 +
83 + switch (samplerate) {
84 + case 44100:
85 + gpiod_set_value_cansleep(led_gpio_1, 1);
86 + gpiod_set_value_cansleep(led_gpio_2, 0);
87 + gpiod_set_value_cansleep(led_gpio_3, 0);
88 + break;
89 + case 48000:
90 + gpiod_set_value_cansleep(led_gpio_1, 1);
91 + gpiod_set_value_cansleep(led_gpio_2, 0);
92 + gpiod_set_value_cansleep(led_gpio_3, 0);
93 + break;
94 + case 88200:
95 + gpiod_set_value_cansleep(led_gpio_1, 0);
96 + gpiod_set_value_cansleep(led_gpio_2, 1);
97 + gpiod_set_value_cansleep(led_gpio_3, 0);
98 + break;
99 + case 96000:
100 + gpiod_set_value_cansleep(led_gpio_1, 0);
101 + gpiod_set_value_cansleep(led_gpio_2, 1);
102 + gpiod_set_value_cansleep(led_gpio_3, 0);
103 + break;
104 + case 176400:
105 + gpiod_set_value_cansleep(led_gpio_1, 0);
106 + gpiod_set_value_cansleep(led_gpio_2, 0);
107 + gpiod_set_value_cansleep(led_gpio_3, 1);
108 + break;
109 + case 192000:
110 + gpiod_set_value_cansleep(led_gpio_1, 0);
111 + gpiod_set_value_cansleep(led_gpio_2, 0);
112 + gpiod_set_value_cansleep(led_gpio_3, 1);
113 + break;
114 + default:
115 + break;
116 + }
117 + return ret;
118 +}
119 +
120 +const struct snd_soc_ops interlude_audio_digital_dai_ops = {
121 + .hw_params = snd_interlude_audio_hw_params,
122 +};
123 +
124 SND_SOC_DAILINK_DEFS(justboom_digi,
125 DAILINK_COMP_ARRAY(COMP_EMPTY()),
126 DAILINK_COMP_ARRAY(COMP_EMPTY()),
127 @@ -287,6 +370,60 @@ static struct snd_rpi_wm8804_drvdata drv
128 .probe = snd_hifiberry_digi_probe,
129 };
130
131 +SND_SOC_DAILINK_DEFS(interlude_audio_digital,
132 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
133 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
134 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
135 +
136 +static int snd_interlude_audio_init(struct snd_soc_pcm_runtime *rtd)
137 +{
138 + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
139 + int ret;
140 +
141 + ret = wm8805_add_input_controls(component);
142 + if (ret != 0)
143 + pr_err("failed to add input controls");
144 +
145 + return 0;
146 +}
147 +
148 +
149 +static struct snd_soc_dai_link snd_interlude_audio_digital_dai[] = {
150 +{
151 + .name = "Interlude Audio Digital",
152 + .stream_name = "Interlude Audio Digital HiFi",
153 + .init = snd_interlude_audio_init,
154 + .ops = &interlude_audio_digital_dai_ops,
155 + SND_SOC_DAILINK_REG(interlude_audio_digital),
156 +},
157 +};
158 +
159 +
160 +static int snd_interlude_audio_digital_probe(struct platform_device *pdev)
161 +{
162 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
163 + return 0;
164 +
165 + custom_reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
166 + gpiod_set_value_cansleep(custom_reset, 0);
167 + mdelay(10);
168 + gpiod_set_value_cansleep(custom_reset, 1);
169 +
170 + snd_interlude_audio_digital_dai->name = "Interlude Audio Digital";
171 + snd_interlude_audio_digital_dai->stream_name = "Interlude Audio Digital HiFi";
172 + led_gpio_1 = devm_gpiod_get(&pdev->dev, "led1", GPIOD_OUT_LOW);
173 + led_gpio_2 = devm_gpiod_get(&pdev->dev, "led2", GPIOD_OUT_LOW);
174 + led_gpio_3 = devm_gpiod_get(&pdev->dev, "led3", GPIOD_OUT_LOW);
175 + return 0;
176 +}
177 +
178 +
179 +static struct snd_rpi_wm8804_drvdata drvdata_interlude_audio_digital = {
180 + .card_name = "snd_IA_Digital_Hat",
181 + .dai = snd_interlude_audio_digital_dai,
182 + .probe = snd_interlude_audio_digital_probe,
183 +};
184 +
185 static const struct of_device_id snd_rpi_wm8804_of_match[] = {
186 { .compatible = "justboom,justboom-digi",
187 .data = (void *) &drvdata_justboom_digi },
188 @@ -296,6 +433,8 @@ static const struct of_device_id snd_rpi
189 .data = (void *) &drvdata_allo_digione },
190 { .compatible = "hifiberry,hifiberry-digi",
191 .data = (void *) &drvdata_hifiberry_digi },
192 + { .compatible = "interludeaudio,interludeaudio-digital",
193 + .data = (void *) &drvdata_interlude_audio_digital },
194 {},
195 };
196