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