1 From 93af36d0b04fd39e5f14769a3284a1d4620fba39 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] Add support for Allo Piano DAC 2.1 plus add-on board
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 The Piano DAC 2.1 has support for 4 channels with subwoofer.
12 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
13 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
14 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
16 Add clock changes and mute gpios (#1938)
18 Also improve code style and adhere to ALSA coding conventions.
20 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
21 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
22 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
24 PianoPlus: Dual Mono & Dual Stereo features added (#2069)
26 allo-piano-dac-plus: Master volume added + fixes
28 Master volume added, which controls both DACs volumes.
30 See: https://github.com/raspberrypi/linux/pull/2149
32 Also fix initial max volume, default mode value, and unmute.
34 Signed-off-by: allocom <sparky-dev@allo.com>
36 ASoC: allo-piano-dac-plus: fix S24_LE format
38 Remove set_bclk_ratio call so 24-bit data is transmitted in
41 Signed-off-by: Matthias Reichl <hias@horus.com>
43 sound: bcm: Fix memset dereference warning
45 This warning appears with GCC 6.4.0 from toolchains.bootlin.com:
47 ../sound/soc/bcm/allo-piano-dac-plus.c: In function ‘snd_allo_piano_dac_init’:
48 ../sound/soc/bcm/allo-piano-dac-plus.c:711:30: warning: argument to ‘sizeof’ in ‘memset’ call is the same expression as the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess]
49 memset(glb_ptr, 0x00, sizeof(glb_ptr));
52 Suggested-by: Phil Elwell <phil@raspberrypi.org>
53 Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
55 ASoC: allo-piano-dac-plus: use modern dai_link style
57 Signed-off-by: Hui Wang <hui.wang@canonical.com>
59 sound/soc/bcm/allo-piano-dac-plus.c | 1013 +++++++++++++++++++++++++++
60 1 file changed, 1013 insertions(+)
61 create mode 100644 sound/soc/bcm/allo-piano-dac-plus.c
64 +++ b/sound/soc/bcm/allo-piano-dac-plus.c
67 + * ALSA ASoC Machine Driver for Allo Piano DAC Plus Subwoofer
69 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
71 + * based on code by Daniel Matuschek <info@crazy-audio.com>
72 + * based on code by Florian Meier <florian.meier@koalo.de>
74 + * This program is free software; you can redistribute it and/or
75 + * modify it under the terms of the GNU General Public License
76 + * version 2 as published by the Free Software Foundation.
78 + * This program is distributed in the hope that it will be useful, but
79 + * WITHOUT ANY WARRANTY; without even the implied warranty of
80 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
81 + * General Public License for more details.
84 +#include <linux/module.h>
85 +#include <linux/platform_device.h>
86 +#include <linux/gpio/consumer.h>
87 +#include <sound/core.h>
88 +#include <sound/pcm.h>
89 +#include <sound/pcm_params.h>
90 +#include <sound/soc.h>
91 +#include <linux/firmware.h>
92 +#include <linux/delay.h>
93 +#include <sound/tlv.h>
94 +#include "../codecs/pcm512x.h"
96 +#define P_DAC_LEFT_MUTE 0x10
97 +#define P_DAC_RIGHT_MUTE 0x01
98 +#define P_DAC_MUTE 0x11
99 +#define P_DAC_UNMUTE 0x00
111 + unsigned int dual_mode;
112 + unsigned int set_lowpass;
113 + unsigned int set_mode;
114 + unsigned int set_rate;
115 + unsigned int dsp_page_number;
118 +static bool digital_gain_0db_limit = true;
121 +static struct gpio_desc *mute_gpio[2];
123 +static const char * const allo_piano_mode_texts[] = {
130 +static const SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum,
131 + 0, 0, allo_piano_mode_texts);
133 +static const char * const allo_piano_dual_mode_texts[] = {
139 +static const SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum,
140 + 0, 0, allo_piano_dual_mode_texts);
142 +static const char * const allo_piano_dsp_low_pass_texts[] = {
160 +static const SOC_ENUM_SINGLE_DECL(allo_piano_enum,
161 + 0, 0, allo_piano_dsp_low_pass_texts);
163 +static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
164 + unsigned int mode, unsigned int rate, unsigned int lowpass)
166 + const struct firmware *fw;
167 + struct snd_soc_card *card = rtd->card;
168 + struct glb_pool *glb_ptr = card->drvdata;
169 + char firmware_name[60];
170 + int ret = 0, dac = 0;
174 + else if (rate <= 68000)
176 + else if (rate <= 92000)
178 + else if (rate <= 136000)
180 + else if (rate <= 184000)
186 + glb_ptr->set_lowpass = lowpass = 0;
189 + glb_ptr->set_mode = mode = 0;
192 + glb_ptr->dual_mode = 0;
194 + /* same configuration loaded */
195 + if ((rate == glb_ptr->set_rate) && (lowpass == glb_ptr->set_lowpass)
196 + && (mode == glb_ptr->set_mode))
204 + snd_soc_component_write(rtd->codec_dais[0]->component,
205 + PCM512x_MUTE, P_DAC_UNMUTE);
206 + snd_soc_component_write(rtd->codec_dais[1]->component,
207 + PCM512x_MUTE, P_DAC_MUTE);
208 + glb_ptr->set_rate = rate;
209 + glb_ptr->set_mode = mode;
210 + glb_ptr->set_lowpass = lowpass;
214 + snd_soc_component_write(rtd->codec_dais[0]->component,
215 + PCM512x_MUTE, P_DAC_UNMUTE);
216 + snd_soc_component_write(rtd->codec_dais[1]->component,
217 + PCM512x_MUTE, P_DAC_UNMUTE);
220 + for (dac = 0; dac < rtd->num_codecs; dac++) {
221 + struct dsp_code *dsp_code_read;
224 + if (dac == 0) { /* high */
225 + snprintf(firmware_name, sizeof(firmware_name),
226 + "allo/piano/2.2/allo-piano-dsp-%d-%d-%d.bin",
227 + rate, ((lowpass * 10) + 60), dac);
229 + snprintf(firmware_name, sizeof(firmware_name),
230 + "allo/piano/2.%d/allo-piano-dsp-%d-%d-%d.bin",
231 + (mode - 1), rate, ((lowpass * 10) + 60), dac);
234 + dev_info(rtd->card->dev, "Dsp Firmware File Name: %s\n",
237 + ret = request_firmware(&fw, firmware_name, rtd->card->dev);
239 + dev_err(rtd->card->dev,
240 + "Error: Allo Piano Firmware %s missing. %d\n",
241 + firmware_name, ret);
245 + while (i < (fw->size - 1)) {
246 + dsp_code_read = (struct dsp_code *)&fw->data[i];
248 + if (dsp_code_read->offset == 0) {
249 + glb_ptr->dsp_page_number = dsp_code_read->val;
250 + ret = snd_soc_component_write(rtd->codec_dais[dac]->component,
251 + PCM512x_PAGE_BASE(0),
252 + dsp_code_read->val);
254 + } else if (dsp_code_read->offset != 0) {
255 + ret = snd_soc_component_write(rtd->codec_dais[dac]->component,
256 + (PCM512x_PAGE_BASE(
257 + glb_ptr->dsp_page_number) +
258 + dsp_code_read->offset),
259 + dsp_code_read->val);
262 + dev_err(rtd->card->dev,
263 + "Failed to write Register: %d\n", ret);
264 + release_firmware(fw);
269 + release_firmware(fw);
271 + glb_ptr->set_rate = rate;
272 + glb_ptr->set_mode = mode;
273 + glb_ptr->set_lowpass = lowpass;
280 +static int snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
281 + unsigned int mode, unsigned int rate, unsigned int lowpass)
283 + struct snd_soc_card *card = rtd->card;
284 + struct glb_pool *glb_ptr = card->drvdata;
287 + mutex_lock(&glb_ptr->lock);
289 + ret = __snd_allo_piano_dsp_program(rtd, mode, rate, lowpass);
291 + mutex_unlock(&glb_ptr->lock);
296 +static int snd_allo_piano_dual_mode_get(struct snd_kcontrol *kcontrol,
297 + struct snd_ctl_elem_value *ucontrol)
299 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
300 + struct glb_pool *glb_ptr = card->drvdata;
302 + ucontrol->value.integer.value[0] = glb_ptr->dual_mode;
307 +static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
308 + struct snd_ctl_elem_value *ucontrol)
310 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
311 + struct glb_pool *glb_ptr = card->drvdata;
312 + struct snd_soc_pcm_runtime *rtd;
313 + struct snd_card *snd_card_ptr = card->snd_card;
314 + struct snd_kcontrol *kctl;
315 + struct soc_mixer_control *mc;
316 + unsigned int left_val = 0, right_val = 0;
318 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
320 + if (ucontrol->value.integer.value[0] > 0) {
321 + glb_ptr->dual_mode = ucontrol->value.integer.value[0];
322 + glb_ptr->set_mode = 0;
324 + if (glb_ptr->set_mode <= 0) {
325 + glb_ptr->dual_mode = 1;
326 + glb_ptr->set_mode = 0;
328 + glb_ptr->dual_mode = 0;
333 + if (glb_ptr->dual_mode == 1) { // Dual Mono
334 + snd_soc_component_write(rtd->codec_dais[0]->component,
335 + PCM512x_MUTE, P_DAC_RIGHT_MUTE);
336 + snd_soc_component_write(rtd->codec_dais[1]->component,
337 + PCM512x_MUTE, P_DAC_LEFT_MUTE);
338 + snd_soc_component_write(rtd->codec_dais[0]->component,
339 + PCM512x_DIGITAL_VOLUME_3, 0xff);
340 + snd_soc_component_write(rtd->codec_dais[1]->component,
341 + PCM512x_DIGITAL_VOLUME_2, 0xff);
343 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
344 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
345 + sizeof(kctl->id.name))) {
346 + mc = (struct soc_mixer_control *)
347 + kctl->private_value;
348 + mc->rreg = mc->reg;
353 + snd_soc_component_read(rtd->codec_dais[0]->component,
354 + PCM512x_DIGITAL_VOLUME_2, &left_val);
355 + snd_soc_component_read(rtd->codec_dais[1]->component,
356 + PCM512x_DIGITAL_VOLUME_3, &right_val);
358 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
359 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
360 + sizeof(kctl->id.name))) {
361 + mc = (struct soc_mixer_control *)
362 + kctl->private_value;
363 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
368 + snd_soc_component_write(rtd->codec_dais[0]->component,
369 + PCM512x_DIGITAL_VOLUME_3, left_val);
370 + snd_soc_component_write(rtd->codec_dais[1]->component,
371 + PCM512x_DIGITAL_VOLUME_2, right_val);
372 + snd_soc_component_write(rtd->codec_dais[0]->component,
373 + PCM512x_MUTE, P_DAC_UNMUTE);
374 + snd_soc_component_write(rtd->codec_dais[1]->component,
375 + PCM512x_MUTE, P_DAC_UNMUTE);
381 +static int snd_allo_piano_mode_get(struct snd_kcontrol *kcontrol,
382 + struct snd_ctl_elem_value *ucontrol)
384 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
385 + struct glb_pool *glb_ptr = card->drvdata;
387 + ucontrol->value.integer.value[0] = glb_ptr->set_mode;
391 +static int snd_allo_piano_mode_put(struct snd_kcontrol *kcontrol,
392 + struct snd_ctl_elem_value *ucontrol)
394 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
395 + struct snd_soc_pcm_runtime *rtd;
396 + struct glb_pool *glb_ptr = card->drvdata;
397 + struct snd_card *snd_card_ptr = card->snd_card;
398 + struct snd_kcontrol *kctl;
399 + struct soc_mixer_control *mc;
400 + unsigned int left_val = 0, right_val = 0;
402 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
404 + if ((glb_ptr->dual_mode == 1) &&
405 + (ucontrol->value.integer.value[0] > 0)) {
406 + snd_soc_component_read(rtd->codec_dais[0]->component,
407 + PCM512x_DIGITAL_VOLUME_2, &left_val);
408 + snd_soc_component_read(rtd->codec_dais[1]->component,
409 + PCM512x_DIGITAL_VOLUME_2, &right_val);
411 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
412 + if (!strncmp(kctl->id.name, "Digital Playback Volume",
413 + sizeof(kctl->id.name))) {
414 + mc = (struct soc_mixer_control *)
415 + kctl->private_value;
416 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
420 + snd_soc_component_write(rtd->codec_dais[0]->component,
421 + PCM512x_DIGITAL_VOLUME_3, left_val);
422 + snd_soc_component_write(rtd->codec_dais[1]->component,
423 + PCM512x_DIGITAL_VOLUME_3, right_val);
426 + return(snd_allo_piano_dsp_program(rtd,
427 + ucontrol->value.integer.value[0],
428 + glb_ptr->set_rate, glb_ptr->set_lowpass));
431 +static int snd_allo_piano_lowpass_get(struct snd_kcontrol *kcontrol,
432 + struct snd_ctl_elem_value *ucontrol)
434 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
435 + struct glb_pool *glb_ptr = card->drvdata;
437 + ucontrol->value.integer.value[0] = glb_ptr->set_lowpass;
441 +static int snd_allo_piano_lowpass_put(struct snd_kcontrol *kcontrol,
442 + struct snd_ctl_elem_value *ucontrol)
444 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
445 + struct snd_soc_pcm_runtime *rtd;
446 + struct glb_pool *glb_ptr = card->drvdata;
448 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
449 + return(snd_allo_piano_dsp_program(rtd,
450 + glb_ptr->set_mode, glb_ptr->set_rate,
451 + ucontrol->value.integer.value[0]));
454 +static int pcm512x_get_reg_sub(struct snd_kcontrol *kcontrol,
455 + struct snd_ctl_elem_value *ucontrol)
457 + struct soc_mixer_control *mc =
458 + (struct soc_mixer_control *)kcontrol->private_value;
459 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
460 + struct glb_pool *glb_ptr = card->drvdata;
461 + struct snd_soc_pcm_runtime *rtd;
462 + unsigned int left_val = 0;
463 + unsigned int right_val = 0;
465 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
466 + ret = snd_soc_component_read(rtd->codec_dais[1]->component,
467 + PCM512x_DIGITAL_VOLUME_3, &right_val);
471 + if (glb_ptr->dual_mode != 1) {
472 + ret = snd_soc_component_read(rtd->codec_dais[1]->component,
473 + PCM512x_DIGITAL_VOLUME_2, &left_val);
478 + left_val = right_val;
481 + ucontrol->value.integer.value[0] =
482 + (~(left_val >> mc->shift)) & mc->max;
483 + ucontrol->value.integer.value[1] =
484 + (~(right_val >> mc->shift)) & mc->max;
489 +static int pcm512x_set_reg_sub(struct snd_kcontrol *kcontrol,
490 + struct snd_ctl_elem_value *ucontrol)
492 + struct soc_mixer_control *mc =
493 + (struct soc_mixer_control *)kcontrol->private_value;
494 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
495 + struct glb_pool *glb_ptr = card->drvdata;
496 + struct snd_soc_pcm_runtime *rtd;
497 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
498 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
501 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
502 + if (glb_ptr->dual_mode != 1) {
503 + ret = snd_soc_component_write(rtd->codec_dais[1]->component,
504 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
509 + if (digital_gain_0db_limit) {
510 + ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
513 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
517 + ret = snd_soc_component_write(rtd->codec_dais[1]->component,
518 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
525 +static int pcm512x_get_reg_sub_switch(struct snd_kcontrol *kcontrol,
526 + struct snd_ctl_elem_value *ucontrol)
528 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
529 + struct snd_soc_pcm_runtime *rtd;
533 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
534 + ret = snd_soc_component_read(rtd->codec_dais[1]->component, PCM512x_MUTE, &val);
538 + ucontrol->value.integer.value[0] =
539 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
540 + ucontrol->value.integer.value[1] =
541 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
546 +static int pcm512x_set_reg_sub_switch(struct snd_kcontrol *kcontrol,
547 + struct snd_ctl_elem_value *ucontrol)
549 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
550 + struct snd_soc_pcm_runtime *rtd;
551 + struct glb_pool *glb_ptr = card->drvdata;
552 + unsigned int left_val = (ucontrol->value.integer.value[0]);
553 + unsigned int right_val = (ucontrol->value.integer.value[1]);
556 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
557 + if (glb_ptr->set_mode != 1) {
558 + ret = snd_soc_component_write(rtd->codec_dais[1]->component, PCM512x_MUTE,
559 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
567 +static int pcm512x_get_reg_master(struct snd_kcontrol *kcontrol,
568 + struct snd_ctl_elem_value *ucontrol)
570 + struct soc_mixer_control *mc =
571 + (struct soc_mixer_control *)kcontrol->private_value;
572 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
573 + struct glb_pool *glb_ptr = card->drvdata;
574 + struct snd_soc_pcm_runtime *rtd;
575 + unsigned int left_val = 0, right_val = 0;
578 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
580 + ret = snd_soc_component_read(rtd->codec_dais[0]->component,
581 + PCM512x_DIGITAL_VOLUME_2, &left_val);
585 + if (glb_ptr->dual_mode == 1) {
586 + ret = snd_soc_component_read(rtd->codec_dais[1]->component,
587 + PCM512x_DIGITAL_VOLUME_3, &right_val);
591 + ret = snd_soc_component_read(rtd->codec_dais[0]->component,
592 + PCM512x_DIGITAL_VOLUME_3, &right_val);
597 + ucontrol->value.integer.value[0] =
598 + (~(left_val >> mc->shift)) & mc->max;
599 + ucontrol->value.integer.value[1] =
600 + (~(right_val >> mc->shift)) & mc->max;
605 +static int pcm512x_set_reg_master(struct snd_kcontrol *kcontrol,
606 + struct snd_ctl_elem_value *ucontrol)
608 + struct soc_mixer_control *mc =
609 + (struct soc_mixer_control *)kcontrol->private_value;
610 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
611 + struct glb_pool *glb_ptr = card->drvdata;
612 + struct snd_soc_pcm_runtime *rtd;
613 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
614 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
617 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
619 + if (digital_gain_0db_limit) {
620 + ret = snd_soc_limit_volume(card, "Master Playback Volume",
623 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
627 + if (glb_ptr->dual_mode != 1) {
628 + ret = snd_soc_component_write(rtd->codec_dais[1]->component,
629 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
633 + ret = snd_soc_component_write(rtd->codec_dais[0]->component,
634 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
640 + ret = snd_soc_component_write(rtd->codec_dais[1]->component,
641 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
645 + ret = snd_soc_component_write(rtd->codec_dais[0]->component,
646 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
652 +static int pcm512x_get_reg_master_switch(struct snd_kcontrol *kcontrol,
653 + struct snd_ctl_elem_value *ucontrol)
655 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
656 + struct glb_pool *glb_ptr = card->drvdata;
657 + struct snd_soc_pcm_runtime *rtd;
661 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
663 + ret = snd_soc_component_read(rtd->codec_dais[0]->component, PCM512x_MUTE, &val);
667 + ucontrol->value.integer.value[0] =
668 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
670 + if (glb_ptr->dual_mode == 1) {
671 + ret = snd_soc_component_read(rtd->codec_dais[1]->component, PCM512x_MUTE, &val);
675 + ucontrol->value.integer.value[1] =
676 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
681 +static int pcm512x_set_reg_master_switch(struct snd_kcontrol *kcontrol,
682 + struct snd_ctl_elem_value *ucontrol)
684 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
685 + struct snd_soc_pcm_runtime *rtd;
686 + struct glb_pool *glb_ptr = card->drvdata;
687 + unsigned int left_val = (ucontrol->value.integer.value[0]);
688 + unsigned int right_val = (ucontrol->value.integer.value[1]);
691 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
692 + if (glb_ptr->dual_mode == 1) {
693 + ret = snd_soc_component_write(rtd->codec_dais[0]->component, PCM512x_MUTE,
694 + ~((left_val & 0x01)<<4));
697 + ret = snd_soc_component_write(rtd->codec_dais[1]->component, PCM512x_MUTE,
698 + ~((right_val & 0x01)));
702 + } else if (glb_ptr->set_mode == 1) {
703 + ret = snd_soc_component_write(rtd->codec_dais[0]->component, PCM512x_MUTE,
704 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
709 + ret = snd_soc_component_write(rtd->codec_dais[0]->component, PCM512x_MUTE,
710 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
714 + ret = snd_soc_component_write(rtd->codec_dais[1]->component, PCM512x_MUTE,
715 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
722 +static const DECLARE_TLV_DB_SCALE(digital_tlv_sub, -10350, 50, 1);
723 +static const DECLARE_TLV_DB_SCALE(digital_tlv_master, -10350, 50, 1);
725 +static const struct snd_kcontrol_new allo_piano_controls[] = {
726 + SOC_ENUM_EXT("Subwoofer mode Route",
727 + allo_piano_mode_enum,
728 + snd_allo_piano_mode_get,
729 + snd_allo_piano_mode_put),
731 + SOC_ENUM_EXT("Dual Mode Route",
732 + allo_piano_dual_mode_enum,
733 + snd_allo_piano_dual_mode_get,
734 + snd_allo_piano_dual_mode_put),
736 + SOC_ENUM_EXT("Lowpass Route", allo_piano_enum,
737 + snd_allo_piano_lowpass_get,
738 + snd_allo_piano_lowpass_put),
740 + SOC_DOUBLE_R_EXT_TLV("Subwoofer Playback Volume",
741 + PCM512x_DIGITAL_VOLUME_2,
742 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
743 + pcm512x_get_reg_sub,
744 + pcm512x_set_reg_sub,
747 + SOC_DOUBLE_EXT("Subwoofer Playback Switch",
749 + PCM512x_RQML_SHIFT,
750 + PCM512x_RQMR_SHIFT, 1, 1,
751 + pcm512x_get_reg_sub_switch,
752 + pcm512x_set_reg_sub_switch),
754 + SOC_DOUBLE_R_EXT_TLV("Master Playback Volume",
755 + PCM512x_DIGITAL_VOLUME_2,
756 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
757 + pcm512x_get_reg_master,
758 + pcm512x_set_reg_master,
759 + digital_tlv_master),
761 + SOC_DOUBLE_EXT("Master Playback Switch",
763 + PCM512x_RQML_SHIFT,
764 + PCM512x_RQMR_SHIFT, 1, 1,
765 + pcm512x_get_reg_master_switch,
766 + pcm512x_set_reg_master_switch),
769 +static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
771 + struct snd_soc_card *card = rtd->card;
772 + struct glb_pool *glb_ptr;
774 + glb_ptr = kzalloc(sizeof(struct glb_pool), GFP_KERNEL);
778 + card->drvdata = glb_ptr;
779 + glb_ptr->dual_mode = 2;
780 + glb_ptr->set_mode = 0;
782 + mutex_init(&glb_ptr->lock);
784 + if (digital_gain_0db_limit) {
787 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
790 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
796 +static void snd_allo_piano_gpio_mute(struct snd_soc_card *card)
799 + gpiod_set_value_cansleep(mute_gpio[0], P_MUTE);
802 + gpiod_set_value_cansleep(mute_gpio[1], P_MUTE);
805 +static void snd_allo_piano_gpio_unmute(struct snd_soc_card *card)
808 + gpiod_set_value_cansleep(mute_gpio[0], P_UNMUTE);
811 + gpiod_set_value_cansleep(mute_gpio[1], P_UNMUTE);
814 +static int snd_allo_piano_set_bias_level(struct snd_soc_card *card,
815 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
817 + struct snd_soc_pcm_runtime *rtd;
818 + struct snd_soc_dai *codec_dai;
820 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
821 + codec_dai = rtd->codec_dai;
823 + if (dapm->dev != codec_dai->dev)
827 + case SND_SOC_BIAS_PREPARE:
828 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
831 + snd_allo_piano_gpio_unmute(card);
834 + case SND_SOC_BIAS_STANDBY:
835 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
838 + snd_allo_piano_gpio_mute(card);
848 +static int snd_allo_piano_dac_startup(
849 + struct snd_pcm_substream *substream)
851 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
852 + struct snd_soc_card *card = rtd->card;
854 + snd_allo_piano_gpio_mute(card);
859 +static int snd_allo_piano_dac_hw_params(
860 + struct snd_pcm_substream *substream,
861 + struct snd_pcm_hw_params *params)
863 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
864 + unsigned int rate = params_rate(params);
865 + struct snd_soc_card *card = rtd->card;
866 + struct glb_pool *glb_ptr = card->drvdata;
867 + int ret = 0, val = 0, dac;
869 + for (dac = 0; (glb_mclk && dac < 2); dac++) {
870 + /* Configure the PLL clock reference for both the Codecs */
871 + ret = snd_soc_component_read(rtd->codec_dais[dac]->component,
872 + PCM512x_RATE_DET_4, &val);
874 + dev_err(rtd->codec_dais[dac]->component->dev,
875 + "Failed to read register PCM512x_RATE_DET_4\n");
880 + snd_soc_component_write(rtd->codec_dais[dac]->component,
884 + dev_info(rtd->codec_dais[dac]->component->dev,
885 + "Setting BCLK as input clock & Enable PLL\n");
887 + snd_soc_component_write(rtd->codec_dais[dac]->component,
891 + snd_soc_component_write(rtd->codec_dais[dac]->component,
895 + dev_info(rtd->codec_dais[dac]->component->dev,
896 + "Setting SCLK as input clock & disabled PLL\n");
900 + ret = snd_allo_piano_dsp_program(rtd, glb_ptr->set_mode, rate,
901 + glb_ptr->set_lowpass);
908 +static int snd_allo_piano_dac_prepare(
909 + struct snd_pcm_substream *substream)
911 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
912 + struct snd_soc_card *card = rtd->card;
914 + snd_allo_piano_gpio_unmute(card);
919 +/* machine stream operations */
920 +static struct snd_soc_ops snd_allo_piano_dac_ops = {
921 + .startup = snd_allo_piano_dac_startup,
922 + .hw_params = snd_allo_piano_dac_hw_params,
923 + .prepare = snd_allo_piano_dac_prepare,
926 +static struct snd_soc_dai_link_component allo_piano_2_1_codecs[] = {
928 + .dai_name = "pcm512x-hifi",
931 + .dai_name = "pcm512x-hifi",
935 +SND_SOC_DAILINK_DEFS(allo_piano_dai_plus,
936 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
937 + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "pcm512x-hifi"),
938 + COMP_CODEC(NULL, "pcm512x-hifi")),
939 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
941 +static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
943 + .name = "PianoDACPlus",
944 + .stream_name = "PianoDACPlus",
945 + .dai_fmt = SND_SOC_DAIFMT_I2S |
946 + SND_SOC_DAIFMT_NB_NF |
947 + SND_SOC_DAIFMT_CBS_CFS,
948 + .ops = &snd_allo_piano_dac_ops,
949 + .init = snd_allo_piano_dac_init,
950 + SND_SOC_DAILINK_REG(allo_piano_dai_plus),
954 +/* audio machine driver */
955 +static struct snd_soc_card snd_allo_piano_dac = {
956 + .name = "PianoDACPlus",
957 + .owner = THIS_MODULE,
958 + .dai_link = snd_allo_piano_dac_dai,
959 + .num_links = ARRAY_SIZE(snd_allo_piano_dac_dai),
960 + .controls = allo_piano_controls,
961 + .num_controls = ARRAY_SIZE(allo_piano_controls),
964 +static int snd_allo_piano_dac_probe(struct platform_device *pdev)
966 + struct snd_soc_card *card = &snd_allo_piano_dac;
967 + int ret = 0, i = 0;
969 + card->dev = &pdev->dev;
970 + platform_set_drvdata(pdev, &snd_allo_piano_dac);
972 + if (pdev->dev.of_node) {
973 + struct device_node *i2s_node;
974 + struct snd_soc_dai_link *dai;
976 + dai = &snd_allo_piano_dac_dai[0];
977 + i2s_node = of_parse_phandle(pdev->dev.of_node,
978 + "i2s-controller", 0);
980 + for (i = 0; i < card->num_links; i++) {
981 + dai->cpus->dai_name = NULL;
982 + dai->cpus->of_node = i2s_node;
983 + dai->platforms->name = NULL;
984 + dai->platforms->of_node = i2s_node;
987 + digital_gain_0db_limit =
988 + !of_property_read_bool(pdev->dev.of_node,
989 + "allo,24db_digital_gain");
991 + glb_mclk = of_property_read_bool(pdev->dev.of_node,
994 + allo_piano_2_1_codecs[0].of_node =
995 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
996 + if (!allo_piano_2_1_codecs[0].of_node) {
997 + dev_err(&pdev->dev,
998 + "Property 'audio-codec' missing or invalid\n");
1002 + allo_piano_2_1_codecs[1].of_node =
1003 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 1);
1004 + if (!allo_piano_2_1_codecs[1].of_node) {
1005 + dev_err(&pdev->dev,
1006 + "Property 'audio-codec' missing or invalid\n");
1010 + mute_gpio[0] = devm_gpiod_get_optional(&pdev->dev, "mute1",
1012 + if (IS_ERR(mute_gpio[0])) {
1013 + ret = PTR_ERR(mute_gpio[0]);
1014 + dev_err(&pdev->dev,
1015 + "failed to get mute1 gpio6: %d\n", ret);
1019 + mute_gpio[1] = devm_gpiod_get_optional(&pdev->dev, "mute2",
1021 + if (IS_ERR(mute_gpio[1])) {
1022 + ret = PTR_ERR(mute_gpio[1]);
1023 + dev_err(&pdev->dev,
1024 + "failed to get mute2 gpio25: %d\n", ret);
1028 + if (mute_gpio[0] && mute_gpio[1])
1029 + snd_allo_piano_dac.set_bias_level =
1030 + snd_allo_piano_set_bias_level;
1032 + ret = snd_soc_register_card(&snd_allo_piano_dac);
1034 + dev_err(&pdev->dev,
1035 + "snd_soc_register_card() failed: %d\n", ret);
1039 + if ((mute_gpio[0]) && (mute_gpio[1]))
1040 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1048 +static int snd_allo_piano_dac_remove(struct platform_device *pdev)
1050 + struct snd_soc_card *card = platform_get_drvdata(pdev);
1052 + kfree(&card->drvdata);
1053 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1054 + return snd_soc_unregister_card(&snd_allo_piano_dac);
1057 +static const struct of_device_id snd_allo_piano_dac_of_match[] = {
1058 + { .compatible = "allo,piano-dac-plus", },
1059 + { /* sentinel */ },
1062 +MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
1064 +static struct platform_driver snd_allo_piano_dac_driver = {
1066 + .name = "snd-allo-piano-dac-plus",
1067 + .owner = THIS_MODULE,
1068 + .of_match_table = snd_allo_piano_dac_of_match,
1070 + .probe = snd_allo_piano_dac_probe,
1071 + .remove = snd_allo_piano_dac_remove,
1074 +module_platform_driver(snd_allo_piano_dac_driver);
1076 +MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
1077 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC Plus");
1078 +MODULE_LICENSE("GPL v2");