04060d92d9993f4107c74b652bc94c2b398fb44e
[openwrt/staging/luka.git] /
1 From 649b1181f032801c12e17196618c032cdb3cb587 Mon Sep 17 00:00:00 2001
2 From: Raashid Muhammed <raashidmuhammed@zilogic.com>
3 Date: Mon, 27 Mar 2017 12:35:00 +0530
4 Subject: [PATCH 080/454] Add support for Allo Piano DAC 2.1 plus add-on board
5 for Raspberry Pi.
6
7 The Piano DAC 2.1 has support for 4 channels with subwoofer.
8
9 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
10 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
11 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
12
13 Add clock changes and mute gpios (#1938)
14
15 Also improve code style and adhere to ALSA coding conventions.
16
17 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
18 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
19 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
20
21 PianoPlus: Dual Mono & Dual Stereo features added (#2069)
22
23 allo-piano-dac-plus: Master volume added + fixes
24
25 Master volume added, which controls both DACs volumes.
26
27 See: https://github.com/raspberrypi/linux/pull/2149
28
29 Also fix initial max volume, default mode value, and unmute.
30
31 Signed-off-by: allocom <sparky-dev@allo.com>
32 ---
33 sound/soc/bcm/Kconfig | 7 +
34 sound/soc/bcm/Makefile | 2 +
35 sound/soc/bcm/allo-piano-dac-plus.c | 1014 +++++++++++++++++++++++++++
36 3 files changed, 1023 insertions(+)
37 create mode 100644 sound/soc/bcm/allo-piano-dac-plus.c
38
39 --- a/sound/soc/bcm/Kconfig
40 +++ b/sound/soc/bcm/Kconfig
41 @@ -131,3 +131,10 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC
42 select SND_SOC_PCM512x_I2C
43 help
44 Say Y or M if you want to add support for Allo Piano DAC.
45 +
46 +config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS
47 + tristate "Support for Allo Piano DAC Plus"
48 + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
49 + select SND_SOC_PCM512x_I2C
50 + help
51 + Say Y or M if you want to add support for Allo Piano DAC Plus.
52 --- a/sound/soc/bcm/Makefile
53 +++ b/sound/soc/bcm/Makefile
54 @@ -25,6 +25,7 @@ snd-soc-audioinjector-pi-soundcard-objs
55 snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
56 snd-soc-dionaudio-loco-objs := dionaudio_loco.o
57 snd-soc-allo-piano-dac-objs := allo-piano-dac.o
58 +snd-soc-allo-piano-dac-plus-objs := allo-piano-dac-plus.o
59
60 obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
61 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
62 @@ -42,3 +43,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDC
63 obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
64 obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
65 obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o
66 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS) += snd-soc-allo-piano-dac-plus.o
67 --- /dev/null
68 +++ b/sound/soc/bcm/allo-piano-dac-plus.c
69 @@ -0,0 +1,1014 @@
70 +/*
71 + * ALSA ASoC Machine Driver for Allo Piano DAC Plus Subwoofer
72 + *
73 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
74 + * Copyright 2016
75 + * based on code by Daniel Matuschek <info@crazy-audio.com>
76 + * based on code by Florian Meier <florian.meier@koalo.de>
77 + *
78 + * This program is free software; you can redistribute it and/or
79 + * modify it under the terms of the GNU General Public License
80 + * version 2 as published by the Free Software Foundation.
81 + *
82 + * This program is distributed in the hope that it will be useful, but
83 + * WITHOUT ANY WARRANTY; without even the implied warranty of
84 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
85 + * General Public License for more details.
86 + */
87 +
88 +#include <linux/module.h>
89 +#include <linux/platform_device.h>
90 +#include <linux/gpio/consumer.h>
91 +#include <sound/core.h>
92 +#include <sound/pcm.h>
93 +#include <sound/pcm_params.h>
94 +#include <sound/soc.h>
95 +#include <linux/firmware.h>
96 +#include <linux/delay.h>
97 +#include <sound/tlv.h>
98 +#include "../codecs/pcm512x.h"
99 +
100 +#define P_DAC_LEFT_MUTE 0x10
101 +#define P_DAC_RIGHT_MUTE 0x01
102 +#define P_DAC_MUTE 0x11
103 +#define P_DAC_UNMUTE 0x00
104 +#define P_MUTE 1
105 +#define P_UNMUTE 0
106 +
107 +struct dsp_code {
108 + char i2c_addr;
109 + char offset;
110 + char val;
111 +};
112 +
113 +struct glb_pool {
114 + struct mutex lock;
115 + unsigned int dual_mode;
116 + unsigned int set_lowpass;
117 + unsigned int set_mode;
118 + unsigned int set_rate;
119 + unsigned int dsp_page_number;
120 +};
121 +
122 +static bool digital_gain_0db_limit = true;
123 +bool glb_mclk;
124 +
125 +static struct gpio_desc *mute_gpio[2];
126 +
127 +static const char * const allo_piano_mode_texts[] = {
128 + "None",
129 + "2.0",
130 + "2.1",
131 + "2.2",
132 +};
133 +
134 +static const SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum,
135 + 0, 0, allo_piano_mode_texts);
136 +
137 +static const char * const allo_piano_dual_mode_texts[] = {
138 + "None",
139 + "Dual-Mono",
140 + "Dual-Stereo",
141 +};
142 +
143 +static const SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum,
144 + 0, 0, allo_piano_dual_mode_texts);
145 +
146 +static const char * const allo_piano_dsp_low_pass_texts[] = {
147 + "60",
148 + "70",
149 + "80",
150 + "90",
151 + "100",
152 + "110",
153 + "120",
154 + "130",
155 + "140",
156 + "150",
157 + "160",
158 + "170",
159 + "180",
160 + "190",
161 + "200",
162 +};
163 +
164 +static const SOC_ENUM_SINGLE_DECL(allo_piano_enum,
165 + 0, 0, allo_piano_dsp_low_pass_texts);
166 +
167 +static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
168 + unsigned int mode, unsigned int rate, unsigned int lowpass)
169 +{
170 + const struct firmware *fw;
171 + struct snd_soc_card *card = rtd->card;
172 + struct glb_pool *glb_ptr = card->drvdata;
173 + char firmware_name[60];
174 + int ret = 0, dac = 0;
175 +
176 + if (rate <= 46000)
177 + rate = 44100;
178 + else if (rate <= 68000)
179 + rate = 48000;
180 + else if (rate <= 92000)
181 + rate = 88200;
182 + else if (rate <= 136000)
183 + rate = 96000;
184 + else if (rate <= 184000)
185 + rate = 176400;
186 + else
187 + rate = 192000;
188 +
189 + if (lowpass > 14)
190 + glb_ptr->set_lowpass = lowpass = 0;
191 +
192 + if (mode > 3)
193 + glb_ptr->set_mode = mode = 0;
194 +
195 + if (mode > 0)
196 + glb_ptr->dual_mode = 0;
197 +
198 + /* same configuration loaded */
199 + if ((rate == glb_ptr->set_rate) && (lowpass == glb_ptr->set_lowpass)
200 + && (mode == glb_ptr->set_mode))
201 + return 0;
202 +
203 + switch (mode) {
204 + case 0: /* None */
205 + return 1;
206 +
207 + case 1: /* 2.0 */
208 + snd_soc_write(rtd->codec_dais[0]->codec,
209 + PCM512x_MUTE, P_DAC_UNMUTE);
210 + snd_soc_write(rtd->codec_dais[1]->codec,
211 + PCM512x_MUTE, P_DAC_MUTE);
212 + glb_ptr->set_rate = rate;
213 + glb_ptr->set_mode = mode;
214 + glb_ptr->set_lowpass = lowpass;
215 + return 1;
216 +
217 + default:
218 + snd_soc_write(rtd->codec_dais[0]->codec,
219 + PCM512x_MUTE, P_DAC_UNMUTE);
220 + snd_soc_write(rtd->codec_dais[1]->codec,
221 + PCM512x_MUTE, P_DAC_UNMUTE);
222 + }
223 +
224 + for (dac = 0; dac < rtd->num_codecs; dac++) {
225 + struct dsp_code *dsp_code_read;
226 + struct snd_soc_codec *codec = rtd->codec_dais[dac]->codec;
227 + int i = 1;
228 +
229 + if (dac == 0) { /* high */
230 + snprintf(firmware_name, sizeof(firmware_name),
231 + "allo/piano/2.2/allo-piano-dsp-%d-%d-%d.bin",
232 + rate, ((lowpass * 10) + 60), dac);
233 + } else { /* low */
234 + snprintf(firmware_name, sizeof(firmware_name),
235 + "allo/piano/2.%d/allo-piano-dsp-%d-%d-%d.bin",
236 + (mode - 1), rate, ((lowpass * 10) + 60), dac);
237 + }
238 +
239 + dev_info(codec->dev, "Dsp Firmware File Name: %s\n",
240 + firmware_name);
241 +
242 + ret = request_firmware(&fw, firmware_name, codec->dev);
243 + if (ret < 0) {
244 + dev_err(codec->dev,
245 + "Error: Allo Piano Firmware %s missing. %d\n",
246 + firmware_name, ret);
247 + goto err;
248 + }
249 +
250 + while (i < (fw->size - 1)) {
251 + dsp_code_read = (struct dsp_code *)&fw->data[i];
252 +
253 + if (dsp_code_read->offset == 0) {
254 + glb_ptr->dsp_page_number = dsp_code_read->val;
255 + ret = snd_soc_write(rtd->codec_dais[dac]->codec,
256 + PCM512x_PAGE_BASE(0),
257 + dsp_code_read->val);
258 +
259 + } else if (dsp_code_read->offset != 0) {
260 + ret = snd_soc_write(rtd->codec_dais[dac]->codec,
261 + (PCM512x_PAGE_BASE(
262 + glb_ptr->dsp_page_number) +
263 + dsp_code_read->offset),
264 + dsp_code_read->val);
265 + }
266 + if (ret < 0) {
267 + dev_err(codec->dev,
268 + "Failed to write Register: %d\n", ret);
269 + release_firmware(fw);
270 + goto err;
271 + }
272 + i = i + 3;
273 + }
274 + release_firmware(fw);
275 + }
276 + glb_ptr->set_rate = rate;
277 + glb_ptr->set_mode = mode;
278 + glb_ptr->set_lowpass = lowpass;
279 + return 1;
280 +
281 +err:
282 + return ret;
283 +}
284 +
285 +static int snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
286 + unsigned int mode, unsigned int rate, unsigned int lowpass)
287 +{
288 + struct snd_soc_card *card = rtd->card;
289 + struct glb_pool *glb_ptr = card->drvdata;
290 + int ret = 0;
291 +
292 + mutex_lock(&glb_ptr->lock);
293 +
294 + ret = __snd_allo_piano_dsp_program(rtd, mode, rate, lowpass);
295 +
296 + mutex_unlock(&glb_ptr->lock);
297 +
298 + return ret;
299 +}
300 +
301 +static int snd_allo_piano_dual_mode_get(struct snd_kcontrol *kcontrol,
302 + struct snd_ctl_elem_value *ucontrol)
303 +{
304 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
305 + struct glb_pool *glb_ptr = card->drvdata;
306 +
307 + ucontrol->value.integer.value[0] = glb_ptr->dual_mode;
308 +
309 + return 0;
310 +}
311 +
312 +static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
313 + struct snd_ctl_elem_value *ucontrol)
314 +{
315 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
316 + struct glb_pool *glb_ptr = card->drvdata;
317 + struct snd_soc_pcm_runtime *rtd;
318 + struct snd_card *snd_card_ptr = card->snd_card;
319 + struct snd_kcontrol *kctl;
320 + struct soc_mixer_control *mc;
321 + unsigned int left_val = 0, right_val = 0;
322 +
323 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
324 +
325 + if (ucontrol->value.integer.value[0] > 0) {
326 + glb_ptr->dual_mode = ucontrol->value.integer.value[0];
327 + glb_ptr->set_mode = 0;
328 + } else {
329 + if (glb_ptr->set_mode <= 0) {
330 + glb_ptr->dual_mode = 1;
331 + glb_ptr->set_mode = 0;
332 + } else {
333 + glb_ptr->dual_mode = 0;
334 + return 0;
335 + }
336 + }
337 +
338 + if (glb_ptr->dual_mode == 1) { // Dual Mono
339 + snd_soc_write(rtd->codec_dais[0]->codec,
340 + PCM512x_MUTE, P_DAC_RIGHT_MUTE);
341 + snd_soc_write(rtd->codec_dais[1]->codec,
342 + PCM512x_MUTE, P_DAC_LEFT_MUTE);
343 + snd_soc_write(rtd->codec_dais[0]->codec,
344 + PCM512x_DIGITAL_VOLUME_3, 0xff);
345 + snd_soc_write(rtd->codec_dais[1]->codec,
346 + PCM512x_DIGITAL_VOLUME_2, 0xff);
347 +
348 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
349 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
350 + sizeof(kctl->id.name))) {
351 + mc = (struct soc_mixer_control *)
352 + kctl->private_value;
353 + mc->rreg = mc->reg;
354 + break;
355 + }
356 + }
357 + } else {
358 + left_val = snd_soc_read(rtd->codec_dais[0]->codec,
359 + PCM512x_DIGITAL_VOLUME_2);
360 + right_val = snd_soc_read(rtd->codec_dais[1]->codec,
361 + PCM512x_DIGITAL_VOLUME_3);
362 +
363 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
364 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
365 + sizeof(kctl->id.name))) {
366 + mc = (struct soc_mixer_control *)
367 + kctl->private_value;
368 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
369 + break;
370 + }
371 + }
372 +
373 + snd_soc_write(rtd->codec_dais[0]->codec,
374 + PCM512x_DIGITAL_VOLUME_3, left_val);
375 + snd_soc_write(rtd->codec_dais[1]->codec,
376 + PCM512x_DIGITAL_VOLUME_2, right_val);
377 + snd_soc_write(rtd->codec_dais[0]->codec,
378 + PCM512x_MUTE, P_DAC_UNMUTE);
379 + snd_soc_write(rtd->codec_dais[1]->codec,
380 + PCM512x_MUTE, P_DAC_UNMUTE);
381 + }
382 +
383 + return 0;
384 +}
385 +
386 +static int snd_allo_piano_mode_get(struct snd_kcontrol *kcontrol,
387 + struct snd_ctl_elem_value *ucontrol)
388 +{
389 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
390 + struct glb_pool *glb_ptr = card->drvdata;
391 +
392 + ucontrol->value.integer.value[0] = glb_ptr->set_mode;
393 + return 0;
394 +}
395 +
396 +static int snd_allo_piano_mode_put(struct snd_kcontrol *kcontrol,
397 + struct snd_ctl_elem_value *ucontrol)
398 +{
399 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
400 + struct snd_soc_pcm_runtime *rtd;
401 + struct glb_pool *glb_ptr = card->drvdata;
402 + struct snd_card *snd_card_ptr = card->snd_card;
403 + struct snd_kcontrol *kctl;
404 + struct soc_mixer_control *mc;
405 + unsigned int left_val = 0, right_val = 0;
406 +
407 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
408 +
409 + if ((glb_ptr->dual_mode == 1) &&
410 + (ucontrol->value.integer.value[0] > 0)) {
411 + left_val = snd_soc_read(rtd->codec_dais[0]->codec,
412 + PCM512x_DIGITAL_VOLUME_2);
413 + right_val = snd_soc_read(rtd->codec_dais[1]->codec,
414 + PCM512x_DIGITAL_VOLUME_2);
415 +
416 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
417 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
418 + sizeof(kctl->id.name))) {
419 + mc = (struct soc_mixer_control *)
420 + kctl->private_value;
421 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
422 + break;
423 + }
424 + }
425 + snd_soc_write(rtd->codec_dais[0]->codec,
426 + PCM512x_DIGITAL_VOLUME_3, left_val);
427 + snd_soc_write(rtd->codec_dais[1]->codec,
428 + PCM512x_DIGITAL_VOLUME_3, right_val);
429 + }
430 +
431 + return(snd_allo_piano_dsp_program(rtd,
432 + ucontrol->value.integer.value[0],
433 + glb_ptr->set_rate, glb_ptr->set_lowpass));
434 +}
435 +
436 +static int snd_allo_piano_lowpass_get(struct snd_kcontrol *kcontrol,
437 + struct snd_ctl_elem_value *ucontrol)
438 +{
439 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
440 + struct glb_pool *glb_ptr = card->drvdata;
441 +
442 + ucontrol->value.integer.value[0] = glb_ptr->set_lowpass;
443 + return 0;
444 +}
445 +
446 +static int snd_allo_piano_lowpass_put(struct snd_kcontrol *kcontrol,
447 + struct snd_ctl_elem_value *ucontrol)
448 +{
449 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
450 + struct snd_soc_pcm_runtime *rtd;
451 + struct glb_pool *glb_ptr = card->drvdata;
452 +
453 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
454 + return(snd_allo_piano_dsp_program(rtd,
455 + glb_ptr->set_mode, glb_ptr->set_rate,
456 + ucontrol->value.integer.value[0]));
457 +}
458 +
459 +static int pcm512x_get_reg_sub(struct snd_kcontrol *kcontrol,
460 + struct snd_ctl_elem_value *ucontrol)
461 +{
462 + struct soc_mixer_control *mc =
463 + (struct soc_mixer_control *)kcontrol->private_value;
464 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
465 + struct glb_pool *glb_ptr = card->drvdata;
466 + struct snd_soc_pcm_runtime *rtd;
467 + unsigned int left_val = 0;
468 + unsigned int right_val = 0;
469 +
470 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
471 + right_val = snd_soc_read(rtd->codec_dais[1]->codec,
472 + PCM512x_DIGITAL_VOLUME_3);
473 + if (right_val < 0)
474 + return right_val;
475 +
476 + if (glb_ptr->dual_mode != 1) {
477 + left_val = snd_soc_read(rtd->codec_dais[1]->codec,
478 + PCM512x_DIGITAL_VOLUME_2);
479 + if (left_val < 0)
480 + return left_val;
481 +
482 + } else {
483 + left_val = right_val;
484 + }
485 +
486 + ucontrol->value.integer.value[0] =
487 + (~(left_val >> mc->shift)) & mc->max;
488 + ucontrol->value.integer.value[1] =
489 + (~(right_val >> mc->shift)) & mc->max;
490 +
491 + return 0;
492 +}
493 +
494 +static int pcm512x_set_reg_sub(struct snd_kcontrol *kcontrol,
495 + struct snd_ctl_elem_value *ucontrol)
496 +{
497 + struct soc_mixer_control *mc =
498 + (struct soc_mixer_control *)kcontrol->private_value;
499 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
500 + struct glb_pool *glb_ptr = card->drvdata;
501 + struct snd_soc_pcm_runtime *rtd;
502 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
503 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
504 + int ret = 0;
505 +
506 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
507 + if (glb_ptr->dual_mode != 1) {
508 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
509 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
510 + if (ret < 0)
511 + return ret;
512 + }
513 +
514 + if (digital_gain_0db_limit) {
515 + ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
516 + 207);
517 + if (ret < 0)
518 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
519 + ret);
520 + }
521 +
522 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
523 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
524 + if (ret < 0)
525 + return ret;
526 +
527 + return 1;
528 +}
529 +
530 +static int pcm512x_get_reg_sub_switch(struct snd_kcontrol *kcontrol,
531 + struct snd_ctl_elem_value *ucontrol)
532 +{
533 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
534 + struct snd_soc_pcm_runtime *rtd;
535 + int val = 0;
536 +
537 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
538 + val = snd_soc_read(rtd->codec_dais[1]->codec, PCM512x_MUTE);
539 + if (val < 0)
540 + return val;
541 +
542 + ucontrol->value.integer.value[0] =
543 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
544 + ucontrol->value.integer.value[1] =
545 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
546 +
547 + return val;
548 +}
549 +
550 +static int pcm512x_set_reg_sub_switch(struct snd_kcontrol *kcontrol,
551 + struct snd_ctl_elem_value *ucontrol)
552 +{
553 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
554 + struct snd_soc_pcm_runtime *rtd;
555 + struct glb_pool *glb_ptr = card->drvdata;
556 + unsigned int left_val = (ucontrol->value.integer.value[0]);
557 + unsigned int right_val = (ucontrol->value.integer.value[1]);
558 + int ret = 0;
559 +
560 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
561 + if (glb_ptr->set_mode != 1) {
562 + ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
563 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
564 + if (ret < 0)
565 + return ret;
566 + }
567 + return 1;
568 +
569 +}
570 +
571 +static int pcm512x_get_reg_master(struct snd_kcontrol *kcontrol,
572 + struct snd_ctl_elem_value *ucontrol)
573 +{
574 + struct soc_mixer_control *mc =
575 + (struct soc_mixer_control *)kcontrol->private_value;
576 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
577 + struct glb_pool *glb_ptr = card->drvdata;
578 + struct snd_soc_pcm_runtime *rtd;
579 + unsigned int left_val = 0, right_val = 0;
580 +
581 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
582 +
583 + left_val = snd_soc_read(rtd->codec_dais[0]->codec,
584 + PCM512x_DIGITAL_VOLUME_2);
585 + if (left_val < 0)
586 + return left_val;
587 +
588 + if (glb_ptr->dual_mode == 1) {
589 + right_val = snd_soc_read(rtd->codec_dais[1]->codec,
590 + PCM512x_DIGITAL_VOLUME_3);
591 + if (right_val < 0)
592 + return right_val;
593 + } else {
594 + right_val = snd_soc_read(rtd->codec_dais[0]->codec,
595 + PCM512x_DIGITAL_VOLUME_3);
596 + if (right_val < 0)
597 + return right_val;
598 + }
599 +
600 + ucontrol->value.integer.value[0] =
601 + (~(left_val >> mc->shift)) & mc->max;
602 + ucontrol->value.integer.value[1] =
603 + (~(right_val >> mc->shift)) & mc->max;
604 +
605 + return 0;
606 +}
607 +
608 +static int pcm512x_set_reg_master(struct snd_kcontrol *kcontrol,
609 + struct snd_ctl_elem_value *ucontrol)
610 +{
611 + struct soc_mixer_control *mc =
612 + (struct soc_mixer_control *)kcontrol->private_value;
613 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
614 + struct glb_pool *glb_ptr = card->drvdata;
615 + struct snd_soc_pcm_runtime *rtd;
616 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
617 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
618 + int ret = 0;
619 +
620 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
621 +
622 + if (digital_gain_0db_limit) {
623 + ret = snd_soc_limit_volume(card, "Master Playback Volume",
624 + 207);
625 + if (ret < 0)
626 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
627 + ret);
628 + }
629 +
630 + if (glb_ptr->dual_mode != 1) {
631 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
632 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
633 + if (ret < 0)
634 + return ret;
635 +
636 + ret = snd_soc_write(rtd->codec_dais[0]->codec,
637 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
638 + if (ret < 0)
639 + return ret;
640 +
641 + }
642 +
643 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
644 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
645 + if (ret < 0)
646 + return ret;
647 +
648 + ret = snd_soc_write(rtd->codec_dais[0]->codec,
649 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
650 + if (ret < 0)
651 + return ret;
652 + return 1;
653 +}
654 +
655 +static int pcm512x_get_reg_master_switch(struct snd_kcontrol *kcontrol,
656 + struct snd_ctl_elem_value *ucontrol)
657 +{
658 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
659 + struct glb_pool *glb_ptr = card->drvdata;
660 + struct snd_soc_pcm_runtime *rtd;
661 + int val = 0;
662 +
663 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
664 +
665 + val = snd_soc_read(rtd->codec_dais[0]->codec, PCM512x_MUTE);
666 + if (val < 0)
667 + return val;
668 +
669 + ucontrol->value.integer.value[0] =
670 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
671 +
672 + if (glb_ptr->dual_mode == 1) {
673 + val = snd_soc_read(rtd->codec_dais[1]->codec, PCM512x_MUTE);
674 + if (val < 0)
675 + return val;
676 + }
677 + ucontrol->value.integer.value[1] =
678 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
679 +
680 + return val;
681 +}
682 +
683 +static int pcm512x_set_reg_master_switch(struct snd_kcontrol *kcontrol,
684 + struct snd_ctl_elem_value *ucontrol)
685 +{
686 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
687 + struct snd_soc_pcm_runtime *rtd;
688 + struct glb_pool *glb_ptr = card->drvdata;
689 + unsigned int left_val = (ucontrol->value.integer.value[0]);
690 + unsigned int right_val = (ucontrol->value.integer.value[1]);
691 + int ret = 0;
692 +
693 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
694 + if (glb_ptr->dual_mode == 1) {
695 + ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
696 + ~((left_val & 0x01)<<4));
697 + if (ret < 0)
698 + return ret;
699 + ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
700 + ~((right_val & 0x01)));
701 + if (ret < 0)
702 + return ret;
703 +
704 + } else if (glb_ptr->set_mode == 1) {
705 + ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
706 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
707 + if (ret < 0)
708 + return ret;
709 +
710 + } else {
711 + ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
712 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
713 + if (ret < 0)
714 + return ret;
715 +
716 + ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
717 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
718 + if (ret < 0)
719 + return ret;
720 + }
721 + return 1;
722 +}
723 +
724 +static const DECLARE_TLV_DB_SCALE(digital_tlv_sub, -10350, 50, 1);
725 +static const DECLARE_TLV_DB_SCALE(digital_tlv_master, -10350, 50, 1);
726 +
727 +static const struct snd_kcontrol_new allo_piano_controls[] = {
728 + SOC_ENUM_EXT("Subwoofer mode Route",
729 + allo_piano_mode_enum,
730 + snd_allo_piano_mode_get,
731 + snd_allo_piano_mode_put),
732 +
733 + SOC_ENUM_EXT("Dual Mode Route",
734 + allo_piano_dual_mode_enum,
735 + snd_allo_piano_dual_mode_get,
736 + snd_allo_piano_dual_mode_put),
737 +
738 + SOC_ENUM_EXT("Lowpass Route", allo_piano_enum,
739 + snd_allo_piano_lowpass_get,
740 + snd_allo_piano_lowpass_put),
741 +
742 + SOC_DOUBLE_R_EXT_TLV("Subwoofer Playback Volume",
743 + PCM512x_DIGITAL_VOLUME_2,
744 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
745 + pcm512x_get_reg_sub,
746 + pcm512x_set_reg_sub,
747 + digital_tlv_sub),
748 +
749 + SOC_DOUBLE_EXT("Subwoofer Playback Switch",
750 + PCM512x_MUTE,
751 + PCM512x_RQML_SHIFT,
752 + PCM512x_RQMR_SHIFT, 1, 1,
753 + pcm512x_get_reg_sub_switch,
754 + pcm512x_set_reg_sub_switch),
755 +
756 + SOC_DOUBLE_R_EXT_TLV("Master Playback Volume",
757 + PCM512x_DIGITAL_VOLUME_2,
758 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
759 + pcm512x_get_reg_master,
760 + pcm512x_set_reg_master,
761 + digital_tlv_master),
762 +
763 + SOC_DOUBLE_EXT("Master Playback Switch",
764 + PCM512x_MUTE,
765 + PCM512x_RQML_SHIFT,
766 + PCM512x_RQMR_SHIFT, 1, 1,
767 + pcm512x_get_reg_master_switch,
768 + pcm512x_set_reg_master_switch),
769 +};
770 +
771 +static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
772 +{
773 + struct snd_soc_card *card = rtd->card;
774 + struct glb_pool *glb_ptr;
775 +
776 + glb_ptr = kmalloc(sizeof(struct glb_pool), GFP_KERNEL);
777 + if (!glb_ptr)
778 + return -ENOMEM;
779 +
780 + memset(glb_ptr, 0x00, sizeof(glb_ptr));
781 + card->drvdata = glb_ptr;
782 + glb_ptr->dual_mode = 2;
783 + glb_ptr->set_mode = 0;
784 +
785 + mutex_init(&glb_ptr->lock);
786 +
787 + if (digital_gain_0db_limit) {
788 + int ret;
789 +
790 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
791 + 207);
792 + if (ret < 0)
793 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
794 + ret);
795 + }
796 + return 0;
797 +}
798 +
799 +static void snd_allo_piano_gpio_mute(struct snd_soc_card *card)
800 +{
801 + if (mute_gpio[0])
802 + gpiod_set_value_cansleep(mute_gpio[0], P_MUTE);
803 +
804 + if (mute_gpio[1])
805 + gpiod_set_value_cansleep(mute_gpio[1], P_MUTE);
806 +}
807 +
808 +static void snd_allo_piano_gpio_unmute(struct snd_soc_card *card)
809 +{
810 + if (mute_gpio[0])
811 + gpiod_set_value_cansleep(mute_gpio[0], P_UNMUTE);
812 +
813 + if (mute_gpio[1])
814 + gpiod_set_value_cansleep(mute_gpio[1], P_UNMUTE);
815 +}
816 +
817 +static int snd_allo_piano_set_bias_level(struct snd_soc_card *card,
818 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
819 +{
820 + struct snd_soc_pcm_runtime *rtd;
821 + struct snd_soc_dai *codec_dai;
822 +
823 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
824 + codec_dai = rtd->codec_dai;
825 +
826 + if (dapm->dev != codec_dai->dev)
827 + return 0;
828 +
829 + switch (level) {
830 + case SND_SOC_BIAS_PREPARE:
831 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
832 + break;
833 + /* UNMUTE DAC */
834 + snd_allo_piano_gpio_unmute(card);
835 + break;
836 +
837 + case SND_SOC_BIAS_STANDBY:
838 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
839 + break;
840 + /* MUTE DAC */
841 + snd_allo_piano_gpio_mute(card);
842 + break;
843 +
844 + default:
845 + break;
846 + }
847 +
848 + return 0;
849 +}
850 +
851 +static int snd_allo_piano_dac_startup(
852 + struct snd_pcm_substream *substream)
853 +{
854 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
855 + struct snd_soc_card *card = rtd->card;
856 +
857 + snd_allo_piano_gpio_mute(card);
858 +
859 + return 0;
860 +}
861 +
862 +static int snd_allo_piano_dac_hw_params(
863 + struct snd_pcm_substream *substream,
864 + struct snd_pcm_hw_params *params)
865 +{
866 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
867 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
868 + unsigned int sample_bits =
869 + snd_pcm_format_physical_width(params_format(params));
870 + unsigned int rate = params_rate(params);
871 + struct snd_soc_card *card = rtd->card;
872 + struct glb_pool *glb_ptr = card->drvdata;
873 + int ret = 0, val = 0, dac;
874 +
875 + for (dac = 0; (glb_mclk && dac < 2); dac++) {
876 + /* Configure the PLL clock reference for both the Codecs */
877 + val = snd_soc_read(rtd->codec_dais[dac]->codec,
878 + PCM512x_RATE_DET_4);
879 + if (val < 0) {
880 + dev_err(rtd->codec_dais[dac]->codec->dev,
881 + "Failed to read register PCM512x_RATE_DET_4\n");
882 + return val;
883 + }
884 +
885 + if (val & 0x40) {
886 + snd_soc_write(rtd->codec_dais[dac]->codec,
887 + PCM512x_PLL_REF,
888 + PCM512x_SREF_BCK);
889 +
890 + dev_info(rtd->codec_dais[dac]->codec->dev,
891 + "Setting BCLK as input clock & Enable PLL\n");
892 + } else {
893 + snd_soc_write(rtd->codec_dais[dac]->codec,
894 + PCM512x_PLL_EN,
895 + 0x00);
896 +
897 + snd_soc_write(rtd->codec_dais[dac]->codec,
898 + PCM512x_PLL_REF,
899 + PCM512x_SREF_SCK);
900 +
901 + dev_info(rtd->codec_dais[dac]->codec->dev,
902 + "Setting SCLK as input clock & disabled PLL\n");
903 + }
904 + }
905 +
906 + ret = snd_allo_piano_dsp_program(rtd, glb_ptr->set_mode, rate,
907 + glb_ptr->set_lowpass);
908 + if (ret < 0)
909 + return ret;
910 +
911 + ret = snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
912 +
913 + return ret;
914 +}
915 +
916 +static int snd_allo_piano_dac_prepare(
917 + struct snd_pcm_substream *substream)
918 +{
919 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
920 + struct snd_soc_card *card = rtd->card;
921 +
922 + snd_allo_piano_gpio_unmute(card);
923 +
924 + return 0;
925 +}
926 +
927 +/* machine stream operations */
928 +static struct snd_soc_ops snd_allo_piano_dac_ops = {
929 + .startup = snd_allo_piano_dac_startup,
930 + .hw_params = snd_allo_piano_dac_hw_params,
931 + .prepare = snd_allo_piano_dac_prepare,
932 +};
933 +
934 +static struct snd_soc_dai_link_component allo_piano_2_1_codecs[] = {
935 + {
936 + .dai_name = "pcm512x-hifi",
937 + },
938 + {
939 + .dai_name = "pcm512x-hifi",
940 + },
941 +};
942 +
943 +static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
944 + {
945 + .name = "PianoDACPlus",
946 + .stream_name = "PianoDACPlus",
947 + .cpu_dai_name = "bcm2708-i2s.0",
948 + .platform_name = "bcm2708-i2s.0",
949 + .codecs = allo_piano_2_1_codecs,
950 + .num_codecs = 2,
951 + .dai_fmt = SND_SOC_DAIFMT_I2S |
952 + SND_SOC_DAIFMT_NB_NF |
953 + SND_SOC_DAIFMT_CBS_CFS,
954 + .ops = &snd_allo_piano_dac_ops,
955 + .init = snd_allo_piano_dac_init,
956 + },
957 +};
958 +
959 +/* audio machine driver */
960 +static struct snd_soc_card snd_allo_piano_dac = {
961 + .name = "PianoDACPlus",
962 + .owner = THIS_MODULE,
963 + .dai_link = snd_allo_piano_dac_dai,
964 + .num_links = ARRAY_SIZE(snd_allo_piano_dac_dai),
965 + .controls = allo_piano_controls,
966 + .num_controls = ARRAY_SIZE(allo_piano_controls),
967 +};
968 +
969 +static int snd_allo_piano_dac_probe(struct platform_device *pdev)
970 +{
971 + struct snd_soc_card *card = &snd_allo_piano_dac;
972 + int ret = 0, i = 0;
973 +
974 + card->dev = &pdev->dev;
975 + platform_set_drvdata(pdev, &snd_allo_piano_dac);
976 +
977 + if (pdev->dev.of_node) {
978 + struct device_node *i2s_node;
979 + struct snd_soc_dai_link *dai;
980 +
981 + dai = &snd_allo_piano_dac_dai[0];
982 + i2s_node = of_parse_phandle(pdev->dev.of_node,
983 + "i2s-controller", 0);
984 + if (i2s_node) {
985 + for (i = 0; i < card->num_links; i++) {
986 + dai->cpu_dai_name = NULL;
987 + dai->cpu_of_node = i2s_node;
988 + dai->platform_name = NULL;
989 + dai->platform_of_node = i2s_node;
990 + }
991 + }
992 + digital_gain_0db_limit =
993 + !of_property_read_bool(pdev->dev.of_node,
994 + "allo,24db_digital_gain");
995 +
996 + glb_mclk = of_property_read_bool(pdev->dev.of_node,
997 + "allo,glb_mclk");
998 +
999 + allo_piano_2_1_codecs[0].of_node =
1000 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
1001 + if (!allo_piano_2_1_codecs[0].of_node) {
1002 + dev_err(&pdev->dev,
1003 + "Property 'audio-codec' missing or invalid\n");
1004 + return -EINVAL;
1005 + }
1006 +
1007 + allo_piano_2_1_codecs[1].of_node =
1008 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 1);
1009 + if (!allo_piano_2_1_codecs[1].of_node) {
1010 + dev_err(&pdev->dev,
1011 + "Property 'audio-codec' missing or invalid\n");
1012 + return -EINVAL;
1013 + }
1014 +
1015 + mute_gpio[0] = devm_gpiod_get_optional(&pdev->dev, "mute1",
1016 + GPIOD_OUT_LOW);
1017 + if (IS_ERR(mute_gpio[0])) {
1018 + ret = PTR_ERR(mute_gpio[0]);
1019 + dev_err(&pdev->dev,
1020 + "failed to get mute1 gpio6: %d\n", ret);
1021 + return ret;
1022 + }
1023 +
1024 + mute_gpio[1] = devm_gpiod_get_optional(&pdev->dev, "mute2",
1025 + GPIOD_OUT_LOW);
1026 + if (IS_ERR(mute_gpio[1])) {
1027 + ret = PTR_ERR(mute_gpio[1]);
1028 + dev_err(&pdev->dev,
1029 + "failed to get mute2 gpio25: %d\n", ret);
1030 + return ret;
1031 + }
1032 +
1033 + if (mute_gpio[0] && mute_gpio[1])
1034 + snd_allo_piano_dac.set_bias_level =
1035 + snd_allo_piano_set_bias_level;
1036 +
1037 + ret = snd_soc_register_card(&snd_allo_piano_dac);
1038 + if (ret < 0) {
1039 + dev_err(&pdev->dev,
1040 + "snd_soc_register_card() failed: %d\n", ret);
1041 + return ret;
1042 + }
1043 +
1044 + if ((mute_gpio[0]) && (mute_gpio[1]))
1045 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1046 +
1047 + return 0;
1048 + }
1049 +
1050 + return -EINVAL;
1051 +}
1052 +
1053 +static int snd_allo_piano_dac_remove(struct platform_device *pdev)
1054 +{
1055 + struct snd_soc_card *card = platform_get_drvdata(pdev);
1056 +
1057 + kfree(&card->drvdata);
1058 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1059 + return snd_soc_unregister_card(&snd_allo_piano_dac);
1060 +}
1061 +
1062 +static const struct of_device_id snd_allo_piano_dac_of_match[] = {
1063 + { .compatible = "allo,piano-dac-plus", },
1064 + { /* sentinel */ },
1065 +};
1066 +
1067 +MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
1068 +
1069 +static struct platform_driver snd_allo_piano_dac_driver = {
1070 + .driver = {
1071 + .name = "snd-allo-piano-dac-plus",
1072 + .owner = THIS_MODULE,
1073 + .of_match_table = snd_allo_piano_dac_of_match,
1074 + },
1075 + .probe = snd_allo_piano_dac_probe,
1076 + .remove = snd_allo_piano_dac_remove,
1077 +};
1078 +
1079 +module_platform_driver(snd_allo_piano_dac_driver);
1080 +
1081 +MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
1082 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC Plus");
1083 +MODULE_LICENSE("GPL v2");