2 * ASoC Driver for AudioInjector Pi octo channel soundcard (hat)
4 * Created on: 27-October-2016
5 * Author: flatmax@flatmax.org
6 * based on audioinjector-pi-soundcard.c
8 * Copyright (C) 2016 Flatmax Pty. Ltd.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
20 #include <linux/module.h>
21 #include <linux/types.h>
22 #include <linux/gpio/consumer.h>
24 #include <sound/core.h>
25 #include <sound/soc.h>
26 #include <sound/pcm_params.h>
27 #include <sound/control.h>
29 static struct gpio_descs
*mult_gpios
;
30 static unsigned int audioinjector_octo_rate
;
32 static int audioinjector_octo_dai_init(struct snd_soc_pcm_runtime
*rtd
)
34 return snd_soc_dai_set_bclk_ratio(rtd
->cpu_dai
, 64);
37 static int audioinjector_octo_startup(struct snd_pcm_substream
*substream
)
39 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
40 rtd
->cpu_dai
->driver
->playback
.channels_min
= 8;
41 rtd
->cpu_dai
->driver
->playback
.channels_max
= 8;
42 rtd
->cpu_dai
->driver
->capture
.channels_min
= 8;
43 rtd
->cpu_dai
->driver
->capture
.channels_max
= 8;
44 rtd
->codec_dai
->driver
->capture
.channels_max
= 8;
48 static void audioinjector_octo_shutdown(struct snd_pcm_substream
*substream
)
50 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
51 rtd
->cpu_dai
->driver
->playback
.channels_min
= 2;
52 rtd
->cpu_dai
->driver
->playback
.channels_max
= 2;
53 rtd
->cpu_dai
->driver
->capture
.channels_min
= 2;
54 rtd
->cpu_dai
->driver
->capture
.channels_max
= 2;
55 rtd
->codec_dai
->driver
->capture
.channels_max
= 6;
58 static int audioinjector_octo_hw_params(struct snd_pcm_substream
*substream
,
59 struct snd_pcm_hw_params
*params
)
61 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
63 // set codec DAI configuration
64 int ret
= snd_soc_dai_set_fmt(rtd
->codec_dai
,
65 SND_SOC_DAIFMT_CBS_CFS
|SND_SOC_DAIFMT_DSP_A
|
66 SND_SOC_DAIFMT_NB_NF
);
70 // set cpu DAI configuration
71 ret
= snd_soc_dai_set_fmt(rtd
->cpu_dai
,
72 SND_SOC_DAIFMT_CBM_CFM
|SND_SOC_DAIFMT_I2S
|
73 SND_SOC_DAIFMT_NB_NF
);
77 audioinjector_octo_rate
= params_rate(params
);
82 static int audioinjector_octo_trigger(struct snd_pcm_substream
*substream
,
91 case SNDRV_PCM_TRIGGER_START
:
92 case SNDRV_PCM_TRIGGER_RESUME
:
93 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
94 switch (audioinjector_octo_rate
) {
142 case SNDRV_PCM_TRIGGER_STOP
:
143 case SNDRV_PCM_TRIGGER_SUSPEND
:
144 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
149 gpiod_set_array_value_cansleep(mult_gpios
->ndescs
, mult_gpios
->desc
,
155 static struct snd_soc_ops audioinjector_octo_ops
= {
156 .startup
= audioinjector_octo_startup
,
157 .shutdown
= audioinjector_octo_shutdown
,
158 .hw_params
= audioinjector_octo_hw_params
,
159 .trigger
= audioinjector_octo_trigger
,
162 static struct snd_soc_dai_link audioinjector_octo_dai
[] = {
164 .name
= "AudioInjector Octo",
165 .stream_name
= "AudioInject-HIFI",
166 .codec_dai_name
= "cs42448",
167 .ops
= &audioinjector_octo_ops
,
168 .init
= audioinjector_octo_dai_init
,
172 static const struct snd_soc_dapm_widget audioinjector_octo_widgets
[] = {
173 SND_SOC_DAPM_OUTPUT("OUTPUTS0"),
174 SND_SOC_DAPM_OUTPUT("OUTPUTS1"),
175 SND_SOC_DAPM_OUTPUT("OUTPUTS2"),
176 SND_SOC_DAPM_OUTPUT("OUTPUTS3"),
177 SND_SOC_DAPM_INPUT("INPUTS0"),
178 SND_SOC_DAPM_INPUT("INPUTS1"),
179 SND_SOC_DAPM_INPUT("INPUTS2"),
182 static const struct snd_soc_dapm_route audioinjector_octo_route
[] = {
183 /* Balanced outputs */
184 {"OUTPUTS0", NULL
, "AOUT1L"},
185 {"OUTPUTS0", NULL
, "AOUT1R"},
186 {"OUTPUTS1", NULL
, "AOUT2L"},
187 {"OUTPUTS1", NULL
, "AOUT2R"},
188 {"OUTPUTS2", NULL
, "AOUT3L"},
189 {"OUTPUTS2", NULL
, "AOUT3R"},
190 {"OUTPUTS3", NULL
, "AOUT4L"},
191 {"OUTPUTS3", NULL
, "AOUT4R"},
193 /* Balanced inputs */
194 {"AIN1L", NULL
, "INPUTS0"},
195 {"AIN1R", NULL
, "INPUTS0"},
196 {"AIN2L", NULL
, "INPUTS1"},
197 {"AIN2R", NULL
, "INPUTS1"},
198 {"AIN3L", NULL
, "INPUTS2"},
199 {"AIN3R", NULL
, "INPUTS2"},
202 static struct snd_soc_card snd_soc_audioinjector_octo
= {
203 .name
= "audioinjector-octo-soundcard",
204 .dai_link
= audioinjector_octo_dai
,
205 .num_links
= ARRAY_SIZE(audioinjector_octo_dai
),
207 .dapm_widgets
= audioinjector_octo_widgets
,
208 .num_dapm_widgets
= ARRAY_SIZE(audioinjector_octo_widgets
),
209 .dapm_routes
= audioinjector_octo_route
,
210 .num_dapm_routes
= ARRAY_SIZE(audioinjector_octo_route
),
213 static int audioinjector_octo_probe(struct platform_device
*pdev
)
215 struct snd_soc_card
*card
= &snd_soc_audioinjector_octo
;
218 card
->dev
= &pdev
->dev
;
220 if (pdev
->dev
.of_node
) {
221 struct snd_soc_dai_link
*dai
= &audioinjector_octo_dai
[0];
222 struct device_node
*i2s_node
=
223 of_parse_phandle(pdev
->dev
.of_node
,
224 "i2s-controller", 0);
225 struct device_node
*codec_node
=
226 of_parse_phandle(pdev
->dev
.of_node
,
229 mult_gpios
= devm_gpiod_get_array_optional(&pdev
->dev
, "mult",
231 if (IS_ERR(mult_gpios
))
232 return PTR_ERR(mult_gpios
);
234 if (i2s_node
&& codec_node
) {
235 dai
->cpu_dai_name
= NULL
;
236 dai
->cpu_of_node
= i2s_node
;
237 dai
->platform_name
= NULL
;
238 dai
->platform_of_node
= i2s_node
;
239 dai
->codec_name
= NULL
;
240 dai
->codec_of_node
= codec_node
;
242 if (!dai
->cpu_of_node
) {
244 "i2s-controller missing or invalid in DT\n");
248 "Property 'codec' missing or invalid\n");
253 ret
= snd_soc_register_card(card
);
255 dev_err(&pdev
->dev
, "snd_soc_register_card failed (%d)\n", ret
);
259 static int audioinjector_octo_remove(struct platform_device
*pdev
)
261 struct snd_soc_card
*card
= platform_get_drvdata(pdev
);
263 return snd_soc_unregister_card(card
);
266 static const struct of_device_id audioinjector_octo_of_match
[] = {
267 { .compatible
= "ai,audioinjector-octo-soundcard", },
270 MODULE_DEVICE_TABLE(of
, audioinjector_octo_of_match
);
272 static struct platform_driver audioinjector_octo_driver
= {
274 .name
= "audioinjector-audio",
275 .owner
= THIS_MODULE
,
276 .of_match_table
= audioinjector_octo_of_match
,
278 .probe
= audioinjector_octo_probe
,
279 .remove
= audioinjector_octo_remove
,
282 module_platform_driver(audioinjector_octo_driver
);
283 MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
284 MODULE_DESCRIPTION("AudioInjector.net octo Soundcard");
285 MODULE_LICENSE("GPL v2");
286 MODULE_ALIAS("platform:audioinjector-octo-soundcard");