1 From 9fec5358c76947685887921f3f6c73fbf0dea882 Mon Sep 17 00:00:00 2001
2 From: Florian Meier <florian.meier@koalo.de>
3 Date: Mon, 25 Jan 2016 15:48:59 +0000
4 Subject: [PATCH] ASoC: Add support for all the downstream rpi sound card
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
10 ASoC: Add support for Rpi-DAC
12 ASoC: Add prompt for ICS43432 codec
14 Without a prompt string, a config setting can't be included in a
15 defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards
18 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
20 Add IQaudIO Sound Card support for Raspberry Pi
22 Set a limit of 0dB on Digital Volume Control
24 The main volume control in the PCM512x DAC has a range up to
25 +24dB. This is dangerously loud and can potentially cause massive
26 clipping in the output stages. Therefore this sets a sensible
27 limit of 0dB for this control.
29 Allow up to 24dB digital gain to be applied when using IQAudIO DAC+
31 24db_digital_gain DT param can be used to specify that PCM512x
32 codec "Digital" volume control should not be limited to 0dB gain,
33 and if specified will allow the full 24dB gain.
35 Modify IQAudIO DAC+ ASoC driver to set card/dai config from dt
37 Add the ability to set the card name, dai name and dai stream name, from
40 Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
42 IQaudIO: auto-mute for AMP+ and DigiAMP+
44 IQAudIO amplifier mute via GPIO22. Add dt params for "one-shot" unmute
47 Revision 2, auto mute implementing HiassofT suggestion to mute/unmute
48 using set_bias_level, rather than startup/shutdown....
49 "By default DAPM waits 5 seconds (pmdown_time) before shutting down
50 playback streams so a close/stop immediately followed by open/start
51 doesn't trigger an amp mute+unmute."
53 Tested on both AMP+ (via DAC+) and DigiAMP+, with both options...
55 dtoverlay=iqaudio-dacplus,unmute_amp
56 "one-shot" unmute when kernel module loads.
58 dtoverlay=iqaudio-dacplus,auto_mute_amp
59 Unmute amp when ALSA device opened by a client. Mute, with 5 second delay
60 when ALSA device closed. (Re-opening the device within the 5 second close
61 window, will cancel mute.)
63 Revision 4, using gpiod.
65 Revision 5, clean-up formatting before adding mute code.
66 - Convert tab plus 4 space formatting to 2x tab
67 - Remove '// NOT USED' commented code
69 Revision 6, don't attempt to "one-shot" unmute amp, unless card is
70 successfully registered.
72 Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
74 ASoC: iqaudio-dac: fix S24_LE format
76 Remove set_bclk_ratio call so 24-bit data is transmitted in
79 Signed-off-by: Matthias Reichl <hias@horus.com>
81 ASoC: iqaudio-dac: use modern dai_link style
83 Signed-off-by: Matthias Reichl <hias@horus.com>
85 Added support for HiFiBerry DAC+
87 The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses
88 a different codec chip (PCM5122), therefore a new driver is necessary.
90 Add support for the HiFiBerry DAC+ Pro.
92 The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators.
94 An addition bug fix is included for the PCM512x codec where by the physical size of the sample frame is used in the calculation of the LRCK divisor as it was found to be wrong when using 24-bit depth sample contained in a little endian 4-byte sample frame.
96 Limit PCM512x "Digital" gain to 0dB by default with HiFiBerry DAC+
98 24db_digital_gain DT param can be used to specify that PCM512x
99 codec "Digital" volume control should not be limited to 0dB gain,
100 and if specified will allow the full 24dB gain.
102 Add dt param to force HiFiBerry DAC+ Pro into slave mode
104 "dtoverlay=hifiberry-dacplus,slave"
106 Add 'slave' param to use HiFiBerry DAC+ Pro in slave mode,
107 with Pi as master for bit and frame clock.
109 Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
111 Fixed a bug when using 352.8kHz sample rate
113 Signed-off-by: Daniel Matuschek <daniel@hifiberry.com>
115 ASoC: pcm512x: revert downstream changes
117 This partially reverts commit 185ea05465aac8bf02a0d2b2f4289d42c72870b7
118 which was added by https://github.com/raspberrypi/linux/pull/1152
120 The downstream pcm512x changes caused a regression, it broke normal
121 use of the 24bit format with the codec, eg when using simple-audio-card.
123 The actual bug with 24bit playback is the incorrect usage
124 of physical_width in various drivers in the downstream tree
125 which causes 24bit data to be transmitted with 32 clock
126 cycles. So it's not the pcm512x that needs fixing, it's the
129 Signed-off-by: Matthias Reichl <hias@horus.com>
131 ASoC: hifiberry_dacplus: fix S24_LE format
133 Remove set_bclk_ratio call so 24-bit data is transmitted in
136 Signed-off-by: Matthias Reichl <hias@horus.com>
138 ASoC: hifiberry_dacplus: transmit S24_LE with 64 BCLK cycles
140 Signed-off-by: Matthias Reichl <hias@horus.com>
142 hifiberry_dacplus: switch to snd_soc_dai_set_bclk_ratio
144 Signed-off-by: Matthias Reichl <hias@horus.com>
146 ASoC: hifiberry_dacplus: use modern dai_link style
148 Signed-off-by: Hui Wang <hui.wang@canonical.com>
150 Add driver for rpi-proto
152 Forward port of 3.10.x driver from https://github.com/koalo
153 We are using a custom board and would like to use rpi 3.18.x
154 kernel. Patch works fine for our embedded system.
156 URL to the audio chip:
157 http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/
159 Playback tested with devicetree enabled.
161 Signed-off-by: Waldemar Brodkorb <wbrodkorb@conet.de>
163 ASoC: rpi-proto: use modern dai_link style
165 Signed-off-by: Hui Wang <hui.wang@canonical.com>
167 Add Support for JustBoom Audio boards
169 justboom-dac: Adjust for ALSA API change
171 As of 4.4, snd_soc_limit_volume now takes a struct snd_soc_card *
172 rather than a struct snd_soc_codec *.
174 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
176 ASoC: justboom-dac: fix S24_LE format
178 Remove set_bclk_ratio call so 24-bit data is transmitted in
181 Also remove hw_params as it's no longer needed.
183 Signed-off-by: Matthias Reichl <hias@horus.com>
185 ASoC: justboom-dac: use modern dai_link style
187 Signed-off-by: Matthias Reichl <hias@horus.com>
189 New AudioInjector.net Pi soundcard with low jitter audio in and out.
191 Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile.
192 Adds the dts overlay and updates the Makefile and README.
193 Updates the relevant defconfig files to enable building for the Raspberry Pi.
194 Thanks to Phil Elwell (pelwell) for the review, simple-card concepts and discussion. Thanks to Clive Messer for overlay naming suggestions.
196 Added support for headphones, microphone and bclk_ratio settings.
198 This patch adds headphone and microphone capability to the Audio Injector sound card. The patch also sets the bit clock ratio for use in the bcm2835-i2s driver. The bcm2835-i2s can't handle an 8 kHz sample rate when the bit clock is at 12 MHz because its register is only 10 bits wide which can't represent the ch2 offset of 1508. For that reason, the rate constraint is added.
200 ASoC: audioinjector-pi-soundcard: use modern dai_link style
202 Signed-off-by: Hui Wang <hui.wang@canonical.com>
204 New driver for RRA DigiDAC1 soundcard using WM8741 + WM8804
206 ASoC: digidac1-soundcard: use modern dai_link style
208 Signed-off-by: Hui Wang <hui.wang@canonical.com>
210 Add support for Dion Audio LOCO DAC-AMP HAT
212 Using dedicated machine driver and pcm5102a codec driver.
214 Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
216 ASoC: dionaudio_loco: use modern dai_link style
218 Signed-off-by: Hui Wang <hui.wang@canonical.com>
220 Allo Piano DAC boards: Initial 2 channel (stereo) support (#1645)
222 Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards,
223 using allo-piano-dac-pcm512x-audio overlay and allo-piano-dac ALSA ASoC
226 NB. The initial support is 2 channel (stereo) ONLY!
227 (The Piano DAC 2.1 will only support 2 channel (stereo) left/right output,
228 pending an update to the upstream pcm512x codec driver, which will have
229 to be submitted via upstream. With the initial downstream support,
230 provided by this patch, the Piano DAC 2.1 subwoofer outputs will
233 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
234 Signed-off-by: Clive Messer <clive.messer@digitaldreamtime.co.uk>
235 Tested-by: Clive Messer <clive.messer@digitaldreamtime.co.uk>
237 ASoC: allo-piano-dac: fix S24_LE format
239 Remove set_bclk_ratio call so 24-bit data is transmitted in
242 Also remove hw_params and ops as they are no longer needed.
244 Signed-off-by: Matthias Reichl <hias@horus.com>
246 ASoC: allo-piano-dac: use modern dai_link style
248 Signed-off-by: Hui Wang <hui.wang@canonical.com>
250 Add support for Allo Piano DAC 2.1 plus add-on board for Raspberry Pi.
252 The Piano DAC 2.1 has support for 4 channels with subwoofer.
254 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
255 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
256 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
258 Add clock changes and mute gpios (#1938)
260 Also improve code style and adhere to ALSA coding conventions.
262 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
263 Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
264 Reviewed-by: Raashid Muhammed <raashidmuhammed@zilogic.com>
266 PianoPlus: Dual Mono & Dual Stereo features added (#2069)
268 allo-piano-dac-plus: Master volume added + fixes
270 Master volume added, which controls both DACs volumes.
272 See: https://github.com/raspberrypi/linux/pull/2149
274 Also fix initial max volume, default mode value, and unmute.
276 Signed-off-by: allocom <sparky-dev@allo.com>
278 ASoC: allo-piano-dac-plus: fix S24_LE format
280 Remove set_bclk_ratio call so 24-bit data is transmitted in
283 Signed-off-by: Matthias Reichl <hias@horus.com>
285 sound: bcm: Fix memset dereference warning
287 This warning appears with GCC 6.4.0 from toolchains.bootlin.com:
289 ../sound/soc/bcm/allo-piano-dac-plus.c: In function ‘snd_allo_piano_dac_init’:
290 ../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]
291 memset(glb_ptr, 0x00, sizeof(glb_ptr));
294 Suggested-by: Phil Elwell <phil@raspberrypi.org>
295 Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
297 ASoC: allo-piano-dac-plus: use modern dai_link style
299 Signed-off-by: Hui Wang <hui.wang@canonical.com>
301 Add support for Allo Boss DAC add-on board for Raspberry Pi. (#1924)
303 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
304 Reviewed-by: Deepak <deepak@zilogic.com>
305 Reviewed-by: BabuSubashChandar <babusubashchandar@zilogic.com>
307 Add support for new clock rate and mute gpios.
309 Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
310 Reviewed-by: Deepak <deepak@zilogic.com>
311 Reviewed-by: BabuSubashChandar <babusubashchandar@zilogic.com>
313 ASoC: allo-boss-dac: fix S24_LE format
315 Remove set_bclk_ratio call so 24-bit data is transmitted in
318 Signed-off-by: Matthias Reichl <hias@horus.com>
320 ASoC: allo-boss-dac: transmit S24_LE with 64 BCLK cycles
322 Signed-off-by: Matthias Reichl <hias@horus.com>
324 allo-boss-dac: switch to snd_soc_dai_set_bclk_ratio
326 Signed-off-by: Matthias Reichl <hias@horus.com>
328 ASoC: allo-boss-dac: use modern dai_link style
330 Signed-off-by: Hui Wang <hui.wang@canonical.com>
332 Support for Blokas Labs pisound board
334 Pisound dynamic overlay (#1760)
336 Restructuring pisound-overlay.dts, so it can be loaded and unloaded dynamically using dtoverlay.
338 Print a logline when the kernel module is removed.
340 pisound improvements:
342 * Added a writable sysfs object to enable scripts / user space software
343 to blink MIDI activity LEDs for variable duration.
344 * Improved hw_param constraints setting.
345 * Added compatibility with S16_LE sample format.
346 * Exposed some simple placeholder volume controls, so the card appears
347 in volumealsa widget.
349 Add missing SND_PISOUND selects dependency to SND_RAWMIDI
351 Without it the Pisound module fails to compile.
352 See https://github.com/raspberrypi/linux/issues/2366
354 Updates for Pisound module code:
356 * Merged 'Fix a warning in DEBUG builds' (1c8b82b).
357 * Updating some strings and copyright information.
358 * Fix for handling high load of MIDI input and output.
359 * Use dual rate oversampling ratio for 96kHz instead of single
362 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
364 Fixing memset call in pisound.c
366 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
368 Fix for Pisound's MIDI Input getting blocked for a while in rare cases.
370 There was a possible race condition which could lead to Input's FIFO queue
371 to be underflown, causing high amount of processing in the worker thread for
374 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
376 Fix for Pisound kernel module in Real Time kernel configuration.
378 When handler of data_available interrupt is fired, queue_work ends up
379 getting called and it can block on a spin lock which is not allowed in
380 interrupt context. The fix was to run the handler from a thread context
383 Pisound: Remove spinlock usage around spi_sync
385 ASoC: pisound: use modern dai_link style
387 Signed-off-by: Hui Wang <hui.wang@canonical.com>
389 ASoC: pisound: fix the parameter for spi_device_match
391 Signed-off-by: Hui Wang <hui.wang@canonical.com>
393 ASoC: Add driver for Cirrus Logic Audio Card
395 Note: due to problems with deferred probing of regulators
396 the following softdep should be added to a modprobe.d file
398 softdep arizona-spi pre: arizona-ldo1
400 Signed-off-by: Matthias Reichl <hias@horus.com>
402 ASoC: rpi-cirrus: use modern dai_link style
404 Signed-off-by: Matthias Reichl <hias@horus.com>
406 sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT
408 Signed-off-by: Miquel Blauw <info@dionaudio.nl>
410 ASoC: dionaudio_loco-v2: fix S24_LE format
412 Remove set_bclk_ratio call so 24-bit data is transmitted in
415 Also remove hw_params and ops as they are no longer needed.
417 Signed-off-by: Matthias Reichl <hias@horus.com>
419 ASoC: dionaudio_loco-v2: use modern dai_link style
421 Signed-off-by: Hui Wang <hui.wang@canonical.com>
423 Add support for Fe-Pi audio sound card. (#1867)
425 Fe-Pi Audio Sound Card is based on NXP SGTL5000 codec.
426 Mechanical specification of the board is the same the Raspberry Pi Zero.
427 3.5mm jacks for Headphone/Mic, Line In, and Line Out.
429 Signed-off-by: Henry Kupis <fe-pi@cox.net>
431 ASoC: fe-pi-audio: use modern dai_link style
433 Signed-off-by: Hui Wang <hui.wang@canonical.com>
435 Add support for the AudioInjector.net Octo sound card
437 AudioInjector Octo: sample rates, regulators, reset
439 This patch adds new sample rates to the Audioinjector Octo sound card. The
440 new supported rates are (in kHz) :
441 96, 48, 32, 24, 16, 8, 88.2, 44.1, 29.4, 22.05, 14.7
443 Reference the bcm270x DT regulators in the overlay.
445 This patch adds a reset GPIO for the AudioInjector.net octo sound card.
447 Audioinjector octo : Make the playback and capture symmetric
449 This patch ensures that the sample rate and channel count of the audioinjector
450 octo sound card are symmetric.
452 audioinjector-octo: Add continuous clock feature
454 By user request, add a switch to prevent the clocks being stopped when
455 the stream is paused, stopped or shutdown. Provide access to the switch
456 by adding a 'non-stop-clocks' parameter to the audioinjector-addons
459 See: https://github.com/raspberrypi/linux/issues/2409
461 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
463 sound: Fixes for audioinjector-octo under 4.19
465 1. Move the DT alias declaration to the I2C shim in the cases
466 where the shim is enabled. This works around a problem caused by a
467 4.19 commit [1] that generates DT/OF uevents for I2C drivers.
469 2. Fix the diagnostics in an error path of the soundcard driver to
470 correctly identify the reason for the failure to load.
472 3. Move the declaration of the clock node in the overlay outside
473 the I2C node to avoid warnings.
475 4. Sort the overlay nodes so that dependencies are only to earlier
476 fragments, in an attempt to get runtime dtoverlay application to
477 work (it still doesn't...)
479 See: https://github.com/Audio-Injector/Octo/issues/14
480 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
482 [1] af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
484 ASoC: audioinjector-octo-soundcard: use modern dai_link style
486 Signed-off-by: Hui Wang <hui.wang@canonical.com>
488 Driver support for Google voiceHAT soundcard.
490 ASoC: googlevoicehat-codec: Use correct device when grabbing GPIO
492 The fixup for the VoiceHAT in 4.18 incorrectly tried to find the
493 sdmode GPIO pin under the card device, not the codec device.
494 This failed, and therefore caused the device probe to fail.
496 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
498 ASoC: googlevoicehat-codec: Reformat for kernel coding standards
500 Fix all whitespace, indentation, and bracing errors.
502 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
504 ASoC: googlevoicehat-codec: Make driver function structure const
506 Make voicehat_component_driver a const structure.
508 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
510 ASoC: googlevoicehat-codec: Only convert from ms to jiffies once
512 Minor optimisation and allows to become checkpatch clean.
513 A msec value is read out of DT or from a define, and convert once to
514 jiffies, rather than every time that it is used.
516 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
518 Driver and overlay for Allo Katana DAC
520 Allo Katana DAC: Updated default values
522 Signed-off-by: Jaikumar <jaikumar@cem-solutions.com>
524 Added mute stream func
526 Signed-off-by: Jaikumar <jaikumar@cem-solutions.net>
528 codecs: Correct Katana minimum volume
530 Update Katana minimum volume to get the exact 0.5 dB value in each step.
532 Signed-off-by: Sudeep Kumar <sudeepkumar@cem-solutions.net>
534 ASoC: Add generic RPI driver for simple soundcards.
536 The RPI simple sound card driver provides a generic ALSA SOC card driver
537 supporting a variety of Pi HAT soundcards. The intention is to avoid
538 the duplication of code for cards that can't be fully supported by
539 the soc simple/graph cards but are otherwise almost identical.
541 This initial commit adds support for the ADAU1977 ADC, Google VoiceHat,
542 HifiBerry AMP, HifiBerry DAC and RPI DAC.
544 Signed-off-by: Tim Gover <tim.gover@raspberrypi.org>
546 ASoC: Use correct card name in rpi-simple driver
548 Use the specific card name from drvdata instead of the snd_rpi_simple
550 rpi-simple-soundcard: Use nicer driver name "RPi-simple"
552 Rename the driver from "RPI simple soundcard" to "RPi-simple" so that
553 the driver name won't be mangled allowing to be used unaltered as the
556 ASoC: rpi-simple-soundcard: use modern dai_link style
558 Signed-off-by: Hui Wang <hui.wang@canonical.com>
560 ASoC: Add Kconfig and Makefile for sound/soc/bcm
562 Signed-off-by: popcornmix <popcornmix@gmail.com>
564 ASoC: Create a generic Pi Hat WM8804 driver
566 Reduce the amount of duplicated code by creating a generic driver for
567 Pi Hat digi cards using the WM8804 codec.
570 Allo DigiOne, Hifiberry Digi/Pro, JustBoom Digi and IQAudIO Digi
571 dedicate soundcard drivers with a generic driver.
573 There are no significant changes to the runtime behavior of the drivers
574 and end users should not have to change any configuration settings
578 * Check the return value of snd_soc_component_update_bits
579 * Added some pr_debug tracing
580 * Various checkpatch tidyups
581 * Updated allodigi-one to use use 128FS at > 96 Khz. This appears to
582 be an omission in the original driver code so followed the Hifiberry
585 ASoC: rpi-wm8804-soundcard: use modern dai_link style
587 Signed-off-by: Matthias Reichl <hias@horus.com>
589 rpi-wm8804-soundcard: drop PWRDN register writes
591 Since kernel 4.0 the PWRDN register bits are under DAPM
592 control from the wm8804 driver.
594 Drop code that modifies that register to avoid interfering
597 Signed-off-by: Matthias Reichl <hias@horus.com>
599 rpi-wm8804-soundcard: configure wm8804 clocks only on rate change
601 This should avoid clicks when stopping and immediately afterwards
602 starting a stream with the same samplerate as before.
604 Signed-off-by: Matthias Reichl <hias@horus.com>
606 rpi-wm8804-soundcard: Fixed MCLKDIV for Allo Digione
608 The Allo Digione board wants a fixed MCLKDIV of 256.
610 See: https://github.com/raspberrypi/linux/issues/3296
612 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
614 ASoC: Add support for AudioSense-Pi add-on soundcard
616 AudioSense-Pi is a RPi HAT based on a TI's TLV320AIC32x4 stereo codec
618 This hardware provides multiple audio I/O capabilities to the RPi.
619 The codec connects to the RPi's SoC through the I2S Bus.
621 The following devices can be connected through a 3.5mm jack
622 1. Line-In: Plain old audio in from mobile phones, PCs, etc.,
623 2. Mic-In: Connect a microphone
624 3. Line-Out: Connect the output to a speaker
625 4. Headphones: Connect a Headphone w or w/o microphones
628 It supports the following combinations
629 1. Two stereo Line-Inputs and a microphone
630 2. One stereo Line-Input and two microphones
631 3. Two stereo Line-Inputs, a microphone and
632 one mono line-input (with h/w hack)
633 4. One stereo Line-Input, two microphones and
634 one mono line-input (with h/w hack)
637 Audio output can be routed to the headphones or
638 speakers (with additional hardware)
640 Signed-off-by: b-ak <anur.bhargav@gmail.com>
642 ASoC: audiosense-pi: use modern dai_link style
644 Signed-off-by: Hui Wang <hui.wang@canonical.com>
646 Added driver for the HiFiBerry DAC+ ADC (#2694)
648 Signed-off-by: Daniel Matuschek <daniel@hifiberry.com>
650 hifiberry_dacplusadc: switch to snd_soc_dai_set_bclk_ratio
652 Signed-off-by: Matthias Reichl <hias@horus.com>
654 ASoC: hifiberry_dacplusadc: fix DAI link setup
656 The driver only defines a single DAI link and the code that tries
657 to setup the second (non-existent) DAI link looks wrong - using dmic
658 as a CPU/platform driver doesn't make any sense.
660 The DT overlay doesn't define a dmic property, so the code was never
661 executed (otherwise it would have resulted in a memory corruption).
663 So drop the offending code to prevent issues if a dmic property
664 should be added to the DT overlay.
666 Signed-off-by: Matthias Reichl <hias@horus.com>
668 ASoC: hifiberry_dacplusadc: use modern dai_link style
670 Signed-off-by: Matthias Reichl <hias@horus.com>
672 Audiophonics I-Sabre 9038Q2M DAC driver
674 Signed-off-by: Audiophonics <contact@audiophonics.fr>
676 ASoC: i-sabre-q2m: use modern dai_link style
678 Signed-off-by: Hui Wang <hui.wang@canonical.com>
680 Added IQaudIO Pi-Codec board support (#2969)
682 Add support for the IQaudIO Pi-Codec board.
684 Signed-off-by: Gordon <gordon@iqaudio.com>
686 Fixed 48k timing issue
688 ASoC: iqaudio-codec: use modern dai_link style
690 Signed-off-by: Hui Wang <hui.wang@canonical.com>
692 adds the Hifiberry DAC+ADC PRO version
694 This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC
695 Signed-off-by: Joerg Schambacher joerg@i2audio.com
697 Add Hifiberry DAC+DSP soundcard driver (#3224)
699 Adds the driver for the Hifiberry DAC+DSP. It supports capture and
700 playback depending on the DSP firmware.
702 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
704 Allow simultaneous use of JustBoom DAC and Digi
706 Signed-off-by: Johannes Krude <johannes@krude.de>
708 Pisound: MIDI communication fixes for scaled down CPU.
710 * Increased maximum SPI communication speed to avoid running too slow
711 when the CPU is scaled down and losing MIDI data.
713 * Keep track of buffer usage in millibytes for higher precision.
715 Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
717 sound: Add the HiFiBerry DAC+HD version
719 This adds the driver for the DAC+HD version supporting HiFiBerry's
720 PCM179x based DACs. It also adds PLL control for clock generation.
722 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
724 Fix master mode settings of HiFiBerry DAC+ADC PRO card (#3424)
726 This patch fixes the board DAI setting when in master-mode.
727 Wrong setting could have caused random pop noise.
729 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
731 adds LED OFF feature to HiFiBerry DAC+ADC PRO sound card
733 This adds a DT overlay parameter 'leds_off' which allows
734 to switch off the onboard activity LEDs at all times
735 which has been requested by some users.
737 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
739 adds LED OFF feature to HiFiBerry DAC+ADC sound card
741 This adds a DT overlay parameter 'leds_off' which allows
742 to switch off the onboard activity LEDs at all times
743 which has been requested by some users.
745 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
747 adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound cards
749 This adds a DT overlay parameter 'leds_off' which allows
750 to switch off the onboard activity LEDs at all times
751 which has been requested by some users.
753 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
755 pisound: Added reading Pisound board hardware revision and exposing it (#3425)
757 pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file:
759 /sys/kernel/pisound/hw_version
761 Signed-off-by: Giedrius <giedrius@blokas.io>
763 Added driver for HiFiBerry Amp amplifier add-on board
765 The driver contains a low-level hardware driver for the TAS5713 and the
766 drivers for the Raspberry Pi I2S subsystem.
768 TAS5713: return error if initialisation fails
770 Existing TAS5713 driver logs errors during initialisation, but does not return
771 an error code. Therefore even if initialisation fails, the driver will still be
772 loaded, but won't work. This patch fixes this. I2C communication error will now
773 reported correctly by a non-zero return code.
775 HiFiBerry Amp: fix device-tree problems
777 Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
779 According to 5713 pdf doc CLOCK_CTRL is a readonly status register, and it behaves so. Remove useless setting
781 sound: pcm512x-codec: Adding 352.8kHz samplerate support
783 sound/soc: only first codec is master in multicodec setup
785 When using multiple codecs, at most one codec should generate the master
786 clock. All codecs except the first are therefore configured for slave
789 Signed-off-by: Johannes Krude <johannes@krude.de>
791 ASoC: Fix snd_soc_get_pcm_runtime usage
793 Commit [1] changed the snd_soc_get_pcm_runtime to take a dai_link
794 pointer instead of a string. Patch up the downstream drivers to use
797 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
799 [1] 4468189ff307 ("ASoC: soc-core: find rtd via dai_link pointer at snd_soc_get_pcm_runtime()")
801 Add support for the AudioInjector.net Isolated sound card
803 This patch adds support for the Audio Injector Isolated sound card.
805 Signed-off-by: Matt Flax <flatmax@flatmax.org>
807 Add support for merus-amp soundcard and ma120x0p codec
809 Add 96KHz rate support to MA120X0P codec and make enable and mute gpio
812 Signed-off-by: AMuszkat <ariel.muszkat@gmail.com>
814 Fixes a problem with clock settings of HiFiBerry DAC+ADC PRO (#3545)
816 This patch fixes a problem of the re-calculation of
817 i2s-clock and -parameter settings when only the ADC is activated.
819 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
821 configs: Enable the AD193x codecs
823 See: https://github.com/raspberrypi/linux/issues/2850
825 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
827 Switch to snd_soc_dai_set_bclk_ratio
828 Replaces obsolete function snd_soc_dai_set_tdm_slot
830 Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
832 Enhances the DAC+ driver to control the optional headphone amplifier
834 Probes on the I2C bus for TPA6130A2, if successful, it sets DT-parameter
835 'status' from 'disabled' to 'okay' using change_sets to enable
836 the headphone control.
838 Signed-off-by: Joerg Schambacher joerg@i2audio.com
840 Update Allo Piano Dac Driver
842 Add unique names to the individual dac coded drivers
843 Remove some of the codec controls that are not used.
845 Signed-off-by: Paul Hermann <paul@picoreplayer.org>
847 Fixes an onboard clock detection problem of the PRO versions
849 Increasing the sleep time after clock selection to 3-4ms
850 allows the correct detection of all combinations of DAC+ Pro
851 and DAC+ADC Pro sound cards and the various PI revisions.
853 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
855 ASoC:ma120x0p: Increase maximum sample rate to 192KHz
857 Change the maximum sample rate for the amplifier to
858 192KHz as given in the Infineon specification.
860 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
862 ASoC: ma120x0p: Remove unnecessary const specifier
866 sound/soc/codecs/ma120x0p.c:891:14: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
867 static const SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl,
869 ./include/sound/soc.h:362:2: note: expanded from macro 'SOC_VALUE_ENUM_SINGLE_DECL'
870 SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
872 ./include/sound/soc.h:359:2: note: expanded from macro 'SOC_VALUE_ENUM_DOUBLE_DECL'
873 const struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
877 SOC_VALUE_ENUM_DOUBLE_DECL already has a const specifier. Remove the duplicate
878 const to clean up the warning.
880 Fixes: 42444979e710 ("Add support for all the downstream rpi sound card drivers")
881 Signed-off-by: Nathan Chancellor <nathan@kernel.org>
883 ASoC: bcm: allo-piano-dac-plus: Remove unnecessary const specifiers
887 sound/soc/bcm/allo-piano-dac-plus.c:66:14: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
888 static const SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum,
890 ./include/sound/soc.h:355:2: note: expanded from macro 'SOC_ENUM_SINGLE_DECL'
891 SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
893 ./include/sound/soc.h:352:2: note: expanded from macro 'SOC_ENUM_DOUBLE_DECL'
894 const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
896 sound/soc/bcm/allo-piano-dac-plus.c:75:14: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
897 static const SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum,
899 ./include/sound/soc.h:355:2: note: expanded from macro 'SOC_ENUM_SINGLE_DECL'
900 SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
902 ./include/sound/soc.h:352:2: note: expanded from macro 'SOC_ENUM_DOUBLE_DECL'
903 const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
905 sound/soc/bcm/allo-piano-dac-plus.c:96:14: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
906 static const SOC_ENUM_SINGLE_DECL(allo_piano_enum,
908 ./include/sound/soc.h:355:2: note: expanded from macro 'SOC_ENUM_SINGLE_DECL'
909 SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
911 ./include/sound/soc.h:352:2: note: expanded from macro 'SOC_ENUM_DOUBLE_DECL'
912 const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
914 3 warnings generated.
916 SOC_VALUE_ENUM_DOUBLE_DECL already has a const specifier. Remove the duplicate
917 const specifiers to clean up the warnings.
919 Fixes: 42444979e710 ("Add support for all the downstream rpi sound card drivers")
920 Signed-off-by: Nathan Chancellor <nathan@kernel.org>
922 rpi-simple-soundcard: Add Dion Audio KIWI streamer
924 Signed-off-by: Miquel Blauw <miquelblauw@hotmail.com>
926 rpi-simple-soundcard: adds definitions for the HiFiBerry AMP3 card
928 Uses Infineon MA120x0 amplifier and supports full sample rate of 192ksps.
930 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
932 sound: soc: bcm: Added Sound card driver for Dacberry400 Audio card for Raspberry Pi 400
934 Added Sound card driver for DACberry400 Audio card.
936 Signed-off-by: Ashish Vara <ashishhvara@gmail.com>
938 ASoC:ma120x0p: Corrects the volume level display
940 Fixes the wrongly changed 'limiter volume' display back to -50dB minimum
941 and sets the correct minimum volume level to -144dB to be aligned with
942 the controls and display in alsamixer etc.
944 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
946 ASoC: bcm: Fix Rpi-PROTO and audioinjector.net Pi
948 As of kernel 5.19 the WM8731 driver has separate I2C and SPI support
949 modules. Change the Kconfig definitions for the audioinjector.net Pi
950 and Rpi-PROTO soundcards to select SND_SOC_WM8731_I2C.
952 See: https://github.com/raspberrypi/linux/issues/5364
954 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
956 ASoC: adau1977: Add correct compatible strings
958 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
960 ASoC: bcm2835-i2s: Use phys addresses for DAI DMA
962 Contrary to what struct snd_dmaengine_dai_dma_data suggests, the
963 configuration of addresses of DMA slave interfaces should be done in
964 CPU physical addresses.
966 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
968 rpi sound cards: Fix Codec Zero rate switching
970 The Raspberry Pi Codec Zero (and IQaudIO Codec) don't notify the DA7213
971 codec when it needs to change PLL frequencies. As a result, audio can
972 be played at the wrong rate - play a 48kHz sound immediately after a
973 44.1kHz sound to see the effect, but in some configurations the codec
974 can lock into the wrong state and always get some rates wrong.
976 Add the necessary notification to fix the issue.
978 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
980 ASoC: dwc: Support set_bclk_ratio
982 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
984 ASoC: dwc: Add DMACR handling
986 Add control of the DMACR register, which is required for paced DMA
989 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
991 ASOC: dwc: Improve DMA shutdown
993 Disabling the I2S interface with outstanding transfers prevents the
994 DMAC from shutting down, so keep it partially active after a stop.
996 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
998 ASOC: dwc: Fix 16-bit audio handling
1000 IMO the Synopsys datasheet could be clearer in this area, but it seems
1001 that the DMA data ports (DMATX and DMARX) expect left and right samples
1002 in alternate writes; if a stereo pair is pushed in a single 32-bit
1003 write, the upper half is ignored, leading to double speed audio with a
1004 confused stereo image. Make sure the necessary changes happen by
1005 updating the DMA configuration data in the hw_params method.
1007 The set_bclk_ratio change was made at a time when it looked like it
1008 could be causing an error, but I think the division of responsibilities
1009 is clearer this way (and the kernel log clearer without the info-level
1012 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1014 ASoC: bcm: Remove dependency on BCM2835 I2S
1016 These soundcard drivers don't rely on a specific I2S interface, so
1017 remove the dependency declarations.
1019 See: https://github.com/raspberrypi/linux-2712/issues/111
1021 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1023 ASoC: bcm: audioinjector_octo: Add soundcard "owner"
1025 See: https://github.com/raspberrypi/linux/issues/5697
1027 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1029 Pisound: Don't export the button GPIO via sysfs GPIO class.
1031 Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
1033 Pisound: Read out the SPI speed to use from the Device Tree.
1035 Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
1037 ASoC: DACplus - fix 16bit sample support in clock consumer mode
1039 The former code did not adjust the physical sample width when
1040 in clock consumer mode and has taken the fixed 32 bit default.
1041 This has caused the audio to be played at half its frequency due to
1042 the fixed bclk_ratio of 64.
1044 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
1046 ASoC: adds support for AMP4 Pro to the DAC Plus driver
1048 The AMP4 Pro is a I2S master mode capable amplifier with
1049 clean onboard clock generators.
1050 We can share the card driver between TAS575x amplifiers
1051 and the PCM512x DACs as they are SW compatible.
1052 From a HW perspective though we need to limit the sample
1053 rates to the standard audio rates to avoid running the
1054 onboard clocks through the PLL. Using the PLL would require
1055 even a different HW.
1056 DAI/stream name are also set accordingly to allow the user
1057 a convenient identification of the soundcard
1059 Needs the pcm512x driver with TAS575x support (already in
1062 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
1064 ASoC: DACplusADCPro - fix 16bit sample support in clock consumer mode
1066 The former code did not adjust the physical sample width when in
1067 clock consumer mode and has taken the fixed 32 bit default. This
1068 has caused the audio to be played at half its frequency due to
1069 the fixed bclk_ratio of 64.
1071 Problem appears only on PI5 as on the former PIs the I2S module
1072 did simply run at fixed 64x rate.
1074 Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
1076 Impliment driver support for Interlude Audio Digital Hat
1078 Implementing driver support for
1079 Interlude audio's WM8805 based digital hat
1080 by leveraging existing drivers
1082 ASOc: Add HiFiBerry DAC8X to the simple card driver
1084 Defines the settings for the 8 channel version of the standard
1085 DAC by overwriting the number of channels in the DAI defs.
1086 It can run in 8ch mode only on PI5 using the 4 lane data output
1087 of the designware I2S0 module.
1089 Signed-off-by: j-schambacher <joerg@hifiberry.com>
1091 ASoC: bcm: Use the correct sample width value
1093 ALSA's concept of the physical width of a sample is how much memory it
1094 occupies, including any padding. This not the same as the count of bits
1095 of actual sample content. In particular, S24_LE has a width of 24 bits
1096 but a physical width of 32 bits because there is a byte of padding with
1099 When calculating bclk_ratio, etc., it is width that matters, not
1100 physical width. Correct the error that has been replicated across the
1101 drivers for many Raspberry Pi-compatible soundcards.
1103 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1105 ASoC: dwc: Correct channel count reporting
1107 The DWC I2S driver treats the channel count register values as if they
1108 encode a power of two (2, 4, 8, 16), but they actually encode a
1109 multiple of 2 (2, 4, 6, 8).
1111 Also improve the error message when asked for an unsupported number
1114 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1116 ASoC: Fix 16bit sample support for Hifiberry DACplusADC
1118 Same issue as #5919.
1119 'width' needs to be set independent of clocking mode.
1121 Signed-off-by: j-schambacher <joerg@hifiberry.com>
1123 allo-boss-dac mute output when changing parameters
1125 Since I noticed that sometimes changing sample rates causes some digital
1126 quirks and noises, I've changed the function to mute the output before
1127 performing the changes and then unmute it when an error occurs or the
1130 Signed-off-by: Alessandro Marcon <marconalessandro04@gmail.com>
1132 ASoC: bcm: Use power-of-2 bclk_ratios
1134 The soundcard drivers originally used snd_pcm_format_physical_width,
1135 but a later commit changed that to snd_pcm_format_width because the
1136 in-memory sample storage width should not be a factor in determining
1137 the bclk_ratio. However, the physical width rounds the sample bits up
1138 to the nearest power of 2, which makes it easier to find integer clock
1141 Restore the old behaviour, but with an implementation that makes it
1142 clear what is going on.
1144 See: https://github.com/raspberrypi/linux/issues/6104
1146 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1148 ASoC: bcm: Add "owner" info for more soundcards
1150 See: https://github.com/raspberrypi/linux/issues/5697
1152 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1154 ASoC: da7213: Add a set_bclk_ratio method
1156 Following [1], it becomes harder for the CPU DAI to know the correct
1157 BCLK ratio. We can either bake the same knowledge into the sound card
1158 driver, or implement and use set_bclk_ratio on the codec. This commit
1161 [1] commit c89e652e84f6 ("ASoC: da7213: Add support for mono, set
1162 frame width to 32 when possible")
1164 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1166 iqaudio-codec: Use the codec's new set_bclk_ratio
1168 To ensure that the CPU DAI and codec agree over the BCLK ratio, impose
1169 a fixed value of 64 on both of them.
1171 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1173 ASoC: add driver for new HiFiBerry ADC only board(s)
1175 Adds the driver for the soon to be released first ADC only board.
1176 It includes the same ADC controls as used by the DAC+ADC Pro driver.
1178 Signed-off-by: j-schambacher <joerg@hifiberry.com>
1180 ASoC: add HiFiBerry ADC8x 8-channel ADC to simple-card-driver
1182 Definitions for the 8 channel ADC card. The card uses only
1183 HW-controlled devices which allows the uses of the 'dummy-dai'.
1184 It will run only on a PI5 as it requires the designware I2S0 module.
1186 The necessary output lanes I2S0_DI[0..3] are claimed from within the
1189 Signed-off-by: j-schambacher <joerg@hifiberry.com>
1191 .../devicetree/bindings/vendor-prefixes.txt | 463 ++++++
1192 .../devicetree/bindings/vendor-prefixes.yaml | 2 +
1193 drivers/clk/Kconfig | 6 +
1194 drivers/clk/Makefile | 2 +
1195 drivers/clk/clk-hifiberry-dachd.c | 331 ++++
1196 drivers/clk/clk-hifiberry-dacpro.c | 180 +++
1197 sound/soc/bcm/Kconfig | 284 ++++
1198 sound/soc/bcm/Makefile | 73 +-
1199 sound/soc/bcm/allo-boss-dac.c | 470 ++++++
1200 sound/soc/bcm/allo-boss2-dac.c | 1130 ++++++++++++++
1201 sound/soc/bcm/allo-katana-codec.c | 386 +++++
1202 sound/soc/bcm/allo-piano-dac-plus.c | 1063 +++++++++++++
1203 sound/soc/bcm/allo-piano-dac.c | 122 ++
1204 .../bcm/audioinjector-isolated-soundcard.c | 184 +++
1205 sound/soc/bcm/audioinjector-octo-soundcard.c | 347 +++++
1206 sound/soc/bcm/audioinjector-pi-soundcard.c | 190 +++
1207 sound/soc/bcm/audiosense-pi.c | 247 +++
1208 sound/soc/bcm/bcm2835-i2s.c | 26 +-
1209 sound/soc/bcm/chipdip-dac.c | 275 ++++
1210 sound/soc/bcm/dacberry400.c | 258 +++
1211 sound/soc/bcm/digidac1-soundcard.c | 421 +++++
1212 sound/soc/bcm/dionaudio_loco-v2.c | 118 ++
1213 sound/soc/bcm/dionaudio_loco.c | 121 ++
1214 sound/soc/bcm/fe-pi-audio.c | 154 ++
1215 sound/soc/bcm/googlevoicehat-codec.c | 212 +++
1216 sound/soc/bcm/hifiberry_adc.c | 174 +++
1217 sound/soc/bcm/hifiberry_adc_controls.h | 128 ++
1218 sound/soc/bcm/hifiberry_dacplus.c | 563 +++++++
1219 sound/soc/bcm/hifiberry_dacplusadc.c | 399 +++++
1220 sound/soc/bcm/hifiberry_dacplusadcpro.c | 498 ++++++
1221 sound/soc/bcm/hifiberry_dacplusdsp.c | 89 ++
1222 sound/soc/bcm/hifiberry_dacplushd.c | 233 +++
1223 sound/soc/bcm/i-sabre-q2m.c | 159 ++
1224 sound/soc/bcm/iqaudio-codec.c | 283 ++++
1225 sound/soc/bcm/iqaudio-dac.c | 223 +++
1226 sound/soc/bcm/justboom-both.c | 266 ++++
1227 sound/soc/bcm/justboom-dac.c | 147 ++
1228 sound/soc/bcm/pifi-40.c | 281 ++++
1229 sound/soc/bcm/pisound.c | 1254 +++++++++++++++
1230 sound/soc/bcm/rpi-cirrus.c | 1027 ++++++++++++
1231 sound/soc/bcm/rpi-proto.c | 147 ++
1232 sound/soc/bcm/rpi-simple-soundcard.c | 560 +++++++
1233 sound/soc/bcm/rpi-wm8804-soundcard.c | 549 +++++++
1234 sound/soc/codecs/Kconfig | 26 +-
1235 sound/soc/codecs/Makefile | 9 +
1236 sound/soc/codecs/adau1977-i2c.c | 10 +
1237 sound/soc/codecs/cs42xx8-i2c.c | 9 +-
1238 sound/soc/codecs/cs42xx8.c | 10 +
1239 sound/soc/codecs/da7213.c | 21 +
1240 sound/soc/codecs/da7213.h | 1 +
1241 sound/soc/codecs/i-sabre-codec.c | 389 +++++
1242 sound/soc/codecs/i-sabre-codec.h | 42 +
1243 sound/soc/codecs/ma120x0p.c | 1380 +++++++++++++++++
1244 sound/soc/codecs/pcm1794a.c | 68 +
1245 sound/soc/codecs/pcm512x.c | 2 +-
1246 sound/soc/codecs/tas5713.c | 360 +++++
1247 sound/soc/codecs/tas5713.h | 210 +++
1248 sound/soc/dwc/dwc-i2s.c | 149 +-
1249 sound/soc/dwc/local.h | 12 +
1250 sound/soc/soc-core.c | 10 +-
1251 sound/usb/card.c | 8 +-
1252 sound/usb/quirks.c | 2 +
1253 62 files changed, 16723 insertions(+), 40 deletions(-)
1254 create mode 100644 Documentation/devicetree/bindings/vendor-prefixes.txt
1255 create mode 100644 drivers/clk/clk-hifiberry-dachd.c
1256 create mode 100644 drivers/clk/clk-hifiberry-dacpro.c
1257 create mode 100644 sound/soc/bcm/allo-boss-dac.c
1258 create mode 100644 sound/soc/bcm/allo-boss2-dac.c
1259 create mode 100644 sound/soc/bcm/allo-katana-codec.c
1260 create mode 100644 sound/soc/bcm/allo-piano-dac-plus.c
1261 create mode 100644 sound/soc/bcm/allo-piano-dac.c
1262 create mode 100644 sound/soc/bcm/audioinjector-isolated-soundcard.c
1263 create mode 100644 sound/soc/bcm/audioinjector-octo-soundcard.c
1264 create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c
1265 create mode 100644 sound/soc/bcm/audiosense-pi.c
1266 create mode 100644 sound/soc/bcm/chipdip-dac.c
1267 create mode 100644 sound/soc/bcm/dacberry400.c
1268 create mode 100644 sound/soc/bcm/digidac1-soundcard.c
1269 create mode 100644 sound/soc/bcm/dionaudio_loco-v2.c
1270 create mode 100644 sound/soc/bcm/dionaudio_loco.c
1271 create mode 100644 sound/soc/bcm/fe-pi-audio.c
1272 create mode 100644 sound/soc/bcm/googlevoicehat-codec.c
1273 create mode 100644 sound/soc/bcm/hifiberry_adc.c
1274 create mode 100644 sound/soc/bcm/hifiberry_adc_controls.h
1275 create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
1276 create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c
1277 create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c
1278 create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c
1279 create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
1280 create mode 100644 sound/soc/bcm/i-sabre-q2m.c
1281 create mode 100644 sound/soc/bcm/iqaudio-codec.c
1282 create mode 100644 sound/soc/bcm/iqaudio-dac.c
1283 create mode 100644 sound/soc/bcm/justboom-both.c
1284 create mode 100644 sound/soc/bcm/justboom-dac.c
1285 create mode 100644 sound/soc/bcm/pifi-40.c
1286 create mode 100644 sound/soc/bcm/pisound.c
1287 create mode 100644 sound/soc/bcm/rpi-cirrus.c
1288 create mode 100644 sound/soc/bcm/rpi-proto.c
1289 create mode 100644 sound/soc/bcm/rpi-simple-soundcard.c
1290 create mode 100644 sound/soc/bcm/rpi-wm8804-soundcard.c
1291 create mode 100644 sound/soc/codecs/i-sabre-codec.c
1292 create mode 100644 sound/soc/codecs/i-sabre-codec.h
1293 create mode 100644 sound/soc/codecs/ma120x0p.c
1294 create mode 100644 sound/soc/codecs/pcm1794a.c
1295 create mode 100644 sound/soc/codecs/tas5713.c
1296 create mode 100644 sound/soc/codecs/tas5713.h
1299 +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
1301 +Device tree binding vendor prefix registry. Keep list in alphabetical order.
1303 +This isn't an exhaustive list, but you should add new prefixes to it before
1304 +using them to avoid name-space collisions.
1306 +abilis Abilis Systems
1307 +abracon Abracon Corporation
1308 +actions Actions Semiconductor Co., Ltd.
1309 +active-semi Active-Semi International Inc
1310 +ad Avionic Design GmbH
1311 +adafruit Adafruit Industries, LLC
1312 +adapteva Adapteva, Inc.
1313 +adaptrum Adaptrum, Inc.
1314 +adh AD Holdings Plc.
1315 +adi Analog Devices, Inc.
1316 +advantech Advantech Corporation
1317 +aeroflexgaisler Aeroflex Gaisler AB
1320 +allwinner Allwinner Technology Co., Ltd.
1321 +alphascale AlphaScale Integrated Circuits Systems, Inc.
1323 +amarula Amarula Solutions
1324 +amazon Amazon.com, Inc.
1325 +amcc Applied Micro Circuits Corporation (APM, formally AMCC)
1326 +amd Advanced Micro Devices (AMD), Inc.
1327 +amediatech Shenzhen Amediatech Technology Co., Ltd
1328 +amlogic Amlogic, Inc.
1329 +ampire Ampire Co., Ltd.
1331 +amstaos AMS-Taos Inc.
1332 +analogix Analogix Semiconductor, Inc.
1333 +andestech Andes Technology Corporation
1334 +apm Applied Micro Circuits Corporation (APM)
1335 +aptina Aptina Imaging
1336 +arasan Arasan Chip Systems
1337 +archermind ArcherMind Technology (Nanjing) Co., Ltd.
1339 +aries Aries Embedded GmbH
1341 +armadeus ARMadeus Systems SARL
1342 +arrow Arrow Electronics
1343 +artesyn Artesyn Embedded Technologies Inc.
1344 +asahi-kasei Asahi Kasei Corp.
1345 +aspeed ASPEED Technology Inc.
1346 +asus AsusTek Computer Inc.
1347 +atlas Atlas Scientific LLC
1348 +atmel Atmel Corporation
1349 +auo AU Optronics Corporation
1350 +auvidea Auvidea GmbH
1351 +avago Avago Technologies
1352 +avia avia semiconductor
1353 +avic Shanghai AVIC Optoelectronics Co., Ltd.
1355 +axentia Axentia Technologies AB
1356 +axis Axis Communications AB
1357 +bananapi BIPAI KEJI LIMITED
1358 +bhf Beckhoff Automation GmbH & Co. KG
1359 +bitmain Bitmain Technologies
1360 +blokaslabs Vilniaus Blokas UAB
1361 +boe BOE Technology Group Co., Ltd.
1362 +bosch Bosch Sensortec GmbH
1363 +boundary Boundary Devices Inc.
1364 +brcm Broadcom Corporation
1365 +buffalo Buffalo, Inc.
1366 +bticino Bticino International
1368 +capella Capella Microsystems, Inc
1369 +cascoda Cascoda, Ltd.
1370 +catalyst Catalyst Semiconductor, Inc.
1371 +cavium Cavium, Inc.
1372 +cdns Cadence Design Systems Inc.
1373 +cdtech CDTech(H.K.) Electronics Limited
1375 +chipidea Chipidea, Inc
1377 +chipspark ChipSPARK
1378 +chrp Common Hardware Reference Platform
1379 +chunghwa Chunghwa Picture Tubes Ltd.
1380 +ciaa Computadora Industrial Abierta Argentina
1381 +cirrus Cirrus Logic, Inc.
1382 +cloudengines Cloud Engines, Inc.
1383 +cnm Chips&Media, Inc.
1384 +cnxt Conexant Systems, Inc.
1385 +compulab CompuLab Ltd.
1386 +cortina Cortina Systems, Inc.
1387 +cosmic Cosmic Circuits
1388 +crane Crane Connectivity Solutions
1389 +creative Creative Technology Ltd
1390 +crystalfontz Crystalfontz America, Inc.
1391 +csky Hangzhou C-SKY Microsystems Co., Ltd
1392 +cubietech Cubietech, Ltd.
1393 +cypress Cypress Semiconductor Corporation
1394 +cznic CZ.NIC, z.s.p.o.
1395 +dallas Maxim Integrated Products (formerly Dallas Semiconductor)
1396 +dataimage DataImage, Inc.
1397 +davicom DAVICOM Semiconductor, Inc.
1398 +delta Delta Electronics, Inc.
1399 +denx Denx Software Engineering
1400 +devantech Devantech, Ltd.
1401 +dh DH electronics GmbH
1402 +digi Digi International Inc.
1403 +digilent Diglent, Inc.
1404 +dioo Dioo Microcircuit Co., Ltd
1405 +dlc DLC Display Co., Ltd.
1406 +dlg Dialog Semiconductor
1407 +dlink D-Link Corporation
1409 +domintech Domintech Co., Ltd.
1410 +dongwoon Dongwoon Anatech
1411 +dptechnics DPTechnics
1412 +dragino Dragino Technology Co., Limited
1413 +ea Embedded Artists AB
1414 +ebs-systart EBS-SYSTART GmbH
1416 +eckelmann Eckelmann AG
1417 +edt Emerging Display Technologies
1418 +eeti eGalax_eMPIA Technology Inc
1419 +elan Elan Microelectronic Corp.
1421 +embest Shenzhen Embest Technology Co., Ltd.
1423 +emmicro EM Microelectronic
1424 +emtrion emtrion GmbH
1425 +endless Endless Mobile, Inc.
1426 +energymicro Silicon Laboratories (formerly Energy Micro AS)
1427 +engicam Engicam S.r.l.
1429 +epfl Ecole Polytechnique Fédérale de Lausanne
1430 +epson Seiko Epson Corp.
1431 +est ESTeem Wireless Modems
1432 +ettus NI Ettus Research
1433 +eukrea Eukréa Electromatique
1434 +everest Everest Semiconductor Co. Ltd.
1435 +everspin Everspin Technologies, Inc.
1436 +exar Exar Corporation
1438 +ezchip EZchip Semiconductor
1440 +fairphone Fairphone B.V.
1441 +faraday Faraday Technology Corporation
1443 +fcs Fairchild Semiconductor
1444 +feiyang Shenzhen Fly Young Technology Co.,LTD.
1446 +focaltech FocalTech Systems Co.,Ltd
1447 +friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
1448 +fsl Freescale Semiconductor
1449 +fujitsu Fujitsu Ltd.
1450 +gateworks Gateworks Corporation
1451 +gcw Game Consoles Worldwide
1452 +ge General Electric Company
1453 +geekbuying GeekBuying
1454 +gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
1455 +GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
1456 +geniatech Geniatech, Inc.
1457 +giantec Giantec Semiconductor, Inc.
1458 +giantplus Giantplus Technology Co., Ltd.
1459 +globalscale Globalscale Technologies, Inc.
1460 +globaltop GlobalTop Technology, Inc.
1461 +gmt Global Mixed-mode Technology, Inc.
1462 +goodix Shenzhen Huiding Technology Co., Ltd.
1463 +google Google, Inc.
1465 +grmn Garmin Limited
1466 +gumstix Gumstix, Inc.
1467 +gw Gateworks Corporation
1468 +hannstar HannStar Display Corporation
1469 +haoyu Haoyu Microelectronic Co. Ltd.
1470 +hardkernel Hardkernel Co., Ltd
1472 +himax Himax Technologies, Inc.
1473 +hisilicon Hisilicon Limited.
1475 +hitex Hitex Development Tools
1476 +holt Holt Integrated Circuits, Inc.
1477 +honeywell Honeywell
1479 +holtek Holtek Semiconductor, Inc.
1480 +hwacom HwaCom Systems Inc.
1482 +ibm International Business Machines (IBM)
1483 +icplus IC Plus Corp.
1484 +idt Integrated Device Technologies, Inc.
1485 +ifi Ingenieurburo Fur Ic-Technologie (I/F/I)
1486 +ilitek ILI Technology Corporation (ILITEK)
1487 +img Imagination Technologies Ltd.
1488 +infineon Infineon Technologies
1489 +inforce Inforce Computing
1490 +ingenic Ingenic Semiconductor
1491 +innolux Innolux Corporation
1492 +inside-secure INSIDE Secure
1493 +intel Intel Corporation
1494 +intercontrol Inter Control Group
1495 +invensense InvenSense Inc.
1496 +inversepath Inverse Path
1497 +iom Iomega Corporation
1498 +isee ISEE 2007 S.L.
1500 +issi Integrated Silicon Solutions Inc.
1501 +itead ITEAD Intelligent Systems Co.Ltd
1502 +iwave iWave Systems Technologies Pvt. Ltd.
1503 +jdi Japan Display Inc.
1504 +jedec JEDEC Solid State Technology Association
1505 +jianda Jiandangjing Technology Co., Ltd.
1506 +karo Ka-Ro electronics GmbH
1507 +keithkoep Keith & Koep GmbH
1508 +keymile Keymile GmbH
1510 +kiebackpeter Kieback & Peter GmbH
1511 +kinetic Kinetic Technologies
1512 +kingdisplay King & Display Technology Co., Ltd.
1513 +kingnovel Kingnovel Technology Co., Ltd.
1514 +koe Kaohsiung Opto-Electronics Inc.
1515 +kosagi Sutajio Ko-Usagi PTE Ltd.
1516 +kyo Kyocera Corporation
1519 +lantiq Lantiq Semiconductor
1520 +lattice Lattice Semiconductor
1521 +lego LEGO Systems A/S
1522 +lemaker Shenzhen LeMaker Technology Co., Ltd.
1523 +lenovo Lenovo Group Ltd.
1525 +libretech Shenzhen Libre Technology Co., Ltd
1527 +linaro Linaro Limited
1528 +linksys Belkin International, Inc. (Linksys)
1529 +linux Linux-specific binding
1530 +linx Linx Technologies
1531 +lltc Linear Technology Corporation
1532 +logicpd Logic PD, Inc.
1533 +lsi LSI Corp. (LSI Logic)
1534 +lwn Liebherr-Werk Nenzing GmbH
1535 +macnica Macnica Americas
1536 +marvell Marvell Technology Group Ltd.
1537 +maxim Maxim Integrated Products
1540 +meas Measurement Specialties
1541 +mediatek MediaTek Inc.
1542 +megachips MegaChips
1543 +mele Shenzhen MeLE Digital Technology Ltd.
1544 +melexis Melexis N.V.
1546 +mellanox Mellanox Technologies
1548 +merrii Merrii Technology Co., Ltd.
1550 +microchip Microchip Technology Inc.
1551 +microcrystal Micro Crystal AG
1552 +micron Micron Technology Inc.
1553 +mikroe MikroElektronika d.o.o.
1554 +minix MINIX Technology Ltd.
1555 +miramems MiraMEMS Sensing Technology Co., Ltd.
1556 +mitsubishi Mitsubishi Electric Corporation
1557 +mosaixtech Mosaix Technologies, Inc.
1558 +motorola Motorola, Inc.
1561 +mqmaker mqmaker Inc.
1562 +mscc Microsemi Corporation
1563 +msi Micro-Star International Co. Ltd.
1564 +mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
1565 +multi-inno Multi-Inno Technology Co.,Ltd
1566 +mundoreader Mundo Reader S.L.
1567 +murata Murata Manufacturing Co., Ltd.
1568 +mxicy Macronix International Co., Ltd.
1569 +myir MYIR Tech Limited
1570 +national National Semiconductor
1571 +nec NEC LCD Technologies, Ltd.
1572 +neonode Neonode Inc.
1574 +netlogic Broadcom Corporation (formerly NetLogic Microsystems)
1575 +netron-dy Netron DY
1576 +netxeon Shenzhen Netxeon Technology CO., LTD
1578 +nextthing Next Thing Co.
1579 +newhaven Newhaven Display International
1580 +ni National Instruments
1582 +nlt NLT Technologies, Ltd.
1584 +nordic Nordic Semiconductor
1585 +novtech NovTech, Inc.
1586 +nutsboard NutsBoard
1587 +nuvoton Nuvoton Technology Corporation
1588 +nvd New Vision Display
1590 +nxp NXP Semiconductors
1591 +okaya Okaya Electric America, Inc.
1592 +oki Oki Electric Industry Co., Ltd.
1594 +olpc One Laptop Per Child
1595 +onion Onion Corporation
1596 +onnn ON Semiconductor Corp.
1597 +ontat On Tat Industrial Company
1598 +opalkelly Opal Kelly Incorporated
1599 +opencores OpenCores.org
1600 +openrisc OpenRISC.io
1602 +oranth Shenzhen Oranth Technology Co., Ltd.
1603 +ORCL Oracle Corporation
1604 +orisetech Orise Technology
1605 +ortustech Ortus Technology Co., Ltd.
1606 +ovti OmniVision Technologies
1607 +oxsemi Oxford Semiconductor, Ltd.
1608 +panasonic Panasonic Corporation
1609 +parade Parade Technologies Inc.
1610 +pda Precision Design Associates, Inc.
1611 +pericom Pericom Technology Inc.
1612 +pervasive Pervasive Displays, Inc.
1613 +phicomm PHICOMM Co., Ltd.
1614 +phytec PHYTEC Messtechnik GmbH
1615 +picochip Picochip Ltd
1617 +pixcir PIXCIR MICROELECTRONICS Co., Ltd
1618 +plantower Plantower Co., Ltd
1619 +plathome Plat'Home Co., Ltd.
1621 +plx Broadcom Corporation (formerly PLX Technology)
1622 +pni PNI Sensor Corporation
1623 +portwell Portwell Inc.
1624 +poslab Poslab Technology Co., Ltd.
1625 +powervr PowerVR (deprecated, use img)
1626 +probox2 PROBOX2 (by W2COMP Co., Ltd.)
1627 +pulsedlight PulsedLight, Inc
1628 +qca Qualcomm Atheros, Inc.
1629 +qcom Qualcomm Technologies, Inc
1630 +qemu QEMU, a generic and open source machine emulator and virtualizer
1632 +qiaodian QiaoDian XianShi Corporation
1633 +qnap QNAP Systems, Inc.
1635 +raidsonic RaidSonic Technology GmbH
1636 +ralink Mediatek/Ralink Technology Corp.
1637 +ramtron Ramtron International
1638 +raspberrypi Raspberry Pi Foundation
1639 +raydium Raydium Semiconductor Corp.
1640 +rda Unisoc Communications, Inc.
1641 +realtek Realtek Semiconductor Corp.
1642 +renesas Renesas Electronics Corporation
1643 +richtek Richtek Technology Corporation
1644 +ricoh Ricoh Co. Ltd.
1645 +rikomagic Rikomagic Tech Corp. Ltd
1646 +riscv RISC-V Foundation
1647 +rockchip Fuzhou Rockchip Electronics Co., Ltd
1648 +rohm ROHM Semiconductor Co., Ltd
1649 +roofull Shenzhen Roofull Technology Co, Ltd
1650 +samsung Samsung Semiconductor
1651 +samtec Samtec/Softing company
1652 +sancloud Sancloud Ltd
1653 +sandisk Sandisk Corporation
1654 +sbs Smart Battery System
1655 +schindler Schindler
1656 +seagate Seagate Technology PLC
1657 +semtech Semtech Corporation
1658 +sensirion Sensirion AG
1659 +sff Small Form Factor Committee
1660 +sgd Solomon Goldentek Display Corporation
1662 +sharp Sharp Corporation
1663 +shimafuji Shimafuji Electric, Inc.
1664 +si-en Si-En Technology Ltd.
1665 +sifive SiFive, Inc.
1666 +sigma Sigma Designs, Inc.
1667 +sii Seiko Instruments, Inc.
1669 +silabs Silicon Laboratories
1671 +silergy Silergy Corp.
1672 +siliconmitus Silicon Mitus, Inc.
1674 +sirf SiRF Technology, Inc.
1675 +sis Silicon Integrated Systems Corp.
1676 +sitronix Sitronix Technology Corporation
1677 +skyworks Skyworks Solutions, Inc.
1678 +smsc Standard Microsystems Corporation
1679 +snps Synopsys, Inc.
1680 +socionext Socionext Inc.
1682 +solomon Solomon Systech Limited
1683 +sony Sony Corporation
1684 +spansion Spansion Inc.
1685 +sprd Spreadtrum Communications Inc.
1686 +sst Silicon Storage Technology, Inc.
1687 +st STMicroelectronics
1688 +starry Starry Electronic Technology (ShenZhen) Co., LTD
1691 +stericsson ST-Ericsson
1692 +summit Summit microelectronics
1693 +sunchip Shenzhen Sunchip Technology Co., Ltd
1694 +SUNW Sun Microsystems, Inc
1695 +swir Sierra Wireless
1696 +syna Synaptics Inc.
1697 +synology Synology, Inc.
1698 +tbs TBS Technologies
1699 +tbs-biometrics Touchless Biometric Systems AG
1700 +tcg Trusted Computing Group
1701 +tcl Toby Churchill Ltd.
1702 +technexion TechNexion
1703 +technologic Technologic Systems
1704 +tempo Tempo Semiconductor
1705 +techstar Shenzhen Techstar Electronics Co., Ltd.
1706 +terasic Terasic Inc.
1707 +thine THine Electronics, Inc.
1708 +ti Texas Instruments
1709 +tianma Tianma Micro-electronics Co., Ltd.
1710 +tlm Trusted Logic Mobility
1711 +tmt Tecon Microprocessor Technologies, LLC.
1714 +toshiba Toshiba Corporation
1717 +tplink TP-LINK Technologies Co., Ltd.
1720 +tronsmart Tronsmart
1721 +truly Truly Semiconductors Limited
1722 +tsd Theobroma Systems Design und Consulting GmbH
1723 +tyan Tyan Computer Corporation
1725 +ucrobotics uCRobotics
1726 +ubnt Ubiquiti Networks
1728 +uniwest United Western Technologies Corp (UniWest)
1729 +upisemi uPI Semiconductor Corp.
1730 +urt United Radiant Technology Corporation
1731 +usi Universal Scientific Industrial Co., Ltd.
1732 +v3 V3 Semiconductor
1734 +variscite Variscite Ltd.
1735 +via VIA Technologies, Inc.
1736 +virtio Virtual I/O Device Specification, developed by the OASIS consortium
1737 +vishay Vishay Intertechnology, Inc
1738 +vitesse Vitesse Semiconductor Corporation
1739 +vivante Vivante Corporation
1740 +vocore VoCore Studio
1741 +voipac Voipac Technologies s.r.o.
1742 +vot Vision Optical Technology Co., Ltd.
1743 +wd Western Digital Corp.
1744 +wetek WeTek Electronics, limited.
1746 +whwave Shenzhen whwave Electronics, Inc.
1748 +winbond Winbond Electronics corp.
1749 +winstar Winstar Display Corp.
1750 +wlf Wolfson Microelectronics
1751 +wm Wondermedia Technologies, Inc.
1753 +xes Extreme Engineering Solutions (X-ES)
1754 +xillybus Xillybus Ltd.
1756 +xunlong Shenzhen Xunlong Software CO.,Limited
1757 +ysoft Y Soft Corporation a.s.
1758 +zarlink Zarlink Semiconductor
1759 +zeitec ZEITEC Semiconductor Co., LTD.
1760 +zidoo Shenzhen Zidoo Technology Co., Ltd.
1761 +zii Zodiac Inflight Innovations
1763 +zyxel ZyXEL Communications Corp.
1764 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
1765 +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
1766 @@ -216,6 +216,8 @@ patternProperties:
1767 description: Shenzhen BigTree Tech Co., LTD
1769 description: Bitmain Technologies
1771 + description: Vilniaus Blokas UAB
1773 description: BluTek Power
1775 --- a/drivers/clk/Kconfig
1776 +++ b/drivers/clk/Kconfig
1777 @@ -98,6 +98,12 @@ config COMMON_CLK_HI655X
1778 multi-function device has one fixed-rate oscillator, clocked
1781 +config COMMON_CLK_HIFIBERRY_DACPLUSHD
1784 +config COMMON_CLK_HIFIBERRY_DACPRO
1787 config COMMON_CLK_SCMI
1788 tristate "Clock driver controlled via SCMI interface"
1789 depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
1790 --- a/drivers/clk/Makefile
1791 +++ b/drivers/clk/Makefile
1792 @@ -56,6 +56,8 @@ obj-$(CONFIG_COMMON_CLK_LAN966X) += clk-
1793 obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
1794 obj-$(CONFIG_MACH_LOONGSON32) += clk-loongson1.o
1795 obj-$(CONFIG_COMMON_CLK_LOONGSON2) += clk-loongson2.o
1796 +obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o
1797 +obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
1798 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
1799 obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
1800 obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
1802 +++ b/drivers/clk/clk-hifiberry-dachd.c
1804 +// SPDX-License-Identifier: GPL-2.0
1806 + * Clock Driver for HiFiBerry DAC+ HD
1808 + * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
1811 + * This program is free software; you can redistribute it and/or
1812 + * modify it under the terms of the GNU General Public License
1813 + * version 2 as published by the Free Software Foundation.
1815 + * This program is distributed in the hope that it will be useful, but
1816 + * WITHOUT ANY WARRANTY; without even the implied warranty of
1817 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1818 + * General Public License for more details.
1821 +#include <linux/clk-provider.h>
1822 +#include <linux/clk.h>
1823 +#include <linux/kernel.h>
1824 +#include <linux/module.h>
1825 +#include <linux/of.h>
1826 +#include <linux/slab.h>
1827 +#include <linux/platform_device.h>
1828 +#include <linux/i2c.h>
1829 +#include <linux/regmap.h>
1831 +#define NO_PLL_RESET 0
1832 +#define PLL_RESET 1
1833 +#define HIFIBERRY_PLL_MAX_REGISTER 256
1834 +#define DEFAULT_RATE 44100
1836 +static struct reg_default hifiberry_pll_reg_defaults[] = {
1837 + {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
1838 + {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
1839 + {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
1840 + {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
1841 + {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
1842 + {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
1843 + {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
1844 + {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
1845 + {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
1846 + {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
1847 + {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
1849 + {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
1850 + {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
1852 + {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
1855 +static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1856 +static int num_common_pll_regs;
1857 +static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1858 +static int num_dedicated_192k_pll_regs;
1859 +static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1860 +static int num_dedicated_96k_pll_regs;
1861 +static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1862 +static int num_dedicated_48k_pll_regs;
1863 +static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1864 +static int num_dedicated_176k4_pll_regs;
1865 +static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1866 +static int num_dedicated_88k2_pll_regs;
1867 +static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
1868 +static int num_dedicated_44k1_pll_regs;
1871 + * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
1872 + * @hw: clk_hw for the common clk framework
1874 +struct clk_hifiberry_drvdata {
1875 + struct regmap *regmap;
1878 + unsigned long rate;
1881 +#define to_hifiberry_clk(_hw) \
1882 + container_of(_hw, struct clk_hifiberry_drvdata, hw)
1884 +static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
1885 + struct reg_default *regs,
1886 + int num, int do_pll_reset)
1890 + char pll_soft_reset[] = { 177, 0xAC, };
1892 + for (i = 0; i < num; i++) {
1893 + ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
1897 + if (do_pll_reset) {
1898 + ret |= regmap_write(regmap, pll_soft_reset[0],
1899 + pll_soft_reset[1]);
1905 +static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
1906 + unsigned long parent_rate)
1908 + return to_hifiberry_clk(hw)->rate;
1911 +static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
1912 + unsigned long rate, unsigned long *parent_rate)
1917 +static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
1918 + unsigned long rate, unsigned long parent_rate)
1921 + struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
1925 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1926 + dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
1930 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1931 + dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
1935 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1936 + dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
1940 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1941 + dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
1945 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1946 + dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
1950 + ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
1951 + dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
1958 + to_hifiberry_clk(hw)->rate = rate;
1963 +const struct clk_ops clk_hifiberry_dachd_rate_ops = {
1964 + .recalc_rate = clk_hifiberry_dachd_recalc_rate,
1965 + .round_rate = clk_hifiberry_dachd_round_rate,
1966 + .set_rate = clk_hifiberry_dachd_set_rate,
1969 +static int clk_hifiberry_get_prop_values(struct device *dev,
1971 + struct reg_default *regs)
1975 + u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
1977 + ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
1978 + tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
1983 + "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
1990 + for (i = 0; i < ret; i++) {
1991 + regs[i].reg = (u32)tmp[2 * i];
1992 + regs[i].def = (u32)tmp[2 * i + 1];
1998 +static int clk_hifiberry_dachd_dt_parse(struct device *dev)
2000 + num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
2001 + "common_pll_regs", common_pll_regs);
2002 + num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
2003 + "44k1_pll_regs", dedicated_44k1_pll_regs);
2004 + num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
2005 + "88k2_pll_regs", dedicated_88k2_pll_regs);
2006 + num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
2007 + "176k4_pll_regs", dedicated_176k4_pll_regs);
2008 + num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
2009 + "48k_pll_regs", dedicated_48k_pll_regs);
2010 + num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
2011 + "96k_pll_regs", dedicated_96k_pll_regs);
2012 + num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
2013 + "192k_pll_regs", dedicated_192k_pll_regs);
2018 +static int clk_hifiberry_dachd_remove(struct device *dev)
2020 + of_clk_del_provider(dev->of_node);
2024 +const struct regmap_config hifiberry_pll_regmap = {
2027 + .max_register = HIFIBERRY_PLL_MAX_REGISTER,
2028 + .reg_defaults = hifiberry_pll_reg_defaults,
2029 + .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
2030 + .cache_type = REGCACHE_RBTREE,
2032 +EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
2035 +static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c)
2037 + struct clk_hifiberry_drvdata *hdclk;
2039 + struct clk_init_data init;
2040 + struct device *dev = &i2c->dev;
2041 + struct device_node *dev_node = dev->of_node;
2042 + struct regmap_config config = hifiberry_pll_regmap;
2044 + hdclk = devm_kzalloc(&i2c->dev,
2045 + sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
2049 + i2c_set_clientdata(i2c, hdclk);
2051 + hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
2053 + if (IS_ERR(hdclk->regmap))
2054 + return PTR_ERR(hdclk->regmap);
2056 + /* start PLL to allow detection of DAC */
2057 + ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
2058 + hifiberry_pll_reg_defaults,
2059 + ARRAY_SIZE(hifiberry_pll_reg_defaults),
2064 + clk_hifiberry_dachd_dt_parse(dev);
2066 + /* restart PLL with configs from DTB */
2067 + ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
2068 + num_common_pll_regs, PLL_RESET);
2072 + init.name = "clk-hifiberry-dachd";
2073 + init.ops = &clk_hifiberry_dachd_rate_ops;
2075 + init.parent_names = NULL;
2076 + init.num_parents = 0;
2078 + hdclk->hw.init = &init;
2080 + hdclk->clk = devm_clk_register(dev, &hdclk->hw);
2081 + if (IS_ERR(hdclk->clk)) {
2082 + dev_err(dev, "unable to register %s\n", init.name);
2083 + return PTR_ERR(hdclk->clk);
2086 + ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
2088 + dev_err(dev, "Cannot of_clk_add_provider");
2092 + ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
2094 + dev_err(dev, "Cannot set rate : %d\n", ret);
2101 +static void clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
2103 + clk_hifiberry_dachd_remove(&i2c->dev);
2106 +static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
2110 +MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
2112 +static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
2113 + { .compatible = "hifiberry,dachd-clk", },
2116 +MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
2118 +static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
2119 + .probe = clk_hifiberry_dachd_i2c_probe,
2120 + .remove = clk_hifiberry_dachd_i2c_remove,
2121 + .id_table = clk_hifiberry_dachd_i2c_id,
2123 + .name = "dachd-clk",
2124 + .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
2128 +module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
2131 +MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
2132 +MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
2133 +MODULE_LICENSE("GPL v2");
2134 +MODULE_ALIAS("platform:clk-hifiberry-dachd");
2136 +++ b/drivers/clk/clk-hifiberry-dacpro.c
2139 + * Clock Driver for HiFiBerry DAC Pro
2141 + * Author: Stuart MacLean
2144 + * This program is free software; you can redistribute it and/or
2145 + * modify it under the terms of the GNU General Public License
2146 + * version 2 as published by the Free Software Foundation.
2148 + * This program is distributed in the hope that it will be useful, but
2149 + * WITHOUT ANY WARRANTY; without even the implied warranty of
2150 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2151 + * General Public License for more details.
2154 +#include <linux/clk-provider.h>
2155 +#include <linux/clkdev.h>
2156 +#include <linux/kernel.h>
2157 +#include <linux/module.h>
2158 +#include <linux/of.h>
2159 +#include <linux/slab.h>
2160 +#include <linux/platform_device.h>
2162 +struct ext_clk_rates {
2163 + /* Clock rate of CLK44EN attached to GPIO6 pin */
2164 + unsigned long clk_44en;
2165 + /* Clock rate of CLK48EN attached to GPIO3 pin */
2166 + unsigned long clk_48en;
2170 + * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
2171 + * @hw: clk_hw for the common clk framework
2172 + * @mode: 0 => CLK44EN, 1 => CLK48EN
2174 +struct clk_hifiberry_hw {
2177 + struct ext_clk_rates clk_rates;
2180 +#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
2182 +static const struct ext_clk_rates hifiberry_dacpro_clks = {
2183 + .clk_44en = 22579200UL,
2184 + .clk_48en = 24576000UL,
2187 +static const struct ext_clk_rates allo_dac_clks = {
2188 + .clk_44en = 45158400UL,
2189 + .clk_48en = 49152000UL,
2192 +static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
2193 + { .compatible = "hifiberry,dacpro-clk", &hifiberry_dacpro_clks },
2194 + { .compatible = "allo,dac-clk", &allo_dac_clks },
2197 +MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
2199 +static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw,
2200 + unsigned long parent_rate)
2202 + struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
2203 + return (clk->mode == 0) ? clk->clk_rates.clk_44en :
2204 + clk->clk_rates.clk_48en;
2207 +static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw,
2208 + unsigned long rate, unsigned long *parent_rate)
2210 + struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
2213 + if (rate <= clk->clk_rates.clk_44en) {
2214 + actual_rate = (long)clk->clk_rates.clk_44en;
2215 + } else if (rate >= clk->clk_rates.clk_48en) {
2216 + actual_rate = (long)clk->clk_rates.clk_48en;
2218 + long diff44Rate = (long)(rate - clk->clk_rates.clk_44en);
2219 + long diff48Rate = (long)(clk->clk_rates.clk_48en - rate);
2221 + if (diff44Rate < diff48Rate)
2222 + actual_rate = (long)clk->clk_rates.clk_44en;
2224 + actual_rate = (long)clk->clk_rates.clk_48en;
2226 + return actual_rate;
2230 +static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw,
2231 + unsigned long rate, unsigned long parent_rate)
2233 + struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
2234 + unsigned long actual_rate;
2236 + actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
2238 + clk->mode = (actual_rate == clk->clk_rates.clk_44en) ? 0 : 1;
2243 +const struct clk_ops clk_hifiberry_dacpro_rate_ops = {
2244 + .recalc_rate = clk_hifiberry_dacpro_recalc_rate,
2245 + .round_rate = clk_hifiberry_dacpro_round_rate,
2246 + .set_rate = clk_hifiberry_dacpro_set_rate,
2249 +static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
2251 + const struct of_device_id *of_id;
2252 + struct clk_hifiberry_hw *proclk;
2254 + struct device *dev;
2255 + struct clk_init_data init;
2259 + of_id = of_match_node(clk_hifiberry_dacpro_dt_ids, dev->of_node);
2263 + proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
2267 + init.name = "clk-hifiberry-dacpro";
2268 + init.ops = &clk_hifiberry_dacpro_rate_ops;
2270 + init.parent_names = NULL;
2271 + init.num_parents = 0;
2274 + proclk->hw.init = &init;
2275 + memcpy(&proclk->clk_rates, of_id->data, sizeof(proclk->clk_rates));
2277 + clk = devm_clk_register(dev, &proclk->hw);
2278 + if (!IS_ERR(clk)) {
2279 + ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
2282 + dev_err(dev, "Fail to register clock driver\n");
2284 + ret = PTR_ERR(clk);
2289 +static void clk_hifiberry_dacpro_remove(struct platform_device *pdev)
2291 + of_clk_del_provider(pdev->dev.of_node);
2294 +static struct platform_driver clk_hifiberry_dacpro_driver = {
2295 + .probe = clk_hifiberry_dacpro_probe,
2296 + .remove = clk_hifiberry_dacpro_remove,
2298 + .name = "clk-hifiberry-dacpro",
2299 + .of_match_table = clk_hifiberry_dacpro_dt_ids,
2303 +static int __init clk_hifiberry_dacpro_init(void)
2305 + return platform_driver_register(&clk_hifiberry_dacpro_driver);
2307 +core_initcall(clk_hifiberry_dacpro_init);
2309 +static void __exit clk_hifiberry_dacpro_exit(void)
2311 + platform_driver_unregister(&clk_hifiberry_dacpro_driver);
2313 +module_exit(clk_hifiberry_dacpro_exit);
2315 +MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver");
2316 +MODULE_LICENSE("GPL v2");
2317 +MODULE_ALIAS("platform:clk-hifiberry-dacpro");
2318 --- a/sound/soc/bcm/Kconfig
2319 +++ b/sound/soc/bcm/Kconfig
2320 @@ -26,3 +26,287 @@ config SND_BCM63XX_I2S_WHISTLER
2321 DSL/PON chips (bcm63158, bcm63178)
2323 If you don't know what to do here, say N
2325 +config SND_BCM2708_SOC_CHIPDIP_DAC
2326 + tristate "Support for the ChipDip DAC"
2328 + Say Y or M if you want to add support for the ChipDip DAC soundcard
2330 +config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
2331 + tristate "Support for Google voiceHAT soundcard"
2332 + select SND_SOC_VOICEHAT
2333 + select SND_RPI_SIMPLE_SOUNDCARD
2335 + Say Y or M if you want to add support for voiceHAT soundcard.
2337 +config SND_BCM2708_SOC_HIFIBERRY_ADC
2338 + tristate "Support for HifiBerry ADC"
2339 + select SND_SOC_PCM186X_I2C
2340 + select SND_RPI_HIFIBERRY_ADC
2342 + Say Y or M if you want to add support for HifiBerry ADC.
2343 + Use this module for HiFiBerry's ADC-only sound cards
2345 +config SND_BCM2708_SOC_HIFIBERRY_ADC8X
2346 + tristate "Support for HifiBerry ADC8X"
2347 + select SND_RPI_SIMPLE_SOUNDCARD
2349 + Say Y or M if you want to add support for HifiBerry ADC8X.
2350 + Note: ADC8X only works on PI5
2352 +config SND_BCM2708_SOC_HIFIBERRY_DAC
2353 + tristate "Support for HifiBerry DAC and DAC8X"
2354 + select SND_SOC_PCM5102A
2355 + select SND_RPI_SIMPLE_SOUNDCARD
2357 + Say Y or M if you want to add support for HifiBerry DAC and DAC8X.
2358 + Note: DAC8X only works on PI5
2360 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
2361 + tristate "Support for HifiBerry DAC+"
2362 + select SND_SOC_PCM512x
2363 + select SND_SOC_TPA6130A2
2364 + select COMMON_CLK_HIFIBERRY_DACPRO
2366 + Say Y or M if you want to add support for HifiBerry DAC+.
2368 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
2369 + tristate "Support for HifiBerry DAC+ HD"
2370 + select SND_SOC_PCM179X_I2C
2371 + select COMMON_CLK_HIFIBERRY_DACPLUSHD
2373 + Say Y or M if you want to add support for HifiBerry DAC+ HD.
2375 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
2376 + tristate "Support for HifiBerry DAC+ADC"
2377 + select SND_SOC_PCM512x_I2C
2378 + select SND_SOC_DMIC
2379 + select COMMON_CLK_HIFIBERRY_DACPRO
2381 + Say Y or M if you want to add support for HifiBerry DAC+ADC.
2383 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
2384 + tristate "Support for HifiBerry DAC+ADC PRO"
2385 + select SND_SOC_PCM512x_I2C
2386 + select SND_SOC_PCM186X_I2C
2387 + select SND_SOC_TPA6130A2
2388 + select COMMON_CLK_HIFIBERRY_DACPRO
2390 + Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
2392 +config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
2393 + tristate "Support for HifiBerry DAC+DSP"
2394 + select SND_RPI_SIMPLE_SOUNDCARD
2396 + Say Y or M if you want to add support for HifiBerry DSP-DAC.
2398 +config SND_BCM2708_SOC_HIFIBERRY_DIGI
2399 + tristate "Support for HifiBerry Digi"
2400 + select SND_SOC_WM8804
2402 + Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
2404 +config SND_BCM2708_SOC_HIFIBERRY_AMP
2405 + tristate "Support for the HifiBerry Amp"
2406 + select SND_SOC_TAS5713
2407 + select SND_RPI_SIMPLE_SOUNDCARD
2409 + Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
2411 +config SND_BCM2708_SOC_PIFI_40
2412 + tristate "Support for the PiFi-40 amp"
2413 + select SND_SOC_TAS571X
2414 + select SND_PIFI_40
2416 + Say Y or M if you want to add support for the PiFi40 amp board
2418 +config SND_BCM2708_SOC_RPI_CIRRUS
2419 + tristate "Support for Cirrus Logic Audio Card"
2420 + select SND_SOC_WM5102
2421 + select SND_SOC_WM8804
2423 + Say Y or M if you want to add support for the Wolfson and
2424 + Cirrus Logic audio cards.
2426 +config SND_BCM2708_SOC_RPI_DAC
2427 + tristate "Support for RPi-DAC"
2428 + select SND_SOC_PCM1794A
2429 + select SND_RPI_SIMPLE_SOUNDCARD
2431 + Say Y or M if you want to add support for RPi-DAC.
2433 +config SND_BCM2708_SOC_RPI_PROTO
2434 + tristate "Support for Rpi-PROTO"
2435 + select SND_SOC_WM8731_I2C
2437 + Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
2439 +config SND_BCM2708_SOC_JUSTBOOM_BOTH
2440 + tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
2441 + select SND_SOC_WM8804
2442 + select SND_SOC_PCM512x
2444 + Say Y or M if you want to add support for simultaneous
2445 + JustBoom Digi and JustBoom DAC.
2447 + This is not the right choice if you only have one but both of
2450 +config SND_BCM2708_SOC_JUSTBOOM_DAC
2451 + tristate "Support for JustBoom DAC"
2452 + select SND_SOC_PCM512x
2454 + Say Y or M if you want to add support for JustBoom DAC.
2456 +config SND_BCM2708_SOC_JUSTBOOM_DIGI
2457 + tristate "Support for JustBoom Digi"
2458 + select SND_SOC_WM8804
2459 + select SND_RPI_WM8804_SOUNDCARD
2461 + Say Y or M if you want to add support for JustBoom Digi.
2463 +config SND_BCM2708_SOC_IQAUDIO_CODEC
2464 + tristate "Support for IQaudIO-CODEC"
2465 + select SND_SOC_DA7213
2467 + Say Y or M if you want to add support for IQaudIO-CODEC.
2469 +config SND_BCM2708_SOC_IQAUDIO_DAC
2470 + tristate "Support for IQaudIO-DAC"
2471 + select SND_SOC_PCM512x_I2C
2473 + Say Y or M if you want to add support for IQaudIO-DAC.
2475 +config SND_BCM2708_SOC_IQAUDIO_DIGI
2476 + tristate "Support for IQAudIO Digi"
2477 + select SND_SOC_WM8804
2478 + select SND_RPI_WM8804_SOUNDCARD
2480 + Say Y or M if you want to add support for IQAudIO Digital IO board.
2482 +config SND_BCM2708_SOC_I_SABRE_Q2M
2483 + tristate "Support for Audiophonics I-Sabre Q2M DAC"
2484 + select SND_SOC_I_SABRE_CODEC
2486 + Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC
2488 +config SND_BCM2708_SOC_ADAU1977_ADC
2489 + tristate "Support for ADAU1977 ADC"
2490 + select SND_SOC_ADAU1977_I2C
2491 + select SND_RPI_SIMPLE_SOUNDCARD
2493 + Say Y or M if you want to add support for ADAU1977 ADC.
2495 +config SND_AUDIOINJECTOR_PI_SOUNDCARD
2496 + tristate "Support for audioinjector.net Pi add on soundcard"
2497 + select SND_SOC_WM8731_I2C
2499 + Say Y or M if you want to add support for audioinjector.net Pi Hat
2501 +config SND_AUDIOINJECTOR_OCTO_SOUNDCARD
2502 + tristate "Support for audioinjector.net Octo channel (Hat) soundcard"
2503 + select SND_SOC_CS42XX8_I2C
2505 + Say Y or M if you want to add support for audioinjector.net octo add on
2507 +config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD
2508 + tristate "Support for audioinjector.net isolated DAC and ADC soundcard"
2509 + select SND_SOC_CS4271_I2C
2511 + Say Y or M if you want to add support for audioinjector.net isolated soundcard
2513 +config SND_AUDIOSENSE_PI
2514 + tristate "Support for AudioSense Add-On Soundcard"
2515 + select SND_SOC_TLV320AIC32X4_I2C
2517 + Say Y or M if you want to add support for tlv320aic32x4 add-on
2519 +config SND_DIGIDAC1_SOUNDCARD
2520 + tristate "Support for Red Rocks Audio DigiDAC1"
2521 + select SND_SOC_WM8804
2522 + select SND_SOC_WM8741
2524 + Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board.
2526 +config SND_BCM2708_SOC_DIONAUDIO_LOCO
2527 + tristate "Support for Dion Audio LOCO DAC-AMP"
2528 + select SND_SOC_PCM5102a
2530 + Say Y or M if you want to add support for Dion Audio LOCO.
2532 +config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2
2533 + tristate "Support for Dion Audio LOCO-V2 DAC-AMP"
2534 + select SND_SOC_PCM5122
2536 + Say Y or M if you want to add support for Dion Audio LOCO-V2.
2538 +config SND_BCM2708_SOC_ALLO_PIANO_DAC
2539 + tristate "Support for Allo Piano DAC"
2540 + select SND_SOC_PCM512x_I2C
2542 + Say Y or M if you want to add support for Allo Piano DAC.
2544 +config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS
2545 + tristate "Support for Allo Piano DAC Plus"
2546 + select SND_SOC_PCM512x_I2C
2548 + Say Y or M if you want to add support for Allo Piano DAC Plus.
2550 +config SND_BCM2708_SOC_ALLO_BOSS_DAC
2551 + tristate "Support for Allo Boss DAC"
2552 + select SND_SOC_PCM512x_I2C
2553 + select COMMON_CLK_HIFIBERRY_DACPRO
2555 + Say Y or M if you want to add support for Allo Boss DAC.
2557 +config SND_BCM2708_SOC_ALLO_BOSS2_DAC
2558 + tristate "Support for Allo Boss2 DAC"
2561 + select SND_AUDIO_GRAPH_CARD
2563 + Say Y or M if you want to add support for Allo Boss2 DAC.
2565 +config SND_BCM2708_SOC_ALLO_DIGIONE
2566 + tristate "Support for Allo DigiOne"
2567 + select SND_SOC_WM8804
2568 + select SND_RPI_WM8804_SOUNDCARD
2570 + Say Y or M if you want to add support for Allo DigiOne.
2572 +config SND_BCM2708_SOC_ALLO_KATANA_DAC
2573 + tristate "Support for Allo Katana DAC"
2576 + select SND_AUDIO_GRAPH_CARD
2578 + Say Y or M if you want to add support for Allo Katana DAC.
2580 +config SND_BCM2708_SOC_FE_PI_AUDIO
2581 + tristate "Support for Fe-Pi-Audio"
2582 + select SND_SOC_SGTL5000
2584 + Say Y or M if you want to add support for Fe-Pi-Audio.
2587 + tristate "Support for Blokas Labs pisound"
2588 + select SND_RAWMIDI
2590 + Say Y or M if you want to add support for Blokas Labs pisound.
2592 +config SND_RPI_SIMPLE_SOUNDCARD
2593 + tristate "Support for Raspberry Pi simple soundcards"
2595 + Say Y or M if you want to add support Raspbery Pi simple soundcards
2597 +config SND_RPI_WM8804_SOUNDCARD
2598 + tristate "Support for Raspberry Pi generic WM8804 soundcards"
2600 + Say Y or M if you want to add support for the Raspberry Pi
2601 + generic driver for WM8804 based soundcards.
2603 +config SND_DACBERRY400
2604 + tristate "Support for DACBERRY400 Soundcard"
2605 + select SND_SOC_TLV320AIC3X_I2C
2607 + Say Y or M if you want to add support for tlv320aic3x add-on
2608 --- a/sound/soc/bcm/Makefile
2609 +++ b/sound/soc/bcm/Makefile
2610 @@ -12,4 +12,75 @@ obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-
2611 # BCM63XX Platform Support
2612 snd-soc-63xx-y := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
2614 -obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
2615 \ No newline at end of file
2616 +obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
2618 +# Google voiceHAT custom codec support
2619 +snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
2621 +# BCM2708 Machine Support
2622 +snd-soc-hifiberry-adc-objs := hifiberry_adc.o
2623 +snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
2624 +snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
2625 +snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
2626 +snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
2627 +snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
2628 +snd-soc-justboom-both-objs := justboom-both.o
2629 +snd-soc-justboom-dac-objs := justboom-dac.o
2630 +snd-soc-rpi-cirrus-objs := rpi-cirrus.o
2631 +snd-soc-rpi-proto-objs := rpi-proto.o
2632 +snd-soc-iqaudio-codec-objs := iqaudio-codec.o
2633 +snd-soc-iqaudio-dac-objs := iqaudio-dac.o
2634 + snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
2635 +snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
2636 +snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
2637 +snd-soc-audioinjector-isolated-soundcard-objs := audioinjector-isolated-soundcard.o
2638 +snd-soc-audiosense-pi-objs := audiosense-pi.o
2639 +snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
2640 +snd-soc-dionaudio-loco-objs := dionaudio_loco.o
2641 +snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o
2642 +snd-soc-allo-boss-dac-objs := allo-boss-dac.o
2643 +snd-soc-allo-boss2-dac-objs := allo-boss2-dac.o
2644 +snd-soc-allo-piano-dac-objs := allo-piano-dac.o
2645 +snd-soc-allo-piano-dac-plus-objs := allo-piano-dac-plus.o
2646 +snd-soc-allo-katana-codec-objs := allo-katana-codec.o
2647 +snd-soc-pisound-objs := pisound.o
2648 +snd-soc-fe-pi-audio-objs := fe-pi-audio.o
2649 +snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
2650 +snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
2651 +snd-soc-pifi-40-objs := pifi-40.o
2652 +snd-soc-chipdip-dac-objs := chipdip-dac.o
2653 +snd-soc-dacberry400-objs := dacberry400.o
2655 +obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
2656 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC) += snd-soc-hifiberry-adc.o
2657 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
2658 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
2659 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
2660 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
2661 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
2662 +obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
2663 +obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
2664 +obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
2665 +obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
2666 +obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
2667 +obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
2668 +obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o
2669 +obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
2670 +obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
2671 +obj-$(CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD) += snd-soc-audioinjector-isolated-soundcard.o
2672 +obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o
2673 +obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
2674 +obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
2675 +obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o
2676 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += snd-soc-allo-boss-dac.o
2677 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC) += snd-soc-allo-boss2-dac.o
2678 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o
2679 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS) += snd-soc-allo-piano-dac-plus.o
2680 +obj-$(CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC) += snd-soc-allo-katana-codec.o
2681 +obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o
2682 +obj-$(CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO) += snd-soc-fe-pi-audio.o
2683 +obj-$(CONFIG_SND_RPI_SIMPLE_SOUNDCARD) += snd-soc-rpi-simple-soundcard.o
2684 +obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o
2685 +obj-$(CONFIG_SND_BCM2708_SOC_PIFI_40) += snd-soc-pifi-40.o
2686 +obj-$(CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC) += snd-soc-chipdip-dac.o
2687 +obj-$(CONFIG_SND_DACBERRY400) += snd-soc-dacberry400.o
2689 +++ b/sound/soc/bcm/allo-boss-dac.c
2692 + * ALSA ASoC Machine Driver for Allo Boss DAC
2694 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
2696 + * based on code by Daniel Matuschek,
2697 + * Stuart MacLean <stuart@hifiberry.com>
2698 + * based on code by Florian Meier <florian.meier@koalo.de>
2700 + * This program is free software; you can redistribute it and/or
2701 + * modify it under the terms of the GNU General Public License
2702 + * version 2 as published by the Free Software Foundation.
2704 + * This program is distributed in the hope that it will be useful, but
2705 + * WITHOUT ANY WARRANTY; without even the implied warranty of
2706 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2707 + * General Public License for more details.
2710 +#include <linux/module.h>
2711 +#include <linux/gpio/consumer.h>
2712 +#include <linux/platform_device.h>
2713 +#include <linux/clk.h>
2714 +#include <linux/delay.h>
2716 +#include <sound/core.h>
2717 +#include <sound/pcm.h>
2718 +#include <sound/pcm_params.h>
2719 +#include <sound/soc.h>
2720 +#include "../codecs/pcm512x.h"
2722 +#define ALLO_BOSS_NOCLOCK 0
2723 +#define ALLO_BOSS_CLK44EN 1
2724 +#define ALLO_BOSS_CLK48EN 2
2726 +struct pcm512x_priv {
2727 + struct regmap *regmap;
2731 +static struct gpio_desc *mute_gpio;
2733 +/* Clock rate of CLK44EN attached to GPIO6 pin */
2734 +#define CLK_44EN_RATE 45158400UL
2735 +/* Clock rate of CLK48EN attached to GPIO3 pin */
2736 +#define CLK_48EN_RATE 49152000UL
2739 +static bool snd_soc_allo_boss_master;
2740 +static bool digital_gain_0db_limit = true;
2742 +static void snd_allo_boss_select_clk(struct snd_soc_component *component,
2746 + case ALLO_BOSS_NOCLOCK:
2747 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
2749 + case ALLO_BOSS_CLK44EN:
2750 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
2752 + case ALLO_BOSS_CLK48EN:
2753 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
2758 +static void snd_allo_boss_clk_gpio(struct snd_soc_component *component)
2760 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
2761 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
2762 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
2765 +static bool snd_allo_boss_is_sclk(struct snd_soc_component *component)
2769 + sck = snd_soc_component_read(component, PCM512x_RATE_DET_4);
2770 + return (!(sck & 0x40));
2773 +static bool snd_allo_boss_is_sclk_sleep(
2774 + struct snd_soc_component *component)
2777 + return snd_allo_boss_is_sclk(component);
2780 +static bool snd_allo_boss_is_master_card(struct snd_soc_component *component)
2782 + bool isClk44EN, isClk48En, isNoClk;
2784 + snd_allo_boss_clk_gpio(component);
2786 + snd_allo_boss_select_clk(component, ALLO_BOSS_CLK44EN);
2787 + isClk44EN = snd_allo_boss_is_sclk_sleep(component);
2789 + snd_allo_boss_select_clk(component, ALLO_BOSS_NOCLOCK);
2790 + isNoClk = snd_allo_boss_is_sclk_sleep(component);
2792 + snd_allo_boss_select_clk(component, ALLO_BOSS_CLK48EN);
2793 + isClk48En = snd_allo_boss_is_sclk_sleep(component);
2795 + return (isClk44EN && isClk48En && !isNoClk);
2798 +static int snd_allo_boss_clk_for_rate(int sample_rate)
2802 + switch (sample_rate) {
2809 + type = ALLO_BOSS_CLK44EN;
2812 + type = ALLO_BOSS_CLK48EN;
2818 +static void snd_allo_boss_set_sclk(struct snd_soc_component *component,
2821 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
2823 + if (!IS_ERR(pcm512x->sclk)) {
2826 + ctype = snd_allo_boss_clk_for_rate(sample_rate);
2827 + clk_set_rate(pcm512x->sclk, (ctype == ALLO_BOSS_CLK44EN)
2828 + ? CLK_44EN_RATE : CLK_48EN_RATE);
2829 + snd_allo_boss_select_clk(component, ctype);
2833 +static int snd_allo_boss_init(struct snd_soc_pcm_runtime *rtd)
2835 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
2836 + struct pcm512x_priv *priv = snd_soc_component_get_drvdata(component);
2839 + snd_soc_allo_boss_master = false;
2841 + snd_soc_allo_boss_master =
2842 + snd_allo_boss_is_master_card(component);
2844 + if (snd_soc_allo_boss_master) {
2845 + struct snd_soc_dai_link *dai = rtd->dai_link;
2847 + dai->name = "BossDAC";
2848 + dai->stream_name = "Boss DAC HiFi [Master]";
2849 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
2850 + | SND_SOC_DAIFMT_CBM_CFM;
2852 + snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
2853 + snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
2854 + snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
2856 + * Default sclk to CLK_48EN_RATE, otherwise codec
2857 + * pcm512x_dai_startup_master method could call
2858 + * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
2859 + * which will mask 384k sample rate.
2861 + if (!IS_ERR(priv->sclk))
2862 + clk_set_rate(priv->sclk, CLK_48EN_RATE);
2864 + priv->sclk = ERR_PTR(-ENOENT);
2867 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
2868 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
2869 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
2871 + if (digital_gain_0db_limit) {
2873 + struct snd_soc_card *card = rtd->card;
2875 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
2878 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
2885 +static int snd_allo_boss_update_rate_den(
2886 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
2888 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
2889 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
2890 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
2891 + struct snd_ratnum *rats_no_pll;
2892 + unsigned int num = 0, den = 0;
2895 + rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
2899 + rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
2900 + rats_no_pll->den_min = 1;
2901 + rats_no_pll->den_max = 128;
2902 + rats_no_pll->den_step = 1;
2904 + err = snd_interval_ratnum(hw_param_interval(params,
2905 + SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
2906 + if (err >= 0 && den) {
2907 + params->rate_num = num;
2908 + params->rate_den = den;
2911 + devm_kfree(rtd->dev, rats_no_pll);
2915 +static void snd_allo_boss_gpio_mute(struct snd_soc_card *card)
2918 + gpiod_set_value_cansleep(mute_gpio, 1);
2921 +static void snd_allo_boss_gpio_unmute(struct snd_soc_card *card)
2924 + gpiod_set_value_cansleep(mute_gpio, 0);
2927 +static int snd_allo_boss_set_bias_level(struct snd_soc_card *card,
2928 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
2930 + struct snd_soc_pcm_runtime *rtd;
2931 + struct snd_soc_dai *codec_dai;
2933 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
2934 + codec_dai = snd_soc_rtd_to_codec(rtd, 0);
2936 + if (dapm->dev != codec_dai->dev)
2940 + case SND_SOC_BIAS_PREPARE:
2941 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
2944 + snd_allo_boss_gpio_unmute(card);
2947 + case SND_SOC_BIAS_STANDBY:
2948 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
2951 + snd_allo_boss_gpio_mute(card);
2961 +static int snd_allo_boss_hw_params(
2962 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
2965 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
2966 + int channels = params_channels(params);
2967 + int width = snd_pcm_format_width(params_format(params));
2968 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
2969 + struct snd_soc_card *card = rtd->card;
2971 + /* Using powers of 2 allows for an integer clock divisor */
2972 + width = width <= 16 ? 16 : 32;
2974 + /* Mute before changing sample rate */
2975 + snd_allo_boss_gpio_mute(card);
2977 + if (snd_soc_allo_boss_master) {
2978 + snd_allo_boss_set_sclk(component, params_rate(params));
2980 + ret = snd_allo_boss_update_rate_den(substream, params);
2985 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), channels * width);
2990 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), channels * width);
2995 + /* Unmute after setting parameters or having an error */
2997 + snd_allo_boss_gpio_unmute(card);
3002 +static int snd_allo_boss_startup(
3003 + struct snd_pcm_substream *substream)
3005 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
3006 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
3007 + struct snd_soc_card *card = rtd->card;
3009 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
3010 + snd_allo_boss_gpio_mute(card);
3012 + if (snd_soc_allo_boss_master) {
3013 + struct pcm512x_priv *priv = snd_soc_component_get_drvdata(component);
3015 + * Default sclk to CLK_48EN_RATE, otherwise codec
3016 + * pcm512x_dai_startup_master method could call
3017 + * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
3018 + * which will mask 384k sample rate.
3020 + if (!IS_ERR(priv->sclk))
3021 + clk_set_rate(priv->sclk, CLK_48EN_RATE);
3027 +static void snd_allo_boss_shutdown(
3028 + struct snd_pcm_substream *substream)
3030 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
3031 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
3033 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
3036 +static int snd_allo_boss_prepare(
3037 + struct snd_pcm_substream *substream)
3039 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
3040 + struct snd_soc_card *card = rtd->card;
3042 + snd_allo_boss_gpio_unmute(card);
3045 +/* machine stream operations */
3046 +static struct snd_soc_ops snd_allo_boss_ops = {
3047 + .hw_params = snd_allo_boss_hw_params,
3048 + .startup = snd_allo_boss_startup,
3049 + .shutdown = snd_allo_boss_shutdown,
3050 + .prepare = snd_allo_boss_prepare,
3053 +SND_SOC_DAILINK_DEFS(allo_boss,
3054 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
3055 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
3056 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
3058 +static struct snd_soc_dai_link snd_allo_boss_dai[] = {
3060 + .name = "Boss DAC",
3061 + .stream_name = "Boss DAC HiFi",
3062 + .dai_fmt = SND_SOC_DAIFMT_I2S |
3063 + SND_SOC_DAIFMT_NB_NF |
3064 + SND_SOC_DAIFMT_CBS_CFS,
3065 + .ops = &snd_allo_boss_ops,
3066 + .init = snd_allo_boss_init,
3067 + SND_SOC_DAILINK_REG(allo_boss),
3071 +/* audio machine driver */
3072 +static struct snd_soc_card snd_allo_boss = {
3073 + .name = "BossDAC",
3074 + .owner = THIS_MODULE,
3075 + .dai_link = snd_allo_boss_dai,
3076 + .num_links = ARRAY_SIZE(snd_allo_boss_dai),
3079 +static int snd_allo_boss_probe(struct platform_device *pdev)
3083 + snd_allo_boss.dev = &pdev->dev;
3085 + if (pdev->dev.of_node) {
3086 + struct device_node *i2s_node;
3087 + struct snd_soc_dai_link *dai;
3089 + dai = &snd_allo_boss_dai[0];
3090 + i2s_node = of_parse_phandle(pdev->dev.of_node,
3091 + "i2s-controller", 0);
3094 + dai->cpus->dai_name = NULL;
3095 + dai->cpus->of_node = i2s_node;
3096 + dai->platforms->name = NULL;
3097 + dai->platforms->of_node = i2s_node;
3100 + digital_gain_0db_limit = !of_property_read_bool(
3101 + pdev->dev.of_node, "allo,24db_digital_gain");
3102 + slave = of_property_read_bool(pdev->dev.of_node,
3105 + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
3107 + if (IS_ERR(mute_gpio)) {
3108 + ret = PTR_ERR(mute_gpio);
3109 + dev_err(&pdev->dev,
3110 + "failed to get mute gpio: %d\n", ret);
3115 + snd_allo_boss.set_bias_level =
3116 + snd_allo_boss_set_bias_level;
3118 + ret = snd_soc_register_card(&snd_allo_boss);
3120 + dev_err(&pdev->dev,
3121 + "snd_soc_register_card() failed: %d\n", ret);
3126 + snd_allo_boss_gpio_mute(&snd_allo_boss);
3134 +static void snd_allo_boss_remove(struct platform_device *pdev)
3136 + snd_allo_boss_gpio_mute(&snd_allo_boss);
3137 + snd_soc_unregister_card(&snd_allo_boss);
3140 +static const struct of_device_id snd_allo_boss_of_match[] = {
3141 + { .compatible = "allo,boss-dac", },
3142 + { /* sentinel */ },
3144 +MODULE_DEVICE_TABLE(of, snd_allo_boss_of_match);
3146 +static struct platform_driver snd_allo_boss_driver = {
3148 + .name = "snd-allo-boss-dac",
3149 + .owner = THIS_MODULE,
3150 + .of_match_table = snd_allo_boss_of_match,
3152 + .probe = snd_allo_boss_probe,
3153 + .remove = snd_allo_boss_remove,
3156 +module_platform_driver(snd_allo_boss_driver);
3158 +MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
3159 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Boss DAC");
3160 +MODULE_LICENSE("GPL v2");
3162 +++ b/sound/soc/bcm/allo-boss2-dac.c
3165 + * Driver for the ALLO KATANA CODEC
3167 + * Author: Jaikumar <sudeepkumar@cem-solutions.net>
3170 + * This program is free software; you can redistribute it and/or
3171 + * modify it under the terms of the GNU General Public License
3172 + * version 2 as published by the Free Software Foundation.
3174 + * This program is distributed in the hope that it will be useful, but
3175 + * WITHOUT ANY WARRANTY; without even the implied warranty of
3176 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3177 + * General Public License for more details.
3180 +#include <linux/module.h>
3181 +#include <linux/moduleparam.h>
3182 +#include <linux/kernel.h>
3183 +#include <linux/init.h>
3184 +#include <linux/delay.h>
3185 +#include <linux/gpio.h>
3186 +#include <linux/gpio/consumer.h>
3187 +#include <linux/platform_device.h>
3188 +#include <linux/pm.h>
3189 +#include <linux/i2c.h>
3190 +#include <linux/of_device.h>
3191 +#include <linux/regmap.h>
3192 +#include <linux/slab.h>
3193 +#include <sound/core.h>
3194 +#include <sound/pcm.h>
3195 +#include <sound/pcm_params.h>
3196 +#include <sound/soc.h>
3197 +#include <sound/soc-dapm.h>
3198 +#include <sound/initval.h>
3199 +#include <sound/tlv.h>
3200 +#include <linux/of_gpio.h>
3201 +#include <linux/regulator/consumer.h>
3202 +#include <linux/pm_runtime.h>
3203 +#include <linux/of_irq.h>
3204 +#include <linux/completion.h>
3205 +#include <linux/mutex.h>
3206 +#include <linux/workqueue.h>
3207 +#include <sound/jack.h>
3209 +#include "../codecs/cs43130.h"
3211 +#include <linux/clk.h>
3212 +#include <linux/gcd.h>
3215 +#define CS43130_DSD_EN_MASK 0x10
3216 +#define CS43130_PDN_DONE_INT_MASK 0x00
3218 +static struct gpio_desc *snd_allo_clk44gpio;
3219 +static struct gpio_desc *snd_allo_clk48gpio;
3221 +struct cs43130_priv {
3222 + struct snd_soc_component *component;
3223 + struct regmap *regmap;
3224 + struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES];
3225 + struct gpio_desc *reset_gpio;
3226 + unsigned int dev_id; /* codec device ID */
3228 + /* shared by both DAIs */
3229 + struct mutex clk_mutex;
3232 + struct completion xtal_rdy;
3233 + struct completion pll_rdy;
3234 + unsigned int mclk;
3235 + unsigned int mclk_int;
3238 + /* DAI specific */
3239 + struct cs43130_dai dais[CS43130_DAI_ID_MAX];
3241 + /* HP load specific */
3245 + struct completion hpload_evt;
3246 + unsigned int hpload_stat;
3248 + u16 dc_threshold[CS43130_DC_THRESHOLD];
3249 + u16 ac_freq[CS43130_AC_FREQ];
3250 + u16 hpload_ac[CS43130_AC_FREQ][2];
3251 + struct workqueue_struct *wq;
3252 + struct work_struct work;
3253 + struct snd_soc_jack jack;
3256 +static const struct reg_default cs43130_reg_defaults[] = {
3257 + {CS43130_SYS_CLK_CTL_1, 0x06},
3258 + {CS43130_SP_SRATE, 0x01},
3259 + {CS43130_SP_BITSIZE, 0x05},
3260 + {CS43130_PAD_INT_CFG, 0x03},
3261 + {CS43130_PWDN_CTL, 0xFE},
3262 + {CS43130_CRYSTAL_SET, 0x04},
3263 + {CS43130_PLL_SET_1, 0x00},
3264 + {CS43130_PLL_SET_2, 0x00},
3265 + {CS43130_PLL_SET_3, 0x00},
3266 + {CS43130_PLL_SET_4, 0x00},
3267 + {CS43130_PLL_SET_5, 0x40},
3268 + {CS43130_PLL_SET_6, 0x10},
3269 + {CS43130_PLL_SET_7, 0x80},
3270 + {CS43130_PLL_SET_8, 0x03},
3271 + {CS43130_PLL_SET_9, 0x02},
3272 + {CS43130_PLL_SET_10, 0x02},
3273 + {CS43130_CLKOUT_CTL, 0x00},
3274 + {CS43130_ASP_NUM_1, 0x01},
3275 + {CS43130_ASP_NUM_2, 0x00},
3276 + {CS43130_ASP_DEN_1, 0x08},
3277 + {CS43130_ASP_DEN_2, 0x00},
3278 + {CS43130_ASP_LRCK_HI_TIME_1, 0x1F},
3279 + {CS43130_ASP_LRCK_HI_TIME_2, 0x00},
3280 + {CS43130_ASP_LRCK_PERIOD_1, 0x3F},
3281 + {CS43130_ASP_LRCK_PERIOD_2, 0x00},
3282 + {CS43130_ASP_CLOCK_CONF, 0x0C},
3283 + {CS43130_ASP_FRAME_CONF, 0x0A},
3284 + {CS43130_XSP_NUM_1, 0x01},
3285 + {CS43130_XSP_NUM_2, 0x00},
3286 + {CS43130_XSP_DEN_1, 0x02},
3287 + {CS43130_XSP_DEN_2, 0x00},
3288 + {CS43130_XSP_LRCK_HI_TIME_1, 0x1F},
3289 + {CS43130_XSP_LRCK_HI_TIME_2, 0x00},
3290 + {CS43130_XSP_LRCK_PERIOD_1, 0x3F},
3291 + {CS43130_XSP_LRCK_PERIOD_2, 0x00},
3292 + {CS43130_XSP_CLOCK_CONF, 0x0C},
3293 + {CS43130_XSP_FRAME_CONF, 0x0A},
3294 + {CS43130_ASP_CH_1_LOC, 0x00},
3295 + {CS43130_ASP_CH_2_LOC, 0x00},
3296 + {CS43130_ASP_CH_1_SZ_EN, 0x06},
3297 + {CS43130_ASP_CH_2_SZ_EN, 0x0E},
3298 + {CS43130_XSP_CH_1_LOC, 0x00},
3299 + {CS43130_XSP_CH_2_LOC, 0x00},
3300 + {CS43130_XSP_CH_1_SZ_EN, 0x06},
3301 + {CS43130_XSP_CH_2_SZ_EN, 0x0E},
3302 + {CS43130_DSD_VOL_B, 0x78},
3303 + {CS43130_DSD_VOL_A, 0x78},
3304 + {CS43130_DSD_PATH_CTL_1, 0xA8},
3305 + {CS43130_DSD_INT_CFG, 0x00},
3306 + {CS43130_DSD_PATH_CTL_2, 0x02},
3307 + {CS43130_DSD_PCM_MIX_CTL, 0x00},
3308 + {CS43130_DSD_PATH_CTL_3, 0x40},
3309 + {CS43130_HP_OUT_CTL_1, 0x30},
3310 + {CS43130_PCM_FILT_OPT, 0x02},
3311 + {CS43130_PCM_VOL_B, 0x78},
3312 + {CS43130_PCM_VOL_A, 0x78},
3313 + {CS43130_PCM_PATH_CTL_1, 0xA8},
3314 + {CS43130_PCM_PATH_CTL_2, 0x00},
3315 + {CS43130_CLASS_H_CTL, 0x1E},
3316 + {CS43130_HP_DETECT, 0x04},
3317 + {CS43130_HP_LOAD_1, 0x00},
3318 + {CS43130_HP_MEAS_LOAD_1, 0x00},
3319 + {CS43130_HP_MEAS_LOAD_2, 0x00},
3320 + {CS43130_INT_MASK_1, 0xFF},
3321 + {CS43130_INT_MASK_2, 0xFF},
3322 + {CS43130_INT_MASK_3, 0xFF},
3323 + {CS43130_INT_MASK_4, 0xFF},
3324 + {CS43130_INT_MASK_5, 0xFF},
3326 +static bool cs43130_volatile_register(struct device *dev, unsigned int reg)
3329 + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
3330 + case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2:
3331 + case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2:
3338 +static const char * const pcm_spd_texts[] = {
3343 +static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7,
3346 +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12750, 0);
3348 +static const struct snd_kcontrol_new cs43130_controls[] = {
3349 + SOC_DOUBLE_R_TLV("Master Playback Volume", CS43130_PCM_VOL_B,
3350 + CS43130_PCM_VOL_A, 0, 255, 1, master_tlv),
3351 + SOC_DOUBLE("Master Playback Switch", CS43130_PCM_PATH_CTL_1,
3353 + SOC_DOUBLE_R_TLV("Digital Playback Volume", CS43130_DSD_VOL_B,
3354 + CS43130_DSD_VOL_A, 0, 255, 1, master_tlv),
3355 + SOC_DOUBLE("Digital Playback Switch", CS43130_DSD_PATH_CTL_1,
3357 + SOC_SINGLE("HV_Enable", CS43130_HP_OUT_CTL_1, 0, 1, 0),
3358 + SOC_ENUM("PCM Filter Speed", pcm_spd_enum),
3359 + SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0),
3360 + SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0),
3361 + SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0),
3362 + SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0),
3365 +static bool cs43130_readable_register(struct device *dev, unsigned int reg)
3368 + case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1:
3369 + case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG:
3370 + case CS43130_PWDN_CTL:
3371 + case CS43130_CRYSTAL_SET:
3372 + case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5:
3373 + case CS43130_PLL_SET_6:
3374 + case CS43130_PLL_SET_7:
3375 + case CS43130_PLL_SET_8:
3376 + case CS43130_PLL_SET_9:
3377 + case CS43130_PLL_SET_10:
3378 + case CS43130_CLKOUT_CTL:
3379 + case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF:
3380 + case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF:
3381 + case CS43130_ASP_CH_1_LOC:
3382 + case CS43130_ASP_CH_2_LOC:
3383 + case CS43130_ASP_CH_1_SZ_EN:
3384 + case CS43130_ASP_CH_2_SZ_EN:
3385 + case CS43130_XSP_CH_1_LOC:
3386 + case CS43130_XSP_CH_2_LOC:
3387 + case CS43130_XSP_CH_1_SZ_EN:
3388 + case CS43130_XSP_CH_2_SZ_EN:
3389 + case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3:
3390 + case CS43130_HP_OUT_CTL_1:
3391 + case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2:
3392 + case CS43130_CLASS_H_CTL:
3393 + case CS43130_HP_DETECT:
3394 + case CS43130_HP_STATUS:
3395 + case CS43130_HP_LOAD_1:
3396 + case CS43130_HP_MEAS_LOAD_1:
3397 + case CS43130_HP_MEAS_LOAD_2:
3398 + case CS43130_HP_DC_STAT_1:
3399 + case CS43130_HP_DC_STAT_2:
3400 + case CS43130_HP_AC_STAT_1:
3401 + case CS43130_HP_AC_STAT_2:
3402 + case CS43130_HP_LOAD_STAT:
3403 + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
3404 + case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5:
3410 +static bool cs43130_precious_register(struct device *dev, unsigned int reg)
3413 + case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
3419 +static int cs43130_pcm_pdn(struct snd_soc_component *component)
3421 + struct cs43130_priv *cs43130 =
3422 + snd_soc_component_get_drvdata(component);
3424 + unsigned int reg, pdn_int;
3426 + regmap_write(cs43130->regmap, CS43130_DSD_PATH_CTL_2, 0x02);
3427 + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
3428 + CS43130_PDN_DONE_INT_MASK, 0);
3429 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3430 + CS43130_PDN_HP_MASK, 1 << CS43130_PDN_HP_SHIFT);
3431 + usleep_range(10, 50);
3432 + ret = regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, ®);
3433 + pdn_int = reg & 0xFE;
3434 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3435 + CS43130_PDN_ASP_MASK, 1 << CS43130_PDN_ASP_SHIFT);
3439 +static int cs43130_pwr_up_asp_dac(struct snd_soc_component *component)
3441 + struct cs43130_priv *cs43130 =
3442 + snd_soc_component_get_drvdata(component);
3444 + regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
3445 + CS43130_ASP_3ST_MASK, 0);
3446 + regmap_write(cs43130->regmap, CS43130_DXD1, 0x99);
3447 + regmap_write(cs43130->regmap, CS43130_DXD13, 0x20);
3448 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3449 + CS43130_PDN_ASP_MASK, 0);
3450 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3451 + CS43130_PDN_HP_MASK, 0);
3452 + usleep_range(10000, 12000);
3453 + regmap_write(cs43130->regmap, CS43130_DXD1, 0x00);
3454 + regmap_write(cs43130->regmap, CS43130_DXD13, 0x00);
3457 +static int cs43130_change_clksrc(struct snd_soc_component *component,
3458 + enum cs43130_mclk_src_sel src)
3461 + struct cs43130_priv *cs43130 =
3462 + snd_soc_component_get_drvdata(component);
3463 + int mclk_int_decoded;
3465 + if (src == cs43130->mclk_int_src) {
3466 + /* clk source has not changed */
3469 + switch (cs43130->mclk_int) {
3470 + case CS43130_MCLK_22M:
3471 + mclk_int_decoded = CS43130_MCLK_22P5;
3473 + case CS43130_MCLK_24M:
3474 + mclk_int_decoded = CS43130_MCLK_24P5;
3477 + dev_err(component->dev, "Invalid MCLK INT freq: %u\n",
3478 + cs43130->mclk_int);
3483 + case CS43130_MCLK_SRC_EXT:
3484 + cs43130->pll_bypass = true;
3485 + cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT;
3486 + if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
3487 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3488 + CS43130_PDN_XTAL_MASK,
3489 + 1 << CS43130_PDN_XTAL_SHIFT);
3491 + reinit_completion(&cs43130->xtal_rdy);
3492 + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
3493 + CS43130_XTAL_RDY_INT_MASK, 0);
3494 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3495 + CS43130_PDN_XTAL_MASK, 0);
3496 + ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
3497 + msecs_to_jiffies(100));
3498 + regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
3499 + CS43130_XTAL_RDY_INT_MASK,
3500 + 1 << CS43130_XTAL_RDY_INT_SHIFT);
3502 + dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
3503 + return -ETIMEDOUT;
3506 + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
3507 + CS43130_MCLK_SRC_SEL_MASK,
3508 + src << CS43130_MCLK_SRC_SEL_SHIFT);
3509 + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
3510 + CS43130_MCLK_INT_MASK,
3511 + mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
3512 + usleep_range(150, 200);
3513 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3514 + CS43130_PDN_PLL_MASK,
3515 + 1 << CS43130_PDN_PLL_SHIFT);
3517 + case CS43130_MCLK_SRC_RCO:
3518 + cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
3520 + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
3521 + CS43130_MCLK_SRC_SEL_MASK,
3522 + src << CS43130_MCLK_SRC_SEL_SHIFT);
3523 + regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
3524 + CS43130_MCLK_INT_MASK,
3525 + CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT);
3526 + usleep_range(150, 200);
3527 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3528 + CS43130_PDN_XTAL_MASK,
3529 + 1 << CS43130_PDN_XTAL_SHIFT);
3530 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
3531 + CS43130_PDN_PLL_MASK,
3532 + 1 << CS43130_PDN_PLL_SHIFT);
3535 + dev_err(component->dev, "Invalid MCLK source value\n");
3541 +static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = {
3542 + {8, CS43130_SP_BIT_SIZE_8, CS43130_CH_BIT_SIZE_8},
3543 + {16, CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16},
3544 + {24, CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24},
3545 + {32, CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32},
3548 +static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table(
3549 + unsigned int bitwidth)
3553 + for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) {
3554 + if (cs43130_bitwidth_table[i].bitwidth == bitwidth)
3555 + return &cs43130_bitwidth_table[i];
3560 +static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai,
3561 + struct regmap *regmap)
3563 + const struct cs43130_bitwidth_map *bw_map;
3565 + bw_map = cs43130_get_bitwidth_table(bitwidth_dai);
3570 + case CS43130_ASP_PCM_DAI:
3571 + case CS43130_ASP_DOP_DAI:
3572 + regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN,
3573 + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
3574 + regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN,
3575 + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
3576 + regmap_update_bits(regmap, CS43130_SP_BITSIZE,
3577 + CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit);
3579 + case CS43130_XSP_DOP_DAI:
3580 + regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN,
3581 + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
3582 + regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN,
3583 + CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
3584 + regmap_update_bits(regmap, CS43130_SP_BITSIZE,
3585 + CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit <<
3586 + CS43130_XSP_BITSIZE_SHIFT);
3594 +static const struct cs43130_rate_map cs43130_rate_table[] = {
3595 + {32000, CS43130_ASP_SPRATE_32K},
3596 + {44100, CS43130_ASP_SPRATE_44_1K},
3597 + {48000, CS43130_ASP_SPRATE_48K},
3598 + {88200, CS43130_ASP_SPRATE_88_2K},
3599 + {96000, CS43130_ASP_SPRATE_96K},
3600 + {176400, CS43130_ASP_SPRATE_176_4K},
3601 + {192000, CS43130_ASP_SPRATE_192K},
3602 + {352800, CS43130_ASP_SPRATE_352_8K},
3603 + {384000, CS43130_ASP_SPRATE_384K},
3606 +static const struct cs43130_rate_map *cs43130_get_rate_table(int fs)
3610 + for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) {
3611 + if (cs43130_rate_table[i].fs == fs)
3612 + return &cs43130_rate_table[i];
3618 +static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs,
3619 + const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table)
3623 + for (i = 0; i < len_clk_gen_table; i++) {
3624 + if (clk_gen_table[i].mclk_int == mclk_int &&
3625 + clk_gen_table[i].fs == fs)
3626 + return &clk_gen_table[i];
3631 +static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
3632 + struct snd_pcm_hw_params *params,
3633 + struct cs43130_priv *cs43130)
3646 + const struct cs43130_clk_gen *clk_gen;
3648 + switch (cs43130->dais[dai_id].dai_format) {
3649 + case SND_SOC_DAIFMT_I2S:
3650 + hi_size = bitwidth_sclk;
3654 + case SND_SOC_DAIFMT_LEFT_J:
3655 + hi_size = bitwidth_sclk;
3659 + case SND_SOC_DAIFMT_DSP_A:
3664 + case SND_SOC_DAIFMT_DSP_B:
3672 + switch (cs43130->dais[dai_id].dai_mode) {
3673 + case SND_SOC_DAIFMT_CBS_CFS:
3676 + case SND_SOC_DAIFMT_CBM_CFM:
3683 + frm_size = bitwidth_sclk * params_channels(params);
3687 + loc_ch2 = bitwidth_sclk * (params_channels(params) - 1);
3689 + frm_data = frm_delay & CS43130_SP_FSD_MASK;
3690 + frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK;
3692 + clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK;
3693 + clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) &
3694 + CS43130_SP_LCPOL_OUT_MASK;
3695 + clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) &
3696 + CS43130_SP_SCPOL_IN_MASK;
3697 + clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) &
3698 + CS43130_SP_SCPOL_OUT_MASK;
3699 + clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) &
3700 + CS43130_SP_MODE_MASK;
3702 + case CS43130_ASP_PCM_DAI:
3703 + case CS43130_ASP_DOP_DAI:
3704 + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1,
3705 + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
3706 + CS43130_SP_LCPR_LSB_DATA_SHIFT);
3707 + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2,
3708 + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
3709 + CS43130_SP_LCPR_MSB_DATA_SHIFT);
3710 + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1,
3711 + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
3712 + CS43130_SP_LCHI_LSB_DATA_SHIFT);
3713 + regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2,
3714 + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
3715 + CS43130_SP_LCHI_MSB_DATA_SHIFT);
3716 + regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data);
3717 + regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1);
3718 + regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2);
3719 + regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN,
3720 + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
3721 + regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN,
3722 + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
3723 + regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data);
3725 + case CS43130_XSP_DOP_DAI:
3726 + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1,
3727 + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
3728 + CS43130_SP_LCPR_LSB_DATA_SHIFT);
3729 + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2,
3730 + CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
3731 + CS43130_SP_LCPR_MSB_DATA_SHIFT);
3732 + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1,
3733 + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
3734 + CS43130_SP_LCHI_LSB_DATA_SHIFT);
3735 + regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2,
3736 + CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
3737 + CS43130_SP_LCHI_MSB_DATA_SHIFT);
3738 + regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data);
3739 + regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1);
3740 + regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2);
3741 + regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN,
3742 + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
3743 + regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN,
3744 + CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
3745 + regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data);
3750 + switch (frm_size) {
3752 + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
3753 + params_rate(params),
3754 + cs43130_16_clk_gen,
3755 + ARRAY_SIZE(cs43130_16_clk_gen));
3758 + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
3759 + params_rate(params),
3760 + cs43130_32_clk_gen,
3761 + ARRAY_SIZE(cs43130_32_clk_gen));
3764 + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
3765 + params_rate(params),
3766 + cs43130_48_clk_gen,
3767 + ARRAY_SIZE(cs43130_48_clk_gen));
3770 + clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
3771 + params_rate(params),
3772 + cs43130_64_clk_gen,
3773 + ARRAY_SIZE(cs43130_64_clk_gen));
3781 + case CS43130_ASP_PCM_DAI:
3782 + case CS43130_ASP_DOP_DAI:
3783 + regmap_write(cs43130->regmap, CS43130_ASP_DEN_1,
3784 + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >>
3785 + CS43130_SP_M_LSB_DATA_SHIFT);
3786 + regmap_write(cs43130->regmap, CS43130_ASP_DEN_2,
3787 + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >>
3788 + CS43130_SP_M_MSB_DATA_SHIFT);
3789 + regmap_write(cs43130->regmap, CS43130_ASP_NUM_1,
3790 + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >>
3791 + CS43130_SP_N_LSB_DATA_SHIFT);
3792 + regmap_write(cs43130->regmap, CS43130_ASP_NUM_2,
3793 + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >>
3794 + CS43130_SP_N_MSB_DATA_SHIFT);
3796 + case CS43130_XSP_DOP_DAI:
3797 + regmap_write(cs43130->regmap, CS43130_XSP_DEN_1,
3798 + (clk_gen->v.denominator & CS43130_SP_M_LSB_DATA_MASK) >>
3799 + CS43130_SP_M_LSB_DATA_SHIFT);
3800 + regmap_write(cs43130->regmap, CS43130_XSP_DEN_2,
3801 + (clk_gen->v.denominator & CS43130_SP_M_MSB_DATA_MASK) >>
3802 + CS43130_SP_M_MSB_DATA_SHIFT);
3803 + regmap_write(cs43130->regmap, CS43130_XSP_NUM_1,
3804 + (clk_gen->v.numerator & CS43130_SP_N_LSB_DATA_MASK) >>
3805 + CS43130_SP_N_LSB_DATA_SHIFT);
3806 + regmap_write(cs43130->regmap, CS43130_XSP_NUM_2,
3807 + (clk_gen->v.numerator & CS43130_SP_N_MSB_DATA_MASK) >>
3808 + CS43130_SP_N_MSB_DATA_SHIFT);
3816 +static int cs43130_hw_params(struct snd_pcm_substream *substream,
3817 + struct snd_pcm_hw_params *params,
3818 + struct snd_soc_dai *dai)
3820 + struct snd_soc_component *component = dai->component;
3821 + struct cs43130_priv *cs43130 =
3822 + snd_soc_component_get_drvdata(component);
3823 + const struct cs43130_rate_map *rate_map;
3824 + unsigned int sclk = cs43130->dais[dai->id].sclk;
3825 + unsigned int bitwidth_sclk;
3826 + unsigned int bitwidth_dai = (unsigned int)(params_width(params));
3827 + unsigned int dop_rate = (unsigned int)(params_rate(params));
3828 + unsigned int required_clk, ret;
3831 + cs43130->pll_bypass = true;
3832 + cs43130_pcm_pdn(component);
3833 + mutex_lock(&cs43130->clk_mutex);
3834 + if (!cs43130->clk_req) {
3835 + /* no DAI is currently using clk */
3836 + if (!(CS43130_MCLK_22M % params_rate(params))) {
3837 + required_clk = CS43130_MCLK_22M;
3838 + cs43130->mclk_int = CS43130_MCLK_22M;
3839 + gpiod_set_value_cansleep(snd_allo_clk44gpio, 1);
3840 + gpiod_set_value_cansleep(snd_allo_clk48gpio, 0);
3841 + usleep_range(13500, 14000);
3843 + required_clk = CS43130_MCLK_24M;
3844 + cs43130->mclk_int = CS43130_MCLK_24M;
3845 + gpiod_set_value_cansleep(snd_allo_clk48gpio, 1);
3846 + gpiod_set_value_cansleep(snd_allo_clk44gpio, 0);
3847 + usleep_range(13500, 14000);
3849 + if (cs43130->pll_bypass)
3850 + cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
3852 + cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
3855 + cs43130->clk_req++;
3856 + mutex_unlock(&cs43130->clk_mutex);
3858 + switch (dai->id) {
3859 + case CS43130_ASP_DOP_DAI:
3860 + case CS43130_XSP_DOP_DAI:
3861 + /* DoP bitwidth is always 24-bit */
3862 + bitwidth_dai = 24;
3863 + sclk = params_rate(params) * bitwidth_dai *
3864 + params_channels(params);
3866 + switch (params_rate(params)) {
3874 + dev_err(component->dev, "Rate(%u) not supported\n",
3875 + params_rate(params));
3879 + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
3880 + CS43130_DSD_SPEED_MASK,
3881 + dsd_speed << CS43130_DSD_SPEED_SHIFT);
3883 + case CS43130_ASP_PCM_DAI:
3884 + rate_map = cs43130_get_rate_table(params_rate(params));
3888 + regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
3889 + if ((dop_rate == 176400) && (bitwidth_dai == 24)) {
3891 + regmap_update_bits(cs43130->regmap,
3892 + CS43130_DSD_PATH_CTL_2,
3893 + CS43130_DSD_SPEED_MASK,
3894 + dsd_speed << CS43130_DSD_SPEED_SHIFT);
3895 + regmap_update_bits(cs43130->regmap,
3896 + CS43130_DSD_PATH_CTL_2,
3897 + CS43130_DSD_SRC_MASK,
3898 + CS43130_DSD_SRC_ASP <<
3899 + CS43130_DSD_SRC_SHIFT);
3900 + regmap_update_bits(cs43130->regmap,
3901 + CS43130_DSD_PATH_CTL_2,
3902 + CS43130_DSD_EN_MASK, 0x01 <<
3903 + CS43130_DSD_EN_SHIFT);
3907 + dev_err(component->dev, "Invalid DAI (%d)\n", dai->id);
3911 + switch (dai->id) {
3912 + case CS43130_ASP_DOP_DAI:
3913 + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
3914 + CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP <<
3915 + CS43130_DSD_SRC_SHIFT);
3916 + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
3917 + CS43130_DSD_EN_MASK, 0x01 <<
3918 + CS43130_DSD_EN_SHIFT);
3920 + case CS43130_XSP_DOP_DAI:
3921 + regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
3922 + CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP <<
3923 + CS43130_DSD_SRC_SHIFT);
3926 + if (!sclk && cs43130->dais[dai->id].dai_mode ==
3927 + SND_SOC_DAIFMT_CBM_CFM) {
3928 + /* Calculate SCLK in master mode if unassigned */
3929 + sclk = params_rate(params) * bitwidth_dai *
3930 + params_channels(params);
3933 + /* at this point, SCLK must be set */
3934 + dev_err(component->dev, "SCLK freq is not set\n");
3938 + bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
3939 + if (bitwidth_sclk < bitwidth_dai) {
3940 + dev_err(component->dev, "Format not supported: SCLK freq is too low\n");
3944 + dev_dbg(component->dev,
3945 + "sclk = %u, fs = %d, bitwidth_dai = %u\n",
3946 + sclk, params_rate(params), bitwidth_dai);
3948 + dev_dbg(component->dev,
3949 + "bitwidth_sclk = %u, num_ch = %u\n",
3950 + bitwidth_sclk, params_channels(params));
3952 + cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap);
3953 + cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130);
3954 + ret = cs43130_pwr_up_asp_dac(component);
3958 +static int cs43130_hw_free(struct snd_pcm_substream *substream,
3959 + struct snd_soc_dai *dai)
3961 + struct snd_soc_component *component = dai->component;
3962 + struct cs43130_priv *cs43130 =
3963 + snd_soc_component_get_drvdata(component);
3965 + mutex_lock(&cs43130->clk_mutex);
3966 + cs43130->clk_req--;
3967 + if (!cs43130->clk_req) {
3968 + /* no DAI is currently using clk */
3969 + cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
3970 + cs43130_pcm_pdn(component);
3972 + mutex_unlock(&cs43130->clk_mutex);
3977 +static const unsigned int cs43130_asp_src_rates[] = {
3978 + 32000, 44100, 48000, 88200, 96000, 176400, 192000
3981 +static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = {
3982 + .count = ARRAY_SIZE(cs43130_asp_src_rates),
3983 + .list = cs43130_asp_src_rates,
3986 +static int cs43130_pcm_startup(struct snd_pcm_substream *substream,
3987 + struct snd_soc_dai *dai)
3989 + return snd_pcm_hw_constraint_list(substream->runtime, 0,
3990 + SNDRV_PCM_HW_PARAM_RATE,
3991 + &cs43130_asp_constraints);
3994 +static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
3996 + struct snd_soc_component *component = codec_dai->component;
3997 + struct cs43130_priv *cs43130 =
3998 + snd_soc_component_get_drvdata(component);
4000 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
4001 + case SND_SOC_DAIFMT_CBS_CFS:
4002 + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
4004 + case SND_SOC_DAIFMT_CBM_CFM:
4005 + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
4008 + dev_err(component->dev, "unsupported mode\n");
4012 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
4013 + case SND_SOC_DAIFMT_I2S:
4014 + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S;
4016 + case SND_SOC_DAIFMT_LEFT_J:
4017 + cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J;
4020 + dev_err(component->dev,
4021 + "unsupported audio format\n");
4025 + dev_dbg(component->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n",
4027 + cs43130->dais[codec_dai->id].dai_mode,
4028 + cs43130->dais[codec_dai->id].dai_format);
4033 +static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
4034 + int clk_id, unsigned int freq, int dir)
4036 + struct snd_soc_component *component = codec_dai->component;
4037 + struct cs43130_priv *cs43130 =
4038 + snd_soc_component_get_drvdata(component);
4040 + cs43130->dais[codec_dai->id].sclk = freq;
4041 + dev_dbg(component->dev, "dai_id = %d, sclk = %u\n", codec_dai->id,
4042 + cs43130->dais[codec_dai->id].sclk);
4047 +static int cs43130_component_set_sysclk(struct snd_soc_component *component,
4048 + int clk_id, int source,
4049 + unsigned int freq, int dir)
4051 + struct cs43130_priv *cs43130 =
4052 + snd_soc_component_get_drvdata(component);
4054 + dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
4055 + clk_id, source, freq, dir);
4058 + case CS43130_MCLK_22M:
4059 + case CS43130_MCLK_24M:
4060 + cs43130->mclk = freq;
4063 + dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq);
4067 + if (source == CS43130_MCLK_SRC_EXT) {
4068 + cs43130->pll_bypass = true;
4070 + dev_err(component->dev, "Invalid MCLK source\n");
4076 +static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
4088 +static const struct snd_soc_dai_ops cs43130_dai_ops = {
4089 + .startup = cs43130_pcm_startup,
4090 + .hw_params = cs43130_hw_params,
4091 + .hw_free = cs43130_hw_free,
4092 + .set_sysclk = cs43130_set_sysclk,
4093 + .set_fmt = cs43130_pcm_set_fmt,
4096 +static struct snd_soc_dai_driver cs43130_codec_dai = {
4097 + .name = "allo-cs43130",
4099 + .stream_name = "Playback",
4100 + .channels_min = 2,
4101 + .channels_max = 2,
4102 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
4103 + .rate_min = 44100,
4104 + .rate_max = 192000,
4105 + .formats = SNDRV_PCM_FMTBIT_S16_LE |
4106 + SNDRV_PCM_FMTBIT_S24_LE |
4107 + SNDRV_PCM_FMTBIT_S32_LE
4110 + .ops = &cs43130_dai_ops,
4113 +static struct snd_soc_component_driver cs43130_component_driver = {
4114 + .idle_bias_on = true,
4115 + .controls = cs43130_controls,
4116 + .num_controls = ARRAY_SIZE(cs43130_controls),
4117 + .set_sysclk = cs43130_component_set_sysclk,
4118 + .idle_bias_on = 1,
4119 + .use_pmdown_time = 1,
4123 +static const struct regmap_config cs43130_regmap = {
4128 + .max_register = CS43130_LASTREG,
4129 + .reg_defaults = cs43130_reg_defaults,
4130 + .num_reg_defaults = ARRAY_SIZE(cs43130_reg_defaults),
4131 + .readable_reg = cs43130_readable_register,
4132 + .precious_reg = cs43130_precious_register,
4133 + .volatile_reg = cs43130_volatile_register,
4134 + .cache_type = REGCACHE_RBTREE,
4135 + /* needed for regcache_sync */
4136 + .use_single_read = true,
4137 + .use_single_write = true,
4140 +static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
4145 +static int cs43130_handle_device_data(struct i2c_client *i2c_client,
4146 + struct cs43130_priv *cs43130)
4148 + struct device_node *np = i2c_client->dev.of_node;
4152 + if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) {
4153 + /* Crystal is unused. System clock is used for external MCLK */
4154 + cs43130->xtal_ibias = CS43130_XTAL_UNUSED;
4160 + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA;
4163 + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA;
4166 + cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA;
4169 + dev_err(&i2c_client->dev,
4170 + "Invalid cirrus,xtal-ibias value: %d\n", val);
4174 + cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure");
4175 + cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure");
4177 + if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq,
4178 + CS43130_AC_FREQ) < 0) {
4179 + for (i = 0; i < CS43130_AC_FREQ; i++)
4180 + cs43130->ac_freq[i] = cs43130_ac_freq[i];
4183 + if (of_property_read_u16_array(np, "cirrus,dc-threshold",
4184 + cs43130->dc_threshold,
4185 + CS43130_DC_THRESHOLD) < 0) {
4186 + for (i = 0; i < CS43130_DC_THRESHOLD; i++)
4187 + cs43130->dc_threshold[i] = cs43130_dc_threshold[i];
4194 +static int allo_cs43130_component_probe(struct i2c_client *i2c)
4196 + struct regmap *regmap;
4197 + struct regmap_config config = cs43130_regmap;
4198 + struct device *dev = &i2c->dev;
4199 + struct cs43130_priv *cs43130;
4200 + unsigned int devid = 0;
4204 + regmap = devm_regmap_init_i2c(i2c, &config);
4205 + if (IS_ERR(regmap))
4206 + return PTR_ERR(regmap);
4208 + cs43130 = devm_kzalloc(dev, sizeof(struct cs43130_priv),
4213 + dev_set_drvdata(dev, cs43130);
4214 + cs43130->regmap = regmap;
4216 + if (i2c->dev.of_node) {
4217 + ret = cs43130_handle_device_data(i2c, cs43130);
4221 + usleep_range(2000, 2050);
4223 + ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, ®);
4224 + devid = (reg & 0xFF) << 12;
4225 + ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, ®);
4226 + devid |= (reg & 0xFF) << 4;
4227 + ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, ®);
4228 + devid |= (reg & 0xF0) >> 4;
4229 + if (devid != CS43198_CHIP_ID) {
4230 + dev_err(dev, "Failed to read Chip or wrong Chip id: %d\n", ret);
4234 + cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
4237 + ret = snd_soc_register_component(dev, &cs43130_component_driver,
4238 + &cs43130_codec_dai, 1);
4240 + dev_err(dev, "failed to register codec: %d\n", ret);
4243 + regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
4244 + CS43130_ASP_3ST_MASK, 0);
4245 + regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
4246 + CS43130_XSP_3ST_MASK, 1);
4247 + regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
4248 + CS43130_PDN_HP_MASK, 1 << CS43130_PDN_HP_SHIFT);
4250 + regmap_write(cs43130->regmap, CS43130_CLASS_H_CTL, 0x06);
4251 + snd_allo_clk44gpio = devm_gpiod_get(dev, "clock44", GPIOD_OUT_HIGH);
4252 + if (IS_ERR(snd_allo_clk44gpio))
4253 + dev_err(dev, "devm_gpiod_get() failed\n");
4255 + snd_allo_clk48gpio = devm_gpiod_get(dev, "clock48", GPIOD_OUT_LOW);
4256 + if (IS_ERR(snd_allo_clk48gpio))
4257 + dev_err(dev, "devm_gpiod_get() failed\n");
4262 +static void allo_cs43130_component_remove(struct i2c_client *i2c)
4264 + snd_soc_unregister_component(&i2c->dev);
4267 +static const struct i2c_device_id allo_cs43130_component_id[] = {
4268 + { "allo-cs43198", },
4271 +MODULE_DEVICE_TABLE(i2c, allo_cs43130_component_id);
4273 +static const struct of_device_id allo_cs43130_codec_of_match[] = {
4274 + { .compatible = "allo,allo-cs43198", },
4277 +MODULE_DEVICE_TABLE(of, allo_cs43130_codec_of_match);
4279 +static struct i2c_driver allo_cs43130_component_driver = {
4280 + .probe = allo_cs43130_component_probe,
4281 + .remove = allo_cs43130_component_remove,
4282 + .id_table = allo_cs43130_component_id,
4284 + .name = "allo-cs43198",
4285 + .of_match_table = allo_cs43130_codec_of_match,
4289 +module_i2c_driver(allo_cs43130_component_driver);
4291 +MODULE_DESCRIPTION("ASoC Allo Boss2 Codec Driver");
4292 +MODULE_AUTHOR("Sudeepkumar <sudeepkumar@cem-solutions.net>");
4293 +MODULE_LICENSE("GPL v2");
4295 +++ b/sound/soc/bcm/allo-katana-codec.c
4298 + * Driver for the ALLO KATANA CODEC
4300 + * Author: Jaikumar <jaikumar@cem-solutions.net>
4303 + * This program is free software; you can redistribute it and/or
4304 + * modify it under the terms of the GNU General Public License
4305 + * version 2 as published by the Free Software Foundation.
4307 + * This program is distributed in the hope that it will be useful, but
4308 + * WITHOUT ANY WARRANTY; without even the implied warranty of
4309 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4310 + * General Public License for more details.
4314 +#include <linux/init.h>
4315 +#include <linux/module.h>
4316 +#include <linux/clk.h>
4317 +#include <linux/kernel.h>
4318 +#include <linux/regmap.h>
4319 +#include <linux/regulator/consumer.h>
4320 +#include <linux/gcd.h>
4321 +#include <sound/soc.h>
4322 +#include <sound/soc-dapm.h>
4323 +#include <sound/pcm_params.h>
4324 +#include <sound/tlv.h>
4325 +#include <linux/i2c.h>
4328 +#define KATANA_CODEC_CHIP_ID 0x30
4329 +#define KATANA_CODEC_VIRT_BASE 0x100
4330 +#define KATANA_CODEC_PAGE 0
4332 +#define KATANA_CODEC_CHIP_ID_REG (KATANA_CODEC_VIRT_BASE + 0)
4333 +#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
4334 +#define KATANA_CODEC_VOLUME_1 (KATANA_CODEC_VIRT_BASE + 2)
4335 +#define KATANA_CODEC_VOLUME_2 (KATANA_CODEC_VIRT_BASE + 3)
4336 +#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
4337 +#define KATANA_CODEC_DSP_PROGRAM (KATANA_CODEC_VIRT_BASE + 5)
4338 +#define KATANA_CODEC_DEEMPHASIS (KATANA_CODEC_VIRT_BASE + 6)
4339 +#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
4340 +#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
4341 +#define KATANA_CODEC_COMMAND (KATANA_CODEC_VIRT_BASE + 9)
4342 +#define KATANA_CODEC_MUTE_STREAM (KATANA_CODEC_VIRT_BASE + 10)
4344 +#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 10)
4346 +#define KATANA_CODEC_FMT 0xff
4347 +#define KATANA_CODEC_CHAN_MONO 0x00
4348 +#define KATANA_CODEC_CHAN_STEREO 0x80
4349 +#define KATANA_CODEC_ALEN_16 0x10
4350 +#define KATANA_CODEC_ALEN_24 0x20
4351 +#define KATANA_CODEC_ALEN_32 0x30
4352 +#define KATANA_CODEC_RATE_11025 0x01
4353 +#define KATANA_CODEC_RATE_22050 0x02
4354 +#define KATANA_CODEC_RATE_32000 0x03
4355 +#define KATANA_CODEC_RATE_44100 0x04
4356 +#define KATANA_CODEC_RATE_48000 0x05
4357 +#define KATANA_CODEC_RATE_88200 0x06
4358 +#define KATANA_CODEC_RATE_96000 0x07
4359 +#define KATANA_CODEC_RATE_176400 0x08
4360 +#define KATANA_CODEC_RATE_192000 0x09
4361 +#define KATANA_CODEC_RATE_352800 0x0a
4362 +#define KATANA_CODEC_RATE_384000 0x0b
4365 +struct katana_codec_priv {
4366 + struct regmap *regmap;
4370 +static const struct reg_default katana_codec_reg_defaults[] = {
4371 + { KATANA_CODEC_RESET, 0x00 },
4372 + { KATANA_CODEC_VOLUME_1, 0xF0 },
4373 + { KATANA_CODEC_VOLUME_2, 0xF0 },
4374 + { KATANA_CODEC_MUTE, 0x00 },
4375 + { KATANA_CODEC_DSP_PROGRAM, 0x04 },
4376 + { KATANA_CODEC_DEEMPHASIS, 0x00 },
4377 + { KATANA_CODEC_DOP, 0x00 },
4378 + { KATANA_CODEC_FORMAT, 0xb4 },
4381 +static const char * const katana_codec_dsp_program_texts[] = {
4382 + "Linear Phase Fast Roll-off Filter",
4383 + "Linear Phase Slow Roll-off Filter",
4384 + "Minimum Phase Fast Roll-off Filter",
4385 + "Minimum Phase Slow Roll-off Filter",
4386 + "Apodizing Fast Roll-off Filter",
4387 + "Corrected Minimum Phase Fast Roll-off Filter",
4388 + "Brick Wall Filter",
4391 +static const unsigned int katana_codec_dsp_program_values[] = {
4401 +static SOC_VALUE_ENUM_SINGLE_DECL(katana_codec_dsp_program,
4402 + KATANA_CODEC_DSP_PROGRAM, 0, 0x07,
4403 + katana_codec_dsp_program_texts,
4404 + katana_codec_dsp_program_values);
4406 +static const char * const katana_codec_deemphasis_texts[] = {
4413 +static const unsigned int katana_codec_deemphasis_values[] = {
4420 +static SOC_VALUE_ENUM_SINGLE_DECL(katana_codec_deemphasis,
4421 + KATANA_CODEC_DEEMPHASIS, 0, 0x03,
4422 + katana_codec_deemphasis_texts,
4423 + katana_codec_deemphasis_values);
4425 +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12750, 0);
4427 +static const struct snd_kcontrol_new katana_codec_controls[] = {
4428 + SOC_DOUBLE_R_TLV("Master Playback Volume", KATANA_CODEC_VOLUME_1,
4429 + KATANA_CODEC_VOLUME_2, 0, 255, 1, master_tlv),
4430 + SOC_DOUBLE("Master Playback Switch", KATANA_CODEC_MUTE, 0, 0, 1, 1),
4431 + SOC_ENUM("DSP Program Route", katana_codec_dsp_program),
4432 + SOC_ENUM("Deemphasis Route", katana_codec_deemphasis),
4433 + SOC_SINGLE("DoP Playback Switch", KATANA_CODEC_DOP, 0, 1, 1)
4436 +static bool katana_codec_readable_register(struct device *dev,
4440 + case KATANA_CODEC_CHIP_ID_REG:
4443 + return reg < 0xff;
4447 +static int katana_codec_hw_params(struct snd_pcm_substream *substream,
4448 + struct snd_pcm_hw_params *params,
4449 + struct snd_soc_dai *dai)
4451 + struct snd_soc_component *component = dai->component;
4452 + struct katana_codec_priv *katana_codec =
4453 + snd_soc_component_get_drvdata(component);
4457 + dev_dbg(component->card->dev, "hw_params %u Hz, %u channels, %u bits\n",
4458 + params_rate(params),
4459 + params_channels(params),
4460 + params_width(params));
4462 + switch (katana_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
4463 + case SND_SOC_DAIFMT_CBM_CFM: // master
4464 + if (params_channels(params) == 2)
4465 + fmt = KATANA_CODEC_CHAN_STEREO;
4467 + fmt = KATANA_CODEC_CHAN_MONO;
4469 + switch (params_width(params)) {
4471 + fmt |= KATANA_CODEC_ALEN_16;
4474 + fmt |= KATANA_CODEC_ALEN_24;
4477 + fmt |= KATANA_CODEC_ALEN_32;
4480 + dev_err(component->card->dev, "Bad frame size: %d\n",
4481 + params_width(params));
4485 + switch (params_rate(params)) {
4487 + fmt |= KATANA_CODEC_RATE_44100;
4490 + fmt |= KATANA_CODEC_RATE_48000;
4493 + fmt |= KATANA_CODEC_RATE_88200;
4496 + fmt |= KATANA_CODEC_RATE_96000;
4499 + fmt |= KATANA_CODEC_RATE_176400;
4502 + fmt |= KATANA_CODEC_RATE_192000;
4505 + fmt |= KATANA_CODEC_RATE_352800;
4508 + fmt |= KATANA_CODEC_RATE_384000;
4511 + dev_err(component->card->dev, "Bad sample rate: %d\n",
4512 + params_rate(params));
4516 + ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT,
4519 + dev_err(component->card->dev, "Failed to set format: %d\n", ret);
4524 + case SND_SOC_DAIFMT_CBS_CFS:
4534 +static int katana_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
4536 + struct snd_soc_component *component = dai->component;
4537 + struct katana_codec_priv *katana_codec =
4538 + snd_soc_component_get_drvdata(component);
4540 + katana_codec->fmt = fmt;
4545 +static int katana_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute,
4548 + struct snd_soc_component *component = dai->component;
4549 + struct katana_codec_priv *katana_codec =
4550 + snd_soc_component_get_drvdata(component);
4553 + ret = regmap_write(katana_codec->regmap, KATANA_CODEC_MUTE_STREAM,
4556 + dev_err(component->card->dev, "Failed to set mute: %d\n", ret);
4562 +static const struct snd_soc_dai_ops katana_codec_dai_ops = {
4563 + .mute_stream = katana_codec_dai_mute_stream,
4564 + .hw_params = katana_codec_hw_params,
4565 + .set_fmt = katana_codec_set_fmt,
4568 +static struct snd_soc_dai_driver katana_codec_dai = {
4569 + .name = "allo-katana-codec",
4571 + .stream_name = "Playback",
4572 + .channels_min = 2,
4573 + .channels_max = 2,
4574 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
4575 + .rate_min = 44100,
4576 + .rate_max = 384000,
4577 + .formats = SNDRV_PCM_FMTBIT_S16_LE |
4578 + SNDRV_PCM_FMTBIT_S32_LE
4580 + .ops = &katana_codec_dai_ops,
4583 +static struct snd_soc_component_driver katana_codec_component_driver = {
4584 + .idle_bias_on = true,
4586 + .controls = katana_codec_controls,
4587 + .num_controls = ARRAY_SIZE(katana_codec_controls),
4590 +static const struct regmap_range_cfg katana_codec_range = {
4591 + .name = "Pages", .range_min = KATANA_CODEC_VIRT_BASE,
4592 + .range_max = KATANA_CODEC_MAX_REGISTER,
4593 + .selector_reg = KATANA_CODEC_PAGE,
4594 + .selector_mask = 0xff,
4595 + .window_start = 0, .window_len = 0x100,
4598 +const struct regmap_config katana_codec_regmap = {
4602 + .ranges = &katana_codec_range,
4605 + .max_register = KATANA_CODEC_MAX_REGISTER,
4606 + .readable_reg = katana_codec_readable_register,
4607 + .reg_defaults = katana_codec_reg_defaults,
4608 + .num_reg_defaults = ARRAY_SIZE(katana_codec_reg_defaults),
4609 + .cache_type = REGCACHE_RBTREE,
4612 +static int allo_katana_component_probe(struct i2c_client *i2c)
4614 + struct regmap *regmap;
4615 + struct regmap_config config = katana_codec_regmap;
4616 + struct device *dev = &i2c->dev;
4617 + struct katana_codec_priv *katana_codec;
4618 + unsigned int chip_id = 0;
4621 + regmap = devm_regmap_init_i2c(i2c, &config);
4622 + if (IS_ERR(regmap))
4623 + return PTR_ERR(regmap);
4625 + katana_codec = devm_kzalloc(dev, sizeof(struct katana_codec_priv),
4627 + if (!katana_codec)
4630 + dev_set_drvdata(dev, katana_codec);
4631 + katana_codec->regmap = regmap;
4633 + ret = regmap_read(regmap, KATANA_CODEC_CHIP_ID_REG, &chip_id);
4634 + if ((ret != 0) || (chip_id != KATANA_CODEC_CHIP_ID)) {
4635 + dev_err(dev, "Failed to read Chip or wrong Chip id: %d\n", ret);
4638 + regmap_update_bits(regmap, KATANA_CODEC_RESET, 0x01, 0x01);
4641 + ret = snd_soc_register_component(dev, &katana_codec_component_driver,
4642 + &katana_codec_dai, 1);
4644 + dev_err(dev, "failed to register codec: %d\n", ret);
4651 +static void allo_katana_component_remove(struct i2c_client *i2c)
4653 + snd_soc_unregister_component(&i2c->dev);
4656 +static const struct i2c_device_id allo_katana_component_id[] = {
4657 + { "allo-katana-codec", },
4660 +MODULE_DEVICE_TABLE(i2c, allo_katana_component_id);
4662 +static const struct of_device_id allo_katana_codec_of_match[] = {
4663 + { .compatible = "allo,allo-katana-codec", },
4666 +MODULE_DEVICE_TABLE(of, allo_katana_codec_of_match);
4668 +static struct i2c_driver allo_katana_component_driver = {
4669 + .probe = allo_katana_component_probe,
4670 + .remove = allo_katana_component_remove,
4671 + .id_table = allo_katana_component_id,
4673 + .name = "allo-katana-codec",
4674 + .of_match_table = allo_katana_codec_of_match,
4678 +module_i2c_driver(allo_katana_component_driver);
4680 +MODULE_DESCRIPTION("ASoC Allo Katana Codec Driver");
4681 +MODULE_AUTHOR("Jaikumar <jaikumar@cem-solutions.net>");
4682 +MODULE_LICENSE("GPL v2");
4684 +++ b/sound/soc/bcm/allo-piano-dac-plus.c
4687 + * ALSA ASoC Machine Driver for Allo Piano DAC Plus Subwoofer
4689 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
4691 + * based on code by David Knell <david.knell@gmail.com)
4692 + * based on code by Daniel Matuschek <info@crazy-audio.com>
4693 + * based on code by Florian Meier <florian.meier@koalo.de>
4695 + * This program is free software; you can redistribute it and/or
4696 + * modify it under the terms of the GNU General Public License
4697 + * version 2 as published by the Free Software Foundation.
4699 + * This program is distributed in the hope that it will be useful, but
4700 + * WITHOUT ANY WARRANTY; without even the implied warranty of
4701 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4702 + * General Public License for more details.
4705 +#include <linux/module.h>
4706 +#include <linux/platform_device.h>
4707 +#include <linux/gpio/consumer.h>
4708 +#include <sound/core.h>
4709 +#include <sound/pcm.h>
4710 +#include <sound/pcm_params.h>
4711 +#include <sound/soc.h>
4712 +#include <linux/firmware.h>
4713 +#include <linux/delay.h>
4714 +#include <sound/tlv.h>
4715 +#include "../codecs/pcm512x.h"
4717 +#define P_DAC_LEFT_MUTE 0x10
4718 +#define P_DAC_RIGHT_MUTE 0x01
4719 +#define P_DAC_MUTE 0x11
4720 +#define P_DAC_UNMUTE 0x00
4731 + struct mutex lock;
4732 + unsigned int dual_mode;
4733 + unsigned int set_lowpass;
4734 + unsigned int set_mode;
4735 + unsigned int set_rate;
4736 + unsigned int dsp_page_number;
4739 +static bool digital_gain_0db_limit = true;
4742 +static struct gpio_desc *mute_gpio[2];
4744 +static const char * const allo_piano_mode_texts[] = {
4751 +static SOC_ENUM_SINGLE_DECL(allo_piano_mode_enum,
4752 + 0, 0, allo_piano_mode_texts);
4754 +static const char * const allo_piano_dual_mode_texts[] = {
4760 +static SOC_ENUM_SINGLE_DECL(allo_piano_dual_mode_enum,
4761 + 0, 0, allo_piano_dual_mode_texts);
4763 +static const char * const allo_piano_dsp_low_pass_texts[] = {
4781 +static SOC_ENUM_SINGLE_DECL(allo_piano_enum,
4782 + 0, 0, allo_piano_dsp_low_pass_texts);
4784 +static int __snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
4785 + unsigned int mode, unsigned int rate, unsigned int lowpass)
4787 + const struct firmware *fw;
4788 + struct snd_soc_card *card = rtd->card;
4789 + struct glb_pool *glb_ptr = card->drvdata;
4790 + char firmware_name[60];
4791 + int ret = 0, dac = 0;
4793 + if (rate <= 46000)
4795 + else if (rate <= 68000)
4797 + else if (rate <= 92000)
4799 + else if (rate <= 136000)
4801 + else if (rate <= 184000)
4807 + glb_ptr->set_lowpass = lowpass = 0;
4810 + glb_ptr->set_mode = mode = 0;
4813 + glb_ptr->dual_mode = 0;
4815 + /* same configuration loaded */
4816 + if ((rate == glb_ptr->set_rate) && (lowpass == glb_ptr->set_lowpass)
4817 + && (mode == glb_ptr->set_mode))
4821 + case 0: /* None */
4825 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
4826 + PCM512x_MUTE, P_DAC_UNMUTE);
4827 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
4828 + PCM512x_MUTE, P_DAC_MUTE);
4829 + glb_ptr->set_rate = rate;
4830 + glb_ptr->set_mode = mode;
4831 + glb_ptr->set_lowpass = lowpass;
4835 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
4836 + PCM512x_MUTE, P_DAC_UNMUTE);
4837 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
4838 + PCM512x_MUTE, P_DAC_UNMUTE);
4841 + for (dac = 0; dac < rtd->dai_link->num_codecs; dac++) {
4842 + struct dsp_code *dsp_code_read;
4845 + if (dac == 0) { /* high */
4846 + snprintf(firmware_name, sizeof(firmware_name),
4847 + "allo/piano/2.2/allo-piano-dsp-%d-%d-%d.bin",
4848 + rate, ((lowpass * 10) + 60), dac);
4849 + } else { /* low */
4850 + snprintf(firmware_name, sizeof(firmware_name),
4851 + "allo/piano/2.%d/allo-piano-dsp-%d-%d-%d.bin",
4852 + (mode - 1), rate, ((lowpass * 10) + 60), dac);
4855 + dev_info(rtd->card->dev, "Dsp Firmware File Name: %s\n",
4858 + ret = request_firmware(&fw, firmware_name, rtd->card->dev);
4860 + dev_err(rtd->card->dev,
4861 + "Error: Allo Piano Firmware %s missing. %d\n",
4862 + firmware_name, ret);
4866 + while (i < (fw->size - 1)) {
4867 + dsp_code_read = (struct dsp_code *)&fw->data[i];
4869 + if (dsp_code_read->offset == 0) {
4870 + glb_ptr->dsp_page_number = dsp_code_read->val;
4871 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, dac)->component,
4872 + PCM512x_PAGE_BASE(0),
4873 + dsp_code_read->val);
4875 + } else if (dsp_code_read->offset != 0) {
4876 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, dac)->component,
4877 + (PCM512x_PAGE_BASE(
4878 + glb_ptr->dsp_page_number) +
4879 + dsp_code_read->offset),
4880 + dsp_code_read->val);
4883 + dev_err(rtd->card->dev,
4884 + "Failed to write Register: %d\n", ret);
4885 + release_firmware(fw);
4890 + release_firmware(fw);
4892 + glb_ptr->set_rate = rate;
4893 + glb_ptr->set_mode = mode;
4894 + glb_ptr->set_lowpass = lowpass;
4901 +static int snd_allo_piano_dsp_program(struct snd_soc_pcm_runtime *rtd,
4902 + unsigned int mode, unsigned int rate, unsigned int lowpass)
4904 + struct snd_soc_card *card = rtd->card;
4905 + struct glb_pool *glb_ptr = card->drvdata;
4908 + mutex_lock(&glb_ptr->lock);
4910 + ret = __snd_allo_piano_dsp_program(rtd, mode, rate, lowpass);
4912 + mutex_unlock(&glb_ptr->lock);
4917 +static int snd_allo_piano_dual_mode_get(struct snd_kcontrol *kcontrol,
4918 + struct snd_ctl_elem_value *ucontrol)
4920 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
4921 + struct glb_pool *glb_ptr = card->drvdata;
4923 + ucontrol->value.integer.value[0] = glb_ptr->dual_mode;
4928 +static int snd_allo_piano_dual_mode_put(struct snd_kcontrol *kcontrol,
4929 + struct snd_ctl_elem_value *ucontrol)
4931 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
4932 + struct glb_pool *glb_ptr = card->drvdata;
4933 + struct snd_soc_pcm_runtime *rtd;
4934 + struct snd_card *snd_card_ptr = card->snd_card;
4935 + struct snd_kcontrol *kctl;
4936 + struct soc_mixer_control *mc;
4937 + unsigned int left_val = 0, right_val = 0;
4939 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
4941 + if (ucontrol->value.integer.value[0] > 0) {
4942 + glb_ptr->dual_mode = ucontrol->value.integer.value[0];
4943 + glb_ptr->set_mode = 0;
4945 + if (glb_ptr->set_mode <= 0) {
4946 + glb_ptr->dual_mode = 1;
4947 + glb_ptr->set_mode = 0;
4949 + glb_ptr->dual_mode = 0;
4954 + if (glb_ptr->dual_mode == 1) { // Dual Mono
4955 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
4956 + PCM512x_MUTE, P_DAC_RIGHT_MUTE);
4957 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
4958 + PCM512x_MUTE, P_DAC_LEFT_MUTE);
4959 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
4960 + PCM512x_DIGITAL_VOLUME_3, 0xff);
4961 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
4962 + PCM512x_DIGITAL_VOLUME_2, 0xff);
4964 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
4965 + if (!strncmp(kctl->id.name, "Main Digital Playback Volume",
4966 + sizeof(kctl->id.name))) {
4967 + mc = (struct soc_mixer_control *)
4968 + kctl->private_value;
4969 + mc->rreg = mc->reg;
4972 + if (!strncmp(kctl->id.name, "Sub Digital Playback Volume",
4973 + sizeof(kctl->id.name))) {
4974 + mc = (struct soc_mixer_control *)
4975 + kctl->private_value;
4976 + mc->rreg = mc->reg;
4981 + left_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 0)->component,
4982 + PCM512x_DIGITAL_VOLUME_2);
4983 + right_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component,
4984 + PCM512x_DIGITAL_VOLUME_3);
4986 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
4987 + if (!strncmp(kctl->id.name, "Main Digital Playback Volume",
4988 + sizeof(kctl->id.name))) {
4989 + mc = (struct soc_mixer_control *)
4990 + kctl->private_value;
4991 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
4994 + if (!strncmp(kctl->id.name, "Sub Digital Playback Volume",
4995 + sizeof(kctl->id.name))) {
4996 + mc = (struct soc_mixer_control *)
4997 + kctl->private_value;
4998 + mc->rreg = PCM512x_DIGITAL_VOLUME_2;
5003 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5004 + PCM512x_DIGITAL_VOLUME_3, left_val);
5005 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5006 + PCM512x_DIGITAL_VOLUME_2, right_val);
5007 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5008 + PCM512x_MUTE, P_DAC_UNMUTE);
5009 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5010 + PCM512x_MUTE, P_DAC_UNMUTE);
5016 +static int snd_allo_piano_mode_get(struct snd_kcontrol *kcontrol,
5017 + struct snd_ctl_elem_value *ucontrol)
5019 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5020 + struct glb_pool *glb_ptr = card->drvdata;
5022 + ucontrol->value.integer.value[0] = glb_ptr->set_mode;
5026 +static int snd_allo_piano_mode_put(struct snd_kcontrol *kcontrol,
5027 + struct snd_ctl_elem_value *ucontrol)
5029 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5030 + struct snd_soc_pcm_runtime *rtd;
5031 + struct glb_pool *glb_ptr = card->drvdata;
5032 + struct snd_card *snd_card_ptr = card->snd_card;
5033 + struct snd_kcontrol *kctl;
5034 + struct soc_mixer_control *mc;
5035 + unsigned int left_val = 0, right_val = 0;
5037 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5039 + if ((glb_ptr->dual_mode == 1) &&
5040 + (ucontrol->value.integer.value[0] > 0)) {
5041 + left_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 0)->component,
5042 + PCM512x_DIGITAL_VOLUME_2);
5043 + right_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component,
5044 + PCM512x_DIGITAL_VOLUME_2);
5046 + list_for_each_entry(kctl, &snd_card_ptr->controls, list) {
5047 + if (!strncmp(kctl->id.name, "Main Digital Playback Volume",
5048 + sizeof(kctl->id.name))) {
5049 + mc = (struct soc_mixer_control *)
5050 + kctl->private_value;
5051 + mc->rreg = PCM512x_DIGITAL_VOLUME_3;
5054 + if (!strncmp(kctl->id.name, "Sub Digital Playback Volume",
5055 + sizeof(kctl->id.name))) {
5056 + mc = (struct soc_mixer_control *)
5057 + kctl->private_value;
5058 + mc->rreg = PCM512x_DIGITAL_VOLUME_2;
5062 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5063 + PCM512x_DIGITAL_VOLUME_3, left_val);
5064 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5065 + PCM512x_DIGITAL_VOLUME_3, right_val);
5068 + return(snd_allo_piano_dsp_program(rtd,
5069 + ucontrol->value.integer.value[0],
5070 + glb_ptr->set_rate, glb_ptr->set_lowpass));
5073 +static int snd_allo_piano_lowpass_get(struct snd_kcontrol *kcontrol,
5074 + struct snd_ctl_elem_value *ucontrol)
5076 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5077 + struct glb_pool *glb_ptr = card->drvdata;
5079 + ucontrol->value.integer.value[0] = glb_ptr->set_lowpass;
5083 +static int snd_allo_piano_lowpass_put(struct snd_kcontrol *kcontrol,
5084 + struct snd_ctl_elem_value *ucontrol)
5086 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5087 + struct snd_soc_pcm_runtime *rtd;
5088 + struct glb_pool *glb_ptr = card->drvdata;
5090 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5091 + return(snd_allo_piano_dsp_program(rtd,
5092 + glb_ptr->set_mode, glb_ptr->set_rate,
5093 + ucontrol->value.integer.value[0]));
5096 +static int pcm512x_get_reg_sub(struct snd_kcontrol *kcontrol,
5097 + struct snd_ctl_elem_value *ucontrol)
5099 + struct soc_mixer_control *mc =
5100 + (struct soc_mixer_control *)kcontrol->private_value;
5101 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5102 + struct glb_pool *glb_ptr = card->drvdata;
5103 + struct snd_soc_pcm_runtime *rtd;
5104 + unsigned int left_val = 0;
5105 + unsigned int right_val = 0;
5106 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5108 + right_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component,
5109 + PCM512x_DIGITAL_VOLUME_3);
5110 + if (glb_ptr->dual_mode != 1) {
5111 + left_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component,
5112 + PCM512x_DIGITAL_VOLUME_2);
5115 + left_val = right_val;
5118 + ucontrol->value.integer.value[0] =
5119 + (~(left_val >> mc->shift)) & mc->max;
5120 + ucontrol->value.integer.value[1] =
5121 + (~(right_val >> mc->shift)) & mc->max;
5126 +static int pcm512x_set_reg_sub(struct snd_kcontrol *kcontrol,
5127 + struct snd_ctl_elem_value *ucontrol)
5129 + struct soc_mixer_control *mc =
5130 + (struct soc_mixer_control *)kcontrol->private_value;
5131 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5132 + struct glb_pool *glb_ptr = card->drvdata;
5133 + struct snd_soc_pcm_runtime *rtd;
5134 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
5135 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
5138 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5140 + if (digital_gain_0db_limit) {
5141 + ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
5144 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
5148 + // When in Dual Mono, Sub vol control should not set anything.
5149 + if (glb_ptr->dual_mode != 1) { //Not in Dual Mono mode
5151 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5152 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
5156 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5157 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
5166 +static int pcm512x_get_reg_sub_switch(struct snd_kcontrol *kcontrol,
5167 + struct snd_ctl_elem_value *ucontrol)
5169 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5170 + struct snd_soc_pcm_runtime *rtd;
5173 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5174 + val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component, PCM512x_MUTE);
5176 + ucontrol->value.integer.value[0] =
5177 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
5178 + ucontrol->value.integer.value[1] =
5179 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
5184 +static int pcm512x_set_reg_sub_switch(struct snd_kcontrol *kcontrol,
5185 + struct snd_ctl_elem_value *ucontrol)
5187 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5188 + struct snd_soc_pcm_runtime *rtd;
5189 + struct glb_pool *glb_ptr = card->drvdata;
5190 + unsigned int left_val = (ucontrol->value.integer.value[0]);
5191 + unsigned int right_val = (ucontrol->value.integer.value[1]);
5194 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5195 + if (glb_ptr->set_mode != 1) {
5196 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component, PCM512x_MUTE,
5197 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
5205 +static int pcm512x_get_reg_master(struct snd_kcontrol *kcontrol,
5206 + struct snd_ctl_elem_value *ucontrol)
5208 + struct soc_mixer_control *mc =
5209 + (struct soc_mixer_control *)kcontrol->private_value;
5210 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5211 + struct glb_pool *glb_ptr = card->drvdata;
5212 + struct snd_soc_pcm_runtime *rtd;
5213 + unsigned int left_val = 0, right_val = 0;
5215 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5217 + left_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 0)->component,
5218 + PCM512x_DIGITAL_VOLUME_2);
5220 + if (glb_ptr->dual_mode == 1) { // in Dual Mono mode
5221 + right_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component,
5222 + PCM512x_DIGITAL_VOLUME_3);
5224 + right_val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 0)->component,
5225 + PCM512x_DIGITAL_VOLUME_3);
5228 + ucontrol->value.integer.value[0] =
5229 + (~(left_val >> mc->shift)) & mc->max;
5230 + ucontrol->value.integer.value[1] =
5231 + (~(right_val >> mc->shift)) & mc->max;
5236 +static int pcm512x_set_reg_master(struct snd_kcontrol *kcontrol,
5237 + struct snd_ctl_elem_value *ucontrol)
5239 + struct soc_mixer_control *mc =
5240 + (struct soc_mixer_control *)kcontrol->private_value;
5241 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5242 + struct glb_pool *glb_ptr = card->drvdata;
5243 + struct snd_soc_pcm_runtime *rtd;
5244 + unsigned int left_val = (ucontrol->value.integer.value[0] & mc->max);
5245 + unsigned int right_val = (ucontrol->value.integer.value[1] & mc->max);
5248 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5250 + if (digital_gain_0db_limit) {
5251 + ret = snd_soc_limit_volume(card, "Master Playback Volume",
5254 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
5258 + if (glb_ptr->dual_mode == 1) { //in Dual Mono Mode
5260 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5261 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
5265 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component,
5266 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
5272 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5273 + PCM512x_DIGITAL_VOLUME_2, (~left_val));
5277 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component,
5278 + PCM512x_DIGITAL_VOLUME_3, (~right_val));
5286 +static int pcm512x_get_reg_master_switch(struct snd_kcontrol *kcontrol,
5287 + struct snd_ctl_elem_value *ucontrol)
5289 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5290 + struct glb_pool *glb_ptr = card->drvdata;
5291 + struct snd_soc_pcm_runtime *rtd;
5294 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5296 + val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 0)->component, PCM512x_MUTE);
5298 + ucontrol->value.integer.value[0] =
5299 + (val & P_DAC_LEFT_MUTE) ? P_UNMUTE : P_MUTE;
5301 + if (glb_ptr->dual_mode == 1) {
5302 + val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, 1)->component, PCM512x_MUTE);
5304 + ucontrol->value.integer.value[1] =
5305 + (val & P_DAC_RIGHT_MUTE) ? P_UNMUTE : P_MUTE;
5310 +static int pcm512x_set_reg_master_switch(struct snd_kcontrol *kcontrol,
5311 + struct snd_ctl_elem_value *ucontrol)
5313 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
5314 + struct snd_soc_pcm_runtime *rtd;
5315 + struct glb_pool *glb_ptr = card->drvdata;
5316 + unsigned int left_val = (ucontrol->value.integer.value[0]);
5317 + unsigned int right_val = (ucontrol->value.integer.value[1]);
5320 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5321 + if (glb_ptr->dual_mode == 1) {
5322 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component, PCM512x_MUTE,
5323 + ~((left_val & 0x01)<<4));
5326 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component, PCM512x_MUTE,
5327 + ~((right_val & 0x01)));
5331 + } else if (glb_ptr->set_mode == 1) {
5332 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component, PCM512x_MUTE,
5333 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
5338 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 0)->component, PCM512x_MUTE,
5339 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
5343 + ret = snd_soc_component_write(snd_soc_rtd_to_codec(rtd, 1)->component, PCM512x_MUTE,
5344 + ~((left_val & 0x01)<<4 | (right_val & 0x01)));
5351 +static const DECLARE_TLV_DB_SCALE(digital_tlv_sub, -10350, 50, 1);
5352 +static const DECLARE_TLV_DB_SCALE(digital_tlv_master, -10350, 50, 1);
5354 +static const struct snd_kcontrol_new allo_piano_controls[] = {
5355 + SOC_ENUM_EXT("Subwoofer mode Route",
5356 + allo_piano_mode_enum,
5357 + snd_allo_piano_mode_get,
5358 + snd_allo_piano_mode_put),
5360 + SOC_ENUM_EXT("Dual Mode Route",
5361 + allo_piano_dual_mode_enum,
5362 + snd_allo_piano_dual_mode_get,
5363 + snd_allo_piano_dual_mode_put),
5365 + SOC_ENUM_EXT("Lowpass Route", allo_piano_enum,
5366 + snd_allo_piano_lowpass_get,
5367 + snd_allo_piano_lowpass_put),
5369 + SOC_DOUBLE_R_EXT_TLV("Subwoofer Playback Volume",
5370 + PCM512x_DIGITAL_VOLUME_2,
5371 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
5372 + pcm512x_get_reg_sub,
5373 + pcm512x_set_reg_sub,
5376 + SOC_DOUBLE_EXT("Subwoofer Playback Switch",
5378 + PCM512x_RQML_SHIFT,
5379 + PCM512x_RQMR_SHIFT, 1, 1,
5380 + pcm512x_get_reg_sub_switch,
5381 + pcm512x_set_reg_sub_switch),
5383 + SOC_DOUBLE_R_EXT_TLV("Master Playback Volume",
5384 + PCM512x_DIGITAL_VOLUME_2,
5385 + PCM512x_DIGITAL_VOLUME_3, 0, 255, 1,
5386 + pcm512x_get_reg_master,
5387 + pcm512x_set_reg_master,
5388 + digital_tlv_master),
5390 + SOC_DOUBLE_EXT("Master Playback Switch",
5392 + PCM512x_RQML_SHIFT,
5393 + PCM512x_RQMR_SHIFT, 1, 1,
5394 + pcm512x_get_reg_master_switch,
5395 + pcm512x_set_reg_master_switch),
5398 +static const char * const codec_ctl_pfx[] = { "Main", "Sub" };
5399 +static const char * const codec_ctl_name[] = {
5400 + "Digital Playback Volume",
5401 + "Digital Playback Switch",
5402 + "Auto Mute Mono Switch",
5403 + "Auto Mute Switch",
5404 + "Auto Mute Time Left",
5405 + "Auto Mute Time Right",
5406 + "Clock Missing Period",
5407 + "Max Overclock DAC",
5408 + "Max Overclock DSP",
5409 + "Max Overclock PLL",
5410 + "Volume Ramp Down Emergency Rate",
5411 + "Volume Ramp Down Emergency Step",
5412 + "Volume Ramp Up Rate",
5413 + "Volume Ramp Down Rate",
5414 + "Volume Ramp Up Step",
5415 + "Volume Ramp Down Step"
5418 +static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
5420 + struct snd_soc_card *card = rtd->card;
5421 + struct glb_pool *glb_ptr;
5422 + struct snd_kcontrol *kctl;
5425 + glb_ptr = kzalloc(sizeof(struct glb_pool), GFP_KERNEL);
5429 + card->drvdata = glb_ptr;
5430 + glb_ptr->dual_mode = 2;
5431 + glb_ptr->set_mode = 0;
5433 + mutex_init(&glb_ptr->lock);
5435 + if (digital_gain_0db_limit) {
5438 + //Set volume limit on both dacs
5439 + for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) {
5442 + sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[0]);
5443 + ret = snd_soc_limit_volume(card, cname, 207);
5445 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
5450 + // Remove codec controls
5451 + for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) {
5452 + for (j = 0; j < ARRAY_SIZE(codec_ctl_name); j++) {
5455 + sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[j]);
5456 + kctl = snd_soc_card_get_kcontrol(card, cname);
5458 + dev_err(rtd->card->dev, "Control %s not found\n",
5461 + kctl->vd[0].access =
5462 + SNDRV_CTL_ELEM_ACCESS_READWRITE;
5463 + snd_ctl_remove(card->snd_card, kctl);
5471 +static void snd_allo_piano_gpio_mute(struct snd_soc_card *card)
5474 + gpiod_set_value_cansleep(mute_gpio[0], P_MUTE);
5477 + gpiod_set_value_cansleep(mute_gpio[1], P_MUTE);
5480 +static void snd_allo_piano_gpio_unmute(struct snd_soc_card *card)
5483 + gpiod_set_value_cansleep(mute_gpio[0], P_UNMUTE);
5486 + gpiod_set_value_cansleep(mute_gpio[1], P_UNMUTE);
5489 +static int snd_allo_piano_set_bias_level(struct snd_soc_card *card,
5490 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
5492 + struct snd_soc_pcm_runtime *rtd;
5493 + struct snd_soc_dai *codec_dai;
5495 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
5496 + codec_dai = snd_soc_rtd_to_codec(rtd, 0);
5498 + if (dapm->dev != codec_dai->dev)
5502 + case SND_SOC_BIAS_PREPARE:
5503 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
5506 + snd_allo_piano_gpio_unmute(card);
5509 + case SND_SOC_BIAS_STANDBY:
5510 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
5513 + snd_allo_piano_gpio_mute(card);
5523 +static int snd_allo_piano_dac_startup(
5524 + struct snd_pcm_substream *substream)
5526 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
5527 + struct snd_soc_card *card = rtd->card;
5529 + snd_allo_piano_gpio_mute(card);
5534 +static int snd_allo_piano_dac_hw_params(
5535 + struct snd_pcm_substream *substream,
5536 + struct snd_pcm_hw_params *params)
5538 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
5539 + unsigned int rate = params_rate(params);
5540 + struct snd_soc_card *card = rtd->card;
5541 + struct glb_pool *glb_ptr = card->drvdata;
5542 + int ret = 0, val = 0, dac;
5544 + for (dac = 0; (glb_mclk && dac < 2); dac++) {
5545 + /* Configure the PLL clock reference for both the Codecs */
5546 + val = snd_soc_component_read(snd_soc_rtd_to_codec(rtd, dac)->component,
5547 + PCM512x_RATE_DET_4);
5550 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, dac)->component,
5552 + PCM512x_SREF_BCK);
5554 + dev_info(snd_soc_rtd_to_codec(rtd, dac)->component->dev,
5555 + "Setting BCLK as input clock & Enable PLL\n");
5557 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, dac)->component,
5561 + snd_soc_component_write(snd_soc_rtd_to_codec(rtd, dac)->component,
5563 + PCM512x_SREF_SCK);
5565 + dev_info(snd_soc_rtd_to_codec(rtd, dac)->component->dev,
5566 + "Setting SCLK as input clock & disabled PLL\n");
5570 + ret = snd_allo_piano_dsp_program(rtd, glb_ptr->set_mode, rate,
5571 + glb_ptr->set_lowpass);
5578 +static int snd_allo_piano_dac_prepare(
5579 + struct snd_pcm_substream *substream)
5581 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
5582 + struct snd_soc_card *card = rtd->card;
5584 + snd_allo_piano_gpio_unmute(card);
5589 +/* machine stream operations */
5590 +static struct snd_soc_ops snd_allo_piano_dac_ops = {
5591 + .startup = snd_allo_piano_dac_startup,
5592 + .hw_params = snd_allo_piano_dac_hw_params,
5593 + .prepare = snd_allo_piano_dac_prepare,
5596 +static struct snd_soc_dai_link_component allo_piano_2_1_codecs[] = {
5598 + .dai_name = "pcm512x-hifi",
5601 + .dai_name = "pcm512x-hifi",
5605 +SND_SOC_DAILINK_DEFS(allo_piano_dai_plus,
5606 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
5607 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi"),
5608 + COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
5609 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
5611 +static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
5613 + .name = "PianoDACPlus",
5614 + .stream_name = "PianoDACPlus",
5615 + .dai_fmt = SND_SOC_DAIFMT_I2S |
5616 + SND_SOC_DAIFMT_NB_NF |
5617 + SND_SOC_DAIFMT_CBS_CFS,
5618 + .ops = &snd_allo_piano_dac_ops,
5619 + .init = snd_allo_piano_dac_init,
5620 + SND_SOC_DAILINK_REG(allo_piano_dai_plus),
5624 +/* audio machine driver */
5625 +static struct snd_soc_card snd_allo_piano_dac = {
5626 + .name = "PianoDACPlus",
5627 + .owner = THIS_MODULE,
5628 + .dai_link = snd_allo_piano_dac_dai,
5629 + .num_links = ARRAY_SIZE(snd_allo_piano_dac_dai),
5630 + .controls = allo_piano_controls,
5631 + .num_controls = ARRAY_SIZE(allo_piano_controls),
5634 +static int snd_allo_piano_dac_probe(struct platform_device *pdev)
5636 + struct snd_soc_card *card = &snd_allo_piano_dac;
5637 + int ret = 0, i = 0;
5639 + card->dev = &pdev->dev;
5640 + platform_set_drvdata(pdev, &snd_allo_piano_dac);
5642 + if (pdev->dev.of_node) {
5643 + struct device_node *i2s_node;
5644 + struct snd_soc_dai_link *dai;
5646 + dai = &snd_allo_piano_dac_dai[0];
5647 + i2s_node = of_parse_phandle(pdev->dev.of_node,
5648 + "i2s-controller", 0);
5650 + for (i = 0; i < card->num_links; i++) {
5651 + dai->cpus->dai_name = NULL;
5652 + dai->cpus->of_node = i2s_node;
5653 + dai->platforms->name = NULL;
5654 + dai->platforms->of_node = i2s_node;
5657 + digital_gain_0db_limit =
5658 + !of_property_read_bool(pdev->dev.of_node,
5659 + "allo,24db_digital_gain");
5661 + glb_mclk = of_property_read_bool(pdev->dev.of_node,
5664 + allo_piano_2_1_codecs[0].of_node =
5665 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
5666 + if (!allo_piano_2_1_codecs[0].of_node) {
5667 + dev_err(&pdev->dev,
5668 + "Property 'audio-codec' missing or invalid\n");
5672 + allo_piano_2_1_codecs[1].of_node =
5673 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 1);
5674 + if (!allo_piano_2_1_codecs[1].of_node) {
5675 + dev_err(&pdev->dev,
5676 + "Property 'audio-codec' missing or invalid\n");
5680 + mute_gpio[0] = devm_gpiod_get_optional(&pdev->dev, "mute1",
5682 + if (IS_ERR(mute_gpio[0])) {
5683 + ret = PTR_ERR(mute_gpio[0]);
5684 + dev_err(&pdev->dev,
5685 + "failed to get mute1 gpio6: %d\n", ret);
5689 + mute_gpio[1] = devm_gpiod_get_optional(&pdev->dev, "mute2",
5691 + if (IS_ERR(mute_gpio[1])) {
5692 + ret = PTR_ERR(mute_gpio[1]);
5693 + dev_err(&pdev->dev,
5694 + "failed to get mute2 gpio25: %d\n", ret);
5698 + if (mute_gpio[0] && mute_gpio[1])
5699 + snd_allo_piano_dac.set_bias_level =
5700 + snd_allo_piano_set_bias_level;
5702 + ret = snd_soc_register_card(&snd_allo_piano_dac);
5704 + dev_err(&pdev->dev,
5705 + "snd_soc_register_card() failed: %d\n", ret);
5709 + if ((mute_gpio[0]) && (mute_gpio[1]))
5710 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
5718 +static void snd_allo_piano_dac_remove(struct platform_device *pdev)
5720 + struct snd_soc_card *card = platform_get_drvdata(pdev);
5722 + kfree(&card->drvdata);
5723 + snd_allo_piano_gpio_mute(&snd_allo_piano_dac);
5724 + snd_soc_unregister_card(&snd_allo_piano_dac);
5727 +static const struct of_device_id snd_allo_piano_dac_of_match[] = {
5728 + { .compatible = "allo,piano-dac-plus", },
5729 + { /* sentinel */ },
5732 +MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
5734 +static struct platform_driver snd_allo_piano_dac_driver = {
5736 + .name = "snd-allo-piano-dac-plus",
5737 + .owner = THIS_MODULE,
5738 + .of_match_table = snd_allo_piano_dac_of_match,
5740 + .probe = snd_allo_piano_dac_probe,
5741 + .remove = snd_allo_piano_dac_remove,
5744 +module_platform_driver(snd_allo_piano_dac_driver);
5746 +MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
5747 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC Plus");
5748 +MODULE_LICENSE("GPL v2");
5750 +++ b/sound/soc/bcm/allo-piano-dac.c
5753 + * ALSA ASoC Machine Driver for Allo Piano DAC
5755 + * Author: Baswaraj K <jaikumar@cem-solutions.net>
5757 + * based on code by Daniel Matuschek <info@crazy-audio.com>
5758 + * based on code by Florian Meier <florian.meier@koalo.de>
5760 + * This program is free software; you can redistribute it and/or
5761 + * modify it under the terms of the GNU General Public License
5762 + * version 2 as published by the Free Software Foundation.
5764 + * This program is distributed in the hope that it will be useful, but
5765 + * WITHOUT ANY WARRANTY; without even the implied warranty of
5766 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5767 + * General Public License for more details.
5770 +#include <linux/module.h>
5771 +#include <linux/platform_device.h>
5773 +#include <sound/core.h>
5774 +#include <sound/pcm.h>
5775 +#include <sound/pcm_params.h>
5776 +#include <sound/soc.h>
5778 +static bool digital_gain_0db_limit = true;
5780 +static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
5782 + if (digital_gain_0db_limit) {
5784 + struct snd_soc_card *card = rtd->card;
5786 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
5789 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
5796 +SND_SOC_DAILINK_DEFS(allo_piano_dai,
5797 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
5798 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi")),
5799 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
5801 +static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
5803 + .name = "Piano DAC",
5804 + .stream_name = "Piano DAC HiFi",
5805 + .dai_fmt = SND_SOC_DAIFMT_I2S |
5806 + SND_SOC_DAIFMT_NB_NF |
5807 + SND_SOC_DAIFMT_CBS_CFS,
5808 + .init = snd_allo_piano_dac_init,
5809 + SND_SOC_DAILINK_REG(allo_piano_dai),
5813 +/* audio machine driver */
5814 +static struct snd_soc_card snd_allo_piano_dac = {
5815 + .name = "PianoDAC",
5816 + .owner = THIS_MODULE,
5817 + .dai_link = snd_allo_piano_dac_dai,
5818 + .num_links = ARRAY_SIZE(snd_allo_piano_dac_dai),
5821 +static int snd_allo_piano_dac_probe(struct platform_device *pdev)
5825 + snd_allo_piano_dac.dev = &pdev->dev;
5827 + if (pdev->dev.of_node) {
5828 + struct device_node *i2s_node;
5829 + struct snd_soc_dai_link *dai;
5831 + dai = &snd_allo_piano_dac_dai[0];
5832 + i2s_node = of_parse_phandle(pdev->dev.of_node,
5833 + "i2s-controller", 0);
5836 + dai->cpus->dai_name = NULL;
5837 + dai->cpus->of_node = i2s_node;
5838 + dai->platforms->name = NULL;
5839 + dai->platforms->of_node = i2s_node;
5842 + digital_gain_0db_limit = !of_property_read_bool(
5843 + pdev->dev.of_node, "allo,24db_digital_gain");
5846 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_allo_piano_dac);
5847 + if (ret && ret != -EPROBE_DEFER)
5848 + dev_err(&pdev->dev,
5849 + "snd_soc_register_card() failed: %d\n", ret);
5854 +static const struct of_device_id snd_allo_piano_dac_of_match[] = {
5855 + { .compatible = "allo,piano-dac", },
5856 + { /* sentinel */ },
5858 +MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
5860 +static struct platform_driver snd_allo_piano_dac_driver = {
5862 + .name = "snd-allo-piano-dac",
5863 + .owner = THIS_MODULE,
5864 + .of_match_table = snd_allo_piano_dac_of_match,
5866 + .probe = snd_allo_piano_dac_probe,
5869 +module_platform_driver(snd_allo_piano_dac_driver);
5871 +MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
5872 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC");
5873 +MODULE_LICENSE("GPL v2");
5875 +++ b/sound/soc/bcm/audioinjector-isolated-soundcard.c
5878 + * ASoC Driver for AudioInjector.net isolated soundcard
5880 + * Created on: 20-February-2020
5881 + * Author: flatmax@flatmax.org
5882 + * based on audioinjector-octo-soundcard.c
5884 + * Copyright (C) 2020 Flatmax Pty. Ltd.
5886 + * This program is free software; you can redistribute it and/or
5887 + * modify it under the terms of the GNU General Public License
5888 + * version 2 as published by the Free Software Foundation.
5890 + * This program is distributed in the hope that it will be useful, but
5891 + * WITHOUT ANY WARRANTY; without even the implied warranty of
5892 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5893 + * General Public License for more details.
5896 +#include <linux/module.h>
5897 +#include <linux/types.h>
5898 +#include <linux/gpio/consumer.h>
5900 +#include <sound/core.h>
5901 +#include <sound/soc.h>
5902 +#include <sound/pcm_params.h>
5903 +#include <sound/control.h>
5905 +static struct gpio_desc *mute_gpio;
5907 +static const unsigned int audioinjector_isolated_rates[] = {
5908 + 192000, 96000, 48000, 32000, 24000, 16000, 8000
5911 +static struct snd_pcm_hw_constraint_list audioinjector_isolated_constraints = {
5912 + .list = audioinjector_isolated_rates,
5913 + .count = ARRAY_SIZE(audioinjector_isolated_rates),
5916 +static int audioinjector_isolated_dai_init(struct snd_soc_pcm_runtime *rtd)
5918 + int ret=snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 24576000, 0);
5922 + return snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), 64);
5925 +static int audioinjector_isolated_startup(struct snd_pcm_substream *substream)
5927 + snd_pcm_hw_constraint_list(substream->runtime, 0,
5928 + SNDRV_PCM_HW_PARAM_RATE, &audioinjector_isolated_constraints);
5933 +static int audioinjector_isolated_trigger(struct snd_pcm_substream *substream,
5937 + case SNDRV_PCM_TRIGGER_STOP:
5938 + case SNDRV_PCM_TRIGGER_SUSPEND:
5939 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
5940 + gpiod_set_value(mute_gpio, 0);
5942 + case SNDRV_PCM_TRIGGER_START:
5943 + case SNDRV_PCM_TRIGGER_RESUME:
5944 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
5945 + gpiod_set_value(mute_gpio, 1);
5953 +static struct snd_soc_ops audioinjector_isolated_ops = {
5954 + .startup = audioinjector_isolated_startup,
5955 + .trigger = audioinjector_isolated_trigger,
5958 +SND_SOC_DAILINK_DEFS(audioinjector_isolated,
5959 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
5960 + DAILINK_COMP_ARRAY(COMP_CODEC("cs4271.1-0010", "cs4271-hifi")),
5961 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
5963 +static struct snd_soc_dai_link audioinjector_isolated_dai[] = {
5965 + .name = "AudioInjector ISO",
5966 + .stream_name = "AI-HIFI",
5967 + .ops = &audioinjector_isolated_ops,
5968 + .init = audioinjector_isolated_dai_init,
5969 + .symmetric_rate = 1,
5970 + .symmetric_channels = 1,
5971 + .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF,
5972 + SND_SOC_DAILINK_REG(audioinjector_isolated),
5976 +static const struct snd_soc_dapm_widget audioinjector_isolated_widgets[] = {
5977 + SND_SOC_DAPM_OUTPUT("OUTPUTS"),
5978 + SND_SOC_DAPM_INPUT("INPUTS"),
5981 +static const struct snd_soc_dapm_route audioinjector_isolated_route[] = {
5982 + /* Balanced outputs */
5983 + {"OUTPUTS", NULL, "AOUTA+"},
5984 + {"OUTPUTS", NULL, "AOUTA-"},
5985 + {"OUTPUTS", NULL, "AOUTB+"},
5986 + {"OUTPUTS", NULL, "AOUTB-"},
5988 + /* Balanced inputs */
5989 + {"AINA", NULL, "INPUTS"},
5990 + {"AINB", NULL, "INPUTS"},
5993 +static struct snd_soc_card snd_soc_audioinjector_isolated = {
5994 + .name = "audioinjector-isolated-soundcard",
5995 + .owner = THIS_MODULE,
5996 + .dai_link = audioinjector_isolated_dai,
5997 + .num_links = ARRAY_SIZE(audioinjector_isolated_dai),
5999 + .dapm_widgets = audioinjector_isolated_widgets,
6000 + .num_dapm_widgets = ARRAY_SIZE(audioinjector_isolated_widgets),
6001 + .dapm_routes = audioinjector_isolated_route,
6002 + .num_dapm_routes = ARRAY_SIZE(audioinjector_isolated_route),
6005 +static int audioinjector_isolated_probe(struct platform_device *pdev)
6007 + struct snd_soc_card *card = &snd_soc_audioinjector_isolated;
6010 + card->dev = &pdev->dev;
6012 + if (pdev->dev.of_node) {
6013 + struct snd_soc_dai_link *dai = &audioinjector_isolated_dai[0];
6014 + struct device_node *i2s_node =
6015 + of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
6018 + dai->cpus->dai_name = NULL;
6019 + dai->cpus->of_node = i2s_node;
6020 + dai->platforms->name = NULL;
6021 + dai->platforms->of_node = i2s_node;
6023 + dev_err(&pdev->dev,
6024 + "i2s-controller missing or invalid in DT\n");
6028 + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_LOW);
6029 + if (IS_ERR(mute_gpio)){
6030 + dev_err(&pdev->dev, "mute gpio not found in dt overlay\n");
6031 + return PTR_ERR(mute_gpio);
6035 + ret = devm_snd_soc_register_card(&pdev->dev, card);
6036 + if (ret && ret != -EPROBE_DEFER)
6037 + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
6041 +static const struct of_device_id audioinjector_isolated_of_match[] = {
6042 + { .compatible = "ai,audioinjector-isolated-soundcard", },
6045 +MODULE_DEVICE_TABLE(of, audioinjector_isolated_of_match);
6047 +static struct platform_driver audioinjector_isolated_driver = {
6049 + .name = "audioinjector-isolated",
6050 + .owner = THIS_MODULE,
6051 + .of_match_table = audioinjector_isolated_of_match,
6053 + .probe = audioinjector_isolated_probe,
6056 +module_platform_driver(audioinjector_isolated_driver);
6057 +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
6058 +MODULE_DESCRIPTION("AudioInjector.net isolated Soundcard");
6059 +MODULE_LICENSE("GPL v2");
6060 +MODULE_ALIAS("platform:audioinjector-isolated-soundcard");
6062 +++ b/sound/soc/bcm/audioinjector-octo-soundcard.c
6065 + * ASoC Driver for AudioInjector Pi octo channel soundcard (hat)
6067 + * Created on: 27-October-2016
6068 + * Author: flatmax@flatmax.org
6069 + * based on audioinjector-pi-soundcard.c
6071 + * Copyright (C) 2016 Flatmax Pty. Ltd.
6073 + * This program is free software; you can redistribute it and/or
6074 + * modify it under the terms of the GNU General Public License
6075 + * version 2 as published by the Free Software Foundation.
6077 + * This program is distributed in the hope that it will be useful, but
6078 + * WITHOUT ANY WARRANTY; without even the implied warranty of
6079 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6080 + * General Public License for more details.
6083 +#include <linux/module.h>
6084 +#include <linux/types.h>
6085 +#include <linux/gpio/consumer.h>
6087 +#include <sound/core.h>
6088 +#include <sound/soc.h>
6089 +#include <sound/pcm_params.h>
6090 +#include <sound/control.h>
6092 +static struct gpio_descs *mult_gpios;
6093 +static struct gpio_desc *codec_rst_gpio;
6094 +static unsigned int audioinjector_octo_rate;
6095 +static bool non_stop_clocks;
6097 +static const unsigned int audioinjector_octo_rates[] = {
6098 + 96000, 48000, 32000, 24000, 16000, 8000, 88200, 44100, 29400, 22050, 14700,
6101 +static struct snd_pcm_hw_constraint_list audioinjector_octo_constraints = {
6102 + .list = audioinjector_octo_rates,
6103 + .count = ARRAY_SIZE(audioinjector_octo_rates),
6106 +static int audioinjector_octo_dai_init(struct snd_soc_pcm_runtime *rtd)
6108 + return snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), 64);
6111 +static int audioinjector_octo_startup(struct snd_pcm_substream *substream)
6113 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
6114 + snd_soc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = 8;
6115 + snd_soc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = 8;
6116 + snd_soc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = 8;
6117 + snd_soc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = 8;
6118 + snd_soc_rtd_to_codec(rtd, 0)->driver->capture.channels_max = 8;
6120 + snd_pcm_hw_constraint_list(substream->runtime, 0,
6121 + SNDRV_PCM_HW_PARAM_RATE,
6122 + &audioinjector_octo_constraints);
6127 +static void audioinjector_octo_shutdown(struct snd_pcm_substream *substream)
6129 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
6130 + snd_soc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = 2;
6131 + snd_soc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = 2;
6132 + snd_soc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = 2;
6133 + snd_soc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = 2;
6134 + snd_soc_rtd_to_codec(rtd, 0)->driver->capture.channels_max = 6;
6137 +static int audioinjector_octo_hw_params(struct snd_pcm_substream *substream,
6138 + struct snd_pcm_hw_params *params)
6140 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
6142 + // set codec DAI configuration
6143 + int ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0),
6144 + SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_DSP_A|
6145 + SND_SOC_DAIFMT_NB_NF);
6149 + // set cpu DAI configuration
6150 + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
6151 + SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|
6152 + SND_SOC_DAIFMT_NB_NF);
6156 + audioinjector_octo_rate = params_rate(params);
6158 + // Set the correct sysclock for the codec
6159 + switch (audioinjector_octo_rate) {
6162 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 49152000,
6166 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 49152000/2,
6171 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 49152000/3,
6175 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 49152000/6,
6180 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 45185400,
6184 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 45185400/2,
6189 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, 45185400/3,
6197 +static int audioinjector_octo_trigger(struct snd_pcm_substream *substream,
6199 + DECLARE_BITMAP(mult, 4);
6201 + memset(mult, 0, sizeof(mult));
6204 + case SNDRV_PCM_TRIGGER_STOP:
6205 + case SNDRV_PCM_TRIGGER_SUSPEND:
6206 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
6207 + if (!non_stop_clocks)
6210 + case SNDRV_PCM_TRIGGER_START:
6211 + case SNDRV_PCM_TRIGGER_RESUME:
6212 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
6213 + switch (audioinjector_octo_rate) {
6215 + __assign_bit(3, mult, 1);
6218 + __assign_bit(1, mult, 1);
6219 + __assign_bit(2, mult, 1);
6222 + __assign_bit(3, mult, 1);
6225 + __assign_bit(2, mult, 1);
6228 + __assign_bit(3, mult, 1);
6231 + __assign_bit(0, mult, 1);
6232 + __assign_bit(1, mult, 1);
6235 + __assign_bit(3, mult, 1);
6238 + __assign_bit(1, mult, 1);
6241 + __assign_bit(3, mult, 1);
6244 + __assign_bit(0, mult, 1);
6247 + __assign_bit(3, mult, 1);
6256 + gpiod_set_array_value_cansleep(mult_gpios->ndescs, mult_gpios->desc,
6262 +static struct snd_soc_ops audioinjector_octo_ops = {
6263 + .startup = audioinjector_octo_startup,
6264 + .shutdown = audioinjector_octo_shutdown,
6265 + .hw_params = audioinjector_octo_hw_params,
6266 + .trigger = audioinjector_octo_trigger,
6269 +SND_SOC_DAILINK_DEFS(audioinjector_octo,
6270 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
6271 + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
6272 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
6274 +static struct snd_soc_dai_link audioinjector_octo_dai[] = {
6276 + .name = "AudioInjector Octo",
6277 + .stream_name = "AudioInject-HIFI",
6278 + .ops = &audioinjector_octo_ops,
6279 + .init = audioinjector_octo_dai_init,
6280 + .symmetric_rate = 1,
6281 + .symmetric_channels = 1,
6282 + SND_SOC_DAILINK_REG(audioinjector_octo),
6286 +static const struct snd_soc_dapm_widget audioinjector_octo_widgets[] = {
6287 + SND_SOC_DAPM_OUTPUT("OUTPUTS0"),
6288 + SND_SOC_DAPM_OUTPUT("OUTPUTS1"),
6289 + SND_SOC_DAPM_OUTPUT("OUTPUTS2"),
6290 + SND_SOC_DAPM_OUTPUT("OUTPUTS3"),
6291 + SND_SOC_DAPM_INPUT("INPUTS0"),
6292 + SND_SOC_DAPM_INPUT("INPUTS1"),
6293 + SND_SOC_DAPM_INPUT("INPUTS2"),
6296 +static const struct snd_soc_dapm_route audioinjector_octo_route[] = {
6297 + /* Balanced outputs */
6298 + {"OUTPUTS0", NULL, "AOUT1L"},
6299 + {"OUTPUTS0", NULL, "AOUT1R"},
6300 + {"OUTPUTS1", NULL, "AOUT2L"},
6301 + {"OUTPUTS1", NULL, "AOUT2R"},
6302 + {"OUTPUTS2", NULL, "AOUT3L"},
6303 + {"OUTPUTS2", NULL, "AOUT3R"},
6304 + {"OUTPUTS3", NULL, "AOUT4L"},
6305 + {"OUTPUTS3", NULL, "AOUT4R"},
6307 + /* Balanced inputs */
6308 + {"AIN1L", NULL, "INPUTS0"},
6309 + {"AIN1R", NULL, "INPUTS0"},
6310 + {"AIN2L", NULL, "INPUTS1"},
6311 + {"AIN2R", NULL, "INPUTS1"},
6312 + {"AIN3L", NULL, "INPUTS2"},
6313 + {"AIN3R", NULL, "INPUTS2"},
6316 +static struct snd_soc_card snd_soc_audioinjector_octo = {
6317 + .name = "audioinjector-octo-soundcard",
6318 + .owner = THIS_MODULE,
6319 + .dai_link = audioinjector_octo_dai,
6320 + .num_links = ARRAY_SIZE(audioinjector_octo_dai),
6322 + .dapm_widgets = audioinjector_octo_widgets,
6323 + .num_dapm_widgets = ARRAY_SIZE(audioinjector_octo_widgets),
6324 + .dapm_routes = audioinjector_octo_route,
6325 + .num_dapm_routes = ARRAY_SIZE(audioinjector_octo_route),
6328 +static int audioinjector_octo_probe(struct platform_device *pdev)
6330 + struct snd_soc_card *card = &snd_soc_audioinjector_octo;
6333 + card->dev = &pdev->dev;
6335 + if (pdev->dev.of_node) {
6336 + struct snd_soc_dai_link *dai = &audioinjector_octo_dai[0];
6337 + struct device_node *i2s_node =
6338 + of_parse_phandle(pdev->dev.of_node,
6339 + "i2s-controller", 0);
6340 + struct device_node *codec_node =
6341 + of_parse_phandle(pdev->dev.of_node,
6344 + mult_gpios = devm_gpiod_get_array_optional(&pdev->dev, "mult",
6346 + if (IS_ERR(mult_gpios))
6347 + return PTR_ERR(mult_gpios);
6349 + codec_rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
6351 + if (IS_ERR(codec_rst_gpio))
6352 + return PTR_ERR(codec_rst_gpio);
6354 + non_stop_clocks = of_property_read_bool(pdev->dev.of_node, "non-stop-clocks");
6356 + if (codec_rst_gpio)
6357 + gpiod_set_value(codec_rst_gpio, 1);
6359 + if (codec_rst_gpio)
6360 + gpiod_set_value(codec_rst_gpio, 0);
6362 + if (codec_rst_gpio)
6363 + gpiod_set_value(codec_rst_gpio, 1);
6366 + if (i2s_node && codec_node) {
6367 + dai->cpus->dai_name = NULL;
6368 + dai->cpus->of_node = i2s_node;
6369 + dai->platforms->name = NULL;
6370 + dai->platforms->of_node = i2s_node;
6371 + dai->codecs->name = NULL;
6372 + dai->codecs->of_node = codec_node;
6375 + dev_err(&pdev->dev,
6376 + "i2s-controller missing or invalid in DT\n");
6379 + dev_err(&pdev->dev,
6380 + "Property 'codec' missing or invalid\n");
6385 + ret = devm_snd_soc_register_card(&pdev->dev, card);
6387 + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
6391 +static const struct of_device_id audioinjector_octo_of_match[] = {
6392 + { .compatible = "ai,audioinjector-octo-soundcard", },
6395 +MODULE_DEVICE_TABLE(of, audioinjector_octo_of_match);
6397 +static struct platform_driver audioinjector_octo_driver = {
6399 + .name = "audioinjector-octo",
6400 + .owner = THIS_MODULE,
6401 + .of_match_table = audioinjector_octo_of_match,
6403 + .probe = audioinjector_octo_probe,
6406 +module_platform_driver(audioinjector_octo_driver);
6407 +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
6408 +MODULE_DESCRIPTION("AudioInjector.net octo Soundcard");
6409 +MODULE_LICENSE("GPL v2");
6410 +MODULE_ALIAS("platform:audioinjector-octo-soundcard");
6412 +++ b/sound/soc/bcm/audioinjector-pi-soundcard.c
6415 + * ASoC Driver for AudioInjector Pi add on soundcard
6417 + * Created on: 13-May-2016
6418 + * Author: flatmax@flatmax.org
6419 + * based on code by Cliff Cai <Cliff.Cai@analog.com> for the ssm2602 machine blackfin.
6420 + * with help from Lars-Peter Clausen for simplifying the original code to use the dai_fmt field.
6421 + * i2s_node code taken from the other sound/soc/bcm machine drivers.
6423 + * Copyright (C) 2016 Flatmax Pty. Ltd.
6425 + * This program is free software; you can redistribute it and/or
6426 + * modify it under the terms of the GNU General Public License
6427 + * version 2 as published by the Free Software Foundation.
6429 + * This program is distributed in the hope that it will be useful, but
6430 + * WITHOUT ANY WARRANTY; without even the implied warranty of
6431 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6432 + * General Public License for more details.
6435 +#include <linux/module.h>
6436 +#include <linux/types.h>
6438 +#include <sound/core.h>
6439 +#include <sound/soc.h>
6440 +#include <sound/pcm_params.h>
6441 +#include <sound/control.h>
6443 +#include "../codecs/wm8731.h"
6445 +static const unsigned int bcm2835_rates_12000000[] = {
6446 + 8000, 16000, 32000, 44100, 48000, 96000, 88200,
6449 +static struct snd_pcm_hw_constraint_list bcm2835_constraints_12000000 = {
6450 + .list = bcm2835_rates_12000000,
6451 + .count = ARRAY_SIZE(bcm2835_rates_12000000),
6454 +static int snd_audioinjector_pi_soundcard_startup(struct snd_pcm_substream *substream)
6456 + /* Setup constraints, because there is a 12 MHz XTAL on the board */
6457 + snd_pcm_hw_constraint_list(substream->runtime, 0,
6458 + SNDRV_PCM_HW_PARAM_RATE,
6459 + &bcm2835_constraints_12000000);
6463 +static int snd_audioinjector_pi_soundcard_hw_params(struct snd_pcm_substream *substream,
6464 + struct snd_pcm_hw_params *params)
6466 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
6467 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
6469 + switch (params_rate(params)){
6471 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 1);
6473 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 750);
6475 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 375);
6477 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 272);
6479 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 250);
6481 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 136);
6483 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 125);
6485 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 125);
6489 +/* machine stream operations */
6490 +static struct snd_soc_ops snd_audioinjector_pi_soundcard_ops = {
6491 + .startup = snd_audioinjector_pi_soundcard_startup,
6492 + .hw_params = snd_audioinjector_pi_soundcard_hw_params,
6495 +static int audioinjector_pi_soundcard_dai_init(struct snd_soc_pcm_runtime *rtd)
6497 + return snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), WM8731_SYSCLK_XTAL, 12000000, SND_SOC_CLOCK_IN);
6500 +SND_SOC_DAILINK_DEFS(audioinjector_pi,
6501 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
6502 + DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.1-001a", "wm8731-hifi")),
6503 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
6505 +static struct snd_soc_dai_link audioinjector_pi_soundcard_dai[] = {
6507 + .name = "AudioInjector audio",
6508 + .stream_name = "AudioInjector audio",
6509 + .ops = &snd_audioinjector_pi_soundcard_ops,
6510 + .init = audioinjector_pi_soundcard_dai_init,
6511 + .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF,
6512 + SND_SOC_DAILINK_REG(audioinjector_pi),
6516 +static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
6517 + SND_SOC_DAPM_HP("Headphone Jack", NULL),
6518 + SND_SOC_DAPM_SPK("Ext Spk", NULL),
6519 + SND_SOC_DAPM_LINE("Line In Jacks", NULL),
6520 + SND_SOC_DAPM_MIC("Microphone", NULL),
6523 +static const struct snd_soc_dapm_route audioinjector_audio_map[] = {
6524 + /* headphone connected to LHPOUT, RHPOUT */
6525 + {"Headphone Jack", NULL, "LHPOUT"},
6526 + {"Headphone Jack", NULL, "RHPOUT"},
6528 + /* speaker connected to LOUT, ROUT */
6529 + {"Ext Spk", NULL, "ROUT"},
6530 + {"Ext Spk", NULL, "LOUT"},
6533 + {"Line In Jacks", NULL, "Line Input"},
6535 + /* mic is connected to Mic Jack, with WM8731 Mic Bias */
6536 + {"Microphone", NULL, "Mic Bias"},
6539 +static struct snd_soc_card snd_soc_audioinjector = {
6540 + .name = "audioinjector-pi-soundcard",
6541 + .owner = THIS_MODULE,
6542 + .dai_link = audioinjector_pi_soundcard_dai,
6543 + .num_links = ARRAY_SIZE(audioinjector_pi_soundcard_dai),
6545 + .dapm_widgets = wm8731_dapm_widgets,
6546 + .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
6547 + .dapm_routes = audioinjector_audio_map,
6548 + .num_dapm_routes = ARRAY_SIZE(audioinjector_audio_map),
6551 +static int audioinjector_pi_soundcard_probe(struct platform_device *pdev)
6553 + struct snd_soc_card *card = &snd_soc_audioinjector;
6556 + card->dev = &pdev->dev;
6558 + if (pdev->dev.of_node) {
6559 + struct snd_soc_dai_link *dai = &audioinjector_pi_soundcard_dai[0];
6560 + struct device_node *i2s_node = of_parse_phandle(pdev->dev.of_node,
6561 + "i2s-controller", 0);
6564 + dai->cpus->dai_name = NULL;
6565 + dai->cpus->of_node = i2s_node;
6566 + dai->platforms->name = NULL;
6567 + dai->platforms->of_node = i2s_node;
6569 + if (!dai->cpus->of_node) {
6570 + dev_err(&pdev->dev, "Property 'i2s-controller' missing or invalid\n");
6575 + if ((ret = devm_snd_soc_register_card(&pdev->dev, card)))
6576 + return dev_err_probe(&pdev->dev, ret, "%s\n", __func__);
6578 + dev_info(&pdev->dev, "successfully loaded\n");
6583 +static const struct of_device_id audioinjector_pi_soundcard_of_match[] = {
6584 + { .compatible = "ai,audioinjector-pi-soundcard", },
6587 +MODULE_DEVICE_TABLE(of, audioinjector_pi_soundcard_of_match);
6589 +static struct platform_driver audioinjector_pi_soundcard_driver = {
6591 + .name = "audioinjector-stereo",
6592 + .owner = THIS_MODULE,
6593 + .of_match_table = audioinjector_pi_soundcard_of_match,
6595 + .probe = audioinjector_pi_soundcard_probe,
6598 +module_platform_driver(audioinjector_pi_soundcard_driver);
6599 +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
6600 +MODULE_DESCRIPTION("AudioInjector.net Pi Soundcard");
6601 +MODULE_LICENSE("GPL v2");
6602 +MODULE_ALIAS("platform:audioinjector-pi-soundcard");
6605 +++ b/sound/soc/bcm/audiosense-pi.c
6608 + * ASoC Driver for AudioSense add on soundcard
6610 + * Bhargav A K <anur.bhargav@gmail.com>
6613 + * This program is free software; you can redistribute it and/or
6614 + * modify it under the terms of the GNU General Public License
6615 + * version 2 as published by the Free Software Foundation.
6617 + * This program is distributed in the hope that it will be useful, but
6618 + * WITHOUT ANY WARRANTY; without even the implied warranty of
6619 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6620 + * General Public License for more details.
6623 +#include <linux/module.h>
6624 +#include <linux/platform_device.h>
6625 +#include <linux/clk.h>
6626 +#include <linux/i2c.h>
6627 +#include <sound/core.h>
6628 +#include <sound/pcm.h>
6629 +#include <sound/pcm_params.h>
6630 +#include <sound/soc.h>
6631 +#include <sound/jack.h>
6632 +#include <sound/control.h>
6634 +#include <sound/tlv320aic32x4.h>
6635 +#include "../codecs/tlv320aic32x4.h"
6637 +#define AIC32X4_SYSCLK_XTAL 0x00
6640 + * Setup Codec Sample Rates and Channels
6641 + * Supported Rates:
6642 + * 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000,
6644 +static const unsigned int audiosense_pi_rate[] = {
6648 +static struct snd_pcm_hw_constraint_list audiosense_constraints_rates = {
6649 + .list = audiosense_pi_rate,
6650 + .count = ARRAY_SIZE(audiosense_pi_rate),
6653 +static const unsigned int audiosense_pi_channels[] = {
6657 +static struct snd_pcm_hw_constraint_list audiosense_constraints_ch = {
6658 + .count = ARRAY_SIZE(audiosense_pi_channels),
6659 + .list = audiosense_pi_channels,
6663 +/* Setup DAPM widgets and paths */
6664 +static const struct snd_soc_dapm_widget audiosense_pi_dapm_widgets[] = {
6665 + SND_SOC_DAPM_HP("Headphone Jack", NULL),
6666 + SND_SOC_DAPM_LINE("Line Out", NULL),
6667 + SND_SOC_DAPM_LINE("Line In", NULL),
6668 + SND_SOC_DAPM_INPUT("CM_L"),
6669 + SND_SOC_DAPM_INPUT("CM_R"),
6672 +static const struct snd_soc_dapm_route audiosense_pi_audio_map[] = {
6673 + /* Line Inputs are connected to
6678 + {"IN1_L", NULL, "Line In"},
6679 + {"IN1_R", NULL, "Line In"},
6680 + {"IN2_L", NULL, "Line In"},
6681 + {"IN2_R", NULL, "Line In"},
6682 + {"IN3_L", NULL, "Line In"},
6683 + {"IN3_R", NULL, "Line In"},
6685 + /* Mic is connected to IN2_L and IN2_R */
6686 + {"Left ADC", NULL, "Mic Bias"},
6687 + {"Right ADC", NULL, "Mic Bias"},
6689 + /* Headphone connected to HPL, HPR */
6690 + {"Headphone Jack", NULL, "HPL"},
6691 + {"Headphone Jack", NULL, "HPR"},
6693 + /* Speakers connected to LOL and LOR */
6694 + {"Line Out", NULL, "LOL"},
6695 + {"Line Out", NULL, "LOR"},
6698 +static int audiosense_pi_card_init(struct snd_soc_pcm_runtime *rtd)
6700 + /* TODO: init of the codec specific dapm data, ignore suspend/resume */
6701 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
6703 + snd_soc_component_update_bits(component, AIC32X4_MICBIAS, 0x78,
6704 + AIC32X4_MICBIAS_LDOIN |
6705 + AIC32X4_MICBIAS_2075V);
6706 + snd_soc_component_update_bits(component, AIC32X4_PWRCFG, 0x08,
6707 + AIC32X4_AVDDWEAKDISABLE);
6708 + snd_soc_component_update_bits(component, AIC32X4_LDOCTL, 0x01,
6709 + AIC32X4_LDOCTLEN);
6714 +static int audiosense_pi_card_hw_params(
6715 + struct snd_pcm_substream *substream,
6716 + struct snd_pcm_hw_params *params)
6719 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
6720 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
6722 + /* Set the codec system clock, there is a 12 MHz XTAL on the board */
6723 + ret = snd_soc_dai_set_sysclk(codec_dai, AIC32X4_SYSCLK_XTAL,
6724 + 12000000, SND_SOC_CLOCK_IN);
6726 + dev_err(rtd->card->dev,
6727 + "could not set codec driver clock params\n");
6733 +static int audiosense_pi_card_startup(struct snd_pcm_substream *substream)
6735 + struct snd_pcm_runtime *runtime = substream->runtime;
6738 + * Set codec to 48Khz Sampling, Stereo I/O and 16 bit audio
6740 + runtime->hw.channels_max = 2;
6741 + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
6742 + &audiosense_constraints_ch);
6744 + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
6745 + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
6748 + snd_pcm_hw_constraint_list(substream->runtime, 0,
6749 + SNDRV_PCM_HW_PARAM_RATE,
6750 + &audiosense_constraints_rates);
6754 +static struct snd_soc_ops audiosense_pi_card_ops = {
6755 + .startup = audiosense_pi_card_startup,
6756 + .hw_params = audiosense_pi_card_hw_params,
6759 +SND_SOC_DAILINK_DEFS(audiosense_pi,
6760 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
6761 + DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.1-0018", "tlv320aic32x4-hifi")),
6762 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
6764 +static struct snd_soc_dai_link audiosense_pi_card_dai[] = {
6766 + .name = "TLV320AIC3204 Audio",
6767 + .stream_name = "TLV320AIC3204 Hifi Audio",
6768 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
6769 + SND_SOC_DAIFMT_CBM_CFM,
6770 + .ops = &audiosense_pi_card_ops,
6771 + .init = audiosense_pi_card_init,
6772 + SND_SOC_DAILINK_REG(audiosense_pi),
6776 +static struct snd_soc_card audiosense_pi_card = {
6777 + .name = "audiosense-pi",
6778 + .driver_name = "audiosense-pi",
6779 + .dai_link = audiosense_pi_card_dai,
6780 + .owner = THIS_MODULE,
6781 + .num_links = ARRAY_SIZE(audiosense_pi_card_dai),
6782 + .dapm_widgets = audiosense_pi_dapm_widgets,
6783 + .num_dapm_widgets = ARRAY_SIZE(audiosense_pi_dapm_widgets),
6784 + .dapm_routes = audiosense_pi_audio_map,
6785 + .num_dapm_routes = ARRAY_SIZE(audiosense_pi_audio_map),
6788 +static int audiosense_pi_card_probe(struct platform_device *pdev)
6791 + struct snd_soc_card *card = &audiosense_pi_card;
6792 + struct snd_soc_dai_link *dai = &audiosense_pi_card_dai[0];
6793 + struct device_node *i2s_node = pdev->dev.of_node;
6795 + card->dev = &pdev->dev;
6798 + dev_err(&pdev->dev, "DAI not found. Missing or Invalid\n");
6802 + i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
6804 + dev_err(&pdev->dev,
6805 + "Property 'i2s-controller' missing or invalid\n");
6809 + dai->cpus->dai_name = NULL;
6810 + dai->cpus->of_node = i2s_node;
6811 + dai->platforms->name = NULL;
6812 + dai->platforms->of_node = i2s_node;
6814 + of_node_put(i2s_node);
6816 + ret = snd_soc_register_card(card);
6817 + if (ret && ret != -EPROBE_DEFER)
6818 + dev_err(&pdev->dev,
6819 + "snd_soc_register_card() failed: %d\n", ret);
6824 +static void audiosense_pi_card_remove(struct platform_device *pdev)
6826 + struct snd_soc_card *card = platform_get_drvdata(pdev);
6828 + snd_soc_unregister_card(card);
6831 +static const struct of_device_id audiosense_pi_card_of_match[] = {
6832 + { .compatible = "as,audiosense-pi", },
6835 +MODULE_DEVICE_TABLE(of, audiosense_pi_card_of_match);
6837 +static struct platform_driver audiosense_pi_card_driver = {
6839 + .name = "audiosense-snd-card",
6840 + .owner = THIS_MODULE,
6841 + .of_match_table = audiosense_pi_card_of_match,
6843 + .probe = audiosense_pi_card_probe,
6844 + .remove = audiosense_pi_card_remove,
6847 +module_platform_driver(audiosense_pi_card_driver);
6849 +MODULE_AUTHOR("Bhargav AK <anur.bhargav@gmail.com>");
6850 +MODULE_DESCRIPTION("ASoC Driver for TLV320AIC3204 Audio");
6851 +MODULE_LICENSE("GPL v2");
6852 +MODULE_ALIAS("platform:audiosense-pi");
6854 --- a/sound/soc/bcm/bcm2835-i2s.c
6855 +++ b/sound/soc/bcm/bcm2835-i2s.c
6857 #include <linux/init.h>
6858 #include <linux/io.h>
6859 #include <linux/module.h>
6860 -#include <linux/of_address.h>
6861 #include <linux/slab.h>
6863 #include <sound/core.h>
6864 @@ -620,6 +619,10 @@ static int bcm2835_i2s_prepare(struct sn
6865 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
6868 + snd_pcm_hw_constraint_minmax(substream->runtime,
6869 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 256,
6873 * Clear both FIFOs if the one that should be started
6874 * is not empty at the moment. This should only happen
6875 @@ -701,6 +704,10 @@ static int bcm2835_i2s_startup(struct sn
6876 /* Should this still be running stop it */
6877 bcm2835_i2s_stop_clock(dev);
6879 + snd_pcm_hw_constraint_minmax(substream->runtime,
6880 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
6883 /* Enable PCM block */
6884 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
6885 BCM2835_I2S_EN, BCM2835_I2S_EN);
6886 @@ -830,8 +837,7 @@ static int bcm2835_i2s_probe(struct plat
6887 struct bcm2835_i2s_dev *dev;
6890 - const __be32 *addr;
6891 - dma_addr_t dma_base;
6892 + struct resource *res;
6894 dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
6896 @@ -846,7 +852,7 @@ static int bcm2835_i2s_probe(struct plat
6897 "could not get clk\n");
6899 /* Request ioarea */
6900 - base = devm_platform_ioremap_resource(pdev, 0);
6901 + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
6903 return PTR_ERR(base);
6905 @@ -855,19 +861,11 @@ static int bcm2835_i2s_probe(struct plat
6906 if (IS_ERR(dev->i2s_regmap))
6907 return PTR_ERR(dev->i2s_regmap);
6909 - /* Set the DMA address - we have to parse DT ourselves */
6910 - addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
6912 - dev_err(&pdev->dev, "could not get DMA-register address\n");
6915 - dma_base = be32_to_cpup(addr);
6917 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
6918 - dma_base + BCM2835_I2S_FIFO_A_REG;
6919 + res->start + BCM2835_I2S_FIFO_A_REG;
6921 dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
6922 - dma_base + BCM2835_I2S_FIFO_A_REG;
6923 + res->start + BCM2835_I2S_FIFO_A_REG;
6925 /* Set the bus width */
6926 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
6928 +++ b/sound/soc/bcm/chipdip-dac.c
6931 + * ASoC Driver for ChipDip DAC
6933 + * Author: Evgenij Sapunov
6935 + * based on code by Milan Neskovic <info@justboom.co>
6936 + * based on code by Jaikumar <jaikumar@cem-solutions.net>
6938 + * Thanks to Phil Elwell (pelwell) for help.
6940 + * This program is free software; you can redistribute it and/or
6941 + * modify it under the terms of the GNU General Public License
6942 + * version 2 as published by the Free Software Foundation.
6944 + * This program is distributed in the hope that it will be useful, but
6945 + * WITHOUT ANY WARRANTY; without even the implied warranty of
6946 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6947 + * General Public License for more details.
6950 +#include <linux/module.h>
6951 +#include <linux/gpio/consumer.h>
6952 +#include <linux/platform_device.h>
6953 +#include <linux/delay.h>
6955 +#include <sound/core.h>
6956 +#include <sound/pcm.h>
6957 +#include <sound/pcm_params.h>
6958 +#include <sound/soc.h>
6959 +#include <sound/jack.h>
6961 +#define SR_BIT_0 0 //sample rate bits
6964 +#define BD_BIT_0 3 //bit depth bits
6967 +#define SAMPLE_RATE_MASK_44_1 0
6968 +#define SAMPLE_RATE_MASK_48 (1 << SR_BIT_0)
6969 +#define SAMPLE_RATE_MASK_88_2 ((1 << SR_BIT_2) | (1 << SR_BIT_1))
6970 +#define SAMPLE_RATE_MASK_96 (1 << SR_BIT_1)
6971 +#define SAMPLE_RATE_MASK_176_4 ((1 << SR_BIT_2) | (1 << SR_BIT_1) | (1 << SR_BIT_0))
6972 +#define SAMPLE_RATE_MASK_192 ((1 << SR_BIT_1) | (1 << SR_BIT_0))
6973 +#define SAMPLE_RATE_MASK ((1 << SR_BIT_2) | (1 << SR_BIT_1) | (1 << SR_BIT_0))
6975 +#define BIT_DEPTH_MASK_16 0
6976 +#define BIT_DEPTH_MASK_24 (1 << BD_BIT_0)
6977 +#define BIT_DEPTH_MASK_32 (1 << BD_BIT_1)
6978 +#define BIT_DEPTH_MASK ((1 << BD_BIT_1) | (1 << BD_BIT_0))
6980 +#define MUTE_ACTIVE 0
6981 +#define MUTE_NOT_ACTIVE 1
6983 +#define HW_PARAMS_GPIO_COUNT 5
6985 +static struct gpio_desc *mute_gpio;
6986 +static struct gpio_desc *sdwn_gpio;
6987 +static struct gpio_desc *hw_params_gpios[HW_PARAMS_GPIO_COUNT];
6988 +static int current_width;
6989 +static int current_rate;
6991 +static void snd_rpi_chipdip_dac_gpio_array_set(int value);
6992 +static void snd_rpi_chipdip_dac_gpio_set(struct gpio_desc *gpio_item, int value);
6994 +static void snd_rpi_chipdip_dac_gpio_array_set(int value)
6998 + for (i = 0; i < HW_PARAMS_GPIO_COUNT; i++)
6999 + snd_rpi_chipdip_dac_gpio_set(hw_params_gpios[i], ((value >> i) & 1));
7002 +static void snd_rpi_chipdip_dac_gpio_set(struct gpio_desc *gpio_item, int value)
7005 + gpiod_set_value_cansleep(gpio_item, value);
7008 +static int snd_rpi_chipdip_dac_init(struct snd_soc_pcm_runtime *rtd)
7013 +static int snd_rpi_chipdip_dac_hw_params(struct snd_pcm_substream *substream,
7014 + struct snd_pcm_hw_params *params)
7017 + int gpio_change_pending = 0;
7018 + int sample_rate_state = 0;
7019 + int bit_depth_state = 0;
7020 + int param_value = params_width(params);
7021 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
7023 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), 2 * 32);
7025 + if (current_width != param_value) {
7026 + current_width = param_value;
7027 + gpio_change_pending = 1;
7029 + switch (param_value) {
7031 + bit_depth_state = BIT_DEPTH_MASK_16;
7034 + bit_depth_state = BIT_DEPTH_MASK_24;
7037 + bit_depth_state = BIT_DEPTH_MASK_32;
7044 + param_value = params_rate(params);
7045 + if (current_rate != param_value) {
7046 + current_rate = param_value;
7047 + gpio_change_pending = 1;
7049 + switch (param_value) {
7051 + sample_rate_state = SAMPLE_RATE_MASK_44_1;
7054 + sample_rate_state = SAMPLE_RATE_MASK_48;
7057 + sample_rate_state = SAMPLE_RATE_MASK_88_2;
7060 + sample_rate_state = SAMPLE_RATE_MASK_96;
7063 + sample_rate_state = SAMPLE_RATE_MASK_176_4;
7066 + sample_rate_state = SAMPLE_RATE_MASK_192;
7073 + if (gpio_change_pending) {
7074 + snd_rpi_chipdip_dac_gpio_set(mute_gpio, MUTE_ACTIVE);
7075 + snd_rpi_chipdip_dac_gpio_array_set(bit_depth_state | sample_rate_state);
7077 + snd_rpi_chipdip_dac_gpio_set(mute_gpio, MUTE_NOT_ACTIVE);
7083 +static int snd_rpi_chipdip_dac_startup(struct snd_pcm_substream *substream)
7088 +static void snd_rpi_chipdip_dac_shutdown(struct snd_pcm_substream *substream)
7093 +/* machine stream operations */
7094 +static struct snd_soc_ops snd_rpi_chipdip_dac_ops = {
7095 + .hw_params = snd_rpi_chipdip_dac_hw_params,
7096 + .startup = snd_rpi_chipdip_dac_startup,
7097 + .shutdown = snd_rpi_chipdip_dac_shutdown,
7100 +SND_SOC_DAILINK_DEFS(hifi,
7101 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
7102 + DAILINK_COMP_ARRAY(COMP_CODEC("spdif-transmitter", "dit-hifi")),
7103 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
7105 +static struct snd_soc_dai_link snd_rpi_chipdip_dac_dai[] = {
7107 + .name = "ChipDip DAC",
7108 + .stream_name = "ChipDip DAC HiFi",
7109 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
7110 + SND_SOC_DAIFMT_CBM_CFM,
7111 + .ops = &snd_rpi_chipdip_dac_ops,
7112 + .init = snd_rpi_chipdip_dac_init,
7113 + SND_SOC_DAILINK_REG(hifi),
7117 +/* audio machine driver */
7118 +static struct snd_soc_card snd_rpi_chipdip_dac = {
7119 + .name = "ChipDipDAC",
7120 + .driver_name = "ChipdipDac",
7121 + .owner = THIS_MODULE,
7122 + .dai_link = snd_rpi_chipdip_dac_dai,
7123 + .num_links = ARRAY_SIZE(snd_rpi_chipdip_dac_dai),
7126 +static int snd_rpi_chipdip_dac_probe(struct platform_device *pdev)
7131 + snd_rpi_chipdip_dac.dev = &pdev->dev;
7133 + if (pdev->dev.of_node) {
7134 + struct device_node *i2s_node;
7135 + struct snd_soc_dai_link *dai = &snd_rpi_chipdip_dac_dai[0];
7136 + i2s_node = of_parse_phandle(pdev->dev.of_node,
7137 + "i2s-controller", 0);
7140 + dai->cpus->dai_name = NULL;
7141 + dai->cpus->of_node = i2s_node;
7142 + dai->platforms->name = NULL;
7143 + dai->platforms->of_node = i2s_node;
7147 + hw_params_gpios[SR_BIT_0] = devm_gpiod_get_optional(&pdev->dev, "sr0", GPIOD_OUT_LOW);
7148 + hw_params_gpios[SR_BIT_1] = devm_gpiod_get_optional(&pdev->dev, "sr1", GPIOD_OUT_LOW);
7149 + hw_params_gpios[SR_BIT_2] = devm_gpiod_get_optional(&pdev->dev, "sr2", GPIOD_OUT_LOW);
7150 + hw_params_gpios[BD_BIT_0] = devm_gpiod_get_optional(&pdev->dev, "res0", GPIOD_OUT_LOW);
7151 + hw_params_gpios[BD_BIT_1] = devm_gpiod_get_optional(&pdev->dev, "res1", GPIOD_OUT_LOW);
7152 + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_LOW);
7153 + sdwn_gpio = devm_gpiod_get_optional(&pdev->dev, "sdwn", GPIOD_OUT_HIGH);
7155 + for (i = 0; i < HW_PARAMS_GPIO_COUNT; i++) {
7156 + if (IS_ERR(hw_params_gpios[i])) {
7157 + ret = PTR_ERR(hw_params_gpios[i]);
7158 + dev_err(&pdev->dev, "failed to get hw_params gpio: %d\n", ret);
7163 + if (IS_ERR(mute_gpio)) {
7164 + ret = PTR_ERR(mute_gpio);
7165 + dev_err(&pdev->dev, "failed to get mute gpio: %d\n", ret);
7169 + if (IS_ERR(sdwn_gpio)) {
7170 + ret = PTR_ERR(sdwn_gpio);
7171 + dev_err(&pdev->dev, "failed to get sdwn gpio: %d\n", ret);
7175 + snd_rpi_chipdip_dac_gpio_set(sdwn_gpio, 1);
7177 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_chipdip_dac);
7178 + if (ret && ret != -EPROBE_DEFER)
7179 + dev_err(&pdev->dev,
7180 + "snd_soc_register_card() failed: %d\n", ret);
7185 +static const struct of_device_id snd_rpi_chipdip_dac_of_match[] = {
7186 + { .compatible = "chipdip,chipdip-dac", },
7189 +MODULE_DEVICE_TABLE(of, snd_rpi_chipdip_dac_of_match);
7191 +static struct platform_driver snd_rpi_chipdip_dac_driver = {
7193 + .name = "snd-rpi-chipdip-dac",
7194 + .owner = THIS_MODULE,
7195 + .of_match_table = snd_rpi_chipdip_dac_of_match,
7197 + .probe = snd_rpi_chipdip_dac_probe,
7200 +module_platform_driver(snd_rpi_chipdip_dac_driver);
7202 +MODULE_AUTHOR("Evgenij Sapunov <evgenij.sapunov@chipdip.ru>");
7203 +MODULE_DESCRIPTION("ASoC Driver for ChipDip DAC");
7204 +MODULE_LICENSE("GPL v2");
7206 +++ b/sound/soc/bcm/dacberry400.c
7209 + * ASoC Driver for Dacberry400 soundcard
7211 + * Ashish Vara<ashishhvara@gmail.com>
7214 + * This program is free software; you can redistribute it and/or
7215 + * modify it under the terms of the GNU General Public License
7216 + * version 2 as published by the Free Software Foundation.
7218 + * This program is distributed in the hope that it will be useful, but
7219 + * WITHOUT ANY WARRANTY; without even the implied warranty of
7220 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7221 + * General Public License for more details.
7224 +#include <linux/module.h>
7225 +#include <linux/gpio/consumer.h>
7226 +#include <linux/platform_device.h>
7227 +#include <sound/core.h>
7228 +#include <sound/pcm.h>
7229 +#include <sound/pcm_params.h>
7230 +#include <sound/soc.h>
7231 +#include <sound/jack.h>
7232 +#include <linux/i2c.h>
7233 +#include <linux/acpi.h>
7234 +#include <linux/slab.h>
7235 +#include "../sound/soc/codecs/tlv320aic3x.h"
7237 +static const struct snd_kcontrol_new dacberry400_controls[] = {
7238 + SOC_DAPM_PIN_SWITCH("MIC Jack"),
7239 + SOC_DAPM_PIN_SWITCH("Line In"),
7240 + SOC_DAPM_PIN_SWITCH("Line Out"),
7241 + SOC_DAPM_PIN_SWITCH("Headphone Jack"),
7244 +static const struct snd_soc_dapm_widget dacberry400_widgets[] = {
7245 + SND_SOC_DAPM_HP("Headphone Jack", NULL),
7246 + SND_SOC_DAPM_MIC("MIC Jack", NULL),
7247 + SND_SOC_DAPM_LINE("Line In", NULL),
7248 + SND_SOC_DAPM_LINE("Line Out", NULL),
7251 +static const struct snd_soc_dapm_route dacberry400_audio_map[] = {
7252 + {"Headphone Jack", NULL, "HPLOUT"},
7253 + {"Headphone Jack", NULL, "HPROUT"},
7255 + {"LINE1L", NULL, "Line In"},
7256 + {"LINE1R", NULL, "Line In"},
7258 + {"Line Out", NULL, "LLOUT"},
7259 + {"Line Out", NULL, "RLOUT"},
7261 + {"MIC3L", NULL, "MIC Jack"},
7262 + {"MIC3R", NULL, "MIC Jack"},
7265 +static int snd_rpi_dacberry400_init(struct snd_soc_pcm_runtime *rtd)
7267 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
7268 + struct snd_soc_component *component = codec_dai->component;
7271 + ret = snd_soc_dai_set_sysclk(codec_dai, 2, 12000000,
7272 + SND_SOC_CLOCK_OUT);
7274 + if (ret && ret != -ENOTSUPP)
7277 + snd_soc_component_write(component, HPRCOM_CFG, 0x20);
7278 + snd_soc_component_write(component, DACL1_2_HPLOUT_VOL, 0x80);
7279 + snd_soc_component_write(component, DACR1_2_HPROUT_VOL, 0x80);
7284 +static int snd_rpi_dacberry400_set_bias_level(struct snd_soc_card *card,
7285 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
7287 + struct snd_soc_pcm_runtime *rtd;
7288 + struct snd_soc_dai *codec_dai;
7289 + struct snd_soc_component *component;
7290 + struct dacberry_priv *aic3x;
7293 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
7294 + codec_dai = snd_soc_rtd_to_codec(rtd, 0);
7295 + component = codec_dai->component;
7296 + aic3x = snd_soc_component_get_drvdata(component);
7297 + if (dapm->dev != codec_dai->dev)
7301 + case SND_SOC_BIAS_PREPARE:
7302 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
7304 + /* UNMUTE ADC/DAC */
7305 + hpcom_reg = snd_soc_component_read(component, HPLCOM_CFG);
7306 + snd_soc_component_write(component, HPLCOM_CFG, hpcom_reg | 0x20);
7307 + snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x04);
7308 + snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x04);
7309 + snd_soc_component_write(component, LADC_VOL, 0x00);
7310 + snd_soc_component_write(component, RADC_VOL, 0x00);
7311 + pr_info("%s: unmute ADC/DAC\n", __func__);
7314 + case SND_SOC_BIAS_STANDBY:
7315 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
7317 + /* MUTE ADC/DAC */
7318 + snd_soc_component_write(component, LDAC_VOL, 0x80);
7319 + snd_soc_component_write(component, RDAC_VOL, 0x80);
7320 + snd_soc_component_write(component, LADC_VOL, 0x80);
7321 + snd_soc_component_write(component, RADC_VOL, 0x80);
7322 + snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x00);
7323 + snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x00);
7324 + snd_soc_component_write(component, HPLCOM_CFG, 0x00);
7325 + pr_info("%s: mute ADC/DAC\n", __func__);
7334 +static int snd_rpi_dacberry400_hw_params(struct snd_pcm_substream *substream,
7335 + struct snd_pcm_hw_params *params)
7339 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
7340 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
7341 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
7342 + struct snd_soc_component *component = codec_dai->component;
7343 + int fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
7344 + int channels = params_channels(params);
7348 + data = (LDAC2LCH | RDAC2RCH);
7349 + data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
7350 + if (params_rate(params) >= 64000)
7351 + data |= DUAL_RATE_MODE;
7352 + ret = snd_soc_component_write(component, 0x7, data);
7353 + width = params_width(params);
7355 + clock = snd_soc_component_read(component, 2);
7357 + ret = snd_soc_dai_set_bclk_ratio(cpu_dai, channels*width);
7362 +static const struct snd_soc_ops snd_rpi_dacberry400_ops = {
7363 + .hw_params = snd_rpi_dacberry400_hw_params,
7367 +SND_SOC_DAILINK_DEFS(rpi_dacberry400,
7368 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2835-i2s.0")),
7369 + DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x.1-0018", "tlv320aic3x-hifi")),
7370 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
7372 +static struct snd_soc_dai_link snd_rpi_dacberry400_dai[] = {
7374 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
7375 + SND_SOC_DAIFMT_CBS_CFS,
7376 + .init = snd_rpi_dacberry400_init,
7377 + .ops = &snd_rpi_dacberry400_ops,
7378 + .symmetric_rate = 1,
7379 + SND_SOC_DAILINK_REG(rpi_dacberry400),
7383 +static struct snd_soc_card snd_rpi_dacberry400 = {
7384 + .owner = THIS_MODULE,
7385 + .dai_link = snd_rpi_dacberry400_dai,
7386 + .num_links = ARRAY_SIZE(snd_rpi_dacberry400_dai),
7387 + .controls = dacberry400_controls,
7388 + .num_controls = ARRAY_SIZE(dacberry400_controls),
7389 + .dapm_widgets = dacberry400_widgets,
7390 + .num_dapm_widgets = ARRAY_SIZE(dacberry400_widgets),
7391 + .dapm_routes = dacberry400_audio_map,
7392 + .num_dapm_routes = ARRAY_SIZE(dacberry400_audio_map),
7393 + .set_bias_level = snd_rpi_dacberry400_set_bias_level,
7396 +static int snd_rpi_dacberry400_probe(struct platform_device *pdev)
7400 + snd_rpi_dacberry400.dev = &pdev->dev;
7402 + if (pdev->dev.of_node) {
7403 + struct device_node *i2s_node;
7404 + struct snd_soc_card *card = &snd_rpi_dacberry400;
7405 + struct snd_soc_dai_link *dai = &snd_rpi_dacberry400_dai[0];
7407 + i2s_node = of_parse_phandle(pdev->dev.of_node,
7408 + "i2s-controller", 0);
7410 + dai->cpus->dai_name = NULL;
7411 + dai->cpus->of_node = i2s_node;
7412 + dai->platforms->name = NULL;
7413 + dai->platforms->of_node = i2s_node;
7414 + of_node_put(i2s_node);
7417 + if (of_property_read_string(pdev->dev.of_node, "card_name",
7419 + card->name = "tlvaudioCODEC";
7421 + if (of_property_read_string(pdev->dev.of_node, "dai_name",
7423 + dai->name = "tlvaudio CODEC";
7427 + ret = snd_soc_register_card(&snd_rpi_dacberry400);
7429 + if (ret != -EPROBE_DEFER)
7430 + dev_err(&pdev->dev,
7431 + "snd_soc_register_card() failed: %d\n", ret);
7438 +static void snd_rpi_dacberry400_remove(struct platform_device *pdev)
7440 + snd_soc_unregister_card(&snd_rpi_dacberry400);
7443 +static const struct of_device_id dacberry400_match_id[] = {
7444 + { .compatible = "osaelectronics,dacberry400",},
7447 +MODULE_DEVICE_TABLE(of, dacberry400_match_id);
7449 +static struct platform_driver snd_rpi_dacberry400_driver = {
7451 + .name = "snd-rpi-dacberry400",
7452 + .owner = THIS_MODULE,
7453 + .of_match_table = dacberry400_match_id,
7455 + .probe = snd_rpi_dacberry400_probe,
7456 + .remove = snd_rpi_dacberry400_remove,
7459 +module_platform_driver(snd_rpi_dacberry400_driver);
7461 +MODULE_AUTHOR("Ashish Vara");
7462 +MODULE_DESCRIPTION("Dacberry400 sound card driver");
7463 +MODULE_LICENSE("GPL");
7464 +MODULE_ALIAS("platform:dacberry400");
7465 +MODULE_SOFTDEP("pre: snd-soc-tlv320aic3x");
7467 +++ b/sound/soc/bcm/digidac1-soundcard.c
7470 + * ASoC Driver for RRA DigiDAC1
7472 + * Author: José M. Tasende <vintage@redrocksaudio.es>
7473 + * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
7474 + * and the Wolfson card driver by Nikesh Oswal, <Nikesh.Oswal@wolfsonmicro.com>
7475 + * This program is free software; you can redistribute it and/or
7476 + * modify it under the terms of the GNU General Public License
7477 + * version 2 as published by the Free Software Foundation.
7479 + * This program is distributed in the hope that it will be useful, but
7480 + * WITHOUT ANY WARRANTY; without even the implied warranty of
7481 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7482 + * General Public License for more details.
7485 +#include <linux/module.h>
7486 +#include <linux/platform_device.h>
7487 +#include <linux/i2c.h>
7488 +#include <sound/core.h>
7489 +#include <sound/pcm.h>
7490 +#include <sound/pcm_params.h>
7491 +#include <sound/soc.h>
7492 +#include <sound/jack.h>
7493 +#include <sound/soc-dapm.h>
7494 +#include <sound/tlv.h>
7495 +#include <linux/regulator/consumer.h>
7497 +#include "../codecs/wm8804.h"
7498 +#include "../codecs/wm8741.h"
7500 +#define WM8741_NUM_SUPPLIES 2
7502 +/* codec private data */
7503 +struct wm8741_priv {
7504 + struct wm8741_platform_data pdata;
7505 + struct regmap *regmap;
7506 + struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
7507 + unsigned int sysclk;
7508 + const struct snd_pcm_hw_constraint_list *sysclk_constraints;
7511 +static int samplerate = 44100;
7513 +/* New Alsa Controls not exposed by original wm8741 codec driver */
7514 +/* in actual driver the att. adjustment is wrong because */
7515 +/* this DAC has a coarse attenuation register with 4dB steps */
7516 +/* and a fine level register with 0.125dB steps */
7517 +/* each register has 32 steps so combining both we have 1024 steps */
7519 +/* The original level controls from driver are removed at startup */
7520 +/* and replaced by the corrected ones. */
7521 +/* The same wm8741 driver can be used for wm8741 and wm8742 devices */
7523 +static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, 0, 13, 0);
7524 +static const DECLARE_TLV_DB_SCALE(dac_tlv_coarse, -12700, 400, 1);
7525 +static const char *w8741_dither[4] = {"Off", "RPDF", "TPDF", "HPDF"};
7526 +static const char *w8741_filter[5] = {
7527 + "Type 1", "Type 2", "Type 3", "Type 4", "Type 5"};
7528 +static const char *w8741_switch[2] = {"Off", "On"};
7529 +static const struct soc_enum w8741_enum[] = {
7530 +SOC_ENUM_SINGLE(WM8741_MODE_CONTROL_2, 0, 4, w8741_dither),/* dithering type */
7531 +SOC_ENUM_SINGLE(WM8741_FILTER_CONTROL, 0, 5, w8741_filter),/* filter type */
7532 +SOC_ENUM_SINGLE(WM8741_FORMAT_CONTROL, 6, 2, w8741_switch),/* phase invert */
7533 +SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 0, 2, w8741_switch),/* volume ramp */
7534 +SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 3, 2, w8741_switch),/* soft mute */
7537 +static const struct snd_kcontrol_new w8741_snd_controls_stereo[] = {
7538 +SOC_DOUBLE_R_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
7539 + WM8741_DACRLSB_ATTENUATION, 0, 31, 1, dac_tlv_fine),
7540 +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
7541 + WM8741_DACRMSB_ATTENUATION, 0, 31, 1, dac_tlv_coarse),
7542 +SOC_ENUM("DAC Dither", w8741_enum[0]),
7543 +SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
7544 +SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
7545 +SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
7546 +SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
7549 +static const struct snd_kcontrol_new w8741_snd_controls_mono_left[] = {
7550 +SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
7551 + 0, 31, 0, dac_tlv_fine),
7552 +SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
7553 + 0, 31, 1, dac_tlv_coarse),
7554 +SOC_ENUM("DAC Dither", w8741_enum[0]),
7555 +SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
7556 +SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
7557 +SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
7558 +SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
7561 +static const struct snd_kcontrol_new w8741_snd_controls_mono_right[] = {
7562 +SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
7563 + 0, 31, 0, dac_tlv_fine),
7564 +SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACRMSB_ATTENUATION,
7565 + 0, 31, 1, dac_tlv_coarse),
7566 +SOC_ENUM("DAC Dither", w8741_enum[0]),
7567 +SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
7568 +SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
7569 +SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
7570 +SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
7573 +static int w8741_add_controls(struct snd_soc_component *component)
7575 + struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
7577 + switch (wm8741->pdata.diff_mode) {
7578 + case WM8741_DIFF_MODE_STEREO:
7579 + case WM8741_DIFF_MODE_STEREO_REVERSED:
7580 + snd_soc_add_component_controls(component,
7581 + w8741_snd_controls_stereo,
7582 + ARRAY_SIZE(w8741_snd_controls_stereo));
7584 + case WM8741_DIFF_MODE_MONO_LEFT:
7585 + snd_soc_add_component_controls(component,
7586 + w8741_snd_controls_mono_left,
7587 + ARRAY_SIZE(w8741_snd_controls_mono_left));
7589 + case WM8741_DIFF_MODE_MONO_RIGHT:
7590 + snd_soc_add_component_controls(component,
7591 + w8741_snd_controls_mono_right,
7592 + ARRAY_SIZE(w8741_snd_controls_mono_right));
7601 +static int digidac1_soundcard_init(struct snd_soc_pcm_runtime *rtd)
7603 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
7604 + struct snd_soc_card *card = rtd->card;
7605 + struct snd_soc_pcm_runtime *wm8741_rtd;
7606 + struct snd_soc_component *wm8741_component;
7607 + struct snd_card *sound_card = card->snd_card;
7608 + struct snd_kcontrol *kctl;
7611 + wm8741_rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
7612 + if (!wm8741_rtd) {
7613 + dev_warn(card->dev, "digidac1_soundcard_init: couldn't get wm8741 rtd\n");
7616 + wm8741_component = snd_soc_rtd_to_codec(wm8741_rtd, 0)->component;
7617 + ret = w8741_add_controls(wm8741_component);
7619 + dev_warn(card->dev, "Failed to add new wm8741 controls: %d\n",
7622 + /* enable TX output */
7623 + snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x0);
7625 + kctl = snd_soc_card_get_kcontrol(card,
7626 + "Playback Volume");
7628 + kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
7629 + snd_ctl_remove(sound_card, kctl);
7631 + kctl = snd_soc_card_get_kcontrol(card,
7632 + "Fine Playback Volume");
7634 + kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
7635 + snd_ctl_remove(sound_card, kctl);
7640 +static int digidac1_soundcard_startup(struct snd_pcm_substream *substream)
7642 + /* turn on wm8804 digital output */
7643 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
7644 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
7645 + struct snd_soc_card *card = rtd->card;
7646 + struct snd_soc_pcm_runtime *wm8741_rtd;
7647 + struct snd_soc_component *wm8741_component;
7649 + snd_soc_component_update_bits(component, WM8804_PWRDN, 0x3c, 0x00);
7650 + wm8741_rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
7651 + if (!wm8741_rtd) {
7652 + dev_warn(card->dev, "digidac1_soundcard_startup: couldn't get WM8741 rtd\n");
7655 + wm8741_component = snd_soc_rtd_to_codec(wm8741_rtd, 0)->component;
7657 + /* latch wm8741 level */
7658 + snd_soc_component_update_bits(wm8741_component, WM8741_DACLLSB_ATTENUATION,
7659 + WM8741_UPDATELL, WM8741_UPDATELL);
7660 + snd_soc_component_update_bits(wm8741_component, WM8741_DACLMSB_ATTENUATION,
7661 + WM8741_UPDATELM, WM8741_UPDATELM);
7662 + snd_soc_component_update_bits(wm8741_component, WM8741_DACRLSB_ATTENUATION,
7663 + WM8741_UPDATERL, WM8741_UPDATERL);
7664 + snd_soc_component_update_bits(wm8741_component, WM8741_DACRMSB_ATTENUATION,
7665 + WM8741_UPDATERM, WM8741_UPDATERM);
7670 +static void digidac1_soundcard_shutdown(struct snd_pcm_substream *substream)
7672 + /* turn off wm8804 digital output */
7673 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
7674 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
7676 + snd_soc_component_update_bits(component, WM8804_PWRDN, 0x3c, 0x3c);
7679 +static int digidac1_soundcard_hw_params(struct snd_pcm_substream *substream,
7680 + struct snd_pcm_hw_params *params)
7682 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
7683 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
7684 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
7685 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
7686 + struct snd_soc_card *card = rtd->card;
7687 + struct snd_soc_pcm_runtime *wm8741_rtd;
7688 + struct snd_soc_component *wm8741_component;
7690 + int sysclk = 27000000;
7691 + long mclk_freq = 0;
7693 + int sampling_freq = 1;
7696 + wm8741_rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
7697 + if (!wm8741_rtd) {
7698 + dev_warn(card->dev, "digidac1_soundcard_hw_params: couldn't get WM8741 rtd\n");
7701 + wm8741_component = snd_soc_rtd_to_codec(wm8741_rtd, 0)->component;
7702 + samplerate = params_rate(params);
7704 + if (samplerate <= 96000) {
7705 + mclk_freq = samplerate*256;
7706 + mclk_div = WM8804_MCLKDIV_256FS;
7708 + mclk_freq = samplerate*128;
7709 + mclk_div = WM8804_MCLKDIV_128FS;
7712 + switch (samplerate) {
7714 + sampling_freq = 0x03;
7717 + sampling_freq = 0x00;
7720 + sampling_freq = 0x02;
7723 + sampling_freq = 0x08;
7726 + sampling_freq = 0x0a;
7729 + sampling_freq = 0x0c;
7732 + sampling_freq = 0x0e;
7735 + dev_err(card->dev,
7736 + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
7740 + snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
7741 + snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
7743 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
7744 + sysclk, SND_SOC_CLOCK_OUT);
7746 + dev_err(card->dev,
7747 + "Failed to set WM8804 SYSCLK: %d\n", ret);
7750 + /* Enable wm8804 TX output */
7751 + snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x0);
7753 + /* wm8804 Power on */
7754 + snd_soc_component_update_bits(component, WM8804_PWRDN, 0x9, 0);
7756 + /* wm8804 set sampling frequency status bits */
7757 + snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f, sampling_freq);
7759 + /* Now update wm8741 registers for the correct oversampling */
7760 + if (samplerate <= 48000)
7761 + snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
7762 + WM8741_OSR_MASK, 0x00);
7763 + else if (samplerate <= 96000)
7764 + snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
7765 + WM8741_OSR_MASK, 0x20);
7767 + snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
7768 + WM8741_OSR_MASK, 0x40);
7770 + /* wm8741 bit size */
7771 + switch (params_width(params)) {
7773 + snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
7774 + WM8741_IWL_MASK, 0x00);
7777 + snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
7778 + WM8741_IWL_MASK, 0x01);
7781 + snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
7782 + WM8741_IWL_MASK, 0x02);
7785 + snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
7786 + WM8741_IWL_MASK, 0x03);
7789 + dev_dbg(card->dev, "wm8741_hw_params: Unsupported bit size param = %d",
7790 + params_width(params));
7794 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
7796 +/* machine stream operations */
7797 +static struct snd_soc_ops digidac1_soundcard_ops = {
7798 + .hw_params = digidac1_soundcard_hw_params,
7799 + .startup = digidac1_soundcard_startup,
7800 + .shutdown = digidac1_soundcard_shutdown,
7803 +SND_SOC_DAILINK_DEFS(digidac1,
7804 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
7805 + DAILINK_COMP_ARRAY(COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
7806 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
7808 +SND_SOC_DAILINK_DEFS(digidac11,
7809 + DAILINK_COMP_ARRAY(COMP_CPU("wm8804-spdif")),
7810 + DAILINK_COMP_ARRAY(COMP_CODEC("wm8741.1-001a", "wm8741")),
7811 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
7813 +static struct snd_soc_dai_link digidac1_soundcard_dai[] = {
7815 + .name = "RRA DigiDAC1",
7816 + .stream_name = "RRA DigiDAC1 HiFi",
7817 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
7818 + SND_SOC_DAIFMT_CBM_CFM,
7819 + .ops = &digidac1_soundcard_ops,
7820 + .init = digidac1_soundcard_init,
7821 + SND_SOC_DAILINK_REG(digidac1),
7824 + .name = "RRA DigiDAC11",
7825 + .stream_name = "RRA DigiDAC11 HiFi",
7826 + .dai_fmt = SND_SOC_DAIFMT_I2S
7827 + | SND_SOC_DAIFMT_NB_NF
7828 + | SND_SOC_DAIFMT_CBS_CFS,
7829 + SND_SOC_DAILINK_REG(digidac11),
7833 +/* audio machine driver */
7834 +static struct snd_soc_card digidac1_soundcard = {
7835 + .name = "digidac1-soundcard",
7836 + .owner = THIS_MODULE,
7837 + .dai_link = digidac1_soundcard_dai,
7838 + .num_links = ARRAY_SIZE(digidac1_soundcard_dai),
7841 +static int digidac1_soundcard_probe(struct platform_device *pdev)
7845 + digidac1_soundcard.dev = &pdev->dev;
7847 + if (pdev->dev.of_node) {
7848 + struct device_node *i2s_node;
7849 + struct snd_soc_dai_link *dai = &digidac1_soundcard_dai[0];
7851 + i2s_node = of_parse_phandle(pdev->dev.of_node,
7852 + "i2s-controller", 0);
7855 + dai->cpus->dai_name = NULL;
7856 + dai->cpus->of_node = i2s_node;
7857 + dai->platforms->name = NULL;
7858 + dai->platforms->of_node = i2s_node;
7862 + ret = devm_snd_soc_register_card(&pdev->dev, &digidac1_soundcard);
7863 + if (ret && ret != -EPROBE_DEFER)
7864 + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
7870 +static const struct of_device_id digidac1_soundcard_of_match[] = {
7871 + { .compatible = "rra,digidac1-soundcard", },
7874 +MODULE_DEVICE_TABLE(of, digidac1_soundcard_of_match);
7876 +static struct platform_driver digidac1_soundcard_driver = {
7878 + .name = "digidac1-audio",
7879 + .owner = THIS_MODULE,
7880 + .of_match_table = digidac1_soundcard_of_match,
7882 + .probe = digidac1_soundcard_probe,
7885 +module_platform_driver(digidac1_soundcard_driver);
7887 +MODULE_AUTHOR("José M. Tasende <vintage@redrocksaudio.es>");
7888 +MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1");
7889 +MODULE_LICENSE("GPL v2");
7891 +++ b/sound/soc/bcm/dionaudio_loco-v2.c
7894 + * ASoC Driver for Dion Audio LOCO-V2 DAC-AMP
7896 + * Author: Miquel Blauw <info@dionaudio.nl>
7899 + * Based on the software of the RPi-DAC writen by Florian Meier
7901 + * This program is free software; you can redistribute it and/or
7902 + * modify it under the terms of the GNU General Public License
7903 + * version 2 as published by the Free Software Foundation.
7905 + * This program is distributed in the hope that it will be useful, but
7906 + * WITHOUT ANY WARRANTY; without even the implied warranty of
7907 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7908 + * General Public License for more details.
7911 +#include <linux/module.h>
7912 +#include <linux/platform_device.h>
7914 +#include <sound/core.h>
7915 +#include <sound/pcm.h>
7916 +#include <sound/pcm_params.h>
7917 +#include <sound/soc.h>
7918 +#include <sound/jack.h>
7920 +static bool digital_gain_0db_limit = true;
7922 +static int snd_rpi_dionaudio_loco_v2_init(struct snd_soc_pcm_runtime *rtd)
7924 + if (digital_gain_0db_limit) {
7926 + struct snd_soc_card *card = rtd->card;
7928 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
7930 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
7936 +SND_SOC_DAILINK_DEFS(dionaudio_loco_v2,
7937 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
7938 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
7939 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
7941 +static struct snd_soc_dai_link snd_rpi_dionaudio_loco_v2_dai[] = {
7943 + .name = "DionAudio LOCO-V2",
7944 + .stream_name = "DionAudio LOCO-V2 DAC-AMP",
7945 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
7946 + SND_SOC_DAIFMT_CBS_CFS,
7947 + .init = snd_rpi_dionaudio_loco_v2_init,
7948 + SND_SOC_DAILINK_REG(dionaudio_loco_v2),
7951 +/* audio machine driver */
7952 +static struct snd_soc_card snd_rpi_dionaudio_loco_v2 = {
7953 + .name = "Dion Audio LOCO-V2",
7954 + .owner = THIS_MODULE,
7955 + .dai_link = snd_rpi_dionaudio_loco_v2_dai,
7956 + .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_v2_dai),
7959 +static int snd_rpi_dionaudio_loco_v2_probe(struct platform_device *pdev)
7963 + snd_rpi_dionaudio_loco_v2.dev = &pdev->dev;
7965 + if (pdev->dev.of_node) {
7966 + struct device_node *i2s_node;
7967 + struct snd_soc_dai_link *dai =
7968 + &snd_rpi_dionaudio_loco_v2_dai[0];
7970 + i2s_node = of_parse_phandle(pdev->dev.of_node,
7971 + "i2s-controller", 0);
7973 + dai->cpus->dai_name = NULL;
7974 + dai->cpus->of_node = i2s_node;
7975 + dai->platforms->name = NULL;
7976 + dai->platforms->of_node = i2s_node;
7979 + digital_gain_0db_limit = !of_property_read_bool(
7980 + pdev->dev.of_node, "dionaudio,24db_digital_gain");
7983 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_dionaudio_loco_v2);
7985 + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
7991 +static const struct of_device_id dionaudio_of_match[] = {
7992 + { .compatible = "dionaudio,dionaudio-loco-v2", },
7995 +MODULE_DEVICE_TABLE(of, dionaudio_of_match);
7997 +static struct platform_driver snd_rpi_dionaudio_loco_v2_driver = {
7999 + .name = "snd-rpi-dionaudio-loco-v2",
8000 + .owner = THIS_MODULE,
8001 + .of_match_table = dionaudio_of_match,
8003 + .probe = snd_rpi_dionaudio_loco_v2_probe,
8006 +module_platform_driver(snd_rpi_dionaudio_loco_v2_driver);
8008 +MODULE_AUTHOR("Miquel Blauw <info@dionaudio.nl>");
8009 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2");
8010 +MODULE_LICENSE("GPL v2");
8012 +++ b/sound/soc/bcm/dionaudio_loco.c
8015 + * ASoC Driver for Dion Audio LOCO DAC-AMP
8017 + * Author: Miquel Blauw <info@dionaudio.nl>
8020 + * Based on the software of the RPi-DAC writen by Florian Meier
8022 + * This program is free software; you can redistribute it and/or
8023 + * modify it under the terms of the GNU General Public License
8024 + * version 2 as published by the Free Software Foundation.
8026 + * This program is distributed in the hope that it will be useful, but
8027 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8028 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8029 + * General Public License for more details.
8032 +#include <linux/module.h>
8033 +#include <linux/platform_device.h>
8035 +#include <sound/core.h>
8036 +#include <sound/pcm.h>
8037 +#include <sound/pcm_params.h>
8038 +#include <sound/soc.h>
8039 +#include <sound/jack.h>
8041 +static int snd_rpi_dionaudio_loco_hw_params(
8042 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
8044 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
8045 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
8047 + unsigned int sample_bits =
8048 + snd_pcm_format_width(params_format(params));
8050 + /* Using powers of 2 allows for an integer clock divisor */
8051 + sample_bits = sample_bits <= 16 ? 16 : 32;
8053 + return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
8056 +/* machine stream operations */
8057 +static struct snd_soc_ops snd_rpi_dionaudio_loco_ops = {
8058 + .hw_params = snd_rpi_dionaudio_loco_hw_params,
8061 +SND_SOC_DAILINK_DEFS(dionaudio_loco,
8062 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
8063 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")),
8064 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
8066 +static struct snd_soc_dai_link snd_rpi_dionaudio_loco_dai[] = {
8068 + .name = "DionAudio LOCO",
8069 + .stream_name = "DionAudio LOCO DAC-AMP",
8070 + .dai_fmt = SND_SOC_DAIFMT_I2S |
8071 + SND_SOC_DAIFMT_NB_NF |
8072 + SND_SOC_DAIFMT_CBS_CFS,
8073 + .ops = &snd_rpi_dionaudio_loco_ops,
8074 + SND_SOC_DAILINK_REG(dionaudio_loco),
8078 +/* audio machine driver */
8079 +static struct snd_soc_card snd_rpi_dionaudio_loco = {
8080 + .name = "snd_rpi_dionaudio_loco",
8081 + .owner = THIS_MODULE,
8082 + .dai_link = snd_rpi_dionaudio_loco_dai,
8083 + .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_dai),
8086 +static int snd_rpi_dionaudio_loco_probe(struct platform_device *pdev)
8088 + struct device_node *np;
8091 + snd_rpi_dionaudio_loco.dev = &pdev->dev;
8093 + np = pdev->dev.of_node;
8095 + struct snd_soc_dai_link *dai = &snd_rpi_dionaudio_loco_dai[0];
8096 + struct device_node *i2s_np;
8098 + i2s_np = of_parse_phandle(np, "i2s-controller", 0);
8100 + dai->cpus->dai_name = NULL;
8101 + dai->cpus->of_node = i2s_np;
8102 + dai->platforms->name = NULL;
8103 + dai->platforms->of_node = i2s_np;
8107 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_dionaudio_loco);
8108 + if (ret && ret != -EPROBE_DEFER)
8109 + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
8115 +static const struct of_device_id snd_rpi_dionaudio_loco_of_match[] = {
8116 + { .compatible = "dionaudio,loco-pcm5242-tpa3118", },
8117 + { /* sentinel */ },
8119 +MODULE_DEVICE_TABLE(of, snd_rpi_dionaudio_loco_of_match);
8121 +static struct platform_driver snd_rpi_dionaudio_loco_driver = {
8123 + .name = "snd-dionaudio-loco",
8124 + .owner = THIS_MODULE,
8125 + .of_match_table = snd_rpi_dionaudio_loco_of_match,
8127 + .probe = snd_rpi_dionaudio_loco_probe,
8130 +module_platform_driver(snd_rpi_dionaudio_loco_driver);
8132 +MODULE_AUTHOR("Miquel Blauw <info@dionaudio.nl>");
8133 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO");
8134 +MODULE_LICENSE("GPL v2");
8136 +++ b/sound/soc/bcm/fe-pi-audio.c
8139 + * ASoC Driver for Fe-Pi Audio Sound Card
8141 + * Author: Henry Kupis <kuupaz@gmail.com>
8143 + * based on code by Florian Meier <florian.meier@koalo.de>
8144 + * based on code by Shawn Guo <shawn.guo@linaro.org>
8146 + * This program is free software; you can redistribute it and/or
8147 + * modify it under the terms of the GNU General Public License
8148 + * version 2 as published by the Free Software Foundation.
8150 + * This program is distributed in the hope that it will be useful, but
8151 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8152 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8153 + * General Public License for more details.
8156 +#include <linux/module.h>
8157 +#include <linux/platform_device.h>
8158 +#include <linux/io.h>
8160 +#include <sound/core.h>
8161 +#include <sound/pcm.h>
8162 +#include <sound/pcm_params.h>
8163 +#include <sound/soc.h>
8164 +#include <sound/jack.h>
8166 +#include "../codecs/sgtl5000.h"
8168 +static int snd_fe_pi_audio_init(struct snd_soc_pcm_runtime *rtd)
8170 + struct snd_soc_card *card = rtd->card;
8171 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
8173 + snd_soc_dapm_force_enable_pin(&card->dapm, "LO");
8174 + snd_soc_dapm_force_enable_pin(&card->dapm, "ADC");
8175 + snd_soc_dapm_force_enable_pin(&card->dapm, "DAC");
8176 + snd_soc_dapm_force_enable_pin(&card->dapm, "HP");
8177 + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
8178 + SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
8183 +static int snd_fe_pi_audio_hw_params(struct snd_pcm_substream *substream,
8184 + struct snd_pcm_hw_params *params)
8186 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
8187 + struct device *dev = rtd->card->dev;
8188 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
8192 + /* Set SGTL5000's SYSCLK */
8193 + ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 12288000, SND_SOC_CLOCK_IN);
8195 + dev_err(dev, "could not set codec driver clock params\n");
8203 +static struct snd_soc_ops snd_fe_pi_audio_ops = {
8204 + .hw_params = snd_fe_pi_audio_hw_params,
8207 +SND_SOC_DAILINK_DEFS(fe_pi,
8208 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
8209 + DAILINK_COMP_ARRAY(COMP_CODEC("sgtl5000.1-000a", "sgtl5000")),
8210 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
8212 +static struct snd_soc_dai_link snd_fe_pi_audio_dai[] = {
8215 + .stream_name = "Fe-Pi HiFi",
8216 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
8217 + SND_SOC_DAIFMT_CBM_CFM,
8218 + .ops = &snd_fe_pi_audio_ops,
8219 + .init = snd_fe_pi_audio_init,
8220 + SND_SOC_DAILINK_REG(fe_pi),
8224 +static const struct snd_soc_dapm_route fe_pi_audio_dapm_routes[] = {
8225 + {"ADC", NULL, "Mic Bias"},
8229 +static struct snd_soc_card fe_pi_audio = {
8230 + .name = "Fe-Pi Audio",
8231 + .owner = THIS_MODULE,
8232 + .dai_link = snd_fe_pi_audio_dai,
8233 + .num_links = ARRAY_SIZE(snd_fe_pi_audio_dai),
8235 + .dapm_routes = fe_pi_audio_dapm_routes,
8236 + .num_dapm_routes = ARRAY_SIZE(fe_pi_audio_dapm_routes),
8239 +static int snd_fe_pi_audio_probe(struct platform_device *pdev)
8242 + struct snd_soc_card *card = &fe_pi_audio;
8243 + struct device_node *np = pdev->dev.of_node;
8244 + struct device_node *i2s_node;
8245 + struct snd_soc_dai_link *dai = &snd_fe_pi_audio_dai[0];
8247 + fe_pi_audio.dev = &pdev->dev;
8249 + i2s_node = of_parse_phandle(np, "i2s-controller", 0);
8251 + dev_err(&pdev->dev, "i2s_node phandle missing or invalid\n");
8255 + dai->cpus->dai_name = NULL;
8256 + dai->cpus->of_node = i2s_node;
8257 + dai->platforms->name = NULL;
8258 + dai->platforms->of_node = i2s_node;
8260 + of_node_put(i2s_node);
8262 + card->dev = &pdev->dev;
8263 + platform_set_drvdata(pdev, card);
8265 + ret = devm_snd_soc_register_card(&pdev->dev, card);
8266 + if (ret && ret != -EPROBE_DEFER)
8267 + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
8272 +static const struct of_device_id snd_fe_pi_audio_of_match[] = {
8273 + { .compatible = "fe-pi,fe-pi-audio", },
8276 +MODULE_DEVICE_TABLE(of, snd_fe_pi_audio_of_match);
8278 +static struct platform_driver snd_fe_pi_audio_driver = {
8280 + .name = "snd-fe-pi-audio",
8281 + .owner = THIS_MODULE,
8282 + .of_match_table = snd_fe_pi_audio_of_match,
8284 + .probe = snd_fe_pi_audio_probe,
8287 +module_platform_driver(snd_fe_pi_audio_driver);
8289 +MODULE_AUTHOR("Henry Kupis <fe-pi@cox.net>");
8290 +MODULE_DESCRIPTION("ASoC Driver for Fe-Pi Audio");
8291 +MODULE_LICENSE("GPL v2");
8293 +++ b/sound/soc/bcm/googlevoicehat-codec.c
8296 + * Driver for the Google voiceHAT audio codec for Raspberry Pi.
8298 + * Author: Peter Malkin <petermalkin@google.com>
8301 + * This program is free software; you can redistribute it and/or
8302 + * modify it under the terms of the GNU General Public License
8303 + * version 2 as published by the Free Software Foundation.
8305 + * This program is distributed in the hope that it will be useful, but
8306 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8307 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8308 + * General Public License for more details.
8311 +#include <linux/device.h>
8312 +#include <linux/err.h>
8313 +#include <linux/gpio.h>
8314 +#include <linux/gpio/consumer.h>
8315 +#include <linux/init.h>
8316 +#include <linux/kernel.h>
8317 +#include <linux/mod_devicetable.h>
8318 +#include <linux/module.h>
8319 +#include <linux/of.h>
8320 +#include <linux/platform_device.h>
8321 +#include <linux/version.h>
8322 +#include <sound/pcm.h>
8323 +#include <sound/soc.h>
8324 +#include <sound/soc-dai.h>
8325 +#include <sound/soc-dapm.h>
8327 +#define ICS43432_RATE_MIN_HZ 7190 /* from data sheet */
8328 +#define ICS43432_RATE_MAX_HZ 52800 /* from data sheet */
8329 +/* Delay in enabling SDMODE after clock settles to remove pop */
8330 +#define SDMODE_DELAY_MS 5
8332 +struct voicehat_priv {
8333 + struct delayed_work enable_sdmode_work;
8334 + struct gpio_desc *sdmode_gpio;
8335 + unsigned long sdmode_delay_jiffies;
8338 +static void voicehat_enable_sdmode_work(struct work_struct *work)
8340 + struct voicehat_priv *voicehat = container_of(work,
8341 + struct voicehat_priv,
8342 + enable_sdmode_work.work);
8343 + gpiod_set_value(voicehat->sdmode_gpio, 1);
8346 +static int voicehat_component_probe(struct snd_soc_component *component)
8348 + struct voicehat_priv *voicehat =
8349 + snd_soc_component_get_drvdata(component);
8351 + voicehat->sdmode_gpio = devm_gpiod_get(component->dev, "sdmode",
8353 + if (IS_ERR(voicehat->sdmode_gpio)) {
8354 + dev_err(component->dev, "Unable to allocate GPIO pin\n");
8355 + return PTR_ERR(voicehat->sdmode_gpio);
8358 + INIT_DELAYED_WORK(&voicehat->enable_sdmode_work,
8359 + voicehat_enable_sdmode_work);
8363 +static void voicehat_component_remove(struct snd_soc_component *component)
8365 + struct voicehat_priv *voicehat =
8366 + snd_soc_component_get_drvdata(component);
8368 + cancel_delayed_work_sync(&voicehat->enable_sdmode_work);
8371 +static const struct snd_soc_dapm_widget voicehat_dapm_widgets[] = {
8372 + SND_SOC_DAPM_OUTPUT("Speaker"),
8375 +static const struct snd_soc_dapm_route voicehat_dapm_routes[] = {
8376 + {"Speaker", NULL, "HiFi Playback"},
8379 +static const struct snd_soc_component_driver voicehat_component_driver = {
8380 + .probe = voicehat_component_probe,
8381 + .remove = voicehat_component_remove,
8382 + .dapm_widgets = voicehat_dapm_widgets,
8383 + .num_dapm_widgets = ARRAY_SIZE(voicehat_dapm_widgets),
8384 + .dapm_routes = voicehat_dapm_routes,
8385 + .num_dapm_routes = ARRAY_SIZE(voicehat_dapm_routes),
8388 +static int voicehat_daiops_trigger(struct snd_pcm_substream *substream, int cmd,
8389 + struct snd_soc_dai *dai)
8391 + struct snd_soc_component *component = dai->component;
8392 + struct voicehat_priv *voicehat = snd_soc_component_get_drvdata(component);
8394 + if (voicehat->sdmode_delay_jiffies == 0)
8397 + dev_dbg(dai->dev, "CMD %d", cmd);
8398 + dev_dbg(dai->dev, "Playback Active %d", dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active);
8399 + dev_dbg(dai->dev, "Capture Active %d", dai->stream[SNDRV_PCM_STREAM_CAPTURE].active);
8402 + case SNDRV_PCM_TRIGGER_START:
8403 + case SNDRV_PCM_TRIGGER_RESUME:
8404 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
8405 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
8406 + dev_info(dai->dev, "Enabling audio amp...\n");
8407 + queue_delayed_work(
8408 + system_power_efficient_wq,
8409 + &voicehat->enable_sdmode_work,
8410 + voicehat->sdmode_delay_jiffies);
8413 + case SNDRV_PCM_TRIGGER_STOP:
8414 + case SNDRV_PCM_TRIGGER_SUSPEND:
8415 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
8416 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
8417 + cancel_delayed_work(&voicehat->enable_sdmode_work);
8418 + dev_info(dai->dev, "Disabling audio amp...\n");
8419 + gpiod_set_value(voicehat->sdmode_gpio, 0);
8426 +static const struct snd_soc_dai_ops voicehat_dai_ops = {
8427 + .trigger = voicehat_daiops_trigger,
8430 +static struct snd_soc_dai_driver voicehat_dai = {
8431 + .name = "voicehat-hifi",
8433 + .stream_name = "HiFi Capture",
8434 + .channels_min = 2,
8435 + .channels_max = 2,
8436 + .rates = SNDRV_PCM_RATE_48000,
8437 + .formats = SNDRV_PCM_FMTBIT_S32_LE
8440 + .stream_name = "HiFi Playback",
8441 + .channels_min = 2,
8442 + .channels_max = 2,
8443 + .rates = SNDRV_PCM_RATE_48000,
8444 + .formats = SNDRV_PCM_FMTBIT_S32_LE
8446 + .ops = &voicehat_dai_ops,
8447 + .symmetric_rate = 1
8451 +static const struct of_device_id voicehat_ids[] = {
8452 + { .compatible = "google,voicehat", }, {}
8454 + MODULE_DEVICE_TABLE(of, voicehat_ids);
8457 +static int voicehat_platform_probe(struct platform_device *pdev)
8459 + struct voicehat_priv *voicehat;
8460 + unsigned int sdmode_delay;
8463 + voicehat = devm_kzalloc(&pdev->dev, sizeof(*voicehat), GFP_KERNEL);
8467 + ret = device_property_read_u32(&pdev->dev, "voicehat_sdmode_delay",
8471 + sdmode_delay = SDMODE_DELAY_MS;
8472 + dev_info(&pdev->dev,
8473 + "property 'voicehat_sdmode_delay' not found default 5 mS");
8475 + dev_info(&pdev->dev, "property 'voicehat_sdmode_delay' found delay= %d mS",
8478 + voicehat->sdmode_delay_jiffies = msecs_to_jiffies(sdmode_delay);
8480 + dev_set_drvdata(&pdev->dev, voicehat);
8482 + return snd_soc_register_component(&pdev->dev,
8483 + &voicehat_component_driver,
8488 +static void voicehat_platform_remove(struct platform_device *pdev)
8490 + snd_soc_unregister_component(&pdev->dev);
8493 +static struct platform_driver voicehat_driver = {
8495 + .name = "voicehat-codec",
8496 + .of_match_table = of_match_ptr(voicehat_ids),
8498 + .probe = voicehat_platform_probe,
8499 + .remove = voicehat_platform_remove,
8502 +module_platform_driver(voicehat_driver);
8504 +MODULE_DESCRIPTION("Google voiceHAT Codec driver");
8505 +MODULE_AUTHOR("Peter Malkin <petermalkin@google.com>");
8506 +MODULE_LICENSE("GPL v2");
8508 +++ b/sound/soc/bcm/hifiberry_adc.c
8510 +// SPDX-License-Identifier: GPL-2.0
8512 + * ASoC Driver for HiFiBerry ADC
8514 + * Author: Joerg Schambacher <joerg@hifiberry.com>
8517 + * This program is free software; you can redistribute it and/or
8518 + * modify it under the terms of the GNU General Public License
8519 + * version 2 as published by the Free Software Foundation.
8521 + * This program is distributed in the hope that it will be useful, but
8522 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8523 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8524 + * General Public License for more details.
8527 +#include <linux/module.h>
8528 +#include <linux/platform_device.h>
8529 +#include <linux/kernel.h>
8530 +#include <linux/clk.h>
8531 +#include <linux/kernel.h>
8532 +#include <linux/module.h>
8533 +#include <linux/of.h>
8534 +#include <linux/slab.h>
8535 +#include <linux/delay.h>
8536 +#include <linux/i2c.h>
8538 +#include <sound/core.h>
8539 +#include <sound/pcm.h>
8540 +#include <sound/pcm_params.h>
8541 +#include <sound/soc.h>
8542 +#include <sound/jack.h>
8543 +#include <sound/tlv.h>
8545 +#include "../codecs/pcm186x.h"
8546 +#include "hifiberry_adc_controls.h"
8548 +static bool leds_off;
8550 +static int pcm1863_add_controls(struct snd_soc_component *component)
8552 + snd_soc_add_component_controls(component,
8553 + pcm1863_snd_controls_card,
8554 + ARRAY_SIZE(pcm1863_snd_controls_card));
8558 +static int snd_rpi_hifiberry_adc_init(struct snd_soc_pcm_runtime *rtd)
8560 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
8561 + struct snd_soc_component *adc = codec_dai->component;
8564 + ret = pcm1863_add_controls(adc);
8566 + dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
8569 + codec_dai->driver->capture.rates =
8570 + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
8571 + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
8572 + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000;
8574 + /* set GPIO2 to output, GPIO3 input */
8575 + snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
8576 + snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
8578 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
8580 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
8585 +static int snd_rpi_hifiberry_adc_hw_params(
8586 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
8589 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
8590 + int channels = params_channels(params);
8591 + int width = snd_pcm_format_width(params_format(params));
8593 + /* Using powers of 2 allows for an integer clock divisor */
8594 + width = width <= 16 ? 16 : 32;
8596 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), channels * width);
8600 +/* machine stream operations */
8601 +static const struct snd_soc_ops snd_rpi_hifiberry_adc_ops = {
8602 + .hw_params = snd_rpi_hifiberry_adc_hw_params,
8605 +SND_SOC_DAILINK_DEFS(hifi,
8606 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
8607 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")),
8608 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
8610 +static struct snd_soc_dai_link snd_rpi_hifiberry_adc_dai[] = {
8612 + .name = "HiFiBerry ADC",
8613 + .stream_name = "HiFiBerry ADC HiFi",
8614 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
8615 + SND_SOC_DAIFMT_CBS_CFS,
8616 + .ops = &snd_rpi_hifiberry_adc_ops,
8617 + .init = snd_rpi_hifiberry_adc_init,
8618 + SND_SOC_DAILINK_REG(hifi),
8622 +/* audio machine driver */
8623 +static struct snd_soc_card snd_rpi_hifiberry_adc = {
8624 + .name = "snd_rpi_hifiberry_adc",
8625 + .driver_name = "HifiberryAdc",
8626 + .owner = THIS_MODULE,
8627 + .dai_link = snd_rpi_hifiberry_adc_dai,
8628 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_adc_dai),
8631 +static int snd_rpi_hifiberry_adc_probe(struct platform_device *pdev)
8633 + int ret = 0, i = 0;
8634 + struct snd_soc_card *card = &snd_rpi_hifiberry_adc;
8636 + snd_rpi_hifiberry_adc.dev = &pdev->dev;
8637 + if (pdev->dev.of_node) {
8638 + struct device_node *i2s_node;
8639 + struct snd_soc_dai_link *dai;
8641 + dai = &snd_rpi_hifiberry_adc_dai[0];
8642 + i2s_node = of_parse_phandle(pdev->dev.of_node,
8643 + "i2s-controller", 0);
8645 + for (i = 0; i < card->num_links; i++) {
8646 + dai->cpus->dai_name = NULL;
8647 + dai->cpus->of_node = i2s_node;
8648 + dai->platforms->name = NULL;
8649 + dai->platforms->of_node = i2s_node;
8653 + leds_off = of_property_read_bool(pdev->dev.of_node,
8654 + "hifiberry-adc,leds_off");
8655 + ret = snd_soc_register_card(&snd_rpi_hifiberry_adc);
8656 + if (ret && ret != -EPROBE_DEFER)
8657 + dev_err(&pdev->dev,
8658 + "snd_soc_register_card() failed: %d\n", ret);
8663 +static const struct of_device_id snd_rpi_hifiberry_adc_of_match[] = {
8664 + { .compatible = "hifiberry,hifiberry-adc", },
8668 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_adc_of_match);
8670 +static struct platform_driver snd_rpi_hifiberry_adc_driver = {
8672 + .name = "snd-rpi-hifiberry-adc",
8673 + .owner = THIS_MODULE,
8674 + .of_match_table = snd_rpi_hifiberry_adc_of_match,
8676 + .probe = snd_rpi_hifiberry_adc_probe,
8679 +module_platform_driver(snd_rpi_hifiberry_adc_driver);
8681 +MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
8682 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry ADC");
8683 +MODULE_LICENSE("GPL");
8685 +++ b/sound/soc/bcm/hifiberry_adc_controls.h
8687 +/* SPDX-License-Identifier: GPL-2.0 */
8689 + * ALSA mixer/Kcontrol definitions common to HiFiBerry ADCs
8691 + * used by DAC+ADC Pro (hifiberry_dacplusadcpro.c),
8692 + * ADC (hifiberry_adc.c)
8694 + * Author: Joerg Schambacher <joerg@hifiberry.com>
8697 + * This program is free software; you can redistribute it and/or
8698 + * modify it under the terms of the GNU General Public License
8699 + * version 2 as published by the Free Software Foundation.
8701 + * This program is distributed in the hope that it will be useful, but
8702 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8703 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8704 + * General Public License for more details.
8707 +static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
8708 + 0x00, 0x01, 0x02, 0x03, 0x10
8711 +static const char * const pcm186x_adcl_input_channel_sel_text[] = {
8713 + "VINL1[SE]", /* Default for ADCL */
8715 + "VINL2[SE] + VINL1[SE]",
8716 + "{VIN1P, VIN1M}[DIFF]"
8719 +static const char * const pcm186x_adcr_input_channel_sel_text[] = {
8721 + "VINR1[SE]", /* Default for ADCR */
8723 + "VINR2[SE] + VINR1[SE]",
8724 + "{VIN2P, VIN2M}[DIFF]"
8727 +static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
8728 + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
8729 + PCM186X_ADC_INPUT_SEL_MASK,
8730 + ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
8731 + pcm186x_adcl_input_channel_sel_text,
8732 + pcm186x_adc_input_channel_sel_value),
8733 + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
8734 + PCM186X_ADC_INPUT_SEL_MASK,
8735 + ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
8736 + pcm186x_adcr_input_channel_sel_text,
8737 + pcm186x_adc_input_channel_sel_value),
8740 +static const unsigned int pcm186x_mic_bias_sel_value[] = {
8744 +static const char * const pcm186x_mic_bias_sel_text[] = {
8747 + "Mic Bias with Bypass Resistor"
8750 +static const struct soc_enum pcm186x_mic_bias_sel[] = {
8751 + SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0,
8753 + ARRAY_SIZE(pcm186x_mic_bias_sel_text),
8754 + pcm186x_mic_bias_sel_text,
8755 + pcm186x_mic_bias_sel_value),
8758 +static const unsigned int pcm186x_gain_sel_value[] = {
8759 + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
8760 + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
8761 + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
8762 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
8763 + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
8764 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
8765 + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
8766 + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
8767 + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
8768 + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
8769 + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
8770 + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
8771 + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
8775 +static const char * const pcm186x_gain_sel_text[] = {
8776 + "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB",
8777 + "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB",
8778 + "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB",
8779 + "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB",
8780 + "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB",
8781 + "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB",
8782 + "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB",
8783 + "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB",
8784 + "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB",
8785 + "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB",
8786 + "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB",
8787 + "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB",
8788 + "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB",
8789 + "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB",
8790 + "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB",
8791 + "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB",
8792 + "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB",
8793 + "39.0dB", "39.5dB", "40.0dB"};
8795 +static const struct soc_enum pcm186x_gain_sel[] = {
8796 + SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0,
8798 + ARRAY_SIZE(pcm186x_gain_sel_text),
8799 + pcm186x_gain_sel_text,
8800 + pcm186x_gain_sel_value),
8801 + SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0,
8803 + ARRAY_SIZE(pcm186x_gain_sel_text),
8804 + pcm186x_gain_sel_text,
8805 + pcm186x_gain_sel_value),
8808 +static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = {
8809 + SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]),
8810 + SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]),
8811 + SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel),
8812 + SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]),
8813 + SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]),
8816 +++ b/sound/soc/bcm/hifiberry_dacplus.c
8819 + * ASoC Driver for HiFiBerry DAC+ / DAC Pro / AMP100
8821 + * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
8822 + * Copyright 2014-2015
8823 + * based on code by Florian Meier <florian.meier@koalo.de>
8824 + * Headphone/AMP100 Joerg Schambacher <joerg@hifiberry.com>
8826 + * This program is free software; you can redistribute it and/or
8827 + * modify it under the terms of the GNU General Public License
8828 + * version 2 as published by the Free Software Foundation.
8830 + * This program is distributed in the hope that it will be useful, but
8831 + * WITHOUT ANY WARRANTY; without even the implied warranty of
8832 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8833 + * General Public License for more details.
8836 +#include <linux/module.h>
8837 +#include <linux/gpio/consumer.h>
8838 +#include <../drivers/gpio/gpiolib.h>
8839 +#include <linux/platform_device.h>
8840 +#include <linux/kernel.h>
8841 +#include <linux/clk.h>
8842 +#include <linux/kernel.h>
8843 +#include <linux/module.h>
8844 +#include <linux/of.h>
8845 +#include <linux/slab.h>
8846 +#include <linux/delay.h>
8847 +#include <linux/i2c.h>
8849 +#include <sound/core.h>
8850 +#include <sound/pcm.h>
8851 +#include <sound/pcm_params.h>
8852 +#include <sound/soc.h>
8853 +#include <sound/jack.h>
8855 +#include "../codecs/pcm512x.h"
8857 +#define HIFIBERRY_DACPRO_NOCLOCK 0
8858 +#define HIFIBERRY_DACPRO_CLK44EN 1
8859 +#define HIFIBERRY_DACPRO_CLK48EN 2
8861 +struct pcm512x_priv {
8862 + struct regmap *regmap;
8866 +/* Clock rate of CLK44EN attached to GPIO6 pin */
8867 +#define CLK_44EN_RATE 22579200UL
8868 +/* Clock rate of CLK48EN attached to GPIO3 pin */
8869 +#define CLK_48EN_RATE 24576000UL
8872 +static bool snd_rpi_hifiberry_is_dacpro;
8873 +static bool digital_gain_0db_limit = true;
8874 +static bool leds_off;
8875 +static bool auto_mute;
8876 +static int mute_ext_ctl;
8877 +static int mute_ext;
8878 +static bool tas_device;
8879 +static struct gpio_desc *snd_mute_gpio;
8880 +static struct gpio_desc *snd_reset_gpio;
8881 +static struct snd_soc_card snd_rpi_hifiberry_dacplus;
8883 +static const u32 master_dai_rates[] = {
8884 + 44100, 48000, 88200, 96000,
8885 + 176400, 192000, 352800, 384000,
8888 +static const struct snd_pcm_hw_constraint_list constraints_master = {
8889 + .count = ARRAY_SIZE(master_dai_rates),
8890 + .list = master_dai_rates,
8893 +static int snd_rpi_hifiberry_dacplus_mute_set(int mute)
8895 + gpiod_set_value_cansleep(snd_mute_gpio, mute);
8899 +static int snd_rpi_hifiberry_dacplus_mute_get(struct snd_kcontrol *kcontrol,
8900 + struct snd_ctl_elem_value *ucontrol)
8902 + ucontrol->value.integer.value[0] = mute_ext;
8907 +static int snd_rpi_hifiberry_dacplus_mute_put(struct snd_kcontrol *kcontrol,
8908 + struct snd_ctl_elem_value *ucontrol)
8910 + if (mute_ext == ucontrol->value.integer.value[0])
8913 + mute_ext = ucontrol->value.integer.value[0];
8915 + return snd_rpi_hifiberry_dacplus_mute_set(mute_ext);
8918 +static const char * const mute_text[] = {"Play", "Mute"};
8919 +static const struct soc_enum hb_dacplus_opt_mute_enum =
8920 + SOC_ENUM_SINGLE_EXT(2, mute_text);
8922 +static const struct snd_kcontrol_new hb_dacplus_opt_mute_controls[] = {
8923 + SOC_ENUM_EXT("Mute(ext)", hb_dacplus_opt_mute_enum,
8924 + snd_rpi_hifiberry_dacplus_mute_get,
8925 + snd_rpi_hifiberry_dacplus_mute_put),
8928 +static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
8932 + case HIFIBERRY_DACPRO_NOCLOCK:
8933 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
8935 + case HIFIBERRY_DACPRO_CLK44EN:
8936 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
8938 + case HIFIBERRY_DACPRO_CLK48EN:
8939 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
8942 + usleep_range(3000, 4000);
8945 +static void snd_rpi_hifiberry_dacplus_clk_gpio(struct snd_soc_component *component)
8947 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
8948 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
8949 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
8952 +static bool snd_rpi_hifiberry_dacplus_is_sclk(struct snd_soc_component *component)
8956 + sck = snd_soc_component_read(component, PCM512x_RATE_DET_4);
8957 + return (!(sck & 0x40));
8960 +static bool snd_rpi_hifiberry_dacplus_is_pro_card(struct snd_soc_component *component)
8962 + bool isClk44EN, isClk48En, isNoClk;
8964 + snd_rpi_hifiberry_dacplus_clk_gpio(component);
8966 + snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
8967 + isClk44EN = snd_rpi_hifiberry_dacplus_is_sclk(component);
8969 + snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
8970 + isNoClk = snd_rpi_hifiberry_dacplus_is_sclk(component);
8972 + snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
8973 + isClk48En = snd_rpi_hifiberry_dacplus_is_sclk(component);
8975 + return (isClk44EN && isClk48En && !isNoClk);
8978 +static int snd_rpi_hifiberry_dacplus_clk_for_rate(int sample_rate)
8982 + switch (sample_rate) {
8989 + type = HIFIBERRY_DACPRO_CLK44EN;
8992 + type = HIFIBERRY_DACPRO_CLK48EN;
8998 +static void snd_rpi_hifiberry_dacplus_set_sclk(struct snd_soc_component *component,
9001 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
9003 + if (!IS_ERR(pcm512x->sclk)) {
9006 + ctype = snd_rpi_hifiberry_dacplus_clk_for_rate(sample_rate);
9007 + clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
9008 + ? CLK_44EN_RATE : CLK_48EN_RATE);
9009 + snd_rpi_hifiberry_dacplus_select_clk(component, ctype);
9013 +static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
9015 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9016 + struct pcm512x_priv *priv;
9017 + struct snd_soc_card *card = &snd_rpi_hifiberry_dacplus;
9020 + snd_rpi_hifiberry_is_dacpro = false;
9022 + snd_rpi_hifiberry_is_dacpro =
9023 + snd_rpi_hifiberry_dacplus_is_pro_card(component);
9025 + if (snd_rpi_hifiberry_is_dacpro) {
9026 + struct snd_soc_dai_link *dai = rtd->dai_link;
9029 + dai->name = "HiFiBerry AMP4 Pro";
9030 + dai->stream_name = "HiFiBerry AMP4 Pro HiFi";
9032 + dai->name = "HiFiBerry DAC+ Pro";
9033 + dai->stream_name = "HiFiBerry DAC+ Pro HiFi";
9035 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
9036 + | SND_SOC_DAIFMT_CBM_CFM;
9038 + snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
9039 + snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
9040 + snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
9042 + priv = snd_soc_component_get_drvdata(component);
9043 + priv->sclk = ERR_PTR(-ENOENT);
9046 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
9047 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
9049 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
9051 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
9053 + if (digital_gain_0db_limit) {
9055 + struct snd_soc_card *card = rtd->card;
9057 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
9059 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
9061 + if (snd_reset_gpio) {
9062 + gpiod_set_value_cansleep(snd_reset_gpio, 0);
9064 + gpiod_set_value_cansleep(snd_reset_gpio, 1);
9066 + gpiod_set_value_cansleep(snd_reset_gpio, 0);
9070 + snd_soc_add_card_controls(card, hb_dacplus_opt_mute_controls,
9071 + ARRAY_SIZE(hb_dacplus_opt_mute_controls));
9073 + if (snd_mute_gpio)
9074 + gpiod_set_value_cansleep(snd_mute_gpio, mute_ext);
9079 +static int snd_rpi_hifiberry_dacplus_update_rate_den(
9080 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
9082 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9083 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9084 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
9085 + struct snd_ratnum *rats_no_pll;
9086 + unsigned int num = 0, den = 0;
9089 + rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
9093 + rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
9094 + rats_no_pll->den_min = 1;
9095 + rats_no_pll->den_max = 128;
9096 + rats_no_pll->den_step = 1;
9098 + err = snd_interval_ratnum(hw_param_interval(params,
9099 + SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
9100 + if (err >= 0 && den) {
9101 + params->rate_num = num;
9102 + params->rate_den = den;
9105 + devm_kfree(rtd->dev, rats_no_pll);
9109 +static int snd_rpi_hifiberry_dacplus_hw_params(
9110 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
9113 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9114 + int channels = params_channels(params);
9115 + int width = snd_pcm_format_width(params_format(params));
9117 + /* Using powers of 2 allows for an integer clock divisor */
9118 + width = width <= 16 ? 16 : 32;
9120 + if (snd_rpi_hifiberry_is_dacpro) {
9121 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9123 + snd_rpi_hifiberry_dacplus_set_sclk(component,
9124 + params_rate(params));
9126 + ret = snd_rpi_hifiberry_dacplus_update_rate_den(
9127 + substream, params);
9130 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), channels * width);
9133 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), channels * width);
9137 +static int snd_rpi_hifiberry_dacplus_startup(
9138 + struct snd_pcm_substream *substream)
9140 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9141 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9144 + if (tas_device && !slave) {
9145 + ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
9146 + SNDRV_PCM_HW_PARAM_RATE,
9147 + &constraints_master);
9149 + dev_err(rtd->card->dev,
9150 + "Cannot apply constraints for sample rates\n");
9156 + gpiod_set_value_cansleep(snd_mute_gpio, 0);
9159 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
9163 +static void snd_rpi_hifiberry_dacplus_shutdown(
9164 + struct snd_pcm_substream *substream)
9166 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9167 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9169 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
9171 + gpiod_set_value_cansleep(snd_mute_gpio, 1);
9174 +/* machine stream operations */
9175 +static const struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = {
9176 + .hw_params = snd_rpi_hifiberry_dacplus_hw_params,
9177 + .startup = snd_rpi_hifiberry_dacplus_startup,
9178 + .shutdown = snd_rpi_hifiberry_dacplus_shutdown,
9181 +SND_SOC_DAILINK_DEFS(rpi_hifiberry_dacplus,
9182 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
9183 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
9184 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
9186 +static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = {
9188 + .name = "HiFiBerry DAC+",
9189 + .stream_name = "HiFiBerry DAC+ HiFi",
9190 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
9191 + SND_SOC_DAIFMT_CBS_CFS,
9192 + .ops = &snd_rpi_hifiberry_dacplus_ops,
9193 + .init = snd_rpi_hifiberry_dacplus_init,
9194 + SND_SOC_DAILINK_REG(rpi_hifiberry_dacplus),
9198 +/* aux device for optional headphone amp */
9199 +static struct snd_soc_aux_dev hifiberry_dacplus_aux_devs[] = {
9202 + .name = "tpa6130a2.1-0060",
9207 +/* audio machine driver */
9208 +static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
9209 + .name = "snd_rpi_hifiberry_dacplus",
9210 + .driver_name = "HifiberryDacp",
9211 + .owner = THIS_MODULE,
9212 + .dai_link = snd_rpi_hifiberry_dacplus_dai,
9213 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
9216 +static int hb_hp_detect(void)
9218 + struct i2c_adapter *adap = i2c_get_adapter(1);
9220 + struct i2c_client tpa_i2c_client = {
9226 + return -EPROBE_DEFER; /* I2C module not yet available */
9228 + ret = i2c_smbus_read_byte(&tpa_i2c_client) >= 0;
9229 + i2c_put_adapter(adap);
9233 +static struct property tpa_enable_prop = {
9235 + .length = 4 + 1, /* length 'okay' + 1 */
9239 +static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
9242 + struct snd_soc_card *card = &snd_rpi_hifiberry_dacplus;
9244 + struct device_node *tpa_node;
9245 + struct device_node *tas_node;
9246 + struct property *tpa_prop;
9247 + struct of_changeset ocs;
9248 + struct property *pp;
9251 + /* probe for head phone amp */
9252 + ret = hb_hp_detect();
9256 + card->aux_dev = hifiberry_dacplus_aux_devs;
9257 + card->num_aux_devs =
9258 + ARRAY_SIZE(hifiberry_dacplus_aux_devs);
9259 + tpa_node = of_find_compatible_node(NULL, NULL, "ti,tpa6130a2");
9260 + tpa_prop = of_find_property(tpa_node, "status", &len);
9262 + if (strcmp((char *)tpa_prop->value, "okay")) {
9263 + /* and activate headphone using change_sets */
9264 + dev_info(&pdev->dev, "activating headphone amplifier");
9265 + of_changeset_init(&ocs);
9266 + ret = of_changeset_update_property(&ocs, tpa_node,
9267 + &tpa_enable_prop);
9269 + dev_err(&pdev->dev,
9270 + "cannot activate headphone amplifier\n");
9273 + ret = of_changeset_apply(&ocs);
9275 + dev_err(&pdev->dev,
9276 + "cannot activate headphone amplifier\n");
9282 + tas_node = of_find_compatible_node(NULL, NULL, "ti,tas5756");
9284 + tas_device = true;
9285 + dev_info(&pdev->dev, "TAS5756 device found!\n");
9288 + snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
9289 + if (pdev->dev.of_node) {
9290 + struct device_node *i2s_node;
9291 + struct snd_soc_dai_link *dai;
9293 + dai = &snd_rpi_hifiberry_dacplus_dai[0];
9294 + i2s_node = of_parse_phandle(pdev->dev.of_node,
9295 + "i2s-controller", 0);
9298 + dai->cpus->dai_name = NULL;
9299 + dai->cpus->of_node = i2s_node;
9300 + dai->platforms->name = NULL;
9301 + dai->platforms->of_node = i2s_node;
9304 + digital_gain_0db_limit = !of_property_read_bool(
9305 + pdev->dev.of_node, "hifiberry,24db_digital_gain");
9306 + slave = of_property_read_bool(pdev->dev.of_node,
9307 + "hifiberry-dacplus,slave");
9308 + leds_off = of_property_read_bool(pdev->dev.of_node,
9309 + "hifiberry-dacplus,leds_off");
9310 + auto_mute = of_property_read_bool(pdev->dev.of_node,
9311 + "hifiberry-dacplus,auto_mute");
9314 + * check for HW MUTE as defined in DT-overlay
9315 + * active high, therefore default to HIGH to MUTE
9317 + snd_mute_gpio = devm_gpiod_get_optional(&pdev->dev,
9318 + "mute", GPIOD_OUT_HIGH);
9319 + if (IS_ERR(snd_mute_gpio)) {
9320 + dev_err(&pdev->dev, "Can't allocate GPIO (HW-MUTE)");
9321 + return PTR_ERR(snd_mute_gpio);
9324 + /* add ALSA control if requested in DT-overlay (AMP100) */
9325 + pp = of_find_property(pdev->dev.of_node,
9326 + "hifiberry-dacplus,mute_ext_ctl", &tmp);
9328 + if (!of_property_read_u32(pdev->dev.of_node,
9329 + "hifiberry-dacplus,mute_ext_ctl", &mute_ext)) {
9330 + /* ALSA control will be used */
9335 + /* check for HW RESET (AMP100) */
9336 + snd_reset_gpio = devm_gpiod_get_optional(&pdev->dev,
9337 + "reset", GPIOD_OUT_HIGH);
9338 + if (IS_ERR(snd_reset_gpio)) {
9339 + dev_err(&pdev->dev, "Can't allocate GPIO (HW-RESET)");
9340 + return PTR_ERR(snd_reset_gpio);
9345 + ret = devm_snd_soc_register_card(&pdev->dev,
9346 + &snd_rpi_hifiberry_dacplus);
9347 + if (ret && ret != -EPROBE_DEFER)
9348 + dev_err(&pdev->dev,
9349 + "snd_soc_register_card() failed: %d\n", ret);
9351 + if (snd_mute_gpio)
9352 + dev_info(&pdev->dev, "GPIO%i for HW-MUTE selected",
9353 + gpio_chip_hwgpio(snd_mute_gpio));
9354 + if (snd_reset_gpio)
9355 + dev_info(&pdev->dev, "GPIO%i for HW-RESET selected",
9356 + gpio_chip_hwgpio(snd_reset_gpio));
9361 +static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
9362 + { .compatible = "hifiberry,hifiberry-dacplus", },
9365 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
9367 +static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
9369 + .name = "snd-rpi-hifiberry-dacplus",
9370 + .owner = THIS_MODULE,
9371 + .of_match_table = snd_rpi_hifiberry_dacplus_of_match,
9373 + .probe = snd_rpi_hifiberry_dacplus_probe,
9376 +module_platform_driver(snd_rpi_hifiberry_dacplus_driver);
9378 +MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
9379 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+");
9380 +MODULE_LICENSE("GPL v2");
9382 +++ b/sound/soc/bcm/hifiberry_dacplusadc.c
9385 + * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC
9387 + * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
9388 + * Copyright 2014-2015
9389 + * based on code by Florian Meier <florian.meier@koalo.de>
9390 + * ADC added by Joerg Schambacher <joscha@schambacher.com>
9393 + * This program is free software; you can redistribute it and/or
9394 + * modify it under the terms of the GNU General Public License
9395 + * version 2 as published by the Free Software Foundation.
9397 + * This program is distributed in the hope that it will be useful, but
9398 + * WITHOUT ANY WARRANTY; without even the implied warranty of
9399 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9400 + * General Public License for more details.
9403 +#include <linux/module.h>
9404 +#include <linux/platform_device.h>
9405 +#include <linux/kernel.h>
9406 +#include <linux/clk.h>
9407 +#include <linux/kernel.h>
9408 +#include <linux/module.h>
9409 +#include <linux/of.h>
9410 +#include <linux/slab.h>
9411 +#include <linux/delay.h>
9413 +#include <sound/core.h>
9414 +#include <sound/pcm.h>
9415 +#include <sound/pcm_params.h>
9416 +#include <sound/soc.h>
9417 +#include <sound/jack.h>
9419 +#include "../codecs/pcm512x.h"
9421 +#define HIFIBERRY_DACPRO_NOCLOCK 0
9422 +#define HIFIBERRY_DACPRO_CLK44EN 1
9423 +#define HIFIBERRY_DACPRO_CLK48EN 2
9425 +struct platform_device *dmic_codec_dev;
9427 +struct pcm512x_priv {
9428 + struct regmap *regmap;
9432 +/* Clock rate of CLK44EN attached to GPIO6 pin */
9433 +#define CLK_44EN_RATE 22579200UL
9434 +/* Clock rate of CLK48EN attached to GPIO3 pin */
9435 +#define CLK_48EN_RATE 24576000UL
9438 +static bool snd_rpi_hifiberry_is_dacpro;
9439 +static bool digital_gain_0db_limit = true;
9440 +static bool leds_off;
9442 +static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
9446 + case HIFIBERRY_DACPRO_NOCLOCK:
9447 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
9449 + case HIFIBERRY_DACPRO_CLK44EN:
9450 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
9452 + case HIFIBERRY_DACPRO_CLK48EN:
9453 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
9458 +static void snd_rpi_hifiberry_dacplusadc_clk_gpio(struct snd_soc_component *component)
9460 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
9461 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
9462 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
9465 +static bool snd_rpi_hifiberry_dacplusadc_is_sclk(struct snd_soc_component *component)
9469 + sck = snd_soc_component_read(component, PCM512x_RATE_DET_4);
9470 + return (!(sck & 0x40));
9473 +static bool snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(
9474 + struct snd_soc_component *component)
9477 + return snd_rpi_hifiberry_dacplusadc_is_sclk(component);
9480 +static bool snd_rpi_hifiberry_dacplusadc_is_pro_card(struct snd_soc_component *component)
9482 + bool isClk44EN, isClk48En, isNoClk;
9484 + snd_rpi_hifiberry_dacplusadc_clk_gpio(component);
9486 + snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
9487 + isClk44EN = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
9489 + snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
9490 + isNoClk = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
9492 + snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
9493 + isClk48En = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component);
9495 + return (isClk44EN && isClk48En && !isNoClk);
9498 +static int snd_rpi_hifiberry_dacplusadc_clk_for_rate(int sample_rate)
9502 + switch (sample_rate) {
9509 + type = HIFIBERRY_DACPRO_CLK44EN;
9512 + type = HIFIBERRY_DACPRO_CLK48EN;
9518 +static void snd_rpi_hifiberry_dacplusadc_set_sclk(struct snd_soc_component *component,
9521 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
9523 + if (!IS_ERR(pcm512x->sclk)) {
9526 + ctype = snd_rpi_hifiberry_dacplusadc_clk_for_rate(sample_rate);
9527 + clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
9528 + ? CLK_44EN_RATE : CLK_48EN_RATE);
9529 + snd_rpi_hifiberry_dacplusadc_select_clk(component, ctype);
9533 +static int snd_rpi_hifiberry_dacplusadc_init(struct snd_soc_pcm_runtime *rtd)
9535 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9536 + struct pcm512x_priv *priv;
9539 + snd_rpi_hifiberry_is_dacpro = false;
9541 + snd_rpi_hifiberry_is_dacpro =
9542 + snd_rpi_hifiberry_dacplusadc_is_pro_card(component);
9544 + if (snd_rpi_hifiberry_is_dacpro) {
9545 + struct snd_soc_dai_link *dai = rtd->dai_link;
9547 + dai->name = "HiFiBerry ADCDAC+ Pro";
9548 + dai->stream_name = "HiFiBerry ADCDAC+ Pro HiFi";
9549 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
9550 + | SND_SOC_DAIFMT_CBM_CFM;
9552 + snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
9553 + snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
9554 + snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
9556 + priv = snd_soc_component_get_drvdata(component);
9557 + priv->sclk = ERR_PTR(-ENOENT);
9560 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
9561 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
9563 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
9565 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
9567 + if (digital_gain_0db_limit) {
9569 + struct snd_soc_card *card = rtd->card;
9571 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
9573 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
9579 +static int snd_rpi_hifiberry_dacplusadc_update_rate_den(
9580 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
9582 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9583 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9584 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
9585 + struct snd_ratnum *rats_no_pll;
9586 + unsigned int num = 0, den = 0;
9589 + rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
9593 + rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
9594 + rats_no_pll->den_min = 1;
9595 + rats_no_pll->den_max = 128;
9596 + rats_no_pll->den_step = 1;
9598 + err = snd_interval_ratnum(hw_param_interval(params,
9599 + SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
9600 + if (err >= 0 && den) {
9601 + params->rate_num = num;
9602 + params->rate_den = den;
9605 + devm_kfree(rtd->dev, rats_no_pll);
9609 +static int snd_rpi_hifiberry_dacplusadc_hw_params(
9610 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
9613 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9614 + int channels = params_channels(params);
9615 + int width = snd_pcm_format_width(params_format(params));
9617 + /* Using powers of 2 allows for an integer clock divisor */
9618 + width = width <= 16 ? 16 : 32;
9620 + if (snd_rpi_hifiberry_is_dacpro) {
9621 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9623 + snd_rpi_hifiberry_dacplusadc_set_sclk(component,
9624 + params_rate(params));
9626 + ret = snd_rpi_hifiberry_dacplusadc_update_rate_den(
9627 + substream, params);
9630 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), channels * width);
9633 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), channels * width);
9637 +static int hifiberry_dacplusadc_LED_cnt;
9639 +static int snd_rpi_hifiberry_dacplusadc_startup(
9640 + struct snd_pcm_substream *substream)
9642 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9643 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9647 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
9649 + hifiberry_dacplusadc_LED_cnt++;
9653 +static void snd_rpi_hifiberry_dacplusadc_shutdown(
9654 + struct snd_pcm_substream *substream)
9656 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
9657 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
9659 + hifiberry_dacplusadc_LED_cnt--;
9660 + if (!hifiberry_dacplusadc_LED_cnt)
9661 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
9665 +/* machine stream operations */
9666 +static struct snd_soc_ops snd_rpi_hifiberry_dacplusadc_ops = {
9667 + .hw_params = snd_rpi_hifiberry_dacplusadc_hw_params,
9668 + .startup = snd_rpi_hifiberry_dacplusadc_startup,
9669 + .shutdown = snd_rpi_hifiberry_dacplusadc_shutdown,
9672 +SND_SOC_DAILINK_DEFS(hifi,
9673 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
9674 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
9675 + COMP_CODEC("dmic-codec", "dmic-hifi")),
9676 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
9678 +static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadc_dai[] = {
9680 + .name = "HiFiBerry DAC+ADC",
9681 + .stream_name = "HiFiBerry DAC+ADC HiFi",
9682 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
9683 + SND_SOC_DAIFMT_CBS_CFS,
9684 + .ops = &snd_rpi_hifiberry_dacplusadc_ops,
9685 + .init = snd_rpi_hifiberry_dacplusadc_init,
9686 + SND_SOC_DAILINK_REG(hifi),
9690 +/* audio machine driver */
9691 +static struct snd_soc_card snd_rpi_hifiberry_dacplusadc = {
9692 + .name = "snd_rpi_hifiberry_dacplusadc",
9693 + .driver_name = "HifiberryDacpAdc",
9694 + .owner = THIS_MODULE,
9695 + .dai_link = snd_rpi_hifiberry_dacplusadc_dai,
9696 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadc_dai),
9700 +static int snd_rpi_hifiberry_dacplusadc_probe(struct platform_device *pdev)
9704 + snd_rpi_hifiberry_dacplusadc.dev = &pdev->dev;
9705 + if (pdev->dev.of_node) {
9706 + struct device_node *i2s_node;
9707 + struct snd_soc_dai_link *dai;
9709 + dai = &snd_rpi_hifiberry_dacplusadc_dai[0];
9710 + i2s_node = of_parse_phandle(pdev->dev.of_node,
9711 + "i2s-controller", 0);
9713 + dai->cpus->of_node = i2s_node;
9714 + dai->platforms->of_node = i2s_node;
9715 + dai->cpus->dai_name = NULL;
9716 + dai->platforms->name = NULL;
9719 + digital_gain_0db_limit = !of_property_read_bool(
9720 + pdev->dev.of_node, "hifiberry,24db_digital_gain");
9721 + slave = of_property_read_bool(pdev->dev.of_node,
9722 + "hifiberry-dacplusadc,slave");
9723 + leds_off = of_property_read_bool(pdev->dev.of_node,
9724 + "hifiberry-dacplusadc,leds_off");
9726 + ret = devm_snd_soc_register_card(&pdev->dev,
9727 + &snd_rpi_hifiberry_dacplusadc);
9728 + if (ret && ret != -EPROBE_DEFER)
9729 + dev_err(&pdev->dev,
9730 + "snd_soc_register_card() failed: %d\n", ret);
9735 +static const struct of_device_id snd_rpi_hifiberry_dacplusadc_of_match[] = {
9736 + { .compatible = "hifiberry,hifiberry-dacplusadc", },
9740 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadc_of_match);
9742 +static struct platform_driver snd_rpi_hifiberry_dacplusadc_driver = {
9744 + .name = "snd-rpi-hifiberry-dacplusadc",
9745 + .owner = THIS_MODULE,
9746 + .of_match_table = snd_rpi_hifiberry_dacplusadc_of_match,
9748 + .probe = snd_rpi_hifiberry_dacplusadc_probe,
9751 +static int __init hifiberry_dacplusadc_init(void)
9755 + dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
9757 + if (IS_ERR(dmic_codec_dev)) {
9758 + pr_err("%s: dmic-codec device registration failed\n", __func__);
9759 + return PTR_ERR(dmic_codec_dev);
9762 + ret = platform_driver_register(&snd_rpi_hifiberry_dacplusadc_driver);
9764 + pr_err("%s: platform driver registration failed\n", __func__);
9765 + platform_device_unregister(dmic_codec_dev);
9770 +module_init(hifiberry_dacplusadc_init);
9772 +static void __exit hifiberry_dacplusadc_exit(void)
9774 + platform_driver_unregister(&snd_rpi_hifiberry_dacplusadc_driver);
9775 + platform_device_unregister(dmic_codec_dev);
9777 +module_exit(hifiberry_dacplusadc_exit);
9779 +MODULE_AUTHOR("Joerg Schambacher <joscha@schambacher.com>");
9780 +MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
9781 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
9782 +MODULE_LICENSE("GPL v2");
9784 +++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
9787 + * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control)
9789 + * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
9790 + * Copyright 2014-2015
9791 + * based on code by Florian Meier <florian.meier@koalo.de>
9792 + * ADC, HP added by Joerg Schambacher <joerg@hifiberry.com>
9793 + * Copyright 2018-21
9795 + * This program is free software; you can redistribute it and/or
9796 + * modify it under the terms of the GNU General Public License
9797 + * version 2 as published by the Free Software Foundation.
9799 + * This program is distributed in the hope that it will be useful, but
9800 + * WITHOUT ANY WARRANTY; without even the implied warranty of
9801 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9802 + * General Public License for more details.
9805 +#include <linux/module.h>
9806 +#include <linux/platform_device.h>
9807 +#include <linux/kernel.h>
9808 +#include <linux/clk.h>
9809 +#include <linux/kernel.h>
9810 +#include <linux/module.h>
9811 +#include <linux/of.h>
9812 +#include <linux/slab.h>
9813 +#include <linux/delay.h>
9814 +#include <linux/i2c.h>
9816 +#include <sound/core.h>
9817 +#include <sound/pcm.h>
9818 +#include <sound/pcm_params.h>
9819 +#include <sound/soc.h>
9820 +#include <sound/jack.h>
9821 +#include <sound/tlv.h>
9823 +#include "../codecs/pcm512x.h"
9824 +#include "../codecs/pcm186x.h"
9825 +#include "hifiberry_adc_controls.h"
9827 +#define HIFIBERRY_DACPRO_NOCLOCK 0
9828 +#define HIFIBERRY_DACPRO_CLK44EN 1
9829 +#define HIFIBERRY_DACPRO_CLK48EN 2
9831 +struct pcm512x_priv {
9832 + struct regmap *regmap;
9836 +/* Clock rate of CLK44EN attached to GPIO6 pin */
9837 +#define CLK_44EN_RATE 22579200UL
9838 +/* Clock rate of CLK48EN attached to GPIO3 pin */
9839 +#define CLK_48EN_RATE 24576000UL
9842 +static bool snd_rpi_hifiberry_is_dacpro;
9843 +static bool digital_gain_0db_limit = true;
9844 +static bool leds_off;
9846 +static int pcm1863_add_controls(struct snd_soc_component *component)
9848 + snd_soc_add_component_controls(component,
9849 + pcm1863_snd_controls_card,
9850 + ARRAY_SIZE(pcm1863_snd_controls_card));
9854 +static void snd_rpi_hifiberry_dacplusadcpro_select_clk(
9855 + struct snd_soc_component *component, int clk_id)
9858 + case HIFIBERRY_DACPRO_NOCLOCK:
9859 + snd_soc_component_update_bits(component,
9860 + PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
9862 + case HIFIBERRY_DACPRO_CLK44EN:
9863 + snd_soc_component_update_bits(component,
9864 + PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
9866 + case HIFIBERRY_DACPRO_CLK48EN:
9867 + snd_soc_component_update_bits(component,
9868 + PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
9871 + usleep_range(3000, 4000);
9874 +static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component)
9876 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
9877 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
9878 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
9881 +static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component)
9885 + sck = snd_soc_component_read(component, PCM512x_RATE_DET_4);
9886 + return (!(sck & 0x40));
9889 +static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component)
9891 + bool isClk44EN, isClk48En, isNoClk;
9893 + snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component);
9895 + snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
9896 + isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
9898 + snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
9899 + isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
9901 + snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
9902 + isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
9904 + return (isClk44EN && isClk48En && !isNoClk);
9907 +static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate)
9911 + switch (sample_rate) {
9918 + type = HIFIBERRY_DACPRO_CLK44EN;
9921 + type = HIFIBERRY_DACPRO_CLK48EN;
9927 +static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component,
9930 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
9932 + if (!IS_ERR(pcm512x->sclk)) {
9935 + ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate);
9936 + clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
9937 + ? CLK_44EN_RATE : CLK_48EN_RATE);
9938 + snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype);
9942 +static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd)
9944 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 0)->component;
9945 + struct snd_soc_component *adc = snd_soc_rtd_to_codec(rtd, 1)->component;
9946 + struct snd_soc_dai_driver *adc_driver = snd_soc_rtd_to_codec(rtd, 1)->driver;
9947 + struct pcm512x_priv *priv;
9951 + snd_rpi_hifiberry_is_dacpro = false;
9953 + snd_rpi_hifiberry_is_dacpro =
9954 + snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac);
9956 + if (snd_rpi_hifiberry_is_dacpro) {
9957 + struct snd_soc_dai_link *dai = rtd->dai_link;
9959 + dai->name = "HiFiBerry DAC+ADC Pro";
9960 + dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
9961 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
9962 + | SND_SOC_DAIFMT_CBM_CFM;
9964 + // set DAC DAI configuration
9965 + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0),
9966 + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
9967 + | SND_SOC_DAIFMT_CBM_CFM);
9971 + // set ADC DAI configuration
9972 + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 1),
9973 + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
9974 + | SND_SOC_DAIFMT_CBS_CFS);
9978 + // set CPU DAI configuration
9979 + ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
9980 + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
9984 + snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
9985 + snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03);
9986 + snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
9988 + priv = snd_soc_component_get_drvdata(dac);
9989 + priv->sclk = ERR_PTR(-ENOENT);
9992 + /* disable 24bit mode as long as I2S module does not have sign extension fixed */
9993 + adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE;
9995 + snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
9996 + snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
9998 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
10000 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
10002 + ret = pcm1863_add_controls(adc);
10004 + dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
10007 + /* set GPIO2 to output, GPIO3 input */
10008 + snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
10009 + snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
10011 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
10013 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
10015 + if (digital_gain_0db_limit) {
10017 + struct snd_soc_card *card = rtd->card;
10019 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
10021 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
10027 +static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
10028 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
10030 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10031 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; /* only use DAC */
10032 + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
10033 + struct snd_ratnum *rats_no_pll;
10034 + unsigned int num = 0, den = 0;
10037 + rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
10038 + if (!rats_no_pll)
10041 + rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
10042 + rats_no_pll->den_min = 1;
10043 + rats_no_pll->den_max = 128;
10044 + rats_no_pll->den_step = 1;
10046 + err = snd_interval_ratnum(hw_param_interval(params,
10047 + SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
10048 + if (err >= 0 && den) {
10049 + params->rate_num = num;
10050 + params->rate_den = den;
10053 + devm_kfree(rtd->dev, rats_no_pll);
10057 +static int snd_rpi_hifiberry_dacplusadcpro_hw_params(
10058 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
10061 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10062 + int channels = params_channels(params);
10063 + int width = snd_pcm_format_width(params_format(params));
10064 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 0)->component;
10065 + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
10066 + struct snd_soc_dai_driver *drv = dai->driver;
10067 + const struct snd_soc_dai_ops *ops = drv->ops;
10069 + /* Using powers of 2 allows for an integer clock divisor */
10070 + width = width <= 16 ? 16 : 32;
10072 + if (snd_rpi_hifiberry_is_dacpro) {
10073 + snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac,
10074 + params_rate(params));
10076 + ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
10077 + substream, params);
10082 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_cpu(rtd, 0), channels * width);
10085 + ret = snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), channels * width);
10088 + if (snd_rpi_hifiberry_is_dacpro && ops->hw_params)
10089 + ret = ops->hw_params(substream, params, dai);
10093 +static int snd_rpi_hifiberry_dacplusadcpro_startup(
10094 + struct snd_pcm_substream *substream)
10096 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10097 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 0)->component;
10098 + struct snd_soc_component *adc = snd_soc_rtd_to_codec(rtd, 1)->component;
10102 + /* switch on respective LED */
10103 + if (!substream->stream)
10104 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
10106 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
10110 +static void snd_rpi_hifiberry_dacplusadcpro_shutdown(
10111 + struct snd_pcm_substream *substream)
10113 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10114 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 0)->component;
10115 + struct snd_soc_component *adc = snd_soc_rtd_to_codec(rtd, 1)->component;
10117 + /* switch off respective LED */
10118 + if (!substream->stream)
10119 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
10121 + snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
10125 +/* machine stream operations */
10126 +static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = {
10127 + .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params,
10128 + .startup = snd_rpi_hifiberry_dacplusadcpro_startup,
10129 + .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
10132 +SND_SOC_DAILINK_DEFS(hifi,
10133 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
10134 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
10135 + COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")),
10136 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
10138 +static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
10140 + .name = "HiFiBerry DAC+ADC PRO",
10141 + .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
10142 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
10143 + SND_SOC_DAIFMT_CBS_CFS,
10144 + .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
10145 + .init = snd_rpi_hifiberry_dacplusadcpro_init,
10146 + SND_SOC_DAILINK_REG(hifi),
10150 +/* aux device for optional headphone amp */
10151 +static struct snd_soc_aux_dev hifiberry_dacplusadcpro_aux_devs[] = {
10154 + .name = "tpa6130a2.1-0060",
10159 +/* audio machine driver */
10160 +static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = {
10161 + .name = "snd_rpi_hifiberry_dacplusadcpro",
10162 + .driver_name = "HifiberryDacpAdcPro",
10163 + .owner = THIS_MODULE,
10164 + .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai,
10165 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai),
10168 +static int hb_hp_detect(void)
10170 + struct i2c_adapter *adap = i2c_get_adapter(1);
10172 + struct i2c_client tpa_i2c_client = {
10178 + return -EPROBE_DEFER; /* I2C module not yet available */
10180 + ret = i2c_smbus_read_byte(&tpa_i2c_client) >= 0;
10181 + i2c_put_adapter(adap);
10185 +static struct property tpa_enable_prop = {
10186 + .name = "status",
10187 + .length = 4 + 1, /* length 'okay' + 1 */
10191 +static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev)
10193 + int ret = 0, i = 0;
10194 + struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro;
10195 + struct device_node *tpa_node;
10196 + struct property *tpa_prop;
10197 + struct of_changeset ocs;
10200 + /* probe for head phone amp */
10201 + ret = hb_hp_detect();
10205 + card->aux_dev = hifiberry_dacplusadcpro_aux_devs;
10206 + card->num_aux_devs =
10207 + ARRAY_SIZE(hifiberry_dacplusadcpro_aux_devs);
10208 + tpa_node = of_find_compatible_node(NULL, NULL, "ti,tpa6130a2");
10209 + tpa_prop = of_find_property(tpa_node, "status", &len);
10211 + if (strcmp((char *)tpa_prop->value, "okay")) {
10212 + /* and activate headphone using change_sets */
10213 + dev_info(&pdev->dev, "activating headphone amplifier");
10214 + of_changeset_init(&ocs);
10215 + ret = of_changeset_update_property(&ocs, tpa_node,
10216 + &tpa_enable_prop);
10218 + dev_err(&pdev->dev,
10219 + "cannot activate headphone amplifier\n");
10222 + ret = of_changeset_apply(&ocs);
10224 + dev_err(&pdev->dev,
10225 + "cannot activate headphone amplifier\n");
10231 + snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev;
10232 + if (pdev->dev.of_node) {
10233 + struct device_node *i2s_node;
10234 + struct snd_soc_dai_link *dai;
10236 + dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0];
10237 + i2s_node = of_parse_phandle(pdev->dev.of_node,
10238 + "i2s-controller", 0);
10240 + for (i = 0; i < card->num_links; i++) {
10241 + dai->cpus->dai_name = NULL;
10242 + dai->cpus->of_node = i2s_node;
10243 + dai->platforms->name = NULL;
10244 + dai->platforms->of_node = i2s_node;
10248 + digital_gain_0db_limit = !of_property_read_bool(
10249 + pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
10250 + slave = of_property_read_bool(pdev->dev.of_node,
10251 + "hifiberry-dacplusadcpro,slave");
10252 + leds_off = of_property_read_bool(pdev->dev.of_node,
10253 + "hifiberry-dacplusadcpro,leds_off");
10254 + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
10255 + if (ret && ret != -EPROBE_DEFER)
10256 + dev_err(&pdev->dev,
10257 + "snd_soc_register_card() failed: %d\n", ret);
10262 +static const struct of_device_id snd_rpi_hifiberry_dacplusadcpro_of_match[] = {
10263 + { .compatible = "hifiberry,hifiberry-dacplusadcpro", },
10267 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match);
10269 +static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = {
10271 + .name = "snd-rpi-hifiberry-dacplusadcpro",
10272 + .owner = THIS_MODULE,
10273 + .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match,
10275 + .probe = snd_rpi_hifiberry_dacplusadcpro_probe,
10278 +module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver);
10280 +MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
10281 +MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
10282 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
10283 +MODULE_LICENSE("GPL v2");
10285 +++ b/sound/soc/bcm/hifiberry_dacplusdsp.c
10287 +// SPDX-License-Identifier: GPL-2.0
10289 + * ASoC Driver for HiFiBerry DAC + DSP
10291 + * Author: Joerg Schambacher <joscha@schambacher.com>
10294 + * This program is free software; you can redistribute it and/or
10295 + * modify it under the terms of the GNU General Public License
10296 + * version 2 as published by the Free Software Foundation.
10298 + * This program is distributed in the hope that it will be useful, but
10299 + * WITHOUT ANY WARRANTY; without even the implied warranty of
10300 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10301 + * General Public License for more details.
10304 +#include <linux/init.h>
10305 +#include <linux/module.h>
10306 +#include <linux/of.h>
10307 +#include <linux/platform_device.h>
10308 +#include <sound/soc.h>
10310 +static struct snd_soc_component_driver dacplusdsp_component_driver;
10312 +static struct snd_soc_dai_driver dacplusdsp_dai = {
10313 + .name = "dacplusdsp-hifi",
10315 + .stream_name = "DAC+DSP Capture",
10316 + .channels_min = 2,
10317 + .channels_max = 2,
10318 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
10319 + .formats = SNDRV_PCM_FMTBIT_S16_LE |
10320 + SNDRV_PCM_FMTBIT_S24_LE |
10321 + SNDRV_PCM_FMTBIT_S32_LE,
10324 + .stream_name = "DACP+DSP Playback",
10325 + .channels_min = 2,
10326 + .channels_max = 2,
10327 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
10328 + .formats = SNDRV_PCM_FMTBIT_S16_LE |
10329 + SNDRV_PCM_FMTBIT_S24_LE |
10330 + SNDRV_PCM_FMTBIT_S32_LE,
10332 + .symmetric_rate = 1};
10335 +static const struct of_device_id dacplusdsp_ids[] = {
10337 + .compatible = "hifiberry,dacplusdsp",
10340 +MODULE_DEVICE_TABLE(of, dacplusdsp_ids);
10343 +static int dacplusdsp_platform_probe(struct platform_device *pdev)
10347 + ret = snd_soc_register_component(&pdev->dev,
10348 + &dacplusdsp_component_driver, &dacplusdsp_dai, 1);
10350 + pr_alert("snd_soc_register_component failed\n");
10357 +static void dacplusdsp_platform_remove(struct platform_device *pdev)
10359 + snd_soc_unregister_component(&pdev->dev);
10362 +static struct platform_driver dacplusdsp_driver = {
10364 + .name = "hifiberry-dacplusdsp-codec",
10365 + .of_match_table = of_match_ptr(dacplusdsp_ids),
10367 + .probe = dacplusdsp_platform_probe,
10368 + .remove = dacplusdsp_platform_remove,
10371 +module_platform_driver(dacplusdsp_driver);
10373 +MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
10374 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP");
10375 +MODULE_LICENSE("GPL v2");
10377 +++ b/sound/soc/bcm/hifiberry_dacplushd.c
10379 +// SPDX-License-Identifier: GPL-2.0
10381 + * ASoC Driver for HiFiBerry DAC+ HD
10383 + * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
10386 + * This program is free software; you can redistribute it and/or
10387 + * modify it under the terms of the GNU General Public License
10388 + * version 2 as published by the Free Software Foundation.
10390 + * This program is distributed in the hope that it will be useful, but
10391 + * WITHOUT ANY WARRANTY; without even the implied warranty of
10392 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10393 + * General Public License for more details.
10396 +#include <linux/module.h>
10397 +#include <linux/platform_device.h>
10398 +#include <linux/kernel.h>
10399 +#include <linux/delay.h>
10400 +#include <linux/module.h>
10401 +#include <linux/of.h>
10402 +#include <linux/delay.h>
10403 +#include <linux/gpio.h>
10404 +#include <linux/gpio/consumer.h>
10405 +#include <sound/core.h>
10406 +#include <sound/pcm.h>
10407 +#include <sound/pcm_params.h>
10408 +#include <sound/soc.h>
10409 +#include <linux/i2c.h>
10410 +#include <linux/clk.h>
10412 +#include "../codecs/pcm179x.h"
10414 +#define DEFAULT_RATE 44100
10416 +struct brd_drv_data {
10417 + struct regmap *regmap;
10418 + struct clk *sclk;
10421 +static struct brd_drv_data drvdata;
10422 +static struct gpio_desc *reset_gpio;
10423 +static const unsigned int hb_dacplushd_rates[] = {
10424 + 192000, 96000, 48000, 176400, 88200, 44100,
10427 +static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
10428 + .list = hb_dacplushd_rates,
10429 + .count = ARRAY_SIZE(hb_dacplushd_rates),
10432 +static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
10434 + /* constraints for standard sample rates */
10435 + snd_pcm_hw_constraint_list(substream->runtime, 0,
10436 + SNDRV_PCM_HW_PARAM_RATE,
10437 + &hb_dacplushd_constraints);
10441 +static void snd_rpi_hifiberry_dacplushd_set_sclk(
10442 + struct snd_soc_component *component,
10445 + if (!IS_ERR(drvdata.sclk))
10446 + clk_set_rate(drvdata.sclk, sample_rate);
10449 +static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
10451 + struct snd_soc_dai_link *dai = rtd->dai_link;
10452 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
10454 + dai->name = "HiFiBerry DAC+ HD";
10455 + dai->stream_name = "HiFiBerry DAC+ HD HiFi";
10456 + dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
10457 + | SND_SOC_DAIFMT_CBM_CFM;
10459 + /* allow only fixed 32 clock counts per channel */
10460 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
10465 +static int snd_rpi_hifiberry_dacplushd_hw_params(
10466 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
10469 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10471 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
10473 + snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
10477 +/* machine stream operations */
10478 +static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
10479 + .startup = snd_rpi_hb_dacplushd_startup,
10480 + .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
10483 +SND_SOC_DAILINK_DEFS(hifi,
10484 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
10485 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")),
10486 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
10489 +static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
10491 + .name = "HiFiBerry DAC+ HD",
10492 + .stream_name = "HiFiBerry DAC+ HD HiFi",
10493 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
10494 + SND_SOC_DAIFMT_CBS_CFS,
10495 + .ops = &snd_rpi_hifiberry_dacplushd_ops,
10496 + .init = snd_rpi_hifiberry_dacplushd_init,
10497 + SND_SOC_DAILINK_REG(hifi),
10501 +/* audio machine driver */
10502 +static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
10503 + .name = "snd_rpi_hifiberry_dacplushd",
10504 + .driver_name = "HifiberryDacplusHD",
10505 + .owner = THIS_MODULE,
10506 + .dai_link = snd_rpi_hifiberry_dacplushd_dai,
10507 + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
10510 +static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
10513 + static int dac_reset_done;
10514 + struct device *dev = &pdev->dev;
10515 + struct device_node *dev_node = dev->of_node;
10517 + snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
10519 + /* get GPIO and release DAC from RESET */
10520 + if (!dac_reset_done) {
10521 + reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
10522 + if (IS_ERR(reset_gpio)) {
10523 + dev_err(&pdev->dev, "gpiod_get() failed\n");
10526 + dac_reset_done = 1;
10528 + if (!IS_ERR(reset_gpio))
10529 + gpiod_set_value(reset_gpio, 0);
10531 + if (!IS_ERR(reset_gpio))
10532 + gpiod_set_value(reset_gpio, 1);
10534 + if (!IS_ERR(reset_gpio))
10535 + gpiod_set_value(reset_gpio, 0);
10537 + if (pdev->dev.of_node) {
10538 + struct device_node *i2s_node;
10539 + struct snd_soc_dai_link *dai;
10541 + dai = &snd_rpi_hifiberry_dacplushd_dai[0];
10542 + i2s_node = of_parse_phandle(pdev->dev.of_node,
10543 + "i2s-controller", 0);
10546 + dai->cpus->of_node = i2s_node;
10547 + dai->platforms->of_node = i2s_node;
10548 + dai->cpus->dai_name = NULL;
10549 + dai->platforms->name = NULL;
10551 + return -EPROBE_DEFER;
10556 + ret = devm_snd_soc_register_card(&pdev->dev,
10557 + &snd_rpi_hifiberry_dacplushd);
10558 + if (ret && ret != -EPROBE_DEFER) {
10559 + dev_err(&pdev->dev,
10560 + "snd_soc_register_card() failed: %d\n", ret);
10563 + if (ret == -EPROBE_DEFER)
10566 + dev_set_drvdata(dev, &drvdata);
10567 + if (dev_node == NULL) {
10568 + dev_err(&pdev->dev, "Device tree node not found\n");
10572 + drvdata.sclk = devm_clk_get(dev, NULL);
10573 + if (IS_ERR(drvdata.sclk)) {
10574 + drvdata.sclk = ERR_PTR(-ENOENT);
10578 + clk_set_rate(drvdata.sclk, DEFAULT_RATE);
10583 +static void snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
10585 + /* put DAC into RESET and release GPIO */
10586 + gpiod_set_value(reset_gpio, 0);
10587 + gpiod_put(reset_gpio);
10590 +static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
10591 + { .compatible = "hifiberry,hifiberry-dacplushd", },
10595 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
10597 +static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
10599 + .name = "snd-rpi-hifiberry-dacplushd",
10600 + .owner = THIS_MODULE,
10601 + .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
10603 + .probe = snd_rpi_hifiberry_dacplushd_probe,
10604 + .remove = snd_rpi_hifiberry_dacplushd_remove,
10607 +module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
10609 +MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
10610 +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
10611 +MODULE_LICENSE("GPL v2");
10613 +++ b/sound/soc/bcm/i-sabre-q2m.c
10616 + * ASoC Driver for I-Sabre Q2M
10618 + * Author: Satoru Kawase
10619 + * Modified by: Xiao Qingyong
10620 + * Update kernel v4.18+ by : Audiophonics
10621 + * Copyright 2018 Audiophonics
10623 + * This program is free software; you can redistribute it and/or
10624 + * modify it under the terms of the GNU General Public License
10625 + * version 2 as published by the Free Software Foundation.
10627 + * This program is distributed in the hope that it will be useful, but
10628 + * WITHOUT ANY WARRANTY; without even the implied warranty of
10629 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10630 + * General Public License for more details.
10633 +#include <linux/kernel.h>
10634 +#include <linux/init.h>
10635 +#include <linux/module.h>
10636 +#include <linux/delay.h>
10637 +#include <linux/fs.h>
10638 +#include <asm/uaccess.h>
10639 +#include <sound/core.h>
10640 +#include <sound/soc.h>
10641 +#include <sound/pcm.h>
10642 +#include <sound/pcm_params.h>
10644 +#include "../codecs/i-sabre-codec.h"
10647 +static int snd_rpi_i_sabre_q2m_init(struct snd_soc_pcm_runtime *rtd)
10649 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
10650 + unsigned int value;
10653 + value = snd_soc_component_read(component, ISABRECODEC_REG_01);
10654 + dev_info(component->card->dev, "Audiophonics Device ID : %02X\n", value);
10656 + /* API revision */
10657 + value = snd_soc_component_read(component, ISABRECODEC_REG_02);
10658 + dev_info(component->card->dev, "Audiophonics API revision : %02X\n", value);
10663 +static int snd_rpi_i_sabre_q2m_hw_params(
10664 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
10666 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10667 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
10670 + /* Using powers of 2 allows for an integer clock divisor */
10671 + bclk_ratio = (snd_pcm_format_width(params_format(params)) <= 16 ? 16 : 32) *
10672 + params_channels(params);
10673 + return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio);
10676 +/* machine stream operations */
10677 +static struct snd_soc_ops snd_rpi_i_sabre_q2m_ops = {
10678 + .hw_params = snd_rpi_i_sabre_q2m_hw_params,
10681 +SND_SOC_DAILINK_DEFS(rpi_i_sabre_q2m,
10682 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
10683 + DAILINK_COMP_ARRAY(COMP_CODEC("i-sabre-codec-i2c.1-0048", "i-sabre-codec-dai")),
10684 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
10686 +static struct snd_soc_dai_link snd_rpi_i_sabre_q2m_dai[] = {
10688 + .name = "I-Sabre Q2M",
10689 + .stream_name = "I-Sabre Q2M DAC",
10690 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
10691 + | SND_SOC_DAIFMT_CBS_CFS,
10692 + .init = snd_rpi_i_sabre_q2m_init,
10693 + .ops = &snd_rpi_i_sabre_q2m_ops,
10694 + SND_SOC_DAILINK_REG(rpi_i_sabre_q2m),
10698 +/* audio machine driver */
10699 +static struct snd_soc_card snd_rpi_i_sabre_q2m = {
10700 + .name = "I-Sabre Q2M DAC",
10701 + .owner = THIS_MODULE,
10702 + .dai_link = snd_rpi_i_sabre_q2m_dai,
10703 + .num_links = ARRAY_SIZE(snd_rpi_i_sabre_q2m_dai)
10707 +static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev)
10711 + snd_rpi_i_sabre_q2m.dev = &pdev->dev;
10712 + if (pdev->dev.of_node) {
10713 + struct device_node *i2s_node;
10714 + struct snd_soc_dai_link *dai;
10716 + dai = &snd_rpi_i_sabre_q2m_dai[0];
10717 + i2s_node = of_parse_phandle(pdev->dev.of_node,
10718 + "i2s-controller", 0);
10720 + dai->cpus->dai_name = NULL;
10721 + dai->cpus->of_node = i2s_node;
10722 + dai->platforms->name = NULL;
10723 + dai->platforms->of_node = i2s_node;
10725 + dev_err(&pdev->dev,
10726 + "Property 'i2s-controller' missing or invalid\n");
10727 + return (-EINVAL);
10730 + dai->name = "I-Sabre Q2M";
10731 + dai->stream_name = "I-Sabre Q2M DAC";
10732 + dai->dai_fmt = SND_SOC_DAIFMT_I2S
10733 + | SND_SOC_DAIFMT_NB_NF
10734 + | SND_SOC_DAIFMT_CBS_CFS;
10737 + /* Wait for registering codec driver */
10740 + ret = snd_soc_register_card(&snd_rpi_i_sabre_q2m);
10742 + dev_err(&pdev->dev,
10743 + "snd_soc_register_card() failed: %d\n", ret);
10749 +static void snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev)
10751 + snd_soc_unregister_card(&snd_rpi_i_sabre_q2m);
10754 +static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = {
10755 + { .compatible = "audiophonics,i-sabre-q2m", },
10758 +MODULE_DEVICE_TABLE(of, snd_rpi_i_sabre_q2m_of_match);
10760 +static struct platform_driver snd_rpi_i_sabre_q2m_driver = {
10762 + .name = "snd-rpi-i-sabre-q2m",
10763 + .owner = THIS_MODULE,
10764 + .of_match_table = snd_rpi_i_sabre_q2m_of_match,
10766 + .probe = snd_rpi_i_sabre_q2m_probe,
10767 + .remove = snd_rpi_i_sabre_q2m_remove,
10769 +module_platform_driver(snd_rpi_i_sabre_q2m_driver);
10771 +MODULE_DESCRIPTION("ASoC Driver for I-Sabre Q2M");
10772 +MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
10773 +MODULE_LICENSE("GPL");
10775 +++ b/sound/soc/bcm/iqaudio-codec.c
10778 + * ASoC Driver for IQaudIO Raspberry Pi Codec board
10780 + * Author: Gordon Garrity <gordon@iqaudio.com>
10781 + * (C) Copyright IQaudio Limited, 2017-2019
10783 + * This program is free software; you can redistribute it and/or
10784 + * modify it under the terms of the GNU General Public License
10785 + * version 2 as published by the Free Software Foundation.
10787 + * This program is distributed in the hope that it will be useful, but
10788 + * WITHOUT ANY WARRANTY; without even the implied warranty of
10789 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10790 + * General Public License for more details.
10793 +#include <linux/module.h>
10794 +#include <linux/gpio/consumer.h>
10795 +#include <linux/platform_device.h>
10797 +#include <sound/core.h>
10798 +#include <sound/pcm.h>
10799 +#include <sound/pcm_params.h>
10800 +#include <sound/soc.h>
10801 +#include <sound/jack.h>
10803 +#include <linux/acpi.h>
10804 +#include <linux/slab.h>
10805 +#include "../codecs/da7213.h"
10807 +static int pll_out = DA7213_PLL_FREQ_OUT_90316800;
10809 +static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w,
10810 + struct snd_kcontrol *k, int event)
10813 + struct snd_soc_dapm_context *dapm = w->dapm;
10814 + struct snd_soc_card *card = dapm->card;
10815 + struct snd_soc_pcm_runtime *rtd =
10816 + snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
10817 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
10819 + if (SND_SOC_DAPM_EVENT_OFF(event)) {
10820 + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0,
10823 + dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
10824 + /* Allow PLL time to bypass */
10826 + } else if (SND_SOC_DAPM_EVENT_ON(event)) {
10827 + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
10830 + dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
10831 + /* Allow PLL time to lock */
10838 +static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w,
10839 + struct snd_kcontrol *kcontrol,
10843 + case SND_SOC_DAPM_POST_PMU:
10844 + /* Delay for mic bias ramp */
10854 +static const struct snd_kcontrol_new dapm_controls[] = {
10855 + SOC_DAPM_PIN_SWITCH("HP Jack"),
10856 + SOC_DAPM_PIN_SWITCH("MIC Jack"),
10857 + SOC_DAPM_PIN_SWITCH("Onboard MIC"),
10858 + SOC_DAPM_PIN_SWITCH("AUX Jack"),
10861 +static const struct snd_soc_dapm_widget dapm_widgets[] = {
10862 + SND_SOC_DAPM_HP("HP Jack", NULL),
10863 + SND_SOC_DAPM_MIC("MIC Jack", NULL),
10864 + SND_SOC_DAPM_MIC("Onboard MIC", NULL),
10865 + SND_SOC_DAPM_LINE("AUX Jack", NULL),
10866 + SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0,
10867 + snd_rpi_iqaudio_pll_control,
10868 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
10869 + SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event),
10872 +static const struct snd_soc_dapm_route audio_map[] = {
10873 + {"HP Jack", NULL, "HPL"},
10874 + {"HP Jack", NULL, "HPR"},
10875 + {"HP Jack", NULL, "PLL Control"},
10877 + {"AUXR", NULL, "AUX Jack"},
10878 + {"AUXL", NULL, "AUX Jack"},
10879 + {"AUX Jack", NULL, "PLL Control"},
10881 + /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
10882 + {"MIC1", NULL, "MIC Jack"},
10883 + {"MIC Jack", NULL, "PLL Control"},
10884 + {"MIC2", NULL, "Onboard MIC"},
10885 + {"Onboard MIC", NULL, "PLL Control"},
10888 +/* machine stream operations */
10890 +static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd)
10892 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
10893 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
10897 + * Disable AUX Jack Pin by default to prevent PLL being enabled at
10898 + * startup. This avoids holding the PLL to a fixed SR config for
10899 + * subsequent streams.
10901 + * This pin can still be enabled later, as required by user-space.
10903 + snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack");
10904 + snd_soc_dapm_sync(&rtd->card->dapm);
10906 + /* Impose BCLK ratios otherwise the codec may cheat */
10907 + ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
10909 + dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n");
10913 + ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
10915 + dev_err(rtd->dev, "Failed to set codec BCLK ratio\n");
10919 + /* Set MCLK frequency to codec, onboard 11.2896MHz clock */
10920 + return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600,
10921 + SND_SOC_CLOCK_OUT);
10924 +static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream,
10925 + struct snd_pcm_hw_params *params)
10927 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
10928 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
10929 + unsigned int samplerate = params_rate(params);
10931 + switch (samplerate) {
10937 + pll_out = DA7213_PLL_FREQ_OUT_98304000;
10941 + pll_out = DA7213_PLL_FREQ_OUT_90316800;
10944 + dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
10948 + return snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, pll_out);
10951 +static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
10952 + .hw_params = snd_rpi_iqaudio_codec_hw_params,
10955 +SND_SOC_DAILINK_DEFS(rpi_iqaudio,
10956 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
10957 + DAILINK_COMP_ARRAY(COMP_CODEC("da7213.1-001a", "da7213-hifi")),
10958 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
10960 +static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = {
10962 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
10963 + SND_SOC_DAIFMT_CBM_CFM,
10964 + .init = snd_rpi_iqaudio_codec_init,
10965 + .ops = &snd_rpi_iqaudio_codec_ops,
10966 + .symmetric_rate = 1,
10967 + .symmetric_channels = 1,
10968 + .symmetric_sample_bits = 1,
10969 + SND_SOC_DAILINK_REG(rpi_iqaudio),
10973 +/* audio machine driver */
10974 +static struct snd_soc_card snd_rpi_iqaudio_codec = {
10975 + .owner = THIS_MODULE,
10976 + .dai_link = snd_rpi_iqaudio_codec_dai,
10977 + .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
10978 + .controls = dapm_controls,
10979 + .num_controls = ARRAY_SIZE(dapm_controls),
10980 + .dapm_widgets = dapm_widgets,
10981 + .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
10982 + .dapm_routes = audio_map,
10983 + .num_dapm_routes = ARRAY_SIZE(audio_map),
10986 +static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev)
10990 + snd_rpi_iqaudio_codec.dev = &pdev->dev;
10992 + if (pdev->dev.of_node) {
10993 + struct device_node *i2s_node;
10994 + struct snd_soc_card *card = &snd_rpi_iqaudio_codec;
10995 + struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0];
10997 + i2s_node = of_parse_phandle(pdev->dev.of_node,
10998 + "i2s-controller", 0);
11000 + dai->cpus->dai_name = NULL;
11001 + dai->cpus->of_node = i2s_node;
11002 + dai->platforms->name = NULL;
11003 + dai->platforms->of_node = i2s_node;
11006 + if (of_property_read_string(pdev->dev.of_node, "card_name",
11008 + card->name = "IQaudIOCODEC";
11010 + if (of_property_read_string(pdev->dev.of_node, "dai_name",
11012 + dai->name = "IQaudIO CODEC";
11014 + if (of_property_read_string(pdev->dev.of_node,
11015 + "dai_stream_name", &dai->stream_name))
11016 + dai->stream_name = "IQaudIO CODEC HiFi v1.2";
11020 + ret = snd_soc_register_card(&snd_rpi_iqaudio_codec);
11022 + if (ret != -EPROBE_DEFER)
11023 + dev_err(&pdev->dev,
11024 + "snd_soc_register_card() failed: %d\n", ret);
11031 +static void snd_rpi_iqaudio_codec_remove(struct platform_device *pdev)
11033 + snd_soc_unregister_card(&snd_rpi_iqaudio_codec);
11036 +static const struct of_device_id iqaudio_of_match[] = {
11037 + { .compatible = "iqaudio,iqaudio-codec", },
11041 +MODULE_DEVICE_TABLE(of, iqaudio_of_match);
11043 +static struct platform_driver snd_rpi_iqaudio_codec_driver = {
11045 + .name = "snd-rpi-iqaudio-codec",
11046 + .owner = THIS_MODULE,
11047 + .of_match_table = iqaudio_of_match,
11049 + .probe = snd_rpi_iqaudio_codec_probe,
11050 + .remove = snd_rpi_iqaudio_codec_remove,
11055 +module_platform_driver(snd_rpi_iqaudio_codec_driver);
11057 +MODULE_AUTHOR("Gordon Garrity <gordon@iqaudio.com>");
11058 +MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC");
11059 +MODULE_LICENSE("GPL v2");
11061 +++ b/sound/soc/bcm/iqaudio-dac.c
11064 + * ASoC Driver for IQaudIO DAC
11066 + * Author: Florian Meier <florian.meier@koalo.de>
11069 + * This program is free software; you can redistribute it and/or
11070 + * modify it under the terms of the GNU General Public License
11071 + * version 2 as published by the Free Software Foundation.
11073 + * This program is distributed in the hope that it will be useful, but
11074 + * WITHOUT ANY WARRANTY; without even the implied warranty of
11075 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11076 + * General Public License for more details.
11079 +#include <linux/module.h>
11080 +#include <linux/gpio/consumer.h>
11081 +#include <linux/platform_device.h>
11083 +#include <sound/core.h>
11084 +#include <sound/pcm.h>
11085 +#include <sound/pcm_params.h>
11086 +#include <sound/soc.h>
11087 +#include <sound/jack.h>
11089 +static bool digital_gain_0db_limit = true;
11091 +static struct gpio_desc *mute_gpio;
11093 +static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
11095 + if (digital_gain_0db_limit)
11098 + struct snd_soc_card *card = rtd->card;
11100 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
11102 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
11108 +static void snd_rpi_iqaudio_gpio_mute(struct snd_soc_card *card)
11111 + dev_info(card->dev, "%s: muting amp using GPIO22\n",
11113 + gpiod_set_value_cansleep(mute_gpio, 0);
11117 +static void snd_rpi_iqaudio_gpio_unmute(struct snd_soc_card *card)
11120 + dev_info(card->dev, "%s: un-muting amp using GPIO22\n",
11122 + gpiod_set_value_cansleep(mute_gpio, 1);
11126 +static int snd_rpi_iqaudio_set_bias_level(struct snd_soc_card *card,
11127 + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
11129 + struct snd_soc_pcm_runtime *rtd;
11130 + struct snd_soc_dai *codec_dai;
11132 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
11133 + codec_dai = snd_soc_rtd_to_codec(rtd, 0);
11135 + if (dapm->dev != codec_dai->dev)
11139 + case SND_SOC_BIAS_PREPARE:
11140 + if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
11144 + snd_rpi_iqaudio_gpio_unmute(card);
11147 + case SND_SOC_BIAS_STANDBY:
11148 + if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
11152 + snd_rpi_iqaudio_gpio_mute(card);
11162 +SND_SOC_DAILINK_DEFS(hifi,
11163 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
11164 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi")),
11165 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
11167 +static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
11169 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
11170 + SND_SOC_DAIFMT_CBS_CFS,
11171 + .init = snd_rpi_iqaudio_dac_init,
11172 + SND_SOC_DAILINK_REG(hifi),
11176 +/* audio machine driver */
11177 +static struct snd_soc_card snd_rpi_iqaudio_dac = {
11178 + .owner = THIS_MODULE,
11179 + .dai_link = snd_rpi_iqaudio_dac_dai,
11180 + .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
11183 +static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
11186 + bool gpio_unmute = false;
11188 + snd_rpi_iqaudio_dac.dev = &pdev->dev;
11190 + if (pdev->dev.of_node) {
11191 + struct device_node *i2s_node;
11192 + struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
11193 + struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
11194 + bool auto_gpio_mute = false;
11196 + i2s_node = of_parse_phandle(pdev->dev.of_node,
11197 + "i2s-controller", 0);
11199 + dai->cpus->dai_name = NULL;
11200 + dai->cpus->of_node = i2s_node;
11201 + dai->platforms->name = NULL;
11202 + dai->platforms->of_node = i2s_node;
11205 + digital_gain_0db_limit = !of_property_read_bool(
11206 + pdev->dev.of_node, "iqaudio,24db_digital_gain");
11208 + if (of_property_read_string(pdev->dev.of_node, "card_name",
11210 + card->name = "IQaudIODAC";
11212 + if (of_property_read_string(pdev->dev.of_node, "dai_name",
11214 + dai->name = "IQaudIO DAC";
11216 + if (of_property_read_string(pdev->dev.of_node,
11217 + "dai_stream_name", &dai->stream_name))
11218 + dai->stream_name = "IQaudIO DAC HiFi";
11220 + /* gpio_unmute - one time unmute amp using GPIO */
11221 + gpio_unmute = of_property_read_bool(pdev->dev.of_node,
11222 + "iqaudio-dac,unmute-amp");
11224 + /* auto_gpio_mute - mute/unmute amp using GPIO */
11225 + auto_gpio_mute = of_property_read_bool(pdev->dev.of_node,
11226 + "iqaudio-dac,auto-mute-amp");
11228 + if (auto_gpio_mute || gpio_unmute) {
11229 + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
11231 + if (IS_ERR(mute_gpio)) {
11232 + ret = PTR_ERR(mute_gpio);
11233 + dev_err(&pdev->dev,
11234 + "Failed to get mute gpio: %d\n", ret);
11238 + if (auto_gpio_mute && mute_gpio)
11239 + snd_rpi_iqaudio_dac.set_bias_level =
11240 + snd_rpi_iqaudio_set_bias_level;
11244 + ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
11246 + if (ret != -EPROBE_DEFER)
11247 + dev_err(&pdev->dev,
11248 + "snd_soc_register_card() failed: %d\n", ret);
11252 + if (gpio_unmute && mute_gpio)
11253 + snd_rpi_iqaudio_gpio_unmute(&snd_rpi_iqaudio_dac);
11258 +static void snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
11260 + snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac);
11262 + snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
11265 +static const struct of_device_id iqaudio_of_match[] = {
11266 + { .compatible = "iqaudio,iqaudio-dac", },
11269 +MODULE_DEVICE_TABLE(of, iqaudio_of_match);
11271 +static struct platform_driver snd_rpi_iqaudio_dac_driver = {
11273 + .name = "snd-rpi-iqaudio-dac",
11274 + .owner = THIS_MODULE,
11275 + .of_match_table = iqaudio_of_match,
11277 + .probe = snd_rpi_iqaudio_dac_probe,
11278 + .remove = snd_rpi_iqaudio_dac_remove,
11281 +module_platform_driver(snd_rpi_iqaudio_dac_driver);
11283 +MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
11284 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
11285 +MODULE_LICENSE("GPL v2");
11287 +++ b/sound/soc/bcm/justboom-both.c
11289 +// SPDX-License-Identifier: GPL-2.0
11291 + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
11293 + * Authors: Johannes Krude <johannes@krude.de
11295 + * Driver for when connecting simultaneously justboom-digi and justboom-dac
11297 + * Based upon code from:
11298 + * justboom-digi.c
11299 + * by Milan Neskovic <info@justboom.co>
11301 + * by Milan Neskovic <info@justboom.co>
11303 + * This program is free software; you can redistribute it and/or
11304 + * modify it under the terms of the GNU General Public License
11305 + * version 2 as published by the Free Software Foundation.
11307 + * This program is distributed in the hope that it will be useful, but
11308 + * WITHOUT ANY WARRANTY; without even the implied warranty of
11309 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11310 + * General Public License for more details.
11313 +#include <linux/module.h>
11314 +#include <linux/platform_device.h>
11316 +#include <sound/core.h>
11317 +#include <sound/pcm.h>
11318 +#include <sound/pcm_params.h>
11319 +#include <sound/soc.h>
11320 +#include <sound/jack.h>
11322 +#include "../codecs/wm8804.h"
11323 +#include "../codecs/pcm512x.h"
11326 +static bool digital_gain_0db_limit = true;
11328 +static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
11330 + struct snd_soc_component *digi = snd_soc_rtd_to_codec(rtd, 0)->component;
11331 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 1)->component;
11333 + /* enable TX output */
11334 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
11336 + snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
11337 + snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
11338 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
11340 + if (digital_gain_0db_limit) {
11342 + struct snd_soc_card *card = rtd->card;
11344 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
11347 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
11354 +static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
11355 + struct snd_pcm_hw_params *params)
11357 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11358 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
11359 + struct snd_soc_component *digi = snd_soc_rtd_to_codec(rtd, 0)->component;
11360 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
11362 + int sysclk = 27000000; /* This is fixed on this board */
11364 + long mclk_freq = 0;
11365 + int mclk_div = 1;
11366 + int sampling_freq = 1;
11370 + int samplerate = params_rate(params);
11372 + if (samplerate <= 96000) {
11373 + mclk_freq = samplerate*256;
11374 + mclk_div = WM8804_MCLKDIV_256FS;
11376 + mclk_freq = samplerate*128;
11377 + mclk_div = WM8804_MCLKDIV_128FS;
11380 + switch (samplerate) {
11382 + sampling_freq = 0x03;
11385 + sampling_freq = 0x00;
11388 + sampling_freq = 0x02;
11391 + sampling_freq = 0x08;
11394 + sampling_freq = 0x0a;
11397 + sampling_freq = 0x0c;
11400 + sampling_freq = 0x0e;
11403 + dev_err(rtd->card->dev,
11404 + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
11408 + snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
11409 + snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
11411 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
11412 + sysclk, SND_SOC_CLOCK_OUT);
11414 + dev_err(rtd->card->dev,
11415 + "Failed to set WM8804 SYSCLK: %d\n", ret);
11419 + /* Enable TX output */
11420 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
11423 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
11425 + /* set sampling frequency status bits */
11426 + snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
11428 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
11431 +static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
11433 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11434 + struct snd_soc_component *digi = snd_soc_rtd_to_codec(rtd, 0)->component;
11435 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 1)->component;
11437 + /* turn on digital output */
11438 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
11440 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
11445 +static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
11447 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11448 + struct snd_soc_component *digi = snd_soc_rtd_to_codec(rtd, 0)->component;
11449 + struct snd_soc_component *dac = snd_soc_rtd_to_codec(rtd, 1)->component;
11451 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
11453 + /* turn off output */
11454 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
11457 +/* machine stream operations */
11458 +static struct snd_soc_ops snd_rpi_justboom_both_ops = {
11459 + .hw_params = snd_rpi_justboom_both_hw_params,
11460 + .startup = snd_rpi_justboom_both_startup,
11461 + .shutdown = snd_rpi_justboom_both_shutdown,
11464 +SND_SOC_DAILINK_DEFS(rpi_justboom_both,
11465 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
11466 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
11467 + COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
11468 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
11470 +static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
11472 + .name = "JustBoom Digi",
11473 + .stream_name = "JustBoom Digi HiFi",
11474 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
11475 + SND_SOC_DAIFMT_CBM_CFM,
11476 + .ops = &snd_rpi_justboom_both_ops,
11477 + .init = snd_rpi_justboom_both_init,
11478 + SND_SOC_DAILINK_REG(rpi_justboom_both),
11482 +/* audio machine driver */
11483 +static struct snd_soc_card snd_rpi_justboom_both = {
11484 + .name = "snd_rpi_justboom_both",
11485 + .driver_name = "JustBoomBoth",
11486 + .owner = THIS_MODULE,
11487 + .dai_link = snd_rpi_justboom_both_dai,
11488 + .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
11491 +static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
11494 + struct snd_soc_card *card = &snd_rpi_justboom_both;
11496 + snd_rpi_justboom_both.dev = &pdev->dev;
11498 + if (pdev->dev.of_node) {
11499 + struct device_node *i2s_node;
11500 + struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
11502 + i2s_node = of_parse_phandle(pdev->dev.of_node,
11503 + "i2s-controller", 0);
11508 + for (i = 0; i < card->num_links; i++) {
11509 + dai->cpus->dai_name = NULL;
11510 + dai->cpus->of_node = i2s_node;
11511 + dai->platforms->name = NULL;
11512 + dai->platforms->of_node = i2s_node;
11516 + digital_gain_0db_limit = !of_property_read_bool(
11517 + pdev->dev.of_node, "justboom,24db_digital_gain");
11520 + ret = snd_soc_register_card(card);
11521 + if (ret && ret != -EPROBE_DEFER) {
11522 + dev_err(&pdev->dev,
11523 + "snd_soc_register_card() failed: %d\n", ret);
11529 +static void snd_rpi_justboom_both_remove(struct platform_device *pdev)
11531 + snd_soc_unregister_card(&snd_rpi_justboom_both);
11534 +static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
11535 + { .compatible = "justboom,justboom-both", },
11538 +MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
11540 +static struct platform_driver snd_rpi_justboom_both_driver = {
11542 + .name = "snd-rpi-justboom-both",
11543 + .owner = THIS_MODULE,
11544 + .of_match_table = snd_rpi_justboom_both_of_match,
11546 + .probe = snd_rpi_justboom_both_probe,
11547 + .remove = snd_rpi_justboom_both_remove,
11550 +module_platform_driver(snd_rpi_justboom_both_driver);
11552 +MODULE_AUTHOR("Johannes Krude <johannes@krude.de>");
11553 +MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
11554 +MODULE_LICENSE("GPL v2");
11556 +++ b/sound/soc/bcm/justboom-dac.c
11559 + * ASoC Driver for JustBoom DAC Raspberry Pi HAT Sound Card
11561 + * Author: Milan Neskovic
11563 + * based on code by Daniel Matuschek <info@crazy-audio.com>
11564 + * based on code by Florian Meier <florian.meier@koalo.de>
11566 + * This program is free software; you can redistribute it and/or
11567 + * modify it under the terms of the GNU General Public License
11568 + * version 2 as published by the Free Software Foundation.
11570 + * This program is distributed in the hope that it will be useful, but
11571 + * WITHOUT ANY WARRANTY; without even the implied warranty of
11572 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11573 + * General Public License for more details.
11576 +#include <linux/module.h>
11577 +#include <linux/platform_device.h>
11579 +#include <sound/core.h>
11580 +#include <sound/pcm.h>
11581 +#include <sound/pcm_params.h>
11582 +#include <sound/soc.h>
11583 +#include <sound/jack.h>
11585 +#include "../codecs/pcm512x.h"
11587 +static bool digital_gain_0db_limit = true;
11589 +static int snd_rpi_justboom_dac_init(struct snd_soc_pcm_runtime *rtd)
11591 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
11592 + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
11593 + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
11594 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
11596 + if (digital_gain_0db_limit)
11599 + struct snd_soc_card *card = rtd->card;
11601 + ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
11603 + dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
11609 +static int snd_rpi_justboom_dac_startup(struct snd_pcm_substream *substream) {
11610 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11611 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
11612 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
11616 +static void snd_rpi_justboom_dac_shutdown(struct snd_pcm_substream *substream) {
11617 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11618 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
11619 + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
11622 +/* machine stream operations */
11623 +static struct snd_soc_ops snd_rpi_justboom_dac_ops = {
11624 + .startup = snd_rpi_justboom_dac_startup,
11625 + .shutdown = snd_rpi_justboom_dac_shutdown,
11628 +SND_SOC_DAILINK_DEFS(hifi,
11629 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
11630 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
11631 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
11633 +static struct snd_soc_dai_link snd_rpi_justboom_dac_dai[] = {
11635 + .name = "JustBoom DAC",
11636 + .stream_name = "JustBoom DAC HiFi",
11637 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
11638 + SND_SOC_DAIFMT_CBS_CFS,
11639 + .ops = &snd_rpi_justboom_dac_ops,
11640 + .init = snd_rpi_justboom_dac_init,
11641 + SND_SOC_DAILINK_REG(hifi),
11645 +/* audio machine driver */
11646 +static struct snd_soc_card snd_rpi_justboom_dac = {
11647 + .name = "snd_rpi_justboom_dac",
11648 + .driver_name = "JustBoomDac",
11649 + .owner = THIS_MODULE,
11650 + .dai_link = snd_rpi_justboom_dac_dai,
11651 + .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai),
11654 +static int snd_rpi_justboom_dac_probe(struct platform_device *pdev)
11658 + snd_rpi_justboom_dac.dev = &pdev->dev;
11660 + if (pdev->dev.of_node) {
11661 + struct device_node *i2s_node;
11662 + struct snd_soc_dai_link *dai = &snd_rpi_justboom_dac_dai[0];
11663 + i2s_node = of_parse_phandle(pdev->dev.of_node,
11664 + "i2s-controller", 0);
11667 + dai->cpus->dai_name = NULL;
11668 + dai->cpus->of_node = i2s_node;
11669 + dai->platforms->name = NULL;
11670 + dai->platforms->of_node = i2s_node;
11673 + digital_gain_0db_limit = !of_property_read_bool(
11674 + pdev->dev.of_node, "justboom,24db_digital_gain");
11677 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_justboom_dac);
11678 + if (ret && ret != -EPROBE_DEFER)
11679 + dev_err(&pdev->dev,
11680 + "snd_soc_register_card() failed: %d\n", ret);
11685 +static const struct of_device_id snd_rpi_justboom_dac_of_match[] = {
11686 + { .compatible = "justboom,justboom-dac", },
11689 +MODULE_DEVICE_TABLE(of, snd_rpi_justboom_dac_of_match);
11691 +static struct platform_driver snd_rpi_justboom_dac_driver = {
11693 + .name = "snd-rpi-justboom-dac",
11694 + .owner = THIS_MODULE,
11695 + .of_match_table = snd_rpi_justboom_dac_of_match,
11697 + .probe = snd_rpi_justboom_dac_probe,
11700 +module_platform_driver(snd_rpi_justboom_dac_driver);
11702 +MODULE_AUTHOR("Milan Neskovic <info@justboom.co>");
11703 +MODULE_DESCRIPTION("ASoC Driver for JustBoom PI DAC HAT Sound Card");
11704 +MODULE_LICENSE("GPL v2");
11706 +++ b/sound/soc/bcm/pifi-40.c
11708 +// SPDX-License-Identifier: GPL-2.0-only
11710 + * ALSA ASoC Machine Driver for PiFi-40
11712 + * Author: David Knell <david.knell@gmail.com)
11713 + * based on code by Daniel Matuschek <info@crazy-audio.com>
11714 + * based on code by Florian Meier <florian.meier@koalo.de>
11715 + * Copyright (C) 2020
11717 + * This program is free software; you can redistribute it and/or
11718 + * modify it under the terms of the GNU General Public License
11719 + * version 2 as published by the Free Software Foundation.
11721 + * This program is distributed in the hope that it will be useful, but
11722 + * WITHOUT ANY WARRANTY; without even the implied warranty of
11723 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11724 + * General Public License for more details.
11727 +#include <linux/module.h>
11728 +#include <linux/platform_device.h>
11729 +#include <linux/gpio/consumer.h>
11730 +#include <sound/core.h>
11731 +#include <sound/pcm.h>
11732 +#include <sound/pcm_params.h>
11733 +#include <sound/soc.h>
11734 +#include <linux/firmware.h>
11735 +#include <linux/delay.h>
11736 +#include <sound/tlv.h>
11738 +static struct gpio_desc *pdn_gpio;
11739 +static int vol = 0x30;
11742 +static int pifi_40_vol_get(struct snd_kcontrol *kcontrol,
11743 + struct snd_ctl_elem_value *ucontrol)
11745 + ucontrol->value.integer.value[0] = vol;
11746 + ucontrol->value.integer.value[1] = vol;
11750 +static int pifi_40_vol_set(struct snd_kcontrol *kcontrol,
11751 + struct snd_ctl_elem_value *ucontrol)
11753 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
11754 + struct snd_soc_pcm_runtime *rtd;
11755 + unsigned int v = ucontrol->value.integer.value[0];
11756 + struct snd_soc_component *dac[2];
11758 + rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
11759 + dac[0] = snd_soc_rtd_to_codec(rtd, 0)->component;
11760 + dac[1] = snd_soc_rtd_to_codec(rtd, 1)->component;
11762 + snd_soc_component_write(dac[0], 0x07, 255 - v);
11763 + snd_soc_component_write(dac[1], 0x07, 255 - v);
11769 +static const DECLARE_TLV_DB_SCALE(digital_tlv_master, -10350, 50, 1);
11770 +static const struct snd_kcontrol_new pifi_40_controls[] = {
11771 + SOC_DOUBLE_R_EXT_TLV("Master Volume", 0x00, 0x01,
11775 + pifi_40_vol_get, pifi_40_vol_set,
11776 + digital_tlv_master)
11779 +static const char * const codec_ctl_pfx[] = { "Left", "Right" };
11781 +static const char * const codec_ctl_name[] = { "Master Volume",
11782 + "Speaker Volume",
11783 + "Speaker Switch" };
11785 +static int snd_pifi_40_init(struct snd_soc_pcm_runtime *rtd)
11787 + struct snd_soc_card *card = rtd->card;
11788 + struct snd_soc_component *dac[2];
11789 + struct snd_kcontrol *kctl;
11792 + dac[0] = snd_soc_rtd_to_codec(rtd, 0)->component;
11793 + dac[1] = snd_soc_rtd_to_codec(rtd, 1)->component;
11796 + // Set up cards - pulse power down first
11797 + gpiod_set_value_cansleep(pdn_gpio, 1);
11798 + usleep_range(1000, 10000);
11799 + gpiod_set_value_cansleep(pdn_gpio, 0);
11800 + usleep_range(20000, 30000);
11802 + // Oscillator trim
11803 + snd_soc_component_write(dac[0], 0x1b, 0);
11804 + snd_soc_component_write(dac[1], 0x1b, 0);
11805 + usleep_range(60000, 80000);
11808 + for (i = 0; i < 2; i++) {
11809 + // MCLK at 64fs, sample rate 44.1 or 48kHz
11810 + snd_soc_component_write(dac[i], 0x00, 0x60);
11812 + // Set up for PBTL
11813 + snd_soc_component_write(dac[i], 0x19, 0x3A);
11814 + snd_soc_component_write(dac[i], 0x25, 0x01103245);
11816 + // Master vol to -10db
11817 + snd_soc_component_write(dac[i], 0x07, 0x44);
11819 + // Inputs set to L and R respectively
11820 + snd_soc_component_write(dac[0], 0x20, 0x00017772);
11821 + snd_soc_component_write(dac[1], 0x20, 0x00107772);
11823 + // Remove codec controls
11824 + for (i = 0; i < 2; i++) {
11825 + for (j = 0; j < 3; j++) {
11828 + sprintf(cname, "%s %s", codec_ctl_pfx[i],
11829 + codec_ctl_name[j]);
11830 + kctl = snd_soc_card_get_kcontrol(card, cname);
11832 + pr_info("Control %s not found\n",
11835 + kctl->vd[0].access =
11836 + SNDRV_CTL_ELEM_ACCESS_READWRITE;
11837 + snd_ctl_remove(card->snd_card, kctl);
11845 +static int snd_pifi_40_hw_params(struct snd_pcm_substream *substream,
11846 + struct snd_pcm_hw_params *params)
11848 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
11849 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
11851 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
11854 +static struct snd_soc_ops snd_pifi_40_ops = { .hw_params =
11855 + snd_pifi_40_hw_params };
11857 +static struct snd_soc_dai_link_component pifi_40_codecs[] = {
11859 + .dai_name = "tas571x-hifi",
11862 + .dai_name = "tas571x-hifi",
11866 +SND_SOC_DAILINK_DEFS(
11867 + pifi_40_dai, DAILINK_COMP_ARRAY(COMP_EMPTY()),
11868 + DAILINK_COMP_ARRAY(COMP_CODEC("tas571x.1-001a", "tas571x-hifi"),
11869 + COMP_CODEC("tas571x.1-001b", "tas571x-hifi")),
11870 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
11872 +static struct snd_soc_dai_link snd_pifi_40_dai[] = {
11874 + .name = "PiFi40",
11875 + .stream_name = "PiFi40",
11876 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
11877 + SND_SOC_DAIFMT_CBS_CFS,
11878 + .ops = &snd_pifi_40_ops,
11879 + .init = snd_pifi_40_init,
11880 + SND_SOC_DAILINK_REG(pifi_40_dai),
11885 +static struct snd_soc_card snd_pifi_40 = {
11886 + .name = "PiFi40",
11887 + .owner = THIS_MODULE,
11888 + .dai_link = snd_pifi_40_dai,
11889 + .num_links = ARRAY_SIZE(snd_pifi_40_dai),
11890 + .controls = pifi_40_controls,
11891 + .num_controls = ARRAY_SIZE(pifi_40_controls)
11894 +static void snd_pifi_40_pdn(struct snd_soc_card *card, int on)
11897 + gpiod_set_value_cansleep(pdn_gpio, on ? 0 : 1);
11900 +static int snd_pifi_40_probe(struct platform_device *pdev)
11902 + struct snd_soc_card *card = &snd_pifi_40;
11903 + int ret = 0, i = 0;
11905 + card->dev = &pdev->dev;
11906 + platform_set_drvdata(pdev, &snd_pifi_40);
11908 + if (pdev->dev.of_node) {
11909 + struct device_node *i2s_node;
11910 + struct snd_soc_dai_link *dai;
11912 + dai = &snd_pifi_40_dai[0];
11913 + i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller",
11916 + for (i = 0; i < card->num_links; i++) {
11917 + dai->cpus->dai_name = NULL;
11918 + dai->cpus->of_node = i2s_node;
11919 + dai->platforms->name = NULL;
11920 + dai->platforms->of_node = i2s_node;
11924 + pifi_40_codecs[0].of_node =
11925 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
11926 + pifi_40_codecs[1].of_node =
11927 + of_parse_phandle(pdev->dev.of_node, "audio-codec", 1);
11928 + if (!pifi_40_codecs[0].of_node || !pifi_40_codecs[1].of_node) {
11929 + dev_err(&pdev->dev,
11930 + "Property 'audio-codec' missing or invalid\n");
11934 + pdn_gpio = devm_gpiod_get_optional(&pdev->dev, "pdn",
11936 + if (IS_ERR(pdn_gpio)) {
11937 + ret = PTR_ERR(pdn_gpio);
11938 + dev_err(&pdev->dev, "failed to get pdn gpio: %d\n",
11943 + ret = snd_soc_register_card(&snd_pifi_40);
11945 + dev_err(&pdev->dev,
11946 + "snd_soc_register_card() failed: %d\n", ret);
11956 +static void snd_pifi_40_remove(struct platform_device *pdev)
11958 + struct snd_soc_card *card = platform_get_drvdata(pdev);
11960 + kfree(&card->drvdata);
11961 + snd_pifi_40_pdn(&snd_pifi_40, 0);
11962 + snd_soc_unregister_card(&snd_pifi_40);
11965 +static const struct of_device_id snd_pifi_40_of_match[] = {
11967 + .compatible = "pifi,pifi-40",
11969 + { /* sentinel */ },
11972 +MODULE_DEVICE_TABLE(of, snd_pifi_40_of_match);
11974 +static struct platform_driver snd_pifi_40_driver = {
11976 + .name = "snd-pifi-40",
11977 + .owner = THIS_MODULE,
11978 + .of_match_table = snd_pifi_40_of_match,
11980 + .probe = snd_pifi_40_probe,
11981 + .remove = snd_pifi_40_remove,
11984 +module_platform_driver(snd_pifi_40_driver);
11986 +MODULE_AUTHOR("David Knell <david.knell@gmail.com>");
11987 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for PiFi-40");
11988 +MODULE_LICENSE("GPL v2");
11990 +++ b/sound/soc/bcm/pisound.c
11993 + * Pisound Linux kernel module.
11994 + * Copyright (C) 2016-2024 Vilniaus Blokas UAB, https://blokas.io/pisound
11996 + * This program is free software; you can redistribute it and/or
11997 + * modify it under the terms of the GNU General Public License
11998 + * as published by the Free Software Foundation; version 2 of the
12001 + * This program is distributed in the hope that it will be useful,
12002 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
12003 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12004 + * GNU General Public License for more details.
12006 + * You should have received a copy of the GNU General Public License
12007 + * along with this program; if not, write to the Free Software
12008 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
12009 + * MA 02110-1301, USA.
12012 +#include <linux/init.h>
12013 +#include <linux/module.h>
12014 +#include <linux/platform_device.h>
12015 +#include <linux/gpio.h>
12016 +#include <linux/kobject.h>
12017 +#include <linux/sysfs.h>
12018 +#include <linux/delay.h>
12019 +#include <linux/spi/spi.h>
12020 +#include <linux/interrupt.h>
12021 +#include <linux/kfifo.h>
12022 +#include <linux/jiffies.h>
12024 +#include <sound/core.h>
12025 +#include <sound/pcm.h>
12026 +#include <sound/pcm_params.h>
12027 +#include <sound/soc.h>
12028 +#include <sound/jack.h>
12029 +#include <sound/rawmidi.h>
12030 +#include <sound/asequencer.h>
12031 +#include <sound/control.h>
12033 +static int pisnd_spi_init(struct device *dev);
12034 +static void pisnd_spi_uninit(void);
12036 +static void pisnd_spi_flush(void);
12037 +static void pisnd_spi_start(void);
12038 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
12040 +typedef void (*pisnd_spi_recv_cb)(void *data);
12041 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data);
12043 +static const char *pisnd_spi_get_serial(void);
12044 +static const char *pisnd_spi_get_id(void);
12045 +static const char *pisnd_spi_get_fw_version(void);
12046 +static const char *pisnd_spi_get_hw_version(void);
12048 +static int pisnd_midi_init(struct snd_card *card);
12049 +static void pisnd_midi_uninit(void);
12052 + TASK_PROCESS = 0,
12055 +static void pisnd_schedule_process(enum task_e task);
12057 +#define PISOUND_LOG_PREFIX "pisound: "
12059 +#ifdef PISOUND_DEBUG
12060 +# define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
12062 +# define printd(...) do {} while (0)
12065 +#define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
12066 +#define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
12068 +static struct snd_rawmidi *g_rmidi;
12069 +static struct snd_rawmidi_substream *g_midi_output_substream;
12071 +static int pisnd_output_open(struct snd_rawmidi_substream *substream)
12073 + g_midi_output_substream = substream;
12077 +static int pisnd_output_close(struct snd_rawmidi_substream *substream)
12079 + g_midi_output_substream = NULL;
12083 +static void pisnd_output_trigger(
12084 + struct snd_rawmidi_substream *substream,
12088 + if (substream != g_midi_output_substream) {
12089 + printe("MIDI output trigger called for an unexpected stream!");
12096 + pisnd_spi_start();
12099 +static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
12101 + pisnd_spi_flush();
12104 +static int pisnd_input_open(struct snd_rawmidi_substream *substream)
12109 +static int pisnd_input_close(struct snd_rawmidi_substream *substream)
12114 +static void pisnd_midi_recv_callback(void *substream)
12116 + uint8_t data[128];
12119 + while ((n = pisnd_spi_recv(data, sizeof(data)))) {
12120 + int res = snd_rawmidi_receive(substream, data, n);
12122 + printd("midi recv %u bytes, res = %d\n", n, res);
12126 +static void pisnd_input_trigger(struct snd_rawmidi_substream *substream, int up)
12129 + pisnd_spi_set_callback(pisnd_midi_recv_callback, substream);
12130 + pisnd_schedule_process(TASK_PROCESS);
12132 + pisnd_spi_set_callback(NULL, NULL);
12136 +static const struct snd_rawmidi_ops pisnd_output_ops = {
12137 + .open = pisnd_output_open,
12138 + .close = pisnd_output_close,
12139 + .trigger = pisnd_output_trigger,
12140 + .drain = pisnd_output_drain,
12143 +static const struct snd_rawmidi_ops pisnd_input_ops = {
12144 + .open = pisnd_input_open,
12145 + .close = pisnd_input_close,
12146 + .trigger = pisnd_input_trigger,
12149 +static void pisnd_get_port_info(
12150 + struct snd_rawmidi *rmidi,
12152 + struct snd_seq_port_info *seq_port_info
12155 + seq_port_info->type =
12156 + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
12157 + SNDRV_SEQ_PORT_TYPE_HARDWARE |
12158 + SNDRV_SEQ_PORT_TYPE_PORT;
12159 + seq_port_info->midi_voices = 0;
12162 +static struct snd_rawmidi_global_ops pisnd_global_ops = {
12163 + .get_port_info = pisnd_get_port_info,
12166 +static int pisnd_midi_init(struct snd_card *card)
12170 + g_midi_output_substream = NULL;
12172 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
12175 + printe("snd_rawmidi_new failed: %d\n", err);
12179 + strcpy(g_rmidi->name, "pisound MIDI ");
12180 + strcat(g_rmidi->name, pisnd_spi_get_serial());
12182 + g_rmidi->info_flags =
12183 + SNDRV_RAWMIDI_INFO_OUTPUT |
12184 + SNDRV_RAWMIDI_INFO_INPUT |
12185 + SNDRV_RAWMIDI_INFO_DUPLEX;
12187 + g_rmidi->ops = &pisnd_global_ops;
12189 + g_rmidi->private_data = (void *)0;
12191 + snd_rawmidi_set_ops(
12193 + SNDRV_RAWMIDI_STREAM_OUTPUT,
12194 + &pisnd_output_ops
12197 + snd_rawmidi_set_ops(
12199 + SNDRV_RAWMIDI_STREAM_INPUT,
12206 +static void pisnd_midi_uninit(void)
12210 +static void *g_recvData;
12211 +static pisnd_spi_recv_cb g_recvCallback;
12213 +#define FIFO_SIZE 4096
12215 +static char g_serial_num[11];
12216 +static char g_id[25];
12217 +enum { MAX_VERSION_STR_LEN = 6 };
12218 +static char g_fw_version[MAX_VERSION_STR_LEN];
12219 +static char g_hw_version[MAX_VERSION_STR_LEN];
12220 +static u32 g_spi_speed_hz;
12222 +static uint8_t g_ledFlashDuration;
12223 +static bool g_ledFlashDurationChanged;
12225 +DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
12226 +DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
12228 +static struct gpio_desc *data_available;
12229 +static struct gpio_desc *spi_reset;
12231 +static struct spi_device *pisnd_spi_device;
12233 +static struct workqueue_struct *pisnd_workqueue;
12234 +static struct work_struct pisnd_work_process;
12236 +static void pisnd_work_handler(struct work_struct *work);
12238 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
12239 +static uint16_t spi_transfer16(uint16_t val);
12241 +static int pisnd_init_workqueues(void)
12243 + pisnd_workqueue = create_singlethread_workqueue("pisnd_workqueue");
12244 + INIT_WORK(&pisnd_work_process, pisnd_work_handler);
12249 +static void pisnd_uninit_workqueues(void)
12251 + flush_workqueue(pisnd_workqueue);
12252 + destroy_workqueue(pisnd_workqueue);
12254 + pisnd_workqueue = NULL;
12257 +static bool pisnd_spi_has_more(void)
12259 + return gpiod_get_value(data_available);
12262 +static void pisnd_schedule_process(enum task_e task)
12264 + if (pisnd_spi_device != NULL &&
12265 + pisnd_workqueue != NULL &&
12266 + !work_pending(&pisnd_work_process)
12268 + printd("schedule: has more = %d\n", pisnd_spi_has_more());
12269 + if (task == TASK_PROCESS)
12270 + queue_work(pisnd_workqueue, &pisnd_work_process);
12274 +static irqreturn_t data_available_interrupt_handler(int irq, void *dev_id)
12276 + if (irq == gpiod_to_irq(data_available) && pisnd_spi_has_more()) {
12277 + printd("schedule from irq\n");
12278 + pisnd_schedule_process(TASK_PROCESS);
12281 + return IRQ_HANDLED;
12284 +static uint16_t spi_transfer16(uint16_t val)
12286 + uint8_t txbuf[2];
12287 + uint8_t rxbuf[2];
12289 + if (!pisnd_spi_device) {
12290 + printe("pisnd_spi_device null, returning\n");
12294 + txbuf[0] = val >> 8;
12295 + txbuf[1] = val & 0xff;
12297 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
12299 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
12301 + return (rxbuf[0] << 8) | rxbuf[1];
12304 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
12307 + struct spi_transfer transfer;
12308 + struct spi_message msg;
12310 + memset(rxbuf, 0, len);
12312 + if (!pisnd_spi_device) {
12313 + printe("pisnd_spi_device null, returning\n");
12317 + spi_message_init(&msg);
12319 + memset(&transfer, 0, sizeof(transfer));
12321 + transfer.tx_buf = txbuf;
12322 + transfer.rx_buf = rxbuf;
12323 + transfer.len = len;
12324 + transfer.speed_hz = g_spi_speed_hz;
12325 + transfer.delay.value = 10;
12326 + transfer.delay.unit = SPI_DELAY_UNIT_USECS;
12328 + spi_message_add_tail(&transfer, &msg);
12330 + err = spi_sync(pisnd_spi_device, &msg);
12333 + printe("spi_sync error %d\n", err);
12337 + printd("hasMore %d\n", pisnd_spi_has_more());
12340 +static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
12346 + memset(dst, 0, length);
12349 + rx = spi_transfer16(0);
12353 + size = rx & 0xff;
12355 + if (size > length)
12358 + for (i = 0; i < size; ++i) {
12359 + rx = spi_transfer16(0);
12363 + dst[i] = rx & 0xff;
12371 +static int spi_device_match(struct device *dev, const void *data)
12373 + struct spi_device *spi = container_of(dev, struct spi_device, dev);
12375 + printd(" %s %s %dkHz %d bits mode=0x%02X\n",
12376 + spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
12377 + spi->bits_per_word, spi->mode);
12379 + if (strcmp("pisound-spi", spi->modalias) == 0) {
12380 + printi("\tFound!\n");
12384 + printe("\tNot found!\n");
12388 +static struct spi_device *pisnd_spi_find_device(void)
12390 + struct device *dev;
12392 + printi("Searching for spi device...\n");
12393 + dev = bus_find_device(&spi_bus_type, NULL, NULL, spi_device_match);
12395 + return container_of(dev, struct spi_device, dev);
12400 +static void pisnd_work_handler(struct work_struct *work)
12402 + enum { TRANSFER_SIZE = 4 };
12403 + enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 };
12404 + enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ };
12405 + int out_buffer_used_millibytes = 0;
12406 + unsigned long now;
12408 + uint8_t txbuf[TRANSFER_SIZE];
12409 + uint8_t rxbuf[TRANSFER_SIZE];
12410 + uint8_t midibuf[TRANSFER_SIZE];
12414 + unsigned long last_transfer_at = jiffies;
12416 + if (work == &pisnd_work_process) {
12417 + if (pisnd_spi_device == NULL)
12421 + if (g_midi_output_substream &&
12422 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
12424 + n = snd_rawmidi_transmit_peek(
12425 + g_midi_output_substream,
12426 + midibuf, sizeof(midibuf)
12430 + for (i = 0; i < n; ++i)
12435 + snd_rawmidi_transmit_ack(
12436 + g_midi_output_substream,
12442 + had_data = false;
12443 + memset(txbuf, 0, sizeof(txbuf));
12444 + for (i = 0; i < sizeof(txbuf) &&
12445 + ((out_buffer_used_millibytes+1000 <
12446 + PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) ||
12447 + g_ledFlashDurationChanged);
12452 + if (g_ledFlashDurationChanged) {
12453 + txbuf[i+0] = 0xf0;
12454 + txbuf[i+1] = g_ledFlashDuration;
12455 + g_ledFlashDuration = 0;
12456 + g_ledFlashDurationChanged = false;
12457 + } else if (kfifo_get(&spi_fifo_out, &val)) {
12458 + txbuf[i+0] = 0x0f;
12459 + txbuf[i+1] = val;
12460 + out_buffer_used_millibytes += 1000;
12464 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
12465 + /* Estimate the Pisound's MIDI output buffer usage, so
12466 + * that we don't overflow it. Space in the buffer should
12467 + * be becoming available at the UART MIDI byte transfer
12471 + if (now != last_transfer_at) {
12472 + out_buffer_used_millibytes -=
12473 + (now - last_transfer_at) *
12474 + MIDI_MILLIBYTES_PER_JIFFIE;
12475 + if (out_buffer_used_millibytes < 0)
12476 + out_buffer_used_millibytes = 0;
12477 + last_transfer_at = now;
12480 + for (i = 0; i < sizeof(rxbuf); i += 2) {
12482 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
12483 + if (kfifo_len(&spi_fifo_in) > 16 &&
12485 + g_recvCallback(g_recvData);
12489 + } while (had_data
12490 + || !kfifo_is_empty(&spi_fifo_out)
12491 + || pisnd_spi_has_more()
12492 + || g_ledFlashDurationChanged
12493 + || out_buffer_used_millibytes != 0
12496 + if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
12497 + g_recvCallback(g_recvData);
12501 +static int pisnd_spi_gpio_init(struct device *dev)
12503 + spi_reset = gpiod_get_index(dev, "reset", 1, GPIOD_ASIS);
12504 + data_available = gpiod_get_index(dev, "data_available", 0, GPIOD_ASIS);
12506 + gpiod_direction_output(spi_reset, 1);
12507 + gpiod_direction_input(data_available);
12509 + /* Reset the slave. */
12510 + gpiod_set_value(spi_reset, false);
12512 + gpiod_set_value(spi_reset, true);
12514 + /* Give time for spi slave to start. */
12520 +static void pisnd_spi_gpio_uninit(void)
12522 + gpiod_set_value(spi_reset, false);
12523 + gpiod_put(spi_reset);
12524 + spi_reset = NULL;
12526 + gpiod_put(data_available);
12527 + data_available = NULL;
12530 +static int pisnd_spi_gpio_irq_init(struct device *dev)
12532 + return request_threaded_irq(
12533 + gpiod_to_irq(data_available), NULL,
12534 + data_available_interrupt_handler,
12535 + IRQF_TIMER | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
12536 + "data_available_int",
12541 +static void pisnd_spi_gpio_irq_uninit(void)
12543 + free_irq(gpiod_to_irq(data_available), NULL);
12546 +static int spi_read_info(void)
12553 + char buffer[257];
12557 + memset(g_serial_num, 0, sizeof(g_serial_num));
12558 + memset(g_fw_version, 0, sizeof(g_fw_version));
12559 + strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version.
12560 + memset(g_id, 0, sizeof(g_id));
12562 + tmp = spi_transfer16(0);
12567 + count = tmp & 0xff;
12569 + for (i = 0; i < count; ++i) {
12570 + memset(buffer, 0, sizeof(buffer));
12571 + ret = spi_read_bytes(buffer, sizeof(buffer)-1, &n);
12583 + MAX_VERSION_STR_LEN,
12589 + g_fw_version[MAX_VERSION_STR_LEN-1] = '\0';
12597 + MAX_VERSION_STR_LEN,
12603 + g_hw_version[MAX_VERSION_STR_LEN-1] = '\0';
12606 + if (n >= sizeof(g_serial_num))
12609 + memcpy(g_serial_num, buffer, sizeof(g_serial_num));
12613 + if (n*2 >= sizeof(g_id))
12617 + for (j = 0; j < n; ++j)
12618 + p += sprintf(p, "%02x", buffer[j]);
12631 +static int pisnd_spi_init(struct device *dev)
12634 + struct spi_device *spi;
12636 + memset(g_serial_num, 0, sizeof(g_serial_num));
12637 + memset(g_id, 0, sizeof(g_id));
12638 + memset(g_fw_version, 0, sizeof(g_fw_version));
12639 + memset(g_hw_version, 0, sizeof(g_hw_version));
12641 + g_spi_speed_hz = 150000;
12642 + if (dev->of_node) {
12643 + struct device_node *spi_node;
12645 + spi_node = of_parse_phandle(
12647 + "spi-controller",
12652 + ret = of_property_read_u32(spi_node, "spi-speed-hz", &g_spi_speed_hz);
12654 + printe("Failed reading spi-speed-hz! (%d)\n", ret);
12656 + of_node_put(spi_node);
12659 + printi("Using SPI speed: %u\n", g_spi_speed_hz);
12661 + spi = pisnd_spi_find_device();
12663 + if (spi != NULL) {
12664 + printd("initializing spi!\n");
12665 + pisnd_spi_device = spi;
12666 + ret = spi_setup(pisnd_spi_device);
12668 + printe("SPI device not found, deferring!\n");
12669 + return -EPROBE_DEFER;
12672 + ret = pisnd_spi_gpio_init(dev);
12675 + printe("SPI GPIO init failed: %d\n", ret);
12676 + spi_dev_put(pisnd_spi_device);
12677 + pisnd_spi_device = NULL;
12678 + pisnd_spi_gpio_uninit();
12682 + ret = spi_read_info();
12685 + printe("Reading card info failed: %d\n", ret);
12686 + spi_dev_put(pisnd_spi_device);
12687 + pisnd_spi_device = NULL;
12688 + pisnd_spi_gpio_uninit();
12692 + /* Flash the LEDs. */
12693 + spi_transfer16(0xf008);
12695 + ret = pisnd_spi_gpio_irq_init(dev);
12697 + printe("SPI irq request failed: %d\n", ret);
12698 + spi_dev_put(pisnd_spi_device);
12699 + pisnd_spi_device = NULL;
12700 + pisnd_spi_gpio_irq_uninit();
12701 + pisnd_spi_gpio_uninit();
12704 + ret = pisnd_init_workqueues();
12706 + printe("Workqueue initialization failed: %d\n", ret);
12707 + spi_dev_put(pisnd_spi_device);
12708 + pisnd_spi_device = NULL;
12709 + pisnd_spi_gpio_irq_uninit();
12710 + pisnd_spi_gpio_uninit();
12711 + pisnd_uninit_workqueues();
12715 + if (pisnd_spi_has_more()) {
12716 + printd("data is available, scheduling from init\n");
12717 + pisnd_schedule_process(TASK_PROCESS);
12723 +static void pisnd_spi_uninit(void)
12725 + pisnd_uninit_workqueues();
12727 + spi_dev_put(pisnd_spi_device);
12728 + pisnd_spi_device = NULL;
12730 + pisnd_spi_gpio_irq_uninit();
12731 + pisnd_spi_gpio_uninit();
12734 +static void pisnd_spi_flash_leds(uint8_t duration)
12736 + g_ledFlashDuration = duration;
12737 + g_ledFlashDurationChanged = true;
12738 + printd("schedule from spi_flash_leds\n");
12739 + pisnd_schedule_process(TASK_PROCESS);
12742 +static void pisnd_spi_flush(void)
12744 + while (!kfifo_is_empty(&spi_fifo_out)) {
12745 + pisnd_spi_start();
12746 + flush_workqueue(pisnd_workqueue);
12750 +static void pisnd_spi_start(void)
12752 + printd("schedule from spi_start\n");
12753 + pisnd_schedule_process(TASK_PROCESS);
12756 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length)
12758 + return kfifo_out(&spi_fifo_in, buffer, length);
12761 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data)
12763 + g_recvData = data;
12764 + g_recvCallback = cb;
12767 +static const char *pisnd_spi_get_serial(void)
12769 + return g_serial_num;
12772 +static const char *pisnd_spi_get_id(void)
12777 +static const char *pisnd_spi_get_fw_version(void)
12779 + return g_fw_version;
12782 +static const char *pisnd_spi_get_hw_version(void)
12784 + return g_hw_version;
12787 +static const struct of_device_id pisound_of_match[] = {
12788 + { .compatible = "blokaslabs,pisound", },
12789 + { .compatible = "blokaslabs,pisound-spi", },
12798 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
12799 + struct snd_ctl_elem_info *uinfo)
12801 + if (kcontrol->private_value == SWITCH) {
12802 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
12803 + uinfo->count = 1;
12804 + uinfo->value.integer.min = 0;
12805 + uinfo->value.integer.max = 1;
12807 + } else if (kcontrol->private_value == VOLUME) {
12808 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12809 + uinfo->count = 1;
12810 + uinfo->value.integer.min = 0;
12811 + uinfo->value.integer.max = 100;
12817 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
12818 + struct snd_ctl_elem_value *ucontrol)
12820 + if (kcontrol->private_value == SWITCH) {
12821 + ucontrol->value.integer.value[0] = 1;
12823 + } else if (kcontrol->private_value == VOLUME) {
12824 + ucontrol->value.integer.value[0] = 100;
12831 +static struct snd_kcontrol_new pisnd_ctl[] = {
12833 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12834 + .name = "PCM Playback Switch",
12836 + .private_value = SWITCH,
12837 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
12838 + .info = pisnd_ctl_info,
12839 + .get = pisnd_ctl_get,
12842 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12843 + .name = "PCM Playback Volume",
12845 + .private_value = VOLUME,
12846 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
12847 + .info = pisnd_ctl_info,
12848 + .get = pisnd_ctl_get,
12852 +static int pisnd_ctl_init(struct snd_card *card)
12856 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
12857 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
12865 +static int pisnd_ctl_uninit(void)
12870 +static struct gpio_desc *osr0, *osr1, *osr2;
12871 +static struct gpio_desc *reset;
12873 +static int pisnd_hw_params(
12874 + struct snd_pcm_substream *substream,
12875 + struct snd_pcm_hw_params *params
12878 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
12879 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
12881 + /* Pisound runs on fixed 32 clock counts per channel,
12882 + * as generated by the master ADC.
12884 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
12886 + printd("rate = %d\n", params_rate(params));
12887 + printd("ch = %d\n", params_channels(params));
12888 + printd("bits = %u\n",
12889 + snd_pcm_format_width(params_format(params)));
12890 + printd("format = %d\n", params_format(params));
12892 + gpiod_set_value(reset, false);
12894 + switch (params_rate(params)) {
12896 + gpiod_set_value(osr0, true);
12897 + gpiod_set_value(osr1, false);
12898 + gpiod_set_value(osr2, false);
12901 + gpiod_set_value(osr0, true);
12902 + gpiod_set_value(osr1, false);
12903 + gpiod_set_value(osr2, true);
12906 + gpiod_set_value(osr0, true);
12907 + gpiod_set_value(osr1, true);
12908 + gpiod_set_value(osr2, true);
12911 + printe("Unsupported rate %u!\n", params_rate(params));
12915 + gpiod_set_value(reset, true);
12920 +static unsigned int rates[3] = {
12921 + 48000, 96000, 192000
12924 +static struct snd_pcm_hw_constraint_list constraints_rates = {
12925 + .count = ARRAY_SIZE(rates),
12930 +static int pisnd_startup(struct snd_pcm_substream *substream)
12932 + int err = snd_pcm_hw_constraint_list(
12933 + substream->runtime,
12935 + SNDRV_PCM_HW_PARAM_RATE,
12936 + &constraints_rates
12942 + err = snd_pcm_hw_constraint_single(
12943 + substream->runtime,
12944 + SNDRV_PCM_HW_PARAM_CHANNELS,
12951 + err = snd_pcm_hw_constraint_mask64(
12952 + substream->runtime,
12953 + SNDRV_PCM_HW_PARAM_FORMAT,
12954 + SNDRV_PCM_FMTBIT_S16_LE |
12955 + SNDRV_PCM_FMTBIT_S24_LE |
12956 + SNDRV_PCM_FMTBIT_S32_LE
12965 +static const struct snd_soc_ops pisnd_ops = {
12966 + .startup = pisnd_startup,
12967 + .hw_params = pisnd_hw_params,
12970 +SND_SOC_DAILINK_DEFS(pisnd,
12971 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
12972 + DAILINK_COMP_ARRAY(COMP_DUMMY()),
12973 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
12975 +static struct snd_soc_dai_link pisnd_dai[] = {
12977 + .name = "pisound",
12978 + .stream_name = "pisound",
12980 + SND_SOC_DAIFMT_I2S |
12981 + SND_SOC_DAIFMT_NB_NF |
12982 + SND_SOC_DAIFMT_CBM_CFM,
12983 + .ops = &pisnd_ops,
12984 + SND_SOC_DAILINK_REG(pisnd),
12988 +static int pisnd_card_probe(struct snd_soc_card *card)
12990 + int err = pisnd_midi_init(card->snd_card);
12993 + printe("pisnd_midi_init failed: %d\n", err);
12997 + err = pisnd_ctl_init(card->snd_card);
12999 + printe("pisnd_ctl_init failed: %d\n", err);
13006 +static int pisnd_card_remove(struct snd_soc_card *card)
13008 + pisnd_ctl_uninit();
13009 + pisnd_midi_uninit();
13013 +static struct snd_soc_card pisnd_card = {
13014 + .name = "pisound",
13015 + .owner = THIS_MODULE,
13016 + .dai_link = pisnd_dai,
13017 + .num_links = ARRAY_SIZE(pisnd_dai),
13018 + .probe = pisnd_card_probe,
13019 + .remove = pisnd_card_remove,
13022 +static int pisnd_init_gpio(struct device *dev)
13024 + osr0 = gpiod_get_index(dev, "osr", 0, GPIOD_ASIS);
13025 + osr1 = gpiod_get_index(dev, "osr", 1, GPIOD_ASIS);
13026 + osr2 = gpiod_get_index(dev, "osr", 2, GPIOD_ASIS);
13028 + reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS);
13030 + gpiod_direction_output(osr0, 1);
13031 + gpiod_direction_output(osr1, 1);
13032 + gpiod_direction_output(osr2, 1);
13033 + gpiod_direction_output(reset, 1);
13035 + gpiod_set_value(reset, false);
13036 + gpiod_set_value(osr0, true);
13037 + gpiod_set_value(osr1, false);
13038 + gpiod_set_value(osr2, false);
13039 + gpiod_set_value(reset, true);
13044 +static int pisnd_uninit_gpio(void)
13048 + struct gpio_desc **gpios[] = {
13049 + &osr0, &osr1, &osr2, &reset,
13052 + for (i = 0; i < ARRAY_SIZE(gpios); ++i) {
13053 + if (*gpios[i] == NULL) {
13054 + printd("weird, GPIO[%d] is NULL already\n", i);
13058 + gpiod_put(*gpios[i]);
13059 + *gpios[i] = NULL;
13065 +static struct kobject *pisnd_kobj;
13067 +static ssize_t pisnd_serial_show(
13068 + struct kobject *kobj,
13069 + struct kobj_attribute *attr,
13073 + return sprintf(buf, "%s\n", pisnd_spi_get_serial());
13076 +static ssize_t pisnd_id_show(
13077 + struct kobject *kobj,
13078 + struct kobj_attribute *attr,
13082 + return sprintf(buf, "%s\n", pisnd_spi_get_id());
13085 +static ssize_t pisnd_fw_version_show(
13086 + struct kobject *kobj,
13087 + struct kobj_attribute *attr,
13091 + return sprintf(buf, "%s\n", pisnd_spi_get_fw_version());
13094 +static ssize_t pisnd_hw_version_show(
13095 + struct kobject *kobj,
13096 + struct kobj_attribute *attr,
13100 + return sprintf(buf, "%s\n", pisnd_spi_get_hw_version());
13103 +static ssize_t pisnd_led_store(
13104 + struct kobject *kobj,
13105 + struct kobj_attribute *attr,
13110 + uint32_t timeout;
13113 + err = kstrtou32(buf, 10, &timeout);
13115 + if (err == 0 && timeout <= 255)
13116 + pisnd_spi_flash_leds(timeout);
13121 +static struct kobj_attribute pisnd_serial_attribute =
13122 + __ATTR(serial, 0444, pisnd_serial_show, NULL);
13123 +static struct kobj_attribute pisnd_id_attribute =
13124 + __ATTR(id, 0444, pisnd_id_show, NULL);
13125 +static struct kobj_attribute pisnd_fw_version_attribute =
13126 + __ATTR(version, 0444, pisnd_fw_version_show, NULL);
13127 +static struct kobj_attribute pisnd_hw_version_attribute =
13128 +__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL);
13129 +static struct kobj_attribute pisnd_led_attribute =
13130 + __ATTR(led, 0644, NULL, pisnd_led_store);
13132 +static struct attribute *attrs[] = {
13133 + &pisnd_serial_attribute.attr,
13134 + &pisnd_id_attribute.attr,
13135 + &pisnd_fw_version_attribute.attr,
13136 + &pisnd_hw_version_attribute.attr,
13137 + &pisnd_led_attribute.attr,
13141 +static struct attribute_group attr_group = { .attrs = attrs };
13143 +static int pisnd_probe(struct platform_device *pdev)
13148 + ret = pisnd_spi_init(&pdev->dev);
13150 + printe("pisnd_spi_init failed: %d\n", ret);
13154 + printi("Detected Pisound card:\n");
13155 + printi("\tSerial: %s\n", pisnd_spi_get_serial());
13156 + printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version());
13157 + printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version());
13158 + printi("\tId: %s\n", pisnd_spi_get_id());
13160 + pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
13161 + if (!pisnd_kobj) {
13162 + pisnd_spi_uninit();
13166 + ret = sysfs_create_group(pisnd_kobj, &attr_group);
13168 + pisnd_spi_uninit();
13169 + kobject_put(pisnd_kobj);
13173 + pisnd_init_gpio(&pdev->dev);
13174 + pisnd_card.dev = &pdev->dev;
13176 + if (pdev->dev.of_node) {
13177 + struct device_node *i2s_node;
13179 + i2s_node = of_parse_phandle(
13180 + pdev->dev.of_node,
13181 + "i2s-controller",
13185 + for (i = 0; i < pisnd_card.num_links; ++i) {
13186 + struct snd_soc_dai_link *dai = &pisnd_dai[i];
13189 + dai->cpus->dai_name = NULL;
13190 + dai->cpus->of_node = i2s_node;
13191 + dai->platforms->name = NULL;
13192 + dai->platforms->of_node = i2s_node;
13193 + dai->stream_name = pisnd_spi_get_serial();
13198 + ret = snd_soc_register_card(&pisnd_card);
13201 + if (ret != -EPROBE_DEFER)
13202 + printe("snd_soc_register_card() failed: %d\n", ret);
13203 + pisnd_uninit_gpio();
13204 + kobject_put(pisnd_kobj);
13205 + pisnd_spi_uninit();
13211 +static void pisnd_remove(struct platform_device *pdev)
13213 + printi("Unloading.\n");
13215 + if (pisnd_kobj) {
13216 + kobject_put(pisnd_kobj);
13217 + pisnd_kobj = NULL;
13220 + pisnd_spi_uninit();
13223 + gpiod_set_value(reset, false);
13224 + pisnd_uninit_gpio();
13226 + snd_soc_unregister_card(&pisnd_card);
13229 +MODULE_DEVICE_TABLE(of, pisound_of_match);
13231 +static struct platform_driver pisnd_driver = {
13233 + .name = "snd-rpi-pisound",
13234 + .owner = THIS_MODULE,
13235 + .of_match_table = pisound_of_match,
13237 + .probe = pisnd_probe,
13238 + .remove = pisnd_remove,
13241 +module_platform_driver(pisnd_driver);
13243 +MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
13244 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
13245 +MODULE_LICENSE("GPL v2");
13247 +++ b/sound/soc/bcm/rpi-cirrus.c
13250 + * ASoC machine driver for Cirrus Logic Audio Card
13251 + * (with WM5102 and WM8804 codecs)
13253 + * Copyright 2015-2017 Matthias Reichl <hias@horus.com>
13255 + * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc.
13257 + * This program is free software; you can redistribute it and/or modify
13258 + * it under the terms of the GNU General Public License version 2 as
13259 + * published by the Free Software Foundation.
13262 +#include <linux/module.h>
13263 +#include <linux/mutex.h>
13264 +#include <linux/slab.h>
13265 +#include <linux/list.h>
13266 +#include <linux/delay.h>
13267 +#include <sound/pcm_params.h>
13269 +#include <linux/mfd/arizona/registers.h>
13271 +#include "../codecs/wm5102.h"
13272 +#include "../codecs/wm8804.h"
13274 +#define WM8804_CLKOUT_HZ 12000000
13276 +#define RPI_CIRRUS_DEFAULT_RATE 44100
13277 +#define WM5102_MAX_SYSCLK_1 49152000 /* max sysclk for 4K family */
13278 +#define WM5102_MAX_SYSCLK_2 45158400 /* max sysclk for 11.025K family */
13280 +static inline unsigned int calc_sysclk(unsigned int rate)
13282 + return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1;
13290 +struct rpi_cirrus_priv {
13291 + /* mutex for synchronzing FLL1 access with DAPM */
13292 + struct mutex lock;
13293 + unsigned int card_rate;
13294 + int sync_path_enable;
13295 + int fll1_freq; /* negative means RefClock in spdif rx case */
13297 + /* track hw params/free for substreams */
13298 + unsigned int params_set;
13299 + unsigned int min_rate_idx, max_rate_idx;
13300 + unsigned char iec958_status[4];
13303 +/* helper functions */
13304 +static inline struct snd_soc_pcm_runtime *get_wm5102_runtime(
13305 + struct snd_soc_card *card) {
13306 + return snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_WM5102]);
13309 +static inline struct snd_soc_pcm_runtime *get_wm8804_runtime(
13310 + struct snd_soc_card *card) {
13311 + return snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_WM8804]);
13315 +struct rate_info {
13316 + unsigned int value;
13320 +static struct rate_info min_rates[] = {
13322 + { 32000, "32kHz"},
13323 + { 44100, "44.1kHz"}
13326 +#define NUM_MIN_RATES ARRAY_SIZE(min_rates)
13328 +static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol,
13329 + struct snd_ctl_elem_info *uinfo)
13331 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
13332 + uinfo->count = 1;
13333 + uinfo->value.enumerated.items = NUM_MIN_RATES;
13335 + if (uinfo->value.enumerated.item >= NUM_MIN_RATES)
13336 + uinfo->value.enumerated.item = NUM_MIN_RATES - 1;
13337 + strcpy(uinfo->value.enumerated.name,
13338 + min_rates[uinfo->value.enumerated.item].text);
13342 +static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol,
13343 + struct snd_ctl_elem_value *ucontrol)
13345 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13346 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13348 + ucontrol->value.enumerated.item[0] = priv->min_rate_idx;
13352 +static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol,
13353 + struct snd_ctl_elem_value *ucontrol)
13355 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13356 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13359 + if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) {
13361 + priv->min_rate_idx = ucontrol->value.enumerated.item[0];
13367 +static struct rate_info max_rates[] = {
13369 + { 48000, "48kHz"},
13370 + { 96000, "96kHz"}
13373 +#define NUM_MAX_RATES ARRAY_SIZE(max_rates)
13375 +static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol,
13376 + struct snd_ctl_elem_info *uinfo)
13378 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
13379 + uinfo->count = 1;
13380 + uinfo->value.enumerated.items = NUM_MAX_RATES;
13381 + if (uinfo->value.enumerated.item >= NUM_MAX_RATES)
13382 + uinfo->value.enumerated.item = NUM_MAX_RATES - 1;
13383 + strcpy(uinfo->value.enumerated.name,
13384 + max_rates[uinfo->value.enumerated.item].text);
13388 +static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol,
13389 + struct snd_ctl_elem_value *ucontrol)
13391 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13392 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13394 + ucontrol->value.enumerated.item[0] = priv->max_rate_idx;
13398 +static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol,
13399 + struct snd_ctl_elem_value *ucontrol)
13401 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13402 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13405 + if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) {
13407 + priv->max_rate_idx = ucontrol->value.enumerated.item[0];
13413 +static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol,
13414 + struct snd_ctl_elem_info *uinfo)
13416 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
13417 + uinfo->count = 1;
13421 +static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol,
13422 + struct snd_ctl_elem_value *ucontrol)
13424 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13425 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13428 + for (i = 0; i < 4; i++)
13429 + ucontrol->value.iec958.status[i] = priv->iec958_status[i];
13434 +static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol,
13435 + struct snd_ctl_elem_value *ucontrol)
13437 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13438 + struct snd_soc_component *wm8804_component =
13439 + snd_soc_rtd_to_codec(get_wm8804_runtime(card), 0)->component;
13440 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13441 + unsigned char *stat = priv->iec958_status;
13442 + unsigned char *ctrl_stat = ucontrol->value.iec958.status;
13443 + unsigned int mask;
13444 + int i, changed = 0;
13446 + for (i = 0; i < 4; i++) {
13447 + mask = (i == 3) ? 0x3f : 0xff;
13448 + if ((ctrl_stat[i] & mask) != (stat[i] & mask)) {
13450 + stat[i] = ctrl_stat[i] & mask;
13451 + snd_soc_component_update_bits(wm8804_component,
13452 + WM8804_SPDTX1 + i, mask, stat[i]);
13459 +static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol,
13460 + struct snd_ctl_elem_value *ucontrol)
13462 + ucontrol->value.iec958.status[0] = 0xff;
13463 + ucontrol->value.iec958.status[1] = 0xff;
13464 + ucontrol->value.iec958.status[2] = 0xff;
13465 + ucontrol->value.iec958.status[3] = 0x3f;
13470 +static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol,
13471 + struct snd_ctl_elem_value *ucontrol)
13473 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13474 + struct snd_soc_component *wm8804_component =
13475 + snd_soc_rtd_to_codec(get_wm8804_runtime(card), 0)->component;
13476 + unsigned int val, mask;
13479 + for (i = 0; i < 4; i++) {
13480 + val = snd_soc_component_read(wm8804_component,
13481 + WM8804_RXCHAN1 + i);
13482 + mask = (i == 3) ? 0x3f : 0xff;
13483 + ucontrol->value.iec958.status[i] = val & mask;
13489 +#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \
13491 + .access = SNDRV_CTL_ELEM_ACCESS_READ \
13492 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
13493 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
13494 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) \
13496 + .info = snd_ctl_boolean_mono_info, \
13497 + .get = rpi_cirrus_spdif_status_flag_get, \
13498 + .private_value = \
13499 + (bit) | ((reg) << 8) | ((invert) << 16) \
13502 +static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol,
13503 + struct snd_ctl_elem_value *ucontrol)
13505 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13506 + struct snd_soc_component *wm8804_component =
13507 + snd_soc_rtd_to_codec(get_wm8804_runtime(card), 0)->component;
13509 + unsigned int bit = kcontrol->private_value & 0xff;
13510 + unsigned int reg = (kcontrol->private_value >> 8) & 0xff;
13511 + unsigned int invert = (kcontrol->private_value >> 16) & 0xff;
13512 + unsigned int val;
13515 + val = snd_soc_component_read(wm8804_component, reg);
13517 + flag = val & (1 << bit);
13519 + ucontrol->value.integer.value[0] = invert ? !flag : flag;
13524 +static const char * const recovered_frequency_texts[] = {
13531 +#define NUM_RECOVERED_FREQUENCIES \
13532 + ARRAY_SIZE(recovered_frequency_texts)
13534 +static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol,
13535 + struct snd_ctl_elem_info *uinfo)
13537 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
13538 + uinfo->count = 1;
13539 + uinfo->value.enumerated.items = NUM_RECOVERED_FREQUENCIES;
13540 + if (uinfo->value.enumerated.item >= NUM_RECOVERED_FREQUENCIES)
13541 + uinfo->value.enumerated.item = NUM_RECOVERED_FREQUENCIES - 1;
13542 + strcpy(uinfo->value.enumerated.name,
13543 + recovered_frequency_texts[uinfo->value.enumerated.item]);
13547 +static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol,
13548 + struct snd_ctl_elem_value *ucontrol)
13550 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
13551 + struct snd_soc_component *wm8804_component =
13552 + snd_soc_rtd_to_codec(get_wm8804_runtime(card), 0)->component;
13553 + unsigned int val;
13555 + val = snd_soc_component_read(wm8804_component, WM8804_SPDSTAT);
13557 + ucontrol->value.enumerated.item[0] = (val >> 4) & 0x03;
13561 +static const struct snd_kcontrol_new rpi_cirrus_controls[] = {
13563 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13564 + .name = "Min Sample Rate",
13565 + .info = rpi_cirrus_min_rate_info,
13566 + .get = rpi_cirrus_min_rate_get,
13567 + .put = rpi_cirrus_min_rate_put,
13570 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13571 + .name = "Max Sample Rate",
13572 + .info = rpi_cirrus_max_rate_info,
13573 + .get = rpi_cirrus_max_rate_get,
13574 + .put = rpi_cirrus_max_rate_put,
13577 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13578 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
13579 + .info = rpi_cirrus_spdif_info,
13580 + .get = rpi_cirrus_spdif_playback_get,
13581 + .put = rpi_cirrus_spdif_playback_put,
13584 + .access = SNDRV_CTL_ELEM_ACCESS_READ
13585 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
13586 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13587 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
13588 + .info = rpi_cirrus_spdif_info,
13589 + .get = rpi_cirrus_spdif_capture_get,
13592 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
13593 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13594 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
13595 + .info = rpi_cirrus_spdif_info,
13596 + .get = rpi_cirrus_spdif_mask_get,
13599 + .access = SNDRV_CTL_ELEM_ACCESS_READ
13600 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
13601 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13602 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE)
13603 + "Recovered Frequency",
13604 + .info = rpi_cirrus_recovered_frequency_info,
13605 + .get = rpi_cirrus_recovered_frequency_get,
13607 + SPDIF_FLAG_CTRL("Audio", WM8804_SPDSTAT, 0, 1),
13608 + SPDIF_FLAG_CTRL("Non-PCM", WM8804_SPDSTAT, 1, 0),
13609 + SPDIF_FLAG_CTRL("Copyright", WM8804_SPDSTAT, 2, 1),
13610 + SPDIF_FLAG_CTRL("De-Emphasis", WM8804_SPDSTAT, 3, 0),
13611 + SPDIF_FLAG_CTRL("Lock", WM8804_SPDSTAT, 6, 1),
13612 + SPDIF_FLAG_CTRL("Invalid", WM8804_INTSTAT, 1, 0),
13613 + SPDIF_FLAG_CTRL("TransErr", WM8804_INTSTAT, 3, 0),
13616 +static const char * const linein_micbias_texts[] = {
13620 +static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum,
13621 + linein_micbias_texts);
13623 +static const struct snd_kcontrol_new linein_micbias_mux =
13624 + SOC_DAPM_ENUM("Route", linein_micbias_enum);
13626 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
13627 + struct snd_kcontrol *kcontrol, int event);
13629 +const struct snd_soc_dapm_widget rpi_cirrus_dapm_widgets[] = {
13630 + SND_SOC_DAPM_MIC("DMIC", NULL),
13631 + SND_SOC_DAPM_MIC("Headset Mic", NULL),
13632 + SND_SOC_DAPM_INPUT("Line Input"),
13633 + SND_SOC_DAPM_MIC("Line Input with Micbias", NULL),
13634 + SND_SOC_DAPM_MUX("Line Input Micbias", SND_SOC_NOPM, 0, 0,
13635 + &linein_micbias_mux),
13636 + SND_SOC_DAPM_INPUT("dummy SPDIF in"),
13637 + SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0, NULL, 0,
13638 + rpi_cirrus_spdif_rx_enable_event,
13639 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
13640 + SND_SOC_DAPM_INPUT("Dummy Input"),
13641 + SND_SOC_DAPM_OUTPUT("Dummy Output"),
13644 +const struct snd_soc_dapm_route rpi_cirrus_dapm_routes[] = {
13645 + { "IN1L", NULL, "Headset Mic" },
13646 + { "IN1R", NULL, "Headset Mic" },
13647 + { "Headset Mic", NULL, "MICBIAS1" },
13649 + { "IN2L", NULL, "DMIC" },
13650 + { "IN2R", NULL, "DMIC" },
13651 + { "DMIC", NULL, "MICBIAS2" },
13653 + { "IN3L", NULL, "Line Input Micbias" },
13654 + { "IN3R", NULL, "Line Input Micbias" },
13656 + { "Line Input Micbias", "off", "Line Input" },
13657 + { "Line Input Micbias", "on", "Line Input with Micbias" },
13659 + /* Make sure MICVDD is enabled, otherwise we get noise */
13660 + { "Line Input", NULL, "MICVDD" },
13661 + { "Line Input with Micbias", NULL, "MICBIAS3" },
13663 + /* Dummy routes to check whether SPDIF RX is enabled or not */
13664 + {"dummy SPDIFRX", NULL, "dummy SPDIF in"},
13665 + {"AIFTX", NULL, "dummy SPDIFRX"},
13668 + * Dummy routes to keep wm5102 from staying off on
13669 + * playback/capture if all mixers are off.
13671 + { "Dummy Output", NULL, "AIF1RX1" },
13672 + { "Dummy Output", NULL, "AIF1RX2" },
13673 + { "AIF1TX1", NULL, "Dummy Input" },
13674 + { "AIF1TX2", NULL, "Dummy Input" },
13677 +static int rpi_cirrus_clear_flls(struct snd_soc_card *card,
13678 + struct snd_soc_component *wm5102_component) {
13682 + ret1 = snd_soc_component_set_pll(wm5102_component,
13683 + WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
13684 + ret2 = snd_soc_component_set_pll(wm5102_component,
13685 + WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
13688 + dev_warn(card->dev,
13689 + "setting FLL1 to zero failed: %d\n", ret1);
13693 + dev_warn(card->dev,
13694 + "setting FLL1_REFCLK to zero failed: %d\n", ret2);
13700 +static int rpi_cirrus_set_fll(struct snd_soc_card *card,
13701 + struct snd_soc_component *wm5102_component, unsigned int clk_freq)
13703 + int ret = snd_soc_component_set_pll(wm5102_component,
13705 + ARIZONA_CLK_SRC_MCLK1,
13706 + WM8804_CLKOUT_HZ,
13709 + dev_err(card->dev, "Failed to set FLL1 to %d: %d\n",
13712 + usleep_range(1000, 2000);
13716 +static int rpi_cirrus_set_fll_refclk(struct snd_soc_card *card,
13717 + struct snd_soc_component *wm5102_component,
13718 + unsigned int clk_freq, unsigned int aif2_freq)
13720 + int ret = snd_soc_component_set_pll(wm5102_component,
13721 + WM5102_FLL1_REFCLK,
13722 + ARIZONA_CLK_SRC_MCLK1,
13723 + WM8804_CLKOUT_HZ,
13726 + dev_err(card->dev,
13727 + "Failed to set FLL1_REFCLK to %d: %d\n",
13732 + ret = snd_soc_component_set_pll(wm5102_component,
13734 + ARIZONA_CLK_SRC_AIF2BCLK,
13735 + aif2_freq, clk_freq);
13737 + dev_err(card->dev,
13738 + "Failed to set FLL1 with Sync Clock %d to %d: %d\n",
13739 + aif2_freq, clk_freq, ret);
13741 + usleep_range(1000, 2000);
13745 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
13746 + struct snd_kcontrol *kcontrol, int event)
13748 + struct snd_soc_card *card = w->dapm->card;
13749 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13750 + struct snd_soc_component *wm5102_component =
13751 + snd_soc_rtd_to_codec(get_wm5102_runtime(card), 0)->component;
13753 + unsigned int clk_freq, aif2_freq;
13757 + case SND_SOC_DAPM_POST_PMU:
13758 + mutex_lock(&priv->lock);
13760 + /* Enable sync path in case of SPDIF capture use case */
13762 + clk_freq = calc_sysclk(priv->card_rate);
13763 + aif2_freq = 64 * priv->card_rate;
13765 + dev_dbg(card->dev,
13766 + "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n",
13767 + clk_freq, aif2_freq);
13769 + ret = rpi_cirrus_clear_flls(card, wm5102_component);
13771 + dev_err(card->dev, "spdif_rx: failed to clear FLLs\n");
13775 + ret = rpi_cirrus_set_fll_refclk(card, wm5102_component,
13776 + clk_freq, aif2_freq);
13779 + dev_err(card->dev, "spdif_rx: failed to set FLLs\n");
13783 + /* set to negative to indicate we're doing spdif rx */
13784 + priv->fll1_freq = -clk_freq;
13785 + priv->sync_path_enable = 1;
13788 + case SND_SOC_DAPM_POST_PMD:
13789 + mutex_lock(&priv->lock);
13790 + priv->sync_path_enable = 0;
13798 + mutex_unlock(&priv->lock);
13802 +static int rpi_cirrus_set_bias_level(struct snd_soc_card *card,
13803 + struct snd_soc_dapm_context *dapm,
13804 + enum snd_soc_bias_level level)
13806 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13807 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
13808 + struct snd_soc_component *wm5102_component =
13809 + snd_soc_rtd_to_codec(wm5102_runtime, 0)->component;
13812 + unsigned int clk_freq;
13814 + if (dapm->dev != snd_soc_rtd_to_codec(wm5102_runtime, 0)->dev)
13818 + case SND_SOC_BIAS_PREPARE:
13819 + if (dapm->bias_level == SND_SOC_BIAS_ON)
13822 + mutex_lock(&priv->lock);
13824 + if (!priv->sync_path_enable) {
13825 + clk_freq = calc_sysclk(priv->card_rate);
13827 + dev_dbg(card->dev,
13828 + "set_bias: changing FLL1 from %d to %d\n",
13829 + priv->fll1_freq, clk_freq);
13831 + ret = rpi_cirrus_set_fll(card,
13832 + wm5102_component, clk_freq);
13834 + dev_err(card->dev,
13835 + "set_bias: Failed to set FLL1\n");
13837 + priv->fll1_freq = clk_freq;
13839 + mutex_unlock(&priv->lock);
13848 +static int rpi_cirrus_set_bias_level_post(struct snd_soc_card *card,
13849 + struct snd_soc_dapm_context *dapm,
13850 + enum snd_soc_bias_level level)
13852 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13853 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
13854 + struct snd_soc_component *wm5102_component =
13855 + snd_soc_rtd_to_codec(wm5102_runtime, 0)->component;
13857 + if (dapm->dev != snd_soc_rtd_to_codec(wm5102_runtime, 0)->dev)
13861 + case SND_SOC_BIAS_STANDBY:
13862 + mutex_lock(&priv->lock);
13864 + dev_dbg(card->dev,
13865 + "set_bias_post: changing FLL1 from %d to off\n",
13866 + priv->fll1_freq);
13868 + if (rpi_cirrus_clear_flls(card, wm5102_component))
13869 + dev_err(card->dev,
13870 + "set_bias_post: failed to clear FLLs\n");
13872 + priv->fll1_freq = 0;
13874 + mutex_unlock(&priv->lock);
13884 +static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card,
13885 + struct snd_soc_dai *wm8804_dai, unsigned int rate)
13890 + unsigned int clk_freq = rate * 256;
13892 + ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0,
13893 + WM8804_CLKOUT_HZ, clk_freq);
13895 + dev_err(card->dev,
13896 + "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret);
13900 + /* Set MCLK as PLL Output */
13901 + ret = snd_soc_dai_set_sysclk(wm8804_dai,
13902 + WM8804_TX_CLKSRC_PLL, clk_freq, 0);
13904 + dev_err(card->dev,
13905 + "Failed to set MCLK as PLL Output: %d\n", ret);
13912 +static int rpi_cirrus_startup(struct snd_pcm_substream *substream)
13914 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
13915 + struct snd_soc_card *card = rtd->card;
13916 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13917 + unsigned int min_rate = min_rates[priv->min_rate_idx].value;
13918 + unsigned int max_rate = max_rates[priv->max_rate_idx].value;
13920 + if (min_rate || max_rate) {
13921 + if (max_rate == 0)
13922 + max_rate = UINT_MAX;
13924 + dev_dbg(card->dev,
13925 + "startup: limiting rate to %u-%u\n",
13926 + min_rate, max_rate);
13928 + snd_pcm_hw_constraint_minmax(substream->runtime,
13929 + SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate);
13935 +static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = {
13936 + .formats = SNDRV_PCM_FMTBIT_S24_LE,
13937 + .channels_min = 2,
13938 + .channels_max = 2,
13939 + .rate_min = RPI_CIRRUS_DEFAULT_RATE,
13940 + .rate_max = RPI_CIRRUS_DEFAULT_RATE,
13943 +static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream,
13944 + struct snd_pcm_hw_params *params)
13946 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
13947 + struct snd_soc_card *card = rtd->card;
13948 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
13949 + struct snd_soc_dai *bcm_i2s_dai = snd_soc_rtd_to_cpu(rtd, 0);
13950 + struct snd_soc_component *wm5102_component = snd_soc_rtd_to_codec(rtd, 0)->component;
13951 + struct snd_soc_dai *wm8804_dai = snd_soc_rtd_to_codec(get_wm8804_runtime(card), 0);
13955 + unsigned int width = snd_pcm_format_width(params_format(params));
13956 + unsigned int rate = params_rate(params);
13957 + unsigned int clk_freq = calc_sysclk(rate);
13959 + /* Using powers of 2 allows for an integer clock divisor */
13960 + width = width <= 16 ? 16 : 32;
13962 + mutex_lock(&priv->lock);
13964 + dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate);
13966 + ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width);
13968 + dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret);
13972 + ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0x03, 0x03, 2, width);
13974 + dev_err(card->dev, "set_tdm_slot failed: %d\n", ret);
13978 + /* WM8804 supports sample rates from 32k only */
13979 + if (rate >= 32000) {
13980 + ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate);
13985 + ret = snd_soc_component_set_sysclk(wm5102_component,
13986 + ARIZONA_CLK_SYSCLK,
13987 + ARIZONA_CLK_SRC_FLL1,
13989 + SND_SOC_CLOCK_IN);
13991 + dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret);
13995 + if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) {
13996 + dev_dbg(card->dev,
13997 + "hw_params: changing FLL1 from %d to %d\n",
13998 + priv->fll1_freq, clk_freq);
14000 + if (rpi_cirrus_clear_flls(card, wm5102_component)) {
14001 + dev_err(card->dev, "hw_params: failed to clear FLLs\n");
14005 + if (rpi_cirrus_set_fll(card, wm5102_component, clk_freq)) {
14006 + dev_err(card->dev, "hw_params: failed to set FLL\n");
14010 + priv->fll1_freq = clk_freq;
14013 + priv->card_rate = rate;
14014 + rpi_cirrus_dai_link2_params.rate_min = rate;
14015 + rpi_cirrus_dai_link2_params.rate_max = rate;
14017 + priv->params_set |= 1 << substream->stream;
14020 + mutex_unlock(&priv->lock);
14025 +static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream)
14027 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
14028 + struct snd_soc_card *card = rtd->card;
14029 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
14030 + struct snd_soc_component *wm5102_component = snd_soc_rtd_to_codec(rtd, 0)->component;
14032 + unsigned int old_params_set = priv->params_set;
14034 + priv->params_set &= ~(1 << substream->stream);
14036 + /* disable sysclk if this was the last open stream */
14037 + if (priv->params_set == 0 && old_params_set) {
14038 + dev_dbg(card->dev,
14039 + "hw_free: Setting SYSCLK to Zero\n");
14041 + ret = snd_soc_component_set_sysclk(wm5102_component,
14042 + ARIZONA_CLK_SYSCLK,
14043 + ARIZONA_CLK_SRC_FLL1,
14045 + SND_SOC_CLOCK_IN);
14047 + dev_err(card->dev,
14048 + "hw_free: Failed to set SYSCLK to Zero: %d\n",
14054 +static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd)
14056 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
14059 + /* no 32kHz input, derive it from sysclk if needed */
14060 + snd_soc_component_update_bits(component,
14061 + ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, 2);
14063 + if (rpi_cirrus_clear_flls(rtd->card, component))
14064 + dev_warn(rtd->card->dev,
14065 + "init_wm5102: failed to clear FLLs\n");
14067 + ret = snd_soc_component_set_sysclk(component,
14068 + ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1,
14069 + 0, SND_SOC_CLOCK_IN);
14071 + dev_err(rtd->card->dev,
14072 + "Failed to set SYSCLK to Zero: %d\n", ret);
14079 +static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd)
14081 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14082 + struct snd_soc_component *component = codec_dai->component;
14083 + struct snd_soc_card *card = rtd->card;
14084 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
14085 + unsigned int val, mask;
14088 + for (i = 0; i < 4; i++) {
14089 + val = snd_soc_component_read(component,
14090 + WM8804_SPDTX1 + i);
14091 + mask = (i == 3) ? 0x3f : 0xff;
14092 + priv->iec958_status[i] = val & mask;
14095 + /* Setup for 256fs */
14096 + ret = snd_soc_dai_set_clkdiv(codec_dai,
14097 + WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS);
14099 + dev_err(card->dev,
14100 + "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n",
14105 + /* Output OSC on CLKOUT */
14106 + ret = snd_soc_dai_set_sysclk(codec_dai,
14107 + WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0);
14109 + dev_err(card->dev,
14110 + "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n",
14113 + /* Init PLL with default samplerate */
14114 + ret = rpi_cirrus_set_wm8804_pll(card, codec_dai,
14115 + RPI_CIRRUS_DEFAULT_RATE);
14117 + dev_err(card->dev,
14118 + "init_wm8804: Failed to setup PLL for %dHz: %d\n",
14119 + RPI_CIRRUS_DEFAULT_RATE, ret);
14124 +static struct snd_soc_ops rpi_cirrus_ops = {
14125 + .startup = rpi_cirrus_startup,
14126 + .hw_params = rpi_cirrus_hw_params,
14127 + .hw_free = rpi_cirrus_hw_free,
14130 +SND_SOC_DAILINK_DEFS(wm5102,
14131 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14132 + DAILINK_COMP_ARRAY(COMP_CODEC("wm5102-codec", "wm5102-aif1")),
14133 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14135 +SND_SOC_DAILINK_DEFS(wm8804,
14136 + DAILINK_COMP_ARRAY(COMP_CPU("wm5102-aif2")),
14137 + DAILINK_COMP_ARRAY(COMP_CODEC("wm8804.1-003b", "wm8804-spdif")));
14139 +static struct snd_soc_dai_link rpi_cirrus_dai[] = {
14141 + .name = "WM5102",
14142 + .stream_name = "WM5102 AiFi",
14143 + .dai_fmt = SND_SOC_DAIFMT_I2S
14144 + | SND_SOC_DAIFMT_NB_NF
14145 + | SND_SOC_DAIFMT_CBM_CFM,
14146 + .ops = &rpi_cirrus_ops,
14147 + .init = rpi_cirrus_init_wm5102,
14148 + SND_SOC_DAILINK_REG(wm5102),
14151 + .name = "WM5102 SPDIF",
14152 + .stream_name = "SPDIF Tx/Rx",
14153 + .dai_fmt = SND_SOC_DAIFMT_I2S
14154 + | SND_SOC_DAIFMT_NB_NF
14155 + | SND_SOC_DAIFMT_CBM_CFM,
14156 + .ignore_suspend = 1,
14157 + .c2c_params = &rpi_cirrus_dai_link2_params,
14158 + .init = rpi_cirrus_init_wm8804,
14159 + SND_SOC_DAILINK_REG(wm8804),
14164 +static int rpi_cirrus_late_probe(struct snd_soc_card *card)
14166 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
14167 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
14168 + struct snd_soc_pcm_runtime *wm8804_runtime = get_wm8804_runtime(card);
14171 + dev_dbg(card->dev, "iec958_bits: %02x %02x %02x %02x\n",
14172 + priv->iec958_status[0],
14173 + priv->iec958_status[1],
14174 + priv->iec958_status[2],
14175 + priv->iec958_status[3]);
14177 + ret = snd_soc_dai_set_sysclk(
14178 + snd_soc_rtd_to_codec(wm5102_runtime, 0), ARIZONA_CLK_SYSCLK, 0, 0);
14180 + dev_err(card->dev,
14181 + "Failed to set WM5102 codec dai clk domain: %d\n", ret);
14185 + ret = snd_soc_dai_set_sysclk(
14186 + snd_soc_rtd_to_cpu(wm8804_runtime, 0), ARIZONA_CLK_SYSCLK, 0, 0);
14188 + dev_err(card->dev,
14189 + "Failed to set WM8804 codec dai clk domain: %d\n", ret);
14194 +/* audio machine driver */
14195 +static struct snd_soc_card rpi_cirrus_card = {
14196 + .name = "RPi-Cirrus",
14197 + .driver_name = "RPiCirrus",
14198 + .owner = THIS_MODULE,
14199 + .dai_link = rpi_cirrus_dai,
14200 + .num_links = ARRAY_SIZE(rpi_cirrus_dai),
14201 + .late_probe = rpi_cirrus_late_probe,
14202 + .controls = rpi_cirrus_controls,
14203 + .num_controls = ARRAY_SIZE(rpi_cirrus_controls),
14204 + .dapm_widgets = rpi_cirrus_dapm_widgets,
14205 + .num_dapm_widgets = ARRAY_SIZE(rpi_cirrus_dapm_widgets),
14206 + .dapm_routes = rpi_cirrus_dapm_routes,
14207 + .num_dapm_routes = ARRAY_SIZE(rpi_cirrus_dapm_routes),
14208 + .set_bias_level = rpi_cirrus_set_bias_level,
14209 + .set_bias_level_post = rpi_cirrus_set_bias_level_post,
14212 +static int rpi_cirrus_probe(struct platform_device *pdev)
14215 + struct rpi_cirrus_priv *priv;
14216 + struct device_node *i2s_node;
14218 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
14222 + priv->min_rate_idx = 1; /* min samplerate 32kHz */
14223 + priv->card_rate = RPI_CIRRUS_DEFAULT_RATE;
14225 + mutex_init(&priv->lock);
14227 + snd_soc_card_set_drvdata(&rpi_cirrus_card, priv);
14229 + if (!pdev->dev.of_node)
14232 + i2s_node = of_parse_phandle(
14233 + pdev->dev.of_node, "i2s-controller", 0);
14235 + dev_err(&pdev->dev, "i2s-controller missing in DT\n");
14239 + rpi_cirrus_dai[DAI_WM5102].cpus->of_node = i2s_node;
14240 + rpi_cirrus_dai[DAI_WM5102].platforms->of_node = i2s_node;
14242 + rpi_cirrus_card.dev = &pdev->dev;
14244 + ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card);
14246 + if (ret == -EPROBE_DEFER)
14247 + dev_dbg(&pdev->dev,
14248 + "register card requested probe deferral\n");
14250 + dev_err(&pdev->dev,
14251 + "Failed to register card: %d\n", ret);
14257 +static const struct of_device_id rpi_cirrus_of_match[] = {
14258 + { .compatible = "wlf,rpi-cirrus", },
14261 +MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match);
14263 +static struct platform_driver rpi_cirrus_driver = {
14265 + .name = "snd-rpi-cirrus",
14266 + .of_match_table = of_match_ptr(rpi_cirrus_of_match),
14268 + .probe = rpi_cirrus_probe,
14271 +module_platform_driver(rpi_cirrus_driver);
14273 +MODULE_AUTHOR("Matthias Reichl <hias@horus.com>");
14274 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card");
14275 +MODULE_LICENSE("GPL");
14277 +++ b/sound/soc/bcm/rpi-proto.c
14280 + * ASoC driver for PROTO AudioCODEC (with a WM8731)
14281 + * connected to a Raspberry Pi
14283 + * Author: Florian Meier, <koalo@koalo.de>
14286 + * This program is free software; you can redistribute it and/or modify
14287 + * it under the terms of the GNU General Public License version 2 as
14288 + * published by the Free Software Foundation.
14291 +#include <linux/module.h>
14292 +#include <linux/platform_device.h>
14294 +#include <sound/core.h>
14295 +#include <sound/pcm.h>
14296 +#include <sound/soc.h>
14297 +#include <sound/jack.h>
14299 +#include "../codecs/wm8731.h"
14301 +static const unsigned int wm8731_rates_12288000[] = {
14302 + 8000, 32000, 48000, 96000,
14305 +static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
14306 + .list = wm8731_rates_12288000,
14307 + .count = ARRAY_SIZE(wm8731_rates_12288000),
14310 +static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
14312 + /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
14313 + snd_pcm_hw_constraint_list(substream->runtime, 0,
14314 + SNDRV_PCM_HW_PARAM_RATE,
14315 + &wm8731_constraints_12288000);
14319 +static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
14320 + struct snd_pcm_hw_params *params)
14322 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
14323 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14324 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
14325 + int sysclk = 12288000; /* This is fixed on this board */
14327 + /* Set proto bclk */
14328 + int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
14330 + dev_err(rtd->card->dev,
14331 + "Failed to set BCLK ratio %d\n", ret);
14335 + /* Set proto sysclk */
14336 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
14337 + sysclk, SND_SOC_CLOCK_IN);
14339 + dev_err(rtd->card->dev,
14340 + "Failed to set WM8731 SYSCLK: %d\n", ret);
14347 +/* machine stream operations */
14348 +static struct snd_soc_ops snd_rpi_proto_ops = {
14349 + .startup = snd_rpi_proto_startup,
14350 + .hw_params = snd_rpi_proto_hw_params,
14353 +SND_SOC_DAILINK_DEFS(rpi_proto,
14354 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
14355 + DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.1-001a", "wm8731-hifi")),
14356 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
14358 +static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
14360 + .name = "WM8731",
14361 + .stream_name = "WM8731 HiFi",
14362 + .dai_fmt = SND_SOC_DAIFMT_I2S
14363 + | SND_SOC_DAIFMT_NB_NF
14364 + | SND_SOC_DAIFMT_CBM_CFM,
14365 + .ops = &snd_rpi_proto_ops,
14366 + SND_SOC_DAILINK_REG(rpi_proto),
14370 +/* audio machine driver */
14371 +static struct snd_soc_card snd_rpi_proto = {
14372 + .name = "snd_rpi_proto",
14373 + .owner = THIS_MODULE,
14374 + .dai_link = snd_rpi_proto_dai,
14375 + .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
14378 +static int snd_rpi_proto_probe(struct platform_device *pdev)
14382 + snd_rpi_proto.dev = &pdev->dev;
14384 + if (pdev->dev.of_node) {
14385 + struct device_node *i2s_node;
14386 + struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
14387 + i2s_node = of_parse_phandle(pdev->dev.of_node,
14388 + "i2s-controller", 0);
14391 + dai->cpus->dai_name = NULL;
14392 + dai->cpus->of_node = i2s_node;
14393 + dai->platforms->name = NULL;
14394 + dai->platforms->of_node = i2s_node;
14398 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_proto);
14399 + if (ret && ret != -EPROBE_DEFER)
14400 + dev_err(&pdev->dev,
14401 + "snd_soc_register_card() failed: %d\n", ret);
14406 +static const struct of_device_id snd_rpi_proto_of_match[] = {
14407 + { .compatible = "rpi,rpi-proto", },
14410 +MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
14412 +static struct platform_driver snd_rpi_proto_driver = {
14414 + .name = "snd-rpi-proto",
14415 + .owner = THIS_MODULE,
14416 + .of_match_table = snd_rpi_proto_of_match,
14418 + .probe = snd_rpi_proto_probe,
14421 +module_platform_driver(snd_rpi_proto_driver);
14423 +MODULE_AUTHOR("Florian Meier");
14424 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
14425 +MODULE_LICENSE("GPL");
14427 +++ b/sound/soc/bcm/rpi-simple-soundcard.c
14429 +// SPDX-License-Identifier: GPL-2.0
14431 + * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard.
14433 + * Copyright (C) 2018 Raspberry Pi.
14435 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
14438 + * hifiberry_amp.c, hifiberry_dac.c, rpi-dac.c
14439 + * by Florian Meier <florian.meier@koalo.de>
14441 + * googlevoicehat-soundcard.c
14442 + * by Peter Malkin <petermalkin@google.com>
14445 + * by Andrey Grodzovsky <andrey2805@gmail.com>
14448 + * by Ariel Muszkat <ariel.muszkat@gmail.com>
14449 + * Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
14451 + * This program is free software; you can redistribute it and/or
14452 + * modify it under the terms of the GNU General Public License
14453 + * version 2 as published by the Free Software Foundation.
14455 + * This program is distributed in the hope that it will be useful, but
14456 + * WITHOUT ANY WARRANTY; without even the implied warranty of
14457 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14458 + * General Public License for more details.
14461 +#include <linux/module.h>
14462 +#include <linux/platform_device.h>
14463 +#include <linux/gpio/consumer.h>
14465 +#include <sound/core.h>
14466 +#include <sound/pcm.h>
14467 +#include <sound/pcm_params.h>
14468 +#include <sound/soc.h>
14470 +/* Parameters for generic RPI functions */
14471 +struct snd_rpi_simple_drvdata {
14472 + struct snd_soc_dai_link *dai;
14473 + const char* card_name;
14474 + unsigned int fixed_bclk_ratio;
14477 +static struct snd_soc_card snd_rpi_simple = {
14478 + .driver_name = "RPi-simple",
14479 + .owner = THIS_MODULE,
14480 + .dai_link = NULL,
14481 + .num_links = 1, /* Only a single DAI supported at the moment */
14484 +static int snd_rpi_simple_init(struct snd_soc_pcm_runtime *rtd)
14486 + struct snd_rpi_simple_drvdata *drvdata =
14487 + snd_soc_card_get_drvdata(rtd->card);
14488 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
14490 + if (drvdata->fixed_bclk_ratio > 0)
14491 + return snd_soc_dai_set_bclk_ratio(cpu_dai,
14492 + drvdata->fixed_bclk_ratio);
14497 +static int pifi_mini_210_init(struct snd_soc_pcm_runtime *rtd)
14499 + struct snd_soc_component *dac;
14500 + struct gpio_desc *pdn_gpio, *rst_gpio;
14501 + struct snd_soc_dai *codec_dai;
14504 + snd_rpi_simple_init(rtd);
14505 + codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14507 + dac = codec_dai[0].component;
14509 + pdn_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "pdn",
14511 + if (IS_ERR(pdn_gpio)) {
14512 + ret = PTR_ERR(pdn_gpio);
14513 + dev_err(snd_rpi_simple.dev, "failed to get pdn gpio: %d\n", ret);
14517 + rst_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "rst",
14519 + if (IS_ERR(rst_gpio)) {
14520 + ret = PTR_ERR(rst_gpio);
14521 + dev_err(snd_rpi_simple.dev, "failed to get rst gpio: %d\n", ret);
14525 + // Set up cards - pulse power down and reset first, then
14526 + // set up according to datasheet
14527 + gpiod_set_value_cansleep(pdn_gpio, 1);
14528 + gpiod_set_value_cansleep(rst_gpio, 1);
14529 + usleep_range(1000, 10000);
14530 + gpiod_set_value_cansleep(pdn_gpio, 0);
14531 + usleep_range(20000, 30000);
14532 + gpiod_set_value_cansleep(rst_gpio, 0);
14533 + usleep_range(20000, 30000);
14535 + // Oscillator trim
14536 + snd_soc_component_write(dac, 0x1b, 0);
14537 + usleep_range(60000, 80000);
14539 + // MCLK at 64fs, sample rate 44.1 or 48kHz
14540 + snd_soc_component_write(dac, 0x00, 0x60);
14542 + // Set up for BTL - AD/BD mode - AD is 0x00107772, BD is 0x00987772
14543 + snd_soc_component_write(dac, 0x20, 0x00107772);
14546 + snd_soc_component_write(dac, 0x05, 0x00);
14551 +static int snd_rpi_simple_hw_params(struct snd_pcm_substream *substream,
14552 + struct snd_pcm_hw_params *params)
14554 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
14555 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
14556 + struct snd_rpi_simple_drvdata *drvdata;
14557 + unsigned int sample_bits;
14559 + drvdata = snd_soc_card_get_drvdata(rtd->card);
14561 + if (drvdata->fixed_bclk_ratio > 0)
14562 + return 0; // BCLK is configured in .init
14564 + /* The simple drivers just set the bclk_ratio to sample_bits * 2 so
14565 + * hard-code this for now, but sticking to powers of 2 to allow for
14566 + * integer clock divisors. More complex drivers could just replace
14567 + * the hw_params routine.
14569 + sample_bits = snd_pcm_format_width(params_format(params));
14570 + sample_bits = sample_bits <= 16 ? 16 : 32;
14572 + return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
14575 +static struct snd_soc_ops snd_rpi_simple_ops = {
14576 + .hw_params = snd_rpi_simple_hw_params,
14579 +static int snd_merus_amp_hw_params(struct snd_pcm_substream *substream,
14580 + struct snd_pcm_hw_params *params)
14582 + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
14585 + rate = params_rate(params);
14586 + if (rate > 48000) {
14587 + dev_err(rtd->card->dev,
14588 + "Unsupported samplerate %d\n",
14595 +static struct snd_soc_ops snd_merus_amp_ops = {
14596 + .hw_params = snd_merus_amp_hw_params,
14599 +enum adau1977_clk_id {
14603 +enum adau1977_sysclk_src {
14604 + ADAU1977_SYSCLK_SRC_MCLK,
14605 + ADAU1977_SYSCLK_SRC_LRCLK,
14608 +static int adau1977_init(struct snd_soc_pcm_runtime *rtd)
14611 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14613 + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 0);
14617 + return snd_soc_component_set_sysclk(codec_dai->component,
14618 + ADAU1977_SYSCLK, ADAU1977_SYSCLK_SRC_MCLK,
14619 + 11289600, SND_SOC_CLOCK_IN);
14622 +SND_SOC_DAILINK_DEFS(adau1977,
14623 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14624 + DAILINK_COMP_ARRAY(COMP_CODEC("adau1977.1-0011", "adau1977-hifi")),
14625 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14627 +static struct snd_soc_dai_link snd_rpi_adau1977_dai[] = {
14629 + .name = "adau1977",
14630 + .stream_name = "ADAU1977",
14631 + .init = adau1977_init,
14632 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14633 + SND_SOC_DAIFMT_NB_NF |
14634 + SND_SOC_DAIFMT_CBM_CFM,
14635 + SND_SOC_DAILINK_REG(adau1977),
14639 +static struct snd_rpi_simple_drvdata drvdata_adau1977 = {
14640 + .card_name = "snd_rpi_adau1977_adc",
14641 + .dai = snd_rpi_adau1977_dai,
14644 +SND_SOC_DAILINK_DEFS(gvchat,
14645 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14646 + DAILINK_COMP_ARRAY(COMP_CODEC("voicehat-codec", "voicehat-hifi")),
14647 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14649 +static struct snd_soc_dai_link snd_googlevoicehat_soundcard_dai[] = {
14651 + .name = "Google voiceHAT SoundCard",
14652 + .stream_name = "Google voiceHAT SoundCard HiFi",
14653 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
14654 + SND_SOC_DAIFMT_CBS_CFS,
14655 + SND_SOC_DAILINK_REG(gvchat),
14659 +static struct snd_rpi_simple_drvdata drvdata_googlevoicehat = {
14660 + .card_name = "snd_rpi_googlevoicehat_soundcard",
14661 + .dai = snd_googlevoicehat_soundcard_dai,
14664 +SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp,
14665 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14666 + DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")),
14667 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14669 +static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
14671 + .name = "Hifiberry DAC+DSP SoundCard",
14672 + .stream_name = "Hifiberry DAC+DSP SoundCard HiFi",
14673 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14674 + SND_SOC_DAIFMT_NB_NF |
14675 + SND_SOC_DAIFMT_CBS_CFS,
14676 + SND_SOC_DAILINK_REG(hifiberry_dacplusdsp),
14680 +static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
14681 + .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
14682 + .dai = snd_hifiberrydacplusdsp_soundcard_dai,
14685 +SND_SOC_DAILINK_DEFS(hifiberry_adc,
14686 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14687 + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")),
14688 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14690 +static int hifiberry_adc8x_init(struct snd_soc_pcm_runtime *rtd)
14692 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14694 + /* set limits of 8 channels and 192ksps sample rate
14696 + codec_dai->driver->capture.channels_max = 8;
14697 + codec_dai->driver->capture.rates = SNDRV_PCM_RATE_8000_192000;
14702 +static struct snd_soc_dai_link snd_hifiberry_adc8x_dai[] = {
14704 + .name = "HifiBerry ADC8x",
14705 + .stream_name = "HifiBerry ADC8x HiFi",
14706 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14707 + SND_SOC_DAIFMT_NB_NF |
14708 + SND_SOC_DAIFMT_CBS_CFS,
14709 + .init = hifiberry_adc8x_init,
14710 + SND_SOC_DAILINK_REG(hifiberry_adc),
14714 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_adc8x = {
14715 + .card_name = "snd_rpi_hifiberry_adc8x",
14716 + .dai = snd_hifiberry_adc8x_dai,
14717 + .fixed_bclk_ratio = 64,
14720 +SND_SOC_DAILINK_DEFS(hifiberry_amp,
14721 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14722 + DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")),
14723 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14725 +static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
14727 + .name = "HifiBerry AMP",
14728 + .stream_name = "HifiBerry AMP HiFi",
14729 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14730 + SND_SOC_DAIFMT_NB_NF |
14731 + SND_SOC_DAIFMT_CBS_CFS,
14732 + SND_SOC_DAILINK_REG(hifiberry_amp),
14736 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp = {
14737 + .card_name = "snd_rpi_hifiberry_amp",
14738 + .dai = snd_hifiberry_amp_dai,
14739 + .fixed_bclk_ratio = 64,
14742 +SND_SOC_DAILINK_DEFS(hifiberry_amp3,
14743 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14744 + DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")),
14745 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14747 +static struct snd_soc_dai_link snd_hifiberry_amp3_dai[] = {
14749 + .name = "HifiberryAmp3",
14750 + .stream_name = "Hifiberry Amp3",
14751 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14752 + SND_SOC_DAIFMT_NB_NF |
14753 + SND_SOC_DAIFMT_CBS_CFS,
14754 + SND_SOC_DAILINK_REG(hifiberry_amp3),
14758 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp3 = {
14759 + .card_name = "snd_rpi_hifiberry_amp3",
14760 + .dai = snd_hifiberry_amp3_dai,
14761 + .fixed_bclk_ratio = 64,
14764 +SND_SOC_DAILINK_DEFS(hifiberry_dac,
14765 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14766 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")),
14767 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14769 +static struct snd_soc_dai_link snd_hifiberry_dac_dai[] = {
14771 + .name = "HifiBerry DAC",
14772 + .stream_name = "HifiBerry DAC HiFi",
14773 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14774 + SND_SOC_DAIFMT_NB_NF |
14775 + SND_SOC_DAIFMT_CBS_CFS,
14776 + SND_SOC_DAILINK_REG(hifiberry_dac),
14780 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac = {
14781 + .card_name = "snd_rpi_hifiberry_dac",
14782 + .dai = snd_hifiberry_dac_dai,
14785 +static int hifiberry_dac8x_init(struct snd_soc_pcm_runtime *rtd)
14787 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
14789 + /* override the defaults to reflect 4 x PCM5102A on the card
14790 + * and limit the sample rate to 192ksps
14792 + codec_dai->driver->playback.channels_max = 8;
14793 + codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000;
14798 +static struct snd_soc_dai_link snd_hifiberry_dac8x_dai[] = {
14800 + .name = "HifiBerry DAC8x",
14801 + .stream_name = "HifiBerry DAC8x HiFi",
14802 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14803 + SND_SOC_DAIFMT_NB_NF |
14804 + SND_SOC_DAIFMT_CBS_CFS,
14805 + .init = hifiberry_dac8x_init,
14806 + SND_SOC_DAILINK_REG(hifiberry_dac),
14810 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac8x = {
14811 + .card_name = "snd_rpi_hifiberry_dac8x",
14812 + .dai = snd_hifiberry_dac8x_dai,
14813 + .fixed_bclk_ratio = 64,
14816 +SND_SOC_DAILINK_DEFS(dionaudio_kiwi,
14817 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14818 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")),
14819 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14821 +static struct snd_soc_dai_link snd_dionaudio_kiwi_dai[] = {
14823 + .name = "DionAudio KIWI",
14824 + .stream_name = "DionAudio KIWI STREAMER",
14825 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
14826 + SND_SOC_DAIFMT_CBS_CFS,
14827 + SND_SOC_DAILINK_REG(dionaudio_kiwi),
14831 +static struct snd_rpi_simple_drvdata drvdata_dionaudio_kiwi = {
14832 + .card_name = "snd_rpi_dionaudio_kiwi",
14833 + .dai = snd_dionaudio_kiwi_dai,
14834 + .fixed_bclk_ratio = 64,
14837 +SND_SOC_DAILINK_DEFS(rpi_dac,
14838 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14839 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")),
14840 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14842 +static struct snd_soc_dai_link snd_rpi_dac_dai[] = {
14844 + .name = "RPi-DAC",
14845 + .stream_name = "RPi-DAC HiFi",
14846 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
14847 + SND_SOC_DAIFMT_CBS_CFS,
14848 + SND_SOC_DAILINK_REG(rpi_dac),
14852 +static struct snd_rpi_simple_drvdata drvdata_rpi_dac = {
14853 + .card_name = "snd_rpi_rpi_dac",
14854 + .dai = snd_rpi_dac_dai,
14855 + .fixed_bclk_ratio = 64,
14858 +SND_SOC_DAILINK_DEFS(merus_amp,
14859 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14860 + DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020", "ma120x0p-amp")),
14861 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14863 +static struct snd_soc_dai_link snd_merus_amp_dai[] = {
14865 + .name = "MerusAmp",
14866 + .stream_name = "Merus Audio Amp",
14867 + .ops = &snd_merus_amp_ops,
14868 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14869 + SND_SOC_DAIFMT_NB_NF |
14870 + SND_SOC_DAIFMT_CBS_CFS,
14871 + SND_SOC_DAILINK_REG(merus_amp),
14875 +static struct snd_rpi_simple_drvdata drvdata_merus_amp = {
14876 + .card_name = "snd_rpi_merus_amp",
14877 + .dai = snd_merus_amp_dai,
14878 + .fixed_bclk_ratio = 64,
14881 +SND_SOC_DAILINK_DEFS(pifi_mini_210,
14882 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
14883 + DAILINK_COMP_ARRAY(COMP_CODEC("tas571x.1-001a", "tas571x-hifi")),
14884 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
14886 +static struct snd_soc_dai_link snd_pifi_mini_210_dai[] = {
14888 + .name = "PiFi Mini 210",
14889 + .stream_name = "PiFi Mini 210 HiFi",
14890 + .init = pifi_mini_210_init,
14891 + .dai_fmt = SND_SOC_DAIFMT_I2S |
14892 + SND_SOC_DAIFMT_NB_NF |
14893 + SND_SOC_DAIFMT_CBS_CFS,
14894 + SND_SOC_DAILINK_REG(pifi_mini_210),
14898 +static struct snd_rpi_simple_drvdata drvdata_pifi_mini_210 = {
14899 + .card_name = "snd_pifi_mini_210",
14900 + .dai = snd_pifi_mini_210_dai,
14901 + .fixed_bclk_ratio = 64,
14904 +static const struct of_device_id snd_rpi_simple_of_match[] = {
14905 + { .compatible = "adi,adau1977-adc",
14906 + .data = (void *) &drvdata_adau1977 },
14907 + { .compatible = "googlevoicehat,googlevoicehat-soundcard",
14908 + .data = (void *) &drvdata_googlevoicehat },
14909 + { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
14910 + .data = (void *) &drvdata_hifiberrydacplusdsp },
14911 + { .compatible = "hifiberry,hifiberry-adc8x",
14912 + .data = (void *) &drvdata_hifiberry_adc8x },
14913 + { .compatible = "hifiberry,hifiberry-amp",
14914 + .data = (void *) &drvdata_hifiberry_amp },
14915 + { .compatible = "hifiberry,hifiberry-amp3",
14916 + .data = (void *) &drvdata_hifiberry_amp3 },
14917 + { .compatible = "hifiberry,hifiberry-dac",
14918 + .data = (void *) &drvdata_hifiberry_dac },
14919 + { .compatible = "hifiberry,hifiberry-dac8x",
14920 + .data = (void *) &drvdata_hifiberry_dac8x },
14921 + { .compatible = "dionaudio,dionaudio-kiwi",
14922 + .data = (void *) &drvdata_dionaudio_kiwi },
14923 + { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac},
14924 + { .compatible = "merus,merus-amp",
14925 + .data = (void *) &drvdata_merus_amp },
14926 + { .compatible = "pifi,pifi-mini-210",
14927 + .data = (void *) &drvdata_pifi_mini_210 },
14931 +static int snd_rpi_simple_probe(struct platform_device *pdev)
14934 + const struct of_device_id *of_id;
14936 + snd_rpi_simple.dev = &pdev->dev;
14937 + of_id = of_match_node(snd_rpi_simple_of_match, pdev->dev.of_node);
14939 + if (pdev->dev.of_node && of_id->data) {
14940 + struct device_node *i2s_node;
14941 + struct snd_rpi_simple_drvdata *drvdata =
14942 + (struct snd_rpi_simple_drvdata *) of_id->data;
14943 + struct snd_soc_dai_link *dai = drvdata->dai;
14945 + snd_soc_card_set_drvdata(&snd_rpi_simple, drvdata);
14947 + /* More complex drivers might override individual functions */
14949 + dai->init = snd_rpi_simple_init;
14951 + dai->ops = &snd_rpi_simple_ops;
14953 + snd_rpi_simple.name = drvdata->card_name;
14955 + snd_rpi_simple.dai_link = dai;
14956 + i2s_node = of_parse_phandle(pdev->dev.of_node,
14957 + "i2s-controller", 0);
14959 + pr_err("Failed to find i2s-controller DT node\n");
14963 + dai->cpus->of_node = i2s_node;
14964 + dai->platforms->of_node = i2s_node;
14967 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_simple);
14968 + if (ret && ret != -EPROBE_DEFER)
14969 + dev_err(&pdev->dev, "Failed to register card %d\n", ret);
14974 +static struct platform_driver snd_rpi_simple_driver = {
14976 + .name = "snd-rpi-simple",
14977 + .owner = THIS_MODULE,
14978 + .of_match_table = snd_rpi_simple_of_match,
14980 + .probe = snd_rpi_simple_probe,
14982 +MODULE_DEVICE_TABLE(of, snd_rpi_simple_of_match);
14984 +module_platform_driver(snd_rpi_simple_driver);
14986 +MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
14987 +MODULE_DESCRIPTION("ASoC Raspberry Pi simple soundcard driver ");
14988 +MODULE_LICENSE("GPL v2");
14990 +++ b/sound/soc/bcm/rpi-wm8804-soundcard.c
14992 +// SPDX-License-Identifier: GPL-2.0
14994 + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
14996 + * Copyright (C) 2018 Raspberry Pi.
14998 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
15000 + * Generic driver for Pi Hat WM8804 digi sounds cards
15002 + * Based upon code from:
15003 + * justboom-digi.c
15004 + * by Milan Neskovic <info@justboom.co>
15007 + * by Daniel Matuschek <info@crazy-audio.com>
15010 + * by Baswaraj <jaikumar@cem-solutions.net>
15012 + * hifiberry-digi.c
15013 + * Daniel Matuschek <info@crazy-audio.com>
15015 + * This program is free software; you can redistribute it and/or
15016 + * modify it under the terms of the GNU General Public License
15017 + * version 2 as published by the Free Software Foundation.
15019 + * This program is distributed in the hope that it will be useful, but
15020 + * WITHOUT ANY WARRANTY; without even the implied warranty of
15021 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15022 + * General Public License for more details.
15025 +#include <linux/gpio/consumer.h>
15026 +#include <linux/platform_device.h>
15027 +#include <linux/module.h>
15028 +#include <linux/delay.h>
15030 +#include <sound/core.h>
15031 +#include <sound/pcm.h>
15032 +#include <sound/pcm_params.h>
15033 +#include <sound/soc.h>
15035 +#include "../codecs/wm8804.h"
15037 +struct wm8804_clk_cfg {
15038 + unsigned int sysclk_freq;
15039 + unsigned int mclk_freq;
15040 + unsigned int mclk_div;
15043 +/* Parameters for generic functions */
15044 +struct snd_rpi_wm8804_drvdata {
15045 + /* Required - pointer to the DAI structure */
15046 + struct snd_soc_dai_link *dai;
15047 + /* Required - snd_soc_card name */
15048 + const char *card_name;
15049 + /* Optional DT node names if card info is defined in DT */
15050 + const char *card_name_dt;
15051 + const char *dai_name_dt;
15052 + const char *dai_stream_name_dt;
15053 + /* Optional probe extension - called prior to register_card */
15054 + int (*probe)(struct platform_device *pdev);
15057 +static struct gpio_desc *snd_clk44gpio;
15058 +static struct gpio_desc *snd_clk48gpio;
15059 +static int wm8804_samplerate = 0;
15060 +static struct gpio_desc *led_gpio_1;
15061 +static struct gpio_desc *led_gpio_2;
15062 +static struct gpio_desc *led_gpio_3;
15063 +static struct gpio_desc *custom_reset;
15065 +/* Forward declarations */
15066 +static struct snd_soc_dai_link snd_allo_digione_dai[];
15067 +static struct snd_soc_card snd_rpi_wm8804;
15070 +#define CLK_44EN_RATE 22579200UL
15071 +#define CLK_48EN_RATE 24576000UL
15073 +static const char * const wm8805_input_select_text[] = {
15084 +static const unsigned int wm8805_input_channel_select_value[] = {
15085 + 0, 1, 2, 3, 4, 5, 6, 7
15088 +static const struct soc_enum wm8805_input_channel_sel[] = {
15089 + SOC_VALUE_ENUM_SINGLE(WM8804_PLL6, 0, 7, ARRAY_SIZE(wm8805_input_select_text),
15090 + wm8805_input_select_text, wm8805_input_channel_select_value),
15093 +static const struct snd_kcontrol_new wm8805_input_controls_card[] = {
15094 + SOC_ENUM("Select Input Channel", wm8805_input_channel_sel[0]),
15097 +static int wm8805_add_input_controls(struct snd_soc_component *component)
15099 + snd_soc_add_component_controls(component, wm8805_input_controls_card,
15100 + ARRAY_SIZE(wm8805_input_controls_card));
15104 +static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
15106 + switch (samplerate) {
15112 + gpiod_set_value_cansleep(snd_clk44gpio, 1);
15113 + gpiod_set_value_cansleep(snd_clk48gpio, 0);
15114 + return CLK_44EN_RATE;
15116 + gpiod_set_value_cansleep(snd_clk48gpio, 1);
15117 + gpiod_set_value_cansleep(snd_clk44gpio, 0);
15118 + return CLK_48EN_RATE;
15122 +static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
15123 + struct wm8804_clk_cfg *clk_cfg)
15125 + clk_cfg->sysclk_freq = 27000000;
15127 + if (samplerate <= 96000 ||
15128 + snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
15129 + clk_cfg->mclk_freq = samplerate * 256;
15130 + clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
15132 + clk_cfg->mclk_freq = samplerate * 128;
15133 + clk_cfg->mclk_div = WM8804_MCLKDIV_128FS;
15136 + if (!(IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)))
15137 + clk_cfg->sysclk_freq = snd_rpi_wm8804_enable_clock(samplerate);
15140 +static int snd_rpi_wm8804_hw_params(struct snd_pcm_substream *substream,
15141 + struct snd_pcm_hw_params *params)
15143 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
15144 + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
15145 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
15146 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
15147 + int sampling_freq = 1;
15149 + struct wm8804_clk_cfg clk_cfg;
15150 + int samplerate = params_rate(params);
15152 + if (samplerate == wm8804_samplerate)
15155 + /* clear until all clocks are setup properly */
15156 + wm8804_samplerate = 0;
15158 + snd_rpi_wm8804_clk_cfg(samplerate, &clk_cfg);
15160 + pr_debug("%s samplerate: %d mclk_freq: %u mclk_div: %u sysclk: %u\n",
15161 + __func__, samplerate, clk_cfg.mclk_freq,
15162 + clk_cfg.mclk_div, clk_cfg.sysclk_freq);
15164 + switch (samplerate) {
15166 + sampling_freq = 0x03;
15169 + sampling_freq = 0x00;
15172 + sampling_freq = 0x02;
15175 + sampling_freq = 0x08;
15178 + sampling_freq = 0x0a;
15181 + sampling_freq = 0x0c;
15184 + sampling_freq = 0x0e;
15187 + dev_err(rtd->card->dev,
15188 + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
15192 + snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, clk_cfg.mclk_div);
15193 + snd_soc_dai_set_pll(codec_dai, 0, 0,
15194 + clk_cfg.sysclk_freq, clk_cfg.mclk_freq);
15196 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
15197 + clk_cfg.sysclk_freq, SND_SOC_CLOCK_OUT);
15199 + dev_err(rtd->card->dev,
15200 + "Failed to set WM8804 SYSCLK: %d\n", ret);
15204 + wm8804_samplerate = samplerate;
15206 + /* set sampling frequency status bits */
15207 + snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f,
15210 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
15213 +static struct snd_soc_ops snd_rpi_wm8804_ops = {
15214 + .hw_params = snd_rpi_wm8804_hw_params,
15217 +static int snd_interlude_audio_hw_params(struct snd_pcm_substream *substream,
15218 + struct snd_pcm_hw_params *params)
15220 + int ret = snd_rpi_wm8804_hw_params(substream, params);
15221 + int samplerate = params_rate(params);
15223 + switch (samplerate) {
15225 + gpiod_set_value_cansleep(led_gpio_1, 1);
15226 + gpiod_set_value_cansleep(led_gpio_2, 0);
15227 + gpiod_set_value_cansleep(led_gpio_3, 0);
15230 + gpiod_set_value_cansleep(led_gpio_1, 1);
15231 + gpiod_set_value_cansleep(led_gpio_2, 0);
15232 + gpiod_set_value_cansleep(led_gpio_3, 0);
15235 + gpiod_set_value_cansleep(led_gpio_1, 0);
15236 + gpiod_set_value_cansleep(led_gpio_2, 1);
15237 + gpiod_set_value_cansleep(led_gpio_3, 0);
15240 + gpiod_set_value_cansleep(led_gpio_1, 0);
15241 + gpiod_set_value_cansleep(led_gpio_2, 1);
15242 + gpiod_set_value_cansleep(led_gpio_3, 0);
15245 + gpiod_set_value_cansleep(led_gpio_1, 0);
15246 + gpiod_set_value_cansleep(led_gpio_2, 0);
15247 + gpiod_set_value_cansleep(led_gpio_3, 1);
15250 + gpiod_set_value_cansleep(led_gpio_1, 0);
15251 + gpiod_set_value_cansleep(led_gpio_2, 0);
15252 + gpiod_set_value_cansleep(led_gpio_3, 1);
15260 +const struct snd_soc_ops interlude_audio_digital_dai_ops = {
15261 + .hw_params = snd_interlude_audio_hw_params,
15264 +SND_SOC_DAILINK_DEFS(justboom_digi,
15265 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15266 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15267 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
15269 +static struct snd_soc_dai_link snd_justboom_digi_dai[] = {
15271 + .name = "JustBoom Digi",
15272 + .stream_name = "JustBoom Digi HiFi",
15273 + SND_SOC_DAILINK_REG(justboom_digi),
15277 +static struct snd_rpi_wm8804_drvdata drvdata_justboom_digi = {
15278 + .card_name = "snd_rpi_justboom_digi",
15279 + .dai = snd_justboom_digi_dai,
15282 +SND_SOC_DAILINK_DEFS(iqaudio_digi,
15283 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15284 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15285 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
15287 +static struct snd_soc_dai_link snd_iqaudio_digi_dai[] = {
15289 + .name = "IQAudIO Digi",
15290 + .stream_name = "IQAudIO Digi HiFi",
15291 + SND_SOC_DAILINK_REG(iqaudio_digi),
15295 +static struct snd_rpi_wm8804_drvdata drvdata_iqaudio_digi = {
15296 + .card_name = "IQAudIODigi",
15297 + .dai = snd_iqaudio_digi_dai,
15298 + .card_name_dt = "wm8804-digi,card-name",
15299 + .dai_name_dt = "wm8804-digi,dai-name",
15300 + .dai_stream_name_dt = "wm8804-digi,dai-stream-name",
15303 +static int snd_allo_digione_probe(struct platform_device *pdev)
15305 + pr_debug("%s\n", __func__);
15307 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) {
15308 + dev_err(&pdev->dev, "devm_gpiod_get() failed\n");
15314 +SND_SOC_DAILINK_DEFS(allo_digione,
15315 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15316 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15317 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
15319 +static struct snd_soc_dai_link snd_allo_digione_dai[] = {
15321 + .name = "Allo DigiOne",
15322 + .stream_name = "Allo DigiOne HiFi",
15323 + SND_SOC_DAILINK_REG(allo_digione),
15327 +static struct snd_rpi_wm8804_drvdata drvdata_allo_digione = {
15328 + .card_name = "snd_allo_digione",
15329 + .dai = snd_allo_digione_dai,
15330 + .probe = snd_allo_digione_probe,
15333 +SND_SOC_DAILINK_DEFS(hifiberry_digi,
15334 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15335 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15336 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
15338 +static struct snd_soc_dai_link snd_hifiberry_digi_dai[] = {
15340 + .name = "HifiBerry Digi",
15341 + .stream_name = "HifiBerry Digi HiFi",
15342 + SND_SOC_DAILINK_REG(hifiberry_digi),
15346 +static int snd_hifiberry_digi_probe(struct platform_device *pdev)
15348 + pr_debug("%s\n", __func__);
15350 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
15353 + snd_hifiberry_digi_dai->name = "HiFiBerry Digi+ Pro";
15354 + snd_hifiberry_digi_dai->stream_name = "HiFiBerry Digi+ Pro HiFi";
15358 +static struct snd_rpi_wm8804_drvdata drvdata_hifiberry_digi = {
15359 + .card_name = "snd_rpi_hifiberry_digi",
15360 + .dai = snd_hifiberry_digi_dai,
15361 + .probe = snd_hifiberry_digi_probe,
15364 +SND_SOC_DAILINK_DEFS(interlude_audio_digital,
15365 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15366 + DAILINK_COMP_ARRAY(COMP_EMPTY()),
15367 + DAILINK_COMP_ARRAY(COMP_EMPTY()));
15369 +static int snd_interlude_audio_init(struct snd_soc_pcm_runtime *rtd)
15371 + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
15374 + ret = wm8805_add_input_controls(component);
15376 + pr_err("failed to add input controls");
15382 +static struct snd_soc_dai_link snd_interlude_audio_digital_dai[] = {
15384 + .name = "Interlude Audio Digital",
15385 + .stream_name = "Interlude Audio Digital HiFi",
15386 + .init = snd_interlude_audio_init,
15387 + .ops = &interlude_audio_digital_dai_ops,
15388 + SND_SOC_DAILINK_REG(interlude_audio_digital),
15393 +static int snd_interlude_audio_digital_probe(struct platform_device *pdev)
15395 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
15398 + custom_reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
15399 + gpiod_set_value_cansleep(custom_reset, 0);
15401 + gpiod_set_value_cansleep(custom_reset, 1);
15403 + snd_interlude_audio_digital_dai->name = "Interlude Audio Digital";
15404 + snd_interlude_audio_digital_dai->stream_name = "Interlude Audio Digital HiFi";
15405 + led_gpio_1 = devm_gpiod_get(&pdev->dev, "led1", GPIOD_OUT_LOW);
15406 + led_gpio_2 = devm_gpiod_get(&pdev->dev, "led2", GPIOD_OUT_LOW);
15407 + led_gpio_3 = devm_gpiod_get(&pdev->dev, "led3", GPIOD_OUT_LOW);
15412 +static struct snd_rpi_wm8804_drvdata drvdata_interlude_audio_digital = {
15413 + .card_name = "snd_IA_Digital_Hat",
15414 + .dai = snd_interlude_audio_digital_dai,
15415 + .probe = snd_interlude_audio_digital_probe,
15418 +static const struct of_device_id snd_rpi_wm8804_of_match[] = {
15419 + { .compatible = "justboom,justboom-digi",
15420 + .data = (void *) &drvdata_justboom_digi },
15421 + { .compatible = "iqaudio,wm8804-digi",
15422 + .data = (void *) &drvdata_iqaudio_digi },
15423 + { .compatible = "allo,allo-digione",
15424 + .data = (void *) &drvdata_allo_digione },
15425 + { .compatible = "hifiberry,hifiberry-digi",
15426 + .data = (void *) &drvdata_hifiberry_digi },
15427 + { .compatible = "interludeaudio,interludeaudio-digital",
15428 + .data = (void *) &drvdata_interlude_audio_digital },
15432 +static struct snd_soc_card snd_rpi_wm8804 = {
15433 + .driver_name = "RPi-WM8804",
15434 + .owner = THIS_MODULE,
15435 + .dai_link = NULL,
15439 +static int snd_rpi_wm8804_probe(struct platform_device *pdev)
15442 + const struct of_device_id *of_id;
15444 + snd_rpi_wm8804.dev = &pdev->dev;
15445 + of_id = of_match_node(snd_rpi_wm8804_of_match, pdev->dev.of_node);
15447 + if (pdev->dev.of_node && of_id->data) {
15448 + struct device_node *i2s_node;
15449 + struct snd_rpi_wm8804_drvdata *drvdata =
15450 + (struct snd_rpi_wm8804_drvdata *) of_id->data;
15451 + struct snd_soc_dai_link *dai = drvdata->dai;
15453 + snd_soc_card_set_drvdata(&snd_rpi_wm8804, drvdata);
15456 + dai->ops = &snd_rpi_wm8804_ops;
15457 + if (!dai->codecs->dai_name)
15458 + dai->codecs->dai_name = "wm8804-spdif";
15459 + if (!dai->codecs->name)
15460 + dai->codecs->name = "wm8804.1-003b";
15461 + if (!dai->dai_fmt)
15462 + dai->dai_fmt = SND_SOC_DAIFMT_I2S |
15463 + SND_SOC_DAIFMT_NB_NF |
15464 + SND_SOC_DAIFMT_CBM_CFM;
15466 + snd_rpi_wm8804.dai_link = dai;
15467 + i2s_node = of_parse_phandle(pdev->dev.of_node,
15468 + "i2s-controller", 0);
15470 + pr_err("Failed to find i2s-controller DT node\n");
15474 + snd_rpi_wm8804.name = drvdata->card_name;
15476 + /* If requested by in drvdata get card & DAI names from DT */
15477 + if (drvdata->card_name_dt)
15478 + of_property_read_string(i2s_node,
15479 + drvdata->card_name_dt,
15480 + &snd_rpi_wm8804.name);
15482 + if (drvdata->dai_name_dt)
15483 + of_property_read_string(i2s_node,
15484 + drvdata->dai_name_dt,
15487 + if (drvdata->dai_stream_name_dt)
15488 + of_property_read_string(i2s_node,
15489 + drvdata->dai_stream_name_dt,
15490 + &dai->stream_name);
15492 + dai->cpus->of_node = i2s_node;
15493 + dai->platforms->of_node = i2s_node;
15496 + * clk44gpio and clk48gpio are not required by all cards so
15497 + * don't check the error status.
15500 + devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW);
15503 + devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW);
15505 + if (drvdata->probe) {
15506 + ret = drvdata->probe(pdev);
15508 + dev_err(&pdev->dev, "Custom probe failed %d\n",
15514 + pr_debug("%s card: %s dai: %s stream: %s\n", __func__,
15515 + snd_rpi_wm8804.name,
15516 + dai->name, dai->stream_name);
15519 + ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_wm8804);
15520 + if (ret && ret != -EPROBE_DEFER)
15521 + dev_err(&pdev->dev, "Failed to register card %d\n", ret);
15526 +static struct platform_driver snd_rpi_wm8804_driver = {
15528 + .name = "snd-rpi-wm8804",
15529 + .owner = THIS_MODULE,
15530 + .of_match_table = snd_rpi_wm8804_of_match,
15532 + .probe = snd_rpi_wm8804_probe,
15534 +MODULE_DEVICE_TABLE(of, snd_rpi_wm8804_of_match);
15536 +module_platform_driver(snd_rpi_wm8804_driver);
15538 +MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
15539 +MODULE_DESCRIPTION("ASoC Raspberry Pi Hat generic digi driver for WM8804 based cards");
15540 +MODULE_LICENSE("GPL v2");
15541 --- a/sound/soc/codecs/Kconfig
15542 +++ b/sound/soc/codecs/Kconfig
15543 @@ -125,6 +125,7 @@ config SND_SOC_ALL_CODECS
15544 imply SND_SOC_IDT821034
15545 imply SND_SOC_INNO_RK3036
15546 imply SND_SOC_ISABELLE
15547 + imply SND_SOC_I_SABRE_CODEC
15548 imply SND_SOC_JZ4740_CODEC
15549 imply SND_SOC_JZ4725B_CODEC
15550 imply SND_SOC_JZ4760_CODEC
15551 @@ -132,6 +133,7 @@ config SND_SOC_ALL_CODECS
15552 imply SND_SOC_LM4857
15553 imply SND_SOC_LM49453
15554 imply SND_SOC_LOCHNAGAR_SC
15555 + imply SND_SOC_MA120X0P
15556 imply SND_SOC_MAX98088
15557 imply SND_SOC_MAX98090
15558 imply SND_SOC_MAX98095
15559 @@ -175,6 +177,7 @@ config SND_SOC_ALL_CODECS
15560 imply SND_SOC_PCM179X_SPI
15561 imply SND_SOC_PCM186X_I2C
15562 imply SND_SOC_PCM186X_SPI
15563 + imply SND_SOC_PCM1794A
15564 imply SND_SOC_PCM3008
15565 imply SND_SOC_PCM3060_I2C
15566 imply SND_SOC_PCM3060_SPI
15567 @@ -267,6 +270,7 @@ config SND_SOC_ALL_CODECS
15568 imply SND_SOC_TLV320ADCX140
15569 imply SND_SOC_TLV320AIC23_I2C
15570 imply SND_SOC_TLV320AIC23_SPI
15571 + imply SND_SOC_TAS5713
15572 imply SND_SOC_TLV320AIC26
15573 imply SND_SOC_TLV320AIC31XX
15574 imply SND_SOC_TLV320AIC32X4_I2C
15575 @@ -424,12 +428,12 @@ config SND_SOC_AD193X
15578 config SND_SOC_AD193X_SPI
15580 + tristate "Analog Devices AU193X CODEC - SPI"
15581 depends on SPI_MASTER
15582 select SND_SOC_AD193X
15584 config SND_SOC_AD193X_I2C
15586 + tristate "Analog Devices AU193X CODEC - I2C"
15588 select SND_SOC_AD193X
15590 @@ -1229,6 +1233,13 @@ config SND_SOC_LOCHNAGAR_SC
15591 This driver support the sound card functionality of the Cirrus
15592 Logic Lochnagar audio development board.
15594 +config SND_SOC_MA120X0P
15595 + tristate "Infineon Merus(TM) MA120X0P Multilevel Class-D Audio amplifiers"
15598 + Enable support for Infineon MA120X0P Multilevel Class-D audio power
15601 config SND_SOC_MADERA
15603 default y if SND_SOC_CS47L15=y
15604 @@ -1638,6 +1649,10 @@ config SND_SOC_RT5616
15605 tristate "Realtek RT5616 CODEC"
15608 +config SND_SOC_PCM1794A
15612 config SND_SOC_RT5631
15613 tristate "Realtek ALC5631/RT5631 CODEC"
15615 @@ -1995,6 +2010,9 @@ config SND_SOC_TFA9879
15616 tristate "NXP Semiconductors TFA9879 amplifier"
15619 +config SND_SOC_TAS5713
15622 config SND_SOC_TFA989X
15623 tristate "NXP/Goodix TFA989X (TFA1) amplifiers"
15625 @@ -2596,4 +2614,8 @@ config SND_SOC_LPASS_TX_MACRO
15626 select SND_SOC_LPASS_MACRO_COMMON
15627 tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)"
15629 +config SND_SOC_I_SABRE_CODEC
15630 + tristate "Audiophonics I-SABRE Codec"
15634 --- a/sound/soc/codecs/Makefile
15635 +++ b/sound/soc/codecs/Makefile
15636 @@ -820,3 +820,12 @@ obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO) +=
15639 obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o
15641 +snd-soc-i-sabre-codec-objs := i-sabre-codec.o
15642 +snd-soc-ma120x0p-objs := ma120x0p.o
15643 +snd-soc-pcm1794a-objs := pcm1794a.o
15644 +snd-soc-tas5713-objs := tas5713.o
15645 +obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o
15646 +obj-$(CONFIG_SND_SOC_MA120X0P) += snd-soc-ma120x0p.o
15647 +obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o
15648 +obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
15649 --- a/sound/soc/codecs/adau1977-i2c.c
15650 +++ b/sound/soc/codecs/adau1977-i2c.c
15651 @@ -38,9 +38,19 @@ static const struct i2c_device_id adau19
15653 MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
15655 +static const struct of_device_id adau1977_of_ids[] = {
15656 + { .compatible = "adi,adau1977", },
15657 + { .compatible = "adi,adau1978", },
15658 + { .compatible = "adi,adau1979", },
15661 +MODULE_DEVICE_TABLE(of, adau1977_of_ids);
15664 static struct i2c_driver adau1977_i2c_driver = {
15666 .name = "adau1977",
15667 + .of_match_table = adau1977_of_ids,
15669 .probe = adau1977_i2c_probe,
15670 .id_table = adau1977_i2c_ids,
15671 --- a/sound/soc/codecs/cs42xx8-i2c.c
15672 +++ b/sound/soc/codecs/cs42xx8-i2c.c
15673 @@ -58,11 +58,18 @@ static const struct i2c_device_id cs42xx
15675 MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
15677 +const struct of_device_id cs42xx8_i2c_of_match[] = {
15678 + { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
15679 + { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
15680 + { /* sentinel */ }
15682 +MODULE_DEVICE_TABLE(of, cs42xx8_i2c_of_match);
15684 static struct i2c_driver cs42xx8_i2c_driver = {
15688 - .of_match_table = cs42xx8_of_match,
15689 + .of_match_table = cs42xx8_i2c_of_match,
15691 .probe = cs42xx8_i2c_probe,
15692 .remove = cs42xx8_i2c_remove,
15693 --- a/sound/soc/codecs/cs42xx8.c
15694 +++ b/sound/soc/codecs/cs42xx8.c
15695 @@ -510,6 +510,16 @@ const struct cs42xx8_driver_data cs42888
15697 EXPORT_SYMBOL_GPL(cs42888_data);
15699 +const struct of_device_id cs42xx8_of_match[] = {
15700 + { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
15701 + { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
15702 + { /* sentinel */ }
15704 +#if !IS_ENABLED(CONFIG_SND_SOC_CS42XX8_I2C)
15705 +MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
15706 +EXPORT_SYMBOL_GPL(cs42xx8_of_match);
15709 int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)
15711 struct cs42xx8_priv *cs42xx8;
15712 --- a/sound/soc/codecs/da7213.c
15713 +++ b/sound/soc/codecs/da7213.c
15714 @@ -1346,6 +1346,8 @@ static int da7213_hw_params(struct snd_p
15715 switch (params_width(params)) {
15717 dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE;
15718 + if (da7213->bclk_ratio == 64)
15720 dai_clk_mode = DA7213_DAI_BCLKS_PER_WCLK_32; /* 32bit for 1ch and 2ch */
15723 @@ -1361,6 +1363,9 @@ static int da7213_hw_params(struct snd_p
15727 + if (da7213->bclk_ratio == 32 && params_width(params) != 16)
15730 /* Set sampling rate */
15731 switch (params_rate(params)) {
15733 @@ -1523,6 +1528,21 @@ static int da7213_set_dai_fmt(struct snd
15737 +static int da7213_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
15739 + struct snd_soc_component *component = dai->component;
15740 + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
15742 + if (ratio != 32 && ratio != 64) {
15743 + dev_err(component->dev, "Invalid bclk ratio %d\n", ratio);
15747 + da7213->bclk_ratio = ratio;
15752 static int da7213_mute(struct snd_soc_dai *dai, int mute, int direction)
15754 struct snd_soc_component *component = dai->component;
15755 @@ -1735,6 +1755,7 @@ static const u64 da7213_dai_formats =
15756 static const struct snd_soc_dai_ops da7213_dai_ops = {
15757 .hw_params = da7213_hw_params,
15758 .set_fmt = da7213_set_dai_fmt,
15759 + .set_bclk_ratio = da7213_set_bclk_ratio,
15760 .mute_stream = da7213_mute,
15761 .no_capture_mute = 1,
15762 .auto_selectable_formats = &da7213_dai_formats,
15763 --- a/sound/soc/codecs/da7213.h
15764 +++ b/sound/soc/codecs/da7213.h
15765 @@ -600,6 +600,7 @@ struct da7213_priv {
15767 unsigned int mclk_rate;
15768 unsigned int out_rate;
15769 + unsigned int bclk_ratio;
15772 bool alc_calib_auto;
15774 +++ b/sound/soc/codecs/i-sabre-codec.c
15777 + * Driver for I-Sabre Q2M
15779 + * Author: Satoru Kawase
15780 + * Modified by: Xiao Qingyong
15781 + * Modified by: JC BARBAUD (Mute)
15782 + * Update kernel v4.18+ by : Audiophonics
15783 + * Copyright 2018 Audiophonics
15785 + * This program is free software; you can redistribute it and/or
15786 + * modify it under the terms of the GNU General Public License
15787 + * version 2 as published by the Free Software Foundation.
15789 + * This program is distributed in the hope that it will be useful, but
15790 + * WITHOUT ANY WARRANTY; without even the implied warranty of
15791 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15792 + * General Public License for more details.
15796 +#include <linux/init.h>
15797 +#include <linux/module.h>
15798 +#include <linux/regmap.h>
15799 +#include <linux/i2c.h>
15800 +#include <sound/soc.h>
15801 +#include <sound/pcm_params.h>
15802 +#include <sound/tlv.h>
15804 +#include "i-sabre-codec.h"
15807 +/* I-Sabre Q2M Codec Private Data */
15808 +struct i_sabre_codec_priv {
15809 + struct regmap *regmap;
15810 + unsigned int fmt;
15814 +/* I-Sabre Q2M Codec Default Register Value */
15815 +static const struct reg_default i_sabre_codec_reg_defaults[] = {
15816 + { ISABRECODEC_REG_10, 0x00 },
15817 + { ISABRECODEC_REG_20, 0x00 },
15818 + { ISABRECODEC_REG_21, 0x00 },
15819 + { ISABRECODEC_REG_22, 0x00 },
15820 + { ISABRECODEC_REG_24, 0x00 },
15824 +static bool i_sabre_codec_writeable(struct device *dev, unsigned int reg)
15827 + case ISABRECODEC_REG_10:
15828 + case ISABRECODEC_REG_20:
15829 + case ISABRECODEC_REG_21:
15830 + case ISABRECODEC_REG_22:
15831 + case ISABRECODEC_REG_24:
15839 +static bool i_sabre_codec_readable(struct device *dev, unsigned int reg)
15842 + case ISABRECODEC_REG_01:
15843 + case ISABRECODEC_REG_02:
15844 + case ISABRECODEC_REG_10:
15845 + case ISABRECODEC_REG_20:
15846 + case ISABRECODEC_REG_21:
15847 + case ISABRECODEC_REG_22:
15848 + case ISABRECODEC_REG_24:
15856 +static bool i_sabre_codec_volatile(struct device *dev, unsigned int reg)
15859 + case ISABRECODEC_REG_01:
15860 + case ISABRECODEC_REG_02:
15869 +/* Volume Scale */
15870 +static const DECLARE_TLV_DB_SCALE(volume_tlv, -10000, 100, 0);
15874 +static const char * const fir_filter_type_texts[] = {
15876 + "corrected minimum phase fast",
15877 + "minimum phase slow",
15878 + "minimum phase fast",
15879 + "linear phase slow",
15880 + "linear phase fast",
15881 + "apodizing fast",
15884 +static SOC_ENUM_SINGLE_DECL(i_sabre_fir_filter_type_enum,
15885 + ISABRECODEC_REG_22, 0, fir_filter_type_texts);
15888 +/* I2S / SPDIF Select */
15889 +static const char * const iis_spdif_sel_texts[] = {
15894 +static SOC_ENUM_SINGLE_DECL(i_sabre_iis_spdif_sel_enum,
15895 + ISABRECODEC_REG_24, 0, iis_spdif_sel_texts);
15899 +static const struct snd_kcontrol_new i_sabre_codec_controls[] = {
15900 +SOC_SINGLE_RANGE_TLV("Digital Playback Volume", ISABRECODEC_REG_20, 0, 0, 100, 1, volume_tlv),
15901 +SOC_SINGLE("Digital Playback Switch", ISABRECODEC_REG_21, 0, 1, 1),
15902 +SOC_ENUM("FIR Filter Type", i_sabre_fir_filter_type_enum),
15903 +SOC_ENUM("I2S/SPDIF Select", i_sabre_iis_spdif_sel_enum),
15907 +static const u32 i_sabre_codec_dai_rates_slave[] = {
15908 + 8000, 11025, 16000, 22050, 32000,
15909 + 44100, 48000, 64000, 88200, 96000,
15910 + 176400, 192000, 352800, 384000,
15911 + 705600, 768000, 1411200, 1536000
15914 +static const struct snd_pcm_hw_constraint_list constraints_slave = {
15915 + .list = i_sabre_codec_dai_rates_slave,
15916 + .count = ARRAY_SIZE(i_sabre_codec_dai_rates_slave),
15919 +static int i_sabre_codec_dai_startup_slave(
15920 + struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
15922 + struct snd_soc_component *component = dai->component;
15925 + ret = snd_pcm_hw_constraint_list(substream->runtime,
15926 + 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_slave);
15928 + dev_err(component->card->dev, "Failed to setup rates constraints: %d\n", ret);
15934 +static int i_sabre_codec_dai_startup(
15935 + struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
15937 + struct snd_soc_component *component = dai->component;
15938 + struct i_sabre_codec_priv *i_sabre_codec
15939 + = snd_soc_component_get_drvdata(component);
15941 + switch (i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
15942 + case SND_SOC_DAIFMT_CBS_CFS:
15943 + return i_sabre_codec_dai_startup_slave(substream, dai);
15946 + return (-EINVAL);
15950 +static int i_sabre_codec_hw_params(
15951 + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
15952 + struct snd_soc_dai *dai)
15954 + struct snd_soc_component *component = dai->component;
15955 + struct i_sabre_codec_priv *i_sabre_codec
15956 + = snd_soc_component_get_drvdata(component);
15957 + unsigned int daifmt;
15958 + int format_width;
15960 + dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n",
15961 + params_rate(params), params_channels(params));
15963 + /* Check I2S Format (Bit Size) */
15964 + format_width = snd_pcm_format_width(params_format(params));
15965 + if ((format_width != 32) && (format_width != 16)) {
15966 + dev_err(component->card->dev, "Bad frame size: %d\n",
15967 + snd_pcm_format_width(params_format(params)));
15968 + return (-EINVAL);
15971 + /* Check Slave Mode */
15972 + daifmt = i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK;
15973 + if (daifmt != SND_SOC_DAIFMT_CBS_CFS) {
15974 + return (-EINVAL);
15977 + /* Notify Sampling Frequency */
15978 + switch (params_rate(params))
15986 + snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x00);
15995 + snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x01);
16002 +static int i_sabre_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
16004 + struct snd_soc_component *component = dai->component;
16005 + struct i_sabre_codec_priv *i_sabre_codec
16006 + = snd_soc_component_get_drvdata(component);
16008 + /* interface format */
16009 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
16010 + case SND_SOC_DAIFMT_I2S:
16013 + case SND_SOC_DAIFMT_RIGHT_J:
16014 + case SND_SOC_DAIFMT_LEFT_J:
16016 + return (-EINVAL);
16019 + /* clock inversion */
16020 + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
16021 + return (-EINVAL);
16024 + /* Set Audio Data Format */
16025 + i_sabre_codec->fmt = fmt;
16030 +static int i_sabre_codec_dac_mute(struct snd_soc_dai *dai, int mute, int direction)
16032 + struct snd_soc_component *component = dai->component;
16035 + snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x01);
16037 + snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x00);
16044 +static const struct snd_soc_dai_ops i_sabre_codec_dai_ops = {
16045 + .startup = i_sabre_codec_dai_startup,
16046 + .hw_params = i_sabre_codec_hw_params,
16047 + .set_fmt = i_sabre_codec_set_fmt,
16048 + .mute_stream = i_sabre_codec_dac_mute,
16051 +static struct snd_soc_dai_driver i_sabre_codec_dai = {
16052 + .name = "i-sabre-codec-dai",
16054 + .stream_name = "Playback",
16055 + .channels_min = 2,
16056 + .channels_max = 2,
16057 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
16058 + .rate_min = 8000,
16059 + .rate_max = 1536000,
16060 + .formats = SNDRV_PCM_FMTBIT_S16_LE
16061 + | SNDRV_PCM_FMTBIT_S32_LE,
16063 + .ops = &i_sabre_codec_dai_ops,
16066 +static struct snd_soc_component_driver i_sabre_codec_codec_driver = {
16067 + .controls = i_sabre_codec_controls,
16068 + .num_controls = ARRAY_SIZE(i_sabre_codec_controls),
16072 +static const struct regmap_config i_sabre_codec_regmap = {
16075 + .max_register = ISABRECODEC_MAX_REG,
16077 + .reg_defaults = i_sabre_codec_reg_defaults,
16078 + .num_reg_defaults = ARRAY_SIZE(i_sabre_codec_reg_defaults),
16080 + .writeable_reg = i_sabre_codec_writeable,
16081 + .readable_reg = i_sabre_codec_readable,
16082 + .volatile_reg = i_sabre_codec_volatile,
16084 + .cache_type = REGCACHE_RBTREE,
16088 +static int i_sabre_codec_probe(struct device *dev, struct regmap *regmap)
16090 + struct i_sabre_codec_priv *i_sabre_codec;
16093 + i_sabre_codec = devm_kzalloc(dev, sizeof(*i_sabre_codec), GFP_KERNEL);
16094 + if (!i_sabre_codec) {
16095 + dev_err(dev, "devm_kzalloc");
16096 + return (-ENOMEM);
16099 + i_sabre_codec->regmap = regmap;
16101 + dev_set_drvdata(dev, i_sabre_codec);
16103 + ret = snd_soc_register_component(dev,
16104 + &i_sabre_codec_codec_driver, &i_sabre_codec_dai, 1);
16106 + dev_err(dev, "Failed to register CODEC: %d\n", ret);
16113 +static void i_sabre_codec_remove(struct device *dev)
16115 + snd_soc_unregister_component(dev);
16119 +static int i_sabre_codec_i2c_probe(struct i2c_client *i2c)
16121 + struct regmap *regmap;
16123 + regmap = devm_regmap_init_i2c(i2c, &i_sabre_codec_regmap);
16124 + if (IS_ERR(regmap)) {
16125 + return PTR_ERR(regmap);
16128 + return i_sabre_codec_probe(&i2c->dev, regmap);
16131 +static void i_sabre_codec_i2c_remove(struct i2c_client *i2c)
16133 + i_sabre_codec_remove(&i2c->dev);
16137 +static const struct i2c_device_id i_sabre_codec_i2c_id[] = {
16138 + { "i-sabre-codec", },
16141 +MODULE_DEVICE_TABLE(i2c, i_sabre_codec_i2c_id);
16143 +static const struct of_device_id i_sabre_codec_of_match[] = {
16144 + { .compatible = "audiophonics,i-sabre-codec", },
16147 +MODULE_DEVICE_TABLE(of, i_sabre_codec_of_match);
16149 +static struct i2c_driver i_sabre_codec_i2c_driver = {
16151 + .name = "i-sabre-codec-i2c",
16152 + .owner = THIS_MODULE,
16153 + .of_match_table = of_match_ptr(i_sabre_codec_of_match),
16155 + .probe = i_sabre_codec_i2c_probe,
16156 + .remove = i_sabre_codec_i2c_remove,
16157 + .id_table = i_sabre_codec_i2c_id,
16159 +module_i2c_driver(i_sabre_codec_i2c_driver);
16162 +MODULE_DESCRIPTION("ASoC I-Sabre Q2M codec driver");
16163 +MODULE_AUTHOR("Audiophonics <http://www.audiophonics.fr>");
16164 +MODULE_LICENSE("GPL");
16166 +++ b/sound/soc/codecs/i-sabre-codec.h
16169 + * Driver for I-Sabre Q2M
16171 + * Author: Satoru Kawase
16172 + * Modified by: Xiao Qingyong
16173 + * Copyright 2018 Audiophonics
16175 + * This program is free software; you can redistribute it and/or
16176 + * modify it under the terms of the GNU General Public License
16177 + * version 2 as published by the Free Software Foundation.
16179 + * This program is distributed in the hope that it will be useful, but
16180 + * WITHOUT ANY WARRANTY; without even the implied warranty of
16181 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16182 + * General Public License for more details.
16185 +#ifndef _SND_SOC_ISABRECODEC
16186 +#define _SND_SOC_ISABRECODEC
16189 +/* ISABRECODEC Register Address */
16190 +#define ISABRECODEC_REG_01 0x01 /* Virtual Device ID : 0x01 = es9038q2m */
16191 +#define ISABRECODEC_REG_02 0x02 /* API revision : 0x01 = Revision 01 */
16192 +#define ISABRECODEC_REG_10 0x10 /* 0x01 = above 192kHz, 0x00 = otherwise */
16193 +#define ISABRECODEC_REG_20 0x20 /* 0 - 100 (decimal value, 0 = min., 100 = max.) */
16194 +#define ISABRECODEC_REG_21 0x21 /* 0x00 = Mute OFF, 0x01 = Mute ON */
16195 +#define ISABRECODEC_REG_22 0x22
16197 + 0x00 = brick wall,
16198 + 0x01 = corrected minimum phase fast,
16199 + 0x02 = minimum phase slow,
16200 + 0x03 = minimum phase fast,
16201 + 0x04 = linear phase slow,
16202 + 0x05 = linear phase fast,
16203 + 0x06 = apodizing fast,
16205 +//#define ISABRECODEC_REG_23 0x23 /* reserved */
16206 +#define ISABRECODEC_REG_24 0x24 /* 0x00 = I2S, 0x01 = SPDIF */
16207 +#define ISABRECODEC_MAX_REG 0x24 /* Maximum Register Number */
16209 +#endif /* _SND_SOC_ISABRECODEC */
16211 +++ b/sound/soc/codecs/ma120x0p.c
16213 +// SPDX-License-Identifier: GPL-2.0-or-later
16215 + * ASoC Driver for Infineon Merus(TM) ma120x0p multi-level class-D amplifier
16217 + * Authors: Ariel Muszkat <ariel.muszkat@gmail.com>
16218 + * Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
16220 + * Copyright (C) 2019 Infineon Technologies AG
16223 +#include <linux/module.h>
16224 +#include <linux/moduleparam.h>
16225 +#include <linux/init.h>
16226 +#include <linux/delay.h>
16227 +#include <linux/pm_runtime.h>
16228 +#include <linux/i2c.h>
16229 +#include <linux/of_device.h>
16230 +#include <linux/spi/spi.h>
16231 +#include <linux/regmap.h>
16232 +#include <linux/regulator/consumer.h>
16233 +#include <linux/slab.h>
16234 +#include <linux/gpio/consumer.h>
16235 +#include <linux/gpio.h>
16236 +#include <sound/core.h>
16237 +#include <sound/pcm.h>
16238 +#include <sound/pcm_params.h>
16239 +#include <sound/soc.h>
16240 +#include <sound/soc-dapm.h>
16241 +#include <sound/initval.h>
16242 +#include <sound/tlv.h>
16243 +#include <linux/interrupt.h>
16245 +#include <linux/kernel.h>
16246 +#include <linux/string.h>
16247 +#include <linux/fs.h>
16248 +#include <linux/uaccess.h>
16250 +#ifndef _MA120X0P_
16251 +#define _MA120X0P_
16252 +//------------------------------------------------------------------manualPM---
16253 +// Select Manual PowerMode control
16254 +#define ma_manualpm__a 0
16255 +#define ma_manualpm__len 1
16256 +#define ma_manualpm__mask 0x40
16257 +#define ma_manualpm__shift 0x06
16258 +#define ma_manualpm__reset 0x00
16259 +//--------------------------------------------------------------------pm_man---
16260 +// manual selected power mode
16261 +#define ma_pm_man__a 0
16262 +#define ma_pm_man__len 2
16263 +#define ma_pm_man__mask 0x30
16264 +#define ma_pm_man__shift 0x04
16265 +#define ma_pm_man__reset 0x03
16266 +//------------------------------------------ ----------------------mthr_1to2---
16267 +// mod. index threshold value for pm1=>pm2 change.
16268 +#define ma_mthr_1to2__a 1
16269 +#define ma_mthr_1to2__len 8
16270 +#define ma_mthr_1to2__mask 0xff
16271 +#define ma_mthr_1to2__shift 0x00
16272 +#define ma_mthr_1to2__reset 0x3c
16273 +//-----------------------------------------------------------------mthr_2to1---
16274 +// mod. index threshold value for pm2=>pm1 change.
16275 +#define ma_mthr_2to1__a 2
16276 +#define ma_mthr_2to1__len 8
16277 +#define ma_mthr_2to1__mask 0xff
16278 +#define ma_mthr_2to1__shift 0x00
16279 +#define ma_mthr_2to1__reset 0x32
16280 +//-----------------------------------------------------------------mthr_2to3---
16281 +// mod. index threshold value for pm2=>pm3 change.
16282 +#define ma_mthr_2to3__a 3
16283 +#define ma_mthr_2to3__len 8
16284 +#define ma_mthr_2to3__mask 0xff
16285 +#define ma_mthr_2to3__shift 0x00
16286 +#define ma_mthr_2to3__reset 0x5a
16287 +//-----------------------------------------------------------------mthr_3to2---
16288 +// mod. index threshold value for pm3=>pm2 change.
16289 +#define ma_mthr_3to2__a 4
16290 +#define ma_mthr_3to2__len 8
16291 +#define ma_mthr_3to2__mask 0xff
16292 +#define ma_mthr_3to2__shift 0x00
16293 +#define ma_mthr_3to2__reset 0x50
16294 +//-------------------------------------------------------------pwmclkdiv_nom---
16295 +// pwm default clock divider value
16296 +#define ma_pwmclkdiv_nom__a 8
16297 +#define ma_pwmclkdiv_nom__len 8
16298 +#define ma_pwmclkdiv_nom__mask 0xff
16299 +#define ma_pwmclkdiv_nom__shift 0x00
16300 +#define ma_pwmclkdiv_nom__reset 0x26
16301 +//--------- ----------------------------------------------------ocp_latch_en---
16302 +// high to use permanently latching level-2 ocp
16303 +#define ma_ocp_latch_en__a 10
16304 +#define ma_ocp_latch_en__len 1
16305 +#define ma_ocp_latch_en__mask 0x02
16306 +#define ma_ocp_latch_en__shift 0x01
16307 +#define ma_ocp_latch_en__reset 0x00
16308 +//---------------------------------------------------------------lf_clamp_en---
16309 +// high (default) to enable lf int2+3 clamping on clip
16310 +#define ma_lf_clamp_en__a 10
16311 +#define ma_lf_clamp_en__len 1
16312 +#define ma_lf_clamp_en__mask 0x80
16313 +#define ma_lf_clamp_en__shift 0x07
16314 +#define ma_lf_clamp_en__reset 0x00
16315 +//-------------------------------------------------------pmcfg_btl_b.modtype---
16317 +#define ma_pmcfg_btl_b__modtype__a 18
16318 +#define ma_pmcfg_btl_b__modtype__len 2
16319 +#define ma_pmcfg_btl_b__modtype__mask 0x18
16320 +#define ma_pmcfg_btl_b__modtype__shift 0x03
16321 +#define ma_pmcfg_btl_b__modtype__reset 0x02
16322 +//-------------------------------------------------------pmcfg_btl_b.freqdiv---
16323 +#define ma_pmcfg_btl_b__freqdiv__a 18
16324 +#define ma_pmcfg_btl_b__freqdiv__len 2
16325 +#define ma_pmcfg_btl_b__freqdiv__mask 0x06
16326 +#define ma_pmcfg_btl_b__freqdiv__shift 0x01
16327 +#define ma_pmcfg_btl_b__freqdiv__reset 0x01
16328 +//----------------------------------------------------pmcfg_btl_b.lf_gain_ol---
16330 +#define ma_pmcfg_btl_b__lf_gain_ol__a 18
16331 +#define ma_pmcfg_btl_b__lf_gain_ol__len 1
16332 +#define ma_pmcfg_btl_b__lf_gain_ol__mask 0x01
16333 +#define ma_pmcfg_btl_b__lf_gain_ol__shift 0x00
16334 +#define ma_pmcfg_btl_b__lf_gain_ol__reset 0x01
16335 +//-------------------------------------------------------pmcfg_btl_c.freqdiv---
16337 +#define ma_pmcfg_btl_c__freqdiv__a 19
16338 +#define ma_pmcfg_btl_c__freqdiv__len 2
16339 +#define ma_pmcfg_btl_c__freqdiv__mask 0x06
16340 +#define ma_pmcfg_btl_c__freqdiv__shift 0x01
16341 +#define ma_pmcfg_btl_c__freqdiv__reset 0x01
16342 +//-------------------------------------------------------pmcfg_btl_c.modtype---
16344 +#define ma_pmcfg_btl_c__modtype__a 19
16345 +#define ma_pmcfg_btl_c__modtype__len 2
16346 +#define ma_pmcfg_btl_c__modtype__mask 0x18
16347 +#define ma_pmcfg_btl_c__modtype__shift 0x03
16348 +#define ma_pmcfg_btl_c__modtype__reset 0x01
16349 +//----------------------------------------------------pmcfg_btl_c.lf_gain_ol---
16351 +#define ma_pmcfg_btl_c__lf_gain_ol__a 19
16352 +#define ma_pmcfg_btl_c__lf_gain_ol__len 1
16353 +#define ma_pmcfg_btl_c__lf_gain_ol__mask 0x01
16354 +#define ma_pmcfg_btl_c__lf_gain_ol__shift 0x00
16355 +#define ma_pmcfg_btl_c__lf_gain_ol__reset 0x00
16356 +//-------------------------------------------------------pmcfg_btl_d.modtype---
16358 +#define ma_pmcfg_btl_d__modtype__a 20
16359 +#define ma_pmcfg_btl_d__modtype__len 2
16360 +#define ma_pmcfg_btl_d__modtype__mask 0x18
16361 +#define ma_pmcfg_btl_d__modtype__shift 0x03
16362 +#define ma_pmcfg_btl_d__modtype__reset 0x02
16363 +//-------------------------------------------------------pmcfg_btl_d.freqdiv---
16365 +#define ma_pmcfg_btl_d__freqdiv__a 20
16366 +#define ma_pmcfg_btl_d__freqdiv__len 2
16367 +#define ma_pmcfg_btl_d__freqdiv__mask 0x06
16368 +#define ma_pmcfg_btl_d__freqdiv__shift 0x01
16369 +#define ma_pmcfg_btl_d__freqdiv__reset 0x02
16370 +//----------------------------------------------------pmcfg_btl_d.lf_gain_ol---
16372 +#define ma_pmcfg_btl_d__lf_gain_ol__a 20
16373 +#define ma_pmcfg_btl_d__lf_gain_ol__len 1
16374 +#define ma_pmcfg_btl_d__lf_gain_ol__mask 0x01
16375 +#define ma_pmcfg_btl_d__lf_gain_ol__shift 0x00
16376 +#define ma_pmcfg_btl_d__lf_gain_ol__reset 0x00
16377 +//------------ -------------------------------------------pmcfg_se_a.modtype---
16379 +#define ma_pmcfg_se_a__modtype__a 21
16380 +#define ma_pmcfg_se_a__modtype__len 2
16381 +#define ma_pmcfg_se_a__modtype__mask 0x18
16382 +#define ma_pmcfg_se_a__modtype__shift 0x03
16383 +#define ma_pmcfg_se_a__modtype__reset 0x01
16384 +//--------------------------------------------------------pmcfg_se_a.freqdiv---
16386 +#define ma_pmcfg_se_a__freqdiv__a 21
16387 +#define ma_pmcfg_se_a__freqdiv__len 2
16388 +#define ma_pmcfg_se_a__freqdiv__mask 0x06
16389 +#define ma_pmcfg_se_a__freqdiv__shift 0x01
16390 +#define ma_pmcfg_se_a__freqdiv__reset 0x00
16391 +//-----------------------------------------------------pmcfg_se_a.lf_gain_ol---
16393 +#define ma_pmcfg_se_a__lf_gain_ol__a 21
16394 +#define ma_pmcfg_se_a__lf_gain_ol__len 1
16395 +#define ma_pmcfg_se_a__lf_gain_ol__mask 0x01
16396 +#define ma_pmcfg_se_a__lf_gain_ol__shift 0x00
16397 +#define ma_pmcfg_se_a__lf_gain_ol__reset 0x01
16398 +//-----------------------------------------------------pmcfg_se_b.lf_gain_ol---
16400 +#define ma_pmcfg_se_b__lf_gain_ol__a 22
16401 +#define ma_pmcfg_se_b__lf_gain_ol__len 1
16402 +#define ma_pmcfg_se_b__lf_gain_ol__mask 0x01
16403 +#define ma_pmcfg_se_b__lf_gain_ol__shift 0x00
16404 +#define ma_pmcfg_se_b__lf_gain_ol__reset 0x00
16405 +//--------------------------------------------------------pmcfg_se_b.freqdiv---
16407 +#define ma_pmcfg_se_b__freqdiv__a 22
16408 +#define ma_pmcfg_se_b__freqdiv__len 2
16409 +#define ma_pmcfg_se_b__freqdiv__mask 0x06
16410 +#define ma_pmcfg_se_b__freqdiv__shift 0x01
16411 +#define ma_pmcfg_se_b__freqdiv__reset 0x01
16412 +//--------------------------------------------------------pmcfg_se_b.modtype---
16414 +#define ma_pmcfg_se_b__modtype__a 22
16415 +#define ma_pmcfg_se_b__modtype__len 2
16416 +#define ma_pmcfg_se_b__modtype__mask 0x18
16417 +#define ma_pmcfg_se_b__modtype__shift 0x03
16418 +#define ma_pmcfg_se_b__modtype__reset 0x01
16419 +//----------------------------------------------------------balwaitcount_pm1---
16420 +// pm1 balancing period.
16421 +#define ma_balwaitcount_pm1__a 23
16422 +#define ma_balwaitcount_pm1__len 8
16423 +#define ma_balwaitcount_pm1__mask 0xff
16424 +#define ma_balwaitcount_pm1__shift 0x00
16425 +#define ma_balwaitcount_pm1__reset 0x14
16426 +//----------------------------------------------------------balwaitcount_pm2---
16427 +// pm2 balancing period.
16428 +#define ma_balwaitcount_pm2__a 24
16429 +#define ma_balwaitcount_pm2__len 8
16430 +#define ma_balwaitcount_pm2__mask 0xff
16431 +#define ma_balwaitcount_pm2__shift 0x00
16432 +#define ma_balwaitcount_pm2__reset 0x14
16433 +//----------------------------------------------------------balwaitcount_pm3---
16434 +// pm3 balancing period.
16435 +#define ma_balwaitcount_pm3__a 25
16436 +#define ma_balwaitcount_pm3__len 8
16437 +#define ma_balwaitcount_pm3__mask 0xff
16438 +#define ma_balwaitcount_pm3__shift 0x00
16439 +#define ma_balwaitcount_pm3__reset 0x1a
16440 +//-------------------------------------------------------------usespread_pm1---
16441 +// pm1 pwm spread-spectrum mode on/off.
16442 +#define ma_usespread_pm1__a 26
16443 +#define ma_usespread_pm1__len 1
16444 +#define ma_usespread_pm1__mask 0x40
16445 +#define ma_usespread_pm1__shift 0x06
16446 +#define ma_usespread_pm1__reset 0x00
16447 +//---------------------------------------------------------------dtsteps_pm1---
16448 +// pm1 dead time setting [10ns steps].
16449 +#define ma_dtsteps_pm1__a 26
16450 +#define ma_dtsteps_pm1__len 3
16451 +#define ma_dtsteps_pm1__mask 0x38
16452 +#define ma_dtsteps_pm1__shift 0x03
16453 +#define ma_dtsteps_pm1__reset 0x04
16454 +//---------------------------------------------------------------baltype_pm1---
16455 +// pm1 balancing sensor scheme.
16456 +#define ma_baltype_pm1__a 26
16457 +#define ma_baltype_pm1__len 3
16458 +#define ma_baltype_pm1__mask 0x07
16459 +#define ma_baltype_pm1__shift 0x00
16460 +#define ma_baltype_pm1__reset 0x00
16461 +//-------------------------------------------------------------usespread_pm2---
16462 +// pm2 pwm spread-spectrum mode on/off.
16463 +#define ma_usespread_pm2__a 27
16464 +#define ma_usespread_pm2__len 1
16465 +#define ma_usespread_pm2__mask 0x40
16466 +#define ma_usespread_pm2__shift 0x06
16467 +#define ma_usespread_pm2__reset 0x00
16468 +//---------------------------------------------------------------dtsteps_pm2---
16469 +// pm2 dead time setting [10ns steps].
16470 +#define ma_dtsteps_pm2__a 27
16471 +#define ma_dtsteps_pm2__len 3
16472 +#define ma_dtsteps_pm2__mask 0x38
16473 +#define ma_dtsteps_pm2__shift 0x03
16474 +#define ma_dtsteps_pm2__reset 0x03
16475 +//---------------------------------------------------------------baltype_pm2---
16476 +// pm2 balancing sensor scheme.
16477 +#define ma_baltype_pm2__a 27
16478 +#define ma_baltype_pm2__len 3
16479 +#define ma_baltype_pm2__mask 0x07
16480 +#define ma_baltype_pm2__shift 0x00
16481 +#define ma_baltype_pm2__reset 0x01
16482 +//-------------------------------------------------------------usespread_pm3---
16483 +// pm3 pwm spread-spectrum mode on/off.
16484 +#define ma_usespread_pm3__a 28
16485 +#define ma_usespread_pm3__len 1
16486 +#define ma_usespread_pm3__mask 0x40
16487 +#define ma_usespread_pm3__shift 0x06
16488 +#define ma_usespread_pm3__reset 0x00
16489 +//---------------------------------------------------------------dtsteps_pm3---
16490 +// pm3 dead time setting [10ns steps].
16491 +#define ma_dtsteps_pm3__a 28
16492 +#define ma_dtsteps_pm3__len 3
16493 +#define ma_dtsteps_pm3__mask 0x38
16494 +#define ma_dtsteps_pm3__shift 0x03
16495 +#define ma_dtsteps_pm3__reset 0x01
16496 +//---------------------------------------------------------------baltype_pm3---
16497 +// pm3 balancing sensor scheme.
16498 +#define ma_baltype_pm3__a 28
16499 +#define ma_baltype_pm3__len 3
16500 +#define ma_baltype_pm3__mask 0x07
16501 +#define ma_baltype_pm3__shift 0x00
16502 +#define ma_baltype_pm3__reset 0x03
16503 +//-----------------------------------------------------------------pmprofile---
16504 +// pm profile select. valid presets: 0-1-2-3-4. 5=> custom profile.
16505 +#define ma_pmprofile__a 29
16506 +#define ma_pmprofile__len 3
16507 +#define ma_pmprofile__mask 0x07
16508 +#define ma_pmprofile__shift 0x00
16509 +#define ma_pmprofile__reset 0x00
16510 +//-------------------------------------------------------------------pm3_man---
16511 +// custom profile pm3 contents. 0=>a, 1=>b, 2=>c, 3=>d
16512 +#define ma_pm3_man__a 30
16513 +#define ma_pm3_man__len 2
16514 +#define ma_pm3_man__mask 0x30
16515 +#define ma_pm3_man__shift 0x04
16516 +#define ma_pm3_man__reset 0x02
16517 +//-------------------------------------------------------------------pm2_man---
16518 +// custom profile pm2 contents. 0=>a, 1=>b, 2=>c, 3=>d
16519 +#define ma_pm2_man__a 30
16520 +#define ma_pm2_man__len 2
16521 +#define ma_pm2_man__mask 0x0c
16522 +#define ma_pm2_man__shift 0x02
16523 +#define ma_pm2_man__reset 0x03
16524 +//-------------------------------------------------------------------pm1_man---
16525 +// custom profile pm1 contents. 0=>a, 1=>b, 2=>c, 3=>d
16526 +#define ma_pm1_man__a 30
16527 +#define ma_pm1_man__len 2
16528 +#define ma_pm1_man__mask 0x03
16529 +#define ma_pm1_man__shift 0x00
16530 +#define ma_pm1_man__reset 0x03
16531 +//-----------------------------------------------------------ocp_latch_clear---
16532 +// low-high clears current ocp latched condition.
16533 +#define ma_ocp_latch_clear__a 32
16534 +#define ma_ocp_latch_clear__len 1
16535 +#define ma_ocp_latch_clear__mask 0x80
16536 +#define ma_ocp_latch_clear__shift 0x07
16537 +#define ma_ocp_latch_clear__reset 0x00
16538 +//-------------------------------------------------------------audio_in_mode---
16539 +// audio input mode; 0-1-2-3-4-5
16540 +#define ma_audio_in_mode__a 37
16541 +#define ma_audio_in_mode__len 3
16542 +#define ma_audio_in_mode__mask 0xe0
16543 +#define ma_audio_in_mode__shift 0x05
16544 +#define ma_audio_in_mode__reset 0x00
16545 +//-----------------------------------------------------------------eh_dcshdn---
16546 +// high to enable dc protection
16547 +#define ma_eh_dcshdn__a 38
16548 +#define ma_eh_dcshdn__len 1
16549 +#define ma_eh_dcshdn__mask 0x04
16550 +#define ma_eh_dcshdn__shift 0x02
16551 +#define ma_eh_dcshdn__reset 0x01
16552 +//---------------------------------------------------------audio_in_mode_ext---
16553 +// if set, audio_in_mode is controlled from audio_in_mode register. if not set
16554 +//audio_in_mode is set from fuse bank setting
16555 +#define ma_audio_in_mode_ext__a 39
16556 +#define ma_audio_in_mode_ext__len 1
16557 +#define ma_audio_in_mode_ext__mask 0x20
16558 +#define ma_audio_in_mode_ext__shift 0x05
16559 +#define ma_audio_in_mode_ext__reset 0x00
16560 +//------------------------------------------------------------------eh_clear---
16561 +// flip to clear error registers
16562 +#define ma_eh_clear__a 45
16563 +#define ma_eh_clear__len 1
16564 +#define ma_eh_clear__mask 0x04
16565 +#define ma_eh_clear__shift 0x02
16566 +#define ma_eh_clear__reset 0x00
16567 +//----------------------------------------------------------thermal_compr_en---
16568 +// enable otw-contr. input compression?
16569 +#define ma_thermal_compr_en__a 45
16570 +#define ma_thermal_compr_en__len 1
16571 +#define ma_thermal_compr_en__mask 0x20
16572 +#define ma_thermal_compr_en__shift 0x05
16573 +#define ma_thermal_compr_en__reset 0x01
16574 +//---------------------------------------------------------------system_mute---
16575 +// 1 = mute system, 0 = normal operation
16576 +#define ma_system_mute__a 45
16577 +#define ma_system_mute__len 1
16578 +#define ma_system_mute__mask 0x40
16579 +#define ma_system_mute__shift 0x06
16580 +#define ma_system_mute__reset 0x00
16581 +//------------------------------------------------------thermal_compr_max_db---
16582 +// audio limiter max thermal reduction
16583 +#define ma_thermal_compr_max_db__a 46
16584 +#define ma_thermal_compr_max_db__len 3
16585 +#define ma_thermal_compr_max_db__mask 0x07
16586 +#define ma_thermal_compr_max_db__shift 0x00
16587 +#define ma_thermal_compr_max_db__reset 0x04
16588 +//---------------------------------------------------------audio_proc_enable---
16589 +// enable audio proc, bypass if not enabled
16590 +#define ma_audio_proc_enable__a 53
16591 +#define ma_audio_proc_enable__len 1
16592 +#define ma_audio_proc_enable__mask 0x08
16593 +#define ma_audio_proc_enable__shift 0x03
16594 +#define ma_audio_proc_enable__reset 0x00
16595 +//--------------------------------------------------------audio_proc_release---
16596 +// 00:slow, 01:normal, 10:fast
16597 +#define ma_audio_proc_release__a 53
16598 +#define ma_audio_proc_release__len 2
16599 +#define ma_audio_proc_release__mask 0x30
16600 +#define ma_audio_proc_release__shift 0x04
16601 +#define ma_audio_proc_release__reset 0x00
16602 +//---------------------------------------------------------audio_proc_attack---
16603 +// 00:slow, 01:normal, 10:fast
16604 +#define ma_audio_proc_attack__a 53
16605 +#define ma_audio_proc_attack__len 2
16606 +#define ma_audio_proc_attack__mask 0xc0
16607 +#define ma_audio_proc_attack__shift 0x06
16608 +#define ma_audio_proc_attack__reset 0x00
16609 +//----------------------------------------------------------------i2s_format---
16610 +// i2s basic data format, 000 = std. i2s, 001 = left justified (default)
16611 +#define ma_i2s_format__a 53
16612 +#define ma_i2s_format__len 3
16613 +#define ma_i2s_format__mask 0x07
16614 +#define ma_i2s_format__shift 0x00
16615 +#define ma_i2s_format__reset 0x01
16616 +//--------------------------------------------------audio_proc_limiterenable---
16617 +// 1: enable limiter, 0: disable limiter
16618 +#define ma_audio_proc_limiterenable__a 54
16619 +#define ma_audio_proc_limiterenable__len 1
16620 +#define ma_audio_proc_limiterenable__mask 0x40
16621 +#define ma_audio_proc_limiterenable__shift 0x06
16622 +#define ma_audio_proc_limiterenable__reset 0x00
16623 +//-----------------------------------------------------------audio_proc_mute---
16624 +// 1: mute, 0: unmute
16625 +#define ma_audio_proc_mute__a 54
16626 +#define ma_audio_proc_mute__len 1
16627 +#define ma_audio_proc_mute__mask 0x80
16628 +#define ma_audio_proc_mute__shift 0x07
16629 +#define ma_audio_proc_mute__reset 0x00
16630 +//---------------------------------------------------------------i2s_sck_pol---
16631 +// i2s sck polarity cfg. 0 = rising edge data change
16632 +#define ma_i2s_sck_pol__a 54
16633 +#define ma_i2s_sck_pol__len 1
16634 +#define ma_i2s_sck_pol__mask 0x01
16635 +#define ma_i2s_sck_pol__shift 0x00
16636 +#define ma_i2s_sck_pol__reset 0x01
16637 +//-------------------------------------------------------------i2s_framesize---
16638 +// i2s word length. 00 = 32bit, 01 = 24bit
16639 +#define ma_i2s_framesize__a 54
16640 +#define ma_i2s_framesize__len 2
16641 +#define ma_i2s_framesize__mask 0x18
16642 +#define ma_i2s_framesize__shift 0x03
16643 +#define ma_i2s_framesize__reset 0x00
16644 +//----------------------------------------------------------------i2s_ws_pol---
16645 +// i2s ws polarity. 0 = low first
16646 +#define ma_i2s_ws_pol__a 54
16647 +#define ma_i2s_ws_pol__len 1
16648 +#define ma_i2s_ws_pol__mask 0x02
16649 +#define ma_i2s_ws_pol__shift 0x01
16650 +#define ma_i2s_ws_pol__reset 0x00
16651 +//-----------------------------------------------------------------i2s_order---
16652 +// i2s word bit order. 0 = msb first
16653 +#define ma_i2s_order__a 54
16654 +#define ma_i2s_order__len 1
16655 +#define ma_i2s_order__mask 0x04
16656 +#define ma_i2s_order__shift 0x02
16657 +#define ma_i2s_order__reset 0x00
16658 +//------------------------------------------------------------i2s_rightfirst---
16659 +// i2s l/r word order; 0 = left first
16660 +#define ma_i2s_rightfirst__a 54
16661 +#define ma_i2s_rightfirst__len 1
16662 +#define ma_i2s_rightfirst__mask 0x20
16663 +#define ma_i2s_rightfirst__shift 0x05
16664 +#define ma_i2s_rightfirst__reset 0x00
16665 +//-------------------------------------------------------------vol_db_master---
16666 +// master volume db
16667 +#define ma_vol_db_master__a 64
16668 +#define ma_vol_db_master__len 8
16669 +#define ma_vol_db_master__mask 0xff
16670 +#define ma_vol_db_master__shift 0x00
16671 +#define ma_vol_db_master__reset 0x18
16672 +//------------------------------------------------------------vol_lsb_master---
16673 +// master volume lsb 1/4 steps
16674 +#define ma_vol_lsb_master__a 65
16675 +#define ma_vol_lsb_master__len 2
16676 +#define ma_vol_lsb_master__mask 0x03
16677 +#define ma_vol_lsb_master__shift 0x00
16678 +#define ma_vol_lsb_master__reset 0x00
16679 +//----------------------------------------------------------------vol_db_ch0---
16680 +// volume channel 0
16681 +#define ma_vol_db_ch0__a 66
16682 +#define ma_vol_db_ch0__len 8
16683 +#define ma_vol_db_ch0__mask 0xff
16684 +#define ma_vol_db_ch0__shift 0x00
16685 +#define ma_vol_db_ch0__reset 0x18
16686 +//----------------------------------------------------------------vol_db_ch1---
16687 +// volume channel 1
16688 +#define ma_vol_db_ch1__a 67
16689 +#define ma_vol_db_ch1__len 8
16690 +#define ma_vol_db_ch1__mask 0xff
16691 +#define ma_vol_db_ch1__shift 0x00
16692 +#define ma_vol_db_ch1__reset 0x18
16693 +//----------------------------------------------------------------vol_db_ch2---
16694 +// volume channel 2
16695 +#define ma_vol_db_ch2__a 68
16696 +#define ma_vol_db_ch2__len 8
16697 +#define ma_vol_db_ch2__mask 0xff
16698 +#define ma_vol_db_ch2__shift 0x00
16699 +#define ma_vol_db_ch2__reset 0x18
16700 +//----------------------------------------------------------------vol_db_ch3---
16701 +// volume channel 3
16702 +#define ma_vol_db_ch3__a 69
16703 +#define ma_vol_db_ch3__len 8
16704 +#define ma_vol_db_ch3__mask 0xff
16705 +#define ma_vol_db_ch3__shift 0x00
16706 +#define ma_vol_db_ch3__reset 0x18
16707 +//---------------------------------------------------------------vol_lsb_ch0---
16708 +// volume channel 1 - 1/4 steps
16709 +#define ma_vol_lsb_ch0__a 70
16710 +#define ma_vol_lsb_ch0__len 2
16711 +#define ma_vol_lsb_ch0__mask 0x03
16712 +#define ma_vol_lsb_ch0__shift 0x00
16713 +#define ma_vol_lsb_ch0__reset 0x00
16714 +//---------------------------------------------------------------vol_lsb_ch1---
16715 +// volume channel 3 - 1/4 steps
16716 +#define ma_vol_lsb_ch1__a 70
16717 +#define ma_vol_lsb_ch1__len 2
16718 +#define ma_vol_lsb_ch1__mask 0x0c
16719 +#define ma_vol_lsb_ch1__shift 0x02
16720 +#define ma_vol_lsb_ch1__reset 0x00
16721 +//---------------------------------------------------------------vol_lsb_ch2---
16722 +// volume channel 2 - 1/4 steps
16723 +#define ma_vol_lsb_ch2__a 70
16724 +#define ma_vol_lsb_ch2__len 2
16725 +#define ma_vol_lsb_ch2__mask 0x30
16726 +#define ma_vol_lsb_ch2__shift 0x04
16727 +#define ma_vol_lsb_ch2__reset 0x00
16728 +//---------------------------------------------------------------vol_lsb_ch3---
16729 +// volume channel 3 - 1/4 steps
16730 +#define ma_vol_lsb_ch3__a 70
16731 +#define ma_vol_lsb_ch3__len 2
16732 +#define ma_vol_lsb_ch3__mask 0xc0
16733 +#define ma_vol_lsb_ch3__shift 0x06
16734 +#define ma_vol_lsb_ch3__reset 0x00
16735 +//----------------------------------------------------------------thr_db_ch0---
16736 +// thr_db channel 0
16737 +#define ma_thr_db_ch0__a 71
16738 +#define ma_thr_db_ch0__len 8
16739 +#define ma_thr_db_ch0__mask 0xff
16740 +#define ma_thr_db_ch0__shift 0x00
16741 +#define ma_thr_db_ch0__reset 0x18
16742 +//----------------------------------------------------------------thr_db_ch1---
16744 +#define ma_thr_db_ch1__a 72
16745 +#define ma_thr_db_ch1__len 8
16746 +#define ma_thr_db_ch1__mask 0xff
16747 +#define ma_thr_db_ch1__shift 0x00
16748 +#define ma_thr_db_ch1__reset 0x18
16749 +//----------------------------------------------------------------thr_db_ch2---
16751 +#define ma_thr_db_ch2__a 73
16752 +#define ma_thr_db_ch2__len 8
16753 +#define ma_thr_db_ch2__mask 0xff
16754 +#define ma_thr_db_ch2__shift 0x00
16755 +#define ma_thr_db_ch2__reset 0x18
16756 +//----------------------------------------------------------------thr_db_ch3---
16757 +// threshold db ch3
16758 +#define ma_thr_db_ch3__a 74
16759 +#define ma_thr_db_ch3__len 8
16760 +#define ma_thr_db_ch3__mask 0xff
16761 +#define ma_thr_db_ch3__shift 0x00
16762 +#define ma_thr_db_ch3__reset 0x18
16763 +//---------------------------------------------------------------thr_lsb_ch0---
16765 +#define ma_thr_lsb_ch0__a 75
16766 +#define ma_thr_lsb_ch0__len 2
16767 +#define ma_thr_lsb_ch0__mask 0x03
16768 +#define ma_thr_lsb_ch0__shift 0x00
16769 +#define ma_thr_lsb_ch0__reset 0x00
16770 +//---------------------------------------------------------------thr_lsb_ch1---
16772 +#define ma_thr_lsb_ch1__a 75
16773 +#define ma_thr_lsb_ch1__len 2
16774 +#define ma_thr_lsb_ch1__mask 0x0c
16775 +#define ma_thr_lsb_ch1__shift 0x02
16776 +#define ma_thr_lsb_ch1__reset 0x00
16777 +//---------------------------------------------------------------thr_lsb_ch2---
16778 +// thr lsb ch2 1/4 db step
16779 +#define ma_thr_lsb_ch2__a 75
16780 +#define ma_thr_lsb_ch2__len 2
16781 +#define ma_thr_lsb_ch2__mask 0x30
16782 +#define ma_thr_lsb_ch2__shift 0x04
16783 +#define ma_thr_lsb_ch2__reset 0x00
16784 +//---------------------------------------------------------------thr_lsb_ch3---
16785 +// threshold lsb ch3
16786 +#define ma_thr_lsb_ch3__a 75
16787 +#define ma_thr_lsb_ch3__len 2
16788 +#define ma_thr_lsb_ch3__mask 0xc0
16789 +#define ma_thr_lsb_ch3__shift 0x06
16790 +#define ma_thr_lsb_ch3__reset 0x00
16791 +//-----------------------------------------------------------dcu_mon0.pm_mon---
16792 +// power mode monitor channel 0
16793 +#define ma_dcu_mon0__pm_mon__a 96
16794 +#define ma_dcu_mon0__pm_mon__len 2
16795 +#define ma_dcu_mon0__pm_mon__mask 0x03
16796 +#define ma_dcu_mon0__pm_mon__shift 0x00
16797 +#define ma_dcu_mon0__pm_mon__reset 0x00
16798 +//-----------------------------------------------------dcu_mon0.freqmode_mon---
16799 +// frequence mode monitor channel 0
16800 +#define ma_dcu_mon0__freqmode_mon__a 96
16801 +#define ma_dcu_mon0__freqmode_mon__len 3
16802 +#define ma_dcu_mon0__freqmode_mon__mask 0x70
16803 +#define ma_dcu_mon0__freqmode_mon__shift 0x04
16804 +#define ma_dcu_mon0__freqmode_mon__reset 0x00
16805 +//-------------------------------------------------------dcu_mon0.pps_passed---
16806 +// dcu0 pps completion indicator
16807 +#define ma_dcu_mon0__pps_passed__a 96
16808 +#define ma_dcu_mon0__pps_passed__len 1
16809 +#define ma_dcu_mon0__pps_passed__mask 0x80
16810 +#define ma_dcu_mon0__pps_passed__shift 0x07
16811 +#define ma_dcu_mon0__pps_passed__reset 0x00
16812 +//----------------------------------------------------------dcu_mon0.ocp_mon---
16813 +// ocp monitor channel 0
16814 +#define ma_dcu_mon0__ocp_mon__a 97
16815 +#define ma_dcu_mon0__ocp_mon__len 1
16816 +#define ma_dcu_mon0__ocp_mon__mask 0x01
16817 +#define ma_dcu_mon0__ocp_mon__shift 0x00
16818 +#define ma_dcu_mon0__ocp_mon__reset 0x00
16819 +//--------------------------------------------------------dcu_mon0.vcfly1_ok---
16820 +// cfly1 protection monitor channel 0.
16821 +#define ma_dcu_mon0__vcfly1_ok__a 97
16822 +#define ma_dcu_mon0__vcfly1_ok__len 1
16823 +#define ma_dcu_mon0__vcfly1_ok__mask 0x02
16824 +#define ma_dcu_mon0__vcfly1_ok__shift 0x01
16825 +#define ma_dcu_mon0__vcfly1_ok__reset 0x00
16826 +//--------------------------------------------------------dcu_mon0.vcfly2_ok---
16827 +// cfly2 protection monitor channel 0.
16828 +#define ma_dcu_mon0__vcfly2_ok__a 97
16829 +#define ma_dcu_mon0__vcfly2_ok__len 1
16830 +#define ma_dcu_mon0__vcfly2_ok__mask 0x04
16831 +#define ma_dcu_mon0__vcfly2_ok__shift 0x02
16832 +#define ma_dcu_mon0__vcfly2_ok__reset 0x00
16833 +//----------------------------------------------------------dcu_mon0.pvdd_ok---
16834 +// dcu0 pvdd monitor
16835 +#define ma_dcu_mon0__pvdd_ok__a 97
16836 +#define ma_dcu_mon0__pvdd_ok__len 1
16837 +#define ma_dcu_mon0__pvdd_ok__mask 0x08
16838 +#define ma_dcu_mon0__pvdd_ok__shift 0x03
16839 +#define ma_dcu_mon0__pvdd_ok__reset 0x00
16840 +//-----------------------------------------------------------dcu_mon0.vdd_ok---
16841 +// dcu0 vdd monitor
16842 +#define ma_dcu_mon0__vdd_ok__a 97
16843 +#define ma_dcu_mon0__vdd_ok__len 1
16844 +#define ma_dcu_mon0__vdd_ok__mask 0x10
16845 +#define ma_dcu_mon0__vdd_ok__shift 0x04
16846 +#define ma_dcu_mon0__vdd_ok__reset 0x00
16847 +//-------------------------------------------------------------dcu_mon0.mute---
16848 +// dcu0 mute monitor
16849 +#define ma_dcu_mon0__mute__a 97
16850 +#define ma_dcu_mon0__mute__len 1
16851 +#define ma_dcu_mon0__mute__mask 0x20
16852 +#define ma_dcu_mon0__mute__shift 0x05
16853 +#define ma_dcu_mon0__mute__reset 0x00
16854 +//------------------------------------------------------------dcu_mon0.m_mon---
16855 +// m sense monitor channel 0
16856 +#define ma_dcu_mon0__m_mon__a 98
16857 +#define ma_dcu_mon0__m_mon__len 8
16858 +#define ma_dcu_mon0__m_mon__mask 0xff
16859 +#define ma_dcu_mon0__m_mon__shift 0x00
16860 +#define ma_dcu_mon0__m_mon__reset 0x00
16861 +//-----------------------------------------------------------dcu_mon1.pm_mon---
16862 +// power mode monitor channel 1
16863 +#define ma_dcu_mon1__pm_mon__a 100
16864 +#define ma_dcu_mon1__pm_mon__len 2
16865 +#define ma_dcu_mon1__pm_mon__mask 0x03
16866 +#define ma_dcu_mon1__pm_mon__shift 0x00
16867 +#define ma_dcu_mon1__pm_mon__reset 0x00
16868 +//-----------------------------------------------------dcu_mon1.freqmode_mon---
16869 +// frequence mode monitor channel 1
16870 +#define ma_dcu_mon1__freqmode_mon__a 100
16871 +#define ma_dcu_mon1__freqmode_mon__len 3
16872 +#define ma_dcu_mon1__freqmode_mon__mask 0x70
16873 +#define ma_dcu_mon1__freqmode_mon__shift 0x04
16874 +#define ma_dcu_mon1__freqmode_mon__reset 0x00
16875 +//-------------------------------------------------------dcu_mon1.pps_passed---
16876 +// dcu1 pps completion indicator
16877 +#define ma_dcu_mon1__pps_passed__a 100
16878 +#define ma_dcu_mon1__pps_passed__len 1
16879 +#define ma_dcu_mon1__pps_passed__mask 0x80
16880 +#define ma_dcu_mon1__pps_passed__shift 0x07
16881 +#define ma_dcu_mon1__pps_passed__reset 0x00
16882 +//----------------------------------------------------------dcu_mon1.ocp_mon---
16883 +// ocp monitor channel 1
16884 +#define ma_dcu_mon1__ocp_mon__a 101
16885 +#define ma_dcu_mon1__ocp_mon__len 1
16886 +#define ma_dcu_mon1__ocp_mon__mask 0x01
16887 +#define ma_dcu_mon1__ocp_mon__shift 0x00
16888 +#define ma_dcu_mon1__ocp_mon__reset 0x00
16889 +//--------------------------------------------------------dcu_mon1.vcfly1_ok---
16890 +// cfly1 protcetion monitor channel 1
16891 +#define ma_dcu_mon1__vcfly1_ok__a 101
16892 +#define ma_dcu_mon1__vcfly1_ok__len 1
16893 +#define ma_dcu_mon1__vcfly1_ok__mask 0x02
16894 +#define ma_dcu_mon1__vcfly1_ok__shift 0x01
16895 +#define ma_dcu_mon1__vcfly1_ok__reset 0x00
16896 +//--------------------------------------------------------dcu_mon1.vcfly2_ok---
16897 +// cfly2 protection monitor channel 1
16898 +#define ma_dcu_mon1__vcfly2_ok__a 101
16899 +#define ma_dcu_mon1__vcfly2_ok__len 1
16900 +#define ma_dcu_mon1__vcfly2_ok__mask 0x04
16901 +#define ma_dcu_mon1__vcfly2_ok__shift 0x02
16902 +#define ma_dcu_mon1__vcfly2_ok__reset 0x00
16903 +//----------------------------------------------------------dcu_mon1.pvdd_ok---
16904 +// dcu1 pvdd monitor
16905 +#define ma_dcu_mon1__pvdd_ok__a 101
16906 +#define ma_dcu_mon1__pvdd_ok__len 1
16907 +#define ma_dcu_mon1__pvdd_ok__mask 0x08
16908 +#define ma_dcu_mon1__pvdd_ok__shift 0x03
16909 +#define ma_dcu_mon1__pvdd_ok__reset 0x00
16910 +//-----------------------------------------------------------dcu_mon1.vdd_ok---
16911 +// dcu1 vdd monitor
16912 +#define ma_dcu_mon1__vdd_ok__a 101
16913 +#define ma_dcu_mon1__vdd_ok__len 1
16914 +#define ma_dcu_mon1__vdd_ok__mask 0x10
16915 +#define ma_dcu_mon1__vdd_ok__shift 0x04
16916 +#define ma_dcu_mon1__vdd_ok__reset 0x00
16917 +//-------------------------------------------------------------dcu_mon1.mute---
16918 +// dcu1 mute monitor
16919 +#define ma_dcu_mon1__mute__a 101
16920 +#define ma_dcu_mon1__mute__len 1
16921 +#define ma_dcu_mon1__mute__mask 0x20
16922 +#define ma_dcu_mon1__mute__shift 0x05
16923 +#define ma_dcu_mon1__mute__reset 0x00
16924 +//------------------------------------------------------------dcu_mon1.m_mon---
16925 +// m sense monitor channel 1
16926 +#define ma_dcu_mon1__m_mon__a 102
16927 +#define ma_dcu_mon1__m_mon__len 8
16928 +#define ma_dcu_mon1__m_mon__mask 0xff
16929 +#define ma_dcu_mon1__m_mon__shift 0x00
16930 +#define ma_dcu_mon1__m_mon__reset 0x00
16931 +//--------------------------------------------------------dcu_mon0.sw_enable---
16932 +// dcu0 switch enable monitor
16933 +#define ma_dcu_mon0__sw_enable__a 104
16934 +#define ma_dcu_mon0__sw_enable__len 1
16935 +#define ma_dcu_mon0__sw_enable__mask 0x40
16936 +#define ma_dcu_mon0__sw_enable__shift 0x06
16937 +#define ma_dcu_mon0__sw_enable__reset 0x00
16938 +//--------------------------------------------------------dcu_mon1.sw_enable---
16939 +// dcu1 switch enable monitor
16940 +#define ma_dcu_mon1__sw_enable__a 104
16941 +#define ma_dcu_mon1__sw_enable__len 1
16942 +#define ma_dcu_mon1__sw_enable__mask 0x80
16943 +#define ma_dcu_mon1__sw_enable__shift 0x07
16944 +#define ma_dcu_mon1__sw_enable__reset 0x00
16945 +//------------------------------------------------------------hvboot0_ok_mon---
16946 +// hvboot0_ok for test/debug
16947 +#define ma_hvboot0_ok_mon__a 105
16948 +#define ma_hvboot0_ok_mon__len 1
16949 +#define ma_hvboot0_ok_mon__mask 0x40
16950 +#define ma_hvboot0_ok_mon__shift 0x06
16951 +#define ma_hvboot0_ok_mon__reset 0x00
16952 +//------------------------------------------------------------hvboot1_ok_mon---
16953 +// hvboot1_ok for test/debug
16954 +#define ma_hvboot1_ok_mon__a 105
16955 +#define ma_hvboot1_ok_mon__len 1
16956 +#define ma_hvboot1_ok_mon__mask 0x80
16957 +#define ma_hvboot1_ok_mon__shift 0x07
16958 +#define ma_hvboot1_ok_mon__reset 0x00
16959 +//-----------------------------------------------------------------error_acc---
16960 +// accumulated errors, at and after triggering
16961 +#define ma_error_acc__a 109
16962 +#define ma_error_acc__len 8
16963 +#define ma_error_acc__mask 0xff
16964 +#define ma_error_acc__shift 0x00
16965 +#define ma_error_acc__reset 0x00
16966 +//-------------------------------------------------------------i2s_data_rate---
16967 +// detected i2s data rate: 00/01/10 = x1/x2/x4
16968 +#define ma_i2s_data_rate__a 116
16969 +#define ma_i2s_data_rate__len 2
16970 +#define ma_i2s_data_rate__mask 0x03
16971 +#define ma_i2s_data_rate__shift 0x00
16972 +#define ma_i2s_data_rate__reset 0x00
16973 +//---------------------------------------------------------audio_in_mode_mon---
16974 +// audio input mode monitor
16975 +#define ma_audio_in_mode_mon__a 116
16976 +#define ma_audio_in_mode_mon__len 3
16977 +#define ma_audio_in_mode_mon__mask 0x1c
16978 +#define ma_audio_in_mode_mon__shift 0x02
16979 +#define ma_audio_in_mode_mon__reset 0x00
16980 +//------------------------------------------------------------------msel_mon---
16981 +// msel[2:0] monitor register
16982 +#define ma_msel_mon__a 117
16983 +#define ma_msel_mon__len 3
16984 +#define ma_msel_mon__mask 0x07
16985 +#define ma_msel_mon__shift 0x00
16986 +#define ma_msel_mon__reset 0x00
16987 +//---------------------------------------------------------------------error---
16988 +// current error flag monitor reg - for app. ctrl.
16989 +#define ma_error__a 124
16990 +#define ma_error__len 8
16991 +#define ma_error__mask 0xff
16992 +#define ma_error__shift 0x00
16993 +#define ma_error__reset 0x00
16994 +//----------------------------------------------------audio_proc_limiter_mon---
16995 +// b7-b4: channel 3-0 limiter active
16996 +#define ma_audio_proc_limiter_mon__a 126
16997 +#define ma_audio_proc_limiter_mon__len 4
16998 +#define ma_audio_proc_limiter_mon__mask 0xf0
16999 +#define ma_audio_proc_limiter_mon__shift 0x04
17000 +#define ma_audio_proc_limiter_mon__reset 0x00
17001 +//-------------------------------------------------------audio_proc_clip_mon---
17002 +// b3-b0: channel 3-0 clipping monitor
17003 +#define ma_audio_proc_clip_mon__a 126
17004 +#define ma_audio_proc_clip_mon__len 4
17005 +#define ma_audio_proc_clip_mon__mask 0x0f
17006 +#define ma_audio_proc_clip_mon__shift 0x00
17007 +#define ma_audio_proc_clip_mon__reset 0x00
17010 +#define SOC_ENUM_ERR(xname, xenum)\
17011 +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
17012 + .access = SNDRV_CTL_ELEM_ACCESS_READ,\
17013 + .info = snd_soc_info_enum_double,\
17014 + .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double,\
17015 + .private_value = (unsigned long)&(xenum) }
17017 +static struct i2c_client *i2c;
17019 +struct ma120x0p_priv {
17020 + struct regmap *regmap;
17022 + struct snd_soc_component *component;
17023 + struct gpio_desc *enable_gpio;
17024 + struct gpio_desc *mute_gpio;
17025 + struct gpio_desc *booster_gpio;
17026 + struct gpio_desc *error_gpio;
17029 +static struct ma120x0p_priv *priv_data;
17031 +//Used to share the IRQ number within this file
17032 +static unsigned int irqNumber;
17034 +// Function prototype for the custom IRQ handler function
17035 +static irqreturn_t ma120x0p_irq_handler(int irq, void *data);
17038 +static const char * const limenable_text[] = {"Bypassed", "Enabled"};
17039 +static const char * const limatack_text[] = {"Slow", "Normal", "Fast"};
17040 +static const char * const limrelease_text[] = {"Slow", "Normal", "Fast"};
17042 +static const char * const err_flycap_text[] = {"Ok", "Error"};
17043 +static const char * const err_overcurr_text[] = {"Ok", "Error"};
17044 +static const char * const err_pllerr_text[] = {"Ok", "Error"};
17045 +static const char * const err_pvddunder_text[] = {"Ok", "Error"};
17046 +static const char * const err_overtempw_text[] = {"Ok", "Error"};
17047 +static const char * const err_overtempe_text[] = {"Ok", "Error"};
17048 +static const char * const err_pinlowimp_text[] = {"Ok", "Error"};
17049 +static const char * const err_dcprot_text[] = {"Ok", "Error"};
17051 +static const char * const pwr_mode_prof_text[] = {"PMF0", "PMF1", "PMF2",
17054 +static const struct soc_enum lim_enable_ctrl =
17055 + SOC_ENUM_SINGLE(ma_audio_proc_limiterenable__a,
17056 + ma_audio_proc_limiterenable__shift,
17057 + ma_audio_proc_limiterenable__len + 1,
17059 +static const struct soc_enum limatack_ctrl =
17060 + SOC_ENUM_SINGLE(ma_audio_proc_attack__a,
17061 + ma_audio_proc_attack__shift,
17062 + ma_audio_proc_attack__len + 1,
17064 +static const struct soc_enum limrelease_ctrl =
17065 + SOC_ENUM_SINGLE(ma_audio_proc_release__a,
17066 + ma_audio_proc_release__shift,
17067 + ma_audio_proc_release__len + 1,
17068 + limrelease_text);
17069 +static const struct soc_enum err_flycap_ctrl =
17070 + SOC_ENUM_SINGLE(ma_error__a, 0, 3, err_flycap_text);
17071 +static const struct soc_enum err_overcurr_ctrl =
17072 + SOC_ENUM_SINGLE(ma_error__a, 1, 3, err_overcurr_text);
17073 +static const struct soc_enum err_pllerr_ctrl =
17074 + SOC_ENUM_SINGLE(ma_error__a, 2, 3, err_pllerr_text);
17075 +static const struct soc_enum err_pvddunder_ctrl =
17076 + SOC_ENUM_SINGLE(ma_error__a, 3, 3, err_pvddunder_text);
17077 +static const struct soc_enum err_overtempw_ctrl =
17078 + SOC_ENUM_SINGLE(ma_error__a, 4, 3, err_overtempw_text);
17079 +static const struct soc_enum err_overtempe_ctrl =
17080 + SOC_ENUM_SINGLE(ma_error__a, 5, 3, err_overtempe_text);
17081 +static const struct soc_enum err_pinlowimp_ctrl =
17082 + SOC_ENUM_SINGLE(ma_error__a, 6, 3, err_pinlowimp_text);
17083 +static const struct soc_enum err_dcprot_ctrl =
17084 + SOC_ENUM_SINGLE(ma_error__a, 7, 3, err_dcprot_text);
17085 +static const struct soc_enum pwr_mode_prof_ctrl =
17086 + SOC_ENUM_SINGLE(ma_pmprofile__a, ma_pmprofile__shift, 5,
17087 + pwr_mode_prof_text);
17089 +static const char * const pwr_mode_texts[] = {
17090 + "Dynamic power mode",
17096 +static const int pwr_mode_values[] = {
17103 +static SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl,
17104 + ma_pm_man__a, 0, 0x70,
17106 + pwr_mode_values);
17108 +static const DECLARE_TLV_DB_SCALE(ma120x0p_vol_tlv, -14400, 100, 0);
17109 +static const DECLARE_TLV_DB_SCALE(ma120x0p_lim_tlv, -5000, 100, 0);
17110 +static const DECLARE_TLV_DB_SCALE(ma120x0p_lr_tlv, -5000, 100, 0);
17112 +static const struct snd_kcontrol_new ma120x0p_snd_controls[] = {
17114 + SOC_SINGLE_RANGE_TLV("A.Mstr Vol Volume",
17115 + ma_vol_db_master__a, 0, 0x18, 0xa8, 1, ma120x0p_vol_tlv),
17118 + SOC_SINGLE_RANGE_TLV("B.L Vol Volume",
17119 + ma_vol_db_ch0__a, 0, 0x18, 0x4a, 1, ma120x0p_lr_tlv),
17120 + SOC_SINGLE_RANGE_TLV("C.R Vol Volume",
17121 + ma_vol_db_ch1__a, 0, 0x18, 0x4a, 1, ma120x0p_lr_tlv),
17123 + //L-R Limiter Threshold ch0-ch1
17124 + SOC_DOUBLE_R_RANGE_TLV("D.Lim thresh Volume",
17125 + ma_thr_db_ch0__a, ma_thr_db_ch1__a, 0, 0x0e, 0x4a, 1,
17126 + ma120x0p_lim_tlv),
17128 + //Enum Switches/Selectors
17129 + //SOC_ENUM("E.AudioProc Mute", audioproc_mute_ctrl),
17130 + SOC_ENUM("F.Limiter Enable", lim_enable_ctrl),
17131 + SOC_ENUM("G.Limiter Attck", limatack_ctrl),
17132 + SOC_ENUM("H.Limiter Rls", limrelease_ctrl),
17134 + //Enum Error Monitor (read-only)
17135 + SOC_ENUM_ERR("I.Err flycap", err_flycap_ctrl),
17136 + SOC_ENUM_ERR("J.Err overcurr", err_overcurr_ctrl),
17137 + SOC_ENUM_ERR("K.Err pllerr", err_pllerr_ctrl),
17138 + SOC_ENUM_ERR("L.Err pvddunder", err_pvddunder_ctrl),
17139 + SOC_ENUM_ERR("M.Err overtempw", err_overtempw_ctrl),
17140 + SOC_ENUM_ERR("N.Err overtempe", err_overtempe_ctrl),
17141 + SOC_ENUM_ERR("O.Err pinlowimp", err_pinlowimp_ctrl),
17142 + SOC_ENUM_ERR("P.Err dcprot", err_dcprot_ctrl),
17144 + //Power modes profiles
17145 + SOC_ENUM("Q.PM Prof", pwr_mode_prof_ctrl),
17147 + // Power mode selection (Dynamic,1,2,3)
17148 + SOC_ENUM("R.Power Mode", pwr_mode_ctrl),
17152 +static int ma120x0p_hw_params(struct snd_pcm_substream *substream,
17153 + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
17157 + struct snd_soc_component *component = dai->component;
17159 + priv_data->component = component;
17161 + switch (params_format(params)) {
17162 + case SNDRV_PCM_FORMAT_S16_LE:
17165 + case SNDRV_PCM_FORMAT_S24_LE:
17168 + case SNDRV_PCM_FORMAT_S32_LE:
17172 + dev_err(dai->dev, "Unsupported word length: %u\n",
17173 + params_format(params));
17177 + // set word length
17178 + snd_soc_component_update_bits(component, ma_i2s_framesize__a,
17179 + ma_i2s_framesize__mask, blen);
17184 +static int ma120x0p_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
17188 + struct ma120x0p_priv *ma120x0p;
17190 + struct snd_soc_component *component = dai->component;
17192 + ma120x0p = snd_soc_component_get_drvdata(component);
17199 + gpiod_set_value_cansleep(priv_data->mute_gpio, val);
17204 +static const struct snd_soc_dai_ops ma120x0p_dai_ops = {
17205 + .hw_params = ma120x0p_hw_params,
17206 + .mute_stream = ma120x0p_mute_stream,
17209 +static struct snd_soc_dai_driver ma120x0p_dai = {
17210 + .name = "ma120x0p-amp",
17212 + .stream_name = "Playback",
17213 + .channels_min = 2,
17214 + .channels_max = 2,
17215 + .rates = SNDRV_PCM_RATE_CONTINUOUS,
17216 + .rate_min = 44100,
17217 + .rate_max = 192000,
17218 + .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE
17220 + .ops = &ma120x0p_dai_ops,
17224 +static int ma120x0p_clear_err(struct snd_soc_component *component)
17228 + struct ma120x0p_priv *ma120x0p;
17230 + ma120x0p = snd_soc_component_get_drvdata(component);
17232 + ret = snd_soc_component_update_bits(component,
17233 + ma_eh_clear__a, ma_eh_clear__mask, 0x00);
17237 + ret = snd_soc_component_update_bits(component,
17238 + ma_eh_clear__a, ma_eh_clear__mask, 0x04);
17242 + ret = snd_soc_component_update_bits(component,
17243 + ma_eh_clear__a, ma_eh_clear__mask, 0x00);
17250 +static void ma120x0p_remove(struct snd_soc_component *component)
17252 + struct ma120x0p_priv *ma120x0p;
17254 + ma120x0p = snd_soc_component_get_drvdata(component);
17257 +static int ma120x0p_probe(struct snd_soc_component *component)
17259 + struct ma120x0p_priv *ma120x0p;
17263 + i2c = container_of(component->dev, struct i2c_client, dev);
17265 + ma120x0p = snd_soc_component_get_drvdata(component);
17268 + ma120x0p_clear_err(component);
17272 + // set serial audio format I2S and enable audio processor
17273 + ret = snd_soc_component_write(component, ma_i2s_format__a, 0x08);
17277 + // Enable audio limiter
17278 + ret = snd_soc_component_update_bits(component,
17279 + ma_audio_proc_limiterenable__a,
17280 + ma_audio_proc_limiterenable__mask, 0x40);
17284 + // Set lim attack to fast
17285 + ret = snd_soc_component_update_bits(component,
17286 + ma_audio_proc_attack__a, ma_audio_proc_attack__mask, 0x80);
17290 + // Set lim attack to low
17291 + ret = snd_soc_component_update_bits(component,
17292 + ma_audio_proc_release__a, ma_audio_proc_release__mask, 0x00);
17296 + // set volume to 0dB
17297 + ret = snd_soc_component_write(component, ma_vol_db_master__a, 0x18);
17301 + // set ch0 lim thresh to -15dB
17302 + ret = snd_soc_component_write(component, ma_thr_db_ch0__a, 0x27);
17306 + // set ch1 lim thresh to -15dB
17307 + ret = snd_soc_component_write(component, ma_thr_db_ch1__a, 0x27);
17311 + //Check for errors
17312 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x00, 0);
17315 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x01, 0);
17318 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x02, 0);
17321 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x08, 0);
17324 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x10, 0);
17327 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x20, 0);
17330 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x40, 0);
17333 + ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x80, 0);
17340 +static int ma120x0p_set_bias_level(struct snd_soc_component *component,
17341 + enum snd_soc_bias_level level)
17345 + struct ma120x0p_priv *ma120x0p;
17347 + ma120x0p = snd_soc_component_get_drvdata(component);
17350 + case SND_SOC_BIAS_ON:
17353 + case SND_SOC_BIAS_PREPARE:
17356 + case SND_SOC_BIAS_STANDBY:
17357 + ret = gpiod_get_value_cansleep(priv_data->enable_gpio);
17359 + dev_err(component->dev, "Device ma120x0p disabled in STANDBY BIAS: %d\n",
17365 + case SND_SOC_BIAS_OFF:
17372 +static const struct snd_soc_dapm_widget ma120x0p_dapm_widgets[] = {
17373 + SND_SOC_DAPM_OUTPUT("OUT_A"),
17374 + SND_SOC_DAPM_OUTPUT("OUT_B"),
17377 +static const struct snd_soc_dapm_route ma120x0p_dapm_routes[] = {
17378 + { "OUT_B", NULL, "Playback" },
17379 + { "OUT_A", NULL, "Playback" },
17382 +static const struct snd_soc_component_driver ma120x0p_component_driver = {
17383 + .probe = ma120x0p_probe,
17384 + .remove = ma120x0p_remove,
17385 + .set_bias_level = ma120x0p_set_bias_level,
17386 + .dapm_widgets = ma120x0p_dapm_widgets,
17387 + .num_dapm_widgets = ARRAY_SIZE(ma120x0p_dapm_widgets),
17388 + .dapm_routes = ma120x0p_dapm_routes,
17389 + .num_dapm_routes = ARRAY_SIZE(ma120x0p_dapm_routes),
17390 + .controls = ma120x0p_snd_controls,
17391 + .num_controls = ARRAY_SIZE(ma120x0p_snd_controls),
17392 + .use_pmdown_time = 1,
17397 +static const struct reg_default ma120x0p_reg_defaults[] = {
17401 +static bool ma120x0p_reg_volatile(struct device *dev, unsigned int reg)
17404 + case ma_error__a:
17411 +static const struct of_device_id ma120x0p_of_match[] = {
17412 + { .compatible = "ma,ma120x0p", },
17416 +MODULE_DEVICE_TABLE(of, ma120x0p_of_match);
17418 +static struct regmap_config ma120x0p_regmap_config = {
17422 + .max_register = 255,
17423 + .volatile_reg = ma120x0p_reg_volatile,
17425 + .cache_type = REGCACHE_RBTREE,
17426 + .reg_defaults = ma120x0p_reg_defaults,
17427 + .num_reg_defaults = ARRAY_SIZE(ma120x0p_reg_defaults),
17430 +static int ma120x0p_i2c_probe(struct i2c_client *i2c)
17434 + priv_data = devm_kzalloc(&i2c->dev, sizeof(*priv_data), GFP_KERNEL);
17437 + i2c_set_clientdata(i2c, priv_data);
17439 + priv_data->regmap = devm_regmap_init_i2c(i2c, &ma120x0p_regmap_config);
17440 + if (IS_ERR(priv_data->regmap)) {
17441 + ret = PTR_ERR(priv_data->regmap);
17445 + //Startup sequence
17447 + //Make sure the device is muted
17448 + priv_data->mute_gpio = devm_gpiod_get_optional(&i2c->dev, "mute_gp",
17450 + if (IS_ERR(priv_data->mute_gpio)) {
17451 + ret = PTR_ERR(priv_data->mute_gpio);
17452 + dev_err(&i2c->dev, "Failed to get mute gpio line: %d\n", ret);
17457 +// MA120xx0P devices are usually powered by an integrated boost converter.
17458 +// An option GPIO control line is provided to enable the booster properly and
17459 +// in sync with the enable and mute GPIO lines.
17460 + priv_data->booster_gpio = devm_gpiod_get_optional(&i2c->dev,
17461 + "booster_gp", GPIOD_OUT_LOW);
17462 + if (IS_ERR(priv_data->booster_gpio)) {
17463 + ret = PTR_ERR(priv_data->booster_gpio);
17464 + dev_err(&i2c->dev,
17465 + "Failed to get booster enable gpio line: %d\n", ret);
17470 + //Enable booster and wait 200ms until stable PVDD
17471 + gpiod_set_value_cansleep(priv_data->booster_gpio, 1);
17474 + //Enable ma120x0pp
17475 + priv_data->enable_gpio = devm_gpiod_get_optional(&i2c->dev,
17476 + "enable_gp", GPIOD_OUT_LOW);
17477 + if (IS_ERR(priv_data->enable_gpio)) {
17478 + ret = PTR_ERR(priv_data->enable_gpio);
17479 + dev_err(&i2c->dev,
17480 + "Failed to get ma120x0p enable gpio line: %d\n", ret);
17485 + //Optional use of ma120x0pp error line as an interrupt trigger to
17487 + //Get error input gpio ma120x0p
17488 + priv_data->error_gpio = devm_gpiod_get_optional(&i2c->dev,
17489 + "error_gp", GPIOD_IN);
17490 + if (IS_ERR(priv_data->error_gpio)) {
17491 + ret = PTR_ERR(priv_data->error_gpio);
17492 + dev_err(&i2c->dev,
17493 + "Failed to get ma120x0p error gpio line: %d\n", ret);
17497 + if (priv_data->error_gpio != NULL) {
17498 + irqNumber = gpiod_to_irq(priv_data->error_gpio);
17500 + ret = devm_request_threaded_irq(&i2c->dev,
17501 + irqNumber, ma120x0p_irq_handler,
17502 + NULL, IRQF_TRIGGER_FALLING,
17503 + "ma120x0p", priv_data);
17505 + dev_warn(&i2c->dev, "Failed to request IRQ: %d\n",
17509 + ret = devm_snd_soc_register_component(&i2c->dev,
17510 + &ma120x0p_component_driver, &ma120x0p_dai, 1);
17515 +static irqreturn_t ma120x0p_irq_handler(int irq, void *data)
17517 + gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
17518 + gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
17519 + return IRQ_HANDLED;
17522 +static void ma120x0p_i2c_remove(struct i2c_client *i2c)
17524 + snd_soc_unregister_component(&i2c->dev);
17525 + i2c_set_clientdata(i2c, NULL);
17527 + gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
17529 + gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
17531 + gpiod_set_value_cansleep(priv_data->booster_gpio, 0);
17534 + kfree(priv_data);
17537 +static void ma120x0p_i2c_shutdown(struct i2c_client *i2c)
17539 + snd_soc_unregister_component(&i2c->dev);
17540 + i2c_set_clientdata(i2c, NULL);
17542 + gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
17544 + gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
17546 + gpiod_set_value_cansleep(priv_data->booster_gpio, 0);
17549 + kfree(priv_data);
17552 +static const struct i2c_device_id ma120x0p_i2c_id[] = {
17553 + { "ma120x0p", 0 },
17557 +MODULE_DEVICE_TABLE(i2c, ma120x0p_i2c_id);
17559 +static struct i2c_driver ma120x0p_i2c_driver = {
17561 + .name = "ma120x0p",
17562 + .owner = THIS_MODULE,
17563 + .of_match_table = ma120x0p_of_match,
17565 + .probe = ma120x0p_i2c_probe,
17566 + .remove = ma120x0p_i2c_remove,
17567 + .shutdown = ma120x0p_i2c_shutdown,
17568 + .id_table = ma120x0p_i2c_id
17571 +static int __init ma120x0p_modinit(void)
17575 + ret = i2c_add_driver(&ma120x0p_i2c_driver);
17577 + pr_err("Failed to register MA120X0P I2C driver: %d\n", ret);
17582 +module_init(ma120x0p_modinit);
17584 +static void __exit ma120x0p_exit(void)
17586 + i2c_del_driver(&ma120x0p_i2c_driver);
17588 +module_exit(ma120x0p_exit);
17590 +MODULE_AUTHOR("Ariel Muszkat ariel.muszkat@gmail.com>");
17591 +MODULE_DESCRIPTION("ASoC driver for ma120x0p");
17592 +MODULE_LICENSE("GPL v2");
17594 +++ b/sound/soc/codecs/pcm1794a.c
17597 + * Driver for the PCM1794A codec
17599 + * Author: Florian Meier <florian.meier@koalo.de>
17602 + * This program is free software; you can redistribute it and/or
17603 + * modify it under the terms of the GNU General Public License
17604 + * version 2 as published by the Free Software Foundation.
17606 + * This program is distributed in the hope that it will be useful, but
17607 + * WITHOUT ANY WARRANTY; without even the implied warranty of
17608 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17609 + * General Public License for more details.
17613 +#include <linux/init.h>
17614 +#include <linux/module.h>
17615 +#include <linux/platform_device.h>
17617 +#include <sound/soc.h>
17619 +static struct snd_soc_dai_driver pcm1794a_dai = {
17620 + .name = "pcm1794a-hifi",
17622 + .channels_min = 2,
17623 + .channels_max = 2,
17624 + .rates = SNDRV_PCM_RATE_8000_192000,
17625 + .formats = SNDRV_PCM_FMTBIT_S16_LE |
17626 + SNDRV_PCM_FMTBIT_S24_LE
17630 +static struct snd_soc_component_driver soc_component_dev_pcm1794a;
17632 +static int pcm1794a_probe(struct platform_device *pdev)
17634 + return snd_soc_register_component(&pdev->dev, &soc_component_dev_pcm1794a,
17635 + &pcm1794a_dai, 1);
17638 +static void pcm1794a_remove(struct platform_device *pdev)
17640 + snd_soc_unregister_component(&pdev->dev);
17643 +static const struct of_device_id pcm1794a_of_match[] = {
17644 + { .compatible = "ti,pcm1794a", },
17647 +MODULE_DEVICE_TABLE(of, pcm1794a_of_match);
17649 +static struct platform_driver pcm1794a_component_driver = {
17650 + .probe = pcm1794a_probe,
17651 + .remove = pcm1794a_remove,
17653 + .name = "pcm1794a-codec",
17654 + .owner = THIS_MODULE,
17655 + .of_match_table = of_match_ptr(pcm1794a_of_match),
17659 +module_platform_driver(pcm1794a_component_driver);
17661 +MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
17662 +MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
17663 +MODULE_LICENSE("GPL v2");
17664 --- a/sound/soc/codecs/pcm512x.c
17665 +++ b/sound/soc/codecs/pcm512x.c
17666 @@ -537,7 +537,7 @@ static unsigned long pcm512x_ncp_target(
17668 static const u32 pcm512x_dai_rates[] = {
17669 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
17670 - 88200, 96000, 176400, 192000, 384000,
17671 + 88200, 96000, 176400, 192000, 352800, 384000,
17674 static const struct snd_pcm_hw_constraint_list constraints_slave = {
17676 +++ b/sound/soc/codecs/tas5713.c
17679 + * ASoC Driver for TAS5713
17681 + * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
17684 + * This program is free software; you can redistribute it and/or
17685 + * modify it under the terms of the GNU General Public License
17686 + * version 2 as published by the Free Software Foundation.
17688 + * This program is distributed in the hope that it will be useful, but
17689 + * WITHOUT ANY WARRANTY; without even the implied warranty of
17690 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17691 + * General Public License for more details.
17694 +#include <linux/module.h>
17695 +#include <linux/moduleparam.h>
17696 +#include <linux/init.h>
17697 +#include <linux/delay.h>
17698 +#include <linux/pm.h>
17699 +#include <linux/i2c.h>
17700 +#include <linux/of_device.h>
17701 +#include <linux/spi/spi.h>
17702 +#include <linux/regmap.h>
17703 +#include <linux/regulator/consumer.h>
17704 +#include <linux/slab.h>
17705 +#include <sound/core.h>
17706 +#include <sound/pcm.h>
17707 +#include <sound/pcm_params.h>
17708 +#include <sound/soc.h>
17709 +#include <sound/initval.h>
17710 +#include <sound/tlv.h>
17712 +#include <linux/kernel.h>
17713 +#include <linux/string.h>
17714 +#include <linux/fs.h>
17715 +#include <asm/uaccess.h>
17717 +#include "tas5713.h"
17720 +static struct i2c_client *i2c;
17722 +struct tas5713_priv {
17723 + struct regmap *regmap;
17725 + struct snd_soc_component *component;
17728 +static struct tas5713_priv *priv_data;
17734 + * _ _ ___ _ ___ _ _
17735 + * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
17736 + * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
17737 + * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
17741 +static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
17744 +static const struct snd_kcontrol_new tas5713_snd_controls[] = {
17745 + SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
17746 + SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
17753 + * __ __ _ _ ___ _
17754 + * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
17755 + * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
17756 + * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
17760 +static int tas5713_hw_params(struct snd_pcm_substream *substream,
17761 + struct snd_pcm_hw_params *params,
17762 + struct snd_soc_dai *dai)
17766 + struct snd_soc_component *component = dai->component;
17767 + priv_data->component = component;
17769 + switch (params_format(params)) {
17770 + case SNDRV_PCM_FORMAT_S16_LE:
17773 + case SNDRV_PCM_FORMAT_S20_3LE:
17776 + case SNDRV_PCM_FORMAT_S24_LE:
17779 + case SNDRV_PCM_FORMAT_S32_LE:
17783 + dev_err(dai->dev, "Unsupported word length: %u\n",
17784 + params_format(params));
17788 + // set word length
17789 + snd_soc_component_update_bits(component, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
17795 +static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
17797 + unsigned int val = 0;
17799 + struct tas5713_priv *tas5713;
17800 + struct snd_soc_component *component = dai->component;
17801 + tas5713 = snd_soc_component_get_drvdata(component);
17804 + val = TAS5713_SOFT_MUTE_ALL;
17807 + return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
17811 +static const struct snd_soc_dai_ops tas5713_dai_ops = {
17812 + .hw_params = tas5713_hw_params,
17813 + .mute_stream = tas5713_mute_stream,
17817 +static struct snd_soc_dai_driver tas5713_dai = {
17818 + .name = "tas5713-hifi",
17820 + .stream_name = "Playback",
17821 + .channels_min = 2,
17822 + .channels_max = 2,
17823 + .rates = SNDRV_PCM_RATE_8000_48000,
17824 + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
17826 + .ops = &tas5713_dai_ops,
17834 + * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
17835 + * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
17836 + * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
17840 +static void tas5713_remove(struct snd_soc_component *component)
17842 + struct tas5713_priv *tas5713;
17844 + tas5713 = snd_soc_component_get_drvdata(component);
17848 +static int tas5713_probe(struct snd_soc_component *component)
17850 + struct tas5713_priv *tas5713;
17853 + i2c = container_of(component->dev, struct i2c_client, dev);
17855 + tas5713 = snd_soc_component_get_drvdata(component);
17858 + ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
17859 + if (ret < 0) return ret;
17861 + // Trim oscillator
17862 + ret = snd_soc_component_write(component, TAS5713_OSC_TRIM, 0x00);
17863 + if (ret < 0) return ret;
17867 + ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
17868 + if (ret < 0) return ret;
17871 + ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
17872 + if (ret < 0) return ret;
17875 + ret = snd_soc_component_write(component, TAS5713_SYSTEM_CTRL2, 0x00);
17876 + if (ret < 0) return ret;
17877 + ret = snd_soc_component_write(component, TAS5713_SOFT_MUTE, 0x00);
17878 + if (ret < 0) return ret;
17880 + // Set volume to 0db
17881 + ret = snd_soc_component_write(component, TAS5713_VOL_MASTER, 0x00);
17882 + if (ret < 0) return ret;
17884 + // Now start programming the default initialization sequence
17885 + for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
17886 + ret = i2c_master_send(i2c,
17887 + tas5713_init_sequence[i].data,
17888 + tas5713_init_sequence[i].size);
17890 + printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
17895 + ret = snd_soc_component_write(component, TAS5713_SYSTEM_CTRL2, 0x00);
17896 + if (ret < 0) return ret;
17902 +static struct snd_soc_component_driver soc_codec_dev_tas5713 = {
17903 + .probe = tas5713_probe,
17904 + .remove = tas5713_remove,
17905 + .controls = tas5713_snd_controls,
17906 + .num_controls = ARRAY_SIZE(tas5713_snd_controls),
17913 + * ___ ___ ___ ___ _
17914 + * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
17915 + * | | / / (__ | |) | '_| \ V / -_) '_|
17916 + * |___/___\___| |___/|_| |_|\_/\___|_|
17920 +static const struct reg_default tas5713_reg_defaults[] = {
17921 + { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
17922 + { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
17923 + { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
17924 + { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
17928 +static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
17931 + case TAS5713_DEVICE_ID:
17932 + case TAS5713_ERROR_STATUS:
17933 + case TAS5713_CLOCK_CTRL:
17941 +static const struct of_device_id tas5713_of_match[] = {
17942 + { .compatible = "ti,tas5713", },
17945 +MODULE_DEVICE_TABLE(of, tas5713_of_match);
17948 +static struct regmap_config tas5713_regmap_config = {
17952 + .max_register = TAS5713_MAX_REGISTER,
17953 + .volatile_reg = tas5713_reg_volatile,
17955 + .cache_type = REGCACHE_RBTREE,
17956 + .reg_defaults = tas5713_reg_defaults,
17957 + .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
17961 +static int tas5713_i2c_probe(struct i2c_client *i2c)
17965 + priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
17969 + priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
17970 + if (IS_ERR(priv_data->regmap)) {
17971 + ret = PTR_ERR(priv_data->regmap);
17975 + i2c_set_clientdata(i2c, priv_data);
17977 + ret = snd_soc_register_component(&i2c->dev,
17978 + &soc_codec_dev_tas5713, &tas5713_dai, 1);
17984 +static void tas5713_i2c_remove(struct i2c_client *i2c)
17986 + snd_soc_unregister_component(&i2c->dev);
17987 + i2c_set_clientdata(i2c, NULL);
17989 + kfree(priv_data);
17993 +static const struct i2c_device_id tas5713_i2c_id[] = {
17994 + { "tas5713", 0 },
17998 +MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
18001 +static struct i2c_driver tas5713_i2c_driver = {
18003 + .name = "tas5713",
18004 + .owner = THIS_MODULE,
18005 + .of_match_table = tas5713_of_match,
18007 + .probe = tas5713_i2c_probe,
18008 + .remove = tas5713_i2c_remove,
18009 + .id_table = tas5713_i2c_id
18013 +static int __init tas5713_modinit(void)
18017 + ret = i2c_add_driver(&tas5713_i2c_driver);
18019 + printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
18025 +module_init(tas5713_modinit);
18028 +static void __exit tas5713_exit(void)
18030 + i2c_del_driver(&tas5713_i2c_driver);
18032 +module_exit(tas5713_exit);
18035 +MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
18036 +MODULE_DESCRIPTION("ASoC driver for TAS5713");
18037 +MODULE_LICENSE("GPL v2");
18039 +++ b/sound/soc/codecs/tas5713.h
18042 + * ASoC Driver for TAS5713
18044 + * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
18047 + * This program is free software; you can redistribute it and/or
18048 + * modify it under the terms of the GNU General Public License
18049 + * version 2 as published by the Free Software Foundation.
18051 + * This program is distributed in the hope that it will be useful, but
18052 + * WITHOUT ANY WARRANTY; without even the implied warranty of
18053 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18054 + * General Public License for more details.
18057 +#ifndef _TAS5713_H
18058 +#define _TAS5713_H
18061 +// TAS5713 I2C-bus register addresses
18063 +#define TAS5713_CLOCK_CTRL 0x00
18064 +#define TAS5713_DEVICE_ID 0x01
18065 +#define TAS5713_ERROR_STATUS 0x02
18066 +#define TAS5713_SYSTEM_CTRL1 0x03
18067 +#define TAS5713_SERIAL_DATA_INTERFACE 0x04
18068 +#define TAS5713_SYSTEM_CTRL2 0x05
18069 +#define TAS5713_SOFT_MUTE 0x06
18070 +#define TAS5713_VOL_MASTER 0x07
18071 +#define TAS5713_VOL_CH1 0x08
18072 +#define TAS5713_VOL_CH2 0x09
18073 +#define TAS5713_VOL_HEADPHONE 0x0A
18074 +#define TAS5713_VOL_CONFIG 0x0E
18075 +#define TAS5713_MODULATION_LIMIT 0x10
18076 +#define TAS5713_IC_DLY_CH1 0x11
18077 +#define TAS5713_IC_DLY_CH2 0x12
18078 +#define TAS5713_IC_DLY_CH3 0x13
18079 +#define TAS5713_IC_DLY_CH4 0x14
18081 +#define TAS5713_START_STOP_PERIOD 0x1A
18082 +#define TAS5713_OSC_TRIM 0x1B
18083 +#define TAS5713_BKND_ERR 0x1C
18085 +#define TAS5713_INPUT_MUX 0x20
18086 +#define TAS5713_SRC_SELECT_CH4 0x21
18087 +#define TAS5713_PWM_MUX 0x25
18089 +#define TAS5713_CH1_BQ0 0x29
18090 +#define TAS5713_CH1_BQ1 0x2A
18091 +#define TAS5713_CH1_BQ2 0x2B
18092 +#define TAS5713_CH1_BQ3 0x2C
18093 +#define TAS5713_CH1_BQ4 0x2D
18094 +#define TAS5713_CH1_BQ5 0x2E
18095 +#define TAS5713_CH1_BQ6 0x2F
18096 +#define TAS5713_CH1_BQ7 0x58
18097 +#define TAS5713_CH1_BQ8 0x59
18099 +#define TAS5713_CH2_BQ0 0x30
18100 +#define TAS5713_CH2_BQ1 0x31
18101 +#define TAS5713_CH2_BQ2 0x32
18102 +#define TAS5713_CH2_BQ3 0x33
18103 +#define TAS5713_CH2_BQ4 0x34
18104 +#define TAS5713_CH2_BQ5 0x35
18105 +#define TAS5713_CH2_BQ6 0x36
18106 +#define TAS5713_CH2_BQ7 0x5C
18107 +#define TAS5713_CH2_BQ8 0x5D
18109 +#define TAS5713_CH4_BQ0 0x5A
18110 +#define TAS5713_CH4_BQ1 0x5B
18111 +#define TAS5713_CH3_BQ0 0x5E
18112 +#define TAS5713_CH3_BQ1 0x5F
18114 +#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
18115 +#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
18116 +#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
18117 +#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
18118 +#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
18119 +#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
18120 +#define TAS5713_DRC_CTRL 0x46
18122 +#define TAS5713_BANK_SW_CTRL 0x50
18123 +#define TAS5713_CH1_OUTPUT_MIXER 0x51
18124 +#define TAS5713_CH2_OUTPUT_MIXER 0x52
18125 +#define TAS5713_CH1_INPUT_MIXER 0x53
18126 +#define TAS5713_CH2_INPUT_MIXER 0x54
18127 +#define TAS5713_OUTPUT_POST_SCALE 0x56
18128 +#define TAS5713_OUTPUT_PRESCALE 0x57
18130 +#define TAS5713_IDF_POST_SCALE 0x62
18132 +#define TAS5713_CH1_INLINE_MIXER 0x70
18133 +#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
18134 +#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
18135 +#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
18136 +#define TAS5713_CH2_INLINE_MIXER 0x74
18137 +#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
18138 +#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
18139 +#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
18141 +#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
18142 +#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
18144 +#define TAS5713_REGISTER_COUNT 0x46
18145 +#define TAS5713_MAX_REGISTER 0xF9
18148 +// Bitmasks for registers
18149 +#define TAS5713_SOFT_MUTE_ALL 0x07
18153 +struct tas5713_init_command {
18155 + const char *const data;
18158 +static const struct tas5713_init_command tas5713_init_sequence[] = {
18160 + // Trim oscillator
18161 + { .size = 2, .data = "\x1B\x00" },
18162 + // System control register 1 (0x03): block DC
18163 + { .size = 2, .data = "\x03\x80" },
18164 + // Mute everything
18165 + { .size = 2, .data = "\x05\x40" },
18166 + // Modulation limit register (0x10): 97.7%
18167 + { .size = 2, .data = "\x10\x02" },
18168 + // Interchannel delay registers
18169 + // (0x11, 0x12, 0x13, and 0x14): BD mode
18170 + { .size = 2, .data = "\x11\xB8" },
18171 + { .size = 2, .data = "\x12\x60" },
18172 + { .size = 2, .data = "\x13\xA0" },
18173 + { .size = 2, .data = "\x14\x48" },
18174 + // PWM shutdown group register (0x19): no shutdown
18175 + { .size = 2, .data = "\x19\x00" },
18176 + // Input multiplexer register (0x20): BD mode
18177 + { .size = 2, .data = "\x20\x00\x89\x77\x72" },
18178 + // PWM output mux register (0x25)
18179 + // Channel 1 --> OUTA, channel 1 neg --> OUTB
18180 + // Channel 2 --> OUTC, channel 2 neg --> OUTD
18181 + { .size = 5, .data = "\x25\x01\x02\x13\x45" },
18182 + // DRC control (0x46): DRC off
18183 + { .size = 5, .data = "\x46\x00\x00\x00\x00" },
18184 + // BKND_ERR register (0x1C): 299ms reset period
18185 + { .size = 2, .data = "\x1C\x07" },
18186 + // Mute channel 3
18187 + { .size = 2, .data = "\x0A\xFF" },
18188 + // Volume configuration register (0x0E): volume slew 512 steps
18189 + { .size = 2, .data = "\x0E\x90" },
18190 + // Clock control register (0x00): 44/48kHz, MCLK=64xfs
18191 + { .size = 2, .data = "\x00\x60" },
18192 + // Bank switch and eq control (0x50): no bank switching
18193 + { .size = 5, .data = "\x50\x00\x00\x00\x00" },
18194 + // Volume registers (0x07, 0x08, 0x09, 0x0A)
18195 + { .size = 2, .data = "\x07\x20" },
18196 + { .size = 2, .data = "\x08\x30" },
18197 + { .size = 2, .data = "\x09\x30" },
18198 + { .size = 2, .data = "\x0A\xFF" },
18199 + // 0x72, 0x73, 0x76, 0x77 input mixer:
18200 + // no intermix between channels
18201 + { .size = 5, .data = "\x72\x00\x00\x00\x00" },
18202 + { .size = 5, .data = "\x73\x00\x80\x00\x00" },
18203 + { .size = 5, .data = "\x76\x00\x00\x00\x00" },
18204 + { .size = 5, .data = "\x77\x00\x80\x00\x00" },
18205 + // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
18206 + // no inline DRC inmix
18207 + { .size = 5, .data = "\x70\x00\x80\x00\x00" },
18208 + { .size = 5, .data = "\x71\x00\x00\x00\x00" },
18209 + { .size = 5, .data = "\x74\x00\x80\x00\x00" },
18210 + { .size = 5, .data = "\x75\x00\x00\x00\x00" },
18211 + // 0x56, 0x57 Output scale
18212 + { .size = 5, .data = "\x56\x00\x80\x00\x00" },
18213 + { .size = 5, .data = "\x57\x00\x02\x00\x00" },
18215 + { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
18216 + { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
18217 + { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
18218 + { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
18219 + { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
18220 + { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
18221 + // 0x51, 0x52: output mixer
18222 + { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
18223 + { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
18225 + { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18226 + { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18227 + { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18228 + { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18229 + { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18230 + { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18231 + { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18232 + { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18233 + { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18234 + { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18235 + { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18236 + { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18237 + { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18238 + { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18239 + { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18240 + { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18241 + { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18242 + { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18243 + { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18244 + { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18245 + { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18246 + { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
18250 +#endif /* _TAS5713_H */
18251 --- a/sound/soc/dwc/dwc-i2s.c
18252 +++ b/sound/soc/dwc/dwc-i2s.c
18253 @@ -209,12 +209,21 @@ static void i2s_start(struct dw_i2s_dev
18254 static void i2s_stop(struct dw_i2s_dev *dev,
18255 struct snd_pcm_substream *substream)
18257 + if (dev->is_jh7110) {
18258 + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
18259 + struct snd_soc_dai_link *dai_link = rtd->dai_link;
18261 + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
18263 + i2s_clear_irqs(dev, substream->stream);
18265 + i2s_disable_irqs(dev, substream->stream, 8);
18268 +static void i2s_pause(struct dw_i2s_dev *dev,
18269 + struct snd_pcm_substream *substream)
18271 i2s_clear_irqs(dev, substream->stream);
18272 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18273 - i2s_write_reg(dev->i2s_base, ITER, 0);
18275 - i2s_write_reg(dev->i2s_base, IRER, 0);
18277 if (!(dev->use_pio || dev->is_jh7110))
18278 i2s_disable_dma(dev, substream->stream);
18279 @@ -224,14 +233,39 @@ static void i2s_stop(struct dw_i2s_dev *
18281 if (!dev->active) {
18282 i2s_write_reg(dev->i2s_base, CER, 0);
18283 - i2s_write_reg(dev->i2s_base, IER, 0);
18284 + /* Keep the device enabled until the shutdown - do not clear IER */
18288 +static void dw_i2s_config(struct dw_i2s_dev *dev, int stream);
18289 static int dw_i2s_startup(struct snd_pcm_substream *substream,
18290 struct snd_soc_dai *cpu_dai)
18292 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
18293 + union dw_i2s_snd_dma_data *dma_data = NULL;
18296 + dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
18297 + if (!(dev->capability & DWC_I2S_RECORD) &&
18298 + substream->stream == SNDRV_PCM_STREAM_CAPTURE)
18301 + if (!(dev->capability & DWC_I2S_PLAY) &&
18302 + substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18305 + dw_i2s_config(dev, substream->stream);
18306 + dmacr = i2s_read_reg(dev->i2s_base, I2S_DMACR);
18307 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
18308 + dma_data = &dev->play_dma_data;
18309 + dmacr |= DMACR_DMAEN_TX;
18310 + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
18311 + dma_data = &dev->capture_dma_data;
18312 + dmacr |= DMACR_DMAEN_RX;
18315 + snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
18316 + i2s_write_reg(dev->i2s_base, I2S_DMACR, dmacr);
18318 if (dev->is_jh7110) {
18319 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
18320 @@ -243,14 +277,41 @@ static int dw_i2s_startup(struct snd_pcm
18324 +static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
18325 + struct snd_soc_dai *dai)
18327 + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
18329 + dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
18330 + i2s_disable_channels(dev, substream->stream);
18331 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18332 + i2s_write_reg(dev->i2s_base, ITER, 0);
18334 + i2s_write_reg(dev->i2s_base, IRER, 0);
18336 + i2s_disable_irqs(dev, substream->stream, 8);
18338 + if (!dev->active) {
18339 + i2s_write_reg(dev->i2s_base, CER, 0);
18340 + i2s_write_reg(dev->i2s_base, IER, 0);
18344 static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
18347 struct i2s_clk_config_data *config = &dev->config;
18351 i2s_disable_channels(dev, stream);
18353 + dmacr = i2s_read_reg(dev->i2s_base, I2S_DMACR);
18355 + if (stream == SNDRV_PCM_STREAM_PLAYBACK)
18356 + dmacr &= ~(DMACR_DMAEN_TXCH0 * 0xf);
18358 + dmacr &= ~(DMACR_DMAEN_RXCH0 * 0xf);
18360 for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
18361 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
18362 i2s_write_reg(dev->i2s_base, TCR(ch_reg),
18363 @@ -259,6 +320,7 @@ static void dw_i2s_config(struct dw_i2s_
18365 i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
18366 dev->tdm_mask << TER_TXSLOT_SHIFT);
18367 + dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg);
18369 i2s_write_reg(dev->i2s_base, RCR(ch_reg),
18370 dev->xfer_resolution);
18371 @@ -266,9 +328,11 @@ static void dw_i2s_config(struct dw_i2s_
18373 i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN |
18374 dev->tdm_mask << RER_RXSLOT_SHIFT);
18375 + dmacr |= (DMACR_DMAEN_RXCH0 << ch_reg);
18380 + i2s_write_reg(dev->i2s_base, I2S_DMACR, dmacr);
18383 static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
18384 @@ -276,24 +340,32 @@ static int dw_i2s_hw_params(struct snd_p
18386 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
18387 struct i2s_clk_config_data *config = &dev->config;
18388 + union dw_i2s_snd_dma_data *dma_data = NULL;
18391 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18392 + dma_data = &dev->play_dma_data;
18393 + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
18394 + dma_data = &dev->capture_dma_data;
18398 switch (params_format(params)) {
18399 case SNDRV_PCM_FORMAT_S16_LE:
18400 config->data_width = 16;
18402 + dma_data->dt.addr_width = 2;
18403 dev->xfer_resolution = 0x02;
18406 case SNDRV_PCM_FORMAT_S24_LE:
18407 config->data_width = 24;
18409 + dma_data->dt.addr_width = 4;
18410 dev->xfer_resolution = 0x04;
18413 case SNDRV_PCM_FORMAT_S32_LE:
18414 config->data_width = 32;
18416 + dma_data->dt.addr_width = 4;
18417 dev->xfer_resolution = 0x05;
18420 @@ -314,17 +386,37 @@ static int dw_i2s_hw_params(struct snd_p
18421 case TWO_CHANNEL_SUPPORT:
18424 - dev_err(dev->dev, "channel not supported\n");
18425 + dev_err(dev->dev, "channel count %d not supported\n", config->chan_nr);
18429 dw_i2s_config(dev, substream->stream);
18431 - i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
18433 config->sample_rate = params_rate(params);
18435 if (dev->capability & DW_I2S_MASTER) {
18436 + u32 frame_length = config->data_width * 2;
18438 + if (dev->bclk_ratio)
18439 + frame_length = dev->bclk_ratio;
18441 + switch (frame_length) {
18458 if (dev->i2s_clk_cfg) {
18459 ret = dev->i2s_clk_cfg(config);
18461 @@ -332,8 +424,7 @@ static int dw_i2s_hw_params(struct snd_p
18465 - u32 bitclk = config->sample_rate *
18466 - config->data_width * 2;
18467 + u32 bitclk = config->sample_rate * frame_length;
18469 ret = clk_set_rate(dev->clk, bitclk);
18471 @@ -342,6 +433,8 @@ static int dw_i2s_hw_params(struct snd_p
18476 + i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
18480 @@ -373,9 +466,12 @@ static int dw_i2s_trigger(struct snd_pcm
18481 i2s_start(dev, substream);
18484 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
18486 + i2s_pause(dev, substream);
18488 case SNDRV_PCM_TRIGGER_STOP:
18489 case SNDRV_PCM_TRIGGER_SUSPEND:
18490 - case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
18492 i2s_stop(dev, substream);
18494 @@ -459,6 +555,18 @@ static int dw_i2s_set_tdm_slot(struct sn
18498 +static int dw_i2s_set_bclk_ratio(struct snd_soc_dai *cpu_dai,
18499 + unsigned int ratio)
18501 + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
18503 + dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio);
18505 + dev->bclk_ratio = ratio;
18510 static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
18512 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
18513 @@ -470,11 +578,13 @@ static int dw_i2s_dai_probe(struct snd_s
18514 static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
18515 .probe = dw_i2s_dai_probe,
18516 .startup = dw_i2s_startup,
18517 + .shutdown = dw_i2s_shutdown,
18518 .hw_params = dw_i2s_hw_params,
18519 .prepare = dw_i2s_prepare,
18520 .trigger = dw_i2s_trigger,
18521 .set_fmt = dw_i2s_set_fmt,
18522 .set_tdm_slot = dw_i2s_set_tdm_slot,
18523 + .set_bclk_ratio = dw_i2s_set_bclk_ratio,
18527 @@ -605,7 +715,7 @@ static int dw_configure_dai(struct dw_i2
18529 dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
18530 dw_i2s_dai->playback.channels_max =
18531 - 1 << (COMP1_TX_CHANNELS(comp1) + 1);
18532 + 2 * (COMP1_TX_CHANNELS(comp1) + 1);
18533 dw_i2s_dai->playback.formats = formats[idx];
18534 dw_i2s_dai->playback.rates = rates;
18536 @@ -619,7 +729,7 @@ static int dw_configure_dai(struct dw_i2
18538 dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
18539 dw_i2s_dai->capture.channels_max =
18540 - 1 << (COMP1_RX_CHANNELS(comp1) + 1);
18541 + 2 * (COMP1_RX_CHANNELS(comp1) + 1);
18542 dw_i2s_dai->capture.formats = formats[idx];
18543 dw_i2s_dai->capture.rates = rates;
18545 @@ -701,7 +811,7 @@ static int dw_configure_dai_by_dt(struct
18549 - ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000);
18550 + ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_384000);
18554 @@ -967,6 +1077,7 @@ static int dw_i2s_probe(struct platform_
18558 + dev->bclk_ratio = 0;
18559 dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
18560 dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
18562 --- a/sound/soc/dwc/local.h
18563 +++ b/sound/soc/dwc/local.h
18565 #define TER_TXSLOT_SHIFT 8
18566 #define TER_TXCHEN BIT(0)
18568 +#define DMACR_DMAEN_TX BIT(17)
18569 +#define DMACR_DMAEN_RX BIT(16)
18570 +#define DMACR_DMAEN_TXCH3 BIT(11)
18571 +#define DMACR_DMAEN_TXCH2 BIT(10)
18572 +#define DMACR_DMAEN_TXCH1 BIT(9)
18573 +#define DMACR_DMAEN_TXCH0 BIT(8)
18574 +#define DMACR_DMAEN_RXCH3 BIT(3)
18575 +#define DMACR_DMAEN_RXCH2 BIT(2)
18576 +#define DMACR_DMAEN_RXCH1 BIT(1)
18577 +#define DMACR_DMAEN_RXCH0 BIT(0)
18579 /* I2SCOMPRegisters */
18580 #define I2S_COMP_PARAM_2 0x01F0
18581 #define I2S_COMP_PARAM_1 0x01F4
18582 @@ -117,6 +128,7 @@ struct dw_i2s_dev {
18583 unsigned int quirks;
18584 unsigned int i2s_reg_comp1;
18585 unsigned int i2s_reg_comp2;
18586 + unsigned int bclk_ratio;
18587 struct device *dev;
18589 u32 xfer_resolution;
18590 --- a/sound/soc/soc-core.c
18591 +++ b/sound/soc/soc-core.c
18592 @@ -1434,7 +1434,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
18595 for_each_rtd_codec_dais(rtd, i, codec_dai) {
18596 - ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
18597 + unsigned int codec_dai_fmt = dai_fmt;
18599 + // there can only be one master when using multiple codecs
18600 + if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) {
18601 + codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
18602 + codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
18605 + ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
18606 if (ret != 0 && ret != -ENOTSUPP)
18609 --- a/sound/usb/card.c
18610 +++ b/sound/usb/card.c
18611 @@ -869,8 +869,14 @@ static int usb_audio_probe(struct usb_in
18612 if (ignore_ctl_error)
18613 chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR;
18615 - if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
18616 + if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) {
18618 + * Grab the interface, because on a webcam uvcvideo may race
18619 + * with snd-usb-audio during probe and re-enable autosuspend.
18621 + usb_autopm_get_interface(intf);
18622 usb_disable_autosuspend(interface_to_usbdev(intf));
18626 * For devices with more than one control interface, we assume the
18627 --- a/sound/usb/quirks.c
18628 +++ b/sound/usb/quirks.c
18629 @@ -2358,6 +2358,8 @@ static const struct usb_audio_quirk_flag
18630 QUIRK_FLAG_ALIGN_TRANSFER),
18631 DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
18632 QUIRK_FLAG_ALIGN_TRANSFER),
18633 + DEVICE_FLG(0x09da, 0x2695, /* A4Tech FHD 1080p webcam */
18634 + QUIRK_FLAG_DISABLE_AUTOSUSPEND | QUIRK_FLAG_GET_SAMPLE_RATE),
18636 /* Vendor matches */
18637 VENDOR_FLG(0x045e, /* MS Lifecam */