brcm2708: update linux 4.4 patches to latest version
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0413-IQaudIO-auto-mute-for-AMP-and-DigiAMP.patch
1 From c5368041bdadf28f7081deb6e11c9aaafe05377f Mon Sep 17 00:00:00 2001
2 From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
3 Date: Mon, 9 May 2016 20:38:08 +0100
4 Subject: [PATCH 413/423] IQaudIO: auto-mute for AMP+ and DigiAMP+
5
6 IQAudIO amplifier mute via GPIO22. Add dt params for "one-shot" unmute
7 and auto mute.
8
9 Revision 2, auto mute implementing HiassofT suggestion to mute/unmute
10 using set_bias_level, rather than startup/shutdown....
11 "By default DAPM waits 5 seconds (pmdown_time) before shutting down
12 playback streams so a close/stop immediately followed by open/start
13 doesn't trigger an amp mute+unmute."
14
15 Tested on both AMP+ (via DAC+) and DigiAMP+, with both options...
16
17 dtoverlay=iqaudio-dacplus,unmute_amp
18 "one-shot" unmute when kernel module loads.
19
20 dtoverlay=iqaudio-dacplus,auto_mute_amp
21 Unmute amp when ALSA device opened by a client. Mute, with 5 second delay
22 when ALSA device closed. (Re-opening the device within the 5 second close
23 window, will cancel mute.)
24
25 Revision 4, using gpiod.
26
27 Revision 5, clean-up formatting before adding mute code.
28 - Convert tab plus 4 space formatting to 2x tab
29 - Remove '// NOT USED' commented code
30
31 Revision 6, don't attempt to "one-shot" unmute amp, unless card is
32 successfully registered.
33
34 Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
35 ---
36 arch/arm/boot/dts/overlays/README | 4 +
37 .../boot/dts/overlays/iqaudio-dacplus-overlay.dts | 7 +-
38 sound/soc/bcm/iqaudio-dac.c | 144 ++++++++++++++++-----
39 3 files changed, 124 insertions(+), 31 deletions(-)
40
41 --- a/arch/arm/boot/dts/overlays/README
42 +++ b/arch/arm/boot/dts/overlays/README
43 @@ -540,6 +540,10 @@ Params: 24db_digital_gain Allow ga
44 responsibility of the user to ensure that
45 the Digital volume control is set to a value
46 that does not result in clipping/distortion!)
47 + auto_mute_amp If specified, unmute/mute the IQaudIO amp when
48 + starting/stopping audio playback.
49 + unmute_amp If specified, unmute the IQaudIO amp once when
50 + the DAC driver module loads.
51
52
53 Name: justboom-dac
54 --- a/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
55 +++ b/arch/arm/boot/dts/overlays/iqaudio-dacplus-overlay.dts
56 @@ -30,14 +30,17 @@
57
58 fragment@2 {
59 target = <&sound>;
60 - frag2: __overlay__ {
61 + iqaudio_dac: __overlay__ {
62 compatible = "iqaudio,iqaudio-dac";
63 i2s-controller = <&i2s>;
64 + mute-gpios = <&gpio 22 0>;
65 status = "okay";
66 };
67 };
68
69 __overrides__ {
70 - 24db_digital_gain = <&frag2>,"iqaudio,24db_digital_gain?";
71 + 24db_digital_gain = <&iqaudio_dac>,"iqaudio,24db_digital_gain?";
72 + auto_mute_amp = <&iqaudio_dac>,"iqaudio-dac,auto-mute-amp?";
73 + unmute_amp = <&iqaudio_dac>,"iqaudio-dac,unmute-amp?";
74 };
75 };
76 --- a/sound/soc/bcm/iqaudio-dac.c
77 +++ b/sound/soc/bcm/iqaudio-dac.c
78 @@ -15,6 +15,7 @@
79 */
80
81 #include <linux/module.h>
82 +#include <linux/gpio/consumer.h>
83 #include <linux/platform_device.h>
84
85 #include <sound/core.h>
86 @@ -25,6 +26,8 @@
87
88 static bool digital_gain_0db_limit = true;
89
90 +static struct gpio_desc *mute_gpio;
91 +
92 static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
93 {
94 if (digital_gain_0db_limit)
95 @@ -41,11 +44,9 @@ static int snd_rpi_iqaudio_dac_init(stru
96 }
97
98 static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream,
99 - struct snd_pcm_hw_params *params)
100 + struct snd_pcm_hw_params *params)
101 {
102 struct snd_soc_pcm_runtime *rtd = substream->private_data;
103 -// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai;
104 -// NOT USED struct snd_soc_codec *codec = rtd->codec;
105 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
106
107 unsigned int sample_bits =
108 @@ -54,6 +55,56 @@ static int snd_rpi_iqaudio_dac_hw_params
109 return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
110 }
111
112 +static void snd_rpi_iqaudio_gpio_mute(struct snd_soc_card *card)
113 +{
114 + if (mute_gpio) {
115 + dev_info(card->dev, "%s: muting amp using GPIO22\n",
116 + __func__);
117 + gpiod_set_value_cansleep(mute_gpio, 0);
118 + }
119 +}
120 +
121 +static void snd_rpi_iqaudio_gpio_unmute(struct snd_soc_card *card)
122 +{
123 + if (mute_gpio) {
124 + dev_info(card->dev, "%s: un-muting amp using GPIO22\n",
125 + __func__);
126 + gpiod_set_value_cansleep(mute_gpio, 1);
127 + }
128 +}
129 +
130 +static int snd_rpi_iqaudio_set_bias_level(struct snd_soc_card *card,
131 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
132 +{
133 + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
134 +
135 + if (dapm->dev != codec_dai->dev)
136 + return 0;
137 +
138 + switch (level) {
139 + case SND_SOC_BIAS_PREPARE:
140 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
141 + break;
142 +
143 + /* UNMUTE AMP */
144 + snd_rpi_iqaudio_gpio_unmute(card);
145 +
146 + break;
147 + case SND_SOC_BIAS_STANDBY:
148 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
149 + break;
150 +
151 + /* MUTE AMP */
152 + snd_rpi_iqaudio_gpio_mute(card);
153 +
154 + break;
155 + default:
156 + break;
157 + }
158 +
159 + return 0;
160 +}
161 +
162 /* machine stream operations */
163 static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = {
164 .hw_params = snd_rpi_iqaudio_dac_hw_params,
165 @@ -82,46 +133,81 @@ static struct snd_soc_card snd_rpi_iqaud
166 static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
167 {
168 int ret = 0;
169 + bool gpio_unmute = false;
170
171 snd_rpi_iqaudio_dac.dev = &pdev->dev;
172
173 if (pdev->dev.of_node) {
174 - struct device_node *i2s_node;
175 - struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
176 - struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
177 - i2s_node = of_parse_phandle(pdev->dev.of_node,
178 - "i2s-controller", 0);
179 -
180 - if (i2s_node) {
181 - dai->cpu_dai_name = NULL;
182 - dai->cpu_of_node = i2s_node;
183 - dai->platform_name = NULL;
184 - dai->platform_of_node = i2s_node;
185 - }
186 -
187 - digital_gain_0db_limit = !of_property_read_bool(pdev->dev.of_node,
188 - "iqaudio,24db_digital_gain");
189 - if (of_property_read_string(pdev->dev.of_node, "card_name",
190 - &card->name))
191 - card->name = "IQaudIODAC";
192 - if (of_property_read_string(pdev->dev.of_node, "dai_name",
193 - &dai->name))
194 - dai->name = "IQaudIO DAC";
195 - if (of_property_read_string(pdev->dev.of_node, "dai_stream_name",
196 - &dai->stream_name))
197 - dai->stream_name = "IQaudIO DAC HiFi";
198 + struct device_node *i2s_node;
199 + struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
200 + struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
201 + bool auto_gpio_mute = false;
202 +
203 + i2s_node = of_parse_phandle(pdev->dev.of_node,
204 + "i2s-controller", 0);
205 + if (i2s_node) {
206 + dai->cpu_dai_name = NULL;
207 + dai->cpu_of_node = i2s_node;
208 + dai->platform_name = NULL;
209 + dai->platform_of_node = i2s_node;
210 + }
211 +
212 + digital_gain_0db_limit = !of_property_read_bool(
213 + pdev->dev.of_node, "iqaudio,24db_digital_gain");
214 +
215 + if (of_property_read_string(pdev->dev.of_node, "card_name",
216 + &card->name))
217 + card->name = "IQaudIODAC";
218 +
219 + if (of_property_read_string(pdev->dev.of_node, "dai_name",
220 + &dai->name))
221 + dai->name = "IQaudIO DAC";
222 +
223 + if (of_property_read_string(pdev->dev.of_node,
224 + "dai_stream_name", &dai->stream_name))
225 + dai->stream_name = "IQaudIO DAC HiFi";
226 +
227 + /* gpio_unmute - one time unmute amp using GPIO */
228 + gpio_unmute = of_property_read_bool(pdev->dev.of_node,
229 + "iqaudio-dac,unmute-amp");
230 +
231 + /* auto_gpio_mute - mute/unmute amp using GPIO */
232 + auto_gpio_mute = of_property_read_bool(pdev->dev.of_node,
233 + "iqaudio-dac,auto-mute-amp");
234 +
235 + if (auto_gpio_mute || gpio_unmute) {
236 + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
237 + GPIOD_OUT_LOW);
238 + if (IS_ERR(mute_gpio)) {
239 + ret = PTR_ERR(mute_gpio);
240 + dev_err(&pdev->dev,
241 + "Failed to get mute gpio: %d\n", ret);
242 + return ret;
243 + }
244 +
245 + if (auto_gpio_mute && mute_gpio)
246 + snd_rpi_iqaudio_dac.set_bias_level =
247 + snd_rpi_iqaudio_set_bias_level;
248 + }
249 }
250
251 ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
252 - if (ret)
253 + if (ret) {
254 dev_err(&pdev->dev,
255 "snd_soc_register_card() failed: %d\n", ret);
256 + return ret;
257 + }
258 +
259 + if (gpio_unmute && mute_gpio)
260 + snd_rpi_iqaudio_gpio_unmute(&snd_rpi_iqaudio_dac);
261
262 - return ret;
263 + return 0;
264 }
265
266 static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
267 {
268 + snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac);
269 +
270 return snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
271 }
272