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
7 The Piano DAC 2.1 has support for 4 channels with subwoofer.
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>
13 Add clock changes and mute gpios (#1938)
15 Also improve code style and adhere to ALSA coding conventions.
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>
21 PianoPlus: Dual Mono & Dual Stereo features added (#2069)
23 allo-piano-dac-plus: Master volume added + fixes
25 Master volume added, which controls both DACs volumes.
27 See: https://github.com/raspberrypi/linux/pull/2149
29 Also fix initial max volume, default mode value, and unmute.
31 Signed-off-by: allocom <sparky-dev@allo.com>
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
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
44 Say Y or M if you want to add support for Allo Piano DAC.
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
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
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
68 +++ b/sound/soc/bcm/allo-piano-dac-plus.c
71 + * ALSA ASoC Machine Driver for Allo Piano DAC Plus Subwoofer
73 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
75 + * based on code by Daniel Matuschek <info@crazy-audio.com>
76 + * based on code by Florian Meier <florian.meier@koalo.de>
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.
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.
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"
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
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;
122 +static bool digital_gain_0db_limit = true;
125 +static struct gpio_desc *mute_gpio[2];
127 +static const char * const allo_piano_mode_texts[] = {
134 +static const SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum,
135 + 0, 0, allo_piano_mode_texts);
137 +static const char * const allo_piano_dual_mode_texts[] = {
143 +static const SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum,
144 + 0, 0, allo_piano_dual_mode_texts);
146 +static const char * const allo_piano_dsp_low_pass_texts[] = {
164 +static const SOC_ENUM_SINGLE_DECL(allo_piano_enum,
165 + 0, 0, allo_piano_dsp_low_pass_texts);
167 +static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
168 + unsigned int mode, unsigned int rate, unsigned int lowpass)
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;
178 + else if (rate <= 68000)
180 + else if (rate <= 92000)
182 + else if (rate <= 136000)
184 + else if (rate <= 184000)
190 + glb_ptr->set_lowpass = lowpass = 0;
193 + glb_ptr->set_mode = mode = 0;
196 + glb_ptr->dual_mode = 0;
198 + /* same configuration loaded */
199 + if ((rate == glb_ptr->set_rate) && (lowpass == glb_ptr->set_lowpass)
200 + && (mode == glb_ptr->set_mode))
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;
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);
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;
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);
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);
239 + dev_info(codec->dev, "Dsp Firmware File Name: %s\n",
242 + ret = request_firmware(&fw, firmware_name, codec->dev);
244 + dev_err(codec->dev,
245 + "Error: Allo Piano Firmware %s missing. %d\n",
246 + firmware_name, ret);
250 + while (i < (fw->size - 1)) {
251 + dsp_code_read = (struct dsp_code *)&fw->data[i];
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);
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);
267 + dev_err(codec->dev,
268 + "Failed to write Register: %d\n", ret);
269 + release_firmware(fw);
274 + release_firmware(fw);
276 + glb_ptr->set_rate = rate;
277 + glb_ptr->set_mode = mode;
278 + glb_ptr->set_lowpass = lowpass;
285 +static int snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
286 + unsigned int mode, unsigned int rate, unsigned int lowpass)
288 + struct snd_soc_card *card = rtd->card;
289 + struct glb_pool *glb_ptr = card->drvdata;
292 + mutex_lock(&glb_ptr->lock);
294 + ret = __snd_allo_piano_dsp_program(rtd, mode, rate, lowpass);
296 + mutex_unlock(&glb_ptr->lock);
301 +static int snd_allo_piano_dual_mode_get(struct snd_kcontrol *kcontrol,
302 + struct snd_ctl_elem_value *ucontrol)
304 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
305 + struct glb_pool *glb_ptr = card->drvdata;
307 + ucontrol->value.integer.value[0] = glb_ptr->dual_mode;
312 +static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
313 + struct snd_ctl_elem_value *ucontrol)
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;
323 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
325 + if (ucontrol->value.integer.value[0] > 0) {
326 + glb_ptr->dual_mode = ucontrol->value.integer.value[0];
327 + glb_ptr->set_mode = 0;
329 + if (glb_ptr->set_mode <= 0) {
330 + glb_ptr->dual_mode = 1;
331 + glb_ptr->set_mode = 0;
333 + glb_ptr->dual_mode = 0;
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);
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;
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);
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;
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);
386 +static int snd_allo_piano_mode_get(struct snd_kcontrol *kcontrol,
387 + struct snd_ctl_elem_value *ucontrol)
389 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
390 + struct glb_pool *glb_ptr = card->drvdata;
392 + ucontrol->value.integer.value[0] = glb_ptr->set_mode;
396 +static int snd_allo_piano_mode_put(struct snd_kcontrol *kcontrol,
397 + struct snd_ctl_elem_value *ucontrol)
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;
407 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
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);
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;
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);
431 + return(snd_allo_piano_dsp_program(rtd,
432 + ucontrol->value.integer.value[0],
433 + glb_ptr->set_rate, glb_ptr->set_lowpass));
436 +static int snd_allo_piano_lowpass_get(struct snd_kcontrol *kcontrol,
437 + struct snd_ctl_elem_value *ucontrol)
439 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
440 + struct glb_pool *glb_ptr = card->drvdata;
442 + ucontrol->value.integer.value[0] = glb_ptr->set_lowpass;
446 +static int snd_allo_piano_lowpass_put(struct snd_kcontrol *kcontrol,
447 + struct snd_ctl_elem_value *ucontrol)
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;
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]));
459 +static int pcm512x_get_reg_sub(struct snd_kcontrol *kcontrol,
460 + struct snd_ctl_elem_value *ucontrol)
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;
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);
476 + if (glb_ptr->dual_mode != 1) {
477 + left_val = snd_soc_read(rtd->codec_dais[1]->codec,
478 + PCM512x_DIGITAL_VOLUME_2);
483 + left_val = right_val;
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;
494 +static int pcm512x_set_reg_sub(struct snd_kcontrol *kcontrol,
495 + struct snd_ctl_elem_value *ucontrol)
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);
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));
514 + if (digital_gain_0db_limit) {
515 + ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
518 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
522 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
523 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
530 +static int pcm512x_get_reg_sub_switch(struct snd_kcontrol *kcontrol,
531 + struct snd_ctl_elem_value *ucontrol)
533 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
534 + struct snd_soc_pcm_runtime *rtd;
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);
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;
550 +static int pcm512x_set_reg_sub_switch(struct snd_kcontrol *kcontrol,
551 + struct snd_ctl_elem_value *ucontrol)
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]);
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)));
571 +static int pcm512x_get_reg_master(struct snd_kcontrol *kcontrol,
572 + struct snd_ctl_elem_value *ucontrol)
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;
581 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
583 + left_val = snd_soc_read(rtd->codec_dais[0]->codec,
584 + PCM512x_DIGITAL_VOLUME_2);
588 + if (glb_ptr->dual_mode == 1) {
589 + right_val = snd_soc_read(rtd->codec_dais[1]->codec,
590 + PCM512x_DIGITAL_VOLUME_3);
594 + right_val = snd_soc_read(rtd->codec_dais[0]->codec,
595 + PCM512x_DIGITAL_VOLUME_3);
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;
608 +static int pcm512x_set_reg_master(struct snd_kcontrol *kcontrol,
609 + struct snd_ctl_elem_value *ucontrol)
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);
620 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
622 + if (digital_gain_0db_limit) {
623 + ret = snd_soc_limit_volume(card, "Master Playback Volume",
626 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
630 + if (glb_ptr->dual_mode != 1) {
631 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
632 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
636 + ret = snd_soc_write(rtd->codec_dais[0]->codec,
637 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
643 + ret = snd_soc_write(rtd->codec_dais[1]->codec,
644 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
648 + ret = snd_soc_write(rtd->codec_dais[0]->codec,
649 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
655 +static int pcm512x_get_reg_master_switch(struct snd_kcontrol *kcontrol,
656 + struct snd_ctl_elem_value *ucontrol)
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;
663 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
665 + val = snd_soc_read(rtd->codec_dais[0]->codec, PCM512x_MUTE);
669 + ucontrol->value.integer.value[0] =
670 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
672 + if (glb_ptr->dual_mode == 1) {
673 + val = snd_soc_read(rtd->codec_dais[1]->codec, PCM512x_MUTE);
677 + ucontrol->value.integer.value[1] =
678 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
683 +static int pcm512x_set_reg_master_switch(struct snd_kcontrol *kcontrol,
684 + struct snd_ctl_elem_value *ucontrol)
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]);
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));
699 + ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
700 + ~((right_val & 0x01)));
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)));
711 + ret = snd_soc_write(rtd->codec_dais[0]->codec, PCM512x_MUTE,
712 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
716 + ret = snd_soc_write(rtd->codec_dais[1]->codec, PCM512x_MUTE,
717 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
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);
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),
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),
738 + SOC_ENUM_EXT("Lowpass Route", allo_piano_enum,
739 + snd_allo_piano_lowpass_get,
740 + snd_allo_piano_lowpass_put),
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,
749 + SOC_DOUBLE_EXT("Subwoofer Playback Switch",
751 + PCM512x_RQML_SHIFT,
752 + PCM512x_RQMR_SHIFT, 1, 1,
753 + pcm512x_get_reg_sub_switch,
754 + pcm512x_set_reg_sub_switch),
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),
763 + SOC_DOUBLE_EXT("Master Playback Switch",
765 + PCM512x_RQML_SHIFT,
766 + PCM512x_RQMR_SHIFT, 1, 1,
767 + pcm512x_get_reg_master_switch,
768 + pcm512x_set_reg_master_switch),
771 +static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
773 + struct snd_soc_card *card = rtd->card;
774 + struct glb_pool *glb_ptr;
776 + glb_ptr = kmalloc(sizeof(struct glb_pool), GFP_KERNEL);
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;
785 + mutex_init(&glb_ptr->lock);
787 + if (digital_gain_0db_limit) {
790 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
793 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
799 +static void snd_allo_piano_gpio_mute(struct snd_soc_card *card)
802 + gpiod_set_value_cansleep(mute_gpio[0], P_MUTE);
805 + gpiod_set_value_cansleep(mute_gpio[1], P_MUTE);
808 +static void snd_allo_piano_gpio_unmute(struct snd_soc_card *card)
811 + gpiod_set_value_cansleep(mute_gpio[0], P_UNMUTE);
814 + gpiod_set_value_cansleep(mute_gpio[1], P_UNMUTE);
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)
820 + struct snd_soc_pcm_runtime *rtd;
821 + struct snd_soc_dai *codec_dai;
823 + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
824 + codec_dai = rtd->codec_dai;
826 + if (dapm->dev != codec_dai->dev)
830 + case SND_SOC_BIAS_PREPARE:
831 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
834 + snd_allo_piano_gpio_unmute(card);
837 + case SND_SOC_BIAS_STANDBY:
838 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
841 + snd_allo_piano_gpio_mute(card);
851 +static int snd_allo_piano_dac_startup(
852 + struct snd_pcm_substream *substream)
854 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
855 + struct snd_soc_card *card = rtd->card;
857 + snd_allo_piano_gpio_mute(card);
862 +static int snd_allo_piano_dac_hw_params(
863 + struct snd_pcm_substream *substream,
864 + struct snd_pcm_hw_params *params)
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;
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);
880 + dev_err(rtd->codec_dais[dac]->codec->dev,
881 + "Failed to read register PCM512x_RATE_DET_4\n");
886 + snd_soc_write(rtd->codec_dais[dac]->codec,
890 + dev_info(rtd->codec_dais[dac]->codec->dev,
891 + "Setting BCLK as input clock & Enable PLL\n");
893 + snd_soc_write(rtd->codec_dais[dac]->codec,
897 + snd_soc_write(rtd->codec_dais[dac]->codec,
901 + dev_info(rtd->codec_dais[dac]->codec->dev,
902 + "Setting SCLK as input clock & disabled PLL\n");
906 + ret = snd_allo_piano_dsp_program(rtd, glb_ptr->set_mode, rate,
907 + glb_ptr->set_lowpass);
911 + ret = snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
916 +static int snd_allo_piano_dac_prepare(
917 + struct snd_pcm_substream *substream)
919 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
920 + struct snd_soc_card *card = rtd->card;
922 + snd_allo_piano_gpio_unmute(card);
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,
934 +static struct snd_soc_dai_link_component allo_piano_2_1_codecs[] = {
936 + .dai_name = "pcm512x-hifi",
939 + .dai_name = "pcm512x-hifi",
943 +static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
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,
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,
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),
969 +static int snd_allo_piano_dac_probe(struct platform_device *pdev)
971 + struct snd_soc_card *card = &snd_allo_piano_dac;
972 + int ret = 0, i = 0;
974 + card->dev = &pdev->dev;
975 + platform_set_drvdata(pdev, &snd_allo_piano_dac);
977 + if (pdev->dev.of_node) {
978 + struct device_node *i2s_node;
979 + struct snd_soc_dai_link *dai;
981 + dai = &snd_allo_piano_dac_dai[0];
982 + i2s_node = of_parse_phandle(pdev->dev.of_node,
983 + "i2s-controller", 0);
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;
992 + digital_gain_0db_limit =
993 + !of_property_read_bool(pdev->dev.of_node,
994 + "allo,24db_digital_gain");
996 + glb_mclk = of_property_read_bool(pdev->dev.of_node,
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");
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");
1015 + mute_gpio[0] = devm_gpiod_get_optional(&pdev->dev, "mute1",
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);
1024 + mute_gpio[1] = devm_gpiod_get_optional(&pdev->dev, "mute2",
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);
1033 + if (mute_gpio[0] && mute_gpio[1])
1034 + snd_allo_piano_dac.set_bias_level =
1035 + snd_allo_piano_set_bias_level;
1037 + ret = snd_soc_register_card(&snd_allo_piano_dac);
1039 + dev_err(&pdev->dev,
1040 + "snd_soc_register_card() failed: %d\n", ret);
1044 + if ((mute_gpio[0]) && (mute_gpio[1]))
1045 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1053 +static int snd_allo_piano_dac_remove(struct platform_device *pdev)
1055 + struct snd_soc_card *card = platform_get_drvdata(pdev);
1057 + kfree(&card->drvdata);
1058 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
1059 + return snd_soc_unregister_card(&snd_allo_piano_dac);
1062 +static const struct of_device_id snd_allo_piano_dac_of_match[] = {
1063 + { .compatible = "allo,piano-dac-plus", },
1064 + { /* sentinel */ },
1067 +MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
1069 +static struct platform_driver snd_allo_piano_dac_driver = {
1071 + .name = "snd-allo-piano-dac-plus",
1072 + .owner = THIS_MODULE,
1073 + .of_match_table = snd_allo_piano_dac_of_match,
1075 + .probe = snd_allo_piano_dac_probe,
1076 + .remove = snd_allo_piano_dac_remove,
1079 +module_platform_driver(snd_allo_piano_dac_driver);
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");