Skip to content

Commit 0044894

Browse files
IQaudIOpopcornmix
IQaudIO
authored andcommitted
Added IQaudIO Pi-Codec board support (#2969)
Add support for the IQaudIO Pi-Codec board. Signed-off-by: Gordon <[email protected]>
1 parent 909f814 commit 0044894

File tree

7 files changed

+309
-0
lines changed

7 files changed

+309
-0
lines changed

arch/arm/boot/dts/overlays/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
6666
i2c1-bcm2708.dtbo \
6767
i2s-gpio28-31.dtbo \
6868
ilitek251x.dtbo \
69+
iqaudio-codec.dtbo \
6970
iqaudio-dac.dtbo \
7071
iqaudio-dacplus.dtbo \
7172
iqaudio-digi-wm8804-audio.dtbo \

arch/arm/boot/dts/overlays/README

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,12 @@ Params: interrupt GPIO used for interrupt (default 4)
11341134
touchscreen (in pixels)
11351135

11361136

1137+
Name: iqaudio-codec
1138+
Info: Configures the IQaudio Codec audio card
1139+
Load: dtoverlay=iqaudio-codec
1140+
Params: <None>
1141+
1142+
11371143
Name: iqaudio-dac
11381144
Info: Configures the IQaudio DAC audio card
11391145
Load: dtoverlay=iqaudio-dac,<param>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Definitions for IQaudIO CODEC
2+
/dts-v1/;
3+
/plugin/;
4+
5+
/ {
6+
compatible = "brcm,bcm2708";
7+
8+
fragment@0 {
9+
target = <&i2s>;
10+
__overlay__ {
11+
status = "okay";
12+
};
13+
};
14+
15+
fragment@1 {
16+
target = <&i2c1>;
17+
__overlay__ {
18+
#address-cells = <1>;
19+
#size-cells = <0>;
20+
status = "okay";
21+
22+
da2713@1a {
23+
#sound-dai-cells = <0>;
24+
compatible = "dlg,da7213";
25+
reg = <0x1a>;
26+
status = "okay";
27+
};
28+
};
29+
};
30+
31+
fragment@2 {
32+
target = <&sound>;
33+
iqaudio_dac: __overlay__ {
34+
compatible = "iqaudio,iqaudio-codec";
35+
i2s-controller = <&i2s>;
36+
status = "okay";
37+
};
38+
};
39+
40+
__overrides__ {
41+
};
42+
};

arch/arm64/configs/bcmrpi3_defconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
803803
CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
804804
CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
805805
CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
806+
CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
806807
CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
807808
CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
808809
CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m

sound/soc/bcm/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI
103103
help
104104
Say Y or M if you want to add support for JustBoom Digi.
105105

106+
config SND_BCM2708_SOC_IQAUDIO_CODEC
107+
tristate "Support for IQaudIO-CODEC"
108+
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
109+
select SND_SOC_DA7213
110+
help
111+
Say Y or M if you want to add support for IQaudIO-CODEC.
112+
106113
config SND_BCM2708_SOC_IQAUDIO_DAC
107114
tristate "Support for IQaudIO-DAC"
108115
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S

sound/soc/bcm/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
1818
snd-soc-justboom-dac-objs := justboom-dac.o
1919
snd-soc-rpi-cirrus-objs := rpi-cirrus.o
2020
snd-soc-rpi-proto-objs := rpi-proto.o
21+
snd-soc-iqaudio-codec-objs := iqaudio-codec.o
2122
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
2223
snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
2324
snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusa
4142
obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
4243
obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
4344
obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
45+
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
4446
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
4547
obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
4648
obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o

sound/soc/bcm/iqaudio-codec.c

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* ASoC Driver for IQaudIO Raspberry Pi Codec board
3+
*
4+
* Author: Gordon Garrity <[email protected]>
5+
* (C) Copyright IQaudio Limited, 2017-2019
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* version 2 as published by the Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* General Public License for more details.
15+
*/
16+
17+
#include <linux/module.h>
18+
#include <linux/gpio/consumer.h>
19+
#include <linux/platform_device.h>
20+
21+
#include <sound/core.h>
22+
#include <sound/pcm.h>
23+
#include <sound/pcm_params.h>
24+
#include <sound/soc.h>
25+
#include <sound/jack.h>
26+
27+
#include <linux/acpi.h>
28+
#include <linux/slab.h>
29+
#include "../codecs/da7213.h"
30+
31+
static int pll_out = DA7213_PLL_FREQ_OUT_90316800;
32+
33+
static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w,
34+
struct snd_kcontrol *k, int event)
35+
{
36+
int ret = 0;
37+
struct snd_soc_dapm_context *dapm = w->dapm;
38+
struct snd_soc_card *card = dapm->card;
39+
struct snd_soc_pcm_runtime *rtd =
40+
snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
41+
struct snd_soc_dai *codec_dai = rtd->codec_dai;
42+
43+
if (SND_SOC_DAPM_EVENT_OFF(event)) {
44+
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0,
45+
0);
46+
if (ret)
47+
dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
48+
} else if (SND_SOC_DAPM_EVENT_ON(event)) {
49+
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
50+
pll_out);
51+
if (ret)
52+
dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
53+
}
54+
55+
return ret;
56+
}
57+
58+
static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w,
59+
struct snd_kcontrol *kcontrol,
60+
int event)
61+
{
62+
switch (event) {
63+
case SND_SOC_DAPM_POST_PMU:
64+
/* Delay for mic bias ramp */
65+
msleep(1000);
66+
break;
67+
default:
68+
break;
69+
}
70+
71+
return 0;
72+
}
73+
74+
static const struct snd_soc_dapm_widget dapm_widgets[] = {
75+
SND_SOC_DAPM_HP("HP Jack", NULL),
76+
SND_SOC_DAPM_MIC("MIC Jack", NULL),
77+
SND_SOC_DAPM_MIC("Onboard MIC", NULL),
78+
SND_SOC_DAPM_LINE("AUX Jack", NULL),
79+
SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0,
80+
snd_rpi_iqaudio_pll_control,
81+
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
82+
SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event),
83+
};
84+
85+
static const struct snd_soc_dapm_route audio_map[] = {
86+
{"HP Jack", NULL, "HPL"},
87+
{"HP Jack", NULL, "HPR"},
88+
{"HP Jack", NULL, "PLL Control"},
89+
90+
{"AUX Jack", NULL, "AUXR"},
91+
{"AUX Jack", NULL, "AUXL"},
92+
{"AUX Jack", NULL, "PLL Control"},
93+
94+
/* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
95+
{"MIC Jack", NULL, "MIC1"},
96+
{"MIC Jack", NULL, "PLL Control"},
97+
{"Onboard MIC", NULL, "MIC2"},
98+
{"Onboard MIC", NULL, "PLL Control"},
99+
};
100+
101+
/* machine stream operations */
102+
103+
static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd)
104+
{
105+
struct snd_soc_dai *codec_dai = rtd->codec_dai;
106+
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
107+
int ret;
108+
109+
/* Set bclk ratio to align with codec's BCLK rate */
110+
ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
111+
if (ret) {
112+
dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n");
113+
return ret;
114+
}
115+
116+
/* Set MCLK frequency to codec, onboard 11.2896MHz clock */
117+
return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600,
118+
SND_SOC_CLOCK_OUT);
119+
}
120+
121+
static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream,
122+
struct snd_pcm_hw_params *params)
123+
{
124+
struct snd_soc_pcm_runtime *rtd = substream->private_data;
125+
unsigned int samplerate = params_rate(params);
126+
127+
switch (samplerate) {
128+
case 8000:
129+
case 16000:
130+
case 32000:
131+
case 48000:
132+
case 96000:
133+
pll_out = DA7213_PLL_FREQ_OUT_98304000;
134+
return 0;
135+
case 44100:
136+
case 88200:
137+
pll_out = DA7213_PLL_FREQ_OUT_90316800;
138+
return 0;
139+
default:
140+
dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
141+
return -EINVAL;
142+
}
143+
}
144+
145+
static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
146+
.hw_params = snd_rpi_iqaudio_codec_hw_params,
147+
};
148+
149+
150+
static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = {
151+
{
152+
.cpu_dai_name = "bcm2708-i2s.0",
153+
.codec_dai_name = "da7213-hifi",
154+
.platform_name = "bmc2708-i2s.0",
155+
.codec_name = "da7213.1-001a",
156+
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
157+
SND_SOC_DAIFMT_CBM_CFM,
158+
.init = snd_rpi_iqaudio_codec_init,
159+
.ops = &snd_rpi_iqaudio_codec_ops,
160+
.symmetric_rates = 1,
161+
.symmetric_channels = 1,
162+
.symmetric_samplebits = 1,
163+
},
164+
};
165+
166+
/* audio machine driver */
167+
static struct snd_soc_card snd_rpi_iqaudio_codec = {
168+
.owner = THIS_MODULE,
169+
.dai_link = snd_rpi_iqaudio_codec_dai,
170+
.num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
171+
.dapm_widgets = dapm_widgets,
172+
.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
173+
.dapm_routes = audio_map,
174+
.num_dapm_routes = ARRAY_SIZE(audio_map),
175+
};
176+
177+
static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev)
178+
{
179+
int ret = 0;
180+
181+
snd_rpi_iqaudio_codec.dev = &pdev->dev;
182+
183+
if (pdev->dev.of_node) {
184+
struct device_node *i2s_node;
185+
struct snd_soc_card *card = &snd_rpi_iqaudio_codec;
186+
struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0];
187+
188+
i2s_node = of_parse_phandle(pdev->dev.of_node,
189+
"i2s-controller", 0);
190+
if (i2s_node) {
191+
dai->cpu_dai_name = NULL;
192+
dai->cpu_of_node = i2s_node;
193+
dai->platform_name = NULL;
194+
dai->platform_of_node = i2s_node;
195+
}
196+
197+
if (of_property_read_string(pdev->dev.of_node, "card_name",
198+
&card->name))
199+
card->name = "IQaudIOCODEC";
200+
201+
if (of_property_read_string(pdev->dev.of_node, "dai_name",
202+
&dai->name))
203+
dai->name = "IQaudIO CODEC";
204+
205+
if (of_property_read_string(pdev->dev.of_node,
206+
"dai_stream_name", &dai->stream_name))
207+
dai->stream_name = "IQaudIO CODEC HiFi v1.1";
208+
209+
}
210+
211+
ret = snd_soc_register_card(&snd_rpi_iqaudio_codec);
212+
if (ret) {
213+
if (ret != -EPROBE_DEFER)
214+
dev_err(&pdev->dev,
215+
"snd_soc_register_card() failed: %d\n", ret);
216+
return ret;
217+
}
218+
219+
return 0;
220+
}
221+
222+
static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev)
223+
{
224+
return snd_soc_unregister_card(&snd_rpi_iqaudio_codec);
225+
}
226+
227+
static const struct of_device_id iqaudio_of_match[] = {
228+
{ .compatible = "iqaudio,iqaudio-codec", },
229+
{},
230+
};
231+
232+
MODULE_DEVICE_TABLE(of, iqaudio_of_match);
233+
234+
static struct platform_driver snd_rpi_iqaudio_codec_driver = {
235+
.driver = {
236+
.name = "snd-rpi-iqaudio-codec",
237+
.owner = THIS_MODULE,
238+
.of_match_table = iqaudio_of_match,
239+
},
240+
.probe = snd_rpi_iqaudio_codec_probe,
241+
.remove = snd_rpi_iqaudio_codec_remove,
242+
};
243+
244+
245+
246+
module_platform_driver(snd_rpi_iqaudio_codec_driver);
247+
248+
MODULE_AUTHOR("Gordon Garrity <[email protected]>");
249+
MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC");
250+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)