2 * ASoC Driver for IQaudIO DAC
4 * Author: Florian Meier <florian.meier@koalo.de>
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.
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.
17 #include <linux/module.h>
18 #include <linux/gpio/consumer.h>
19 #include <linux/platform_device.h>
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>
27 static bool digital_gain_0db_limit = true;
29 static struct gpio_desc *mute_gpio;
31 static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
33 if (digital_gain_0db_limit)
36 struct snd_soc_card *card = rtd->card;
38 ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
40 dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
46 static void snd_rpi_iqaudio_gpio_mute(struct snd_soc_card *card)
49 dev_info(card->dev, "%s: muting amp using GPIO22\n",
51 gpiod_set_value_cansleep(mute_gpio, 0);
55 static void snd_rpi_iqaudio_gpio_unmute(struct snd_soc_card *card)
58 dev_info(card->dev, "%s: un-muting amp using GPIO22\n",
60 gpiod_set_value_cansleep(mute_gpio, 1);
64 static int snd_rpi_iqaudio_set_bias_level(struct snd_soc_card *card,
65 struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
67 struct snd_soc_pcm_runtime *rtd;
68 struct snd_soc_dai *codec_dai;
70 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
71 codec_dai = asoc_rtd_to_codec(rtd, 0);
73 if (dapm->dev != codec_dai->dev)
77 case SND_SOC_BIAS_PREPARE:
78 if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
82 snd_rpi_iqaudio_gpio_unmute(card);
85 case SND_SOC_BIAS_STANDBY:
86 if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
90 snd_rpi_iqaudio_gpio_mute(card);
100 SND_SOC_DAILINK_DEFS(hifi,
101 DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
102 DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi")),
103 DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
105 static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
107 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
108 SND_SOC_DAIFMT_CBS_CFS,
109 .init = snd_rpi_iqaudio_dac_init,
110 SND_SOC_DAILINK_REG(hifi),
114 /* audio machine driver */
115 static struct snd_soc_card snd_rpi_iqaudio_dac = {
116 .owner = THIS_MODULE,
117 .dai_link = snd_rpi_iqaudio_dac_dai,
118 .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
121 static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
124 bool gpio_unmute = false;
126 snd_rpi_iqaudio_dac.dev = &pdev->dev;
128 if (pdev->dev.of_node) {
129 struct device_node *i2s_node;
130 struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
131 struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
132 bool auto_gpio_mute = false;
134 i2s_node = of_parse_phandle(pdev->dev.of_node,
135 "i2s-controller", 0);
137 dai->cpus->dai_name = NULL;
138 dai->cpus->of_node = i2s_node;
139 dai->platforms->name = NULL;
140 dai->platforms->of_node = i2s_node;
143 digital_gain_0db_limit = !of_property_read_bool(
144 pdev->dev.of_node, "iqaudio,24db_digital_gain");
146 if (of_property_read_string(pdev->dev.of_node, "card_name",
148 card->name = "IQaudIODAC";
150 if (of_property_read_string(pdev->dev.of_node, "dai_name",
152 dai->name = "IQaudIO DAC";
154 if (of_property_read_string(pdev->dev.of_node,
155 "dai_stream_name", &dai->stream_name))
156 dai->stream_name = "IQaudIO DAC HiFi";
158 /* gpio_unmute - one time unmute amp using GPIO */
159 gpio_unmute = of_property_read_bool(pdev->dev.of_node,
160 "iqaudio-dac,unmute-amp");
162 /* auto_gpio_mute - mute/unmute amp using GPIO */
163 auto_gpio_mute = of_property_read_bool(pdev->dev.of_node,
164 "iqaudio-dac,auto-mute-amp");
166 if (auto_gpio_mute || gpio_unmute) {
167 mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
169 if (IS_ERR(mute_gpio)) {
170 ret = PTR_ERR(mute_gpio);
172 "Failed to get mute gpio: %d\n", ret);
176 if (auto_gpio_mute && mute_gpio)
177 snd_rpi_iqaudio_dac.set_bias_level =
178 snd_rpi_iqaudio_set_bias_level;
182 ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
184 if (ret != -EPROBE_DEFER)
186 "snd_soc_register_card() failed: %d\n", ret);
190 if (gpio_unmute && mute_gpio)
191 snd_rpi_iqaudio_gpio_unmute(&snd_rpi_iqaudio_dac);
196 static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
198 snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac);
200 snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
204 static const struct of_device_id iqaudio_of_match[] = {
205 { .compatible = "iqaudio,iqaudio-dac", },
208 MODULE_DEVICE_TABLE(of, iqaudio_of_match);
210 static struct platform_driver snd_rpi_iqaudio_dac_driver = {
212 .name = "snd-rpi-iqaudio-dac",
213 .owner = THIS_MODULE,
214 .of_match_table = iqaudio_of_match,
216 .probe = snd_rpi_iqaudio_dac_probe,
217 .remove = snd_rpi_iqaudio_dac_remove,
220 module_platform_driver(snd_rpi_iqaudio_dac_driver);
222 MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
223 MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
224 MODULE_LICENSE("GPL v2");