From 0b170f7acd2ab1ca0771b933493b9241706117b4 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Fri, 23 Oct 2015 14:18:48 +0900 Subject: ASoC: wm8962: set ALC2 as non-volatile register Previously ALC2 register is set as a volatile register, declare it as one of ALC Coefficients register together with other non-volatile registers will cause issue, in case wm8962 has enter suspend mode, and cache_only flag is set, any attempt to read from ALC2 will fail. Because the 5 status bits in ALC2 aren't used anywhere nor are useful to end user, so this patch removes ALC2 register from volatile register list to make ALC2 be possible to be accessed when cache_only flag is set. Signed-off-by: Jiada Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index b4eb975da981..2976200abb3a 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -131,7 +131,7 @@ static const struct reg_default wm8962_reg[] = { { 15, 0x6243 }, /* R15 - Software Reset */ { 17, 0x007B }, /* R17 - ALC1 */ - + { 18, 0x0000 }, /* R18 - ALC2 */ { 19, 0x1C32 }, /* R19 - ALC3 */ { 20, 0x3200 }, /* R20 - Noise Gate */ { 21, 0x00C0 }, /* R21 - Left ADC volume */ @@ -794,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg) case WM8962_CLOCKING1: case WM8962_CLOCKING2: case WM8962_SOFTWARE_RESET: - case WM8962_ALC2: case WM8962_THERMAL_SHUTDOWN_STATUS: case WM8962_ADDITIONAL_CONTROL_4: case WM8962_DC_SERVO_6: -- cgit v1.2.3 From ea54a37442639cf884918de69db46caf693490f8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 14 Nov 2015 16:54:50 +0900 Subject: ALSA: fireworks: move mutex from function callees to callers Currently, critical section is protected by mutex in functions of fireworks_stream.c. Callers increments/decrements substreams counter before calling the functions. Moving mutex to the callers code allows to change type of the substeram counter from atomic_t to unsigned int. This commit is a preparation for obsoleting usage of atomic_t for substream counter. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks_midi.c | 8 ++++++++ sound/firewire/fireworks/fireworks_pcm.c | 20 ++++++++++++++++---- sound/firewire/fireworks/fireworks_stream.c | 7 ------- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index fba01bbba456..38232dcf6e03 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -17,8 +17,10 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) if (err < 0) goto end; + mutex_lock(&efw->mutex); atomic_inc(&efw->capture_substreams); err = snd_efw_stream_start_duplex(efw, 0); + mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); @@ -35,8 +37,10 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) if (err < 0) goto end; + mutex_lock(&efw->mutex); atomic_inc(&efw->playback_substreams); err = snd_efw_stream_start_duplex(efw, 0); + mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); end: @@ -47,8 +51,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; + mutex_lock(&efw->mutex); atomic_dec(&efw->capture_substreams); snd_efw_stream_stop_duplex(efw); + mutex_unlock(&efw->mutex); snd_efw_stream_lock_release(efw); return 0; @@ -58,8 +64,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; + mutex_lock(&efw->mutex); atomic_dec(&efw->playback_substreams); snd_efw_stream_stop_duplex(efw); + mutex_unlock(&efw->mutex); snd_efw_stream_lock_release(efw); return 0; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index d27135bac513..69f15a6d6f88 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -251,8 +251,11 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); atomic_inc(&efw->capture_substreams); + mutex_unlock(&efw->mutex); + } amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params)); @@ -269,8 +272,11 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); atomic_inc(&efw->playback_substreams); + mutex_unlock(&efw->mutex); + } amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params)); @@ -281,8 +287,11 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); atomic_dec(&efw->capture_substreams); + mutex_unlock(&efw->mutex); + } snd_efw_stream_stop_duplex(efw); @@ -292,8 +301,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); atomic_dec(&efw->playback_substreams); + mutex_unlock(&efw->mutex); + } snd_efw_stream_stop_duplex(efw); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 759f6e3ed44a..69307452dee7 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -214,8 +214,6 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) unsigned int curr_rate; int err = 0; - mutex_lock(&efw->mutex); - /* Need no substreams */ if ((atomic_read(&efw->playback_substreams) == 0) && (atomic_read(&efw->capture_substreams) == 0)) @@ -286,7 +284,6 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) } } end: - mutex_unlock(&efw->mutex); return err; } @@ -307,16 +304,12 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw) master_substreams = &efw->capture_substreams; } - mutex_lock(&efw->mutex); - if (atomic_read(slave_substreams) == 0) { stop_stream(efw, slave); if (atomic_read(master_substreams) == 0) stop_stream(efw, master); } - - mutex_unlock(&efw->mutex); } void snd_efw_stream_update_duplex(struct snd_efw *efw) -- cgit v1.2.3 From 4d2c50a0a9ca75fcd0fd57947fb7b394932e482a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 14 Nov 2015 16:54:51 +0900 Subject: ALSA: fireworks: change type of substream counter from atomic_t to unsigned int The counter is incremented/decremented in critical section protected with mutex. Therefore, no need to use atomic_t. This commit changes the type to unsigned int. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.h | 4 ++-- sound/firewire/fireworks/fireworks_midi.c | 8 ++++---- sound/firewire/fireworks/fireworks_pcm.c | 8 ++++---- sound/firewire/fireworks/fireworks_stream.c | 25 ++++++++++++------------- 4 files changed, 22 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index c7cb7deafe48..96c4e0c6a9bd 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -86,8 +86,8 @@ struct snd_efw { struct amdtp_stream rx_stream; struct cmp_connection out_conn; struct cmp_connection in_conn; - atomic_t capture_substreams; - atomic_t playback_substreams; + unsigned int capture_substreams; + unsigned int playback_substreams; /* hardware metering parameters */ unsigned int phys_out; diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 38232dcf6e03..3e8c4cf9fe1e 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) goto end; mutex_lock(&efw->mutex); - atomic_inc(&efw->capture_substreams); + efw->capture_substreams++; err = snd_efw_stream_start_duplex(efw, 0); mutex_unlock(&efw->mutex); if (err < 0) @@ -38,7 +38,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) goto end; mutex_lock(&efw->mutex); - atomic_inc(&efw->playback_substreams); + efw->playback_substreams++; err = snd_efw_stream_start_duplex(efw, 0); mutex_unlock(&efw->mutex); if (err < 0) @@ -52,7 +52,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) struct snd_efw *efw = substream->rmidi->private_data; mutex_lock(&efw->mutex); - atomic_dec(&efw->capture_substreams); + efw->capture_substreams--; snd_efw_stream_stop_duplex(efw); mutex_unlock(&efw->mutex); @@ -65,7 +65,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) struct snd_efw *efw = substream->rmidi->private_data; mutex_lock(&efw->mutex); - atomic_dec(&efw->playback_substreams); + efw->playback_substreams--; snd_efw_stream_stop_duplex(efw); mutex_unlock(&efw->mutex); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 69f15a6d6f88..f4fbf75ed198 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -253,7 +253,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - atomic_inc(&efw->capture_substreams); + efw->capture_substreams++; mutex_unlock(&efw->mutex); } @@ -274,7 +274,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - atomic_inc(&efw->playback_substreams); + efw->playback_substreams++; mutex_unlock(&efw->mutex); } @@ -289,7 +289,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - atomic_dec(&efw->capture_substreams); + efw->capture_substreams--; mutex_unlock(&efw->mutex); } @@ -303,7 +303,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - atomic_dec(&efw->playback_substreams); + efw->playback_substreams--; mutex_unlock(&efw->mutex); } diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 69307452dee7..968a40a1beb2 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -209,14 +209,13 @@ end: int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) { struct amdtp_stream *master, *slave; - atomic_t *slave_substreams; + unsigned int slave_substreams; enum cip_flags sync_mode; unsigned int curr_rate; int err = 0; /* Need no substreams */ - if ((atomic_read(&efw->playback_substreams) == 0) && - (atomic_read(&efw->capture_substreams) == 0)) + if (efw->playback_substreams == 0 && efw->capture_substreams == 0) goto end; err = get_sync_mode(efw, &sync_mode); @@ -225,11 +224,11 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) if (sync_mode == CIP_SYNC_TO_DEVICE) { master = &efw->tx_stream; slave = &efw->rx_stream; - slave_substreams = &efw->playback_substreams; + slave_substreams = efw->playback_substreams; } else { master = &efw->rx_stream; slave = &efw->tx_stream; - slave_substreams = &efw->capture_substreams; + slave_substreams = efw->capture_substreams; } /* @@ -275,7 +274,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) } /* start slave if needed */ - if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { + if (slave_substreams > 0 && !amdtp_stream_running(slave)) { err = start_stream(efw, slave, rate); if (err < 0) { dev_err(&efw->unit->device, @@ -290,24 +289,24 @@ end: void snd_efw_stream_stop_duplex(struct snd_efw *efw) { struct amdtp_stream *master, *slave; - atomic_t *master_substreams, *slave_substreams; + unsigned int master_substreams, slave_substreams; if (efw->master == &efw->rx_stream) { slave = &efw->tx_stream; master = &efw->rx_stream; - slave_substreams = &efw->capture_substreams; - master_substreams = &efw->playback_substreams; + slave_substreams = efw->capture_substreams; + master_substreams = efw->playback_substreams; } else { slave = &efw->rx_stream; master = &efw->tx_stream; - slave_substreams = &efw->playback_substreams; - master_substreams = &efw->capture_substreams; + slave_substreams = efw->playback_substreams; + master_substreams = efw->capture_substreams; } - if (atomic_read(slave_substreams) == 0) { + if (slave_substreams == 0) { stop_stream(efw, slave); - if (atomic_read(master_substreams) == 0) + if (master_substreams == 0) stop_stream(efw, master); } } -- cgit v1.2.3 From 3c7a09358729e64119669f454fb1ac3c5cd20b63 Mon Sep 17 00:00:00 2001 From: Cheah Kok Cheong Date: Sun, 15 Nov 2015 05:31:30 +0800 Subject: ALSA: ua101: replace le16_to_cpu() with usb_endpoint_maxp() Commit 939f325f4a0f ("usb: add usb_endpoint_maxp() macro") and commit 29cc88979a88 ("USB: use usb_endpoint_maxp() instead of le16_to_cpu()") introduced a new helper macro. This trivial patch convert remaining users found in ua101 driver. Signed-off-by: Cheah Kok Cheong Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/misc/ua101.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 9581089c28c5..c19a5dd05631 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -1037,7 +1037,7 @@ static int detect_usb_format(struct ua101 *ua) return -ENXIO; } ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); - ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + ua->capture.max_packet_bytes = usb_endpoint_maxp(epd); epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; if (!usb_endpoint_is_isoc_out(epd)) { @@ -1045,7 +1045,7 @@ static int detect_usb_format(struct ua101 *ua) return -ENXIO; } ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); - ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + ua->playback.max_packet_bytes = usb_endpoint_maxp(epd); return 0; } -- cgit v1.2.3 From bef3c4ef7e05cada90b5aba2ca75a29441da9532 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 3 Nov 2015 15:05:50 +0000 Subject: ASoC: wm8998: Remove duplicated consts The SOC_xxx_DECL() macros already include 'const' so there's no need to put a const in the source where they are used. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm8998.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 8782dfb628ab..7719bc509e50 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -199,20 +199,20 @@ static const char * const wm8998_inmux_texts[] = { "B", }; -static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum, - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum, + ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_IN1L_SRC_SHIFT, + wm8998_inmux_texts); -static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum, + ARIZONA_ADC_DIGITAL_VOLUME_1R, + ARIZONA_IN1R_SRC_SHIFT, + wm8998_inmux_texts); -static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum, + ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_IN2L_SRC_SHIFT, + wm8998_inmux_texts); static const struct snd_kcontrol_new wm8998_in1mux[2] = { SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum, @@ -522,17 +522,17 @@ static const unsigned int wm8998_aec_loopback_values[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, }; -static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback, - ARIZONA_DAC_AEC_CONTROL_1, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, - wm8998_aec_loopback_texts, - wm8998_aec_loopback_values); - -static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback, - ARIZONA_DAC_AEC_CONTROL_2, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, - wm8998_aec_loopback_texts, - wm8998_aec_loopback_values); +static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback, + ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + wm8998_aec_loopback_texts, + wm8998_aec_loopback_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback, + ARIZONA_DAC_AEC_CONTROL_2, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + wm8998_aec_loopback_texts, + wm8998_aec_loopback_values); static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = { SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback), -- cgit v1.2.3 From 6610550c4c2663f51cec308a88870da20db48113 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 3 Nov 2015 15:08:35 +0000 Subject: ASoC: cs47l24: Add driver for Cirrus Logic CS47L24 and WM1831 codecs This patch adds support for the Cirrus Logic CS47L24 and WM1831 codecs. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs47l24.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs47l24.h | 23 + 4 files changed, 1181 insertions(+) create mode 100644 sound/soc/codecs/cs47l24.c create mode 100644 sound/soc/codecs/cs47l24.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..55e14a3ed5e1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -55,6 +55,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CS4349 if I2C + select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI select SND_SOC_DA7213 if I2C @@ -195,10 +196,12 @@ config SND_SOC_88PM860X config SND_SOC_ARIZONA tristate + default y if SND_SOC_CS47L24=y default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM8997=y default y if SND_SOC_WM8998=y + default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM8997=m @@ -211,9 +214,11 @@ config SND_SOC_WM_HUBS config SND_SOC_WM_ADSP tristate + default y if SND_SOC_CS47L24=y default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM2200=y + default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM2200=m @@ -422,6 +427,9 @@ config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" depends on I2C +config SND_SOC_CS47L24 + tristate + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..c1d73fe4cf6b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -47,6 +47,7 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs4349-objs := cs4349.o +snd-soc-cs47l24-objs := cs47l24.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o @@ -242,6 +243,7 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o +obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c new file mode 100644 index 000000000000..dc5ae7f7a1bd --- /dev/null +++ b/sound/soc/codecs/cs47l24.c @@ -0,0 +1,1148 @@ +/* + * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24 + * + * Copyright 2015 Cirrus Logic Inc. + * + * Author: Richard Fitzgerald + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "arizona.h" +#include "wm_adsp.h" +#include "cs47l24.h" + +struct cs47l24_priv { + struct arizona_priv core; + struct arizona_fll fll[2]; +}; + +static const struct wm_adsp_region cs47l24_dsp2_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x200000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x280000 }, + { .type = WMFW_ADSP2_XM, .base = 0x290000 }, + { .type = WMFW_ADSP2_YM, .base = 0x2a8000 }, +}; + +static const struct wm_adsp_region cs47l24_dsp3_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x300000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x380000 }, + { .type = WMFW_ADSP2_XM, .base = 0x390000 }, + { .type = WMFW_ADSP2_YM, .base = 0x3a8000 }, +}; + +static const struct wm_adsp_region *cs47l24_dsp_regions[] = { + cs47l24_dsp2_regions, + cs47l24_dsp3_regions, +}; + +static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); +static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); +static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); + +#define CS47L24_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG SPKOUT Switch", base, 6, 1, 0) + +static const struct snd_kcontrol_new cs47l24_snd_controls[] = { +SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]), + +SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL, + ARIZONA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL, + ARIZONA_IN2R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, + ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R, + ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), + +SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), +SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), + +ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), + +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, + 24, 0, eq_tlv), + +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, + 24, 0, eq_tlv), + +ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5, + ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5, + ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA), + +ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), + +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), + +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), +SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), +SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), +SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), +SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), + +ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR, + ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv), + +ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL, + ARIZONA_HP1_SC_ENA_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L, + ARIZONA_OUT4L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L, + ARIZONA_OUT4L_VOL_SHIFT, + 0xbf, 0, digital_tlv), + +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL, + ARIZONA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, + ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), +SOC_ENUM("Noise Gate Hold", arizona_ng_hold), + +CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), +CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), +CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L), + +ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), + +ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE), + +ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), +}; + +ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE); + +static const char * const cs47l24_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "SPKOUT", +}; + +static const unsigned int cs47l24_aec_loopback_values[] = { + 0, 1, 6, +}; + +static const struct soc_enum cs47l24_aec_loopback = + SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l24_aec_loopback_texts), + cs47l24_aec_loopback_texts, + cs47l24_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l24_aec_loopback_mux = + SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback); + +static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, + ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, + ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, + ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_INPUT("IN1L"), +SND_SOC_DAPM_INPUT("IN1R"), +SND_SOC_DAPM_INPUT("IN2L"), +SND_SOC_DAPM_INPUT("IN2R"), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, + ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, + ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, + ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1, + ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1, + ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, + NULL, 0), + +WM_ADSP2("DSP2", 1), +WM_ADSP2("DSP3", 2), + +SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, + &cs47l24_aec_loopback_mux), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"), +ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"), + +ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"), +ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"), +ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"), +ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"), +ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"), +ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"), +ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"), +ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"), + +ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"), + +ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), +ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), +ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), + +ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), + +ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), + +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), + +ARIZONA_DSP_WIDGETS(DSP2, "DSP2"), +ARIZONA_DSP_WIDGETS(DSP3, "DSP3"), + +ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), +ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"), +ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), +ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"), +ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"), + +ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), +ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"), +ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), +ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"), +ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"), + +ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"), +ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"), +ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"), +ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"), +ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"), +ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"), +ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"), + +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("SPKOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTP"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define ARIZONA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC", "AEC Loopback" }, \ + { name, "IN1L", "IN1L PGA" }, \ + { name, "IN1R", "IN1R PGA" }, \ + { name, "IN2L", "IN2L PGA" }, \ + { name, "IN2R", "IN2R PGA" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF1RX7", "AIF1RX7" }, \ + { name, "AIF1RX8", "AIF1RX8" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ASRC1L", "ASRC1L" }, \ + { name, "ASRC1R", "ASRC1R" }, \ + { name, "ASRC2L", "ASRC2L" }, \ + { name, "ASRC2R", "ASRC2R" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1DEC3", "ISRC1DEC3" }, \ + { name, "ISRC1DEC4", "ISRC1DEC4" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC1INT3", "ISRC1INT3" }, \ + { name, "ISRC1INT4", "ISRC1INT4" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2DEC3", "ISRC2DEC3" }, \ + { name, "ISRC2DEC4", "ISRC2DEC4" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "ISRC2INT3", "ISRC2INT3" }, \ + { name, "ISRC2INT4", "ISRC2INT4" }, \ + { name, "ISRC3DEC1", "ISRC3DEC1" }, \ + { name, "ISRC3DEC2", "ISRC3DEC2" }, \ + { name, "ISRC3DEC3", "ISRC3DEC3" }, \ + { name, "ISRC3DEC4", "ISRC3DEC4" }, \ + { name, "ISRC3INT1", "ISRC3INT1" }, \ + { name, "ISRC3INT2", "ISRC3INT2" }, \ + { name, "ISRC3INT3", "ISRC3INT3" }, \ + { name, "ISRC3INT4", "ISRC3INT4" }, \ + { name, "DSP2.1", "DSP2" }, \ + { name, "DSP2.2", "DSP2" }, \ + { name, "DSP2.3", "DSP2" }, \ + { name, "DSP2.4", "DSP2" }, \ + { name, "DSP2.5", "DSP2" }, \ + { name, "DSP2.6", "DSP2" }, \ + { name, "DSP3.1", "DSP3" }, \ + { name, "DSP3.2", "DSP3" }, \ + { name, "DSP3.3", "DSP3" }, \ + { name, "DSP3.4", "DSP3" }, \ + { name, "DSP3.5", "DSP3" }, \ + { name, "DSP3.6", "DSP3" } + +static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { + { "OUT1L", NULL, "CPVDD" }, + { "OUT1R", NULL, "CPVDD" }, + + { "OUT4L", NULL, "SPKVDD" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT4L", NULL, "SYSCLK" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + { "MICBIAS2", NULL, "MICVDD" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + { "AIF1 Capture", NULL, "AIF1TX7" }, + { "AIF1 Capture", NULL, "AIF1TX8" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + { "AIF1RX7", NULL, "AIF1 Playback" }, + { "AIF1RX8", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + + { "IN1L PGA", NULL, "IN1L" }, + { "IN1R PGA", NULL, "IN1R" }, + + { "IN2L PGA", NULL, "IN2L" }, + { "IN2R PGA", NULL, "IN2R" }, + + ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + + ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"), + + ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), + ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), + + ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), + + ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + + ARIZONA_MIXER_ROUTES("EQ1", "EQ1"), + ARIZONA_MIXER_ROUTES("EQ2", "EQ2"), + + ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"), + ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"), + ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"), + ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"), + + ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"), + ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"), + ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), + ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), + + ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), + + ARIZONA_DSP_ROUTES("DSP2"), + ARIZONA_DSP_ROUTES("DSP3"), + + ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"), + ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"), + + ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"), + ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"), + + ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"), + ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"), + + ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"), + ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"), + + ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"), + ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"), + ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"), + ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"), + + ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"), + ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"), + ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"), + ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"), + + { "AEC Loopback", "HPOUT1L", "OUT1L" }, + { "AEC Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1L", NULL, "OUT1L" }, + { "HPOUT1R", NULL, "OUT1R" }, + + { "AEC Loopback", "SPKOUT", "OUT4L" }, + { "SPKOUTN", NULL, "OUT4L" }, + { "SPKOUTP", NULL, "OUT4L" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1L" }, + { "DRC1 Signal Activity", NULL, "DRC1R" }, + { "DRC2 Signal Activity", NULL, "DRC2L" }, + { "DRC2 Signal Activity", NULL, "DRC2R" }, +}; + +static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source, + unsigned int Fref, unsigned int Fout) +{ + struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec); + + switch (fll_id) { + case CS47L24_FLL1: + return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout); + case CS47L24_FLL2: + return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout); + case CS47L24_FLL1_REFCLK: + return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref, + Fout); + case CS47L24_FLL2_REFCLK: + return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref, + Fout); + default: + return -EINVAL; + } +} + +#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000 + +#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver cs47l24_dai[] = { + { + .name = "cs47l24-aif1", + .id = 1, + .base = ARIZONA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l24-aif2", + .id = 2, + .base = ARIZONA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 6, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 6, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l24-aif3", + .id = 3, + .base = ARIZONA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, +}; + +static int cs47l24_codec_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + priv->core.arizona->dapm = dapm; + + arizona_init_spk(codec); + arizona_init_gpio(codec); + arizona_init_mono(codec); + + ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec); + if (ret) + goto err_adsp2_codec_probe; + + ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec); + if (ret) + goto err_adsp2_codec_probe; + + ret = snd_soc_add_codec_controls(codec, + &arizona_adsp2_rate_controls[1], 2); + if (ret) + goto err_adsp2_codec_probe; + + snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + + return 0; + +err_adsp2_codec_probe: + wm_adsp2_codec_remove(&priv->core.adsp[1], codec); + wm_adsp2_codec_remove(&priv->core.adsp[2], codec); + + return ret; +} + +static int cs47l24_codec_remove(struct snd_soc_codec *codec) +{ + struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + + + wm_adsp2_codec_remove(&priv->core.adsp[1], codec); + wm_adsp2_codec_remove(&priv->core.adsp[2], codec); + + priv->core.arizona->dapm = NULL; + + return 0; +} + +#define CS47L24_DIG_VU 0x0200 + +static unsigned int cs47l24_digital_vu[] = { + ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, + ARIZONA_DAC_DIGITAL_VOLUME_4L, +}; + +static struct regmap *cs47l24_get_regmap(struct device *dev) +{ + struct cs47l24_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { + .probe = cs47l24_codec_probe, + .remove = cs47l24_codec_remove, + .get_regmap = cs47l24_get_regmap, + + .idle_bias_off = true, + + .set_sysclk = arizona_set_sysclk, + .set_pll = cs47l24_set_fll, + + .controls = cs47l24_snd_controls, + .num_controls = ARRAY_SIZE(cs47l24_snd_controls), + .dapm_widgets = cs47l24_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets), + .dapm_routes = cs47l24_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), +}; + +static int cs47l24_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct cs47l24_priv *cs47l24; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI); + + cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv), + GFP_KERNEL); + if (!cs47l24) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l24); + + cs47l24->core.arizona = arizona; + cs47l24->core.num_inputs = 4; + + for (i = 1; i <= 2; i++) { + cs47l24->core.adsp[i].part = "cs47l24"; + cs47l24->core.adsp[i].num = i + 1; + cs47l24->core.adsp[i].type = WMFW_ADSP2; + cs47l24->core.adsp[i].dev = arizona->dev; + cs47l24->core.adsp[i].regmap = arizona->regmap; + + cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 + + (0x100 * i); + cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1]; + cs47l24->core.adsp[i].num_mems = + ARRAY_SIZE(cs47l24_dsp2_regions); + + ret = wm_adsp2_init(&cs47l24->core.adsp[i]); + if (ret != 0) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++) + cs47l24->fll[i].vco_mult = 3; + + arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1, + ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK, + &cs47l24->fll[0]); + arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1, + ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, + &cs47l24->fll[1]); + + /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, + ARIZONA_SAMPLE_RATE_2_MASK, 0x11); + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, + ARIZONA_SAMPLE_RATE_3_MASK, 0x12); + + for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++) + arizona_init_dai(&cs47l24->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++) + regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i], + CS47L24_DIG_VU, CS47L24_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, + cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); +} + +static int cs47l24_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver cs47l24_codec_driver = { + .driver = { + .name = "cs47l24-codec", + }, + .probe = cs47l24_probe, + .remove = cs47l24_remove, +}; + +module_platform_driver(cs47l24_codec_driver); + +MODULE_DESCRIPTION("ASoC CS47L24 driver"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l24-codec"); diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h new file mode 100644 index 000000000000..77ab2b77b2e6 --- /dev/null +++ b/sound/soc/codecs/cs47l24.h @@ -0,0 +1,23 @@ +/* + * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24 + * + * Copyright 2015 Cirrus Logic Inc. + * + * Author: Richard Fitzgerald + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _CS47L24_H +#define _CS47L24_H + +#include "arizona.h" + +#define CS47L24_FLL1 1 +#define CS47L24_FLL2 2 +#define CS47L24_FLL1_REFCLK 3 +#define CS47L24_FLL2_REFCLK 4 + +#endif -- cgit v1.2.3 From a737447d080929c54c664adc9c62eadab9e86d3e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 Oct 2015 14:28:33 +0800 Subject: ASoC: da7219: Use logical instead of bitwise OR for boolean expression Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index f238c1e8a69c..e36a7b79b494 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1306,7 +1306,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, } channels = params_channels(params); - if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) { + if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) { dev_err(codec->dev, "Invalid number of channels, only 1 to %d supported\n", DA7219_DAI_CH_NUM_MAX); -- cgit v1.2.3 From 800cff79d7ab55c5ac4b7cef3e8d6d4a23a838d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Oct 2015 16:40:18 +0100 Subject: ASoC: Fix typo in kernel doc comment for snd_soc_put_volsw_sx() Spotted by kbuild bot: sound/soc/soc-ops.c:415: warning: No description found for parameter 'ucontrol' sound/soc/soc-ops.c:415: warning: Excess function parameter 'uinfo' description in 'snd_soc_put_volsw_sx' Reported-by: kbuild test robot Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index ecd38e52285a..2f67ba6d7a8f 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); /** * snd_soc_put_volsw_sx - double mixer set callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a double mixer control that spans 2 registers. * -- cgit v1.2.3 From 95f444dc9371a3910179a9621c8b94f0f60f5f04 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Wed, 28 Oct 2015 10:15:34 +0800 Subject: ASoC: dpcm: Make BE prepare possible in suspend state During suspend/resume, there is a flow that if a driver does not support SNDRV_PCM_INFO_RESUME, it will fail at snd_pcm_resume(), and user space can then issue SNDRV_PCM_IOCTL_PREPARE to let audio continue to play. However, in dpcm_be_dai_prepare() it only allows BEs to be prepared in state SND_SOC_DPCM_STATE_HW_PARAMS or SND_SOC_DPCM_STATE_STOP. The BE state will then stay in SND_SOC_DPCM_STATE_SUSPEND, consequently dpcm_be_dai_shutdown() is skipped in the end of playback and be_substream->runtime is not cleared while this runtime is actually freed by snd_pcm_detach_substream(). If another suspend comes, a NULL pointer dereference will happen in snd_pcm_suspend() when accessing BE substream's runtime. Signed-off-by: Koro Chen Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96e8986..c48232211c56 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2115,7 +2115,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) continue; if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; dev_dbg(be->dev, "ASoC: prepare BE %s\n", -- cgit v1.2.3 From 8973112aa41b8ad956a5b47f2fe17bc2a5cf2645 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 26 Oct 2015 15:19:02 +0800 Subject: ASoC: fsl_esai: ETDR and TX0~5 registers are non volatile ETDR and TX0~5 registers are writable and not readable. So they are non volatile. Remove them from volatile list, and add default register value for them. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 59f234e51971..504e7318f225 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -653,21 +653,28 @@ static const struct snd_soc_component_driver fsl_esai_component = { }; static const struct reg_default fsl_esai_reg_defaults[] = { - {0x8, 0x00000000}, - {0x10, 0x00000000}, - {0x18, 0x00000000}, - {0x98, 0x00000000}, - {0xd0, 0x00000000}, - {0xd4, 0x00000000}, - {0xd8, 0x00000000}, - {0xdc, 0x00000000}, - {0xe0, 0x00000000}, - {0xe4, 0x0000ffff}, - {0xe8, 0x0000ffff}, - {0xec, 0x0000ffff}, - {0xf0, 0x0000ffff}, - {0xf8, 0x00000000}, - {0xfc, 0x00000000}, + {REG_ESAI_ETDR, 0x00000000}, + {REG_ESAI_ECR, 0x00000000}, + {REG_ESAI_TFCR, 0x00000000}, + {REG_ESAI_RFCR, 0x00000000}, + {REG_ESAI_TX0, 0x00000000}, + {REG_ESAI_TX1, 0x00000000}, + {REG_ESAI_TX2, 0x00000000}, + {REG_ESAI_TX3, 0x00000000}, + {REG_ESAI_TX4, 0x00000000}, + {REG_ESAI_TX5, 0x00000000}, + {REG_ESAI_TSR, 0x00000000}, + {REG_ESAI_SAICR, 0x00000000}, + {REG_ESAI_TCR, 0x00000000}, + {REG_ESAI_TCCR, 0x00000000}, + {REG_ESAI_RCR, 0x00000000}, + {REG_ESAI_RCCR, 0x00000000}, + {REG_ESAI_TSMA, 0x0000ffff}, + {REG_ESAI_TSMB, 0x0000ffff}, + {REG_ESAI_RSMA, 0x0000ffff}, + {REG_ESAI_RSMB, 0x0000ffff}, + {REG_ESAI_PRRC, 0x00000000}, + {REG_ESAI_PCRC, 0x00000000}, }; static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg) @@ -705,17 +712,10 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg) static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case REG_ESAI_ETDR: case REG_ESAI_ERDR: case REG_ESAI_ESR: case REG_ESAI_TFSR: case REG_ESAI_RFSR: - case REG_ESAI_TX0: - case REG_ESAI_TX1: - case REG_ESAI_TX2: - case REG_ESAI_TX3: - case REG_ESAI_TX4: - case REG_ESAI_TX5: case REG_ESAI_RX0: case REG_ESAI_RX1: case REG_ESAI_RX2: -- cgit v1.2.3 From 3f6f5b0cb3e3dc8fdd4eb826f30257df423b37cb Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 26 Oct 2015 15:19:03 +0800 Subject: ASoC: fsl-sai: add default register map for regmap cache FSL_SAI_TDR register is writable and not readable. According to regmap_volatile() function, if FSL_SAI_TDR want to be volatile, it should be readable. So we should remove FSL_SAI_TDR from volatile register list. If the flat cache don't have default register map, when do regcache_sync operation, the non volatile and writable registers will be synchronised to 0. FSL_SAI_TDR reigster will be written a 0 and cause channel swap. So add default register map for flat cache, and such register will not be written. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a4435f5e3be9..987fc5478abd 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -608,6 +608,22 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", }; +static struct reg_default fsl_sai_reg_defaults[] = { + {FSL_SAI_TCR1, 0}, + {FSL_SAI_TCR2, 0}, + {FSL_SAI_TCR3, 0}, + {FSL_SAI_TCR4, 0}, + {FSL_SAI_TCR5, 0}, + {FSL_SAI_TDR, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1, 0}, + {FSL_SAI_RCR2, 0}, + {FSL_SAI_RCR3, 0}, + {FSL_SAI_RCR4, 0}, + {FSL_SAI_RCR5, 0}, + {FSL_SAI_RMR, 0}, +}; + static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -641,13 +657,11 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) case FSL_SAI_RCSR: case FSL_SAI_TFR: case FSL_SAI_RFR: - case FSL_SAI_TDR: case FSL_SAI_RDR: return true; default: return false; } - } static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) @@ -680,6 +694,8 @@ static const struct regmap_config fsl_sai_regmap_config = { .val_bits = 32, .max_register = FSL_SAI_RMR, + .reg_defaults = fsl_sai_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults), .readable_reg = fsl_sai_readable_reg, .volatile_reg = fsl_sai_volatile_reg, .writeable_reg = fsl_sai_writeable_reg, -- cgit v1.2.3 From 9f1206dc76a726e1c7b0e2583345c29fd1e75286 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 26 Oct 2015 15:19:04 +0800 Subject: ASoC: fsl_spdif: STL and STR registers are non volatile STL and STR registers are writable and not readable. So they are non volatile. Remove them from volatile list, and add default register value for them. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3d59bb6719f2..28a882336904 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1006,12 +1006,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = { /* FSL SPDIF REGMAP */ static const struct reg_default fsl_spdif_reg_defaults[] = { - {0x0, 0x00000400}, - {0x4, 0x00000000}, - {0xc, 0x00000000}, - {0x34, 0x00000000}, - {0x38, 0x00000000}, - {0x50, 0x00020f00}, + {REG_SPDIF_SCR, 0x00000400}, + {REG_SPDIF_SRCD, 0x00000000}, + {REG_SPDIF_SIE, 0x00000000}, + {REG_SPDIF_STL, 0x00000000}, + {REG_SPDIF_STR, 0x00000000}, + {REG_SPDIF_STCSCH, 0x00000000}, + {REG_SPDIF_STCSCL, 0x00000000}, + {REG_SPDIF_STC, 0x00020f00}, }; static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) @@ -1049,8 +1051,6 @@ static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg) case REG_SPDIF_SRCSL: case REG_SPDIF_SRU: case REG_SPDIF_SRQ: - case REG_SPDIF_STL: - case REG_SPDIF_STR: case REG_SPDIF_SRFM: return true; default: -- cgit v1.2.3 From f4faa29e5d134fdff00403936ab10fea7683913e Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 26 Oct 2015 15:19:05 +0800 Subject: ASoC: fsl_ssi: using macro for default register map using macro for default register map Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 95d2392303eb..674abf778715 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -113,17 +113,17 @@ struct fsl_ssi_rxtx_reg_val { }; static const struct reg_default fsl_ssi_reg_defaults[] = { - {0x10, 0x00000000}, - {0x18, 0x00003003}, - {0x1c, 0x00000200}, - {0x20, 0x00000200}, - {0x24, 0x00040000}, - {0x28, 0x00040000}, - {0x38, 0x00000000}, - {0x48, 0x00000000}, - {0x4c, 0x00000000}, - {0x54, 0x00000000}, - {0x58, 0x00000000}, + {CCSR_SSI_SCR, 0x00000000}, + {CCSR_SSI_SIER, 0x00003003}, + {CCSR_SSI_STCR, 0x00000200}, + {CCSR_SSI_SRCR, 0x00000200}, + {CCSR_SSI_STCCR, 0x00040000}, + {CCSR_SSI_SRCCR, 0x00040000}, + {CCSR_SSI_SACNT, 0x00000000}, + {CCSR_SSI_STMSK, 0x00000000}, + {CCSR_SSI_SRMSK, 0x00000000}, + {CCSR_SSI_SACCEN, 0x00000000}, + {CCSR_SSI_SACCDIS, 0x00000000}, }; static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) -- cgit v1.2.3 From 14b947d9ced4f723b5bfd3f6ec614aa28b5d4cfb Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Wed, 4 Nov 2015 14:40:48 +0000 Subject: ASoC: img: Add driver for I2S input controller Add driver for Imagination Technologies I2S input controller Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/img/Kconfig | 12 ++ sound/soc/img/Makefile | 1 + sound/soc/img/img-i2s-in.c | 516 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 531 insertions(+) create mode 100644 sound/soc/img/Kconfig create mode 100644 sound/soc/img/Makefile create mode 100644 sound/soc/img/img-i2s-in.c (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 7ff7d88e46dd..a012b2655e84 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -50,6 +50,7 @@ source "sound/soc/jz4740/Kconfig" source "sound/soc/nuc900/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/kirkwood/Kconfig" +source "sound/soc/img/Kconfig" source "sound/soc/intel/Kconfig" source "sound/soc/mediatek/Kconfig" source "sound/soc/mxs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 8eb06db32fa0..78625fae78d6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC) += davinci/ obj-$(CONFIG_SND_SOC) += dwc/ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += jz4740/ +obj-$(CONFIG_SND_SOC) += img/ obj-$(CONFIG_SND_SOC) += intel/ obj-$(CONFIG_SND_SOC) += mediatek/ obj-$(CONFIG_SND_SOC) += mxs/ diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig new file mode 100644 index 000000000000..f9f73d0323f1 --- /dev/null +++ b/sound/soc/img/Kconfig @@ -0,0 +1,12 @@ +config SND_SOC_IMG + bool "Audio support for Imagination Technologies designs" + help + Audio support for Imagination Technologies audio hardware + +config SND_SOC_IMG_I2S_IN + tristate "Imagination I2S Input Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for I2S in driver for + Imagination Technologies I2S in device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile new file mode 100644 index 000000000000..fe8426b369c2 --- /dev/null +++ b/sound/soc/img/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c new file mode 100644 index 000000000000..0389203f8560 --- /dev/null +++ b/sound/soc/img/img-i2s-in.c @@ -0,0 +1,516 @@ +/* + * IMG I2S input controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define IMG_I2S_IN_RX_FIFO 0x0 + +#define IMG_I2S_IN_CTL 0x4 +#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK 0xfffffffc +#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT 2 +#define IMG_I2S_IN_CTL_16PACK_MASK BIT(1) +#define IMG_I2S_IN_CTL_ME_MASK BIT(0) + +#define IMG_I2S_IN_CH_CTL 0x4 +#define IMG_I2S_IN_CH_CTL_CCDEL_MASK 0x38000 +#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT 15 +#define IMG_I2S_IN_CH_CTL_FEN_MASK BIT(14) +#define IMG_I2S_IN_CH_CTL_FMODE_MASK BIT(13) +#define IMG_I2S_IN_CH_CTL_16PACK_MASK BIT(12) +#define IMG_I2S_IN_CH_CTL_JUST_MASK BIT(10) +#define IMG_I2S_IN_CH_CTL_PACKH_MASK BIT(9) +#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK BIT(8) +#define IMG_I2S_IN_CH_CTL_BLKP_MASK BIT(7) +#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK BIT(6) +#define IMG_I2S_IN_CH_CTL_LRD_MASK BIT(3) +#define IMG_I2S_IN_CH_CTL_FW_MASK BIT(2) +#define IMG_I2S_IN_CH_CTL_SW_MASK BIT(1) +#define IMG_I2S_IN_CH_CTL_ME_MASK BIT(0) + +#define IMG_I2S_IN_CH_STRIDE 0x20 + +struct img_i2s_in { + void __iomem *base; + struct clk *clk_sys; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int max_i2s_chan; + void __iomem *channel_base; + unsigned int active_channels; + struct snd_soc_dai_driver dai_driver; +}; + +static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg) +{ + writel(val, i2s->base + reg); +} + +static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg) +{ + return readl(i2s->base + reg); +} + +static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan, + u32 val, u32 reg) +{ + writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); +} + +static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan, + u32 reg) +{ + return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); +} + +static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); + reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK; + img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); +} + +static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); + reg |= IMG_I2S_IN_CH_CTL_ME_MASK; + img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); +} + +static inline void img_i2s_in_disable(struct img_i2s_in *i2s) +{ + u32 reg; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg &= ~IMG_I2S_IN_CTL_ME_MASK; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); +} + +static inline void img_i2s_in_enable(struct img_i2s_in *i2s) +{ + u32 reg; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg |= IMG_I2S_IN_CTL_ME_MASK; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); +} + +static inline void img_i2s_in_flush(struct img_i2s_in *i2s) +{ + int i; + u32 reg; + + for (i = 0; i < i2s->active_channels; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } +} + +static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + img_i2s_in_enable(i2s); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_i2s_in_disable(i2s); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_i2s_in_check_rate(struct img_i2s_in *i2s, + unsigned int sample_rate, unsigned int frame_size, + unsigned int *bclk_filter_enable, + unsigned int *bclk_filter_value) +{ + unsigned int bclk_freq, cur_freq; + + bclk_freq = sample_rate * frame_size; + + cur_freq = clk_get_rate(i2s->clk_sys); + + if (cur_freq >= bclk_freq * 8) { + *bclk_filter_enable = 1; + *bclk_filter_value = 0; + } else if (cur_freq >= bclk_freq * 7) { + *bclk_filter_enable = 1; + *bclk_filter_value = 1; + } else if (cur_freq >= bclk_freq * 6) { + *bclk_filter_enable = 0; + *bclk_filter_value = 0; + } else { + dev_err(i2s->dev, + "Sys clock rate %u insufficient for sample rate %u\n", + cur_freq, sample_rate); + return -EINVAL; + } + + return 0; +} + +static int img_i2s_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels, i2s_channels, frame_size; + unsigned int bclk_filter_enable, bclk_filter_value; + int i, ret = 0; + u32 reg, control_mask, chan_control_mask; + u32 control_set = 0, chan_control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + i2s_channels = channels / 2; + + switch (format) { + case SNDRV_PCM_FORMAT_S32_LE: + frame_size = 64; + chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK; + break; + case SNDRV_PCM_FORMAT_S24_LE: + frame_size = 64; + chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; + break; + case SNDRV_PCM_FORMAT_S16_LE: + frame_size = 32; + control_set |= IMG_I2S_IN_CTL_16PACK_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK; + break; + default: + return -EINVAL; + } + + if ((channels < 2) || + (channels > (i2s->max_i2s_chan * 2)) || + (channels % 2)) + return -EINVAL; + + control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT); + + ret = img_i2s_in_check_rate(i2s, rate, frame_size, + &bclk_filter_enable, &bclk_filter_value); + if (ret < 0) + return ret; + + if (bclk_filter_enable) + chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK; + + if (bclk_filter_value) + chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK; + + control_mask = IMG_I2S_IN_CTL_16PACK_MASK | + IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK; + + chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK | + IMG_I2S_IN_CH_CTL_FEN_MASK | + IMG_I2S_IN_CH_CTL_FMODE_MASK | + IMG_I2S_IN_CH_CTL_SW_MASK | + IMG_I2S_IN_CH_CTL_FW_MASK | + IMG_I2S_IN_CH_CTL_PACKH_MASK; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_disable(i2s, i); + + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } + + i2s->active_channels = i2s_channels; + + img_i2s_in_flush(i2s); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_enable(i2s, i); + + return 0; +} + +static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + int i; + u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0; + u32 reg; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; + break; + case SND_SOC_DAIFMT_NB_IF: + break; + case SND_SOC_DAIFMT_IB_NF: + lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; + blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + default: + return -EINVAL; + } + + chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_disable(i2s, i); + + /* + * BLKP and LRD must be set during separate register writes + */ + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_enable(i2s, i); + + return 0; +} + +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + +static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data); + + return 0; +} + +static const struct snd_soc_component_driver img_i2s_in_component = { + .name = "img-i2s-in" +}; + +static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st, + struct snd_pcm_hw_params *params, struct dma_slave_config *sc) +{ + unsigned int i2s_channels = params_channels(params) / 2; + struct snd_soc_pcm_runtime *rtd = st->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); + + ret = snd_hwparams_to_dma_slave_config(st, params, sc); + if (ret) + return ret; + + sc->src_addr = dma_data->addr; + sc->src_addr_width = dma_data->addr_width; + sc->src_maxburst = 4 * i2s_channels; + + return 0; +} + +static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = { + .prepare_slave_config = img_i2s_in_dma_prepare_slave_config +}; + +static int img_i2s_in_probe(struct platform_device *pdev) +{ + struct img_i2s_in *i2s; + struct resource *res; + void __iomem *base; + int ret, i; + struct reset_control *rst; + unsigned int max_i2s_chan_pow_2; + struct device *dev = &pdev->dev; + + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s); + + i2s->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + i2s->base = base; + + if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", + &i2s->max_i2s_chan)) { + dev_err(dev, "No img,i2s-channels property\n"); + return -EINVAL; + } + + max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); + + i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); + + i2s->clk_sys = devm_clk_get(dev, "sys"); + if (IS_ERR(i2s->clk_sys)) { + if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(i2s->clk_sys); + } + + ret = clk_prepare_enable(i2s->clk_sys); + if (ret) + return ret; + + i2s->active_channels = 1; + i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; + i2s->dma_data.addr_width = 4; + + i2s->dai_driver.probe = img_i2s_in_dai_probe; + i2s->dai_driver.capture.channels_min = 2; + i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; + i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; + i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE; + i2s->dai_driver.ops = &img_i2s_in_dai_ops; + + rst = devm_reset_control_get(dev, "rst"); + if (IS_ERR(rst)) { + if (PTR_ERR(rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk_disable; + } + + dev_dbg(dev, "No top level reset found\n"); + + img_i2s_in_disable(i2s); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_in_ch_disable(i2s, i); + } else { + reset_control_assert(rst); + reset_control_deassert(rst); + } + + img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_in_ch_writel(i2s, i, + (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) | + IMG_I2S_IN_CH_CTL_JUST_MASK | + IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL); + + ret = devm_snd_soc_register_component(dev, &img_i2s_in_component, + &i2s->dai_driver, 1); + if (ret) + goto err_clk_disable; + + ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable_unprepare(i2s->clk_sys); + + return ret; +} + +static int img_i2s_in_dev_remove(struct platform_device *pdev) +{ + struct img_i2s_in *i2s = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2s->clk_sys); + + return 0; +} + +static const struct of_device_id img_i2s_in_of_match[] = { + { .compatible = "img,i2s-in" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_i2s_in_of_match); + +static struct platform_driver img_i2s_in_driver = { + .driver = { + .name = "img-i2s-in", + .of_match_table = img_i2s_in_of_match + }, + .probe = img_i2s_in_probe, + .remove = img_i2s_in_dev_remove +}; +module_platform_driver(img_i2s_in_driver); + +MODULE_AUTHOR("Damien Horsley "); +MODULE_DESCRIPTION("IMG I2S Input Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From d0e3992c939cb146a0de9e7c74a227e8be4629a9 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Wed, 4 Nov 2015 14:40:50 +0000 Subject: ASoC: img: Add driver for I2S output controller Add driver for Imagination Technologies I2S output controller Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 8 + sound/soc/img/Makefile | 1 + sound/soc/img/img-i2s-out.c | 565 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 sound/soc/img/img-i2s-out.c (limited to 'sound') diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index f9f73d0323f1..fe83c8e344b2 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -10,3 +10,11 @@ config SND_SOC_IMG_I2S_IN help Say Y or M if you want to add support for I2S in driver for Imagination Technologies I2S in device. + +config SND_SOC_IMG_I2S_OUT + tristate "Imagination I2S Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for I2S out driver for + Imagination Technologies I2S out device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile index fe8426b369c2..c41a4af8dd89 100644 --- a/sound/soc/img/Makefile +++ b/sound/soc/img/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o +obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c new file mode 100644 index 000000000000..5f997135a8ae --- /dev/null +++ b/sound/soc/img/img-i2s-out.c @@ -0,0 +1,565 @@ +/* + * IMG I2S output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define IMG_I2S_OUT_TX_FIFO 0x0 + +#define IMG_I2S_OUT_CTL 0x4 +#define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24) +#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000 +#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13 +#define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8) +#define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6) +#define IMG_I2S_OUT_CTL_CLK_MASK BIT(5) +#define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4) +#define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3) +#define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2) +#define IMG_I2S_OUT_CTL_ME_MASK BIT(0) + +#define IMG_I2S_OUT_CH_CTL 0x4 +#define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11) +#define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10) +#define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0 +#define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4 +#define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3) +#define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1) +#define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0) + +#define IMG_I2S_OUT_CH_STRIDE 0x20 + +struct img_i2s_out { + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int max_i2s_chan; + void __iomem *channel_base; + bool force_clk_active; + unsigned int active_channels; + struct reset_control *rst; + struct snd_soc_dai_driver dai_driver; +}; + +static int img_i2s_out_suspend(struct device *dev) +{ + struct img_i2s_out *i2s = dev_get_drvdata(dev); + + if (!i2s->force_clk_active) + clk_disable_unprepare(i2s->clk_ref); + + return 0; +} + +static int img_i2s_out_resume(struct device *dev) +{ + struct img_i2s_out *i2s = dev_get_drvdata(dev); + int ret; + + if (!i2s->force_clk_active) { + ret = clk_prepare_enable(i2s->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + } + + return 0; +} + +static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val, + u32 reg) +{ + writel(val, i2s->base + reg); +} + +static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg) +{ + return readl(i2s->base + reg); +} + +static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s, + u32 chan, u32 val, u32 reg) +{ + writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); +} + +static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan, + u32 reg) +{ + return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); +} + +static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); + reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; + img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); +} + +static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); + reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK; + img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); +} + +static inline void img_i2s_out_disable(struct img_i2s_out *i2s) +{ + u32 reg; + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg &= ~IMG_I2S_OUT_CTL_ME_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); +} + +static inline void img_i2s_out_enable(struct img_i2s_out *i2s) +{ + u32 reg; + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg |= IMG_I2S_OUT_CTL_ME_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); +} + +static void img_i2s_out_reset(struct img_i2s_out *i2s) +{ + int i; + u32 core_ctl, chan_ctl; + + core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) & + ~IMG_I2S_OUT_CTL_ME_MASK & + ~IMG_I2S_OUT_CTL_DATA_EN_MASK; + + if (!i2s->force_clk_active) + core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK; + + chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) & + ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; + + reset_control_assert(i2s->rst); + reset_control_deassert(i2s->rst); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL); + img_i2s_out_enable(i2s); +} + +static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + u32 reg; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + if (!i2s->force_clk_active) + reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK; + reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_i2s_out_reset(i2s); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_i2s_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int channels, i2s_channels; + long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; + int i; + u32 reg, control_mask, control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + i2s_channels = channels / 2; + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if ((channels < 2) || + (channels > (i2s->max_i2s_chan * 2)) || + (channels % 2)) + return -EINVAL; + + pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256); + if (pre_div_a < 0) + return pre_div_a; + pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384); + if (pre_div_b < 0) + return pre_div_b; + + diff_a = abs((pre_div_a / 256) - rate); + diff_b = abs((pre_div_b / 384) - rate); + + /* If diffs are equal, use lower clock rate */ + if (diff_a > diff_b) + clk_set_rate(i2s->clk_ref, pre_div_b); + else + clk_set_rate(i2s->clk_ref, pre_div_a); + + /* + * Another driver (eg alsa machine driver) may have rejected the above + * change. Get the current rate and set the register bit according to + * the new minimum diff + */ + clk_rate = clk_get_rate(i2s->clk_ref); + + diff_a = abs((clk_rate / 256) - rate); + diff_b = abs((clk_rate / 384) - rate); + + if (diff_a > diff_b) + control_set |= IMG_I2S_OUT_CTL_CLK_MASK; + + control_set |= ((i2s_channels - 1) << + IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) & + IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; + + control_mask = IMG_I2S_OUT_CTL_CLK_MASK | + IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; + + img_i2s_out_disable(i2s); + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + for (i = 0; i < i2s_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + for (; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_disable(i2s, i); + + img_i2s_out_enable(i2s); + + i2s->active_channels = i2s_channels; + + return 0; +} + +static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + int i; + bool force_clk_active; + u32 chan_control_mask, control_mask, chan_control_set = 0; + u32 reg, control_set = 0; + + force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) == + SND_SOC_DAIFMT_CONT); + + if (force_clk_active) + control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; + break; + case SND_SOC_DAIFMT_NB_IF: + control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; + control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK | + IMG_I2S_OUT_CTL_MASTER_MASK | + IMG_I2S_OUT_CTL_BCLK_POL_MASK | + IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + + chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; + + img_i2s_out_disable(i2s); + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_disable(i2s, i); + + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); + } + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + img_i2s_out_enable(i2s); + + i2s->force_clk_active = force_clk_active; + + return 0; +} + +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + +static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL); + + return 0; +} + +static const struct snd_soc_component_driver img_i2s_out_component = { + .name = "img-i2s-out" +}; + +static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st, + struct snd_pcm_hw_params *params, struct dma_slave_config *sc) +{ + unsigned int i2s_channels = params_channels(params) / 2; + struct snd_soc_pcm_runtime *rtd = st->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); + + ret = snd_hwparams_to_dma_slave_config(st, params, sc); + if (ret) + return ret; + + sc->dst_addr = dma_data->addr; + sc->dst_addr_width = dma_data->addr_width; + sc->dst_maxburst = 4 * i2s_channels; + + return 0; +} + +static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = { + .prepare_slave_config = img_i2s_out_dma_prepare_slave_config +}; + +static int img_i2s_out_probe(struct platform_device *pdev) +{ + struct img_i2s_out *i2s; + struct resource *res; + void __iomem *base; + int i, ret; + unsigned int max_i2s_chan_pow_2; + u32 reg; + struct device *dev = &pdev->dev; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s); + + i2s->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + i2s->base = base; + + if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", + &i2s->max_i2s_chan)) { + dev_err(&pdev->dev, "No img,i2s-channels property\n"); + return -EINVAL; + } + + max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); + + i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); + + i2s->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(i2s->rst)) { + if (PTR_ERR(i2s->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(i2s->rst); + } + + i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(i2s->clk_sys)) { + if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(i2s->clk_sys); + } + + i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(i2s->clk_ref)) { + if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(i2s->clk_ref); + } + + ret = clk_prepare_enable(i2s->clk_sys); + if (ret) + return ret; + + reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK | + IMG_I2S_OUT_CHAN_CTL_LT_MASK | + IMG_I2S_OUT_CHAN_CTL_CH_MASK | + (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); + + img_i2s_out_reset(i2s); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_i2s_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + i2s->active_channels = 1; + i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; + i2s->dma_data.addr_width = 4; + i2s->dma_data.maxburst = 4; + + i2s->dai_driver.probe = img_i2s_out_dai_probe; + i2s->dai_driver.playback.channels_min = 2; + i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; + i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; + i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE; + i2s->dai_driver.ops = &img_i2s_out_dai_ops; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_i2s_out_component, &i2s->dai_driver, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, + &img_i2s_out_dma_config, 0); + if (ret) + goto err_suspend; + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_i2s_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(i2s->clk_sys); + + return ret; +} + +static int img_i2s_out_dev_remove(struct platform_device *pdev) +{ + struct img_i2s_out *i2s = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_i2s_out_suspend(&pdev->dev); + + clk_disable_unprepare(i2s->clk_sys); + + return 0; +} + +static const struct of_device_id img_i2s_out_of_match[] = { + { .compatible = "img,i2s-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_i2s_out_of_match); + +static const struct dev_pm_ops img_i2s_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_i2s_out_suspend, + img_i2s_out_resume, NULL) +}; + +static struct platform_driver img_i2s_out_driver = { + .driver = { + .name = "img-i2s-out", + .of_match_table = img_i2s_out_of_match, + .pm = &img_i2s_out_pm_ops + }, + .probe = img_i2s_out_probe, + .remove = img_i2s_out_dev_remove +}; +module_platform_driver(img_i2s_out_driver); + +MODULE_AUTHOR("Damien Horsley "); +MODULE_DESCRIPTION("IMG I2S Output Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8ceb3b259cddb9b0505a6697cdefd3110445d1d7 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Wed, 4 Nov 2015 14:40:52 +0000 Subject: ASoC: img: Add driver for parallel output controller Add driver for Imagination Technologies parallel output controller Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 8 + sound/soc/img/Makefile | 1 + sound/soc/img/img-parallel-out.c | 327 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 sound/soc/img/img-parallel-out.c (limited to 'sound') diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index fe83c8e344b2..3bb507e5570c 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -18,3 +18,11 @@ config SND_SOC_IMG_I2S_OUT help Say Y or M if you want to add support for I2S out driver for Imagination Technologies I2S out device. + +config SND_SOC_IMG_PARALLEL_OUT + tristate "Imagination Parallel Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for parallel out driver for + Imagination Technologies parallel out device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile index c41a4af8dd89..da8976322488 100644 --- a/sound/soc/img/Makefile +++ b/sound/soc/img/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o +obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c new file mode 100644 index 000000000000..beda18b18c64 --- /dev/null +++ b/sound/soc/img/img-parallel-out.c @@ -0,0 +1,327 @@ +/* + * IMG parallel output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define IMG_PRL_OUT_TX_FIFO 0 + +#define IMG_PRL_OUT_CTL 0x4 +#define IMG_PRL_OUT_CTL_CH_MASK BIT(4) +#define IMG_PRL_OUT_CTL_PACKH_MASK BIT(3) +#define IMG_PRL_OUT_CTL_EDGE_MASK BIT(2) +#define IMG_PRL_OUT_CTL_ME_MASK BIT(1) +#define IMG_PRL_OUT_CTL_SRST_MASK BIT(0) + +struct img_prl_out { + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + struct reset_control *rst; +}; + +static int img_prl_out_suspend(struct device *dev) +{ + struct img_prl_out *prl = dev_get_drvdata(dev); + + clk_disable_unprepare(prl->clk_ref); + + return 0; +} + +static int img_prl_out_resume(struct device *dev) +{ + struct img_prl_out *prl = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(prl->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + + return 0; +} + +static inline void img_prl_out_writel(struct img_prl_out *prl, + u32 val, u32 reg) +{ + writel(val, prl->base + reg); +} + +static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg) +{ + return readl(prl->base + reg); +} + +static void img_prl_out_reset(struct img_prl_out *prl) +{ + u32 ctl; + + ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) & + ~IMG_PRL_OUT_CTL_ME_MASK; + + reset_control_assert(prl->rst); + reset_control_deassert(prl->rst); + + img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL); +} + +static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + u32 reg; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg |= IMG_PRL_OUT_CTL_ME_MASK; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_prl_out_reset(prl); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_prl_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels; + u32 reg, control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + control_set |= IMG_PRL_OUT_CTL_PACKH_MASK; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + default: + return -EINVAL; + } + + if (channels != 2) + return -EINVAL; + + clk_set_rate(prl->clk_ref, rate * 256); + + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + + return 0; +} + +static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + u32 reg, control_set; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + control_set |= IMG_PRL_OUT_CTL_EDGE_MASK; + break; + default: + return -EINVAL; + } + + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + + return 0; +} + +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + +static int img_prl_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL); + + return 0; +} + +static struct snd_soc_dai_driver img_prl_out_dai = { + .probe = img_prl_out_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE + }, + .ops = &img_prl_out_dai_ops +}; + +static const struct snd_soc_component_driver img_prl_out_component = { + .name = "img-prl-out" +}; + +static int img_prl_out_probe(struct platform_device *pdev) +{ + struct img_prl_out *prl; + struct resource *res; + void __iomem *base; + int ret; + struct device *dev = &pdev->dev; + + prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL); + if (!prl) + return -ENOMEM; + + platform_set_drvdata(pdev, prl); + + prl->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + prl->base = base; + + prl->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(prl->rst)) { + if (PTR_ERR(prl->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(prl->rst); + } + + prl->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(prl->clk_sys)) { + if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(prl->clk_sys); + } + + prl->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(prl->clk_ref)) { + if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(prl->clk_ref); + } + + ret = clk_prepare_enable(prl->clk_sys); + if (ret) + return ret; + + img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL); + img_prl_out_reset(prl); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_prl_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO; + prl->dma_data.addr_width = 4; + prl->dma_data.maxburst = 4; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_prl_out_component, + &img_prl_out_dai, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_prl_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(prl->clk_sys); + + return ret; +} + +static int img_prl_out_dev_remove(struct platform_device *pdev) +{ + struct img_prl_out *prl = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_prl_out_suspend(&pdev->dev); + + clk_disable_unprepare(prl->clk_sys); + + return 0; +} + +static const struct of_device_id img_prl_out_of_match[] = { + { .compatible = "img,parallel-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_prl_out_of_match); + +static const struct dev_pm_ops img_prl_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_prl_out_suspend, + img_prl_out_resume, NULL) +}; + +static struct platform_driver img_prl_out_driver = { + .driver = { + .name = "img-parallel-out", + .of_match_table = img_prl_out_of_match, + .pm = &img_prl_out_pm_ops + }, + .probe = img_prl_out_probe, + .remove = img_prl_out_dev_remove +}; +module_platform_driver(img_prl_out_driver); + +MODULE_AUTHOR("Damien Horsley "); +MODULE_DESCRIPTION("IMG Parallel Output Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From c4458b740e6b7a0d9ccf680ac81c05a99f602b79 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Wed, 4 Nov 2015 14:40:54 +0000 Subject: ASoC: img: Add driver for SPDIF input controller Add driver for Imagination Technologies SDPIF input controller Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 8 + sound/soc/img/Makefile | 1 + sound/soc/img/img-spdif-in.c | 806 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 815 insertions(+) create mode 100644 sound/soc/img/img-spdif-in.c (limited to 'sound') diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index 3bb507e5570c..161ce90441b7 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -26,3 +26,11 @@ config SND_SOC_IMG_PARALLEL_OUT help Say Y or M if you want to add support for parallel out driver for Imagination Technologies parallel out device. + +config SND_SOC_IMG_SPDIF_IN + tristate "Imagination SPDIF Input Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for SPDIF input driver for + Imagination Technologies SPDIF input device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile index da8976322488..85ded5eede5f 100644 --- a/sound/soc/img/Makefile +++ b/sound/soc/img/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o +obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c new file mode 100644 index 000000000000..4d9953d318af --- /dev/null +++ b/sound/soc/img/img-spdif-in.c @@ -0,0 +1,806 @@ +/* + * IMG SPDIF input controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define IMG_SPDIF_IN_RX_FIFO_OFFSET 0 + +#define IMG_SPDIF_IN_CTL 0x4 +#define IMG_SPDIF_IN_CTL_LOCKLO_MASK 0xff +#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT 0 +#define IMG_SPDIF_IN_CTL_LOCKHI_MASK 0xff00 +#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT 8 +#define IMG_SPDIF_IN_CTL_TRK_MASK 0xff0000 +#define IMG_SPDIF_IN_CTL_TRK_SHIFT 16 +#define IMG_SPDIF_IN_CTL_SRD_MASK 0x70000000 +#define IMG_SPDIF_IN_CTL_SRD_SHIFT 28 +#define IMG_SPDIF_IN_CTL_SRT_MASK BIT(31) + +#define IMG_SPDIF_IN_STATUS 0x8 +#define IMG_SPDIF_IN_STATUS_SAM_MASK 0x7000 +#define IMG_SPDIF_IN_STATUS_SAM_SHIFT 12 +#define IMG_SPDIF_IN_STATUS_LOCK_MASK BIT(15) +#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT 15 + +#define IMG_SPDIF_IN_CLKGEN 0x1c +#define IMG_SPDIF_IN_CLKGEN_NOM_MASK 0x3ff +#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT 0 +#define IMG_SPDIF_IN_CLKGEN_HLD_MASK 0x3ff0000 +#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT 16 + +#define IMG_SPDIF_IN_CSL 0x20 + +#define IMG_SPDIF_IN_CSH 0x24 +#define IMG_SPDIF_IN_CSH_MASK 0xff +#define IMG_SPDIF_IN_CSH_SHIFT 0 + +#define IMG_SPDIF_IN_SOFT_RESET 0x28 +#define IMG_SPDIF_IN_SOFT_RESET_MASK BIT(0) + +#define IMG_SPDIF_IN_ACLKGEN_START 0x2c +#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK 0x3ff +#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT 0 +#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK 0xffc00 +#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT 10 +#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK 0xff00000 +#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT 20 + +#define IMG_SPDIF_IN_NUM_ACLKGEN 4 + +struct img_spdif_in { + spinlock_t lock; + void __iomem *base; + struct clk *clk_sys; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int trk; + bool multi_freq; + int lock_acquire; + int lock_release; + unsigned int single_freq; + unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; + bool active; + + /* Write-only registers */ + unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; +}; + +static inline void img_spdif_in_writel(struct img_spdif_in *spdif, + u32 val, u32 reg) +{ + writel(val, spdif->base + reg); +} + +static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg) +{ + return readl(spdif->base + reg); +} + +static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif, + u32 index) +{ + img_spdif_in_writel(spdif, spdif->aclkgen_regs[index], + IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4)); +} + +static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif, + unsigned int sample_rate, unsigned long *actual_freq) +{ + unsigned long min_freq, freq_t; + + /* Clock rate must be at least 24x the bit rate */ + min_freq = sample_rate * 2 * 32 * 24; + + freq_t = clk_get_rate(spdif->clk_sys); + + if (freq_t < min_freq) + return -EINVAL; + + *actual_freq = freq_t; + + return 0; +} + +static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom, + unsigned int *phld, unsigned long clk_rate) +{ + unsigned int ori, nom, hld; + + /* + * Calculate oversampling ratio, nominal phase increment and hold + * increment for the given rate / frequency + */ + + if (!rate) + return -EINVAL; + + ori = clk_rate / (rate * 64); + + if (!ori) + return -EINVAL; + + nom = (4096 / ori) + 1; + do + hld = 4096 - (--nom * (ori - 1)); + while (hld < 120); + + *pnom = nom; + *phld = hld; + + return 0; +} + +static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif, + unsigned int rate) +{ + unsigned int nom, hld; + unsigned long flags, clk_rate; + int ret = 0; + u32 reg; + + ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate); + if (ret) + return ret; + + ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); + if (ret) + return ret; + + reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) & + IMG_SPDIF_IN_CLKGEN_NOM_MASK; + reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) & + IMG_SPDIF_IN_CLKGEN_HLD_MASK; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN); + + spdif->single_freq = rate; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif, + unsigned int multi_freqs[]) +{ + unsigned int nom, hld, rate, max_rate = 0; + unsigned long flags, clk_rate; + int i, ret = 0; + u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) + if (multi_freqs[i] > max_rate) + max_rate = multi_freqs[i]; + + ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate); + if (ret) + return ret; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + rate = multi_freqs[i]; + + ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); + if (ret) + return ret; + + reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) & + IMG_SPDIF_IN_ACLKGEN_NOM_MASK; + reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) & + IMG_SPDIF_IN_ACLKGEN_HLD_MASK; + temp_regs[i] = reg; + } + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg; + img_spdif_in_aclkgen_writel(spdif, i); + } + + spdif->multi_freq = true; + spdif->multi_freqs[0] = multi_freqs[0]; + spdif->multi_freqs[1] = multi_freqs[1]; + spdif->multi_freqs[2] = multi_freqs[2]; + spdif->multi_freqs[3] = multi_freqs[3]; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + ucontrol->value.iec958.status[4] = 0xff; + + return 0; +} + +static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL); + ucontrol->value.iec958.status[0] = reg & 0xff; + ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff; + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH); + ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK) + >> IMG_SPDIF_IN_CSH_SHIFT; + + return 0; +} + +static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + + return 0; +} + +static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + if (spdif->multi_freq) { + ucontrol->value.integer.value[0] = spdif->multi_freqs[0]; + ucontrol->value.integer.value[1] = spdif->multi_freqs[1]; + ucontrol->value.integer.value[2] = spdif->multi_freqs[2]; + ucontrol->value.integer.value[3] = spdif->multi_freqs[3]; + } else { + ucontrol->value.integer.value[0] = 0; + ucontrol->value.integer.value[1] = 0; + ucontrol->value.integer.value[2] = 0; + ucontrol->value.integer.value[3] = 0; + } + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; + bool multi_freq; + unsigned long flags; + + if ((ucontrol->value.integer.value[0] == 0) && + (ucontrol->value.integer.value[1] == 0) && + (ucontrol->value.integer.value[2] == 0) && + (ucontrol->value.integer.value[3] == 0)) { + multi_freq = false; + } else { + multi_freqs[0] = ucontrol->value.integer.value[0]; + multi_freqs[1] = ucontrol->value.integer.value[1]; + multi_freqs[2] = ucontrol->value.integer.value[2]; + multi_freqs[3] = ucontrol->value.integer.value[3]; + multi_freq = true; + } + + if (multi_freq) + return img_spdif_in_do_clkgen_multi(spdif, multi_freqs); + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->multi_freq = false; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + + return 0; +} + +static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uc) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + int i; + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS); + if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) { + if (spdif->multi_freq) { + i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >> + IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1; + uc->value.integer.value[0] = spdif->multi_freqs[i]; + } else { + uc->value.integer.value[0] = spdif->single_freq; + } + } else { + uc->value.integer.value[0] = 0; + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + + return 0; +} + +static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->trk; + + return 0; +} + +static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + int i; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->trk = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK; + reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] & + ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) | + (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT); + + img_spdif_in_aclkgen_writel(spdif, i); + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -128; + uinfo->value.integer.max = 127; + + return 0; +} + +static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->lock_acquire; + + return 0; +} + +static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->lock_acquire = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK; + reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKHI_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->lock_release; + + return 0; +} + +static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->lock_release = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK; + reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKLO_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static struct snd_kcontrol_new img_spdif_in_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), + .info = img_spdif_in_iec958_info, + .get = img_spdif_in_get_status_mask + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .info = img_spdif_in_iec958_info, + .get = img_spdif_in_get_status + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Multi Frequency Acquire", + .info = img_spdif_in_info_multi_freq, + .get = img_spdif_in_get_multi_freq, + .put = img_spdif_in_set_multi_freq + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Frequency", + .info = img_spdif_in_info_lock_freq, + .get = img_spdif_in_get_lock_freq + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock TRK", + .info = img_spdif_in_info_trk, + .get = img_spdif_in_get_trk, + .put = img_spdif_in_set_trk + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Acquire Threshold", + .info = img_spdif_in_info_lock, + .get = img_spdif_in_get_lock_acquire, + .put = img_spdif_in_set_lock_acquire + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Release Threshold", + .info = img_spdif_in_info_lock, + .get = img_spdif_in_get_lock_release, + .put = img_spdif_in_set_lock_release + } +}; + +static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + unsigned long flags; + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + int ret = 0; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + if (spdif->multi_freq) + reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK; + else + reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT); + reg |= IMG_SPDIF_IN_CTL_SRT_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + spdif->active = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + spdif->active = false; + break; + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return ret; +} + +static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels; + snd_pcm_format_t format; + + rate = params_rate(params); + channels = params_channels(params); + format = params_format(params); + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if (channels != 2) + return -EINVAL; + + return img_spdif_in_do_clkgen_single(spdif, rate); +} + +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + +static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) +{ + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data); + + snd_soc_add_dai_controls(dai, img_spdif_in_controls, + ARRAY_SIZE(img_spdif_in_controls)); + + return 0; +} + +static struct snd_soc_dai_driver img_spdif_in_dai = { + .probe = img_spdif_in_dai_probe, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &img_spdif_in_dai_ops +}; + +static const struct snd_soc_component_driver img_spdif_in_component = { + .name = "img-spdif-in" +}; + +static int img_spdif_in_probe(struct platform_device *pdev) +{ + struct img_spdif_in *spdif; + struct resource *res; + void __iomem *base; + int ret; + struct reset_control *rst; + u32 reg; + struct device *dev = &pdev->dev; + + spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); + if (!spdif) + return -ENOMEM; + + platform_set_drvdata(pdev, spdif); + + spdif->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + spdif->base = base; + + spdif->clk_sys = devm_clk_get(dev, "sys"); + if (IS_ERR(spdif->clk_sys)) { + if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(spdif->clk_sys); + } + + ret = clk_prepare_enable(spdif->clk_sys); + if (ret) + return ret; + + rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(rst)) { + if (PTR_ERR(rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk_disable; + } + dev_dbg(dev, "No top level reset found\n"); + img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK, + IMG_SPDIF_IN_SOFT_RESET); + img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET); + } else { + reset_control_assert(rst); + reset_control_deassert(rst); + } + + spin_lock_init(&spdif->lock); + + spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET; + spdif->dma_data.addr_width = 4; + spdif->dma_data.maxburst = 4; + spdif->trk = 0x80; + spdif->lock_acquire = 4; + spdif->lock_release = -128; + + reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKHI_MASK; + reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKLO_MASK; + reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) & + IMG_SPDIF_IN_CTL_TRK_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_spdif_in_component, &img_spdif_in_dai, 1); + if (ret) + goto err_clk_disable; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable_unprepare(spdif->clk_sys); + + return ret; +} + +static int img_spdif_in_dev_remove(struct platform_device *pdev) +{ + struct img_spdif_in *spdif = platform_get_drvdata(pdev); + + clk_disable_unprepare(spdif->clk_sys); + + return 0; +} + +static const struct of_device_id img_spdif_in_of_match[] = { + { .compatible = "img,spdif-in" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_spdif_in_of_match); + +static struct platform_driver img_spdif_in_driver = { + .driver = { + .name = "img-spdif-in", + .of_match_table = img_spdif_in_of_match + }, + .probe = img_spdif_in_probe, + .remove = img_spdif_in_dev_remove +}; +module_platform_driver(img_spdif_in_driver); + +MODULE_AUTHOR("Damien Horsley "); +MODULE_DESCRIPTION("IMG SPDIF Input driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 3958232273d791629d8fffc67b6c5b895ab1e91a Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Wed, 4 Nov 2015 14:40:57 +0000 Subject: ASoC: img: Add driver for SPDIF output controller Add driver for Imagination Technologies SPDIF output controller Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 8 + sound/soc/img/Makefile | 1 + sound/soc/img/img-spdif-out.c | 441 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 sound/soc/img/img-spdif-out.c (limited to 'sound') diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index 161ce90441b7..d08537ecb915 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -34,3 +34,11 @@ config SND_SOC_IMG_SPDIF_IN help Say Y or M if you want to add support for SPDIF input driver for Imagination Technologies SPDIF input device. + +config SND_SOC_IMG_SPDIF_OUT + tristate "Imagination SPDIF Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for SPDIF out driver for + Imagination Technologies SPDIF out device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile index 85ded5eede5f..1a44fb4b08fe 100644 --- a/sound/soc/img/Makefile +++ b/sound/soc/img/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o +obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c new file mode 100644 index 000000000000..08f93a5dadfe --- /dev/null +++ b/sound/soc/img/img-spdif-out.c @@ -0,0 +1,441 @@ +/* + * IMG SPDIF output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define IMG_SPDIF_OUT_TX_FIFO 0x0 + +#define IMG_SPDIF_OUT_CTL 0x4 +#define IMG_SPDIF_OUT_CTL_FS_MASK BIT(4) +#define IMG_SPDIF_OUT_CTL_CLK_MASK BIT(2) +#define IMG_SPDIF_OUT_CTL_SRT_MASK BIT(0) + +#define IMG_SPDIF_OUT_CSL 0x14 + +#define IMG_SPDIF_OUT_CSH_UV 0x18 +#define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT 0 +#define IMG_SPDIF_OUT_CSH_UV_CSH_MASK 0xff + +struct img_spdif_out { + spinlock_t lock; + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + struct reset_control *rst; +}; + +static int img_spdif_out_suspend(struct device *dev) +{ + struct img_spdif_out *spdif = dev_get_drvdata(dev); + + clk_disable_unprepare(spdif->clk_ref); + + return 0; +} + +static int img_spdif_out_resume(struct device *dev) +{ + struct img_spdif_out *spdif = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(spdif->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + + return 0; +} + +static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val, + u32 reg) +{ + writel(val, spdif->base + reg); +} + +static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg) +{ + return readl(spdif->base + reg); +} + +static void img_spdif_out_reset(struct img_spdif_out *spdif) +{ + u32 ctl, status_low, status_high; + + ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) & + ~IMG_SPDIF_OUT_CTL_SRT_MASK; + status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL); + status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + + reset_control_assert(spdif->rst); + reset_control_deassert(spdif->rst); + + img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL); + img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL); + img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV); +} + +static int img_spdif_out_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + ucontrol->value.iec958.status[4] = 0xff; + + return 0; +} + +static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL); + ucontrol->value.iec958.status[0] = reg & 0xff; + ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff; + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + ucontrol->value.iec958.status[4] = + (reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >> + IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + unsigned long flags; + + reg = ((u32)ucontrol->value.iec958.status[3] << 24); + reg |= ((u32)ucontrol->value.iec958.status[2] << 16); + reg |= ((u32)ucontrol->value.iec958.status[1] << 8); + reg |= (u32)ucontrol->value.iec958.status[0]; + + spin_lock_irqsave(&spdif->lock, flags); + + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK; + reg |= (u32)ucontrol->value.iec958.status[4] << + IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static struct snd_kcontrol_new img_spdif_out_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = img_spdif_out_info, + .get = img_spdif_out_get_status_mask + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = img_spdif_out_info, + .get = img_spdif_out_get_status, + .put = img_spdif_out_set_status + } +}; + +static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + u32 reg; + unsigned long flags; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL); + reg |= IMG_SPDIF_OUT_CTL_SRT_MASK; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&spdif->lock, flags); + img_spdif_out_reset(spdif); + spin_unlock_irqrestore(&spdif->lock, flags); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + unsigned int channels; + long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; + u32 reg; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n", + rate, channels, format); + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if (channels != 2) + return -EINVAL; + + pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256); + if (pre_div_a < 0) + return pre_div_a; + pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384); + if (pre_div_b < 0) + return pre_div_b; + + diff_a = abs((pre_div_a / 256) - rate); + diff_b = abs((pre_div_b / 384) - rate); + + /* If diffs are equal, use lower clock rate */ + if (diff_a > diff_b) + clk_set_rate(spdif->clk_ref, pre_div_b); + else + clk_set_rate(spdif->clk_ref, pre_div_a); + + /* + * Another driver (eg machine driver) may have rejected the above + * change. Get the current rate and set the register bit according to + * the new min diff + */ + clk_rate = clk_get_rate(spdif->clk_ref); + + diff_a = abs((clk_rate / 256) - rate); + diff_b = abs((clk_rate / 384) - rate); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL); + if (diff_a <= diff_b) + reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK; + else + reg |= IMG_SPDIF_OUT_CTL_CLK_MASK; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL); + + return 0; +} + +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + +static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL); + + snd_soc_add_dai_controls(dai, img_spdif_out_controls, + ARRAY_SIZE(img_spdif_out_controls)); + + return 0; +} + +static struct snd_soc_dai_driver img_spdif_out_dai = { + .probe = img_spdif_out_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &img_spdif_out_dai_ops +}; + +static const struct snd_soc_component_driver img_spdif_out_component = { + .name = "img-spdif-out" +}; + +static int img_spdif_out_probe(struct platform_device *pdev) +{ + struct img_spdif_out *spdif; + struct resource *res; + void __iomem *base; + int ret; + struct device *dev = &pdev->dev; + + spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); + if (!spdif) + return -ENOMEM; + + platform_set_drvdata(pdev, spdif); + + spdif->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + spdif->base = base; + + spdif->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(spdif->rst)) { + if (PTR_ERR(spdif->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(spdif->rst); + } + + spdif->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(spdif->clk_sys)) { + if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(spdif->clk_sys); + } + + spdif->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(spdif->clk_ref)) { + if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(spdif->clk_ref); + } + + ret = clk_prepare_enable(spdif->clk_sys); + if (ret) + return ret; + + img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK, + IMG_SPDIF_OUT_CTL); + + img_spdif_out_reset(spdif); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_spdif_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + spin_lock_init(&spdif->lock); + + spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO; + spdif->dma_data.addr_width = 4; + spdif->dma_data.maxburst = 4; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_spdif_out_component, + &img_spdif_out_dai, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + + dev_dbg(&pdev->dev, "Probe successful\n"); + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_spdif_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(spdif->clk_sys); + + return ret; +} + +static int img_spdif_out_dev_remove(struct platform_device *pdev) +{ + struct img_spdif_out *spdif = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_spdif_out_suspend(&pdev->dev); + + clk_disable_unprepare(spdif->clk_sys); + + return 0; +} + +static const struct of_device_id img_spdif_out_of_match[] = { + { .compatible = "img,spdif-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_spdif_out_of_match); + +static const struct dev_pm_ops img_spdif_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_spdif_out_suspend, + img_spdif_out_resume, NULL) +}; + +static struct platform_driver img_spdif_out_driver = { + .driver = { + .name = "img-spdif-out", + .of_match_table = img_spdif_out_of_match, + .pm = &img_spdif_out_pm_ops + }, + .probe = img_spdif_out_probe, + .remove = img_spdif_out_dev_remove +}; +module_platform_driver(img_spdif_out_driver); + +MODULE_AUTHOR("Damien Horsley "); +MODULE_DESCRIPTION("IMG SPDIF Output driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7f0e823d58b7574cbe417d5bbc285891baed4437 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Tue, 10 Nov 2015 14:09:35 +0000 Subject: ASoC: img: parallel out: Add missing initialiser Add missing initialiser for control_set variable in img_prl_out_set_fmt Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/img-parallel-out.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index beda18b18c64..c1610a054d65 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -154,7 +154,7 @@ static int img_prl_out_hw_params(struct snd_pcm_substream *substream, static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); - u32 reg, control_set; + u32 reg, control_set = 0; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: -- cgit v1.2.3 From a28f51db28a3bb550ee54e4e67b4b1d04b4b393a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:44 +0900 Subject: ASoC: Intel: Skylake: Fix to correct check for non DSP widget To get the FE copier module, the check to ignore non DSP widgets was wrong. This path corrects the check to ignore non DSP widget. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index a7854c8fc523..98ccd42b8867 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -846,7 +846,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) w = dai->playback_widget; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connect && p->sink->power && - is_skl_dsp_widget_type(p->sink)) + !is_skl_dsp_widget_type(p->sink)) continue; if (p->sink->priv) { @@ -859,7 +859,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) w = dai->capture_widget; snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connect && p->source->power && - is_skl_dsp_widget_type(p->source)) + !is_skl_dsp_widget_type(p->source)) continue; if (p->source->priv) { -- cgit v1.2.3 From 4bd073f93f13ad5de8affb173056827117a4a930 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:45 +0900 Subject: ASoC: Intel: Skylake: Fix not to ignore return value in be hw_params Return value from skl_tplg_be_update_params() is ignored. But if the blob is null then the hw_params needs to return error. This patch fixes the issue by not ignoring return value from skl_tplg_be_update_params(). Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a2f94ce1679d..1242beac4e46 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -291,9 +291,8 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream, p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - skl_tplg_be_update_params(dai, &p_params); - return 0; + return skl_tplg_be_update_params(dai, &p_params); } static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, @@ -352,9 +351,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, p_params.stream = substream->stream; p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; - skl_tplg_be_update_params(dai, &p_params); - - return 0; + return skl_tplg_be_update_params(dai, &p_params); } static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 6654f39eb4a65b61c3550be352662f57a2701bbc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:46 +0900 Subject: ASoC: Intel: Skylake: Fix to add 32 bit in update FE params In case of 32 bit, the FE update params returns error as it falls thru to default case. This patch adds 32 bit depth handling in update FE params. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 98ccd42b8867..313a02d8db01 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -809,6 +809,7 @@ int skl_tplg_update_pipe_params(struct device *dev, break; case SKL_DEPTH_24BIT: + case SKL_DEPTH_32BIT: format->bit_depth = SKL_DEPTH_32BIT; break; -- cgit v1.2.3 From 029890c67ae6f95c3f7d84af9b7e555515b33193 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:47 +0900 Subject: ASoC: Intel: Skylake: Fix to ignore codec_mask check in probe We have both I2S and hda codec support in the driver. codec_mask check is relevant only for hda codec and some boards may have only I2S Codec, so removed probe error in case no hda codec is found and update the log to info as it may not be error. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5319529aedf7..211ef6e2fa21 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -434,8 +434,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* codec detection */ if (!bus->codec_mask) { - dev_err(bus->dev, "no codecs found!\n"); - return -ENODEV; + dev_info(bus->dev, "no hda codecs found!\n"); } return 0; -- cgit v1.2.3 From b30c275e449ac1c7e149e2138a342c407d8cab3b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:48 +0900 Subject: ASoC: Intel: Skylake: Fix to ignore blob check if link type is HDA If link type is HDA, NHLT blob is null, as NHLT defines non HDA links only. So we should ignore blob query for HDA links. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 313a02d8db01..e11a9e44d064 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -921,6 +921,9 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, memcpy(pipe->p_params, params, sizeof(*params)); + if (link_type == NHLT_LINK_HDA) + return 0; + /* update the blob based on virtual bus_id*/ cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, params->s_fmt, params->ch, -- cgit v1.2.3 From 4f7457089df2984aeee59ec01525aa9917e889e7 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:49 +0900 Subject: ASoC: Intel: Skylake: Fix support for multiple pins in a module For supporting multiple dynamic pins, module state check is incorrect. In case of unbind, module state need to be changed to uninit if all pins in the module is is unbind state. To handle module state correctly add pin state and use pin state check to set module state correctly. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 83 ++++++++++++++++++++++------------ sound/soc/intel/skylake/skl-topology.c | 1 + sound/soc/intel/skylake/skl-topology.h | 10 +++- 3 files changed, 65 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 50a109503a3f..ee059589e9f0 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -571,10 +571,10 @@ static int skl_get_queue_index(struct skl_module_pin *mpin, * In static, the pin_index is fixed based on module_id and instance id */ static int skl_alloc_queue(struct skl_module_pin *mpin, - struct skl_module_inst_id id, int max) + struct skl_module_cfg *tgt_cfg, int max) { int i; - + struct skl_module_inst_id id = tgt_cfg->id; /* * if pin in dynamic, find first free pin * otherwise find match module and instance id pin as topology will @@ -583,16 +583,23 @@ static int skl_alloc_queue(struct skl_module_pin *mpin, */ for (i = 0; i < max; i++) { if (mpin[i].is_dynamic) { - if (!mpin[i].in_use) { + if (!mpin[i].in_use && + mpin[i].pin_state == SKL_PIN_UNBIND) { + mpin[i].in_use = true; mpin[i].id.module_id = id.module_id; mpin[i].id.instance_id = id.instance_id; + mpin[i].tgt_mcfg = tgt_cfg; return i; } } else { if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id) + mpin[i].id.instance_id == id.instance_id && + mpin[i].pin_state == SKL_PIN_UNBIND) { + + mpin[i].tgt_mcfg = tgt_cfg; return i; + } } } @@ -606,6 +613,28 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) mpin[q_index].id.module_id = 0; mpin[q_index].id.instance_id = 0; } + mpin[q_index].pin_state = SKL_PIN_UNBIND; + mpin[q_index].tgt_mcfg = NULL; +} + +/* Module state will be set to unint, if all the out pin state is UNBIND */ + +static void skl_clear_module_state(struct skl_module_pin *mpin, int max, + struct skl_module_cfg *mcfg) +{ + int i; + bool found = false; + + for (i = 0; i < max; i++) { + if (mpin[i].pin_state == SKL_PIN_UNBIND) + continue; + found = true; + break; + } + + if (!found) + mcfg->m_state = SKL_MODULE_UNINIT; + return; } /* @@ -682,37 +711,30 @@ int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_inst_id dst_id = dst_mcfg->id; int in_max = dst_mcfg->max_in_queue; int out_max = src_mcfg->max_out_queue; - int src_index, dst_index; + int src_index, dst_index, src_pin_state, dst_pin_state; skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); - if (src_mcfg->m_state != SKL_MODULE_BIND_DONE) - return 0; - - /* - * if intra module unbind, check if both modules are BIND, - * then send unbind - */ - if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) && - dst_mcfg->m_state != SKL_MODULE_BIND_DONE) - return 0; - else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && - dst_mcfg->m_state < SKL_MODULE_INIT_DONE) - return 0; - /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); if (src_index < 0) return -EINVAL; - msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; + msg.src_queue = src_index; /* get dst queue index */ dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); if (dst_index < 0) return -EINVAL; - msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + msg.dst_queue = dst_index; + + src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; + dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; + + if (src_pin_state != SKL_PIN_BIND_DONE || + dst_pin_state != SKL_PIN_BIND_DONE) + return 0; msg.module_id = src_mcfg->id.module_id; msg.instance_id = src_mcfg->id.instance_id; @@ -722,10 +744,15 @@ int skl_unbind_modules(struct skl_sst *ctx, ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); if (!ret) { - src_mcfg->m_state = SKL_MODULE_UNINIT; /* free queue only if unbind is success */ skl_free_queue(src_mcfg->m_out_pin, src_index); skl_free_queue(dst_mcfg->m_in_pin, dst_index); + + /* + * check only if src module bind state, bind is + * always from src -> sink + */ + skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); } return ret; @@ -744,8 +771,6 @@ int skl_bind_modules(struct skl_sst *ctx, { int ret; struct skl_ipc_bind_unbind_msg msg; - struct skl_module_inst_id src_id = src_mcfg->id; - struct skl_module_inst_id dst_id = dst_mcfg->id; int in_max = dst_mcfg->max_in_queue; int out_max = src_mcfg->max_out_queue; int src_index, dst_index; @@ -756,18 +781,18 @@ int skl_bind_modules(struct skl_sst *ctx, dst_mcfg->m_state < SKL_MODULE_INIT_DONE) return 0; - src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max); + src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); if (src_index < 0) return -EINVAL; - msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; - dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max); + msg.src_queue = src_index; + dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); if (dst_index < 0) { skl_free_queue(src_mcfg->m_out_pin, src_index); return -EINVAL; } - msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + msg.dst_queue = dst_index; dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", msg.src_queue, msg.dst_queue); @@ -782,6 +807,8 @@ int skl_bind_modules(struct skl_sst *ctx, if (!ret) { src_mcfg->m_state = SKL_MODULE_BIND_DONE; + src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; + dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; } else { /* error case , if IPC fails, clear the queue index */ skl_free_queue(src_mcfg->m_out_pin, src_index); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index e11a9e44d064..e8258d4807ff 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1049,6 +1049,7 @@ static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, m_pin[i].id.instance_id = dfw_pin[i].instance_id; m_pin[i].in_use = false; m_pin[i].is_dynamic = is_dynamic; + m_pin[i].pin_state = SKL_PIN_UNBIND; } } diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 76053a8de41c..cd8768308f29 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -180,16 +180,24 @@ struct skl_module_fmt { u32 ch_cfg; }; +struct skl_module_cfg; + struct skl_module_inst_id { u32 module_id; u32 instance_id; }; +enum skl_module_pin_state { + SKL_PIN_UNBIND = 0, + SKL_PIN_BIND_DONE = 1, +}; + struct skl_module_pin { struct skl_module_inst_id id; - u8 pin_index; bool is_dynamic; bool in_use; + enum skl_module_pin_state pin_state; + struct skl_module_cfg *tgt_mcfg; }; struct skl_specific_cfg { -- cgit v1.2.3 From 83b50246d3f193ce7f0546786097ee673c359eb2 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:50 +0900 Subject: ASoC: Intel: Skylake: Fix bit depth when querying the NHLT blob Bps calculation is not correct as this needs to be based on valid bit depth. 16 bit fmt bit depth is 16 bit and for 24 and 32 bit as it is container size This patch fixes the bps. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index b0c7bd113aac..3ff22eba5875 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -115,7 +115,7 @@ struct nhlt_specific_cfg struct device *dev = bus->dev; struct nhlt_specific_cfg *sp_config; struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - u16 bps = num_ch * s_fmt; + u16 bps = (s_fmt == 16) ? 16 : 32; u8 j; dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); -- cgit v1.2.3 From ce1b5551a06af31a72feeb50c02a9fe22599926a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:51 +0900 Subject: ASoC: Intel: Skylake: use module_pin info for unbind in_pin and out_pin list for a module has the information about the module that are bound together. So we can directly look at pin information of module for binding and unbind. As a result the preinitialized dapm_path_last we had is removed and code and memory optimzed. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 - sound/soc/intel/skylake/skl-topology.c | 108 +++++++++++---------------------- sound/soc/intel/skylake/skl-topology.h | 5 -- sound/soc/intel/skylake/skl.h | 1 - 4 files changed, 34 insertions(+), 81 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 1242beac4e46..1a9cd00c0b0a 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -938,7 +938,6 @@ int skl_platform_register(struct device *dev) struct skl *skl = ebus_to_skl(ebus); INIT_LIST_HEAD(&skl->ppl_list); - INIT_LIST_HEAD(&skl->dapm_path_list); ret = snd_soc_register_platform(dev, &skl_platform_drv); if (ret) { diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index e8258d4807ff..abbf8e7eb3e7 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -411,7 +411,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, struct skl *skl) { struct snd_soc_dapm_path *p; - struct skl_dapm_path_list *path_list; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; @@ -455,16 +454,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, if (ret) return ret; } - - path_list = kzalloc( - sizeof(struct skl_dapm_path_list), - GFP_KERNEL); - if (path_list == NULL) - return -ENOMEM; - - /* Add connected path to one global list */ - path_list->dapm_path = p; - list_add_tail(&path_list->node, &skl->dapm_path_list); break; } } @@ -552,54 +541,37 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, struct skl *skl) { - struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, path_found = 0; - struct skl_dapm_path_list *path_list, *tmp_list; + int ret = 0, i; struct skl_sst *ctx = skl->skl_sst; - sink = w; - sink_mconfig = sink->priv; + sink_mconfig = w->priv; /* Stop the pipe */ ret = skl_stop_pipe(ctx, sink_mconfig->pipe); if (ret) return ret; - /* - * This list, dapm_path_list handling here does not need any locks - * as we are under dapm lock while handling widget events. - * List can be manipulated safely only under dapm widgets handler - * routines - */ - list_for_each_entry_safe(path_list, tmp_list, - &skl->dapm_path_list, node) { - if (path_list->dapm_path->sink == sink) { - dev_dbg(ctx->dev, "Path found = %s\n", - path_list->dapm_path->name); - source = path_list->dapm_path->source; - src_mconfig = source->priv; - path_found = 1; + for (i = 0; i < sink_mconfig->max_in_queue; i++) { + if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { + src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; + if (!src_mconfig) + continue; + /* + * If path_found == 1, that means pmd for source + * pipe has not occurred, source is connected to + * some other sink. so its responsibility of sink + * to unbind itself from source. + */ + ret = skl_stop_pipe(ctx, src_mconfig->pipe); + if (ret < 0) + return ret; - list_del(&path_list->node); - kfree(path_list); - break; + ret = skl_unbind_modules(ctx, + src_mconfig, sink_mconfig); } } - /* - * If path_found == 1, that means pmd for source pipe has - * not occurred, source is connected to some other sink. - * so its responsibility of sink to unbind itself from source. - */ - if (path_found) { - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; - - ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); - } - return ret; } @@ -653,14 +625,11 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, struct skl *skl) { - struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, path_found = 0; - struct skl_dapm_path_list *path_list, *tmp_path_list; + int ret = 0, i; struct skl_sst *ctx = skl->skl_sst; - source = w; - src_mconfig = source->priv; + src_mconfig = w->priv; skl_tplg_free_pipe_mcps(skl, src_mconfig); /* Stop the pipe since this is a mixin module */ @@ -668,32 +637,23 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, if (ret) return ret; - list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) { - if (path_list->dapm_path->source == source) { - dev_dbg(ctx->dev, "Path found = %s\n", - path_list->dapm_path->name); - sink = path_list->dapm_path->sink; - sink_mconfig = sink->priv; - path_found = 1; - - list_del(&path_list->node); - kfree(path_list); - break; + for (i = 0; i < src_mconfig->max_out_queue; i++) { + if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { + sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; + if (!sink_mconfig) + continue; + /* + * This is a connecter and if path is found that means + * unbind between source and sink has not happened yet + */ + ret = skl_stop_pipe(ctx, sink_mconfig->pipe); + if (ret < 0) + return ret; + ret = skl_unbind_modules(ctx, src_mconfig, + sink_mconfig); } } - /* - * This is a connector and if path is found that means - * unbind between source and sink has not happened yet - */ - if (path_found) { - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; - - ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); - } - return ret; } diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index cd8768308f29..1b35cb6c397a 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -280,11 +280,6 @@ struct skl_pipeline { struct list_head node; }; -struct skl_dapm_path_list { - struct snd_soc_dapm_path *dapm_path; - struct list_head node; -}; - static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index dd2e79ae45a8..f803ebb10605 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -67,7 +67,6 @@ struct skl { struct skl_dsp_resource resource; struct list_head ppl_list; - struct list_head dapm_path_list; }; #define skl_to_ebus(s) (&(s)->ebus) -- cgit v1.2.3 From 8724ff17521a91a87971027cf78631030091bc52 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:52 +0900 Subject: ASoC: Intel: Skylake: Add support for virtual dsp widgets In SKL topology routes, some paths can be connected by a widget which are not a DSP FW widget and virtual with respect to firmware. In these case when module has to bind, then the virtual DSP modules needs to skipped till a actual DSP module is found which connects the pipelines. So we need to walk the graph and find a widget which is real in nature. This patch adds that support and splits skl_tplg_pga_dapm_pre_pmu_event() fn with parsing code to skl_tplg_bind_sinks() fn and call that recursively as well as while parsing The patch moves code a bit while splitting so diffstat doesn't tell real picture Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 133 ++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index abbf8e7eb3e7..0c6e7833e652 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -397,40 +397,24 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } -/* - * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA - * we need to do following: - * - Bind to sink pipeline - * Since the sink pipes can be running and we don't get mixer event on - * connect for already running mixer, we need to find the sink pipes - * here and bind to them. This way dynamic connect works. - * - Start sink pipeline, if not running - * - Then run current pipe - */ -static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) +static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, + struct skl *skl, + struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *source, *sink; - struct skl_module_cfg *src_mconfig, *sink_mconfig; + struct snd_soc_dapm_widget *sink = NULL; + struct skl_module_cfg *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; - int ret = 0; - - source = w; - src_mconfig = source->priv; + int ret; - /* - * find which sink it is connected to, bind with the sink, - * if sink is not started, start sink pipe first, then start - * this pipe - */ - snd_soc_dapm_widget_for_each_source_path(w, p) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (!p->connect) continue; dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); + sink = p->sink; /* * here we will check widgets in sink pipelines, so that * can be any widgets type and we are only interested if @@ -440,7 +424,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, is_skl_dsp_widget_type(p->sink)) { sink = p->sink; - src_mconfig = source->priv; sink_mconfig = sink->priv; /* Bind source to sink, mixin is always source */ @@ -454,10 +437,43 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, if (ret) return ret; } - break; } } + if (!sink) + return skl_tplg_bind_sinks(sink, skl, src_mconfig); + + return 0; +} + +/* + * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA + * we need to do following: + * - Bind to sink pipeline + * Since the sink pipes can be running and we don't get mixer event on + * connect for already running mixer, we need to find the sink pipes + * here and bind to them. This way dynamic connect works. + * - Start sink pipeline, if not running + * - Then run current pipe + */ +static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, + struct skl *skl) +{ + struct skl_module_cfg *src_mconfig; + struct skl_sst *ctx = skl->skl_sst; + int ret = 0; + + src_mconfig = w->priv; + + /* + * find which sink it is connected to, bind with the sink, + * if sink is not started, start sink pipe first, then start + * this pipe + */ + ret = skl_tplg_bind_sinks(w, skl, src_mconfig); + if (ret) + return ret; + /* Start source pipe last after starting all sinks */ ret = skl_run_pipe(ctx, src_mconfig->pipe); if (ret) @@ -466,6 +482,38 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } +static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( + struct snd_soc_dapm_widget *w, struct skl *skl) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *src_w = NULL; + struct skl_sst *ctx = skl->skl_sst; + + snd_soc_dapm_widget_for_each_source_path(w, p) { + src_w = p->source; + if (!p->connect) + continue; + + dev_dbg(ctx->dev, "sink widget=%s\n", w->name); + dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + + /* + * here we will check widgets in sink pipelines, so that can + * be any widgets type and we are only interested if they are + * ones used for SKL so check that first + */ + if ((p->source->priv != NULL) && + is_skl_dsp_widget_type(p->source)) { + return p->source; + } + } + + if (src_w != NULL) + return skl_get_src_dsp_widget(src_w, skl); + + return NULL; +} + /* * in the Post-PMU event of mixer we need to do following: * - Check if this pipe is running @@ -479,7 +527,6 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, struct skl *skl) { int ret = 0; - struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; @@ -493,32 +540,18 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, * one more sink before this sink got connected, Since source is * started, bind this sink to source and start this pipe. */ - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (!p->connect) - continue; - - dev_dbg(ctx->dev, "sink widget=%s\n", w->name); - dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + source = skl_get_src_dsp_widget(w, skl); + if (source != NULL) { + src_mconfig = source->priv; + sink_mconfig = sink->priv; + src_pipe_started = 1; /* - * here we will check widgets in sink pipelines, so that - * can be any widgets type and we are only interested if - * they are ones used for SKL so check that first + * check pipe state, then no need to bind or start the + * pipe */ - if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source)) { - source = p->source; - src_mconfig = source->priv; - sink_mconfig = sink->priv; - src_pipe_started = 1; - - /* - * check pipe state, then no need to bind or start - * the pipe - */ - if (src_mconfig->pipe->state != SKL_PIPE_STARTED) - src_pipe_started = 0; - } + if (src_mconfig->pipe->state != SKL_PIPE_STARTED) + src_pipe_started = 0; } if (src_pipe_started) { -- cgit v1.2.3 From d1730c3dd90bfac6dffc29b1575837d45edca8cc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:53 +0900 Subject: ASoC: Intel: Skylake: Fix DSP pipe underrun/overrun issue While rigourous testing of SKL drivers, we noticed underuns and overuns and on debug realized that we need to change driver handling of FE pipe startup and shutdown We need to start DMA and then run pipe together and not split these up. Similarly while stopping we should stop pipe and then DMA in a sequence. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 133 +++++++++++++++++++-------------- sound/soc/intel/skylake/skl-topology.c | 13 ++-- 2 files changed, 85 insertions(+), 61 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 1a9cd00c0b0a..2517ec576ffc 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -295,29 +295,101 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream, return skl_tplg_be_update_params(dai, &p_params); } +static int skl_decoupled_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_ext_stream *stream; + int start; + unsigned long cookie; + struct hdac_stream *hstr; + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + if (start) { + snd_hdac_stream_start(hdac_stream(stream), true); + snd_hdac_stream_timecounter_init(hstr, 0); + } else { + snd_hdac_stream_stop(hdac_stream(stream)); + } + + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + return 0; +} + static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct skl *skl = get_skl_ctx(dai->dev); struct skl_sst *ctx = skl->skl_sst; struct skl_module_cfg *mconfig; + int ret; mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); if (!mconfig) return -EIO; switch (cmd) { + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + /* + * Start HOST DMA and Start FE Pipe.This is to make sure that + * there are no underrun/overrun in the case when the FE + * pipeline is started but there is a delay in starting the + * DMA channel on the host. + */ + ret = skl_decoupled_trigger(substream, cmd); + if (ret < 0) + return ret; return skl_run_pipe(ctx, mconfig->pipe); + break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - return skl_stop_pipe(ctx, mconfig->pipe); + case SNDRV_PCM_TRIGGER_STOP: + /* + * Stop FE Pipe first and stop DMA. This is to make sure that + * there are no underrun/overrun in the case if there is a delay + * between the two operations. + */ + ret = skl_stop_pipe(ctx, mconfig->pipe); + if (ret < 0) + return ret; + + ret = skl_decoupled_trigger(substream, cmd); + break; default: - return 0; + return -EINVAL; } + + return 0; } static int skl_link_hw_params(struct snd_pcm_substream *substream, @@ -685,66 +757,15 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream, return 0; } -static int skl_decoupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_ext_bus *ebus = get_bus_ctx(substream); - struct hdac_bus *bus = ebus_to_hbus(ebus); - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct hdac_ext_stream *stream; - int start; - unsigned long cookie; - struct hdac_stream *hstr; - - dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name); - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = 1; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = 0; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - if (start) - snd_hdac_stream_start(hdac_stream(stream), true); - else - snd_hdac_stream_stop(hdac_stream(stream)); - - if (start) - snd_hdac_stream_timecounter_init(hstr, 0); - - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct hdac_ext_bus *ebus = get_bus_ctx(substream); - if (ebus->ppcap) - return skl_decoupled_trigger(substream, cmd); - else + if (!ebus->ppcap) return skl_coupled_trigger(substream, cmd); + + return 0; } /* calculate runtime delay from LPIB */ diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 0c6e7833e652..2f263ddd696d 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -433,7 +433,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, /* Start sinks pipe first */ if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + if (sink_mconfig->pipe->conn_type != + SKL_PIPE_CONN_TYPE_FE) + ret = skl_run_pipe(ctx, + sink_mconfig->pipe); if (ret) return ret; } @@ -475,9 +478,8 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return ret; /* Start source pipe last after starting all sinks */ - ret = skl_run_pipe(ctx, src_mconfig->pipe); - if (ret) - return ret; + if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) + return skl_run_pipe(ctx, src_mconfig->pipe); return 0; } @@ -559,7 +561,8 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, if (ret) return ret; - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) + ret = skl_run_pipe(ctx, sink_mconfig->pipe); } return ret; -- cgit v1.2.3 From 9a03cb49c138146476261e5f9e3189a2631e70c1 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:54 +0900 Subject: ASoC: Intel: Skylake: Fix to remove be copier widget power check ASoC core already checks if BE is active. If BE is active, hw_params callback is ignored. This patch removes the redundant check in driver for copier widget power check in update be hw_params. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2f263ddd696d..7311cd317d87 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -950,18 +950,13 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, if (p->connect && is_skl_dsp_widget_type(p->source) && p->source->priv) { - if (!p->source->power) { - ret = skl_tplg_be_fill_pipe_params( - dai, p->source->priv, - params); - if (ret < 0) - return ret; - } else { - return -EBUSY; - } + ret = skl_tplg_be_fill_pipe_params(dai, + p->source->priv, params); + if (ret < 0) + return ret; } else { - ret = skl_tplg_be_set_src_pipe_params( - dai, p->source, params); + ret = skl_tplg_be_set_src_pipe_params(dai, + p->source, params); if (ret < 0) return ret; } @@ -980,15 +975,10 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, if (p->connect && is_skl_dsp_widget_type(p->sink) && p->sink->priv) { - if (!p->sink->power) { - ret = skl_tplg_be_fill_pipe_params( - dai, p->sink->priv, params); - if (ret < 0) - return ret; - } else { - return -EBUSY; - } - + ret = skl_tplg_be_fill_pipe_params(dai, + p->sink->priv, params); + if (ret < 0) + return ret; } else { ret = skl_tplg_be_set_sink_pipe_params( dai, p->sink, params); -- cgit v1.2.3 From 4cd9899f0d16b475e31b20771de6f580b977daa4 Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Tue, 27 Oct 2015 09:22:55 +0900 Subject: ASoC: Intel: Skylake: Add multiple pin formats The module pin formats are considered homogeneous, but some modules can have different pcm formats on different pins, like reference signal for a module. This patch add support for configuration of each pin of module and allows us to specify if pins and homogeneous or heterogeneous Signed-off-by: Hardik T Shah Signed-off-by: Omair M Abdullah Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 8 +-- sound/soc/intel/skylake/skl-topology.c | 90 ++++++++++++++++------------ sound/soc/intel/skylake/skl-topology.h | 12 +++- sound/soc/intel/skylake/skl-tplg-interface.h | 18 +++++- 4 files changed, 83 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index ee059589e9f0..07d3bf4a8bdd 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -280,7 +280,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_base_cfg *base_cfg) { - struct skl_module_fmt *format = &mconfig->in_fmt; + struct skl_module_fmt *format = &mconfig->in_fmt[0]; base_cfg->audio_fmt.number_of_channels = (u8)format->channels; @@ -399,7 +399,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_audio_data_format *out_fmt) { - struct skl_module_fmt *format = &mconfig->out_fmt; + struct skl_module_fmt *format = &mconfig->out_fmt[0]; out_fmt->number_of_channels = (u8)format->channels; out_fmt->s_freq = format->s_freq; @@ -423,7 +423,7 @@ static void skl_set_src_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_src_module_cfg *src_mconfig) { - struct skl_module_fmt *fmt = &mconfig->out_fmt; + struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; skl_set_base_module_format(ctx, mconfig, (struct skl_base_cfg *)src_mconfig); @@ -440,7 +440,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_up_down_mixer_cfg *mixer_mconfig) { - struct skl_module_fmt *fmt = &mconfig->out_fmt; + struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; int i = 0; skl_set_base_module_format(ctx, mconfig, diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 7311cd317d87..37e5c4fc0f10 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -129,17 +129,15 @@ static void skl_dump_mconfig(struct skl_sst *ctx, { dev_dbg(ctx->dev, "Dumping config\n"); dev_dbg(ctx->dev, "Input Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq); - dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg); - dev_dbg(ctx->dev, "valid bit depth = %d\n", - mcfg->in_fmt.valid_bit_depth); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels); + dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq); + dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth); dev_dbg(ctx->dev, "Output Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq); - dev_dbg(ctx->dev, "valid bit depth = %d\n", - mcfg->out_fmt.valid_bit_depth); - dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels); + dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth); + dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); } static void skl_tplg_update_params(struct skl_module_fmt *fmt, @@ -171,8 +169,9 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, int in_fixup, out_fixup; struct skl_module_fmt *in_fmt, *out_fmt; - in_fmt = &m_cfg->in_fmt; - out_fmt = &m_cfg->out_fmt; + /* Fixups will be applied to pin 0 only */ + in_fmt = &m_cfg->in_fmt[0]; + out_fmt = &m_cfg->out_fmt[0]; if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (is_fe) { @@ -209,18 +208,25 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, struct skl_module_cfg *mcfg) { int multiplier = 1; + struct skl_module_fmt *in_fmt, *out_fmt; + + + /* Since fixups is applied to pin 0 only, ibs, obs needs + * change for pin 0 only + */ + in_fmt = &mcfg->in_fmt[0]; + out_fmt = &mcfg->out_fmt[0]; if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - - mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) * - (mcfg->in_fmt.channels) * - (mcfg->in_fmt.bit_depth >> 3) * + mcfg->ibs = (in_fmt->s_freq / 1000) * + (mcfg->in_fmt->channels) * + (mcfg->in_fmt->bit_depth >> 3) * multiplier; - mcfg->obs = (mcfg->out_fmt.s_freq / 1000) * - (mcfg->out_fmt.channels) * - (mcfg->out_fmt.bit_depth >> 3) * + mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * + (mcfg->out_fmt->channels) * + (mcfg->out_fmt->bit_depth >> 3) * multiplier; } @@ -786,9 +792,9 @@ int skl_tplg_update_pipe_params(struct device *dev, memcpy(pipe->p_params, params, sizeof(*params)); if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) - format = &mconfig->in_fmt; + format = &mconfig->in_fmt[0]; else - format = &mconfig->out_fmt; + format = &mconfig->out_fmt[0]; /* set the hw_params */ format->s_freq = params->s_freq; @@ -1083,6 +1089,24 @@ static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, return ppl->pipe; } +static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, + struct skl_dfw_module_fmt *src_fmt, + int pins) +{ + int i; + + for (i = 0; i < pins; i++) { + dst_fmt[i].channels = src_fmt[i].channels; + dst_fmt[i].s_freq = src_fmt[i].freq; + dst_fmt[i].bit_depth = src_fmt[i].bit_depth; + dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; + dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; + dst_fmt[i].ch_map = src_fmt[i].ch_map; + dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; + dst_fmt[i].sample_type = src_fmt[i].sample_type; + } +} + /* * Topology core widget load callback * @@ -1121,18 +1145,11 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->max_in_queue = dfw_config->max_in_queue; mconfig->max_out_queue = dfw_config->max_out_queue; mconfig->is_loadable = dfw_config->is_loadable; - mconfig->in_fmt.channels = dfw_config->in_fmt.channels; - mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq; - mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth; - mconfig->in_fmt.valid_bit_depth = - dfw_config->in_fmt.valid_bit_depth; - mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg; - mconfig->out_fmt.channels = dfw_config->out_fmt.channels; - mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq; - mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth; - mconfig->out_fmt.valid_bit_depth = - dfw_config->out_fmt.valid_bit_depth; - mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg; + skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, + MODULE_MAX_IN_PINS); + skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, + MODULE_MAX_OUT_PINS); + mconfig->params_fixup = dfw_config->params_fixup; mconfig->converter = dfw_config->converter; mconfig->m_type = dfw_config->module_type; @@ -1147,10 +1164,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->time_slot = dfw_config->time_slot; mconfig->formats_config.caps_size = dfw_config->caps.caps_size; - mconfig->m_in_pin = devm_kzalloc(bus->dev, - (mconfig->max_in_queue) * - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); + mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * + sizeof(*mconfig->m_in_pin), + GFP_KERNEL); if (!mconfig->m_in_pin) return -ENOMEM; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 1b35cb6c397a..3b63450c6d5e 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -36,6 +36,9 @@ /* Maximum number of coefficients up down mixer module */ #define UP_DOWN_MIXER_MAX_COEFF 6 +#define MODULE_MAX_IN_PINS 8 +#define MODULE_MAX_OUT_PINS 8 + enum skl_channel_index { SKL_CHANNEL_LEFT = 0, SKL_CHANNEL_RIGHT = 1, @@ -178,6 +181,9 @@ struct skl_module_fmt { u32 bit_depth; u32 valid_bit_depth; u32 ch_cfg; + u32 interleaving_style; + u32 sample_type; + u32 ch_map; }; struct skl_module_cfg; @@ -247,8 +253,10 @@ enum skl_module_state { struct skl_module_cfg { struct skl_module_inst_id id; - struct skl_module_fmt in_fmt; - struct skl_module_fmt out_fmt; + bool homogenous_inputs; + bool homogenous_outputs; + struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS]; + struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS]; u8 max_in_queue; u8 max_out_queue; u8 in_queue_mask; diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 2bc396d54cbe..7bd9af7ee15c 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -110,6 +110,17 @@ enum skl_dev_type { SKL_DEVICE_NONE }; +enum module_pin_type { + /* All pins of the module takes same PCM inputs or outputs + * e.g. mixout + */ + SKL_PIN_TYPE_HOMOGENEOUS, + /* All pins of the module takes different PCM inputs or outputs + * e.g mux + */ + SKL_PIN_TYPE_HETEROGENEOUS, +}; + struct skl_dfw_module_pin { u16 module_id; u16 instance_id; @@ -121,6 +132,9 @@ struct skl_dfw_module_fmt { u32 bit_depth; u32 valid_bit_depth; u32 ch_cfg; + u32 interleaving_style; + u32 sample_type; + u32 ch_map; } __packed; struct skl_dfw_module_caps { @@ -156,8 +170,8 @@ struct skl_dfw_module { u8 is_dynamic_in_pin; u8 is_dynamic_out_pin; struct skl_dfw_pipe pipe; - struct skl_dfw_module_fmt in_fmt; - struct skl_dfw_module_fmt out_fmt; + struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE]; + struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE]; struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE]; struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE]; struct skl_dfw_module_caps caps; -- cgit v1.2.3 From 04afbbbb1cbacb4b18b2e30dd2b5b83531ecf01d Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Tue, 27 Oct 2015 09:22:56 +0900 Subject: ASoC: Intel: Skylake: Update the topology interface structure This patch updates the topology interface structure alignment and also updates the Sample interleaving defines Signed-off-by: Hardik T Shah Signed-off-by: Omair M Abdullah Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.h | 7 +-- sound/soc/intel/skylake/skl-tplg-interface.h | 69 +++++++++++++++++++++------- 2 files changed, 54 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 3b63450c6d5e..4b0a59898676 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -58,12 +58,6 @@ enum skl_bitdepth { SKL_DEPTH_INVALID }; -enum skl_interleaving { - /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */ - SKL_INTERLEAVING_PER_CHANNEL = 0, - /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */ - SKL_INTERLEAVING_PER_SAMPLE = 1, -}; enum skl_s_freq { SKL_FS_8000 = 8000, @@ -253,6 +247,7 @@ enum skl_module_state { struct skl_module_cfg { struct skl_module_inst_id id; + u8 domain; bool homogenous_inputs; bool homogenous_outputs; struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS]; diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 7bd9af7ee15c..aeb8f251675a 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -72,6 +72,7 @@ enum skl_ch_cfg { SKL_CH_CFG_DUAL_MONO = 9, SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10, SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11, + SKL_CH_CFG_4_CHANNEL = 12, SKL_CH_CFG_INVALID }; @@ -110,6 +111,25 @@ enum skl_dev_type { SKL_DEVICE_NONE }; +/** + * enum skl_interleaving - interleaving style + * + * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN] + * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN] + */ +enum skl_interleaving { + SKL_INTERLEAVING_PER_CHANNEL = 0, + SKL_INTERLEAVING_PER_SAMPLE = 1, +}; + +enum skl_sample_type { + SKL_SAMPLE_TYPE_INT_MSB = 0, + SKL_SAMPLE_TYPE_INT_LSB = 1, + SKL_SAMPLE_TYPE_INT_SIGNED = 2, + SKL_SAMPLE_TYPE_INT_UNSIGNED = 3, + SKL_SAMPLE_TYPE_FLOAT = 4 +}; + enum module_pin_type { /* All pins of the module takes same PCM inputs or outputs * e.g. mixout @@ -138,6 +158,9 @@ struct skl_dfw_module_fmt { } __packed; struct skl_dfw_module_caps { + u32 set_params:1; + u32 rsvd:31; + u32 param_id; u32 caps_size; u32 caps[HDA_SST_CFG_MAX]; }; @@ -145,30 +168,41 @@ struct skl_dfw_module_caps { struct skl_dfw_pipe { u8 pipe_id; u8 pipe_priority; - u16 conn_type; - u32 memory_pages; + u16 conn_type:4; + u16 rsvd:4; + u16 memory_pages:8; } __packed; struct skl_dfw_module { u16 module_id; u16 instance_id; u32 max_mcps; - u8 core_id; - u8 max_in_queue; - u8 max_out_queue; - u8 is_loadable; - u8 conn_type; - u8 dev_type; - u8 hw_conn_type; - u8 time_slot; + u32 mem_pages; u32 obs; u32 ibs; - u32 params_fixup; - u32 converter; - u32 module_type; u32 vbus_id; - u8 is_dynamic_in_pin; - u8 is_dynamic_out_pin; + + u32 max_in_queue:8; + u32 max_out_queue:8; + u32 time_slot:8; + u32 core_id:4; + u32 rsvd1:4; + + u32 module_type:8; + u32 conn_type:4; + u32 dev_type:4; + u32 hw_conn_type:4; + u32 rsvd2:12; + + u32 params_fixup:8; + u32 converter:8; + u32 input_pin_type:1; + u32 output_pin_type:1; + u32 is_dynamic_in_pin:1; + u32 is_dynamic_out_pin:1; + u32 is_loadable:1; + u32 rsvd3:11; + struct skl_dfw_pipe pipe; struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE]; struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE]; @@ -178,8 +212,11 @@ struct skl_dfw_module { } __packed; struct skl_dfw_algo_data { + u32 set_params:1; + u32 rsvd:31; + u32 param_id; u32 max; - char *params; + char params[0]; } __packed; #endif -- cgit v1.2.3 From 65aecfa884d5436dede4c4bdfbc33e4ea8026cad Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Tue, 27 Oct 2015 09:22:57 +0900 Subject: ASoC: Intel: Skylake: Add support for module GUIDs The DSP FW specifies loadable modules using GUIDs so add support to specify the GUIDs from topology Signed-off-by: Hardik T Shah Signed-off-by: Omair M Abdullah Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 4 ++++ sound/soc/intel/skylake/skl-topology.h | 1 + sound/soc/intel/skylake/skl-tplg-interface.h | 3 +++ 3 files changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 37e5c4fc0f10..3c5f06235889 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1164,6 +1164,10 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->time_slot = dfw_config->time_slot; mconfig->formats_config.caps_size = dfw_config->caps.caps_size; + if (dfw_config->is_loadable) + memcpy(mconfig->guid, dfw_config->uuid, + ARRAY_SIZE(dfw_config->uuid)); + mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * sizeof(*mconfig->m_in_pin), GFP_KERNEL); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 4b0a59898676..57cb7b8dd269 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -246,6 +246,7 @@ enum skl_module_state { }; struct skl_module_cfg { + char guid[SKL_UUID_STR_SZ]; struct skl_module_inst_id id; u8 domain; bool homogenous_inputs; diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index aeb8f251675a..20c068754d08 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -32,6 +32,7 @@ #define MAX_IN_QUEUE 8 #define MAX_OUT_QUEUE 8 +#define SKL_UUID_STR_SZ 40 /* Event types goes here */ /* Reserve event type 0 for no event handlers */ enum skl_event_types { @@ -174,6 +175,8 @@ struct skl_dfw_pipe { } __packed; struct skl_dfw_module { + char uuid[SKL_UUID_STR_SZ]; + u16 module_id; u16 instance_id; u32 max_mcps; -- cgit v1.2.3 From 16882d24b3f8c402caf56326aa7bf0448d70d8e6 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:58 +0900 Subject: ASoC: Intel: Skylake: Ignore rate check for DMIC link DMIC NHLT entry is sample rate agnostic, so ignore the rate checks for DMIC type Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 3ff22eba5875..6e4b21cdb1bd 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -55,7 +55,7 @@ void skl_nhlt_free(void *addr) static struct nhlt_specific_cfg *skl_get_specific_cfg( struct device *dev, struct nhlt_fmt *fmt, - u8 no_ch, u32 rate, u16 bps) + u8 no_ch, u32 rate, u16 bps, u8 linktype) { struct nhlt_specific_cfg *sp_config; struct wav_fmt *wfmt; @@ -68,11 +68,17 @@ static struct nhlt_specific_cfg *skl_get_specific_cfg( wfmt = &fmt_config->fmt_ext.fmt; dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, wfmt->bits_per_sample, wfmt->samples_per_sec); - if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate && - wfmt->bits_per_sample == bps) { + if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { + /* + * if link type is dmic ignore rate check as the blob is + * generic for all rates + */ sp_config = &fmt_config->config; + if (linktype == NHLT_LINK_DMIC) + return sp_config; - return sp_config; + if (wfmt->samples_per_sec == rate) + return sp_config; } fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + @@ -128,7 +134,8 @@ struct nhlt_specific_cfg if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); - sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps); + sp_config = skl_get_specific_cfg(dev, fmt, num_ch, + s_rate, bps, link_type); if (sp_config) return sp_config; } -- cgit v1.2.3 From 3e81f1a3c702641227cc59c0dd7a2a5bec741e0f Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:22:59 +0900 Subject: ASoC: Intel: Skylake: Fix to remove channel_map calculation Widget FW topology private data already has the information on the channel map, ch_cfg and interleaving. This patch removes the calculation of channel_map in driver and reads the value directly from widget private data. Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 98 ++-------------------------------- 1 file changed, 5 insertions(+), 93 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 07d3bf4a8bdd..bfde60bb8119 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -182,94 +182,6 @@ enum skl_bitdepth skl_get_bit_depth(int params) } } -static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg) -{ - u32 config; - - switch (ch_cfg) { - case SKL_CH_CFG_MONO: - config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT); - break; - - case SKL_CH_CFG_STEREO: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4)); - break; - - case SKL_CH_CFG_2_1: - config = (0xFFFFF000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4) - | (SKL_CHANNEL_LFE << 8)); - break; - - case SKL_CH_CFG_3_0: - config = (0xFFFFF000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8)); - break; - - case SKL_CH_CFG_3_1: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LFE << 12)); - break; - - case SKL_CH_CFG_QUATRO: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4) - | (SKL_CHANNEL_LEFT_SURROUND << 8) - | (SKL_CHANNEL_RIGHT_SURROUND << 12)); - break; - - case SKL_CH_CFG_4_0: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_CENTER_SURROUND << 12)); - break; - - case SKL_CH_CFG_5_0: - config = (0xFFF00000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LEFT_SURROUND << 12) - | (SKL_CHANNEL_RIGHT_SURROUND << 16)); - break; - - case SKL_CH_CFG_5_1: - config = (0xFF000000 | SKL_CHANNEL_CENTER - | (SKL_CHANNEL_LEFT << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LEFT_SURROUND << 12) - | (SKL_CHANNEL_RIGHT_SURROUND << 16) - | (SKL_CHANNEL_LFE << 20)); - break; - - case SKL_CH_CFG_DUAL_MONO: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_LEFT << 4)); - break; - - case SKL_CH_CFG_I2S_DUAL_STEREO_0: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4)); - break; - - case SKL_CH_CFG_I2S_DUAL_STEREO_1: - config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8) - | (SKL_CHANNEL_RIGHT << 12)); - break; - - default: - config = 0xFFFFFFFF; - break; - - } - - return config; -} - /* * Each module in DSP expects a base module configuration, which consists of * PCM format information, which we calculate in driver and resource values @@ -293,10 +205,9 @@ static void skl_set_base_module_format(struct skl_sst *ctx, format->bit_depth, format->valid_bit_depth, format->ch_cfg); - base_cfg->audio_fmt.channel_map = skl_create_channel_map( - base_cfg->audio_fmt.ch_cfg); + base_cfg->audio_fmt.channel_map = format->ch_map; - base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL; + base_cfg->audio_fmt.interleaving = format->interleaving_style; base_cfg->cps = mconfig->mcps; base_cfg->ibs = mconfig->ibs; @@ -407,8 +318,9 @@ static void skl_setup_out_format(struct skl_sst *ctx, out_fmt->valid_bit_depth = format->valid_bit_depth; out_fmt->ch_cfg = format->ch_cfg; - out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg); - out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL; + out_fmt->channel_map = format->ch_map; + out_fmt->interleaving = format->interleaving_style; + out_fmt->sample_type = format->sample_type; dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", out_fmt->number_of_channels, format->s_freq, format->bit_depth); -- cgit v1.2.3 From 61722f447243d4d8f249a9359ffc5a21c1587f36 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 27 Oct 2015 09:23:00 +0900 Subject: ASoC: Intel: Skylake: Fix PM behaviour The driver runtime behaviour is fine but in suspend, we missed setting the DSP to suspend and also missed resuming DSP on resume. Fix this by having common SKL suspend and resume routines which power up/down links, suspend/resume DSP and other common routines, and call these routines from both runtime as well as system PM handlers Signed-off-by: Jayachandran B Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 60 +++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 211ef6e2fa21..9b94a8cdf9bd 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -129,6 +129,37 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) return 0; } +#ifdef CONFIG_PM +static int _skl_suspend(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + int ret; + + snd_hdac_ext_bus_link_power_down_all(ebus); + + ret = skl_suspend_dsp(skl); + if (ret < 0) + return ret; + + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_enter_link_reset(bus); + + return 0; +} + +static int _skl_resume(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + skl_init_pci(skl); + snd_hdac_bus_init_chip(bus, true); + + return skl_resume_dsp(skl); +} +#endif + #ifdef CONFIG_PM_SLEEP /* * power management @@ -137,26 +168,16 @@ static int skl_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); - struct hdac_bus *bus = ebus_to_hbus(ebus); - - snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_enter_link_reset(bus); - return 0; + return _skl_suspend(ebus); } static int skl_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); - struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *hda = ebus_to_skl(ebus); - - skl_init_pci(hda); - snd_hdac_bus_init_chip(bus, 1); - - return 0; + return _skl_resume(ebus); } #endif /* CONFIG_PM_SLEEP */ @@ -166,24 +187,13 @@ static int skl_runtime_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *skl = ebus_to_skl(ebus); - int ret; dev_dbg(bus->dev, "in %s\n", __func__); /* enable controller wake up event */ snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK); - snd_hdac_ext_bus_link_power_down_all(ebus); - - ret = skl_suspend_dsp(skl); - if (ret < 0) - return ret; - - snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_enter_link_reset(bus); - - return 0; + return _skl_suspend(ebus); } static int skl_runtime_resume(struct device *dev) @@ -204,7 +214,7 @@ static int skl_runtime_resume(struct device *dev) /* disable controller Wake Up event */ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); - return skl_resume_dsp(skl); + return _skl_resume(ebus); } #endif /* CONFIG_PM */ -- cgit v1.2.3 From 677165f76de2c785d4874d69be10dc21a5236bfb Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 29 Oct 2015 12:31:34 +0900 Subject: ASoC: Intel: Skylake: Fix the SSP0 Fmt fixup to 24 bit SSP0 FMT uses 24 bits so fix to the value to 24 bits Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index a73a431bd8b7..e6af48491229 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -112,12 +112,15 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); /* The output is 48KHz, stereo, 16bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } -- cgit v1.2.3 From aaec7e9f789eff57f620f38a96d0118b2a7d71c3 Mon Sep 17 00:00:00 2001 From: Vincent Stehlé Date: Thu, 29 Oct 2015 23:04:41 +0100 Subject: ASoC: Intel: Skylake: fix typo in sizeof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The size of the pointer to a data structure to send is erroneously passed to sst_ipc_tx_message_wait() as its tx_bytes argument. It should be given the size of the pointed skl_ipc_dxstate_info structure instead. Coincidentally, both the pointer and the structure have the same size of 8 bytes on a 64 bit machine, which "masks" the issue. Compiling for 32 bit reveals the issue more clearly. Fix the typo for correctness, and to make the code robust to future evolutions of the skl_ipc_dxstate_info structure size. This fixes the following coccicheck error: sound/soc/intel/skylake/skl-sst-ipc.c:641:8-14: ERROR: application of sizeof to pointer Signed-off-by: Vincent Stehlé Cc: Subhransu S. Prusty Cc: Jeeja KP Cc: Vinod Koul Cc: Mark Brown Cc: trivial@kernel.org Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 3345ea0d4414..95679c02c6ee 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -650,7 +650,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - dx, sizeof(dx), NULL, 0); + dx, sizeof(*dx), NULL, 0); if (ret < 0) { dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); return ret; -- cgit v1.2.3 From b4fe965f4e949d0d965561801de89e90b673b65a Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 30 Oct 2015 20:34:19 +0530 Subject: ASoC: Intel: Skylake: Fix to cleanup if skl_sst_dsp_init fails This patch fixes the below warning reported by Dan by invoking skl_sst_dsp_cleanup() in cleanup path on error and not bailing out sound/soc/intel/skylake/skl-sst.c:270 skl_sst_dsp_init() info: ignoring unreachable code. Reported-by: Dan Carpenter Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 3b83dc99f1d4..5c5a244942ef 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -259,15 +259,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ret = sst->fw_ops.load_fw(sst); if (ret < 0) { dev_err(dev, "Load base fw failed : %d", ret); - return ret; + goto cleanup; } if (dsp) *dsp = skl; - return 0; + return ret; - skl_ipc_free(&skl->ipc); +cleanup: + skl_sst_dsp_cleanup(dev, skl); return ret; } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); -- cgit v1.2.3 From c7b2a44410a1029f1cee4ad0b86588c9a0f83a6c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 30 Oct 2015 20:34:20 +0530 Subject: ASoC: Intel: Skylake: Fix substream dereference before check Smatch warns that we dereferenced substream before check, so fix this by initializing ebus after the check sound/soc/intel/skylake/skl-pcm.c:802 skl_get_position() warn: variable dereferenced before check 'substream->runtime' Reported by: Dan Carpenter Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 2517ec576ffc..e652d58bd9a9 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -807,7 +807,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, { struct hdac_stream *hstr = hdac_stream(hstream); struct snd_pcm_substream *substream = hstr->substream; - struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_bus *ebus; unsigned int pos; int delay; @@ -818,6 +818,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, pos = 0; if (substream->runtime) { + ebus = get_bus_ctx(substream); delay = skl_get_delay_from_lpib(ebus, hstream, pos) + codec_delay; substream->runtime->delay += delay; -- cgit v1.2.3 From 7ae3cb15590ea768323b5e5a6be1769f19e91044 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:10 +0530 Subject: ASoC: Intel: Skylake: Fix resource cleanup on teardown MCPS free was being done from PGA context which will free up MCPS for only last modules in a pipe and not the rest causing MCPS leak and eventual audio loss due to no "free" MCPS. This needs to be freed for every module while cleaning up the modules, so move the check to skl_tplg_mixer_dapm_post_pmd_event() Signed-off-by: Mohan Krishna Velaga Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 3c5f06235889..2b6ee22b5ea2 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -640,6 +640,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; + skl_tplg_free_pipe_mcps(skl, dst_module); if (src_module == NULL) { src_module = dst_module; continue; @@ -673,7 +674,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, src_mconfig = w->priv; - skl_tplg_free_pipe_mcps(skl, src_mconfig); /* Stop the pipe since this is a mixin module */ ret = skl_stop_pipe(ctx, src_mconfig->pipe); if (ret) -- cgit v1.2.3 From 95f098014815b330838b1173d3d7bcea3b481242 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:11 +0530 Subject: ASoC: Intel: Move apci find machine routines This code to find the machine is common for all drivers so move it to a separate file and header for use in other drivers Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 3 +-- sound/soc/intel/common/sst-acpi.c | 33 +------------------------ sound/soc/intel/common/sst-acpi.h | 28 +++++++++++++++++++++ sound/soc/intel/common/sst-match-acpi.c | 43 +++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 sound/soc/intel/common/sst-acpi.h create mode 100644 sound/soc/intel/common/sst-match-acpi.c (limited to 'sound') diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index d9105584c51f..658edce16761 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,5 +1,5 @@ snd-soc-sst-dsp-objs := sst-dsp.o -snd-soc-sst-acpi-objs := sst-acpi.o +snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o snd-soc-sst-ipc-objs := sst-ipc.o ifneq ($(CONFIG_DW_DMAC_CORE),) @@ -8,4 +8,3 @@ endif obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o - diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 67b6d3d52f57..94a43e6fcf88 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -21,21 +21,12 @@ #include #include "sst-dsp.h" +#include "sst-acpi.h" #define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000 #define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000 #define SST_LPT_DSP_DMA_SIZE (1024 - 1) -/* Descriptor for SST ASoC machine driver */ -struct sst_acpi_mach { - /* ACPI ID for the matching machine driver. Audio codec for instance */ - const u8 id[ACPI_ID_LEN]; - /* machine driver name */ - const char *drv_name; - /* firmware file name */ - const char *fw_filename; -}; - /* Descriptor for setting up SST platform data */ struct sst_acpi_desc { const char *drv_name; @@ -88,28 +79,6 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context) return; } -static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - -static struct sst_acpi_mach *sst_acpi_find_machine( - struct sst_acpi_mach *machines) -{ - struct sst_acpi_mach *mach; - bool found = false; - - for (mach = machines; mach->id[0]; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->id, - sst_acpi_mach_match, - &found, NULL)) && found) - return mach; - - return NULL; -} - static int sst_acpi_probe(struct platform_device *pdev) { const struct acpi_device_id *id; diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h new file mode 100644 index 000000000000..1dc059590ead --- /dev/null +++ b/sound/soc/intel/common/sst-acpi.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013-15, Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +/* acpi match */ +struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); + +/* Descriptor for SST ASoC machine driver */ +struct sst_acpi_mach { + /* ACPI ID for the matching machine driver. Audio codec for instance */ + const u8 id[ACPI_ID_LEN]; + /* machine driver name */ + const char *drv_name; + /* firmware file name */ + const char *fw_filename; +}; diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c new file mode 100644 index 000000000000..dd077e116d25 --- /dev/null +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -0,0 +1,43 @@ +/* + * sst_match_apci.c - SST (LPE) match for ACPI enumeration. + * + * Copyright (c) 2013-15, Intel Corporation. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include +#include +#include +#include + +#include "sst-acpi.h" + +static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, + void *context, void **ret) +{ + *(bool *)context = true; + return AE_OK; +} + +struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) +{ + struct sst_acpi_mach *mach; + bool found = false; + + for (mach = machines; mach->id[0]; mach++) + if (ACPI_SUCCESS(acpi_get_devices(mach->id, + sst_acpi_mach_match, + &found, NULL)) && found) + return mach; + + return NULL; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_machine); -- cgit v1.2.3 From 12cc291b0b58503b3b0e629ac605218df1851ce1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:12 +0530 Subject: ASoC: Intel: Atom: move atom driver to common acpi match This patch moves the atom driver to use the common acpi match functions. Since atom driver has few more information in machine table, these are appended to table and set to NULL for common driver Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/atom/sst/sst_acpi.c | 67 +++++++++++-------------------------- sound/soc/intel/common/sst-acpi.c | 8 ++--- sound/soc/intel/common/sst-acpi.h | 5 +++ 4 files changed, 29 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 7b778ab85f8b..13a762172b5d 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -24,6 +24,7 @@ config SND_SST_IPC_PCI config SND_SST_IPC_ACPI tristate select SND_SST_IPC + select SND_SOC_INTEL_SST depends on ACPI config SND_SOC_INTEL_SST diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index bb19b5801466..f3d109eb3800 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -40,18 +40,9 @@ #include #include "../sst-mfld-platform.h" #include "../../common/sst-dsp.h" +#include "../../common/sst-acpi.h" #include "sst.h" -struct sst_machines { - char *codec_id; - char board[32]; - char machine[32]; - void (*machine_quirk)(void); - char firmware[FW_NAME_SIZE]; - struct sst_platform_info *pdata; - -}; - /* LPE viewpoint addresses */ #define SST_BYT_IRAM_PHY_START 0xff2c0000 #define SST_BYT_IRAM_PHY_END 0xff2d4000 @@ -223,37 +214,16 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) return 0; } -static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - -static struct sst_machines *sst_acpi_find_machine( - struct sst_machines *machines) -{ - struct sst_machines *mach; - bool found = false; - - for (mach = machines; mach->codec_id; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id, - sst_acpi_mach_match, - &found, NULL)) && found) - return mach; - - return NULL; -} - static int sst_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret = 0; struct intel_sst_drv *ctx; const struct acpi_device_id *id; - struct sst_machines *mach; + struct sst_acpi_mach *mach; struct platform_device *mdev; struct platform_device *plat_dev; + struct sst_platform_info *pdata; unsigned int dev_id; id = acpi_match_device(dev->driver->acpi_match_table, dev); @@ -261,12 +231,13 @@ static int sst_acpi_probe(struct platform_device *pdev) return -ENODEV; dev_dbg(dev, "for %s", id->id); - mach = (struct sst_machines *)id->driver_data; + mach = (struct sst_acpi_mach *)id->driver_data; mach = sst_acpi_find_machine(mach); if (mach == NULL) { dev_err(dev, "No matching machine driver found\n"); return -ENODEV; } + pdata = mach->pdata; ret = kstrtouint(id->id, 16, &dev_id); if (ret < 0) { @@ -276,16 +247,16 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "ACPI device id: %x\n", dev_id); - plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0); + plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0); if (IS_ERR(plat_dev)) { - dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform); + dev_err(dev, "Failed to create machine device: %s\n", pdata->platform); return PTR_ERR(plat_dev); } /* Create platform device for sst machine driver */ - mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0); + mdev = platform_device_register_data(dev, mach->drv_name, -1, NULL, 0); if (IS_ERR(mdev)) { - dev_err(dev, "Failed to create machine device: %s\n", mach->machine); + dev_err(dev, "Failed to create machine device: %s\n", mach->drv_name); return PTR_ERR(mdev); } @@ -294,8 +265,8 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; /* Fill sst platform data */ - ctx->pdata = mach->pdata; - strcpy(ctx->firmware_name, mach->firmware); + ctx->pdata = pdata; + strcpy(ctx->firmware_name, mach->fw_filename); ret = sst_platform_get_resources(ctx); if (ret) @@ -342,22 +313,22 @@ static int sst_acpi_remove(struct platform_device *pdev) return 0; } -static struct sst_machines sst_acpi_bytcr[] = { - {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin", +static struct sst_acpi_mach sst_acpi_bytcr[] = { + {"10EC5640", "bytt100_rt5640", "intel/fw_sst_0f28.bin", "T100", NULL, &byt_rvp_platform_data }, {}, }; /* Cherryview-based platforms: CherryTrail and Braswell */ -static struct sst_machines sst_acpi_chv[] = { - {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", +static struct sst_acpi_mach sst_acpi_chv[] = { + {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, + {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", + {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", + {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, - "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, }; diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 94a43e6fcf88..7a85c576dad3 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -180,7 +180,7 @@ static int sst_acpi_remove(struct platform_device *pdev) } static struct sst_acpi_mach haswell_machines[] = { - { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" }, + { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL }, {} }; @@ -198,7 +198,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = { }; static struct sst_acpi_mach broadwell_machines[] = { - { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" }, + { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, {} }; @@ -216,8 +216,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { }; static struct sst_acpi_mach baytrail_machines[] = { - { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, - { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, + { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, + { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, {} }; diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 1dc059590ead..3ee3b7ab5d03 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -25,4 +25,9 @@ struct sst_acpi_mach { const char *drv_name; /* firmware file name */ const char *fw_filename; + + /* board name */ + const char *board; + void (*machine_quirk)(void); + void *pdata; }; -- cgit v1.2.3 From cc18c5fdcdcf06f75ff196dedfcde823a6556d7d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:13 +0530 Subject: ASoC: Intel: Skylake: Fix skl machine driver creation Now that we have common match code in place, update the SKL driver to use the common match routines for driver entry creation for UEFI BIOS systems Signed-off-by: Jeeja KP Signed-off-by: Omair M Abdullah Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 55 +++++++++++++++++++++++++++++++++++++++++-- sound/soc/intel/skylake/skl.h | 1 + 2 files changed, 54 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 9b94a8cdf9bd..59336cbc10dd 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@ #include #include #include +#include "../common/sst-acpi.h" #include "skl.h" /* @@ -251,6 +252,42 @@ static int skl_free(struct hdac_ext_bus *ebus) return 0; } +static int skl_machine_device_register(struct skl *skl, void *driver_data) +{ + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct platform_device *pdev; + struct sst_acpi_mach *mach = driver_data; + int ret; + + mach = sst_acpi_find_machine(mach); + if (mach == NULL) { + dev_err(bus->dev, "No matching machine driver found\n"); + return -ENODEV; + } + + pdev = platform_device_alloc(mach->drv_name, -1); + if (pdev == NULL) { + dev_err(bus->dev, "platform device alloc failed\n"); + return -EIO; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(bus->dev, "failed to add machine device\n"); + platform_device_put(pdev); + return -EIO; + } + skl->i2s_dev = pdev; + + return 0; +} + +static void skl_machine_device_unregister(struct skl *skl) +{ + if (skl->i2s_dev) + platform_device_unregister(skl->i2s_dev); +} + static int skl_dmic_device_register(struct skl *skl) { struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); @@ -479,10 +516,15 @@ static int skl_probe(struct pci_dev *pci, /* check if dsp is there */ if (ebus->ppcap) { + err = skl_machine_device_register(skl, + (void *)pci_id->driver_data); + if (err < 0) + goto out_free; + err = skl_init_dsp(skl); if (err < 0) { dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_free; + goto out_mach_free; } } if (ebus->mlcap) @@ -517,6 +559,8 @@ out_dmic_free: skl_dmic_device_unregister(skl); out_dsp_free: skl_free_dsp(skl); +out_mach_free: + skl_machine_device_unregister(skl); out_free: skl->init_failed = 1; skl_free(ebus); @@ -534,15 +578,22 @@ static void skl_remove(struct pci_dev *pci) pci_dev_put(pci); skl_platform_unregister(&pci->dev); skl_free_dsp(skl); + skl_machine_device_unregister(skl); skl_dmic_device_unregister(skl); skl_free(ebus); dev_set_drvdata(&pci->dev, NULL); } +static struct sst_acpi_mach sst_skl_devdata[] = { + { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, + {} +}; + /* PCI IDs */ static const struct pci_device_id skl_ids[] = { /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), 0}, + { PCI_DEVICE(0x8086, 0x9d70), + .driver_data = (unsigned long)&sst_skl_devdata}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index f803ebb10605..9b1beed26f0f 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -61,6 +61,7 @@ struct skl { unsigned int init_failed:1; /* delayed init failed */ struct platform_device *dmic_dev; + struct platform_device *i2s_dev; void *nhlt; /* nhlt ptr */ struct skl_sst *skl_sst; /* sst skl ctx */ -- cgit v1.2.3 From 40c3ac46a49da3b01b1802eb4c4ff08626f48546 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:14 +0530 Subject: ASoC: Intel: add fw name to common dsp context In order to pass the fw name to IPC driver for loading fw, we need to add a memeber to store the fw name Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 2151652d37b7..4452cda28874 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -308,6 +308,8 @@ struct sst_dsp { /* SKL data */ + const char *fw_name; + /* To allocate CL dma buffers */ struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; -- cgit v1.2.3 From aecf6fd878eba5182665cccb943205be4c9a0337 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 5 Nov 2015 21:34:15 +0530 Subject: ASoC: Intel: Skylake: Use the fw name from ACPI mach table The firmware name is hard coded which doesnt allow to load different platforms for various platforms so get this name from available machine table and pass it to dsp context for loading Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-sst-dsp.h | 3 ++- sound/soc/intel/skylake/skl-sst.c | 5 +++-- sound/soc/intel/skylake/skl.c | 1 + sound/soc/intel/skylake/skl.h | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index bfde60bb8119..d71b58322cc7 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -96,7 +96,7 @@ int skl_init_dsp(struct skl *skl) } ret = skl_sst_dsp_init(bus->dev, mmio_base, irq, - loader_ops, &skl->skl_sst); + skl->fw_name, loader_ops, &skl->skl_sst); if (ret < 0) return ret; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 6bfcef449bdc..f2a69d9e56b3 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -139,7 +139,8 @@ void skl_dsp_free(struct sst_dsp *dsp); int skl_dsp_boot(struct sst_dsp *ctx); int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_sst **dsp); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 5c5a244942ef..0c5039f2bd09 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -77,7 +77,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) init_waitqueue_head(&skl->boot_wait); if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev); + ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); if (ret < 0) { dev_err(ctx->dev, "Request firmware failed %d\n", ret); skl_dsp_disable_core(ctx); @@ -223,7 +223,7 @@ static struct sst_dsp_device skl_dev = { }; int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) { struct skl_sst *skl; struct sst_dsp *sst; @@ -244,6 +244,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst = skl->dsp; + sst->fw_name = fw_name; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 59336cbc10dd..390f839d6168 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -264,6 +264,7 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data) dev_err(bus->dev, "No matching machine driver found\n"); return -ENODEV; } + skl->fw_name = mach->fw_filename; pdev = platform_device_alloc(mach->drv_name, -1); if (pdev == NULL) { diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 9b1beed26f0f..774c29cf84dc 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -68,6 +68,8 @@ struct skl { struct skl_dsp_resource resource; struct list_head ppl_list; + + const char *fw_name; }; #define skl_to_ebus(s) (&(s)->ebus) -- cgit v1.2.3 From 232c00b6e55558c216cbf50358549a1967ee1419 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:38:26 +0000 Subject: ASoC: rsnd: DMA become SSI/SRC member Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. Current rsnd_mod is member of rsnd_mod. But the DMA user is only SSI/SRC. This DMA will be implemented as module. As 1st step, DMA become SSI/SRC member by this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 19 ++++++++++++++++--- sound/soc/sh/rcar/rsnd.h | 8 ++++---- sound/soc/sh/rcar/src.c | 19 +++++++++++++------ sound/soc/sh/rcar/ssi.c | 16 ++++++++++------ 4 files changed, 43 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 5d084d040961..923120c7b250 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -606,14 +606,17 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) dma->ops->quit(io, dma); } -int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) +struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, int id) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct rsnd_dma *dma; struct device *dev = rsnd_priv_to_dev(priv); int is_play = rsnd_io_is_play(io); + int ret; /* * DMA failed. try to PIO mode @@ -622,7 +625,13 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) * rsnd_rdai_continuance_probe() */ if (!dmac) - return -EAGAIN; + return ERR_PTR(-EAGAIN); + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return ERR_PTR(-ENOMEM); + + dma->mod = mod; rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); @@ -644,7 +653,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - return dma->ops->init(io, dma, id, mod_from, mod_to); + ret = dma->ops->init(io, dma, id, mod_from, mod_to); + if (ret < 0) + return ERR_PTR(ret); + + return dma; } int rsnd_dma_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 085329878525..1c08eaa51430 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -206,6 +206,7 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_dma_ops *ops; + struct rsnd_mod *mod; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -215,11 +216,12 @@ struct rsnd_dma { }; #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) -#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) +#define rsnd_dma_to_mod(_dma) ((dma)->mod) void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id); +struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, int id); void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); int rsnd_dma_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, @@ -278,7 +280,6 @@ struct rsnd_mod { int id; enum rsnd_mod_type type; struct rsnd_mod_ops *ops; - struct rsnd_dma dma; struct rsnd_priv *priv; struct clk *clk; u32 status; @@ -328,7 +329,6 @@ struct rsnd_mod { #define __rsnd_mod_call_hw_params 0 #define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_to_dma(mod) (&(mod)->dma) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 261b50217c48..3296f1e96d30 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -22,6 +22,7 @@ struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + struct rsnd_dma *dma; struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ @@ -30,6 +31,7 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_to_dma(src) ((src)->dma) #define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) #define rsnd_src_of_node(priv) \ @@ -839,9 +841,9 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, return ret; } - ret = rsnd_dma_init(io, - rsnd_mod_to_dma(mod), - src->info->dma_id); + src->dma = rsnd_dma_init(io, mod, src->info->dma_id); + if (IS_ERR(src->dma)) + return PTR_ERR(src->dma); return ret; } @@ -850,7 +852,9 @@ static int rsnd_src_remove_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); + struct rsnd_src *src = rsnd_mod_to_src(mod); + + rsnd_dma_quit(io, rsnd_src_to_dma(src)); return 0; } @@ -880,7 +884,9 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_dma_start(io, rsnd_mod_to_dma(mod)); + struct rsnd_src *src = rsnd_mod_to_src(mod); + + rsnd_dma_start(io, rsnd_src_to_dma(src)); return _rsnd_src_start_gen2(mod, io); } @@ -889,11 +895,12 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + struct rsnd_src *src = rsnd_mod_to_src(mod); int ret; ret = _rsnd_src_stop_gen2(mod); - rsnd_dma_stop(io, rsnd_mod_to_dma(mod)); + rsnd_dma_stop(io, rsnd_src_to_dma(src)); return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 1427ec21bd7e..eec17bcc89fa 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -63,6 +63,7 @@ struct rsnd_ssi { struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ struct rsnd_ssi *parent; struct rsnd_mod mod; + struct rsnd_dma *dma; u32 cr_own; u32 cr_clk; @@ -77,6 +78,7 @@ struct rsnd_ssi { ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ i++) +#define rsnd_ssi_to_dma(mod) ((ssi)->dma) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) @@ -537,9 +539,9 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, if (ret) return ret; - ret = rsnd_dma_init( - io, rsnd_mod_to_dma(mod), - dma_id); + ssi->dma = rsnd_dma_init(io, mod, dma_id); + if (IS_ERR(ssi->dma)) + return PTR_ERR(ssi->dma); return ret; } @@ -552,7 +554,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; - rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); + rsnd_dma_quit(io, rsnd_ssi_to_dma(ssi)); /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); @@ -585,7 +587,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dma *dma = rsnd_ssi_to_dma(ssi); rsnd_dma_start(io, dma); @@ -598,7 +601,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dma *dma = rsnd_ssi_to_dma(ssi); rsnd_ssi_stop(mod, io, priv); -- cgit v1.2.3 From 3e5afa73a9fb4001789508d6f9f0fca3e3475f5a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:38:58 +0000 Subject: ASoC: rsnd: DMA related definition goes to dma.c Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. DMA will be implemented as module. Current DMA definition is no longer needed on rsnd.h. Let's move it to dma.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 24 ++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 23 ----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 923120c7b250..00e83e0670e7 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -22,6 +22,27 @@ /* PDMACHCR */ #define PDMACHCR_DE (1 << 0) + +struct rsnd_dmaen { + struct dma_chan *chan; +}; + +struct rsnd_dmapp { + int dmapp_id; + u32 chcr; +}; + +struct rsnd_dma { + struct rsnd_dma_ops *ops; + struct rsnd_mod *mod; + dma_addr_t src_addr; + dma_addr_t dst_addr; + union { + struct rsnd_dmaen en; + struct rsnd_dmapp pp; + } dma; +}; + struct rsnd_dma_ctrl { void __iomem *base; int dmapp_num; @@ -37,6 +58,9 @@ struct rsnd_dma_ops { }; #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) +#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) +#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) +#define rsnd_dma_to_mod(_dma) ((dma)->mod) /* * Audio DMAC diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 1c08eaa51430..1dc05a24c01c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -195,29 +195,6 @@ void rsnd_path_parse(struct rsnd_priv *priv, */ struct rsnd_dma; -struct rsnd_dmaen { - struct dma_chan *chan; -}; - -struct rsnd_dmapp { - int dmapp_id; - u32 chcr; -}; - -struct rsnd_dma { - struct rsnd_dma_ops *ops; - struct rsnd_mod *mod; - dma_addr_t src_addr; - dma_addr_t dst_addr; - union { - struct rsnd_dmaen en; - struct rsnd_dmapp pp; - } dma; -}; -#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) -#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) -#define rsnd_dma_to_mod(_dma) ((dma)->mod) - void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, -- cgit v1.2.3 From 81ecbb654e1015840dec6a1ef3fcfef34d28feed Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:39:20 +0000 Subject: ASoC: rsnd: rename rsnd_dma_init() to rsnd_dma_attach() Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. DMA will be implemented as module. Then each rsnd_dma_ops will be rsnd_mod_ops. But current rsnd_dma_ops::init means "DMA attach". This patch removes .init from rsnd_dma_ops, and renames rsnd_dma_init() to rsnd_dma_attach() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 35 +++++++++++++++++++---------------- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 2 +- 4 files changed, 22 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 00e83e0670e7..705e524b0892 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -52,8 +52,6 @@ struct rsnd_dma_ops { char *name; void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); }; @@ -176,7 +174,7 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, return rsnd_mod_dma_req(io, mod_to); } -static int rsnd_dmaen_init(struct rsnd_dai_stream *io, +static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { @@ -221,11 +219,11 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) - goto rsnd_dma_init_err; + goto rsnd_dma_attach_err; return 0; -rsnd_dma_init_err: +rsnd_dma_attach_err: rsnd_dma_quit(io, dma); rsnd_dma_channel_err: @@ -252,7 +250,6 @@ static struct rsnd_dma_ops rsnd_dmaen_ops = { .name = "audmac", .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .init = rsnd_dmaen_init, .quit = rsnd_dmaen_quit, }; @@ -372,9 +369,9 @@ static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); } -static int rsnd_dmapp_init(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) +static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, + struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); @@ -398,7 +395,6 @@ static struct rsnd_dma_ops rsnd_dmapp_ops = { .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, - .init = rsnd_dmapp_init, .quit = rsnd_dmapp_stop, }; @@ -630,8 +626,8 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) dma->ops->quit(io, dma); } -struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, int id) +struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, int id) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; @@ -639,6 +635,8 @@ struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct rsnd_dma *dma; struct device *dev = rsnd_priv_to_dev(priv); + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret; @@ -663,21 +661,26 @@ struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); /* for Gen2 */ - if (mod_from && mod_to) + if (mod_from && mod_to) { dma->ops = &rsnd_dmapp_ops; - else + attach = rsnd_dmapp_attach; + } else { dma->ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + } /* for Gen1, overwrite */ - if (rsnd_is_gen1(priv)) + if (rsnd_is_gen1(priv)) { dma->ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + } dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", dma->ops->name, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - ret = dma->ops->init(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, id, mod_from, mod_to); if (ret < 0) return ERR_PTR(ret); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 1dc05a24c01c..dc31f6d84ee4 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -197,7 +197,7 @@ struct rsnd_dma; void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -struct rsnd_dma *rsnd_dma_init(struct rsnd_dai_stream *io, +struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); int rsnd_dma_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3296f1e96d30..abfcc2480cf6 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -841,7 +841,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, return ret; } - src->dma = rsnd_dma_init(io, mod, src->info->dma_id); + src->dma = rsnd_dma_attach(io, mod, src->info->dma_id); if (IS_ERR(src->dma)) return PTR_ERR(src->dma); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index eec17bcc89fa..d4803a82497d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -539,7 +539,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, if (ret) return ret; - ssi->dma = rsnd_dma_init(io, mod, dma_id); + ssi->dma = rsnd_dma_attach(io, mod, dma_id); if (IS_ERR(ssi->dma)) return PTR_ERR(ssi->dma); -- cgit v1.2.3 From 27924f3208c9f37a1d58b80d999bb9cfc96536d4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:39:41 +0000 Subject: ASoC: rsnd: enable to use rsnd_dai_connect() from each mod Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. DMAC/SSIU/SSI-parent/CMD will be implemented as module, but these are not customer controlled module. These should be automatically install to system. Because of this, rsnd_dai_connect() should be called from each mod. SSI can be very special, because it will be installed as SSI-parent / SSI-child. Thus, new rsnd_dai_connect() has type parameter which should be mod->type except SSI-parent Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 32 +++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 3 +++ 2 files changed, 20 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index deed48ef28b8..d7d2a59d0553 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -332,8 +332,9 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ret; \ }) -static int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) { struct rsnd_priv *priv; struct device *dev; @@ -344,7 +345,7 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, priv = rsnd_mod_to_priv(mod); dev = rsnd_priv_to_dev(priv); - io->mod[mod->type] = mod; + io->mod[type] = mod; dev_dbg(dev, "%s[%d] is connected to io (%s)\n", rsnd_mod_name(mod), rsnd_mod_id(mod), @@ -354,9 +355,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, } static void rsnd_dai_disconnect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) { - io->mod[mod->type] = NULL; + io->mod[type] = NULL; } struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) @@ -572,32 +574,32 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; -#define rsnd_path_add(priv, io, type) \ +#define rsnd_path_add(priv, io, _type) \ ({ \ struct rsnd_mod *mod; \ int ret = 0; \ int id = -1; \ \ - if (rsnd_is_enable_path(io, type)) { \ - id = rsnd_info_id(priv, io, type); \ + if (rsnd_is_enable_path(io, _type)) { \ + id = rsnd_info_id(priv, io, _type); \ if (id >= 0) { \ - mod = rsnd_##type##_mod_get(priv, id); \ - ret = rsnd_dai_connect(mod, io); \ + mod = rsnd_##_type##_mod_get(priv, id); \ + ret = rsnd_dai_connect(mod, io, mod->type);\ } \ } \ ret; \ }) -#define rsnd_path_remove(priv, io, type) \ +#define rsnd_path_remove(priv, io, _type) \ { \ struct rsnd_mod *mod; \ int id = -1; \ \ - if (rsnd_is_enable_path(io, type)) { \ - id = rsnd_info_id(priv, io, type); \ + if (rsnd_is_enable_path(io, _type)) { \ + id = rsnd_info_id(priv, io, _type); \ if (id >= 0) { \ - mod = rsnd_##type##_mod_get(priv, id); \ - rsnd_dai_disconnect(mod, io); \ + mod = rsnd_##_type##_mod_get(priv, id); \ + rsnd_dai_disconnect(mod, io, mod->type);\ } \ } \ } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index dc31f6d84ee4..996fa1ebe7c8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -380,6 +380,9 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); /* * R-Car Gen1/Gen2 -- cgit v1.2.3 From 48d582819fdc38cda1aeb17f26cfe586d3900f2f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:40:02 +0000 Subject: ASoC: rsnd: remove all modules when PIO fallback Current Renesas sound is supporting PIO fallback if it can't use DMA. In such case, it should remove all attached modules, but current driver is missing about CTU/MIX. Because current implement requests specific mod for remove. To avoid same things in future, this patch removes all mods, and re-connects SSI when PIO fallback case. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d7d2a59d0553..b6fc0d86c03d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -590,20 +590,6 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { ret; \ }) -#define rsnd_path_remove(priv, io, _type) \ -{ \ - struct rsnd_mod *mod; \ - int id = -1; \ - \ - if (rsnd_is_enable_path(io, _type)) { \ - id = rsnd_info_id(priv, io, _type); \ - if (id >= 0) { \ - mod = rsnd_##_type##_mod_get(priv, id); \ - rsnd_dai_disconnect(mod, io, mod->type);\ - } \ - } \ -} - void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io) { @@ -1163,6 +1149,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + int i; + /* * Fallback to PIO mode */ @@ -1177,10 +1166,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, rsnd_dai_call(remove, io, priv); /* - * remove SRC/DVC from DAI, + * remove all mod from io + * and, re connect ssi */ - rsnd_path_remove(priv, io, src); - rsnd_path_remove(priv, io, dvc); + for (i = 0; i < RSND_MOD_MAX; i++) + rsnd_dai_disconnect((io)->mod[i], io, i); + rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* * fallback -- cgit v1.2.3 From 40854c648ee79019a90034fc1f73ba2822812099 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:40:19 +0000 Subject: ASoC: rsnd: fixup rsnd_dma_of_path method for mod base common method Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. Current rsnd_dma_of_path is assuming that all mods are related to DMA. But it will be wrong. This patch tidyup this wrong assumption Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 705e524b0892..697f8825215f 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -533,7 +533,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *mod_start, *mod_end; struct rsnd_priv *priv = rsnd_mod_to_priv(this); struct device *dev = rsnd_priv_to_dev(priv); - int nr, i; + int nr, i, idx; if (!ssi) return; @@ -562,23 +562,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, mod_start = (is_play) ? NULL : ssi; mod_end = (is_play) ? ssi : NULL; - mod[0] = mod_start; + idx = 0; + mod[idx++] = mod_start; for (i = 1; i < nr; i++) { if (src) { - mod[i] = src; + mod[idx++] = src; src = NULL; } else if (ctu) { - mod[i] = ctu; + mod[idx++] = ctu; ctu = NULL; } else if (mix) { - mod[i] = mix; + mod[idx++] = mix; mix = NULL; } else if (dvc) { - mod[i] = dvc; + mod[idx++] = dvc; dvc = NULL; } } - mod[i] = mod_end; + mod[idx] = mod_end; /* * | SSI | SRC | @@ -587,8 +588,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, * !is_play | * | o | */ if ((this == ssi) == (is_play)) { - *mod_from = mod[nr - 1]; - *mod_to = mod[nr]; + *mod_from = mod[idx - 1]; + *mod_to = mod[idx]; } else { *mod_from = mod[0]; *mod_to = mod[1]; @@ -596,7 +597,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, dev_dbg(dev, "module connection (this is %s[%d])\n", rsnd_mod_name(this), rsnd_mod_id(this)); - for (i = 0; i <= nr; i++) { + for (i = 0; i <= idx; i++) { dev_dbg(dev, " %s[%d]%s\n", rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), (mod[i] == *mod_from) ? " from" : -- cgit v1.2.3 From 37447b46e8c54c807e368d31ef6423c772b8dbbf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:40:41 +0000 Subject: ASoC: rsnd: move rsnd_src_ssi_irq_enable/disable() to ssi.c Part of SSI IRQ enable/disable was controlled by SRU (on Gen1) or CMD (on Gen2). Because of this reason SSI IRQ function was implemented under src.c. but it is not understandable. Let's move it to ssi.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 -- sound/soc/sh/rcar/src.c | 28 ---------------------------- sound/soc/sh/rcar/ssi.c | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 996fa1ebe7c8..d6365dc2ac99 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -576,8 +576,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif); int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, struct rsnd_dai_stream *io); -int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); -int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); /* * R-Car CTU diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index abfcc2480cf6..513094ec2312 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -210,34 +210,6 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, return 0; } -int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - - if (rsnd_is_gen1(priv)) - return 0; - - /* enable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, - rsnd_ssi_is_dma_mode(ssi_mod) ? - 0x0e000000 : 0x0f000000); - - return 0; -} - -int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - - if (rsnd_is_gen1(priv)) - return 0; - - /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); - - return 0; -} - static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, struct rsnd_src *src) { diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d4803a82497d..c7d943411ae5 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -124,6 +124,34 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, dev_warn(dev, "status check failed\n"); } +static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + + if (rsnd_is_gen1(priv)) + return 0; + + /* enable SSI interrupt if Gen2 */ + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, + rsnd_ssi_is_dma_mode(ssi_mod) ? + 0x0e000000 : 0x0f000000); + + return 0; +} + +static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + + if (rsnd_is_gen1(priv)) + return 0; + + /* disable SSI interrupt if Gen2 */ + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); + + return 0; +} + static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_dai_stream *io) { @@ -401,7 +429,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, rsnd_ssi_hw_start(ssi, io); - rsnd_src_ssi_irq_enable(mod); + rsnd_ssi_irq_enable(mod); return 0; } @@ -412,7 +440,7 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - rsnd_src_ssi_irq_disable(mod); + rsnd_ssi_irq_disable(mod); rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); -- cgit v1.2.3 From b761bf272bce6dff4d8a7ccf4385c9f3d4018094 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:40:59 +0000 Subject: ASoC: rsnd: disable SRC.out only when stop timing Because SRC is connected to DMA and DMA want to keep dreq when stop timing. This patch makes SRC stop SRC.out only when stop timing. And it stops both SRC.out/SRC.in when quit timing Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 513094ec2312..3f6993facf69 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -665,13 +665,27 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) { rsnd_src_irq_disable_gen2(mod); - rsnd_mod_write(mod, SRC_CTRL, 0); + /* + * stop SRC output only + * see rsnd_src_quit_gen2 + */ + rsnd_mod_write(mod, SRC_CTRL, 0x01); rsnd_src_error_record_gen2(mod); return rsnd_src_stop(mod); } +static int rsnd_src_quit_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + /* stop both out/in */ + rsnd_mod_write(mod, SRC_CTRL, 0); + + return 0; +} + static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -943,7 +957,7 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { .probe = rsnd_src_probe_gen2, .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, - .quit = rsnd_src_quit, + .quit = rsnd_src_quit_gen2, .start = rsnd_src_start_gen2, .stop = rsnd_src_stop_gen2, .hw_params = rsnd_src_hw_params, -- cgit v1.2.3 From c2dc47d5cff62bfe21a691bef40eb30a585caa3c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:41:17 +0000 Subject: ASoC: rsnd: rsnd_dai_stream has each mod's status insted of rsnd_mod Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. Current rsnd is controling each mod's status on mod. But it was not good design for SSI, because stream might has SSI-parent. In such case, it can't play/capture in same time, because SSI-parent is used as normal SSI in other stream, but it shares same status. To avoid this issue each mod's status is controlled by rsnd_dai_stream instead of rsnd_mod. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 12 +++++++----- sound/soc/sh/rcar/rsnd.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index b6fc0d86c03d..5f20d6776281 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -300,20 +300,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ -#define rsnd_mod_call(mod, io, func, param...) \ +#define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ + struct rsnd_mod *mod = (io)->mod[idx]; \ struct device *dev = rsnd_priv_to_dev(priv); \ + u32 *status = (io)->mod_status + idx; \ u32 mask = 0xF << __rsnd_mod_shift_##func; \ - u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \ + u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ int ret = 0; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - mod->status = (mod->status & ~mask) + \ + *status = (*status & ~mask) + \ (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ - mod->status, call ? #func : ""); \ + *status, call ? #func : ""); \ if (call) \ ret = (mod)->ops->func(mod, io, param); \ ret; \ @@ -327,7 +329,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) mod = (io)->mod[i]; \ if (!mod) \ continue; \ - ret |= rsnd_mod_call(mod, io, fn, param); \ + ret |= rsnd_mod_call(i, io, fn, param); \ } \ ret; \ }) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d6365dc2ac99..774cb24b7338 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -259,7 +259,6 @@ struct rsnd_mod { struct rsnd_mod_ops *ops; struct rsnd_priv *priv; struct clk *clk; - u32 status; }; /* * status @@ -335,6 +334,7 @@ struct rsnd_dai_stream { struct rsnd_mod *mod[RSND_MOD_MAX]; struct rsnd_dai_path_info *info; /* rcar_snd.h */ struct rsnd_dai *rdai; + u32 mod_status[RSND_MOD_MAX]; int byte_pos; int period_pos; int byte_per_period; -- cgit v1.2.3 From 69e32a58bde67490f57b6172da198b50c7aa6ab1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:41:36 +0000 Subject: ASoC: rsnd: Don't stop HW even if a large number of errors occur Current SSI/SRC restarts HW if under/over flow happened to avoid L/R invert issue. But it will stop HW if too many error happen. But if it stops on HW, other side under/over flow happen. OTHA, it will be forever loop interrupt if something strange error happen on HW/driver without escape route of large number error. To avoid this issue, it indicates error message if large number error occur, and disables error interrupt. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 17 ++++++++++------- sound/soc/sh/rcar/ssi.c | 15 +++++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3f6993facf69..0d96ce5ed9cc 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -690,6 +690,8 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_src *src = rsnd_mod_to_src(mod); + struct device *dev = rsnd_priv_to_dev(priv); spin_lock(&priv->lock); @@ -698,18 +700,19 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, goto rsnd_src_interrupt_gen2_out; if (rsnd_src_error_record_gen2(mod)) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); _rsnd_src_stop_gen2(mod); - if (src->err < 1024) - _rsnd_src_start_gen2(mod, io); - else - dev_warn(dev, "no more SRC restart\n"); + _rsnd_src_start_gen2(mod, io); + } + + if (src->err > 1024) { + rsnd_src_irq_disable_gen2(mod); + + dev_warn(dev, "no more %s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); } rsnd_src_interrupt_gen2_out: diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index c7d943411ae5..86e51ce66b10 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -456,6 +456,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); int is_dma = rsnd_ssi_is_dma_mode(mod); u32 status; bool elapsed = false; @@ -489,8 +490,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) { - struct device *dev = rsnd_priv_to_dev(priv); - /* * restart SSI */ @@ -498,14 +497,18 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, rsnd_mod_name(mod), rsnd_mod_id(mod)); rsnd_ssi_stop(mod, io, priv); - if (ssi->err < 1024) - rsnd_ssi_start(mod, io, priv); - else - dev_warn(dev, "no more SSI restart\n"); + rsnd_ssi_start(mod, io, priv); } rsnd_ssi_record_error(ssi, status); + if (ssi->err > 1024) { + rsnd_ssi_irq_disable(mod); + + dev_warn(dev, "no more %s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + } + rsnd_ssi_interrupt_out: spin_unlock(&priv->lock); -- cgit v1.2.3 From 2daf71ad8da6cb57f919c9c876ee7e42530371df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:41:53 +0000 Subject: ASoC: rsnd: avoid pointless loop in rsnd_mod_interrupt() Current Renesas sound driver doesn't have 1:1 relationship between stream <-> mod because it is supporting MIX. Because of this reason rsnd_mod_interrupt() is searching correspond mod by for loop. But this loop is not needed, because each mod has own type. This patch avoid pointless loop by using mod->type. This patch is good for SSI-parent support, because stream might have 2 SSI as SSI-parent/child. SSI interrupt handler will be called twice if stream has SSI-parent without this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 5f20d6776281..8af2d22d0cd3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -192,19 +192,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io; struct rsnd_dai *rdai; - int i, j; - - for_each_rsnd_dai(rdai, priv, j) { + int i; - for (i = 0; i < RSND_MOD_MAX; i++) { - io = &rdai->playback; - if (mod == io->mod[i]) - callback(mod, io); + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mod == io->mod[mod->type]) + callback(mod, io); - io = &rdai->capture; - if (mod == io->mod[i]) - callback(mod, io); - } + io = &rdai->capture; + if (mod == io->mod[mod->type]) + callback(mod, io); } } -- cgit v1.2.3 From e10369d88c16456b0ff3ae31b4e30a3d2795a243 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:42:09 +0000 Subject: ASoC: rsnd: use common rsnd_ssi_status_xxx() Current ssi.c driver has random access to SSISR register. Let's use common rsnd_ssi_status_xxx() function Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 86e51ce66b10..ad5539def58f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -105,6 +105,16 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) return use_busif; } +static void rsnd_ssi_status_clear(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SSISR, 0); +} + +static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) +{ + return rsnd_mod_read(mod, SSISR); +} + static void rsnd_ssi_status_check(struct rsnd_mod *mod, u32 bit) { @@ -114,7 +124,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, int i; for (i = 0; i < 1024; i++) { - status = rsnd_mod_read(mod, SSISR); + status = rsnd_ssi_status_get(mod); if (status & bit) return; @@ -245,7 +255,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, rsnd_mod_write(mod, SSIWSR, CONT); /* clear error status */ - rsnd_mod_write(mod, SSISR, 0); + rsnd_ssi_status_clear(mod); ssi->usrcnt++; @@ -406,17 +416,20 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return 0; } -static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) +static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) { struct rsnd_mod *mod = rsnd_mod_get(ssi); + u32 status = rsnd_ssi_status_get(mod); /* under/over flow error */ if (status & (UIRQ | OIRQ)) { ssi->err++; /* clear error status */ - rsnd_mod_write(mod, SSISR, 0); + rsnd_ssi_status_clear(mod); } + + return status; } static int rsnd_ssi_start(struct rsnd_mod *mod, @@ -442,7 +455,7 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, rsnd_ssi_irq_disable(mod); - rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); + rsnd_ssi_record_error(ssi); rsnd_ssi_hw_stop(io, ssi); @@ -467,7 +480,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, if (!rsnd_io_is_working(io)) goto rsnd_ssi_interrupt_out; - status = rsnd_mod_read(mod, SSISR); + status = rsnd_ssi_record_error(ssi); /* PIO only */ if (!is_dma && (status & DIRQ)) { @@ -500,8 +513,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, rsnd_ssi_start(mod, io, priv); } - rsnd_ssi_record_error(ssi, status); - if (ssi->err > 1024) { rsnd_ssi_irq_disable(mod); -- cgit v1.2.3 From 940e947926cab8637e7a664e1f6e4bf8b94e42c5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:42:25 +0000 Subject: ASoC: rsnd: use mod base common method on DMA phase1 Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. DMA will be implemented as module. Then rsnd_dma will be mod base. This patch makes rsnd_dma mod base, but still not yet completely finished. This mod is not yet installed to system at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 61 ++++++++++++++++++++++++++++++++---------------- sound/soc/sh/rcar/rsnd.h | 14 +++++------ sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 6 ++--- 4 files changed, 52 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 697f8825215f..45d30b8e6226 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -34,7 +34,8 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_dma_ops *ops; - struct rsnd_mod *mod; + struct rsnd_mod mod; + struct rsnd_mod *user_mod; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -45,6 +46,7 @@ struct rsnd_dma { struct rsnd_dma_ctrl { void __iomem *base; + int dmaen_num; int dmapp_num; }; @@ -56,9 +58,9 @@ struct rsnd_dma_ops { }; #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) +#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) -#define rsnd_dma_to_mod(_dma) ((dma)->mod) /* * Audio DMAC @@ -109,8 +111,8 @@ static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) { struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_mod *user_mod = dma->user_mod; + struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; @@ -129,7 +131,7 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) } desc->callback = rsnd_dmaen_complete; - desc->callback_param = mod; + desc->callback_param = user_mod; if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); @@ -180,6 +182,7 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, { struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); @@ -221,10 +224,12 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, if (ret < 0) goto rsnd_dma_attach_err; + dmac->dmaen_num++; + return 0; rsnd_dma_attach_err: - rsnd_dma_quit(io, dma); + rsnd_dma_quit(io, rsnd_mod_get(dma)); rsnd_dma_channel_err: /* @@ -328,7 +333,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); @@ -340,7 +345,7 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) { - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); @@ -517,13 +522,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, } #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ -static void rsnd_dma_of_path(struct rsnd_dma *dma, +static void rsnd_dma_of_path(struct rsnd_mod *this, struct rsnd_dai_stream *io, int is_play, struct rsnd_mod **mod_from, struct rsnd_mod **mod_to) { - struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); @@ -605,19 +609,23 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } } -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + dma->ops->stop(io, dma); } -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + dma->ops->start(io, dma); } -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); @@ -627,9 +635,13 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) dma->ops->quit(io, dma); } -struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, +static struct rsnd_mod_ops rsnd_dma_ops = { +}; + +struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id) { + struct rsnd_mod *dma_mod; struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); @@ -639,7 +651,7 @@ struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); - int ret; + int ret, dma_id; /* * DMA failed. try to PIO mode @@ -654,10 +666,9 @@ struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, if (!dma) return ERR_PTR(-ENOMEM); - dma->mod = mod; - - rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); + rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); + dma->user_mod = mod; dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); @@ -665,27 +676,37 @@ struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, if (mod_from && mod_to) { dma->ops = &rsnd_dmapp_ops; attach = rsnd_dmapp_attach; + dma_id = dmac->dmapp_num; } else { dma->ops = &rsnd_dmaen_ops; attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; } /* for Gen1, overwrite */ if (rsnd_is_gen1(priv)) { dma->ops = &rsnd_dmaen_ops; attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; } + dma_mod = rsnd_mod_get(dma); + dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", dma->ops->name, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + ret = rsnd_mod_init(priv, dma_mod, + &rsnd_dma_ops, NULL, 0, dma_id); + if (ret < 0) + return ERR_PTR(ret); + ret = attach(io, dma, id, mod_from, mod_to); if (ret < 0) return ERR_PTR(ret); - return dma; + return rsnd_mod_get(dma); } int rsnd_dma_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 774cb24b7338..6a0bd3e6c8d1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -193,13 +193,11 @@ void rsnd_path_parse(struct rsnd_priv *priv, /* * R-Car DMA */ -struct rsnd_dma; - -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -struct rsnd_dma *rsnd_dma_attach(struct rsnd_dai_stream *io, +void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_mod *mod); +void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_mod *mod); +struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); +void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_mod *mod); int rsnd_dma_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); @@ -210,7 +208,9 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, * R-Car sound mod */ enum rsnd_mod_type { - RSND_MOD_DVC = 0, + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_DVC, RSND_MOD_MIX, RSND_MOD_CTU, RSND_MOD_SRC, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 0d96ce5ed9cc..517a1e176795 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -22,7 +22,7 @@ struct rsnd_src { struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; - struct rsnd_dma *dma; + struct rsnd_mod *dma; struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index ad5539def58f..66f9f2a9c167 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -63,7 +63,7 @@ struct rsnd_ssi { struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ struct rsnd_ssi *parent; struct rsnd_mod mod; - struct rsnd_dma *dma; + struct rsnd_mod *dma; u32 cr_own; u32 cr_clk; @@ -630,7 +630,7 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_dma *dma = rsnd_ssi_to_dma(ssi); + struct rsnd_mod *dma = rsnd_ssi_to_dma(ssi); rsnd_dma_start(io, dma); @@ -644,7 +644,7 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_dma *dma = rsnd_ssi_to_dma(ssi); + struct rsnd_mod *dma = rsnd_ssi_to_dma(ssi); rsnd_ssi_stop(mod, io, priv); -- cgit v1.2.3 From 76c80b5b3fa666da1a551c47b4597e4efaf2d8c4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:42:46 +0000 Subject: ASoC: rsnd: use mod base common method on DMA phase2 Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. DMA will be implemented as module. Then rsnd_dma_ops will be rebased to rsnd_mod_ops, but these are similar, but different function. This patch modify rsnd_dma_ops same style as rsnd_mod_ops. This is prepare for final merge Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 62 +++++++++++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 12 +++++++--- sound/soc/sh/rcar/src.c | 6 ++--- sound/soc/sh/rcar/ssi.c | 6 ++--- 4 files changed, 58 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 45d30b8e6226..4905e82c3788 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -52,9 +52,15 @@ struct rsnd_dma_ctrl { struct rsnd_dma_ops { char *name; - void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); + void (*start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + void (*stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + void (*quit)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); }; #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) @@ -101,18 +107,23 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } -static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static void rsnd_dmaen_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); dmaengine_terminate_all(dmaen->chan); } -static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static void rsnd_dmaen_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_mod *user_mod = dma->user_mod; - struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; @@ -229,7 +240,7 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return 0; rsnd_dma_attach_err: - rsnd_dma_quit(io, rsnd_mod_get(dma)); + rsnd_dma_quit(rsnd_mod_get(dma), io, priv); rsnd_dma_channel_err: /* @@ -241,8 +252,11 @@ rsnd_dma_channel_err: return -EAGAIN; } -static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static void rsnd_dmaen_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); if (dmaen->chan) @@ -352,8 +366,11 @@ static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); } -static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static void rsnd_dmapp_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); int i; rsnd_dmapp_write(dma, 0, PDMACHCR); @@ -365,8 +382,11 @@ static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) } } -static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static void rsnd_dmapp_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); @@ -388,8 +408,6 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, dmac->dmapp_num++; - rsnd_dmapp_stop(io, dma); - dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); @@ -609,30 +627,36 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } } -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_mod *mod) +void rsnd_dma_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) + { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - dma->ops->stop(io, dma); + dma->ops->stop(mod, io, priv); } -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_mod *mod) +void rsnd_dma_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - dma->ops->start(io, dma); + dma->ops->start(mod, io, priv); } -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_mod *mod) +void rsnd_dma_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); if (!dmac) return; - dma->ops->quit(io, dma); + dma->ops->quit(mod, io, priv); } static struct rsnd_mod_ops rsnd_dma_ops = { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6a0bd3e6c8d1..f0b4a71b6a48 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -193,11 +193,17 @@ void rsnd_path_parse(struct rsnd_priv *priv, /* * R-Car DMA */ -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_mod *mod); -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_mod *mod); +void rsnd_dma_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); +void rsnd_dma_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); +void rsnd_dma_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_mod *mod); int rsnd_dma_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 517a1e176795..b0c653afa7aa 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -843,7 +843,7 @@ static int rsnd_src_remove_gen2(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_dma_quit(io, rsnd_src_to_dma(src)); + rsnd_dma_quit(rsnd_src_to_dma(src), io, priv); return 0; } @@ -875,7 +875,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_dma_start(io, rsnd_src_to_dma(src)); + rsnd_dma_start(rsnd_src_to_dma(src), io, priv); return _rsnd_src_start_gen2(mod, io); } @@ -889,7 +889,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, ret = _rsnd_src_stop_gen2(mod); - rsnd_dma_stop(io, rsnd_src_to_dma(src)); + rsnd_dma_stop(rsnd_src_to_dma(src), io, priv); return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 66f9f2a9c167..67b6bd55957c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -596,7 +596,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; - rsnd_dma_quit(io, rsnd_ssi_to_dma(ssi)); + rsnd_dma_quit(rsnd_ssi_to_dma(ssi), io, priv); /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); @@ -632,7 +632,7 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *dma = rsnd_ssi_to_dma(ssi); - rsnd_dma_start(io, dma); + rsnd_dma_start(dma, io, priv); rsnd_ssi_start(mod, io, priv); @@ -648,7 +648,7 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, rsnd_ssi_stop(mod, io, priv); - rsnd_dma_stop(io, dma); + rsnd_dma_stop(dma, io, priv); return 0; } -- cgit v1.2.3 From 497debaa803e25fc0163fe4380335b8626acad44 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:43:01 +0000 Subject: ASoC: rsnd: use mod base common method on DMA phase3 Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. This patch makes DMA mod bse common method Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 154 +++++++++++++++++++---------------------------- sound/soc/sh/rcar/rsnd.h | 9 --- sound/soc/sh/rcar/src.c | 50 +++------------ sound/soc/sh/rcar/ssi.c | 34 +---------- 4 files changed, 71 insertions(+), 176 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 4905e82c3788..fc70e97500ad 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -33,9 +33,7 @@ struct rsnd_dmapp { }; struct rsnd_dma { - struct rsnd_dma_ops *ops; struct rsnd_mod mod; - struct rsnd_mod *user_mod; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -50,19 +48,6 @@ struct rsnd_dma_ctrl { int dmapp_num; }; -struct rsnd_dma_ops { - char *name; - void (*start)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - void (*stop)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - void (*quit)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); -}; - #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) #define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) @@ -107,23 +92,24 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } -static void rsnd_dmaen_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); dmaengine_terminate_all(dmaen->chan); + + return 0; } -static void rsnd_dmaen_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct rsnd_mod *user_mod = dma->user_mod; struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; @@ -138,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_mod *mod, if (!desc) { dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return; + return -EIO; } desc->callback = rsnd_dmaen_complete; - desc->callback_param = user_mod; + desc->callback_param = rsnd_mod_get(dma); if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); - return; + return -EIO; } dma_async_issue_pending(dmaen->chan); + + return 0; } struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, @@ -187,10 +175,26 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, return rsnd_mod_dma_req(io, mod_to); } +static int rsnd_dmaen_remove(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + if (dmaen->chan) + dma_release_channel(dmaen->chan); + + dmaen->chan = NULL; + + return 0; +} + static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); @@ -227,8 +231,8 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "%s %pad -> %pad\n", - dma->ops->name, + dev_dbg(dev, "%s[%d] %pad -> %pad\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); @@ -240,7 +244,7 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return 0; rsnd_dma_attach_err: - rsnd_dma_quit(rsnd_mod_get(dma), io, priv); + rsnd_dmaen_remove(mod, io, priv); rsnd_dma_channel_err: /* @@ -252,24 +256,11 @@ rsnd_dma_channel_err: return -EAGAIN; } -static void rsnd_dmaen_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; -} - -static struct rsnd_dma_ops rsnd_dmaen_ops = { +static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .quit = rsnd_dmaen_quit, + .remove = rsnd_dmaen_remove, }; /* @@ -366,9 +357,9 @@ static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); } -static void rsnd_dmapp_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmapp_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); int i; @@ -377,14 +368,16 @@ static void rsnd_dmapp_stop(struct rsnd_mod *mod, for (i = 0; i < 1024; i++) { if (0 == rsnd_dmapp_read(dma, PDMACHCR)) - return; + return -EIO; udelay(1); } + + return 0; } -static void rsnd_dmapp_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmapp_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -392,6 +385,8 @@ static void rsnd_dmapp_start(struct rsnd_mod *mod, rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); + + return 0; } static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, @@ -414,7 +409,7 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, return 0; } -static struct rsnd_dma_ops rsnd_dmapp_ops = { +static struct rsnd_mod_ops rsnd_dmapp_ops = { .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, @@ -627,41 +622,6 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } } -void rsnd_dma_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) - -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - - dma->ops->stop(mod, io, priv); -} - -void rsnd_dma_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - - dma->ops->start(mod, io, priv); -} - -void rsnd_dma_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - - if (!dmac) - return; - - dma->ops->quit(mod, io, priv); -} - -static struct rsnd_mod_ops rsnd_dma_ops = { -}; - struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id) { @@ -672,6 +632,8 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct rsnd_dma *dma; struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod_ops *ops; + enum rsnd_mod_type type; int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); @@ -692,37 +654,39 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); - dma->user_mod = mod; dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); /* for Gen2 */ if (mod_from && mod_to) { - dma->ops = &rsnd_dmapp_ops; + ops = &rsnd_dmapp_ops; attach = rsnd_dmapp_attach; dma_id = dmac->dmapp_num; + type = RSND_MOD_AUDMAPP; } else { - dma->ops = &rsnd_dmaen_ops; + ops = &rsnd_dmaen_ops; attach = rsnd_dmaen_attach; dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; } /* for Gen1, overwrite */ if (rsnd_is_gen1(priv)) { - dma->ops = &rsnd_dmaen_ops; + ops = &rsnd_dmaen_ops; attach = rsnd_dmaen_attach; dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; } dma_mod = rsnd_mod_get(dma); - dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", - dma->ops->name, + dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", + rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); ret = rsnd_mod_init(priv, dma_mod, - &rsnd_dma_ops, NULL, 0, dma_id); + ops, NULL, type, dma_id); if (ret < 0) return ERR_PTR(ret); @@ -730,6 +694,10 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, if (ret < 0) return ERR_PTR(ret); + ret = rsnd_dai_connect(dma_mod, io, type); + if (ret < 0) + return ERR_PTR(ret); + return rsnd_mod_get(dma); } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f0b4a71b6a48..8d42642b1a45 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -193,15 +193,6 @@ void rsnd_path_parse(struct rsnd_priv *priv, /* * R-Car DMA */ -void rsnd_dma_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); -void rsnd_dma_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); -void rsnd_dma_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); int rsnd_dma_probe(struct platform_device *pdev, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index b0c653afa7aa..3faf9d619614 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -632,8 +632,9 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) return ret; } -static int _rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +static int rsnd_src_start_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; @@ -661,7 +662,9 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod, return 0; } -static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) +static int rsnd_src_stop_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { rsnd_src_irq_disable_gen2(mod); @@ -704,8 +707,8 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - _rsnd_src_stop_gen2(mod); - _rsnd_src_start_gen2(mod, io); + rsnd_src_stop_gen2(mod, io, priv); + rsnd_src_start_gen2(mod, io, priv); } if (src->err > 1024) { @@ -837,17 +840,6 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, return ret; } -static int rsnd_src_remove_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - - rsnd_dma_quit(rsnd_src_to_dma(src), io, priv); - - return 0; -} - static int rsnd_src_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -869,31 +861,6 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod, return 0; } -static int rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - - rsnd_dma_start(rsnd_src_to_dma(src), io, priv); - - return _rsnd_src_start_gen2(mod, io); -} - -static int rsnd_src_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - ret = _rsnd_src_stop_gen2(mod); - - rsnd_dma_stop(rsnd_src_to_dma(src), io, priv); - - return ret; -} - static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -958,7 +925,6 @@ static struct rsnd_mod_ops rsnd_src_gen2_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen2, - .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, .quit = rsnd_src_quit_gen2, .start = rsnd_src_start_gen2, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 67b6bd55957c..a4e5c55eec5b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -596,8 +596,6 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; - rsnd_dma_quit(rsnd_ssi_to_dma(ssi), io, priv); - /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); @@ -625,34 +623,6 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_dma_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *dma = rsnd_ssi_to_dma(ssi); - - rsnd_dma_start(dma, io, priv); - - rsnd_ssi_start(mod, io, priv); - - return 0; -} - -static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *dma = rsnd_ssi_to_dma(ssi); - - rsnd_ssi_stop(mod, io, priv); - - rsnd_dma_stop(dma, io, priv); - - return 0; -} - static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -676,8 +646,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, - .start = rsnd_ssi_dma_start, - .stop = rsnd_ssi_dma_stop, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, }; -- cgit v1.2.3 From 1b2ca0adf1a0cb3aa766259650eddd25b44486b7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:43:21 +0000 Subject: ASoC: rsnd: use mod base common method on CMD Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. This patch makes CMD mod base common method Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/cmd.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sh/rcar/core.c | 75 +--------------------- sound/soc/sh/rcar/ctu.c | 8 +++ sound/soc/sh/rcar/dvc.c | 18 ++++-- sound/soc/sh/rcar/mix.c | 10 ++- sound/soc/sh/rcar/rsnd.h | 20 +++++- 7 files changed, 202 insertions(+), 84 deletions(-) create mode 100644 sound/soc/sh/rcar/cmd.c (limited to 'sound') diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 8b258501aa35..5f1000269cfb 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o cmd.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c new file mode 100644 index 000000000000..731d74b13e92 --- /dev/null +++ b/sound/soc/sh/rcar/cmd.c @@ -0,0 +1,153 @@ +/* + * Renesas R-Car CMD support + * + * Copyright (C) 2015 Renesas Solutions Corp. + * Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +struct rsnd_cmd { + struct rsnd_mod mod; +}; + +#define CMD_NAME "cmd" + +#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) +#define for_each_rsnd_cmd(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_cmd_nr(priv)) && \ + ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ + i++) + +static int rsnd_cmd_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 data; + + if (!mix && !dvc) + return 0; + + if (mix) { + struct rsnd_dai *rdai; + int i; + u32 path[] = { + [0] = 0, + [1] = 1 << 0, + [2] = 0, + [3] = 0, + [4] = 0, + [5] = 1 << 8 + }; + + /* + * it is assuming that integrater is well understanding about + * data path. Here doesn't check impossible connection, + * like src2 + src5 + */ + data = 0; + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + + io = &rdai->capture; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + } + + } else { + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + data = path[rsnd_mod_id(src)]; + } + + dev_dbg(dev, "ctu/mix path = 0x%08x", data); + + rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); + + rsnd_mod_write(mod, CMD_CTRL, 0x10); + + return 0; +} + +static struct rsnd_mod_ops rsnd_cmd_ops = { + .name = CMD_NAME, + .init = rsnd_cmd_init, +}; + +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); + + return rsnd_dai_connect(mod, io, mod->type); +} + +struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); +} + +int rsnd_cmd_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_cmd *cmd; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) + return 0; + + /* same number as DVC */ + nr = priv->dvc_nr; + if (!nr) + return 0; + + cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + priv->cmd_nr = nr; + priv->cmd = cmd; + + for_each_rsnd_cmd(cmd, priv, i) { + ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), + &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_cmd_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_cmd *cmd; + int i; + + for_each_rsnd_cmd(cmd, priv, i) { + rsnd_mod_quit(rsnd_mod_get(cmd)); + } +} diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8af2d22d0cd3..1cbd20f311b8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -589,79 +589,6 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { ret; \ }) -void rsnd_path_parse(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) -{ - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *cmd; - struct device *dev = rsnd_priv_to_dev(priv); - u32 data; - - /* Gen1 is not supported */ - if (rsnd_is_gen1(priv)) - return; - - if (!mix && !dvc) - return; - - if (mix) { - struct rsnd_dai *rdai; - int i; - u32 path[] = { - [0] = 0, - [1] = 1 << 0, - [2] = 0, - [3] = 0, - [4] = 0, - [5] = 1 << 8 - }; - - /* - * it is assuming that integrater is well understanding about - * data path. Here doesn't check impossible connection, - * like src2 + src5 - */ - data = 0; - for_each_rsnd_dai(rdai, priv, i) { - io = &rdai->playback; - if (mix == rsnd_io_to_mod_mix(io)) - data |= path[rsnd_mod_id(src)]; - - io = &rdai->capture; - if (mix == rsnd_io_to_mod_mix(io)) - data |= path[rsnd_mod_id(src)]; - } - - /* - * We can't use ctu = rsnd_io_ctu() here. - * Since, ID of dvc/mix are 0 or 1 (= same as CMD number) - * but ctu IDs are 0 - 7 (= CTU00 - CTU13) - */ - cmd = mix; - } else { - u32 path[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; - - data = path[rsnd_mod_id(src)]; - - cmd = dvc; - } - - dev_dbg(dev, "ctu/mix path = 0x%08x", data); - - rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data); - - rsnd_mod_write(cmd, CMD_CTRL, 0x10); -} - static int rsnd_path_init(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) @@ -1208,6 +1135,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_ctu_probe, rsnd_mix_probe, rsnd_dvc_probe, + rsnd_cmd_probe, rsnd_adg_probe, rsnd_dai_probe, }; @@ -1296,6 +1224,7 @@ static int rsnd_remove(struct platform_device *pdev) rsnd_ctu_remove, rsnd_mix_remove, rsnd_dvc_remove, + rsnd_cmd_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 3cb214ab848b..6b76ae6cf549 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) rsnd_mod_write(mod, CTU_CTUIR, enable); } +static int rsnd_ctu_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4); +} + static int rsnd_ctu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, + .probe = rsnd_ctu_probe_, .init = rsnd_ctu_init, .quit = rsnd_ctu_quit, }; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 58f690900e6d..d207000efef0 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -134,9 +134,16 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, rsnd_mod_write(mod, DVC_DVUER, 1); } -static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dvc_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + +static int rsnd_dvc_remove_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); @@ -159,8 +166,6 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_dvc_initialize_lock(mod); - rsnd_path_parse(priv, io); - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); /* ch0/ch1 Volume */ @@ -269,7 +274,8 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, .dma_req = rsnd_dvc_dma_req, - .remove = rsnd_dvc_remove_gen2, + .probe = rsnd_dvc_probe_, + .remove = rsnd_dvc_remove_, .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, .start = rsnd_dvc_start, diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 953dd0be9b60..bcbd821981a9 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -54,6 +54,13 @@ static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, rsnd_mod_write(mod, MIX_MDBER, 1); } +static int rsnd_mix_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + static int rsnd_mix_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -66,8 +73,6 @@ static int rsnd_mix_init(struct rsnd_mod *mod, rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); - rsnd_path_parse(priv, io); - /* volume step */ rsnd_mod_write(mod, MIX_MIXMR, 0); rsnd_mod_write(mod, MIX_MVPDR, 0); @@ -90,6 +95,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_mix_ops = { .name = MIX_NAME, + .probe = rsnd_mix_probe_, .init = rsnd_mix_init, .quit = rsnd_mix_quit, }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 8d42642b1a45..5286f28de831 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -187,8 +187,6 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -void rsnd_path_parse(struct rsnd_priv *priv, - struct rsnd_dai_stream *io); /* * R-Car DMA @@ -210,6 +208,7 @@ enum rsnd_mod_type { RSND_MOD_DVC, RSND_MOD_MIX, RSND_MOD_CTU, + RSND_MOD_CMD, RSND_MOD_SRC, RSND_MOD_SSI, RSND_MOD_MAX, @@ -474,6 +473,12 @@ struct rsnd_priv { void *dvc; int dvc_nr; + /* + * below value will be filled on rsnd_cmd_probe() + */ + void *cmd; + int cmd_nr; + /* * below value will be filled on rsnd_dai_probe() */ @@ -606,6 +611,17 @@ void rsnd_dvc_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); +/* + * R-Car CMD + */ +int rsnd_cmd_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); +void rsnd_cmd_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); +struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id); + #ifdef DEBUG void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); #define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI) -- cgit v1.2.3 From c7f69ab5364da21a2fc7f01c5bc32a5b5b5fee5d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:43:41 +0000 Subject: ASoC: rsnd: use mod base common method on SSIU Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. This patch makes SSIU mod base common method Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/core.c | 2 + sound/soc/sh/rcar/rsnd.h | 23 ++++-- sound/soc/sh/rcar/src.c | 65 ---------------- sound/soc/sh/rcar/ssi.c | 22 +++--- sound/soc/sh/rcar/ssiu.c | 181 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 84 deletions(-) create mode 100644 sound/soc/sh/rcar/ssiu.c (limited to 'sound') diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 5f1000269cfb..a89ddf758695 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o cmd.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1cbd20f311b8..5586b888db56 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1131,6 +1131,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_gen_probe, rsnd_dma_probe, rsnd_ssi_probe, + rsnd_ssiu_probe, rsnd_src_probe, rsnd_ctu_probe, rsnd_mix_probe, @@ -1220,6 +1221,7 @@ static int rsnd_remove(struct platform_device *pdev) void (*remove_func[])(struct platform_device *pdev, struct rsnd_priv *priv) = { rsnd_ssi_remove, + rsnd_ssiu_remove, rsnd_src_remove, rsnd_ctu_remove, rsnd_mix_remove, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5286f28de831..81c789f8e9a6 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -210,6 +210,7 @@ enum rsnd_mod_type { RSND_MOD_CTU, RSND_MOD_CMD, RSND_MOD_SRC, + RSND_MOD_SSIU, RSND_MOD_SSI, RSND_MOD_MAX, }; @@ -449,6 +450,12 @@ struct rsnd_priv { void *ssi; int ssi_nr; + /* + * below value will be filled on rsnd_ssiu_probe() + */ + void *ssiu; + int ssiu_nr; + /* * below value will be filled on rsnd_src_probe() */ @@ -561,6 +568,17 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); +/* + * R-Car SSIU + */ +int rsnd_ssiu_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod); +int rsnd_ssiu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); +void rsnd_ssiu_remove(struct platform_device *pdev, + struct rsnd_priv *priv); + /* * R-Car SRC */ @@ -573,11 +591,6 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct snd_pcm_runtime *runtime); -int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io, - int use_busif); -int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io); /* * R-Car CTU diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3faf9d619614..a710799cb3a1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -145,71 +145,6 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, is_play ? "rx" : "tx"); } -int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io, - int use_busif) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int ssi_id = rsnd_mod_id(ssi_mod); - - /* - * SSI_MODE0 - */ - rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), - !use_busif << ssi_id); - - /* - * SSI_MODE1 - */ - if (rsnd_ssi_is_pin_sharing(io)) { - int shift = -1; - switch (ssi_id) { - case 1: - shift = 0; - break; - case 2: - shift = 2; - break; - case 4: - shift = 16; - break; - } - - if (shift >= 0) - rsnd_mod_bset(ssi_mod, SSI_MODE1, - 0x3 << shift, - rsnd_rdai_is_clk_master(rdai) ? - 0x2 << shift : 0x1 << shift); - } - - /* - * DMA settings for SSIU - */ - if (use_busif) { - u32 val = rsnd_get_dalign(ssi_mod, io); - - rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, - rsnd_get_adinr_bit(ssi_mod, io)); - rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); - rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); - - rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); - } - - return 0; -} - -int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io) -{ - /* - * DMA settings for SSIU - */ - rsnd_mod_write(ssi_mod, SSI_CTRL, 0); - - return 0; -} - static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, struct rsnd_src *src) { diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index a4e5c55eec5b..bb08d6624d7d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -438,8 +438,6 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io)); - rsnd_ssi_hw_start(ssi, io); rsnd_ssi_irq_enable(mod); @@ -459,8 +457,6 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, rsnd_ssi_hw_stop(io, ssi); - rsnd_src_ssiu_stop(mod, io); - return 0; } @@ -539,14 +535,18 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) /* * SSI PIO */ -static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_ssi_common_probe(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; + ret = rsnd_ssiu_attach(io, mod); + if (ret < 0) + return ret; + ret = devm_request_irq(dev, ssi->info->irq, rsnd_ssi_interrupt, IRQF_SHARED, @@ -557,7 +557,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, - .probe = rsnd_ssi_pio_probe, + .probe = rsnd_ssi_common_probe, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, @@ -570,14 +570,10 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); int dma_id = ssi->info->dma_id; int ret; - ret = devm_request_irq(dev, ssi->info->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + ret = rsnd_ssi_common_probe(mod, io, priv); if (ret) return ret; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c new file mode 100644 index 000000000000..fc5ec17fe37e --- /dev/null +++ b/sound/soc/sh/rcar/ssiu.c @@ -0,0 +1,181 @@ +/* + * Renesas R-Car SSIU support + * + * Copyright (c) 2015 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +#define SSIU_NAME "ssiu" + +struct rsnd_ssiu { + struct rsnd_mod mod; +}; + +#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) +#define for_each_rsnd_ssiu(pos, priv, i) \ + for (i = 0; \ + (i < rsnd_ssiu_nr(priv)) && \ + ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ + i++) + +static int rsnd_ssiu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + int use_busif = rsnd_ssi_use_busif(io); + int id = rsnd_mod_id(mod); + + /* + * SSI_MODE0 + */ + rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); + + /* + * SSI_MODE1 + */ + if (rsnd_ssi_is_pin_sharing(io)) { + int shift = -1; + + switch (id) { + case 1: + shift = 0; + break; + case 2: + shift = 2; + break; + case 4: + shift = 16; + break; + } + + if (shift >= 0) + rsnd_mod_bset(mod, SSI_MODE1, + 0x3 << shift, + rsnd_rdai_is_clk_master(rdai) ? + 0x2 << shift : 0x1 << shift); + } + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { + .name = SSIU_NAME, + .init = rsnd_ssiu_init, +}; + +static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + ret = rsnd_ssiu_init(mod, io, priv); + if (ret < 0) + return ret; + + if (rsnd_ssi_use_busif(io)) { + u32 val = rsnd_get_dalign(mod, io); + + rsnd_mod_write(mod, SSI_BUSIF_ADINR, + rsnd_get_adinr_bit(mod, io)); + rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); + rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); + } + + return 0; +} + +static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (rsnd_ssi_use_busif(io)) + rsnd_mod_write(mod, SSI_CTRL, 0x1); + + return 0; +} + +static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (rsnd_ssi_use_busif(io)) + rsnd_mod_write(mod, SSI_CTRL, 0); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { + .name = SSIU_NAME, + .init = rsnd_ssiu_init_gen2, + .start = rsnd_ssiu_start_gen2, + .stop = rsnd_ssiu_stop_gen2, +}; + +static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); +} + +int rsnd_ssiu_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); + + rsnd_mod_confirm_ssi(ssi_mod); + + return rsnd_dai_connect(mod, io, mod->type); +} + +int rsnd_ssiu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ssiu *ssiu; + static struct rsnd_mod_ops *ops; + int i, nr, ret; + + /* same number to SSI */ + nr = priv->ssi_nr; + ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL); + if (!ssiu) + return -ENOMEM; + + priv->ssiu = ssiu; + priv->ssiu_nr = nr; + + if (rsnd_is_gen1(priv)) + ops = &rsnd_ssiu_ops_gen1; + else + ops = &rsnd_ssiu_ops_gen2; + + for_each_rsnd_ssiu(ssiu, priv, i) { + ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), + ops, NULL, RSND_MOD_SSIU, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_ssiu_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_ssiu *ssiu; + int i; + + for_each_rsnd_ssiu(ssiu, priv, i) { + rsnd_mod_quit(rsnd_mod_get(ssiu)); + } +} -- cgit v1.2.3 From e7d850dd10f4e61b728495a87ce096509843315f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Oct 2015 08:43:57 +0000 Subject: ASoC: rsnd: use mod base common method on SSI-parent Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. This patch makes SSI parent mod base common method Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 + sound/soc/sh/rcar/ssi.c | 301 +++++++++++++++++++++++++---------------------- 2 files changed, 161 insertions(+), 142 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 81c789f8e9a6..599dfb69555a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -211,6 +211,7 @@ enum rsnd_mod_type { RSND_MOD_CMD, RSND_MOD_SRC, RSND_MOD_SSIU, + RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, RSND_MOD_MAX, }; @@ -339,6 +340,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index bb08d6624d7d..3e814711f301 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -67,7 +67,9 @@ struct rsnd_ssi { u32 cr_own; u32 cr_clk; + u32 cr_mode; int chan; + int rate; int err; unsigned int usrcnt; }; @@ -82,9 +84,9 @@ struct rsnd_ssi { #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_parent(ssi) ((ssi)->parent) #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) +#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") @@ -168,7 +170,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -176,6 +180,21 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, unsigned int main_rate; unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); + if (!rsnd_rdai_is_clk_master(rdai)) + return 0; + + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return 0; + + if (ssi->usrcnt > 1) { + if (ssi->rate != rate) { + dev_err(dev, "SSI parent/child should use same rate\n"); + return -EINVAL; + } + + return 0; + } + /* * Find best clock, and try to start ADG */ @@ -193,6 +212,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(j); + ssi->rate = rate; + + rsnd_mod_write(mod, SSIWSR, CONT); + dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), rsnd_mod_id(mod), rate); @@ -205,113 +228,26 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, return -EIO; } -static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - - ssi->cr_clk = 0; - rsnd_adg_ssi_clk_stop(mod); -} - -static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, - struct rsnd_dai_stream *io) +static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, + struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod *mod = rsnd_mod_get(ssi); - u32 cr_mode; - u32 cr; - - if (0 == ssi->usrcnt) { - rsnd_mod_power_on(mod); - - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); - - if (ssi_parent) - rsnd_ssi_hw_start(ssi_parent, io); - else - rsnd_ssi_master_clk_start(ssi, io); - } - } - - if (rsnd_ssi_is_dma_mode(mod)) { - cr_mode = UIEN | OIEN | /* over/under run */ - DMEN; /* DMA : enable DMA */ - } else { - cr_mode = DIEN; /* PIO : enable Data interrupt */ - } - - cr = ssi->cr_own | - ssi->cr_clk | - cr_mode | - EN; - - rsnd_mod_write(mod, SSICR, cr); - - /* enable WS continue */ - if (rsnd_rdai_is_clk_master(rdai)) - rsnd_mod_write(mod, SSIWSR, CONT); - - /* clear error status */ - rsnd_ssi_status_clear(mod); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - ssi->usrcnt++; - - dev_dbg(dev, "%s[%d] hw started\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); -} - -static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 cr; - - if (0 == ssi->usrcnt) { - dev_err(dev, "%s called without starting\n", __func__); + if (!rsnd_rdai_is_clk_master(rdai)) return; - } - - ssi->usrcnt--; - - if (0 == ssi->usrcnt) { - /* - * disable all IRQ, - * and, wait all data was sent - */ - cr = ssi->cr_own | - ssi->cr_clk; - - rsnd_mod_write(mod, SSICR, cr | EN); - rsnd_ssi_status_check(mod, DIRQ); - - /* - * disable SSI, - * and, wait idle state - */ - rsnd_mod_write(mod, SSICR, cr); /* disabled all */ - rsnd_ssi_status_check(mod, IIRQ); - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); - - if (ssi_parent) - rsnd_ssi_hw_stop(io, ssi_parent); - else - rsnd_ssi_master_clk_stop(ssi); - } + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return; - rsnd_mod_power_off(mod); + if (ssi->usrcnt > 1) + return; - ssi->chan = 0; - } + ssi->cr_clk = 0; + ssi->rate = 0; - dev_dbg(dev, "%s[%d] hw stopped\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + rsnd_adg_ssi_clk_stop(mod); } /* @@ -325,6 +261,18 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 cr; + int ret; + + ssi->usrcnt++; + + rsnd_mod_power_on(mod); + + ret = rsnd_ssi_master_clk_start(ssi, io); + if (ret < 0) + return ret; + + if (rsnd_ssi_is_parent(mod, io)) + return 0; cr = FORCE; @@ -359,12 +307,24 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (rsnd_io_is_play(io)) cr |= TRMD; - /* - * set ssi parameter - */ ssi->cr_own = cr; + + if (rsnd_ssi_is_dma_mode(mod)) { + cr = UIEN | OIEN | /* over/under run */ + DMEN; /* DMA : enable DMA */ + } else { + cr = DIEN; /* PIO : enable Data interrupt */ + } + + ssi->cr_mode = cr; + ssi->err = -1; /* ignore 1st error */ + /* clear error status */ + rsnd_ssi_status_clear(mod); + + rsnd_ssi_irq_enable(mod); + return 0; } @@ -375,6 +335,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); + if (rsnd_ssi_is_parent(mod, io)) + goto rsnd_ssi_quit_end; + if (ssi->err > 0) dev_warn(dev, "%s[%d] under/over flow err = %d\n", rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); @@ -382,6 +345,19 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, ssi->cr_own = 0; ssi->err = 0; + rsnd_ssi_irq_disable(mod); + +rsnd_ssi_quit_end: + rsnd_ssi_master_clk_stop(ssi, io); + + rsnd_mod_power_off(mod); + + ssi->usrcnt--; + + if (ssi->usrcnt < 0) + dev_err(dev, "%s[%d] usrcnt error\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + return 0; } @@ -391,14 +367,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *params) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); int chan = params_channels(params); /* * Already working. * It will happen if SSI has parent/child connection. */ - if (ssi->usrcnt) { + if (ssi->usrcnt > 1) { /* * it is error if child <-> parent SSI uses * different channels. @@ -407,11 +382,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return -EIO; } - /* It will be removed on rsnd_ssi_hw_stop */ ssi->chan = chan; - if (ssi_parent) - return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io, - substream, params); return 0; } @@ -432,15 +403,59 @@ static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) return status; } +static int __rsnd_ssi_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + cr = ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode | + EN; + + rsnd_mod_write(mod, SSICR, cr); + + return 0; +} + static int rsnd_ssi_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) +{ + /* + * no limit to start + * see also + * rsnd_ssi_stop + * rsnd_ssi_interrupt + */ + return __rsnd_ssi_start(mod, io, priv); +} + +static int __rsnd_ssi_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + /* + * disable all IRQ, + * and, wait all data was sent + */ + cr = ssi->cr_own | + ssi->cr_clk; - rsnd_ssi_hw_start(ssi, io); + rsnd_mod_write(mod, SSICR, cr | EN); + rsnd_ssi_status_check(mod, DIRQ); - rsnd_ssi_irq_enable(mod); + /* + * disable SSI, + * and, wait idle state + */ + rsnd_mod_write(mod, SSICR, cr); /* disabled all */ + rsnd_ssi_status_check(mod, IIRQ); return 0; } @@ -451,13 +466,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - rsnd_ssi_irq_disable(mod); - - rsnd_ssi_record_error(ssi); - - rsnd_ssi_hw_stop(io, ssi); + /* + * don't stop if not last user + * see also + * rsnd_ssi_start + * rsnd_ssi_interrupt + */ + if (ssi->usrcnt > 1) + return 0; - return 0; + return __rsnd_ssi_stop(mod, io, priv); } static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, @@ -505,8 +523,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - rsnd_ssi_stop(mod, io, priv); - rsnd_ssi_start(mod, io, priv); + __rsnd_ssi_stop(mod, io, priv); + __rsnd_ssi_start(mod, io, priv); } if (ssi->err > 1024) { @@ -535,6 +553,27 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) /* * SSI PIO */ +static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (!__rsnd_ssi_is_pin_sharing(mod)) + return; + + switch (rsnd_mod_id(mod)) { + case 1: + case 2: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); + break; + case 4: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); + break; + case 8: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); + break; + } +} + static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -543,6 +582,8 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; + rsnd_ssi_parent_attach(mod, io, priv); + ret = rsnd_ssiu_attach(io, mod); if (ret < 0) return ret; @@ -679,28 +720,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - - if (!__rsnd_ssi_is_pin_sharing(mod)) - return; - - switch (rsnd_mod_id(mod)) { - case 1: - case 2: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); - break; - case 4: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); - break; - case 8: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); - break; - } -} - - static void rsnd_of_parse_ssi(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) @@ -810,8 +829,6 @@ int rsnd_ssi_probe(struct platform_device *pdev, RSND_MOD_SSI, i); if (ret) return ret; - - rsnd_ssi_parent_setup(priv, ssi); } return 0; -- cgit v1.2.3 From f36a82264d5a4ba90f093d397d65b7fdc763885a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 28 Oct 2015 04:30:11 +0000 Subject: ASoC: rsnd: call rsnd_src_quit() from rsnd_src_quit_gen2() 2d604e03("ASoC: rsnd: disable SRC.out only when stop timing") added rsnd_src_quit_gen2(), but it should call rsnd_src_quit() same as before. This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index a710799cb3a1..776b0efec4d6 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -621,7 +621,7 @@ static int rsnd_src_quit_gen2(struct rsnd_mod *mod, /* stop both out/in */ rsnd_mod_write(mod, SRC_CTRL, 0); - return 0; + return rsnd_src_quit(mod, io, priv); } static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, -- cgit v1.2.3 From 9c66eedc17bdf180d952e8d3550a23c2f93d9fff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 28 Oct 2015 04:31:03 +0000 Subject: ASoC: rsnd: fixup rsnd_dmapp_stop() return value 45a4394d03("ASoC: rsnd: use mod base common method on DMA phase3") Exchanged "void rsnd_dmapp_stop()" to "int rsnd_dmapp_stop()", but it returns inverted value. This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index fc70e97500ad..9917b985c403 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -368,11 +368,11 @@ static int rsnd_dmapp_stop(struct rsnd_mod *mod, for (i = 0; i < 1024; i++) { if (0 == rsnd_dmapp_read(dma, PDMACHCR)) - return -EIO; + return 0; udelay(1); } - return 0; + return -EIO; } static int rsnd_dmapp_start(struct rsnd_mod *mod, -- cgit v1.2.3 From 8b27418f300cafbdbbb8cfa9c29d398ed34d6723 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 28 Oct 2015 16:03:48 +0100 Subject: ASoC: rsnd: Add missing initialization of ADG req_rate If the "clock-frequency" DT property is not found, req_rate is used uninitialized, and the "audio_clkout" clock will be created with an arbitrary clock rate. This uninitialized kernel stack data may leak to userspace through /sys/kernel/debug/clk/clk_summary, cfr. the value in the "rate" column: clock enable_cnt prepare_cnt rate accuracy phase -------------------------------------------------------------------- audio_clkout 0 0 4001836240 0 0 Signed-off-by: Geert Uytterhoeven Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2a5b3a293cd2..b123734f9fbd 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -437,7 +437,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; - u32 rate, req_rate, div; + u32 rate, req_rate = 0, div; uint32_t count = 0; unsigned long req_48kHz_rate, req_441kHz_rate; int i; -- cgit v1.2.3 From dcc5a7b3b069cca17f3c5254006c66b99e87ffd3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Nov 2015 08:43:33 +0000 Subject: ASoC: rsnd: move CMD related operation to cmd.c 8cca6e11c1 ("ASoC: rsnd: use mod base common method on CMD") added cmd.c. Let's move CMD related operation to cmd.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 20 ++++++++++++++++++++ sound/soc/sh/rcar/dvc.c | 24 +----------------------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 731d74b13e92..47ef47c22217 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -81,14 +81,34 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); + rsnd_adg_set_cmd_timsel_gen2(mod, io); + + return 0; +} + +static int rsnd_cmd_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ rsnd_mod_write(mod, CMD_CTRL, 0x10); return 0; } +static int rsnd_cmd_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, CMD_CTRL, 0); + + return 0; +} + static struct rsnd_mod_ops rsnd_cmd_ops = { .name = CMD_NAME, .init = rsnd_cmd_init, + .start = rsnd_cmd_start, + .stop = rsnd_cmd_stop, }; int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d207000efef0..651c057b2113 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -171,7 +171,7 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); - rsnd_adg_set_cmd_timsel_gen2(mod, io); + rsnd_dvc_initialize_unlock(mod); return 0; } @@ -185,26 +185,6 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod, return 0; } -static int rsnd_dvc_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dvc_initialize_unlock(mod); - - rsnd_mod_write(mod, CMD_CTRL, 0x10); - - return 0; -} - -static int rsnd_dvc_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0); - - return 0; -} - static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) @@ -278,8 +258,6 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { .remove = rsnd_dvc_remove_, .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, - .start = rsnd_dvc_start, - .stop = rsnd_dvc_stop, .pcm_new = rsnd_dvc_pcm_new, }; -- cgit v1.2.3 From ca16cc61592377ebd48d5f22fd823b592c80038e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Nov 2015 08:44:12 +0000 Subject: ASoC: rsnd: DVC settings matches to datasheet Current DVC settings order was rough. This patch makes it match to datasheet. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 119 +++++++++++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 651c057b2113..0dc8a2a99fa4 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -70,65 +70,105 @@ static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_SWRSR, 1); } -#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1) -#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0) -static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable) -{ - rsnd_mod_write(mod, DVC_DVUIR, enable); -} +#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) +#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) -static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) +static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); u32 val[RSND_DVC_CHANNELS]; - u32 dvucr = 0; - u32 mute = 0; int i; - for (i = 0; i < dvc->mute.cfg.size; i++) - mute |= (!!dvc->mute.cfg.val[i]) << i; + /* Enable Ramp */ + if (dvc->ren.val) + for (i = 0; i < RSND_DVC_CHANNELS; i++) + val[i] = dvc->volume.cfg.max; + else + for (i = 0; i < RSND_DVC_CHANNELS; i++) + val[i] = dvc->volume.val[i]; - /* Disable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 0); + /* Enable Digital Volume */ + rsnd_mod_write(mod, DVC_VOL0R, val[0]); + rsnd_mod_write(mod, DVC_VOL1R, val[1]); +} + +static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 dvucr = 0; + u32 vrctr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + + /* Enable Digital Volume, Zero Cross Mute Mode */ + dvucr |= 0x101; /* Enable Ramp */ if (dvc->ren.val) { dvucr |= 0x10; - /* Digital Volume Max */ - for (i = 0; i < RSND_DVC_CHANNELS; i++) - val[i] = dvc->volume.cfg.max; - - rsnd_mod_write(mod, DVC_VRCTR, 0xff); - rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 | - dvc->rdown.val); /* * FIXME !! * use scale-downed Digital Volume * as Volume Ramp * 7F FFFF -> 3FF */ - rsnd_mod_write(mod, DVC_VRDBR, - 0x3ff - (dvc->volume.val[0] >> 13)); - - } else { - for (i = 0; i < RSND_DVC_CHANNELS; i++) - val[i] = dvc->volume.val[i]; + vrctr = 0xff; + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); } - /* Enable Digital Volume */ - dvucr |= 0x100; - rsnd_mod_write(mod, DVC_VOL0R, val[0]); - rsnd_mod_write(mod, DVC_VOL1R, val[1]); + /* Initialize operation */ + rsnd_mod_write(mod, DVC_DVUIR, 1); + + /* General Information */ + rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); + rsnd_mod_write(mod, DVC_DVUCR, dvucr); + + /* Volume Ramp Parameter */ + rsnd_mod_write(mod, DVC_VRCTR, vrctr); + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); + + /* cancel operation */ + rsnd_mod_write(mod, DVC_DVUIR, 0); +} + +static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 zcmcr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + int i; + + for (i = 0; i < dvc->mute.cfg.size; i++) + zcmcr |= (!!dvc->mute.cfg.val[i]) << i; - /* Enable Mute */ - if (mute) { - dvucr |= 0x1; - rsnd_mod_write(mod, DVC_ZCMCR, mute); + if (dvc->ren.val) { + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); } - rsnd_mod_write(mod, DVC_DVUCR, dvucr); + /* Disable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 0); + + /* Zero Cross Mute Function */ + rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); + + /* Volume Ramp Function */ + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + /* add DVC_VRWTR here */ + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); /* Enable DVC Register access */ rsnd_mod_write(mod, DVC_DVUER, 1); @@ -164,15 +204,10 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_dvc_soft_reset(mod); - rsnd_dvc_initialize_lock(mod); + rsnd_dvc_volume_init(io, mod); - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); - - /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); - rsnd_dvc_initialize_unlock(mod); - return 0; } -- cgit v1.2.3 From 13e0d17d08d1d651aa119c286f74cf366caf09dd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Nov 2015 08:44:32 +0000 Subject: ASoC: rsnd: MIX settings matches to datasheet Current MIX settings order was rough. This patch makes it match to datasheet. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/mix.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index bcbd821981a9..2baa2d79bfc0 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -31,24 +31,41 @@ static void rsnd_mix_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, MIX_SWRSR, 1); } -#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1) -#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0) -static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable) +static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { - rsnd_mod_write(mod, MIX_MIXIR, enable); + rsnd_mod_write(mod, MIX_MDBAR, 0); + rsnd_mod_write(mod, MIX_MDBBR, 0); + rsnd_mod_write(mod, MIX_MDBCR, 0); + rsnd_mod_write(mod, MIX_MDBDR, 0); +} + +static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_MIXIR, 1); + + /* General Information */ + rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); + + /* volume step */ + rsnd_mod_write(mod, MIX_MIXMR, 0); + rsnd_mod_write(mod, MIX_MVPDR, 0); + + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); + + rsnd_mod_write(mod, MIX_MIXIR, 0); } static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { - /* Disable MIX dB setting */ rsnd_mod_write(mod, MIX_MDBER, 0); - rsnd_mod_write(mod, MIX_MDBAR, 0); - rsnd_mod_write(mod, MIX_MDBBR, 0); - rsnd_mod_write(mod, MIX_MDBCR, 0); - rsnd_mod_write(mod, MIX_MDBDR, 0); + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); /* Enable MIX dB setting */ rsnd_mod_write(mod, MIX_MDBER, 1); @@ -69,18 +86,10 @@ static int rsnd_mix_init(struct rsnd_mod *mod, rsnd_mix_soft_reset(mod); - rsnd_mix_initialize_lock(mod); - - rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); - - /* volume step */ - rsnd_mod_write(mod, MIX_MIXMR, 0); - rsnd_mod_write(mod, MIX_MVPDR, 0); + rsnd_mix_volume_init(io, mod); rsnd_mix_volume_update(io, mod); - rsnd_mix_initialize_unlock(mod); - return 0; } -- cgit v1.2.3 From 81ad174db5ca8f372da6dc31a4ca25d52f9bec5f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 5 Nov 2015 08:50:10 +0000 Subject: ASoC: rsnd: tidyup comment position of rsnd_mod_xxx f1df12290("ASoC: rsnd: add common mod confirm method") added rsnd_mod_make_sure(), but rsnd_mod_xxx() comment position was wrong. This patch tidyup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 5586b888db56..1363966fa957 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -127,6 +127,9 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match); #define rsnd_info_id(priv, io, name) \ ((io)->info->name - priv->info->name##_info) +/* + * rsnd_mod functions + */ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) { if (mod->type != type) { @@ -138,9 +141,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) } } -/* - * rsnd_mod functions - */ char *rsnd_mod_name(struct rsnd_mod *mod) { if (!mod || !mod->ops) -- cgit v1.2.3 From 68a550248e295ba548e30c876ccdec351e286eee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 5 Nov 2015 08:51:15 +0000 Subject: ASoC: rsnd: call clk_prepare()/clk_enable() for AUDIO_CLKx ADG can output AUDIO_CLKOUTx, and these are generated from AUDIO_CLKx. Thus we need to call clk_prepare()/clk_enable() for AUDIO_CLKx. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 21 +++++++++++++++++++-- sound/soc/sh/rcar/core.c | 1 + sound/soc/sh/rcar/rsnd.h | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index b123734f9fbd..1946ce8baf2e 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -418,15 +418,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; - int i; + int i, ret; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } - for_each_rsnd_clk(clk, adg, i) + for_each_rsnd_clk(clk, adg, i) { + ret = clk_prepare_enable(clk); + if (ret < 0) + dev_warn(dev, "can't use clk %d\n", i); + dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); + } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, @@ -600,3 +605,15 @@ int rsnd_adg_probe(struct platform_device *pdev, return 0; } + +void rsnd_adg_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct clk *clk; + int i; + + for_each_rsnd_clk(clk, adg, i) { + clk_disable_unprepare(clk); + } +} diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1363966fa957..81250cf6788d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1227,6 +1227,7 @@ static int rsnd_remove(struct platform_device *pdev) rsnd_mix_remove, rsnd_dvc_remove, rsnd_cmd_remove, + rsnd_adg_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 599dfb69555a..8efa19fa2b6e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -405,6 +405,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); int rsnd_adg_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); +void rsnd_adg_remove(struct platform_device *pdev, + struct rsnd_priv *priv); int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, struct rsnd_mod *mod, unsigned int src_rate, -- cgit v1.2.3 From 2458c37779ddb91b4109949d86f5a5e193ba415b Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 6 Nov 2015 19:38:14 +0800 Subject: ASoC: rockchip: i2s: change bclk and lrck according to sample rates This patch sets the dividers autonomously. when i2s works on master mode, and sample rates changed. We need to change bclk and lrck at the same time for cpu internal side. As the input source clock to the module is MCLK_I2S, and by the divider of the module, the clock generator generates SCLK and LRCK to transmitter and receiver. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 58ee64594f07..ce880f3bccc7 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -41,6 +41,7 @@ struct rk_i2s_dev { */ bool tx_start; bool rx_start; + bool is_master_mode; }; static int i2s_runtime_suspend(struct device *dev) @@ -174,9 +175,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_CBS_CFS: /* Set source clock in Master mode */ val = I2S_CKR_MSS_MASTER; + i2s->is_master_mode = true; break; case SND_SOC_DAIFMT_CBM_CFM: val = I2S_CKR_MSS_SLAVE; + i2s->is_master_mode = false; break; default: return -EINVAL; @@ -228,6 +231,26 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, struct rk_i2s_dev *i2s = to_info(dai); struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned int val = 0; + unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck; + + if (i2s->is_master_mode) { + mclk_rate = clk_get_rate(i2s->mclk); + bclk_rate = 2 * 32 * params_rate(params); + if (bclk_rate && mclk_rate % bclk_rate) + return -EINVAL; + + div_bclk = mclk_rate / bclk_rate; + div_lrck = bclk_rate / params_rate(params); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_MDIV_MASK, + I2S_CKR_MDIV(div_bclk)); + + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_TSD_MASK | + I2S_CKR_RSD_MASK, + I2S_CKR_TSD(div_lrck) | + I2S_CKR_RSD(div_lrck)); + } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: -- cgit v1.2.3 From a4ebd38042cf479a6917f09fbb1cf1f093dcf60d Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 6 Nov 2015 19:38:15 +0800 Subject: ASoC: rockchip-max98090: Allow more sample rates The MAX98090 audio codec support sample rates from 8 to 96 kHz as the dai claim. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 26567b10393a..543610282cdb 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -80,11 +80,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: case 16000: + case 24000: + case 32000: case 48000: + case 64000: case 96000: mclk = 12288000; break; + case 11025: + case 22050: case 44100: + case 88200: mclk = 11289600; break; default: -- cgit v1.2.3 From 3a3b070da98e43037e35b9ad02eb0fff1a57e318 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 6 Nov 2015 19:38:16 +0800 Subject: ASoC: rockchip-rt5645: Allow more sample rates The RT5645 audio codec support sample rates from 8 to 96 kHz as the dai claim. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_rt5645.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 68c62e4c2316..440a8026346a 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -79,11 +79,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: case 16000: + case 24000: + case 32000: case 48000: + case 64000: case 96000: mclk = 12288000; break; + case 11025: + case 22050: case 44100: + case 88200: mclk = 11289600; break; default: -- cgit v1.2.3 From 4bbda49cc40f6c2e5cc3a5dd22cded1d217e074d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 21 Oct 2015 16:18:19 +0800 Subject: ASoC: rt298: fix remove unnedded clk setting The bit is no longer present. So remove it. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index b3f795c60749..30c6de62ae6c 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -854,8 +854,6 @@ static int rt298_set_dai_sysclk(struct snd_soc_dai *dai, } else { snd_soc_update_bits(codec, RT298_I2S_CTRL2, 0x0100, 0x0100); - snd_soc_update_bits(codec, - RT298_PLL_CTRL, 0x4, 0x4); snd_soc_update_bits(codec, RT298_PLL_CTRL1, 0x20, 0x0); } -- cgit v1.2.3 From cdab0d4ecc1a890aece7102c2074bf73175b9935 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Thu, 29 Oct 2015 15:31:59 -0700 Subject: ASoC: rt5677: use 'active low' logic for reset pin According to the datasheet RESET is active low pin, i.e. system goes to reset state when pin signal is low. The previous implementeation was assuming the pin is configured as 'active high' in DTS. Changle the gpio handling code and DTS configuration to 'active low'. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 2 +- sound/soc/codecs/rt5677.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index f07078997f87..1b3c13d206ff 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -18,7 +18,7 @@ Required properties: Optional properties: - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. -- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. +- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low. - realtek,in1-differential - realtek,in2-differential diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index b4cd7e3bf5f8..f73fd125e49c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4766,7 +4766,7 @@ static int rt5677_remove(struct snd_soc_codec *codec) regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); return 0; } @@ -4781,7 +4781,7 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_mark_dirty(rt5677->regmap); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); } return 0; @@ -4793,7 +4793,7 @@ static int rt5677_resume(struct snd_soc_codec *codec) if (!rt5677->dsp_vad_en) { gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); - gpiod_set_value_cansleep(rt5677->reset_pin, 1); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); @@ -5138,7 +5138,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, return ret; } rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, - "realtek,reset", GPIOD_OUT_HIGH); + "realtek,reset", GPIOD_OUT_LOW); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); -- cgit v1.2.3 From 700dadfefc3df1f63dfbae7cb42fda147f4c074c Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 1 Nov 2015 20:23:39 +0100 Subject: ASoC: wm9713: convert to regmap Convert the Wolfson WM9713 to regmap API. This will leverage all the regmap functions (debug, registers update, etc ...). As a bonus, this will pave the path to gpio chip introduction, and devicetree support. This was tested on the mioa701 board, pxa27x based, in PCM playback, and through suspend/resume. Signed-off-by: Robert Jarzmik Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/wm9713.c | 174 ++++++++++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 67 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..a62b91989ac7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -891,6 +891,7 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate + select REGMAP_AC97 # Amp config SND_SOC_LM4857 diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 4083a5130cbd..22985c42764c 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -39,33 +40,15 @@ struct wm9713_priv { struct mutex lock; }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg); -static int ac97_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val); - -/* - * WM9713 register cache - * Reg 0x3c bit 15 is used by touch driver. - */ -static const u16 wm9713_reg[] = { - 0x6174, 0x8080, 0x8080, 0x8080, - 0xc880, 0xe808, 0xe808, 0x0808, - 0x00da, 0x8000, 0xd600, 0xaaa0, - 0xaaa0, 0xaaa0, 0x0000, 0x0000, - 0x0f0f, 0x0040, 0x0000, 0x7f00, - 0x0405, 0x0410, 0xbb80, 0xbb80, - 0x0000, 0xbb80, 0x0000, 0x4523, - 0x0000, 0x2000, 0x7eff, 0xffff, - 0x0000, 0x0000, 0x0080, 0x0000, - 0x0000, 0x0000, 0xfffe, 0xffff, - 0x0000, 0x0000, 0x0000, 0xfffe, - 0x4000, 0x0000, 0x0000, 0x0000, - 0xb032, 0x3e00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0006, - 0x0001, 0x0000, 0x574d, 0x4c13, -}; +static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return snd_soc_read(codec, reg); +} +static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + return snd_soc_write(codec, reg, val); +} #define HPL_MIXER 0 #define HPR_MIXER 1 @@ -674,39 +657,97 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { {"Capture Mono Mux", "Right", "Right Capture Source"}, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) +static bool wm9713_readable_reg(struct device *dev, unsigned int reg) { - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || - reg == AC97_CD) - return soc_ac97_ops->read(wm9713->ac97, reg); - else { - reg = reg >> 1; - - if (reg >= (ARRAY_SIZE(wm9713_reg))) - return -EIO; - - return cache[reg]; + switch (reg) { + case AC97_RESET ... AC97_PCM_SURR_DAC_RATE: + case AC97_PCM_LR_ADC_RATE: + case AC97_CENTER_LFE_MASTER: + case AC97_SPDIF ... AC97_LINE1_LEVEL: + case AC97_GPIO_CFG ... 0x5c: + case AC97_CODEC_CLASS_REV ... AC97_PCI_SID: + case 0x74 ... AC97_VENDOR_ID2: + return true; + default: + return false; } } -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) +static bool wm9713_writeable_reg(struct device *dev, unsigned int reg) { - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + switch (reg) { + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return false; + default: + return wm9713_readable_reg(dev, reg); + } +} - u16 *cache = codec->reg_cache; - soc_ac97_ops->write(wm9713->ac97, reg, val); - reg = reg >> 1; - if (reg < (ARRAY_SIZE(wm9713_reg))) - cache[reg] = val; +static const struct reg_default wm9713_reg_defaults[] = { + { 0x02, 0x8080 }, /* Speaker Output Volume */ + { 0x04, 0x8080 }, /* Headphone Output Volume */ + { 0x06, 0x8080 }, /* Out3/OUT4 Volume */ + { 0x08, 0xc880 }, /* Mono Volume */ + { 0x0a, 0xe808 }, /* LINEIN Volume */ + { 0x0c, 0xe808 }, /* DAC PGA Volume */ + { 0x0e, 0x0808 }, /* MIC PGA Volume */ + { 0x10, 0x00da }, /* MIC Routing Control */ + { 0x12, 0x8000 }, /* Record PGA Volume */ + { 0x14, 0xd600 }, /* Record Routing */ + { 0x16, 0xaaa0 }, /* PCBEEP Volume */ + { 0x18, 0xaaa0 }, /* VxDAC Volume */ + { 0x1a, 0xaaa0 }, /* AUXDAC Volume */ + { 0x1c, 0x0000 }, /* Output PGA Mux */ + { 0x1e, 0x0000 }, /* DAC 3D control */ + { 0x20, 0x0f0f }, /* DAC Tone Control*/ + { 0x22, 0x0040 }, /* MIC Input Select & Bias */ + { 0x24, 0x0000 }, /* Output Volume Mapping & Jack */ + { 0x26, 0x7f00 }, /* Powerdown Ctrl/Stat*/ + { 0x28, 0x0405 }, /* Extended Audio ID */ + { 0x2a, 0x0410 }, /* Extended Audio Start/Ctrl */ + { 0x2c, 0xbb80 }, /* Audio DACs Sample Rate */ + { 0x2e, 0xbb80 }, /* AUXDAC Sample Rate */ + { 0x32, 0xbb80 }, /* Audio ADCs Sample Rate */ + { 0x36, 0x4523 }, /* PCM codec control */ + { 0x3a, 0x2000 }, /* SPDIF control */ + { 0x3c, 0xfdff }, /* Powerdown 1 */ + { 0x3e, 0xffff }, /* Powerdown 2 */ + { 0x40, 0x0000 }, /* General Purpose */ + { 0x42, 0x0000 }, /* Fast Power-Up Control */ + { 0x44, 0x0080 }, /* MCLK/PLL Control */ + { 0x46, 0x0000 }, /* MCLK/PLL Control */ + { 0x4c, 0xfffe }, /* GPIO Pin Configuration */ + { 0x4e, 0xffff }, /* GPIO Pin Polarity / Type */ + { 0x50, 0x0000 }, /* GPIO Pin Sticky */ + { 0x52, 0x0000 }, /* GPIO Pin Wake-Up */ + /* GPIO Pin Status */ + { 0x56, 0xfffe }, /* GPIO Pin Sharing */ + { 0x58, 0x4000 }, /* GPIO PullUp/PullDown */ + { 0x5a, 0x0000 }, /* Additional Functions 1 */ + { 0x5c, 0x0000 }, /* Additional Functions 2 */ + { 0x60, 0xb032 }, /* ALC Control */ + { 0x62, 0x3e00 }, /* ALC / Noise Gate Control */ + { 0x64, 0x0000 }, /* AUXDAC input control */ + { 0x74, 0x0000 }, /* Digitiser Reg 1 */ + { 0x76, 0x0006 }, /* Digitiser Reg 2 */ + { 0x78, 0x0001 }, /* Digitiser Reg 3 */ + { 0x7a, 0x0000 }, /* Digitiser Read Back */ +}; - return 0; -} +static const struct regmap_config wm9713_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .reg_defaults = wm9713_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults), + .volatile_reg = regmap_ac97_default_volatile, + .readable_reg = wm9713_readable_reg, + .writeable_reg = wm9713_writeable_reg, +}; /* PLL divisors */ struct _pll_div { @@ -1173,8 +1214,7 @@ static int wm9713_soc_suspend(struct snd_soc_codec *codec) static int wm9713_soc_resume(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - int i, ret; - u16 *cache = codec->reg_cache; + int ret; ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); @@ -1189,12 +1229,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) /* only synchronise the codec if warm reset failed */ if (ret == 0) { - for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) { - if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || - i == AC97_EXTENDED_MSTATUS || i > 0x66) - continue; - soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); - } + regcache_mark_dirty(codec->component.regmap); + snd_soc_cache_sync(codec); } return ret; @@ -1203,6 +1239,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap; int reg; wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID, @@ -1210,6 +1247,14 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) if (IS_ERR(wm9713->ac97)) return PTR_ERR(wm9713->ac97); + regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config); + if (IS_ERR(regmap)) { + snd_soc_free_ac97_codec(wm9713->ac97); + return PTR_ERR(regmap); + } + + snd_soc_codec_init_regmap(codec, regmap); + /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); @@ -1221,6 +1266,7 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(wm9713->ac97); return 0; } @@ -1230,13 +1276,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .remove = wm9713_soc_remove, .suspend = wm9713_soc_suspend, .resume = wm9713_soc_resume, - .read = ac97_read, - .write = ac97_write, .set_bias_level = wm9713_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm9713_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = wm9713_reg, .controls = wm9713_snd_ac97_controls, .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), -- cgit v1.2.3 From fa1a51f3cd9849fcfb811c7cd62d6e2028ad4ea9 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 1 Nov 2015 20:23:40 +0100 Subject: ASoC: wm9713: use snd_soc_*() calls to update ac97 registers Convert wm9713 to use the more modern registers manipulation functions, such as snd_soc_read(), snd_soc_write() and snd_soc_update_bits(). Signed-off-by: Robert Jarzmik Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 140 +++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 88 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 22985c42764c..79e143625ac3 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -40,16 +40,6 @@ struct wm9713_priv { struct mutex lock; }; -static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) -{ - return snd_soc_read(codec, reg); -} -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - #define HPL_MIXER 0 #define HPR_MIXER 1 @@ -203,18 +193,15 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - u16 status, rate; if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD)) return -EINVAL; /* Gracefully shut down the voice interface. */ - status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; - rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200); schedule_timeout_interruptible(msecs_to_jiffies(1)); - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); - ac97_write(codec, AC97_EXTENDED_MID, status); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000); return 0; } @@ -834,10 +821,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, /* turn PLL off ? */ if (freq_in == 0) { /* disable PLL power and select ext source */ - reg = ac97_read(codec, AC97_HANDSET_RATE); - ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200); wm9713->pll_in = 0; return 0; } @@ -847,7 +832,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, if (pll_div.k == 0) { reg = (pll_div.n << 12) | (pll_div.lf << 11) | (pll_div.divsel << 9) | (pll_div.divctl << 8); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); } else { /* write the fractional k to the reg 0x46 pages */ reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) | @@ -855,33 +840,31 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, /* K [21:20] */ reg = reg2 | (0x5 << 4) | (pll_div.k >> 20); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [19:16] */ reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [15:12] */ reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [11:8] */ reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [7:4] */ reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */ - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); } /* turn PLL on and select as source */ - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); - reg = ac97_read(codec, AC97_HANDSET_RATE); - ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000); wm9713->pll_in = freq_in; /* wait 10ms AC97 link frames for the link to stabilise */ @@ -904,10 +887,10 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, int tristate) { struct snd_soc_codec *codec = codec_dai->codec; - u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff; if (tristate) - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x6000, 0x0000); return 0; } @@ -920,36 +903,30 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; switch (div_id) { case WM9713_PCMCLK_DIV: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div); break; case WM9713_CLKA_MULT: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div); break; case WM9713_CLKB_MULT: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div); break; case WM9713_HIFI_DIV: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div); break; case WM9713_PCMBCLK_DIV: - reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff; - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div); + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div); break; case WM9713_PCMCLK_PLL_DIV: - reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80; - ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div); + snd_soc_update_bits(codec, AC97_LINE1_LEVEL, + 0x007f, div | 0x60); break; case WM9713_HIFI_PLL_DIV: - reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80; - ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div); + snd_soc_update_bits(codec, AC97_LINE1_LEVEL, + 0x007f, div | 0x70); break; default: return -EINVAL; @@ -962,7 +939,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5; + u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5; u16 reg = 0x8000; /* clock masters */ @@ -1015,8 +992,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, break; } - ac97_write(codec, AC97_GPIO_CFG, gpio); - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); + snd_soc_write(codec, AC97_GPIO_CFG, gpio); + snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg); return 0; } @@ -1025,24 +1002,24 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; + /* enable PCM interface in master mode */ switch (params_width(params)) { case 16: break; case 20: - reg |= 0x0004; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x0004); break; case 24: - reg |= 0x0008; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x0008); break; case 32: - reg |= 0x000c; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x000c); break; } - - /* enable PCM interface in master mode */ - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); return 0; } @@ -1052,17 +1029,15 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; int reg; - u16 vra; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int ac97_aux_prepare(struct snd_pcm_substream *substream, @@ -1070,17 +1045,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - u16 vra, xsle; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); - xsle = ac97_read(codec, AC97_PCI_SID); - ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001); + snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000); if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; - return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); + return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); } #define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ @@ -1169,27 +1141,23 @@ static struct snd_soc_dai_driver wm9713_dai[] = { static int wm9713_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 reg; - switch (level) { case SND_SOC_BIAS_ON: /* enable thermal shutdown */ - reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; - ac97_write(codec, AC97_EXTENDED_MID, reg); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: /* enable master bias and vmid */ - reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; - ac97_write(codec, AC97_EXTENDED_MID, reg); - ac97_write(codec, AC97_POWERDOWN, 0x0000); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000); + snd_soc_write(codec, AC97_POWERDOWN, 0x0000); break; case SND_SOC_BIAS_OFF: /* disable everything including AC link */ - ac97_write(codec, AC97_EXTENDED_MID, 0xffff); - ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff); + snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); break; } return 0; @@ -1197,16 +1165,14 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec, static int wm9713_soc_suspend(struct snd_soc_codec *codec) { - u16 reg; - /* Disable everything except touchpanel - that will be handled * by the touch driver and left disabled if touch is not in * use. */ - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff); - ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); - ac97_write(codec, AC97_POWERDOWN, 0x6f00); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff, + 0x7fff); + snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0x6f00); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); return 0; } @@ -1240,7 +1206,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); struct regmap *regmap; - int reg; wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); @@ -1256,8 +1221,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) snd_soc_codec_init_regmap(codec, regmap); /* unmute the adc - move to kcontrol */ - reg = ac97_read(codec, AC97_CD) & 0x7fff; - ac97_write(codec, AC97_CD, reg); + snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000); return 0; } -- cgit v1.2.3 From 6e5b143c1d86d75a6d18b9f2cbde3aaebae87423 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 10 Nov 2015 19:35:18 +0800 Subject: ASoC: rt5645: Use the mod_delayed_work instead of the queue_delayed_work and cancel_delayed_work_sync Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 672fafd8314a..4e81181c00c4 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -572,14 +572,12 @@ static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol, struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); int ret; - cancel_delayed_work_sync(&rt5645->rcclock_work); - regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU); ret = snd_soc_put_volsw(kcontrol, ucontrol); - queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work, + mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work, msecs_to_jiffies(200)); return ret; -- cgit v1.2.3 From a3af0c65836e714fa71dcaa0a81f6db83a212faa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 16 Nov 2015 04:51:21 +0000 Subject: ASoC: ak4613: add single-end optional property for IN/OUT pins ak4613 IN/OUT pin can be selected as differential/single-end. Default is differential, because it is register default settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak4613.txt | 10 ++++++++ sound/soc/codecs/ak4613.c | 29 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt index 15a919522b42..3cf63e7f8e77 100644 --- a/Documentation/devicetree/bindings/sound/ak4613.txt +++ b/Documentation/devicetree/bindings/sound/ak4613.txt @@ -7,6 +7,16 @@ Required properties: - compatible : "asahi-kasei,ak4613" - reg : The chip select number on the I2C bus +Optional properties: +- ak4613,in1-single-end : Boolean. Indicate input / output pins are single-ended. +- ak4613,in2-single-end rather than differential. +- ak4613,out1-single-end +- ak4613,out2-single-end +- ak4613,out3-single-end +- ak4613,out4-single-end +- ak4613,out5-single-end +- ak4613,out6-single-end + Example: &i2c { diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 07a266460ec3..394c10ff049e 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -79,6 +79,8 @@ struct ak4613_priv { unsigned int fmt; u8 fmt_ctrl; + u8 oc; + u8 ic; int cnt; }; @@ -343,6 +345,9 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl); snd_soc_write(codec, CTRL2, ctrl2); + snd_soc_write(codec, ICTRL, priv->ic); + snd_soc_write(codec, OCTRL, priv->oc); + hw_params_end: if (ret < 0) dev_warn(dev, "unsupported data width/format combination\n"); @@ -431,6 +436,28 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), }; +static void ak4613_parse_of(struct ak4613_priv *priv, + struct device *dev) +{ + struct device_node *np = dev->of_node; + char prop[32]; + int i; + + /* Input 1 - 2 */ + for (i = 0; i < 2; i++) { + snprintf(prop, sizeof(prop), "ak4613,in%d-single-end", i + 1); + if (!of_get_property(np, prop, NULL)) + priv->ic |= 1 << i; + } + + /* Output 1 - 6 */ + for (i = 0; i < 6; i++) { + snprintf(prop, sizeof(prop), "ak4613,out%d-single-end", i + 1); + if (!of_get_property(np, prop, NULL)) + priv->oc |= 1 << i; + } +} + static int ak4613_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -458,6 +485,8 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM; + ak4613_parse_of(priv, dev); + priv->fmt_ctrl = NO_FMT; priv->cnt = 0; -- cgit v1.2.3 From 35299f1779dbdcb61af4305904963b5bc9276eb9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 16 Nov 2015 06:01:29 +0000 Subject: ASoC: ak4613: tidyup CTRL1 value selection method Current CTRL1 selection method didn't care about simultaneous playback / capture. This patch tidyup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 90 ++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 394c10ff049e..dab127603ff6 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -74,16 +74,6 @@ #define DFS_DOUBLE_SPEED (1 << 2) #define DFS_QUAD_SPEED (2 << 2) -struct ak4613_priv { - struct mutex lock; - - unsigned int fmt; - u8 fmt_ctrl; - u8 oc; - u8 ic; - int cnt; -}; - struct ak4613_formats { unsigned int width; unsigned int fmt; @@ -94,6 +84,16 @@ struct ak4613_interface { struct ak4613_formats playback; }; +struct ak4613_priv { + struct mutex lock; + const struct ak4613_interface *iface; + + unsigned int fmt; + u8 oc; + u8 ic; + int cnt; +}; + /* * Playback Volume * @@ -128,7 +128,7 @@ static const struct reg_default ak4613_reg[] = { { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 }, }; -#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3) +#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3) #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt } static const struct ak4613_interface ak4613_iface[] = { /* capture */ /* playback */ @@ -242,7 +242,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, priv->cnt = 0; } if (!priv->cnt) - priv->fmt_ctrl = NO_FMT; + priv->iface = NULL; mutex_unlock(&priv->lock); } @@ -267,13 +267,35 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface, + int is_play, + unsigned int fmt, unsigned int width) +{ + const struct ak4613_formats *fmts; + + fmts = (is_play) ? &iface->playback : &iface->capture; + + if (fmts->fmt != fmt) + return false; + + if (fmt == SND_SOC_DAIFMT_RIGHT_J) { + if (fmts->width != width) + return false; + } else { + if (fmts->width < width) + return false; + } + + return true; +} + static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec); - const struct ak4613_formats *fmts; + const struct ak4613_interface *iface; struct device *dev = codec->dev; unsigned int width = params_width(params); unsigned int fmt = priv->fmt; @@ -307,33 +329,27 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, * It doesn't support TDM at this point */ fmt_ctrl = NO_FMT; - for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) { - fmts = (is_play) ? &ak4613_iface[i].playback : - &ak4613_iface[i].capture; - - if (fmts->fmt != fmt) - continue; + ret = -EINVAL; + iface = NULL; - if (fmt == SND_SOC_DAIFMT_RIGHT_J) { - if (fmts->width != width) - continue; - } else { - if (fmts->width < width) + mutex_lock(&priv->lock); + if (priv->iface) { + if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) + iface = priv->iface; + } else { + for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) { + if (!ak4613_dai_fmt_matching(ak4613_iface + i, + is_play, + fmt, width)) continue; + iface = ak4613_iface + i; + break; } - - fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i); - break; } - ret = -EINVAL; - if (fmt_ctrl == NO_FMT) - goto hw_params_end; - - mutex_lock(&priv->lock); - if ((priv->fmt_ctrl == NO_FMT) || - (priv->fmt_ctrl == fmt_ctrl)) { - priv->fmt_ctrl = fmt_ctrl; + if ((priv->iface == NULL) || + (priv->iface == iface)) { + priv->iface = iface; priv->cnt++; ret = 0; } @@ -342,6 +358,8 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto hw_params_end; + fmt_ctrl = AUDIO_IFACE_TO_VAL(iface); + snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl); snd_soc_write(codec, CTRL2, ctrl2); @@ -487,7 +505,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, ak4613_parse_of(priv, dev); - priv->fmt_ctrl = NO_FMT; + priv->iface = NULL; priv->cnt = 0; mutex_init(&priv->lock); -- cgit v1.2.3 From 49abc6cd58734803fb1428c3dfbb68fbc6ddb68c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 10 Nov 2015 16:54:54 +0800 Subject: ASoC: rt5645: Separate regmap for rt5645 and rt5650 rt5645.c support both rt5645 and rt5650 codec. And the default value of registers are not identical. So we use different regmap for the two codecs. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 209 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 4e81181c00c4..11cabf8e7551 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -226,6 +226,163 @@ static const struct reg_default rt5645_reg[] = { { 0xff, 0x6308 }, }; +static const struct reg_default rt5650_reg[] = { + { 0x00, 0x0000 }, + { 0x01, 0xc8c8 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x0a, 0x0002 }, + { 0x0b, 0x2827 }, + { 0x0c, 0xe000 }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x14, 0x3333 }, + { 0x16, 0x4b00 }, + { 0x18, 0x018b }, + { 0x19, 0xafaf }, + { 0x1a, 0xafaf }, + { 0x1b, 0x0001 }, + { 0x1c, 0x2f2f }, + { 0x1d, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x20, 0x0000 }, + { 0x27, 0x7060 }, + { 0x28, 0x7070 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5656 }, + { 0x2b, 0x5454 }, + { 0x2c, 0xaaa0 }, + { 0x2d, 0x0000 }, + { 0x2f, 0x1002 }, + { 0x31, 0x5000 }, + { 0x32, 0x0000 }, + { 0x33, 0x0000 }, + { 0x34, 0x0000 }, + { 0x35, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x3f, 0x0000 }, + { 0x40, 0x001f }, + { 0x41, 0x0000 }, + { 0x42, 0x001f }, + { 0x45, 0x6000 }, + { 0x46, 0x003e }, + { 0x47, 0x003e }, + { 0x48, 0xf807 }, + { 0x4a, 0x0004 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x01ff }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x01ff }, + { 0x53, 0xf000 }, + { 0x56, 0x0111 }, + { 0x57, 0x0064 }, + { 0x58, 0xef0e }, + { 0x59, 0xf0f0 }, + { 0x5a, 0xef0e }, + { 0x5b, 0xf0f0 }, + { 0x5c, 0xef0e }, + { 0x5d, 0xf0f0 }, + { 0x5e, 0xf000 }, + { 0x5f, 0x0000 }, + { 0x61, 0x0300 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c2 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x6a, 0x0000 }, + { 0x6c, 0x0aaa }, + { 0x70, 0x8000 }, + { 0x71, 0x8000 }, + { 0x72, 0x8000 }, + { 0x73, 0x7770 }, + { 0x74, 0x3e00 }, + { 0x75, 0x2409 }, + { 0x76, 0x000a }, + { 0x77, 0x0c00 }, + { 0x78, 0x0000 }, + { 0x79, 0x0123 }, + { 0x7a, 0x0123 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x83, 0x0000 }, + { 0x84, 0x0000 }, + { 0x85, 0x0000 }, + { 0x8a, 0x0000 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0646 }, + { 0x91, 0x0c06 }, + { 0x93, 0x0000 }, + { 0x94, 0x0200 }, + { 0x95, 0x0000 }, + { 0x9a, 0x2184 }, + { 0x9b, 0x010a }, + { 0x9c, 0x0aea }, + { 0x9d, 0x000c }, + { 0x9e, 0x0400 }, + { 0xa0, 0xa0a8 }, + { 0xa1, 0x0059 }, + { 0xa2, 0x0001 }, + { 0xae, 0x6000 }, + { 0xaf, 0x0000 }, + { 0xb0, 0x6000 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x020c }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x3100 }, + { 0xc0, 0x0000 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xc3, 0x2000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x1813 }, + { 0xd0, 0x0690 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0400 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xdb, 0x0003 }, + { 0xdc, 0x0049 }, + { 0xdd, 0x001b }, + { 0xdf, 0x0008 }, + { 0xe0, 0x4000 }, + { 0xe6, 0x8000 }, + { 0xe7, 0x0200 }, + { 0xec, 0xb300 }, + { 0xed, 0x0000 }, + { 0xf0, 0x001f }, + { 0xf1, 0x020c }, + { 0xf2, 0x1f00 }, + { 0xf3, 0x0000 }, + { 0xf4, 0x4000 }, + { 0xf8, 0x0000 }, + { 0xf9, 0x0000 }, + { 0xfa, 0x2060 }, + { 0xfb, 0x4040 }, + { 0xfc, 0x0000 }, + { 0xfd, 0x0002 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6308 }, +}; + struct rt5645_eq_param_s { unsigned short reg; unsigned short val; @@ -3316,6 +3473,31 @@ static const struct regmap_config rt5645_regmap = { .num_ranges = ARRAY_SIZE(rt5645_ranges), }; +static const struct regmap_config rt5650_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * + RT5645_PR_SPACING), + .volatile_reg = rt5645_volatile_register, + .readable_reg = rt5645_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5650_reg, + .num_reg_defaults = ARRAY_SIZE(rt5650_reg), + .ranges = rt5645_ranges, + .num_ranges = ARRAY_SIZE(rt5645_ranges), +}; + +static const struct regmap_config temp_regmap = { + .name="nocache", + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5645_VENDOR_ID2 + 1, + .cache_type = REGCACHE_NONE, +}; + static const struct i2c_device_id rt5645_i2c_id[] = { { "rt5645", 0 }, { "rt5650", 0 }, @@ -3426,6 +3608,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, struct rt5645_priv *rt5645; int ret, i; unsigned int val; + struct regmap *regmap; rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), GFP_KERNEL); @@ -3451,14 +3634,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return PTR_ERR(rt5645->gpiod_hp_det); } - rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); - if (IS_ERR(rt5645->regmap)) { - ret = PTR_ERR(rt5645->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) rt5645->supplies[i].supply = rt5645_supply_names[i]; @@ -3477,13 +3652,22 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", + ret); + return ret; + } + regmap_read(regmap, RT5645_VENDOR_ID2, &val); switch (val) { case RT5645_DEVICE_ID: + rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); rt5645->codec_type = CODEC_TYPE_RT5645; break; case RT5650_DEVICE_ID: + rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap); rt5645->codec_type = CODEC_TYPE_RT5650; break; default: @@ -3494,6 +3678,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, goto err_enable; } + if (IS_ERR(rt5645->regmap)) { + ret = PTR_ERR(rt5645->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + regmap_write(rt5645->regmap, RT5645_RESET, 0); ret = regmap_register_patch(rt5645->regmap, init_list, -- cgit v1.2.3 From c4f9374ddc461ed76be30f4d354a6d1ecb94dfa5 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Tue, 10 Nov 2015 15:32:07 +0800 Subject: ASoC: rockchip: i2s: compatible with different chips there maybe more than one i2s module inside chip, and these i2s modules have different channels features. for example: there are 3 i2s in rk3066, one support 8 channels playback and 2 channels capture, but the others only support 2 channels playback and 2 channels capture. in order to compatible with these various chips, we add playback and capture property to specify these values. there are default channels configuration in driver: 8 channels playback and 2 channels capture. if not add property, we use the default values. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index ce880f3bccc7..83b1b9c9e017 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -474,6 +474,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct rk_i2s_dev *i2s; + struct snd_soc_dai_driver *soc_dai; struct resource *res; void __iomem *regs; int ret; @@ -534,17 +535,26 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - /* refine capture channels */ + soc_dai = devm_kzalloc(&pdev->dev, + sizeof(*soc_dai), GFP_KERNEL); + if (!soc_dai) + return -ENOMEM; + + memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai)); + if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { + if (val >= 2 && val <= 8) + soc_dai->playback.channels_max = val; + } + if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { if (val >= 2 && val <= 8) - rockchip_i2s_dai.capture.channels_max = val; - else - rockchip_i2s_dai.capture.channels_max = 2; + soc_dai->capture.channels_max = val; } ret = devm_snd_soc_register_component(&pdev->dev, &rockchip_i2s_component, - &rockchip_i2s_dai, 1); + soc_dai, 1); + if (ret) { dev_err(&pdev->dev, "Could not register DAI\n"); goto err_suspend; -- cgit v1.2.3 From 93189ea425498339b13e5f74d254070d4a2b7d37 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Nov 2015 00:18:52 +0100 Subject: ASoC: Intel: constify sst_block_ops structures The sst_block_ops structure is never modified, and is thus declared as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 6 +++--- sound/soc/intel/common/sst-firmware.c | 4 ++-- sound/soc/intel/haswell/sst-haswell-dsp.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 4452cda28874..81aa1ed64201 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -243,7 +243,7 @@ struct sst_mem_block { u32 size; /* block size */ u32 index; /* block index 0..N */ enum sst_mem_type type; /* block memory type IRAM/DRAM */ - struct sst_block_ops *ops; /* block operations, if any */ + const struct sst_block_ops *ops;/* block operations, if any */ /* block status */ u32 bytes_used; /* bytes in use by modules */ @@ -378,8 +378,8 @@ void sst_block_free_scratch(struct sst_dsp *dsp); /* Register the DSPs memory blocks - would be nice to read from ACPI */ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, - u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, - void *private); + u32 size, enum sst_mem_type type, const struct sst_block_ops *ops, + u32 index, void *private); void sst_mem_block_unregister_all(struct sst_dsp *dsp); /* Create/Free DMA resources */ diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 1636a1eeb002..bee04a9707d8 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -1014,8 +1014,8 @@ EXPORT_SYMBOL_GPL(sst_module_runtime_restore); /* register a DSP memory block for use with FW based modules */ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, - u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, - void *private) + u32 size, enum sst_mem_type type, const struct sst_block_ops *ops, + u32 index, void *private) { struct sst_mem_block *block; diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c index 7f94920c8a4d..b2bec36d074c 100644 --- a/sound/soc/intel/haswell/sst-haswell-dsp.c +++ b/sound/soc/intel/haswell/sst-haswell-dsp.c @@ -607,7 +607,7 @@ static int hsw_block_disable(struct sst_mem_block *block) return 0; } -static struct sst_block_ops sst_hsw_ops = { +static const struct sst_block_ops sst_hsw_ops = { .enable = hsw_block_enable, .disable = hsw_block_disable, }; -- cgit v1.2.3 From 85d4a62140def5402bed3c6b914f6faafa185490 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 6 Nov 2015 06:46:30 +0000 Subject: ASoC: rsnd: SND_SOC_RCAR doesn't depend on DMA_OF 8616774("ASoC: rnsd: fix build regression without CONFIG_OF") added "depends on DMA_OF" in SND_SOC_RCAR to avoid compile error of sound/built-in.o: In function `rsnd_dma_request_channel': :(.text+0x9fb84): undefined reference to `of_dma_request_slave_channel' But, it was OF base DMAEngine API definition issue, not SND_SOC_RCAR issue. This patch remove DMA_OF dependence. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 206d1edab07c..c9902a6d6fa0 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" - depends on DMA_OF depends on COMMON_CLK select SND_SIMPLE_CARD select REGMAP_MMIO -- cgit v1.2.3 From 166765ea8b686c64b590fa62664a4adb35aa2d6a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 17 Nov 2015 11:17:33 +0530 Subject: ASoC: rt286: set combo jack for Skylake Skylake platform also uses combo jack configuration, so add Skylake to existing DMI match for combo jack Signed-off-by: Vinod Koul Acked-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index af2ed774b552..bc08f0c5a5f6 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1114,6 +1114,12 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS") } }, + { + .ident = "Intel Skylake RVP", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform") + } + }, { } }; -- cgit v1.2.3 From f46a93b820eb3707faf238cd769a004e2504515f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 17 Nov 2015 08:28:11 +0000 Subject: ASoC: rsnd: ssi: 24bit data needs right-aligned settings Data left/right aligned is controlled by PDTA bit on SSICR. But default is left-aligned. Thus 24bit sound will be very small sound without this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 3e814711f301..60ef074082e8 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -39,6 +39,7 @@ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ #define SWSP (1 << 12) /* Serial WS Polarity */ #define SDTA (1 << 10) /* Serial Data Alignment */ +#define PDTA (1 << 9) /* Parallel Data Alignment */ #define DEL (1 << 8) /* Serial Data Delay */ #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ @@ -274,7 +275,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (rsnd_ssi_is_parent(mod, io)) return 0; - cr = FORCE; + cr = FORCE | PDTA; /* * always use 32bit system word for easy clock calculation. -- cgit v1.2.3 From b323dd30718e2055adb5534e52f685a57c119c18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 17 Nov 2015 08:28:56 +0000 Subject: ASoC: ak4613: don't overwrite CTRL2 register Current code set DFS settings on CTRL2 register, but it overwrite default settings. This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index dab127603ff6..62c08a6395af 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -70,6 +70,7 @@ #define FMT_MASK (0xf8) /* CTRL2 */ +#define DFS_MASK (3 << 2) #define DFS_NORMAL_SPEED (0 << 2) #define DFS_DOUBLE_SPEED (1 << 2) #define DFS_QUAD_SPEED (2 << 2) @@ -361,7 +362,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, fmt_ctrl = AUDIO_IFACE_TO_VAL(iface); snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl); - snd_soc_write(codec, CTRL2, ctrl2); + snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2); snd_soc_write(codec, ICTRL, priv->ic); snd_soc_write(codec, OCTRL, priv->oc); -- cgit v1.2.3 From 9cc58712358cbfe51248ef369fc50671149b60fc Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 9 Nov 2015 19:02:29 +0800 Subject: ASoC: fsl-sai: don't set bclk for Tx/Rx Synchronous with another SAI mode In fsl_sai_set_bclk function, we should not set bclk for Tx/Rx Synchronous with another SAI mode. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a4435f5e3be9..7e421a97c090 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -354,13 +354,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) return -EINVAL; } - if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) { + /* + * 1) For Asynchronous mode, we must set RCR2 register for capture, and + * set TCR2 register for playback. + * 2) For Tx sync with Rx clock, we must set RCR2 register for playback + * and capture. + * 3) For Rx sync with Tx clock, we must set TCR2 register for playback + * and capture. + * 4) For Tx and Rx are both Synchronous with another SAI, we just + * ignore it. + */ + if ((sai->synchronous[TX] && !sai->synchronous[RX]) || + (!tx && !sai->synchronous[RX])) { regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_DIV_MASK, savediv - 1); - } else { + } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) || + (tx && !sai->synchronous[TX])) { regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); -- cgit v1.2.3 From 51659ca069ce5bdf20675a7967a39ef8419e87f2 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Mon, 9 Nov 2015 19:03:13 +0800 Subject: ASoC: fsl-sai: set xCR4/xCR5/xMR for SAI master mode For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync error sometimes. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7e421a97c090..520dbadaa8b1 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -427,6 +427,35 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr4 |= FSL_SAI_CR4_FRSZ(channels); + /* + * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will + * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), + * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync + * error. + */ + + if (!sai->is_slave_mode) { + if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { + regmap_update_bits(sai->regmap, FSL_SAI_TCR4, + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_TCR5, + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); + regmap_write(sai->regmap, FSL_SAI_TMR, + ~0UL - ((1 << channels) - 1)); + } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { + regmap_update_bits(sai->regmap, FSL_SAI_RCR4, + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_RCR5, + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); + regmap_write(sai->regmap, FSL_SAI_RMR, + ~0UL - ((1 << channels) - 1)); + } + } + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); -- cgit v1.2.3 From b45e68df065a9babc43b4b7cd223c412d34b6658 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Tue, 10 Nov 2015 15:26:12 +0800 Subject: ASoC: mediatek: Move 22M/24M clock control into I2S ops 22M/24M clocks are only required for I2S, so move the control to I2S DAI ops. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-pcm.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index f5baf3c38863..7f7134397f73 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -299,8 +299,6 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, dev_err(afe->dev, "Failed to enable m_ck\n"); return ret; } - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); } if (b_ck) { @@ -340,12 +338,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe, static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, struct clk *m_ck, struct clk *b_ck) { - if (m_ck) { - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); + if (m_ck) clk_disable_unprepare(m_ck); - } if (b_ck) clk_disable_unprepare(b_ck); } @@ -360,6 +354,8 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, return 0; mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); return 0; } @@ -373,6 +369,9 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, return; mtk_afe_set_i2s_enable(afe, false); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); /* disable AFE */ -- cgit v1.2.3 From d3cb2de2479bbbde29391393d68f2e313e1f0504 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Nov 2015 14:47:34 +0800 Subject: ASoC: rt5659: add rt5659 codec driver This is the initial codec driver for rt5659. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5659.txt | 75 + include/sound/rt5659.h | 49 + sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt5659.c | 4223 ++++++++++++++++++++ sound/soc/codecs/rt5659.h | 1819 +++++++++ 6 files changed, 6174 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt5659.txt create mode 100644 include/sound/rt5659.h create mode 100644 sound/soc/codecs/rt5659.c create mode 100644 sound/soc/codecs/rt5659.h (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt new file mode 100644 index 000000000000..5f79e7fde032 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5659.txt @@ -0,0 +1,75 @@ +RT5659/RT5658 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5659" or "realtek,rt5658". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- realtek,in1-differential +- realtek,in3-differential +- realtek,in4-differential + Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN2N pin as dmic1 data pin + 2: using GPIO5 pin as dmic1 data pin + 3: using GPIO9 pin as dmic1 data pin + 4: using GPIO11 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN2P pin as dmic2 data pin + 2: using GPIO6 pin as dmic2 data pin + 3: using GPIO10 pin as dmic2 data pin + 4: using GPIO12 pin as dmic2 data pin + +- realtek,jd-src + 0: No JD is used + 1: using JD3 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. +- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. + +Pins on the device (for linking into audio routes) for RT5659/RT5658: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * SPOL + * SPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + * SPDIF + +Example: + +rt5659 { + compatible = "realtek,rt5659"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h new file mode 100644 index 000000000000..656c4d58948d --- /dev/null +++ b/include/sound/rt5659.h @@ -0,0 +1,49 @@ +/* + * linux/sound/rt5659.h -- Platform data for RT5659 + * + * Copyright 2013 Realtek Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_RT5659_H +#define __LINUX_SND_RT5659_H + +enum rt5659_dmic1_data_pin { + RT5659_DMIC1_NULL, + RT5659_DMIC1_DATA_IN2N, + RT5659_DMIC1_DATA_GPIO5, + RT5659_DMIC1_DATA_GPIO9, + RT5659_DMIC1_DATA_GPIO11, +}; + +enum rt5659_dmic2_data_pin { + RT5659_DMIC2_NULL, + RT5659_DMIC2_DATA_IN2P, + RT5659_DMIC2_DATA_GPIO6, + RT5659_DMIC2_DATA_GPIO10, + RT5659_DMIC2_DATA_GPIO12, +}; + +enum rt5659_jd_src { + RT5659_JD_NULL, + RT5659_JD3, +}; + +struct rt5659_platform_data { + bool in1_diff; + bool in3_diff; + bool in4_diff; + + int ldo1_en; /* GPIO for LDO1_EN */ + int reset; /* GPIO for RESET */ + + enum rt5659_dmic1_data_pin dmic1_data_pin; + enum rt5659_dmic2_data_pin dmic2_data_pin; + enum rt5659_jd_src jd_src; +}; + +#endif + diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..f22c66bde292 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -93,6 +93,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C + select SND_SOC_RT5659 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_SGTL5000 if I2C @@ -526,11 +527,13 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5640=y default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y + default y if SND_SOC_RT5659=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y default m if SND_SOC_RT5640=m default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m + default m if SND_SOC_RT5659=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -562,6 +565,9 @@ config SND_SOC_RT5645 config SND_SOC_RT5651 tristate +config SND_SOC_RT5659 + tristate + config SND_SOC_RT5670 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..418e89eb25ca 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -89,6 +89,7 @@ snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o +snd-soc-rt5659-objs := rt5659.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-spi-objs := rt5677-spi.o @@ -284,6 +285,7 @@ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o +obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c new file mode 100644 index 000000000000..820d8fa62b5e --- /dev/null +++ b/sound/soc/codecs/rt5659.c @@ -0,0 +1,4223 @@ +/* + * rt5659.c -- RT5659/RT5658 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6231.h" +#include "rt5659.h" + +static const struct reg_default rt5659_reg[] = { + { 0x0000, 0x0000 }, + { 0x0001, 0x4848 }, + { 0x0002, 0x8080 }, + { 0x0003, 0xc8c8 }, + { 0x0004, 0xc80a }, + { 0x0005, 0x0000 }, + { 0x0006, 0x0000 }, + { 0x0007, 0x0103 }, + { 0x0008, 0x0080 }, + { 0x0009, 0x0000 }, + { 0x000a, 0x0000 }, + { 0x000c, 0x0000 }, + { 0x000d, 0x0000 }, + { 0x000f, 0x0808 }, + { 0x0010, 0x3080 }, + { 0x0011, 0x4a00 }, + { 0x0012, 0x4e00 }, + { 0x0015, 0x42c1 }, + { 0x0016, 0x0000 }, + { 0x0018, 0x000b }, + { 0x0019, 0xafaf }, + { 0x001a, 0xafaf }, + { 0x001b, 0x0011 }, + { 0x001c, 0x2f2f }, + { 0x001d, 0x2f2f }, + { 0x001e, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0020, 0x0000 }, + { 0x0021, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0026, 0xc060 }, + { 0x0027, 0xd8d8 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xaaaa }, + { 0x002b, 0xaaaa }, + { 0x002c, 0x00af }, + { 0x002d, 0x0000 }, + { 0x002f, 0x1002 }, + { 0x0031, 0x5000 }, + { 0x0032, 0x0000 }, + { 0x0033, 0x0000 }, + { 0x0034, 0x0000 }, + { 0x0035, 0x0000 }, + { 0x0036, 0x0000 }, + { 0x003a, 0x0000 }, + { 0x003b, 0x0000 }, + { 0x003c, 0x007f }, + { 0x003d, 0x0000 }, + { 0x003e, 0x007f }, + { 0x0040, 0x0808 }, + { 0x0046, 0x001f }, + { 0x0047, 0x001f }, + { 0x0048, 0x0003 }, + { 0x0049, 0xe061 }, + { 0x004a, 0x0000 }, + { 0x004b, 0x031f }, + { 0x004d, 0x0000 }, + { 0x004e, 0x001f }, + { 0x004f, 0x0000 }, + { 0x0050, 0x001f }, + { 0x0052, 0xf000 }, + { 0x0053, 0x0111 }, + { 0x0054, 0x0064 }, + { 0x0055, 0x0080 }, + { 0x0056, 0xef0e }, + { 0x0057, 0xf0f0 }, + { 0x0058, 0xef0e }, + { 0x0059, 0xf0f0 }, + { 0x005a, 0xef0e }, + { 0x005b, 0xf0f0 }, + { 0x005c, 0xf000 }, + { 0x005d, 0x0000 }, + { 0x005e, 0x1f2c }, + { 0x005f, 0x1f2c }, + { 0x0060, 0x2717 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x0000 }, + { 0x0067, 0x0000 }, + { 0x006a, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006c, 0x0000 }, + { 0x006e, 0x0000 }, + { 0x006f, 0x0000 }, + { 0x0070, 0x8000 }, + { 0x0071, 0x8000 }, + { 0x0072, 0x8000 }, + { 0x0073, 0x1110 }, + { 0x0074, 0xfe00 }, + { 0x0075, 0x2409 }, + { 0x0076, 0x000a }, + { 0x0077, 0x00f0 }, + { 0x0078, 0x0000 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0123 }, + { 0x007b, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0085, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x0088, 0x0000 }, + { 0x0089, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0000 }, + { 0x008f, 0x1000 }, + { 0x0090, 0x0646 }, + { 0x0091, 0x0c16 }, + { 0x0092, 0x0073 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0097, 0x0000 }, + { 0x0098, 0x0000 }, + { 0x0099, 0x0000 }, + { 0x009a, 0x0000 }, + { 0x009b, 0x0000 }, + { 0x009c, 0x007f }, + { 0x009d, 0x0000 }, + { 0x009e, 0x007f }, + { 0x009f, 0x0000 }, + { 0x00a0, 0x0060 }, + { 0x00a1, 0x90a1 }, + { 0x00ae, 0x2000 }, + { 0x00af, 0x0000 }, + { 0x00b0, 0x2000 }, + { 0x00b1, 0x0000 }, + { 0x00b2, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00b9, 0x0000 }, + { 0x00ba, 0x0000 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00bf, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0000 }, + { 0x00c2, 0x0000 }, + { 0x00c3, 0x0000 }, + { 0x00c4, 0x0003 }, + { 0x00c5, 0x0000 }, + { 0x00cb, 0xa02f }, + { 0x00cc, 0x0000 }, + { 0x00cd, 0x0e02 }, + { 0x00d6, 0x0000 }, + { 0x00d7, 0x2244 }, + { 0x00d9, 0x0809 }, + { 0x00da, 0x0000 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e4, 0x400c }, + { 0x00e5, 0x8031 }, + { 0x00ea, 0xb320 }, + { 0x00eb, 0x0000 }, + { 0x00ec, 0xb300 }, + { 0x00ed, 0x0000 }, + { 0x00f0, 0x0000 }, + { 0x00f1, 0x0202 }, + { 0x00f2, 0x0ddd }, + { 0x00f3, 0x0ddd }, + { 0x00f4, 0x0ddd }, + { 0x00f6, 0x0000 }, + { 0x00f7, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00f9, 0x0000 }, + { 0x00fa, 0x8000 }, + { 0x00fb, 0x0000 }, + { 0x00fc, 0x0000 }, + { 0x00fd, 0x0001 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6311 }, + { 0x0100, 0xaaaa }, + { 0x010a, 0xaaaa }, + { 0x010b, 0x00a0 }, + { 0x010c, 0xaeae }, + { 0x010d, 0xaaaa }, + { 0x010e, 0xaaa8 }, + { 0x010f, 0xa0aa }, + { 0x0110, 0xe02a }, + { 0x0111, 0xa702 }, + { 0x0112, 0xaaaa }, + { 0x0113, 0x2800 }, + { 0x0116, 0x0000 }, + { 0x0117, 0x0f00 }, + { 0x011a, 0x0020 }, + { 0x011b, 0x0011 }, + { 0x011c, 0x0150 }, + { 0x011d, 0x0000 }, + { 0x011e, 0x0000 }, + { 0x011f, 0x0000 }, + { 0x0120, 0x0000 }, + { 0x0121, 0x009b }, + { 0x0122, 0x5014 }, + { 0x0123, 0x0421 }, + { 0x0124, 0x7cea }, + { 0x0125, 0x0420 }, + { 0x0126, 0x5550 }, + { 0x0132, 0x0000 }, + { 0x0133, 0x0000 }, + { 0x0137, 0x5055 }, + { 0x0138, 0x3700 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x2020 }, + { 0x013b, 0x2020 }, + { 0x013c, 0x2005 }, + { 0x013e, 0x1f00 }, + { 0x013f, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0147, 0x0000 }, + { 0x0148, 0x0000 }, + { 0x0150, 0x1813 }, + { 0x0151, 0x0690 }, + { 0x0152, 0x1c17 }, + { 0x0153, 0x6883 }, + { 0x0154, 0xd3ce }, + { 0x0155, 0x352d }, + { 0x0156, 0x00eb }, + { 0x0157, 0x3717 }, + { 0x0158, 0x4c6a }, + { 0x0159, 0xe41b }, + { 0x015a, 0x2a13 }, + { 0x015b, 0xb600 }, + { 0x015c, 0xc730 }, + { 0x015d, 0x35d4 }, + { 0x015e, 0x00bf }, + { 0x0160, 0x0ec0 }, + { 0x0161, 0x0020 }, + { 0x0162, 0x0080 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x001f }, + { 0x0170, 0x4e80 }, + { 0x0171, 0x0020 }, + { 0x0172, 0x0080 }, + { 0x0173, 0x0800 }, + { 0x0174, 0x000c }, + { 0x0175, 0x0000 }, + { 0x0190, 0x3300 }, + { 0x0191, 0x2200 }, + { 0x0192, 0x0000 }, + { 0x01b0, 0x4b38 }, + { 0x01b1, 0x0000 }, + { 0x01b2, 0x0000 }, + { 0x01b3, 0x0000 }, + { 0x01c0, 0x0045 }, + { 0x01c1, 0x0540 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0030 }, + { 0x01c7, 0x0000 }, + { 0x01c8, 0x5757 }, + { 0x01c9, 0x5757 }, + { 0x01ca, 0x5757 }, + { 0x01cb, 0x5757 }, + { 0x01cc, 0x5757 }, + { 0x01cd, 0x5757 }, + { 0x01ce, 0x006f }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01de, 0x7d00 }, + { 0x01df, 0x10c0 }, + { 0x01e0, 0x06a1 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0001 }, + { 0x01e6, 0x0000 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x01f6, 0x1e04 }, + { 0x01f7, 0x01a1 }, + { 0x01f8, 0x0000 }, + { 0x01f9, 0x0000 }, + { 0x01fa, 0x0002 }, + { 0x01fb, 0x0000 }, + { 0x01fc, 0x0000 }, + { 0x01fd, 0x0000 }, + { 0x01fe, 0x0000 }, + { 0x0200, 0x066c }, + { 0x0201, 0x7fff }, + { 0x0202, 0x7fff }, + { 0x0203, 0x0000 }, + { 0x0204, 0x0000 }, + { 0x0205, 0x0000 }, + { 0x0206, 0x0000 }, + { 0x0207, 0x0000 }, + { 0x0208, 0x0000 }, + { 0x0256, 0x0000 }, + { 0x0257, 0x0000 }, + { 0x0258, 0x0000 }, + { 0x0259, 0x0000 }, + { 0x025a, 0x0000 }, + { 0x025b, 0x3333 }, + { 0x025c, 0x3333 }, + { 0x025d, 0x3333 }, + { 0x025e, 0x0000 }, + { 0x025f, 0x0000 }, + { 0x0260, 0x0000 }, + { 0x0261, 0x0022 }, + { 0x0262, 0x0300 }, + { 0x0265, 0x1e80 }, + { 0x0266, 0x0131 }, + { 0x0267, 0x0003 }, + { 0x0268, 0x0000 }, + { 0x0269, 0x0000 }, + { 0x026a, 0x0000 }, + { 0x026b, 0x0000 }, + { 0x026c, 0x0000 }, + { 0x026d, 0x0000 }, + { 0x026e, 0x0000 }, + { 0x026f, 0x0000 }, + { 0x0270, 0x0000 }, + { 0x0271, 0x0000 }, + { 0x0272, 0x0000 }, + { 0x0273, 0x0000 }, + { 0x0280, 0x0000 }, + { 0x0281, 0x0000 }, + { 0x0282, 0x0418 }, + { 0x0283, 0x7fff }, + { 0x0284, 0x7000 }, + { 0x0290, 0x01d0 }, + { 0x0291, 0x0100 }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x0300, 0x001f }, + { 0x0301, 0x032c }, + { 0x0302, 0x5f21 }, + { 0x0303, 0x4000 }, + { 0x0304, 0x4000 }, + { 0x0305, 0x0600 }, + { 0x0306, 0x8000 }, + { 0x0307, 0x0700 }, + { 0x0308, 0x001f }, + { 0x0309, 0x032c }, + { 0x030a, 0x5f21 }, + { 0x030b, 0x4000 }, + { 0x030c, 0x4000 }, + { 0x030d, 0x0600 }, + { 0x030e, 0x8000 }, + { 0x030f, 0x0700 }, + { 0x0310, 0x4560 }, + { 0x0311, 0xa4a8 }, + { 0x0312, 0x7418 }, + { 0x0313, 0x0000 }, + { 0x0314, 0x0006 }, + { 0x0315, 0x00ff }, + { 0x0316, 0xc400 }, + { 0x0317, 0x4560 }, + { 0x0318, 0xa4a8 }, + { 0x0319, 0x7418 }, + { 0x031a, 0x0000 }, + { 0x031b, 0x0006 }, + { 0x031c, 0x00ff }, + { 0x031d, 0xc400 }, + { 0x0320, 0x0f20 }, + { 0x0321, 0x8700 }, + { 0x0322, 0x7dc2 }, + { 0x0323, 0xa178 }, + { 0x0324, 0x5383 }, + { 0x0325, 0x7dc2 }, + { 0x0326, 0xa178 }, + { 0x0327, 0x5383 }, + { 0x0328, 0x003e }, + { 0x0329, 0x02c1 }, + { 0x032a, 0xd37d }, + { 0x0330, 0x00a6 }, + { 0x0331, 0x04c3 }, + { 0x0332, 0x27c8 }, + { 0x0333, 0xbf50 }, + { 0x0334, 0x0045 }, + { 0x0335, 0x2007 }, + { 0x0336, 0x7418 }, + { 0x0337, 0x0501 }, + { 0x0338, 0x0000 }, + { 0x0339, 0x0010 }, + { 0x033a, 0x1010 }, + { 0x0340, 0x0800 }, + { 0x0341, 0x0800 }, + { 0x0342, 0x0800 }, + { 0x0343, 0x0800 }, + { 0x0344, 0x0000 }, + { 0x0345, 0x0000 }, + { 0x0346, 0x0000 }, + { 0x0347, 0x0000 }, + { 0x0348, 0x0000 }, + { 0x0349, 0x0000 }, + { 0x034a, 0x0000 }, + { 0x034b, 0x0000 }, + { 0x034c, 0x0000 }, + { 0x034d, 0x0000 }, + { 0x034e, 0x0000 }, + { 0x034f, 0x0000 }, + { 0x0350, 0x0000 }, + { 0x0351, 0x0000 }, + { 0x0352, 0x0000 }, + { 0x0353, 0x0000 }, + { 0x0354, 0x0000 }, + { 0x0355, 0x0000 }, + { 0x0356, 0x0000 }, + { 0x0357, 0x0000 }, + { 0x0358, 0x0000 }, + { 0x0359, 0x0000 }, + { 0x035a, 0x0000 }, + { 0x035b, 0x0000 }, + { 0x035c, 0x0000 }, + { 0x035d, 0x0000 }, + { 0x035e, 0x2000 }, + { 0x035f, 0x0000 }, + { 0x0360, 0x2000 }, + { 0x0361, 0x2000 }, + { 0x0362, 0x0000 }, + { 0x0363, 0x2000 }, + { 0x0364, 0x0200 }, + { 0x0365, 0x0000 }, + { 0x0366, 0x0000 }, + { 0x0367, 0x0000 }, + { 0x0368, 0x0000 }, + { 0x0369, 0x0000 }, + { 0x036a, 0x0000 }, + { 0x036b, 0x0000 }, + { 0x036c, 0x0000 }, + { 0x036d, 0x0000 }, + { 0x036e, 0x0200 }, + { 0x036f, 0x0000 }, + { 0x0370, 0x0000 }, + { 0x0371, 0x0000 }, + { 0x0372, 0x0000 }, + { 0x0373, 0x0000 }, + { 0x0374, 0x0000 }, + { 0x0375, 0x0000 }, + { 0x0376, 0x0000 }, + { 0x0377, 0x0000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, +}; + +static bool rt5659_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5659_RESET: + case RT5659_EJD_CTRL_2: + case RT5659_SILENCE_CTRL: + case RT5659_DAC2_DIG_VOL: + case RT5659_HP_IMP_GAIN_2: + case RT5659_PDM_OUT_CTRL: + case RT5659_PDM_DATA_CTRL_1: + case RT5659_PDM_DATA_CTRL_4: + case RT5659_HAPTIC_GEN_CTRL_1: + case RT5659_HAPTIC_GEN_CTRL_3: + case RT5659_HAPTIC_LPF_CTRL_3: + case RT5659_CLK_DET: + case RT5659_MICBIAS_1: + case RT5659_ASRC_11: + case RT5659_ADC_EQ_CTRL_1: + case RT5659_DAC_EQ_CTRL_1: + case RT5659_INT_ST_1: + case RT5659_INT_ST_2: + case RT5659_GPIO_STA: + case RT5659_SINE_GEN_CTRL_1: + case RT5659_IL_CMD_1: + case RT5659_4BTN_IL_CMD_1: + case RT5659_PSV_IL_CMD_1: + case RT5659_AJD1_CTRL: + case RT5659_AJD2_AJD3_CTRL: + case RT5659_JD_CTRL_3: + case RT5659_VENDOR_ID: + case RT5659_VENDOR_ID_1: + case RT5659_DEVICE_ID: + case RT5659_MEMORY_TEST: + case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL: + case RT5659_VOL_TEST: + case RT5659_STO_NG2_CTRL_1: + case RT5659_STO_NG2_CTRL_5: + case RT5659_STO_NG2_CTRL_6: + case RT5659_STO_NG2_CTRL_7: + case RT5659_MONO_NG2_CTRL_1: + case RT5659_MONO_NG2_CTRL_5: + case RT5659_MONO_NG2_CTRL_6: + case RT5659_HP_IMP_SENS_CTRL_1: + case RT5659_HP_IMP_SENS_CTRL_3: + case RT5659_HP_IMP_SENS_CTRL_4: + case RT5659_HP_CALIB_CTRL_1: + case RT5659_HP_CALIB_CTRL_9: + case RT5659_HP_CALIB_STA_1: + case RT5659_HP_CALIB_STA_2: + case RT5659_HP_CALIB_STA_3: + case RT5659_HP_CALIB_STA_4: + case RT5659_HP_CALIB_STA_5: + case RT5659_HP_CALIB_STA_6: + case RT5659_HP_CALIB_STA_7: + case RT5659_HP_CALIB_STA_8: + case RT5659_HP_CALIB_STA_9: + case RT5659_MONO_AMP_CALIB_CTRL_1: + case RT5659_MONO_AMP_CALIB_CTRL_3: + case RT5659_MONO_AMP_CALIB_STA_1: + case RT5659_MONO_AMP_CALIB_STA_2: + case RT5659_MONO_AMP_CALIB_STA_3: + case RT5659_MONO_AMP_CALIB_STA_4: + case RT5659_SPK_PWR_LMT_STA_1: + case RT5659_SPK_PWR_LMT_STA_2: + case RT5659_SPK_PWR_LMT_STA_3: + case RT5659_SPK_PWR_LMT_STA_4: + case RT5659_SPK_PWR_LMT_STA_5: + case RT5659_SPK_PWR_LMT_STA_6: + case RT5659_SPK_DC_CAILB_CTRL_1: + case RT5659_SPK_DC_CAILB_STA_1: + case RT5659_SPK_DC_CAILB_STA_2: + case RT5659_SPK_DC_CAILB_STA_3: + case RT5659_SPK_DC_CAILB_STA_4: + case RT5659_SPK_DC_CAILB_STA_5: + case RT5659_SPK_DC_CAILB_STA_6: + case RT5659_SPK_DC_CAILB_STA_7: + case RT5659_SPK_DC_CAILB_STA_8: + case RT5659_SPK_DC_CAILB_STA_9: + case RT5659_SPK_DC_CAILB_STA_10: + case RT5659_SPK_VDD_STA_1: + case RT5659_SPK_VDD_STA_2: + case RT5659_SPK_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_2: + case RT5659_DRC1_PRIV_1: + case RT5659_DRC1_PRIV_4: + case RT5659_DRC1_PRIV_5: + case RT5659_DRC1_PRIV_6: + case RT5659_DRC1_PRIV_7: + case RT5659_DRC2_PRIV_1: + case RT5659_DRC2_PRIV_4: + case RT5659_DRC2_PRIV_5: + case RT5659_DRC2_PRIV_6: + case RT5659_DRC2_PRIV_7: + case RT5659_ALC_PGA_STA_1: + case RT5659_ALC_PGA_STA_2: + case RT5659_ALC_PGA_STA_3: + return true; + default: + return false; + } +} + +static bool rt5659_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5659_RESET: + case RT5659_SPO_VOL: + case RT5659_HP_VOL: + case RT5659_LOUT: + case RT5659_MONO_OUT: + case RT5659_HPL_GAIN: + case RT5659_HPR_GAIN: + case RT5659_MONO_GAIN: + case RT5659_SPDIF_CTRL_1: + case RT5659_SPDIF_CTRL_2: + case RT5659_CAL_BST_CTRL: + case RT5659_IN1_IN2: + case RT5659_IN3_IN4: + case RT5659_INL1_INR1_VOL: + case RT5659_EJD_CTRL_1: + case RT5659_EJD_CTRL_2: + case RT5659_EJD_CTRL_3: + case RT5659_SILENCE_CTRL: + case RT5659_PSV_CTRL: + case RT5659_SIDETONE_CTRL: + case RT5659_DAC1_DIG_VOL: + case RT5659_DAC2_DIG_VOL: + case RT5659_DAC_CTRL: + case RT5659_STO1_ADC_DIG_VOL: + case RT5659_MONO_ADC_DIG_VOL: + case RT5659_STO2_ADC_DIG_VOL: + case RT5659_STO1_BOOST: + case RT5659_MONO_BOOST: + case RT5659_STO2_BOOST: + case RT5659_HP_IMP_GAIN_1: + case RT5659_HP_IMP_GAIN_2: + case RT5659_STO1_ADC_MIXER: + case RT5659_MONO_ADC_MIXER: + case RT5659_AD_DA_MIXER: + case RT5659_STO_DAC_MIXER: + case RT5659_MONO_DAC_MIXER: + case RT5659_DIG_MIXER: + case RT5659_A_DAC_MUX: + case RT5659_DIG_INF23_DATA: + case RT5659_PDM_OUT_CTRL: + case RT5659_PDM_DATA_CTRL_1: + case RT5659_PDM_DATA_CTRL_2: + case RT5659_PDM_DATA_CTRL_3: + case RT5659_PDM_DATA_CTRL_4: + case RT5659_SPDIF_CTRL: + case RT5659_REC1_GAIN: + case RT5659_REC1_L1_MIXER: + case RT5659_REC1_L2_MIXER: + case RT5659_REC1_R1_MIXER: + case RT5659_REC1_R2_MIXER: + case RT5659_CAL_REC: + case RT5659_REC2_L1_MIXER: + case RT5659_REC2_L2_MIXER: + case RT5659_REC2_R1_MIXER: + case RT5659_REC2_R2_MIXER: + case RT5659_SPK_L_MIXER: + case RT5659_SPK_R_MIXER: + case RT5659_SPO_AMP_GAIN: + case RT5659_ALC_BACK_GAIN: + case RT5659_MONOMIX_GAIN: + case RT5659_MONOMIX_IN_GAIN: + case RT5659_OUT_L_GAIN: + case RT5659_OUT_L_MIXER: + case RT5659_OUT_R_GAIN: + case RT5659_OUT_R_MIXER: + case RT5659_LOUT_MIXER: + case RT5659_HAPTIC_GEN_CTRL_1: + case RT5659_HAPTIC_GEN_CTRL_2: + case RT5659_HAPTIC_GEN_CTRL_3: + case RT5659_HAPTIC_GEN_CTRL_4: + case RT5659_HAPTIC_GEN_CTRL_5: + case RT5659_HAPTIC_GEN_CTRL_6: + case RT5659_HAPTIC_GEN_CTRL_7: + case RT5659_HAPTIC_GEN_CTRL_8: + case RT5659_HAPTIC_GEN_CTRL_9: + case RT5659_HAPTIC_GEN_CTRL_10: + case RT5659_HAPTIC_GEN_CTRL_11: + case RT5659_HAPTIC_LPF_CTRL_1: + case RT5659_HAPTIC_LPF_CTRL_2: + case RT5659_HAPTIC_LPF_CTRL_3: + case RT5659_PWR_DIG_1: + case RT5659_PWR_DIG_2: + case RT5659_PWR_ANLG_1: + case RT5659_PWR_ANLG_2: + case RT5659_PWR_ANLG_3: + case RT5659_PWR_MIXER: + case RT5659_PWR_VOL: + case RT5659_PRIV_INDEX: + case RT5659_CLK_DET: + case RT5659_PRIV_DATA: + case RT5659_PRE_DIV_1: + case RT5659_PRE_DIV_2: + case RT5659_I2S1_SDP: + case RT5659_I2S2_SDP: + case RT5659_I2S3_SDP: + case RT5659_ADDA_CLK_1: + case RT5659_ADDA_CLK_2: + case RT5659_DMIC_CTRL_1: + case RT5659_DMIC_CTRL_2: + case RT5659_TDM_CTRL_1: + case RT5659_TDM_CTRL_2: + case RT5659_TDM_CTRL_3: + case RT5659_TDM_CTRL_4: + case RT5659_TDM_CTRL_5: + case RT5659_GLB_CLK: + case RT5659_PLL_CTRL_1: + case RT5659_PLL_CTRL_2: + case RT5659_ASRC_1: + case RT5659_ASRC_2: + case RT5659_ASRC_3: + case RT5659_ASRC_4: + case RT5659_ASRC_5: + case RT5659_ASRC_6: + case RT5659_ASRC_7: + case RT5659_ASRC_8: + case RT5659_ASRC_9: + case RT5659_ASRC_10: + case RT5659_DEPOP_1: + case RT5659_DEPOP_2: + case RT5659_DEPOP_3: + case RT5659_HP_CHARGE_PUMP_1: + case RT5659_HP_CHARGE_PUMP_2: + case RT5659_MICBIAS_1: + case RT5659_MICBIAS_2: + case RT5659_ASRC_11: + case RT5659_ASRC_12: + case RT5659_ASRC_13: + case RT5659_REC_M1_M2_GAIN_CTRL: + case RT5659_RC_CLK_CTRL: + case RT5659_CLASSD_CTRL_1: + case RT5659_CLASSD_CTRL_2: + case RT5659_ADC_EQ_CTRL_1: + case RT5659_ADC_EQ_CTRL_2: + case RT5659_DAC_EQ_CTRL_1: + case RT5659_DAC_EQ_CTRL_2: + case RT5659_DAC_EQ_CTRL_3: + case RT5659_IRQ_CTRL_1: + case RT5659_IRQ_CTRL_2: + case RT5659_IRQ_CTRL_3: + case RT5659_IRQ_CTRL_4: + case RT5659_IRQ_CTRL_5: + case RT5659_IRQ_CTRL_6: + case RT5659_INT_ST_1: + case RT5659_INT_ST_2: + case RT5659_GPIO_CTRL_1: + case RT5659_GPIO_CTRL_2: + case RT5659_GPIO_CTRL_3: + case RT5659_GPIO_CTRL_4: + case RT5659_GPIO_CTRL_5: + case RT5659_GPIO_STA: + case RT5659_SINE_GEN_CTRL_1: + case RT5659_SINE_GEN_CTRL_2: + case RT5659_SINE_GEN_CTRL_3: + case RT5659_HP_AMP_DET_CTRL_1: + case RT5659_HP_AMP_DET_CTRL_2: + case RT5659_SV_ZCD_1: + case RT5659_SV_ZCD_2: + case RT5659_IL_CMD_1: + case RT5659_IL_CMD_2: + case RT5659_IL_CMD_3: + case RT5659_IL_CMD_4: + case RT5659_4BTN_IL_CMD_1: + case RT5659_4BTN_IL_CMD_2: + case RT5659_4BTN_IL_CMD_3: + case RT5659_PSV_IL_CMD_1: + case RT5659_PSV_IL_CMD_2: + case RT5659_ADC_STO1_HP_CTRL_1: + case RT5659_ADC_STO1_HP_CTRL_2: + case RT5659_ADC_MONO_HP_CTRL_1: + case RT5659_ADC_MONO_HP_CTRL_2: + case RT5659_AJD1_CTRL: + case RT5659_AJD2_AJD3_CTRL: + case RT5659_JD1_THD: + case RT5659_JD2_THD: + case RT5659_JD3_THD: + case RT5659_JD_CTRL_1: + case RT5659_JD_CTRL_2: + case RT5659_JD_CTRL_3: + case RT5659_JD_CTRL_4: + case RT5659_DIG_MISC: + case RT5659_DUMMY_2: + case RT5659_DUMMY_3: + case RT5659_VENDOR_ID: + case RT5659_VENDOR_ID_1: + case RT5659_DEVICE_ID: + case RT5659_DAC_ADC_DIG_VOL: + case RT5659_BIAS_CUR_CTRL_1: + case RT5659_BIAS_CUR_CTRL_2: + case RT5659_BIAS_CUR_CTRL_3: + case RT5659_BIAS_CUR_CTRL_4: + case RT5659_BIAS_CUR_CTRL_5: + case RT5659_BIAS_CUR_CTRL_6: + case RT5659_BIAS_CUR_CTRL_7: + case RT5659_BIAS_CUR_CTRL_8: + case RT5659_BIAS_CUR_CTRL_9: + case RT5659_BIAS_CUR_CTRL_10: + case RT5659_MEMORY_TEST: + case RT5659_VREF_REC_OP_FB_CAP_CTRL: + case RT5659_CLASSD_0: + case RT5659_CLASSD_1: + case RT5659_CLASSD_2: + case RT5659_CLASSD_3: + case RT5659_CLASSD_4: + case RT5659_CLASSD_5: + case RT5659_CLASSD_6: + case RT5659_CLASSD_7: + case RT5659_CLASSD_8: + case RT5659_CLASSD_9: + case RT5659_CLASSD_10: + case RT5659_CHARGE_PUMP_1: + case RT5659_CHARGE_PUMP_2: + case RT5659_DIG_IN_CTRL_1: + case RT5659_DIG_IN_CTRL_2: + case RT5659_PAD_DRIVING_CTRL: + case RT5659_SOFT_RAMP_DEPOP: + case RT5659_PLL: + case RT5659_CHOP_DAC: + case RT5659_CHOP_ADC: + case RT5659_CALIB_ADC_CTRL: + case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL: + case RT5659_VOL_TEST: + case RT5659_TEST_MODE_CTRL_1: + case RT5659_TEST_MODE_CTRL_2: + case RT5659_TEST_MODE_CTRL_3: + case RT5659_TEST_MODE_CTRL_4: + case RT5659_BASSBACK_CTRL: + case RT5659_MP3_PLUS_CTRL_1: + case RT5659_MP3_PLUS_CTRL_2: + case RT5659_MP3_HPF_A1: + case RT5659_MP3_HPF_A2: + case RT5659_MP3_HPF_H0: + case RT5659_MP3_LPF_H0: + case RT5659_3D_SPK_CTRL: + case RT5659_3D_SPK_COEF_1: + case RT5659_3D_SPK_COEF_2: + case RT5659_3D_SPK_COEF_3: + case RT5659_3D_SPK_COEF_4: + case RT5659_3D_SPK_COEF_5: + case RT5659_3D_SPK_COEF_6: + case RT5659_3D_SPK_COEF_7: + case RT5659_STO_NG2_CTRL_1: + case RT5659_STO_NG2_CTRL_2: + case RT5659_STO_NG2_CTRL_3: + case RT5659_STO_NG2_CTRL_4: + case RT5659_STO_NG2_CTRL_5: + case RT5659_STO_NG2_CTRL_6: + case RT5659_STO_NG2_CTRL_7: + case RT5659_STO_NG2_CTRL_8: + case RT5659_MONO_NG2_CTRL_1: + case RT5659_MONO_NG2_CTRL_2: + case RT5659_MONO_NG2_CTRL_3: + case RT5659_MONO_NG2_CTRL_4: + case RT5659_MONO_NG2_CTRL_5: + case RT5659_MONO_NG2_CTRL_6: + case RT5659_MID_HP_AMP_DET: + case RT5659_LOW_HP_AMP_DET: + case RT5659_LDO_CTRL: + case RT5659_HP_DECROSS_CTRL_1: + case RT5659_HP_DECROSS_CTRL_2: + case RT5659_HP_DECROSS_CTRL_3: + case RT5659_HP_DECROSS_CTRL_4: + case RT5659_HP_IMP_SENS_CTRL_1: + case RT5659_HP_IMP_SENS_CTRL_2: + case RT5659_HP_IMP_SENS_CTRL_3: + case RT5659_HP_IMP_SENS_CTRL_4: + case RT5659_HP_IMP_SENS_MAP_1: + case RT5659_HP_IMP_SENS_MAP_2: + case RT5659_HP_IMP_SENS_MAP_3: + case RT5659_HP_IMP_SENS_MAP_4: + case RT5659_HP_IMP_SENS_MAP_5: + case RT5659_HP_IMP_SENS_MAP_6: + case RT5659_HP_IMP_SENS_MAP_7: + case RT5659_HP_IMP_SENS_MAP_8: + case RT5659_HP_LOGIC_CTRL_1: + case RT5659_HP_LOGIC_CTRL_2: + case RT5659_HP_CALIB_CTRL_1: + case RT5659_HP_CALIB_CTRL_2: + case RT5659_HP_CALIB_CTRL_3: + case RT5659_HP_CALIB_CTRL_4: + case RT5659_HP_CALIB_CTRL_5: + case RT5659_HP_CALIB_CTRL_6: + case RT5659_HP_CALIB_CTRL_7: + case RT5659_HP_CALIB_CTRL_9: + case RT5659_HP_CALIB_CTRL_10: + case RT5659_HP_CALIB_CTRL_11: + case RT5659_HP_CALIB_STA_1: + case RT5659_HP_CALIB_STA_2: + case RT5659_HP_CALIB_STA_3: + case RT5659_HP_CALIB_STA_4: + case RT5659_HP_CALIB_STA_5: + case RT5659_HP_CALIB_STA_6: + case RT5659_HP_CALIB_STA_7: + case RT5659_HP_CALIB_STA_8: + case RT5659_HP_CALIB_STA_9: + case RT5659_MONO_AMP_CALIB_CTRL_1: + case RT5659_MONO_AMP_CALIB_CTRL_2: + case RT5659_MONO_AMP_CALIB_CTRL_3: + case RT5659_MONO_AMP_CALIB_CTRL_4: + case RT5659_MONO_AMP_CALIB_CTRL_5: + case RT5659_MONO_AMP_CALIB_STA_1: + case RT5659_MONO_AMP_CALIB_STA_2: + case RT5659_MONO_AMP_CALIB_STA_3: + case RT5659_MONO_AMP_CALIB_STA_4: + case RT5659_SPK_PWR_LMT_CTRL_1: + case RT5659_SPK_PWR_LMT_CTRL_2: + case RT5659_SPK_PWR_LMT_CTRL_3: + case RT5659_SPK_PWR_LMT_STA_1: + case RT5659_SPK_PWR_LMT_STA_2: + case RT5659_SPK_PWR_LMT_STA_3: + case RT5659_SPK_PWR_LMT_STA_4: + case RT5659_SPK_PWR_LMT_STA_5: + case RT5659_SPK_PWR_LMT_STA_6: + case RT5659_FLEX_SPK_BST_CTRL_1: + case RT5659_FLEX_SPK_BST_CTRL_2: + case RT5659_FLEX_SPK_BST_CTRL_3: + case RT5659_FLEX_SPK_BST_CTRL_4: + case RT5659_SPK_EX_LMT_CTRL_1: + case RT5659_SPK_EX_LMT_CTRL_2: + case RT5659_SPK_EX_LMT_CTRL_3: + case RT5659_SPK_EX_LMT_CTRL_4: + case RT5659_SPK_EX_LMT_CTRL_5: + case RT5659_SPK_EX_LMT_CTRL_6: + case RT5659_SPK_EX_LMT_CTRL_7: + case RT5659_ADJ_HPF_CTRL_1: + case RT5659_ADJ_HPF_CTRL_2: + case RT5659_SPK_DC_CAILB_CTRL_1: + case RT5659_SPK_DC_CAILB_CTRL_2: + case RT5659_SPK_DC_CAILB_CTRL_3: + case RT5659_SPK_DC_CAILB_CTRL_4: + case RT5659_SPK_DC_CAILB_CTRL_5: + case RT5659_SPK_DC_CAILB_STA_1: + case RT5659_SPK_DC_CAILB_STA_2: + case RT5659_SPK_DC_CAILB_STA_3: + case RT5659_SPK_DC_CAILB_STA_4: + case RT5659_SPK_DC_CAILB_STA_5: + case RT5659_SPK_DC_CAILB_STA_6: + case RT5659_SPK_DC_CAILB_STA_7: + case RT5659_SPK_DC_CAILB_STA_8: + case RT5659_SPK_DC_CAILB_STA_9: + case RT5659_SPK_DC_CAILB_STA_10: + case RT5659_SPK_VDD_STA_1: + case RT5659_SPK_VDD_STA_2: + case RT5659_SPK_DC_DET_CTRL_1: + case RT5659_SPK_DC_DET_CTRL_2: + case RT5659_SPK_DC_DET_CTRL_3: + case RT5659_PURE_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_2: + case RT5659_DUMMY_4: + case RT5659_DUMMY_5: + case RT5659_DUMMY_6: + case RT5659_DRC1_CTRL_1: + case RT5659_DRC1_CTRL_2: + case RT5659_DRC1_CTRL_3: + case RT5659_DRC1_CTRL_4: + case RT5659_DRC1_CTRL_5: + case RT5659_DRC1_CTRL_6: + case RT5659_DRC1_HARD_LMT_CTRL_1: + case RT5659_DRC1_HARD_LMT_CTRL_2: + case RT5659_DRC2_CTRL_1: + case RT5659_DRC2_CTRL_2: + case RT5659_DRC2_CTRL_3: + case RT5659_DRC2_CTRL_4: + case RT5659_DRC2_CTRL_5: + case RT5659_DRC2_CTRL_6: + case RT5659_DRC2_HARD_LMT_CTRL_1: + case RT5659_DRC2_HARD_LMT_CTRL_2: + case RT5659_DRC1_PRIV_1: + case RT5659_DRC1_PRIV_2: + case RT5659_DRC1_PRIV_3: + case RT5659_DRC1_PRIV_4: + case RT5659_DRC1_PRIV_5: + case RT5659_DRC1_PRIV_6: + case RT5659_DRC1_PRIV_7: + case RT5659_DRC2_PRIV_1: + case RT5659_DRC2_PRIV_2: + case RT5659_DRC2_PRIV_3: + case RT5659_DRC2_PRIV_4: + case RT5659_DRC2_PRIV_5: + case RT5659_DRC2_PRIV_6: + case RT5659_DRC2_PRIV_7: + case RT5659_MULTI_DRC_CTRL: + case RT5659_CROSS_OVER_1: + case RT5659_CROSS_OVER_2: + case RT5659_CROSS_OVER_3: + case RT5659_CROSS_OVER_4: + case RT5659_CROSS_OVER_5: + case RT5659_CROSS_OVER_6: + case RT5659_CROSS_OVER_7: + case RT5659_CROSS_OVER_8: + case RT5659_CROSS_OVER_9: + case RT5659_CROSS_OVER_10: + case RT5659_ALC_PGA_CTRL_1: + case RT5659_ALC_PGA_CTRL_2: + case RT5659_ALC_PGA_CTRL_3: + case RT5659_ALC_PGA_CTRL_4: + case RT5659_ALC_PGA_CTRL_5: + case RT5659_ALC_PGA_CTRL_6: + case RT5659_ALC_PGA_CTRL_7: + case RT5659_ALC_PGA_CTRL_8: + case RT5659_ALC_PGA_STA_1: + case RT5659_ALC_PGA_STA_2: + case RT5659_ALC_PGA_STA_3: + case RT5659_DAC_L_EQ_PRE_VOL: + case RT5659_DAC_R_EQ_PRE_VOL: + case RT5659_DAC_L_EQ_POST_VOL: + case RT5659_DAC_R_EQ_POST_VOL: + case RT5659_DAC_L_EQ_LPF1_A1: + case RT5659_DAC_L_EQ_LPF1_H0: + case RT5659_DAC_R_EQ_LPF1_A1: + case RT5659_DAC_R_EQ_LPF1_H0: + case RT5659_DAC_L_EQ_BPF2_A1: + case RT5659_DAC_L_EQ_BPF2_A2: + case RT5659_DAC_L_EQ_BPF2_H0: + case RT5659_DAC_R_EQ_BPF2_A1: + case RT5659_DAC_R_EQ_BPF2_A2: + case RT5659_DAC_R_EQ_BPF2_H0: + case RT5659_DAC_L_EQ_BPF3_A1: + case RT5659_DAC_L_EQ_BPF3_A2: + case RT5659_DAC_L_EQ_BPF3_H0: + case RT5659_DAC_R_EQ_BPF3_A1: + case RT5659_DAC_R_EQ_BPF3_A2: + case RT5659_DAC_R_EQ_BPF3_H0: + case RT5659_DAC_L_EQ_BPF4_A1: + case RT5659_DAC_L_EQ_BPF4_A2: + case RT5659_DAC_L_EQ_BPF4_H0: + case RT5659_DAC_R_EQ_BPF4_A1: + case RT5659_DAC_R_EQ_BPF4_A2: + case RT5659_DAC_R_EQ_BPF4_H0: + case RT5659_DAC_L_EQ_HPF1_A1: + case RT5659_DAC_L_EQ_HPF1_H0: + case RT5659_DAC_R_EQ_HPF1_A1: + case RT5659_DAC_R_EQ_HPF1_H0: + case RT5659_DAC_L_EQ_HPF2_A1: + case RT5659_DAC_L_EQ_HPF2_A2: + case RT5659_DAC_L_EQ_HPF2_H0: + case RT5659_DAC_R_EQ_HPF2_A1: + case RT5659_DAC_R_EQ_HPF2_A2: + case RT5659_DAC_R_EQ_HPF2_H0: + case RT5659_DAC_L_BI_EQ_BPF1_H0_1: + case RT5659_DAC_L_BI_EQ_BPF1_H0_2: + case RT5659_DAC_L_BI_EQ_BPF1_B1_1: + case RT5659_DAC_L_BI_EQ_BPF1_B1_2: + case RT5659_DAC_L_BI_EQ_BPF1_B2_1: + case RT5659_DAC_L_BI_EQ_BPF1_B2_2: + case RT5659_DAC_L_BI_EQ_BPF1_A1_1: + case RT5659_DAC_L_BI_EQ_BPF1_A1_2: + case RT5659_DAC_L_BI_EQ_BPF1_A2_1: + case RT5659_DAC_L_BI_EQ_BPF1_A2_2: + case RT5659_DAC_R_BI_EQ_BPF1_H0_1: + case RT5659_DAC_R_BI_EQ_BPF1_H0_2: + case RT5659_DAC_R_BI_EQ_BPF1_B1_1: + case RT5659_DAC_R_BI_EQ_BPF1_B1_2: + case RT5659_DAC_R_BI_EQ_BPF1_B2_1: + case RT5659_DAC_R_BI_EQ_BPF1_B2_2: + case RT5659_DAC_R_BI_EQ_BPF1_A1_1: + case RT5659_DAC_R_BI_EQ_BPF1_A1_2: + case RT5659_DAC_R_BI_EQ_BPF1_A2_1: + case RT5659_DAC_R_BI_EQ_BPF1_A2_2: + case RT5659_ADC_L_EQ_LPF1_A1: + case RT5659_ADC_R_EQ_LPF1_A1: + case RT5659_ADC_L_EQ_LPF1_H0: + case RT5659_ADC_R_EQ_LPF1_H0: + case RT5659_ADC_L_EQ_BPF1_A1: + case RT5659_ADC_R_EQ_BPF1_A1: + case RT5659_ADC_L_EQ_BPF1_A2: + case RT5659_ADC_R_EQ_BPF1_A2: + case RT5659_ADC_L_EQ_BPF1_H0: + case RT5659_ADC_R_EQ_BPF1_H0: + case RT5659_ADC_L_EQ_BPF2_A1: + case RT5659_ADC_R_EQ_BPF2_A1: + case RT5659_ADC_L_EQ_BPF2_A2: + case RT5659_ADC_R_EQ_BPF2_A2: + case RT5659_ADC_L_EQ_BPF2_H0: + case RT5659_ADC_R_EQ_BPF2_H0: + case RT5659_ADC_L_EQ_BPF3_A1: + case RT5659_ADC_R_EQ_BPF3_A1: + case RT5659_ADC_L_EQ_BPF3_A2: + case RT5659_ADC_R_EQ_BPF3_A2: + case RT5659_ADC_L_EQ_BPF3_H0: + case RT5659_ADC_R_EQ_BPF3_H0: + case RT5659_ADC_L_EQ_BPF4_A1: + case RT5659_ADC_R_EQ_BPF4_A1: + case RT5659_ADC_L_EQ_BPF4_A2: + case RT5659_ADC_R_EQ_BPF4_A2: + case RT5659_ADC_L_EQ_BPF4_H0: + case RT5659_ADC_R_EQ_BPF4_H0: + case RT5659_ADC_L_EQ_HPF1_A1: + case RT5659_ADC_R_EQ_HPF1_A1: + case RT5659_ADC_L_EQ_HPF1_H0: + case RT5659_ADC_R_EQ_HPF1_H0: + case RT5659_ADC_L_EQ_PRE_VOL: + case RT5659_ADC_R_EQ_PRE_VOL: + case RT5659_ADC_L_EQ_POST_VOL: + case RT5659_ADC_R_EQ_POST_VOL: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0); +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0); + +/* Interface data select */ +static const char * const rt5659_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum, + RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum, + RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum, + RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum, + RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select); + +static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum); + +static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux = + SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum); + +static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux = + SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum); + +static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux = + SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum); + +static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux = + SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum); + +static const char * const rt5659_asrc_clk_src[] = { + "clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track", + "clk_i2s3_track", "clk_sys2", "clk_sys3" +}; + +static unsigned int rt5659_asrc_clk_map_values[] = { + 0, 1, 2, 3, 5, 6, +}; + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) { + snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1, + RT5659_NG2_EN_MASK, RT5659_NG2_DIS); + snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1, + RT5659_NG2_EN_MASK, RT5659_NG2_EN); + } + + return ret; +} + +static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + if (enable) { + snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b); + + /* MICBIAS1 and Mic Det Power for button detect*/ + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, + "Mic Det Power"); + snd_soc_dapm_sync(dapm); + + snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, + RT5659_PWR_MB1, RT5659_PWR_MB1); + snd_soc_update_bits(codec, RT5659_PWR_VOL, + RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET); + + snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2, + RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN); + snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2, + RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN); + } else { + snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2, + RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS); + snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2, + RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS); + /* MICBIAS1 and Mic Det Power for button detect*/ + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + } +} + +/** + * rt5659_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + int reg_63; + + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(dapm, + "Mic Det Power"); + snd_soc_dapm_sync(dapm); + reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1); + + snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, + RT5659_PWR_VREF2 | RT5659_PWR_MB, + RT5659_PWR_VREF2 | RT5659_PWR_MB); + msleep(20); + snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, + RT5659_PWR_FV2, RT5659_PWR_FV2); + + snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160); + snd_soc_update_bits(codec, RT5659_EJD_CTRL_1, + 0x20, 0x0); + msleep(20); + snd_soc_update_bits(codec, RT5659_EJD_CTRL_1, + 0x20, 0x20); + + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003; + i++; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + } + + switch (val) { + case 1: + rt5659->jack_type = SND_JACK_HEADSET; + rt5659_enable_push_button_irq(codec, true); + break; + default: + snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63); + rt5659->jack_type = SND_JACK_HEADPHONE; + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + break; + } + } else { + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + if (rt5659->jack_type == SND_JACK_HEADSET) + rt5659_enable_push_button_irq(codec, false); + rt5659->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type); + return rt5659->jack_type; +} + +static int rt5659_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val); + + return btn_type; +} + +static irqreturn_t rt5659_irq(int irq, void *data) +{ + struct rt5659_priv *rt5659 = data; + + queue_delayed_work(system_power_efficient_wq, + &rt5659->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +int rt5659_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + rt5659->hs_jack = hs_jack; + + rt5659_irq(0, rt5659); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5659_set_jack_detect); + +static void rt5659_jack_detect_work(struct work_struct *work) +{ + struct rt5659_priv *rt5659 = + container_of(work, struct rt5659_priv, jack_detect_work.work); + int val, btn_type, report = 0; + + if (!rt5659->codec) + return; + + val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080; + if (!val) { + /* jack in */ + if (rt5659->jack_type == 0) { + /* jack was out, report jack type */ + report = rt5659_headset_detect(rt5659->codec, 1); + } else { + /* jack is already in, report button event */ + report = SND_JACK_HEADSET; + btn_type = rt5659_button_detect(rt5659->codec); + /** + * rt5659 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5659->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + + /* button release or spurious interrput*/ + if (btn_type == 0) + report = rt5659->jack_type; + } + } else { + /* jack out */ + report = rt5659_headset_detect(rt5659->codec, 0); + } + + snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); +} + +static const struct snd_kcontrol_new rt5659_snd_controls[] = { + /* Speaker Output Volume */ + SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* Headphone Output Volume */ + SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN, + RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw, + rt5659_hp_vol_put, hp_vol_tlv), + + /* Mono Output Volume */ + SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT, + RT5659_L_VOL_SFT, 39, 1, out_vol_tlv), + + /* Output Volume */ + SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1), + + SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL, + RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1), + + /* IN1/IN2/IN3/IN4 Volume */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2, + RT5659_BST1_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2, + RT5659_BST2_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4, + RT5659_BST3_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4, + RT5659_BST4_SFT, 69, 0, in_bst_tlv), + + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL, + RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST, + RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST, + RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST, + RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0), + SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0), + SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0), + SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + int pd, idx = -EINVAL; + + pd = rl6231_get_pre_div(rt5659->regmap, + RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd); + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else { + snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1, + RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT); + } + return idx; +} + +static int set_adc_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5659_CHOP_ADC, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5659_CHOP_ADC, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Depop */ + snd_soc_write(codec, RT5659_DEPOP_1, 0x0009); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16); + break; + default: + return 0; + } + + return 0; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5659_GLB_CLK); + val &= RT5659_SCLK_SRC_MASK; + if (val == RT5659_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (w->shift) { + case RT5659_ADC_MONO_R_ASRC_SFT: + reg = RT5659_ASRC_3; + shift = RT5659_AD_MONO_R_T_SFT; + break; + case RT5659_ADC_MONO_L_ASRC_SFT: + reg = RT5659_ASRC_3; + shift = RT5659_AD_MONO_L_T_SFT; + break; + case RT5659_ADC_STO1_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_AD_STO1_T_SFT; + break; + case RT5659_DAC_MONO_R_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_MONO_R_T_SFT; + break; + case RT5659_DAC_MONO_L_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_MONO_L_T_SFT; + break; + case RT5659_DAC_STO_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_STO_T_SFT; + break; + default: + return 0; + } + + val = (snd_soc_read(codec, reg) >> shift) & 0xf; + switch (val) { + case 1: + case 2: + case 3: + /* I2S_Pre_Div1 should be 1 in asrc mode */ + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2); + return 1; + default: + return 0; + } + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER, + RT5659_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER, + RT5659_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L2_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R2_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L2_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R2_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R2_MONO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = { + SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER, + RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER, + RT5659_M_INL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST4_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST3_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST2_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST1_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = { + SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER, + RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER, + RT5659_M_INR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST4_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST3_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST2_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST1_RM1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = { + SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER, + RT5659_M_SPKVOL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER, + RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST4_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST3_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST2_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST1_RM2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER, + RT5659_M_MONOVOL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER, + RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST4_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST3_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST2_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST1_RM2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spk_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER, + RT5659_M_DAC_L2_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER, + RT5659_M_BST1_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER, + RT5659_M_IN_L_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER, + RT5659_M_IN_R_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER, + RT5659_M_BST3_SM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spk_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER, + RT5659_M_DAC_R2_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER, + RT5659_M_BST4_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER, + RT5659_M_IN_L_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER, + RT5659_M_IN_R_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER, + RT5659_M_BST3_SM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_monovol_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_L2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_R2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST1_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST3_MM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_out_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER, + RT5659_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER, + RT5659_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST3_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_out_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER, + RT5659_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER, + RT5659_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST3_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST4_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spo_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0), + SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0), +}; + +static const struct snd_kcontrol_new rt5659_spo_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0), + SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0), +}; + +static const struct snd_kcontrol_new rt5659_mono_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_L2_MA_SFT, 1, 1), + SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_MONOVOL_MA_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_lout_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER, + RT5659_M_DAC_L2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER, + RT5659_M_OV_L_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_lout_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER, + RT5659_M_DAC_R2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER, + RT5659_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC L2, DAC R2*/ +/*MX-1B [6:4], MX-1B [2:0]*/ +static const char * const rt5659_dac2_src[] = { + "IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_l2_enum, RT5659_DAC_CTRL, + RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src); + +static const struct snd_kcontrol_new rt5659_dac_l2_mux = + SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_r2_enum, RT5659_DAC_CTRL, + RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src); + +static const struct snd_kcontrol_new rt5659_dac_r2_mux = + SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum); + + +/* STO1 ADC1 Source */ +/* MX-26 [13] */ +static const char * const rt5659_sto1_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc1_mux = + SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum); + +/* STO1 ADC Source */ +/* MX-26 [12] */ +static const char * const rt5659_sto1_adc_src[] = { + "ADC1", "ADC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc_mux = + SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [11] */ +static const char * const rt5659_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc2_mux = + SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum); + +/* STO1 DMIC Source */ +/* MX-26 [8] */ +static const char * const rt5659_sto1_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src); + +static const struct snd_kcontrol_new rt5659_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum); + + +/* MONO ADC L2 Source */ +/* MX-27 [12] */ +static const char * const rt5659_mono_adc_l2_src[] = { + "Mono DAC MIXL", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum); + + +/* MONO ADC L1 Source */ +/* MX-27 [11] */ +static const char * const rt5659_mono_adc_l1_src[] = { + "Mono DAC MIXL", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum); + +/* MONO ADC L Source, MONO ADC R Source*/ +/* MX-27 [10:9], MX-27 [2:1] */ +static const char * const rt5659_mono_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l_mux = + SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r_mux = + SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum); + +/* MONO DMIC L Source */ +/* MX-27 [8] */ +static const char * const rt5659_mono_dmic_l_src[] = { + "DMIC1 L", "DMIC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src); + +static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum); + +/* MONO ADC R2 Source */ +/* MX-27 [4] */ +static const char * const rt5659_mono_adc_r2_src[] = { + "Mono DAC MIXR", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum); + +/* MONO ADC R1 Source */ +/* MX-27 [3] */ +static const char * const rt5659_mono_adc_r1_src[] = { + "Mono DAC MIXR", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum); + +/* MONO DMIC R Source */ +/* MX-27 [0] */ +static const char * const rt5659_mono_dmic_r_src[] = { + "DMIC1 R", "DMIC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src); + +static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum); + + +/* DAC R1 Source, DAC L1 Source*/ +/* MX-29 [11:10], MX-29 [9:8]*/ +static const char * const rt5659_dac1_src[] = { + "IF1 DAC1", "IF2 DAC", "IF3 DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_r1_enum, RT5659_AD_DA_MIXER, + RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src); + +static const struct snd_kcontrol_new rt5659_dac_r1_mux = + SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_l1_enum, RT5659_AD_DA_MIXER, + RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src); + +static const struct snd_kcontrol_new rt5659_dac_l1_mux = + SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum); + +/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/ +/* MX-2C [6], MX-2C [4]*/ +static const char * const rt5659_dig_dac_mix_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER, + RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux = + SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER, + RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux = + SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2D [3], MX-2D [2]*/ +static const char * const rt5659_alg_dac1_src[] = { + "DAC", "Stereo DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX, + RT5659_A_DACL1_SFT, rt5659_alg_dac1_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX, + RT5659_A_DACR1_SFT, rt5659_alg_dac1_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum); + +/* Analog DAC LR Source, Analog DAC R2 Source*/ +/* MX-2D [1], MX-2D [0]*/ +static const char * const rt5659_alg_dac2_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX, + RT5659_A_DACL2_SFT, rt5659_alg_dac2_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux = + SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX, + RT5659_A_DACR2_SFT, rt5659_alg_dac2_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux = + SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum); + +/* Interface2 ADC Data Input*/ +/* MX-2F [13:12] */ +static const char * const rt5659_if2_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA, + RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src); + +static const struct snd_kcontrol_new rt5659_if2_adc_in_mux = + SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum); + +/* Interface3 ADC Data Input*/ +/* MX-2F [1:0] */ +static const char * const rt5659_if3_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA, + RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5659_if3_adc_in_mux = + SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum); + +/* PDM 1 L/R*/ +/* MX-31 [15] [13] */ +static const char * const rt5659_pdm_src[] = { + "Mono DAC", "Stereo DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL, + RT5659_PDM1_L_SFT, rt5659_pdm_src); + +static const struct snd_kcontrol_new rt5659_pdm_l_mux = + SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL, + RT5659_PDM1_R_SFT, rt5659_pdm_src); + +static const struct snd_kcontrol_new rt5659_pdm_r_mux = + SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum); + +/* SPDIF Output source*/ +/* MX-36 [1:0] */ +static const char * const rt5659_spdif_src[] = { + "IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_spdif_enum, RT5659_SPDIF_CTRL, + RT5659_SPDIF_SEL_SFT, rt5659_spdif_src); + +static const struct snd_kcontrol_new rt5659_spdif_mux = + SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum); + +/* I2S1 TDM ADCDAT Source */ +/* MX-78[4:0] */ +static const char * const rt5659_rx_adc_data_src[] = { + "AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL", + "AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC", + "AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL", + "AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC", + "DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL", + "DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC", + "NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC", + "NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2, + RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src); + +static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux = + SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum); + +/* Out Volume Switch */ +static const struct snd_kcontrol_new spkvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new spkvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new monovol_switch = + SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1); + +/* Out Switch */ +static const struct snd_kcontrol_new spo_switch = + SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1); + +static const struct snd_kcontrol_new mono_switch = + SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1, + 1); + +static const struct snd_kcontrol_new pdm_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1, + 1); + +static int rt5659_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1, + RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN); + snd_soc_update_bits(codec, RT5659_CLASSD_2, + RT5659_M_RI_DIG, RT5659_M_RI_DIG); + snd_soc_write(codec, RT5659_CLASSD_1, 0x0803); + snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_CLASSD_1, 0x0011); + snd_soc_update_bits(codec, RT5659_CLASSD_2, + RT5659_M_RI_DIG, 0x0); + snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003); + snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1, + RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_mono_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e); + snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT5659_DEPOP_1, 0x0000); + break; + + default: + return 0; + } + + return 0; +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /*Add delay to avoid pop noise*/ + msleep(450); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL, + RT5659_PWR_MIC_DET_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1, + RT5659_PWR_VREF3_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S3_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT, + 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_INPUT("DMIC L2"), + SND_SOC_DAPM_INPUT("DMIC R2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + SND_SOC_DAPM_INPUT("IN4P"), + SND_SOC_DAPM_INPUT("IN4N"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2, + RT5659_PWR_BST1_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2, + RT5659_PWR_BST2_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2, + RT5659_PWR_BST3_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2, + RT5659_PWR_BST4_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST3_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST4_BIT, 0, NULL, 0), + + + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT, + 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT, + 0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT, + 0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)), + SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT, + 0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT, + 0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1, + RT5659_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1, + RT5659_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc_clk, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc_clk, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l_mux), + SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, + 0, 0, rt5659_sto1_adc_l_mix, + ARRAY_SIZE(rt5659_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, + 0, 0, rt5659_sto1_adc_r_mix, + ARRAY_SIZE(rt5659_sto1_adc_r_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix, + ARRAY_SIZE(rt5659_mono_adc_l_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL, + RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix, + ARRAY_SIZE(rt5659_mono_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL, + RT5659_R_MUTE_SFT, 1, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0, + &rt5659_rx_adc_dac_mux), + SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_adc_in_mux), + SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_adc_in_mux), + SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_adc_swap_mux), + SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_dac_swap_mux), + SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux), + + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_r2_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)), + SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0, + &rt5659_dig_dac_mixl_mux), + SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0, + &rt5659_dig_dac_mixr_mux), + + /* DACs */ + SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1, + RT5659_PWR_DAC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1, + RT5659_PWR_DAC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1, + RT5659_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1, + RT5659_PWR_DAC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT, + 0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)), + SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT, + 0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)), + SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT, + 0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT, + 0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT, + 0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0, + &spkvol_l_switch), + SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0, + &spkvol_r_switch), + SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0, + &monovol_switch), + SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0, + &outvol_l_switch), + SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0, + &outvol_r_switch), + + /* SPO/MONO/HPO/LOUT */ + SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix, + ARRAY_SIZE(rt5659_spo_l_mix)), + SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix, + ARRAY_SIZE(rt5659_spo_r_mix)), + SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5659_mono_mix, + ARRAY_SIZE(rt5659_mono_mix)), + SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix, + ARRAY_SIZE(rt5659_lout_l_mix)), + SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix, + ARRAY_SIZE(rt5659_lout_r_mix)), + + SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT, + 0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT, + 0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, + rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch), + SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0, + &mono_switch), + SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0, + &hpo_l_switch), + SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0, + &hpo_r_switch), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_switch), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_switch), + SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0, + &pdm_l_switch), + SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0, + &pdm_r_switch), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2, + RT5659_PWR_PDM1_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL, + RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux), + SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL, + RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux), + + /* SPDIF */ + SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux), + + SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("PDML"), + SND_SOC_DAPM_OUTPUT("PDMR"), + SND_SOC_DAPM_OUTPUT("SPDIF"), +}; + +static const struct snd_soc_dapm_route rt5659_dapm_routes[] = { + /*PLL*/ + { "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll }, + + /*ASRC*/ + { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc }, + { "ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc }, + { "DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc }, + { "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc }, + { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, + + { "SYS CLK DET", NULL, "CLKDET" }, + + { "I2S1", NULL, "I2S1 ASRC" }, + { "I2S2", NULL, "I2S2 ASRC" }, + { "I2S3", NULL, "I2S3 ASRC" }, + + { "IN1P", NULL, "LDO2" }, + { "IN2P", NULL, "LDO2" }, + { "IN3P", NULL, "LDO2" }, + { "IN4P", NULL, "LDO2" }, + + { "DMIC1", NULL, "DMIC L1" }, + { "DMIC1", NULL, "DMIC R1" }, + { "DMIC2", NULL, "DMIC L2" }, + { "DMIC2", NULL, "DMIC R2" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "BST1 Power" }, + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + { "BST2", NULL, "BST2 Power" }, + { "BST3", NULL, "IN3P" }, + { "BST3", NULL, "IN3N" }, + { "BST3", NULL, "BST3 Power" }, + { "BST4", NULL, "IN4P" }, + { "BST4", NULL, "IN4N" }, + { "BST4", NULL, "BST4 Power" }, + + { "INL VOL", NULL, "IN2P" }, + { "INR VOL", NULL, "IN2N" }, + + { "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" }, + { "RECMIX1L", "INL Switch", "INL VOL" }, + { "RECMIX1L", "BST4 Switch", "BST4" }, + { "RECMIX1L", "BST3 Switch", "BST3" }, + { "RECMIX1L", "BST2 Switch", "BST2" }, + { "RECMIX1L", "BST1 Switch", "BST1" }, + + { "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" }, + { "RECMIX1R", "INR Switch", "INR VOL" }, + { "RECMIX1R", "BST4 Switch", "BST4" }, + { "RECMIX1R", "BST3 Switch", "BST3" }, + { "RECMIX1R", "BST2 Switch", "BST2" }, + { "RECMIX1R", "BST1 Switch", "BST1" }, + + { "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" }, + { "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" }, + { "RECMIX2L", "BST4 Switch", "BST4" }, + { "RECMIX2L", "BST3 Switch", "BST3" }, + { "RECMIX2L", "BST2 Switch", "BST2" }, + { "RECMIX2L", "BST1 Switch", "BST1" }, + + { "RECMIX2R", "MONOVOL Switch", "MONOVOL" }, + { "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" }, + { "RECMIX2R", "BST4 Switch", "BST4" }, + { "RECMIX2R", "BST3 Switch", "BST3" }, + { "RECMIX2R", "BST2 Switch", "BST2" }, + { "RECMIX2R", "BST1 Switch", "BST1" }, + + { "ADC1 L", NULL, "RECMIX1L" }, + { "ADC1 L", NULL, "ADC1 L Power" }, + { "ADC1 L", NULL, "ADC1 clock" }, + { "ADC1 R", NULL, "RECMIX1R" }, + { "ADC1 R", NULL, "ADC1 R Power" }, + { "ADC1 R", NULL, "ADC1 clock" }, + + { "ADC2 L", NULL, "RECMIX2L" }, + { "ADC2 L", NULL, "ADC2 L Power" }, + { "ADC2 L", NULL, "ADC2 clock" }, + { "ADC2 R", NULL, "RECMIX2R" }, + { "ADC2 R", NULL, "ADC2 R Power" }, + { "ADC2 R", NULL, "ADC2 clock" }, + + { "DMIC L1", NULL, "DMIC CLK" }, + { "DMIC L1", NULL, "DMIC1 Power" }, + { "DMIC R1", NULL, "DMIC CLK" }, + { "DMIC R1", NULL, "DMIC1 Power" }, + { "DMIC L2", NULL, "DMIC CLK" }, + { "DMIC L2", NULL, "DMIC2 Power" }, + { "DMIC R2", NULL, "DMIC CLK" }, + { "DMIC R2", NULL, "DMIC2 Power" }, + + { "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" }, + { "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" }, + + { "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" }, + { "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" }, + + { "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" }, + { "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" }, + + { "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" }, + { "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" }, + + { "Stereo1 ADC L Mux", "ADC1", "ADC1 L" }, + { "Stereo1 ADC L Mux", "ADC2", "ADC2 L" }, + { "Stereo1 ADC R Mux", "ADC1", "ADC1 R" }, + { "Stereo1 ADC R Mux", "ADC2", "ADC2 R" }, + + { "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" }, + { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" }, + { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, + + { "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" }, + { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, + { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" }, + { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + + { "Mono ADC L Mux", "ADC1 L", "ADC1 L" }, + { "Mono ADC L Mux", "ADC1 R", "ADC1 R" }, + { "Mono ADC L Mux", "ADC2 L", "ADC2 L" }, + { "Mono ADC L Mux", "ADC2 R", "ADC2 R" }, + + { "Mono ADC R Mux", "ADC1 L", "ADC1 L" }, + { "Mono ADC R Mux", "ADC1 R", "ADC1 R" }, + { "Mono ADC R Mux", "ADC2 L", "ADC2 L" }, + { "Mono ADC R Mux", "ADC2 R", "ADC2 R" }, + + { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" }, + { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "ADC", "Mono ADC L Mux" }, + + { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + { "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" }, + { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" }, + { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + + { "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" }, + { "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" }, + { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" }, + + { "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" }, + { "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" }, + { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" }, + + { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" }, + { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" }, + { "Mono ADC MIXL", NULL, "ADC Mono Left Filter" }, + + { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" }, + { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" }, + { "Mono ADC MIXR", NULL, "ADC Mono Right Filter" }, + + { "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" }, + { "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" }, + + { "IF_ADC1", NULL, "Stereo1 ADC Volume L" }, + { "IF_ADC1", NULL, "Stereo1 ADC Volume R" }, + { "IF_ADC2", NULL, "Mono ADC MIXL" }, + { "IF_ADC2", NULL, "Mono ADC MIXR" }, + + { "TDM AD1:AD2:DAC", NULL, "IF_ADC1" }, + { "TDM AD1:AD2:DAC", NULL, "IF_ADC2" }, + { "TDM AD1:AD2:DAC", NULL, "DAC_REF" }, + { "TDM AD2:DAC", NULL, "IF_ADC2" }, + { "TDM AD2:DAC", NULL, "DAC_REF" }, + { "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" }, + { "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" }, + { "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" }, + { "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" }, + { "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" }, + { "IF1 ADC", NULL, "I2S1" }, + + { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" }, + { "IF2 ADC Mux", "DAC_REF", "DAC_REF" }, + { "IF2 ADC", NULL, "IF2 ADC Mux"}, + { "IF2 ADC", NULL, "I2S2" }, + + { "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" }, + { "IF3 ADC Mux", "DAC_REF", "DAC_REF" }, + { "IF3 ADC", NULL, "IF3 ADC Mux"}, + { "IF3 ADC", NULL, "I2S3" }, + + { "AIF1TX", NULL, "IF1 ADC" }, + { "IF2 ADC Swap Mux", "L/R", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "R/L", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "L/L", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "R/R", "IF2 ADC" }, + { "AIF2TX", NULL, "IF2 ADC Swap Mux" }, + { "IF3 ADC Swap Mux", "L/R", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "R/L", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "L/L", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "R/R", "IF3 ADC" }, + { "AIF3TX", NULL, "IF3 ADC Swap Mux" }, + + { "IF1 DAC1", NULL, "AIF1RX" }, + { "IF1 DAC2", NULL, "AIF1RX" }, + { "IF2 DAC Swap Mux", "L/R", "AIF2RX" }, + { "IF2 DAC Swap Mux", "R/L", "AIF2RX" }, + { "IF2 DAC Swap Mux", "L/L", "AIF2RX" }, + { "IF2 DAC Swap Mux", "R/R", "AIF2RX" }, + { "IF2 DAC", NULL, "IF2 DAC Swap Mux" }, + { "IF3 DAC Swap Mux", "L/R", "AIF3RX" }, + { "IF3 DAC Swap Mux", "R/L", "AIF3RX" }, + { "IF3 DAC Swap Mux", "L/L", "AIF3RX" }, + { "IF3 DAC Swap Mux", "R/R", "AIF3RX" }, + { "IF3 DAC", NULL, "IF3 DAC Swap Mux" }, + + { "IF1 DAC1", NULL, "I2S1" }, + { "IF1 DAC2", NULL, "I2S1" }, + { "IF2 DAC", NULL, "I2S2" }, + { "IF3 DAC", NULL, "I2S3" }, + + { "IF1 DAC2 L", NULL, "IF1 DAC2" }, + { "IF1 DAC2 R", NULL, "IF1 DAC2" }, + { "IF1 DAC1 L", NULL, "IF1 DAC1" }, + { "IF1 DAC1 R", NULL, "IF1 DAC1" }, + { "IF2 DAC L", NULL, "IF2 DAC" }, + { "IF2 DAC R", NULL, "IF2 DAC" }, + { "IF3 DAC L", NULL, "IF3 DAC" }, + { "IF3 DAC R", NULL, "IF3 DAC" }, + + { "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" }, + { "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" }, + { "DAC L1 Mux", NULL, "DAC Stereo1 Filter" }, + + { "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" }, + { "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" }, + { "DAC R1 Mux", NULL, "DAC Stereo1 Filter" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" }, + { "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" }, + { "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" }, + + { "DAC_REF", NULL, "DAC1 MIXL" }, + { "DAC_REF", NULL, "DAC1 MIXR" }, + + { "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" }, + { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" }, + { "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" }, + { "DAC L2 Mux", NULL, "DAC Mono Left Filter" }, + + { "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" }, + { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" }, + { "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" }, + { "DAC R2 Mux", NULL, "DAC Mono Right Filter" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" }, + { "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" }, + + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" }, + { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" }, + + { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" }, + { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" }, + { "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" }, + { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" }, + + { "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" }, + { "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" }, + + { "DAC L1 Source", NULL, "DAC L1 Power" }, + { "DAC L1 Source", "DAC", "DAC1 MIXL" }, + { "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC R1 Source", NULL, "DAC R1 Power" }, + { "DAC R1 Source", "DAC", "DAC1 MIXR" }, + { "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" }, + { "DAC L2 Source", NULL, "DAC L2 Power" }, + { "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" }, + { "DAC R2 Source", NULL, "DAC R2 Power" }, + + { "DAC L1", NULL, "DAC L1 Source" }, + { "DAC R1", NULL, "DAC R1 Source" }, + { "DAC L2", NULL, "DAC L2 Source" }, + { "DAC R2", NULL, "DAC R2 Source" }, + + { "SPK MIXL", "DAC L2 Switch", "DAC L2" }, + { "SPK MIXL", "BST1 Switch", "BST1" }, + { "SPK MIXL", "INL Switch", "INL VOL" }, + { "SPK MIXL", "INR Switch", "INR VOL" }, + { "SPK MIXL", "BST3 Switch", "BST3" }, + { "SPK MIXR", "DAC R2 Switch", "DAC R2" }, + { "SPK MIXR", "BST4 Switch", "BST4" }, + { "SPK MIXR", "INL Switch", "INL VOL" }, + { "SPK MIXR", "INR Switch", "INR VOL" }, + { "SPK MIXR", "BST3 Switch", "BST3" }, + + { "MONOVOL MIX", "DAC L2 Switch", "DAC L2" }, + { "MONOVOL MIX", "DAC R2 Switch", "DAC R2" }, + { "MONOVOL MIX", "BST1 Switch", "BST1" }, + { "MONOVOL MIX", "BST2 Switch", "BST2" }, + { "MONOVOL MIX", "BST3 Switch", "BST3" }, + + { "OUT MIXL", "DAC L2 Switch", "DAC L2" }, + { "OUT MIXL", "INL Switch", "INL VOL" }, + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "BST2 Switch", "BST2" }, + { "OUT MIXL", "BST3 Switch", "BST3" }, + { "OUT MIXR", "DAC R2 Switch", "DAC R2" }, + { "OUT MIXR", "INR Switch", "INR VOL" }, + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "BST3 Switch", "BST3" }, + { "OUT MIXR", "BST4 Switch", "BST4" }, + + { "SPKVOL L", "Switch", "SPK MIXL" }, + { "SPKVOL R", "Switch", "SPK MIXR" }, + { "SPO L MIX", "DAC L2 Switch", "DAC L2" }, + { "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" }, + { "SPO R MIX", "DAC R2 Switch", "DAC R2" }, + { "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" }, + { "SPK Amp", NULL, "SPO L MIX" }, + { "SPK Amp", NULL, "SPO R MIX" }, + { "SPK Amp", NULL, "SYS CLK DET" }, + { "SPO Playback", "Switch", "SPK Amp" }, + { "SPOL", NULL, "SPO Playback" }, + { "SPOR", NULL, "SPO Playback" }, + + { "MONOVOL", "Switch", "MONOVOL MIX" }, + { "Mono MIX", "DAC L2 Switch", "DAC L2" }, + { "Mono MIX", "MONOVOL Switch", "MONOVOL" }, + { "Mono Amp", NULL, "Mono MIX" }, + { "Mono Amp", NULL, "Mono Vref" }, + { "Mono Amp", NULL, "SYS CLK DET" }, + { "Mono Playback", "Switch", "Mono Amp" }, + { "MONOOUT", NULL, "Mono Playback" }, + + { "HP Amp", NULL, "DAC L1" }, + { "HP Amp", NULL, "DAC R1" }, + { "HP Amp", NULL, "Charge Pump" }, + { "HP Amp", NULL, "SYS CLK DET" }, + { "HPO L Playback", "Switch", "HP Amp"}, + { "HPO R Playback", "Switch", "HP Amp"}, + { "HPOL", NULL, "HPO L Playback" }, + { "HPOR", NULL, "HPO R Playback" }, + + { "OUTVOL L", "Switch", "OUT MIXL" }, + { "OUTVOL R", "Switch", "OUT MIXR" }, + { "LOUT L MIX", "DAC L2 Switch", "DAC L2" }, + { "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" }, + { "LOUT R MIX", "DAC R2 Switch", "DAC R2" }, + { "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" }, + { "LOUT Amp", NULL, "LOUT L MIX" }, + { "LOUT Amp", NULL, "LOUT R MIX" }, + { "LOUT Amp", NULL, "SYS CLK DET" }, + { "LOUT L Playback", "Switch", "LOUT Amp" }, + { "LOUT R Playback", "Switch", "LOUT Amp" }, + { "LOUTL", NULL, "LOUT L Playback" }, + { "LOUTR", NULL, "LOUT R Playback" }, + + { "PDM L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM L Mux", NULL, "PDM Power" }, + { "PDM R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM R Mux", NULL, "PDM Power" }, + { "PDM L Playback", "Switch", "PDM L Mux" }, + { "PDM R Playback", "Switch", "PDM R Mux" }, + { "PDML", NULL, "PDM L Playback" }, + { "PDMR", NULL, "PDM R Playback" }, + + { "SPDIF Mux", "IF3_DAC", "IF3 DAC" }, + { "SPDIF Mux", "IF2_DAC", "IF2 DAC" }, + { "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" }, + { "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" }, + { "SPDIF", NULL, "SPDIF Mux" }, +}; + +static int rt5659_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, frame_size; + + rt5659->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5659->lrck[dai->id], dai->id); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n", + rt5659->lrck[dai->id], pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5659_I2S_DL_20; + break; + case 24: + val_len |= RT5659_I2S_DL_24; + break; + case 8: + val_len |= RT5659_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5659_AIF1: + mask_clk = RT5659_I2S_PD1_MASK; + val_clk = pre_div << RT5659_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5659_I2S1_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + case RT5659_AIF2: + mask_clk = RT5659_I2S_PD2_MASK; + val_clk = pre_div << RT5659_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5659_I2S2_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + case RT5659_AIF3: + mask_clk = RT5659_I2S_PD3_MASK; + val_clk = pre_div << RT5659_I2S_PD3_SFT; + snd_soc_update_bits(codec, RT5659_I2S3_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk); + + switch (rt5659->lrck[dai->id]) { + case 192000: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32); + break; + case 96000: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64); + break; + default: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128); + break; + } + + return 0; +} + +static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5659->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5659_I2S_MS_S; + rt5659->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5659_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5659_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5659_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5659_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5659_AIF1: + snd_soc_update_bits(codec, RT5659_I2S1_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + case RT5659_AIF2: + snd_soc_update_bits(codec, RT5659_I2S2_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + case RT5659_AIF3: + snd_soc_update_bits(codec, RT5659_I2S3_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src) + return 0; + + switch (clk_id) { + case RT5659_SCLK_S_MCLK: + reg_val |= RT5659_SCLK_SRC_MCLK; + break; + case RT5659_SCLK_S_PLL1: + reg_val |= RT5659_SCLK_SRC_PLL1; + break; + case RT5659_SCLK_S_RCCLK: + reg_val |= RT5659_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_SCLK_SRC_MASK, reg_val); + rt5659->sysclk = freq; + rt5659->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (Source == rt5659->pll_src && freq_in == rt5659->pll_in && + freq_out == rt5659->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5659->pll_in = 0; + rt5659->pll_out = 0; + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK); + return 0; + } + + switch (Source) { + case RT5659_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK); + break; + case RT5659_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1); + break; + case RT5659_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2); + break; + case RT5659_PLL1_S_BCLK3: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3); + break; + default: + dev_err(codec->dev, "Unknown PLL Source %d\n", Source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5659_PLL_CTRL_1, + pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5659_PLL_CTRL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT | + pll_code.m_bp << RT5659_PLL_M_BP_SFT); + + rt5659->pll_in = freq_in; + rt5659->pll_out = freq_out; + rt5659->pll_src = Source; + + return 0; +} + +static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= (1 << 15); + + switch (slots) { + case 4: + val |= (1 << 10); + val |= (1 << 8); + break; + case 6: + val |= (2 << 10); + val |= (2 << 8); + break; + case 8: + val |= (3 << 10); + val |= (3 << 8); + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= (1 << 6); + val |= (1 << 4); + break; + case 24: + val |= (2 << 6); + val |= (2 << 4); + break; + case 32: + val |= (3 << 6); + val |= (3 << 4); + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val); + + return 0; +} + +static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + + rt5659->bclk[dai->id] = ratio; + + if (ratio == 64) { + switch (dai->id) { + case RT5659_AIF2: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_BCLK_MS2_MASK, + RT5659_I2S_BCLK_MS2_64); + break; + case RT5659_AIF3: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_BCLK_MS3_MASK, + RT5659_I2S_BCLK_MS3_64); + break; + } + } + + return 0; +} + +static int rt5659_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, + RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL); + regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, + RT5659_PWR_LDO, RT5659_PWR_LDO); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2); + msleep(20); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_FV1 | RT5659_PWR_FV2, + RT5659_PWR_FV1 | RT5659_PWR_FV2); + break; + + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, + RT5659_PWR_LDO, 0); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2 + | RT5659_PWR_FV1 | RT5659_PWR_FV2, + RT5659_PWR_MB | RT5659_PWR_VREF2); + regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, + RT5659_DIG_GATE_CTRL, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5659_probe(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + rt5659->codec = codec; + + return 0; +} + +static int rt5659_remove(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5659->regmap, RT5659_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5659_suspend(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5659->regmap, true); + regcache_mark_dirty(rt5659->regmap); + return 0; +} + +static int rt5659_resume(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5659->regmap, false); + regcache_sync(rt5659->regmap); + + return 0; +} +#else +#define rt5659_suspend NULL +#define rt5659_resume NULL +#endif + +#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5659_aif_dai_ops = { + .hw_params = rt5659_hw_params, + .set_fmt = rt5659_set_dai_fmt, + .set_sysclk = rt5659_set_dai_sysclk, + .set_tdm_slot = rt5659_set_tdm_slot, + .set_pll = rt5659_set_dai_pll, + .set_bclk_ratio = rt5659_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5659_dai[] = { + { + .name = "rt5659-aif1", + .id = RT5659_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, + { + .name = "rt5659-aif2", + .id = RT5659_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, + { + .name = "rt5659-aif3", + .id = RT5659_AIF3, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5659 = { + .probe = rt5659_probe, + .remove = rt5659_remove, + .suspend = rt5659_suspend, + .resume = rt5659_resume, + .set_bias_level = rt5659_set_bias_level, + .idle_bias_off = true, + .controls = rt5659_snd_controls, + .num_controls = ARRAY_SIZE(rt5659_snd_controls), + .dapm_widgets = rt5659_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets), + .dapm_routes = rt5659_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes), +}; + + +static const struct regmap_config rt5659_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 0x0400, + .volatile_reg = rt5659_volatile_register, + .readable_reg = rt5659_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5659_reg, + .num_reg_defaults = ARRAY_SIZE(rt5659_reg), +}; + +static const struct i2c_device_id rt5659_i2c_id[] = { + { "rt5658", 0 }, + { "rt5659", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id); + +static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev) +{ + rt5659->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5659->pdata.in3_diff = device_property_read_bool(dev, + "realtek,in3-differential"); + rt5659->pdata.in4_diff = device_property_read_bool(dev, + "realtek,in4-differential"); + + + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5659->pdata.dmic1_data_pin); + device_property_read_u32(dev, "realtek,dmic2-data-pin", + &rt5659->pdata.dmic2_data_pin); + device_property_read_u32(dev, "realtek,jd-src", + &rt5659->pdata.jd_src); + + return 0; +} + +static void rt5659_calibrate(struct rt5659_priv *rt5659) +{ + int value, count; + + /* Calibrate HPO Start */ + /* Fine tune HP Performance */ + regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502); + regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030); + + regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00); + regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc); + regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280); + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001); + regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000); + + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e); + msleep(60); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080); + usleep_range(10000, 10005); + regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80); + msleep(50); + regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16); + msleep(50); + + /* Enalbe K ADC Power And Clock */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184); + regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1); + + /* K Headphone */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100); + msleep(60); + + /* Manual K ADC Offset */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 30) { + dev_err(rt5659->codec->dev, + "HP Calibration 1 Failure\n"); + return; + } + + count++; + } + + /* Manual K Internal Path Offset */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 85) { + dev_err(rt5659->codec->dev, + "HP Calibration 2 Failure\n"); + return; + } + + count++; + } + + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0); + /* Calibrate HPO End */ + + /* Calibrate SPO Start */ + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021); + regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260); + regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000); + regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000); + regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c); + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000); + regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808); + regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e); + regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e); + regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803); + regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554); + regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103); + + /* Enalbe K ADC Power And Clock */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001, + 0x0001); + + /* Start Calibration */ + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000); + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021); + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80); + regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, + RT5659_SPK_DC_CAILB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 10) { + dev_err(rt5659->codec->dev, + "SPK Calibration Failure\n"); + return; + } + + count++; + } + /* Calibrate SPO End */ + + /* Calibrate MONO Start */ + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000); + regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f); + regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a); + /* MONO NG2 GAIN 5dB */ + regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003); + regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009); + + /* Start Calibration */ + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f); + regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00); + regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, + &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 35) { + dev_err(rt5659->codec->dev, + "Mono Calibration Failure\n"); + return; + } + + count++; + } + + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003); + /* Calibrate MONO End */ + + /* Power Off */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000); + regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0); + regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000); + regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011); + regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e); + regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a); + regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04); + regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e); + regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060); + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021); + regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000); + regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080); + regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080); + regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16); +} + +static int rt5659_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5659_priv *rt5659; + int ret; + unsigned int val; + + rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv), + GFP_KERNEL); + + if (rt5659 == NULL) + return -ENOMEM; + + rt5659->i2c = i2c; + i2c_set_clientdata(i2c, rt5659); + + if (pdata) + rt5659->pdata = *pdata; + else + rt5659_parse_dt(rt5659, &i2c->dev); + + rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5659->gpiod_ldo1_en)) + dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n"); + + rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_HIGH); + + /* Sleep for 300 ms miniumum */ + usleep_range(300000, 350000); + + rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap); + if (IS_ERR(rt5659->regmap)) { + ret = PTR_ERR(rt5659->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5659\n", val); + return -ENODEV; + } + + regmap_write(rt5659->regmap, RT5659_RESET, 0); + + rt5659_calibrate(rt5659); + + /* line in diff mode*/ + if (rt5659->pdata.in1_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2, + RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK); + if (rt5659->pdata.in3_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4, + RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK); + if (rt5659->pdata.in4_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4, + RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK); + + /* DMIC pin*/ + if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL || + rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) { + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL); + + switch (rt5659->pdata.dmic1_data_pin) { + case RT5659_DMIC1_DATA_IN2N: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N); + break; + + case RT5659_DMIC1_DATA_GPIO5: + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_3, + RT5659_I2S2_PIN_MASK, + RT5659_I2S2_PIN_GPIO); + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA); + break; + + case RT5659_DMIC1_DATA_GPIO9: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA); + break; + + case RT5659_DMIC1_DATA_GPIO11: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP11_PIN_MASK, + RT5659_GP11_PIN_DMIC1_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC1\n"); + break; + } + + switch (rt5659->pdata.dmic2_data_pin) { + case RT5659_DMIC2_DATA_IN2P: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_IN2P); + break; + + case RT5659_DMIC2_DATA_GPIO6: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO6); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP6_PIN_MASK, + RT5659_GP6_PIN_DMIC2_SDA); + break; + + case RT5659_DMIC2_DATA_GPIO10: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO10); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP10_PIN_MASK, + RT5659_GP10_PIN_DMIC2_SDA); + break; + + case RT5659_DMIC2_DATA_GPIO12: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO12); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP12_PIN_MASK, + RT5659_GP12_PIN_DMIC2_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC2\n"); + break; + + } + } else { + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK | + RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK | + RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK | + RT5659_GP12_PIN_MASK, + RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 | + RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 | + RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 | + RT5659_GP12_PIN_GPIO12); + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P); + } + + switch (rt5659->pdata.jd_src) { + case RT5659_JD3: + regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880); + regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000); + regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB, RT5659_PWR_MB); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001); + regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040); + break; + case RT5659_JD_NULL: + break; + default: + dev_warn(&i2c->dev, "Currently, support JD3 only\n"); + break; + } + + INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work); + + if (rt5659->i2c->irq) { + ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5659", rt5659); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, + rt5659_dai, ARRAY_SIZE(rt5659_dai)); + + if (ret) { + if (rt5659->i2c->irq) + free_irq(rt5659->i2c->irq, rt5659); + } + + return 0; +} + +static int rt5659_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +void rt5659_i2c_shutdown(struct i2c_client *client) +{ + struct rt5659_priv *rt5659 = i2c_get_clientdata(client); + + regmap_write(rt5659->regmap, RT5659_RESET, 0); +} + +static const struct of_device_id rt5659_of_match[] = { + { .compatible = "realtek,rt5658", }, + { .compatible = "realtek,rt5659", }, + {}, +}; + +static struct acpi_device_id rt5659_acpi_match[] = { + { "10EC5658", 0}, + { "10EC5659", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match); + +struct i2c_driver rt5659_i2c_driver = { + .driver = { + .name = "rt5659", + .owner = THIS_MODULE, + .of_match_table = rt5659_of_match, + .acpi_match_table = ACPI_PTR(rt5659_acpi_match), + }, + .probe = rt5659_i2c_probe, + .remove = rt5659_i2c_remove, + .shutdown = rt5659_i2c_shutdown, + .id_table = rt5659_i2c_id, +}; +module_i2c_driver(rt5659_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5659 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h new file mode 100644 index 000000000000..8f07ee903eaa --- /dev/null +++ b/sound/soc/codecs/rt5659.h @@ -0,0 +1,1819 @@ +/* + * rt5659.h -- RT5659/RT5658 ALSA SoC audio driver + * + * Copyright 2015 Realtek Microelectronics + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5659_H__ +#define __RT5659_H__ + +#include + +#define DEVICE_ID 0x6311 + +/* Info */ +#define RT5659_RESET 0x0000 +#define RT5659_VENDOR_ID 0x00fd +#define RT5659_VENDOR_ID_1 0x00fe +#define RT5659_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5659_SPO_VOL 0x0001 +#define RT5659_HP_VOL 0x0002 +#define RT5659_LOUT 0x0003 +#define RT5659_MONO_OUT 0x0004 +#define RT5659_HPL_GAIN 0x0005 +#define RT5659_HPR_GAIN 0x0006 +#define RT5659_MONO_GAIN 0x0007 +#define RT5659_SPDIF_CTRL_1 0x0008 +#define RT5659_SPDIF_CTRL_2 0x0009 +/* I/O - Input */ +#define RT5659_CAL_BST_CTRL 0x000a +#define RT5659_IN1_IN2 0x000c +#define RT5659_IN3_IN4 0x000d +#define RT5659_INL1_INR1_VOL 0x000f +/* I/O - Speaker */ +#define RT5659_EJD_CTRL_1 0x0010 +#define RT5659_EJD_CTRL_2 0x0011 +#define RT5659_EJD_CTRL_3 0x0012 +#define RT5659_SILENCE_CTRL 0x0015 +#define RT5659_PSV_CTRL 0x0016 +/* I/O - Sidetone */ +#define RT5659_SIDETONE_CTRL 0x0018 +/* I/O - ADC/DAC/DMIC */ +#define RT5659_DAC1_DIG_VOL 0x0019 +#define RT5659_DAC2_DIG_VOL 0x001a +#define RT5659_DAC_CTRL 0x001b +#define RT5659_STO1_ADC_DIG_VOL 0x001c +#define RT5659_MONO_ADC_DIG_VOL 0x001d +#define RT5659_STO2_ADC_DIG_VOL 0x001e +#define RT5659_STO1_BOOST 0x001f +#define RT5659_MONO_BOOST 0x0020 +#define RT5659_STO2_BOOST 0x0021 +#define RT5659_HP_IMP_GAIN_1 0x0022 +#define RT5659_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5659_STO1_ADC_MIXER 0x0026 +#define RT5659_MONO_ADC_MIXER 0x0027 +#define RT5659_AD_DA_MIXER 0x0029 +#define RT5659_STO_DAC_MIXER 0x002a +#define RT5659_MONO_DAC_MIXER 0x002b +#define RT5659_DIG_MIXER 0x002c +#define RT5659_A_DAC_MUX 0x002d +#define RT5659_DIG_INF23_DATA 0x002f +/* Mixer - PDM */ +#define RT5659_PDM_OUT_CTRL 0x0031 +#define RT5659_PDM_DATA_CTRL_1 0x0032 +#define RT5659_PDM_DATA_CTRL_2 0x0033 +#define RT5659_PDM_DATA_CTRL_3 0x0034 +#define RT5659_PDM_DATA_CTRL_4 0x0035 +#define RT5659_SPDIF_CTRL 0x0036 + +/* Mixer - ADC */ +#define RT5659_REC1_GAIN 0x003a +#define RT5659_REC1_L1_MIXER 0x003b +#define RT5659_REC1_L2_MIXER 0x003c +#define RT5659_REC1_R1_MIXER 0x003d +#define RT5659_REC1_R2_MIXER 0x003e +#define RT5659_CAL_REC 0x0040 +#define RT5659_REC2_L1_MIXER 0x009b +#define RT5659_REC2_L2_MIXER 0x009c +#define RT5659_REC2_R1_MIXER 0x009d +#define RT5659_REC2_R2_MIXER 0x009e +#define RT5659_RC_CLK_CTRL 0x009f +/* Mixer - DAC */ +#define RT5659_SPK_L_MIXER 0x0046 +#define RT5659_SPK_R_MIXER 0x0047 +#define RT5659_SPO_AMP_GAIN 0x0048 +#define RT5659_ALC_BACK_GAIN 0x0049 +#define RT5659_MONOMIX_GAIN 0x004a +#define RT5659_MONOMIX_IN_GAIN 0x004b +#define RT5659_OUT_L_GAIN 0x004d +#define RT5659_OUT_L_MIXER 0x004e +#define RT5659_OUT_R_GAIN 0x004f +#define RT5659_OUT_R_MIXER 0x0050 +#define RT5659_LOUT_MIXER 0x0052 + +#define RT5659_HAPTIC_GEN_CTRL_1 0x0053 +#define RT5659_HAPTIC_GEN_CTRL_2 0x0054 +#define RT5659_HAPTIC_GEN_CTRL_3 0x0055 +#define RT5659_HAPTIC_GEN_CTRL_4 0x0056 +#define RT5659_HAPTIC_GEN_CTRL_5 0x0057 +#define RT5659_HAPTIC_GEN_CTRL_6 0x0058 +#define RT5659_HAPTIC_GEN_CTRL_7 0x0059 +#define RT5659_HAPTIC_GEN_CTRL_8 0x005a +#define RT5659_HAPTIC_GEN_CTRL_9 0x005b +#define RT5659_HAPTIC_GEN_CTRL_10 0x005c +#define RT5659_HAPTIC_GEN_CTRL_11 0x005d +#define RT5659_HAPTIC_LPF_CTRL_1 0x005e +#define RT5659_HAPTIC_LPF_CTRL_2 0x005f +#define RT5659_HAPTIC_LPF_CTRL_3 0x0060 +/* Power */ +#define RT5659_PWR_DIG_1 0x0061 +#define RT5659_PWR_DIG_2 0x0062 +#define RT5659_PWR_ANLG_1 0x0063 +#define RT5659_PWR_ANLG_2 0x0064 +#define RT5659_PWR_ANLG_3 0x0065 +#define RT5659_PWR_MIXER 0x0066 +#define RT5659_PWR_VOL 0x0067 +/* Private Register Control */ +#define RT5659_PRIV_INDEX 0x006a +#define RT5659_CLK_DET 0x006b +#define RT5659_PRIV_DATA 0x006c +/* System Clock Pre Divider Gating Control */ +#define RT5659_PRE_DIV_1 0x006e +#define RT5659_PRE_DIV_2 0x006f +/* Format - ADC/DAC */ +#define RT5659_I2S1_SDP 0x0070 +#define RT5659_I2S2_SDP 0x0071 +#define RT5659_I2S3_SDP 0x0072 +#define RT5659_ADDA_CLK_1 0x0073 +#define RT5659_ADDA_CLK_2 0x0074 +#define RT5659_DMIC_CTRL_1 0x0075 +#define RT5659_DMIC_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5659_TDM_CTRL_1 0x0077 +#define RT5659_TDM_CTRL_2 0x0078 +#define RT5659_TDM_CTRL_3 0x0079 +#define RT5659_TDM_CTRL_4 0x007a +#define RT5659_TDM_CTRL_5 0x007b + +/* Function - Analog */ +#define RT5659_GLB_CLK 0x0080 +#define RT5659_PLL_CTRL_1 0x0081 +#define RT5659_PLL_CTRL_2 0x0082 +#define RT5659_ASRC_1 0x0083 +#define RT5659_ASRC_2 0x0084 +#define RT5659_ASRC_3 0x0085 +#define RT5659_ASRC_4 0x0086 +#define RT5659_ASRC_5 0x0087 +#define RT5659_ASRC_6 0x0088 +#define RT5659_ASRC_7 0x0089 +#define RT5659_ASRC_8 0x008a +#define RT5659_ASRC_9 0x008b +#define RT5659_ASRC_10 0x008c +#define RT5659_DEPOP_1 0x008e +#define RT5659_DEPOP_2 0x008f +#define RT5659_DEPOP_3 0x0090 +#define RT5659_HP_CHARGE_PUMP_1 0x0091 +#define RT5659_HP_CHARGE_PUMP_2 0x0092 +#define RT5659_MICBIAS_1 0x0093 +#define RT5659_MICBIAS_2 0x0094 +#define RT5659_ASRC_11 0x0097 +#define RT5659_ASRC_12 0x0098 +#define RT5659_ASRC_13 0x0099 +#define RT5659_REC_M1_M2_GAIN_CTRL 0x009a +#define RT5659_CLASSD_CTRL_1 0x00a0 +#define RT5659_CLASSD_CTRL_2 0x00a1 + +/* Function - Digital */ +#define RT5659_ADC_EQ_CTRL_1 0x00ae +#define RT5659_ADC_EQ_CTRL_2 0x00af +#define RT5659_DAC_EQ_CTRL_1 0x00b0 +#define RT5659_DAC_EQ_CTRL_2 0x00b1 +#define RT5659_DAC_EQ_CTRL_3 0x00b2 + +#define RT5659_IRQ_CTRL_1 0x00b6 +#define RT5659_IRQ_CTRL_2 0x00b7 +#define RT5659_IRQ_CTRL_3 0x00b8 +#define RT5659_IRQ_CTRL_4 0x00b9 +#define RT5659_IRQ_CTRL_5 0x00ba +#define RT5659_IRQ_CTRL_6 0x00bb +#define RT5659_INT_ST_1 0x00be +#define RT5659_INT_ST_2 0x00bf +#define RT5659_GPIO_CTRL_1 0x00c0 +#define RT5659_GPIO_CTRL_2 0x00c1 +#define RT5659_GPIO_CTRL_3 0x00c2 +#define RT5659_GPIO_CTRL_4 0x00c3 +#define RT5659_GPIO_CTRL_5 0x00c4 +#define RT5659_GPIO_STA 0x00c5 +#define RT5659_SINE_GEN_CTRL_1 0x00cb +#define RT5659_SINE_GEN_CTRL_2 0x00cc +#define RT5659_SINE_GEN_CTRL_3 0x00cd +#define RT5659_HP_AMP_DET_CTRL_1 0x00d6 +#define RT5659_HP_AMP_DET_CTRL_2 0x00d7 +#define RT5659_SV_ZCD_1 0x00d9 +#define RT5659_SV_ZCD_2 0x00da +#define RT5659_IL_CMD_1 0x00db +#define RT5659_IL_CMD_2 0x00dc +#define RT5659_IL_CMD_3 0x00dd +#define RT5659_IL_CMD_4 0x00de +#define RT5659_4BTN_IL_CMD_1 0x00df +#define RT5659_4BTN_IL_CMD_2 0x00e0 +#define RT5659_4BTN_IL_CMD_3 0x00e1 +#define RT5659_PSV_IL_CMD_1 0x00e4 +#define RT5659_PSV_IL_CMD_2 0x00e5 + +#define RT5659_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5659_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5659_ADC_MONO_HP_CTRL_1 0x00ec +#define RT5659_ADC_MONO_HP_CTRL_2 0x00ed +#define RT5659_AJD1_CTRL 0x00f0 +#define RT5659_AJD2_AJD3_CTRL 0x00f1 +#define RT5659_JD1_THD 0x00f2 +#define RT5659_JD2_THD 0x00f3 +#define RT5659_JD3_THD 0x00f4 +#define RT5659_JD_CTRL_1 0x00f6 +#define RT5659_JD_CTRL_2 0x00f7 +#define RT5659_JD_CTRL_3 0x00f8 +#define RT5659_JD_CTRL_4 0x00f9 +/* General Control */ +#define RT5659_DIG_MISC 0x00fa +#define RT5659_DUMMY_2 0x00fb +#define RT5659_DUMMY_3 0x00fc + +#define RT5659_DAC_ADC_DIG_VOL 0x0100 +#define RT5659_BIAS_CUR_CTRL_1 0x010a +#define RT5659_BIAS_CUR_CTRL_2 0x010b +#define RT5659_BIAS_CUR_CTRL_3 0x010c +#define RT5659_BIAS_CUR_CTRL_4 0x010d +#define RT5659_BIAS_CUR_CTRL_5 0x010e +#define RT5659_BIAS_CUR_CTRL_6 0x010f +#define RT5659_BIAS_CUR_CTRL_7 0x0110 +#define RT5659_BIAS_CUR_CTRL_8 0x0111 +#define RT5659_BIAS_CUR_CTRL_9 0x0112 +#define RT5659_BIAS_CUR_CTRL_10 0x0113 +#define RT5659_MEMORY_TEST 0x0116 +#define RT5659_VREF_REC_OP_FB_CAP_CTRL 0x0117 +#define RT5659_CLASSD_0 0x011a +#define RT5659_CLASSD_1 0x011b +#define RT5659_CLASSD_2 0x011c +#define RT5659_CLASSD_3 0x011d +#define RT5659_CLASSD_4 0x011e +#define RT5659_CLASSD_5 0x011f +#define RT5659_CLASSD_6 0x0120 +#define RT5659_CLASSD_7 0x0121 +#define RT5659_CLASSD_8 0x0122 +#define RT5659_CLASSD_9 0x0123 +#define RT5659_CLASSD_10 0x0124 +#define RT5659_CHARGE_PUMP_1 0x0125 +#define RT5659_CHARGE_PUMP_2 0x0126 +#define RT5659_DIG_IN_CTRL_1 0x0132 +#define RT5659_DIG_IN_CTRL_2 0x0133 +#define RT5659_PAD_DRIVING_CTRL 0x0137 +#define RT5659_SOFT_RAMP_DEPOP 0x0138 +#define RT5659_PLL 0x0139 +#define RT5659_CHOP_DAC 0x013a +#define RT5659_CHOP_ADC 0x013b +#define RT5659_CALIB_ADC_CTRL 0x013c +#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL 0x013e +#define RT5659_VOL_TEST 0x013f +#define RT5659_TEST_MODE_CTRL_1 0x0145 +#define RT5659_TEST_MODE_CTRL_2 0x0146 +#define RT5659_TEST_MODE_CTRL_3 0x0147 +#define RT5659_TEST_MODE_CTRL_4 0x0148 +#define RT5659_BASSBACK_CTRL 0x0150 +#define RT5659_MP3_PLUS_CTRL_1 0x0151 +#define RT5659_MP3_PLUS_CTRL_2 0x0152 +#define RT5659_MP3_HPF_A1 0x0153 +#define RT5659_MP3_HPF_A2 0x0154 +#define RT5659_MP3_HPF_H0 0x0155 +#define RT5659_MP3_LPF_H0 0x0156 +#define RT5659_3D_SPK_CTRL 0x0157 +#define RT5659_3D_SPK_COEF_1 0x0158 +#define RT5659_3D_SPK_COEF_2 0x0159 +#define RT5659_3D_SPK_COEF_3 0x015a +#define RT5659_3D_SPK_COEF_4 0x015b +#define RT5659_3D_SPK_COEF_5 0x015c +#define RT5659_3D_SPK_COEF_6 0x015d +#define RT5659_3D_SPK_COEF_7 0x015e +#define RT5659_STO_NG2_CTRL_1 0x0160 +#define RT5659_STO_NG2_CTRL_2 0x0161 +#define RT5659_STO_NG2_CTRL_3 0x0162 +#define RT5659_STO_NG2_CTRL_4 0x0163 +#define RT5659_STO_NG2_CTRL_5 0x0164 +#define RT5659_STO_NG2_CTRL_6 0x0165 +#define RT5659_STO_NG2_CTRL_7 0x0166 +#define RT5659_STO_NG2_CTRL_8 0x0167 +#define RT5659_MONO_NG2_CTRL_1 0x0170 +#define RT5659_MONO_NG2_CTRL_2 0x0171 +#define RT5659_MONO_NG2_CTRL_3 0x0172 +#define RT5659_MONO_NG2_CTRL_4 0x0173 +#define RT5659_MONO_NG2_CTRL_5 0x0174 +#define RT5659_MONO_NG2_CTRL_6 0x0175 +#define RT5659_MID_HP_AMP_DET 0x0190 +#define RT5659_LOW_HP_AMP_DET 0x0191 +#define RT5659_LDO_CTRL 0x0192 +#define RT5659_HP_DECROSS_CTRL_1 0x01b0 +#define RT5659_HP_DECROSS_CTRL_2 0x01b1 +#define RT5659_HP_DECROSS_CTRL_3 0x01b2 +#define RT5659_HP_DECROSS_CTRL_4 0x01b3 +#define RT5659_HP_IMP_SENS_CTRL_1 0x01c0 +#define RT5659_HP_IMP_SENS_CTRL_2 0x01c1 +#define RT5659_HP_IMP_SENS_CTRL_3 0x01c2 +#define RT5659_HP_IMP_SENS_CTRL_4 0x01c3 +#define RT5659_HP_IMP_SENS_MAP_1 0x01c7 +#define RT5659_HP_IMP_SENS_MAP_2 0x01c8 +#define RT5659_HP_IMP_SENS_MAP_3 0x01c9 +#define RT5659_HP_IMP_SENS_MAP_4 0x01ca +#define RT5659_HP_IMP_SENS_MAP_5 0x01cb +#define RT5659_HP_IMP_SENS_MAP_6 0x01cc +#define RT5659_HP_IMP_SENS_MAP_7 0x01cd +#define RT5659_HP_IMP_SENS_MAP_8 0x01ce +#define RT5659_HP_LOGIC_CTRL_1 0x01da +#define RT5659_HP_LOGIC_CTRL_2 0x01db +#define RT5659_HP_CALIB_CTRL_1 0x01de +#define RT5659_HP_CALIB_CTRL_2 0x01df +#define RT5659_HP_CALIB_CTRL_3 0x01e0 +#define RT5659_HP_CALIB_CTRL_4 0x01e1 +#define RT5659_HP_CALIB_CTRL_5 0x01e2 +#define RT5659_HP_CALIB_CTRL_6 0x01e3 +#define RT5659_HP_CALIB_CTRL_7 0x01e4 +#define RT5659_HP_CALIB_CTRL_9 0x01e6 +#define RT5659_HP_CALIB_CTRL_10 0x01e7 +#define RT5659_HP_CALIB_CTRL_11 0x01e8 +#define RT5659_HP_CALIB_STA_1 0x01ea +#define RT5659_HP_CALIB_STA_2 0x01eb +#define RT5659_HP_CALIB_STA_3 0x01ec +#define RT5659_HP_CALIB_STA_4 0x01ed +#define RT5659_HP_CALIB_STA_5 0x01ee +#define RT5659_HP_CALIB_STA_6 0x01ef +#define RT5659_HP_CALIB_STA_7 0x01f0 +#define RT5659_HP_CALIB_STA_8 0x01f1 +#define RT5659_HP_CALIB_STA_9 0x01f2 +#define RT5659_MONO_AMP_CALIB_CTRL_1 0x01f6 +#define RT5659_MONO_AMP_CALIB_CTRL_2 0x01f7 +#define RT5659_MONO_AMP_CALIB_CTRL_3 0x01f8 +#define RT5659_MONO_AMP_CALIB_CTRL_4 0x01f9 +#define RT5659_MONO_AMP_CALIB_CTRL_5 0x01fa +#define RT5659_MONO_AMP_CALIB_STA_1 0x01fb +#define RT5659_MONO_AMP_CALIB_STA_2 0x01fc +#define RT5659_MONO_AMP_CALIB_STA_3 0x01fd +#define RT5659_MONO_AMP_CALIB_STA_4 0x01fe +#define RT5659_SPK_PWR_LMT_CTRL_1 0x0200 +#define RT5659_SPK_PWR_LMT_CTRL_2 0x0201 +#define RT5659_SPK_PWR_LMT_CTRL_3 0x0202 +#define RT5659_SPK_PWR_LMT_STA_1 0x0203 +#define RT5659_SPK_PWR_LMT_STA_2 0x0204 +#define RT5659_SPK_PWR_LMT_STA_3 0x0205 +#define RT5659_SPK_PWR_LMT_STA_4 0x0206 +#define RT5659_SPK_PWR_LMT_STA_5 0x0207 +#define RT5659_SPK_PWR_LMT_STA_6 0x0208 +#define RT5659_FLEX_SPK_BST_CTRL_1 0x0256 +#define RT5659_FLEX_SPK_BST_CTRL_2 0x0257 +#define RT5659_FLEX_SPK_BST_CTRL_3 0x0258 +#define RT5659_FLEX_SPK_BST_CTRL_4 0x0259 +#define RT5659_SPK_EX_LMT_CTRL_1 0x025a +#define RT5659_SPK_EX_LMT_CTRL_2 0x025b +#define RT5659_SPK_EX_LMT_CTRL_3 0x025c +#define RT5659_SPK_EX_LMT_CTRL_4 0x025d +#define RT5659_SPK_EX_LMT_CTRL_5 0x025e +#define RT5659_SPK_EX_LMT_CTRL_6 0x025f +#define RT5659_SPK_EX_LMT_CTRL_7 0x0260 +#define RT5659_ADJ_HPF_CTRL_1 0x0261 +#define RT5659_ADJ_HPF_CTRL_2 0x0262 +#define RT5659_SPK_DC_CAILB_CTRL_1 0x0265 +#define RT5659_SPK_DC_CAILB_CTRL_2 0x0266 +#define RT5659_SPK_DC_CAILB_CTRL_3 0x0267 +#define RT5659_SPK_DC_CAILB_CTRL_4 0x0268 +#define RT5659_SPK_DC_CAILB_CTRL_5 0x0269 +#define RT5659_SPK_DC_CAILB_STA_1 0x026a +#define RT5659_SPK_DC_CAILB_STA_2 0x026b +#define RT5659_SPK_DC_CAILB_STA_3 0x026c +#define RT5659_SPK_DC_CAILB_STA_4 0x026d +#define RT5659_SPK_DC_CAILB_STA_5 0x026e +#define RT5659_SPK_DC_CAILB_STA_6 0x026f +#define RT5659_SPK_DC_CAILB_STA_7 0x0270 +#define RT5659_SPK_DC_CAILB_STA_8 0x0271 +#define RT5659_SPK_DC_CAILB_STA_9 0x0272 +#define RT5659_SPK_DC_CAILB_STA_10 0x0273 +#define RT5659_SPK_VDD_STA_1 0x0280 +#define RT5659_SPK_VDD_STA_2 0x0281 +#define RT5659_SPK_DC_DET_CTRL_1 0x0282 +#define RT5659_SPK_DC_DET_CTRL_2 0x0283 +#define RT5659_SPK_DC_DET_CTRL_3 0x0284 +#define RT5659_PURE_DC_DET_CTRL_1 0x0290 +#define RT5659_PURE_DC_DET_CTRL_2 0x0291 +#define RT5659_DUMMY_4 0x02fa +#define RT5659_DUMMY_5 0x02fb +#define RT5659_DUMMY_6 0x02fc +#define RT5659_DRC1_CTRL_1 0x0300 +#define RT5659_DRC1_CTRL_2 0x0301 +#define RT5659_DRC1_CTRL_3 0x0302 +#define RT5659_DRC1_CTRL_4 0x0303 +#define RT5659_DRC1_CTRL_5 0x0304 +#define RT5659_DRC1_CTRL_6 0x0305 +#define RT5659_DRC1_HARD_LMT_CTRL_1 0x0306 +#define RT5659_DRC1_HARD_LMT_CTRL_2 0x0307 +#define RT5659_DRC2_CTRL_1 0x0308 +#define RT5659_DRC2_CTRL_2 0x0309 +#define RT5659_DRC2_CTRL_3 0x030a +#define RT5659_DRC2_CTRL_4 0x030b +#define RT5659_DRC2_CTRL_5 0x030c +#define RT5659_DRC2_CTRL_6 0x030d +#define RT5659_DRC2_HARD_LMT_CTRL_1 0x030e +#define RT5659_DRC2_HARD_LMT_CTRL_2 0x030f +#define RT5659_DRC1_PRIV_1 0x0310 +#define RT5659_DRC1_PRIV_2 0x0311 +#define RT5659_DRC1_PRIV_3 0x0312 +#define RT5659_DRC1_PRIV_4 0x0313 +#define RT5659_DRC1_PRIV_5 0x0314 +#define RT5659_DRC1_PRIV_6 0x0315 +#define RT5659_DRC1_PRIV_7 0x0316 +#define RT5659_DRC2_PRIV_1 0x0317 +#define RT5659_DRC2_PRIV_2 0x0318 +#define RT5659_DRC2_PRIV_3 0x0319 +#define RT5659_DRC2_PRIV_4 0x031a +#define RT5659_DRC2_PRIV_5 0x031b +#define RT5659_DRC2_PRIV_6 0x031c +#define RT5659_DRC2_PRIV_7 0x031d +#define RT5659_MULTI_DRC_CTRL 0x0320 +#define RT5659_CROSS_OVER_1 0x0321 +#define RT5659_CROSS_OVER_2 0x0322 +#define RT5659_CROSS_OVER_3 0x0323 +#define RT5659_CROSS_OVER_4 0x0324 +#define RT5659_CROSS_OVER_5 0x0325 +#define RT5659_CROSS_OVER_6 0x0326 +#define RT5659_CROSS_OVER_7 0x0327 +#define RT5659_CROSS_OVER_8 0x0328 +#define RT5659_CROSS_OVER_9 0x0329 +#define RT5659_CROSS_OVER_10 0x032a +#define RT5659_ALC_PGA_CTRL_1 0x0330 +#define RT5659_ALC_PGA_CTRL_2 0x0331 +#define RT5659_ALC_PGA_CTRL_3 0x0332 +#define RT5659_ALC_PGA_CTRL_4 0x0333 +#define RT5659_ALC_PGA_CTRL_5 0x0334 +#define RT5659_ALC_PGA_CTRL_6 0x0335 +#define RT5659_ALC_PGA_CTRL_7 0x0336 +#define RT5659_ALC_PGA_CTRL_8 0x0337 +#define RT5659_ALC_PGA_STA_1 0x0338 +#define RT5659_ALC_PGA_STA_2 0x0339 +#define RT5659_ALC_PGA_STA_3 0x033a +#define RT5659_DAC_L_EQ_PRE_VOL 0x0340 +#define RT5659_DAC_R_EQ_PRE_VOL 0x0341 +#define RT5659_DAC_L_EQ_POST_VOL 0x0342 +#define RT5659_DAC_R_EQ_POST_VOL 0x0343 +#define RT5659_DAC_L_EQ_LPF1_A1 0x0344 +#define RT5659_DAC_L_EQ_LPF1_H0 0x0345 +#define RT5659_DAC_R_EQ_LPF1_A1 0x0346 +#define RT5659_DAC_R_EQ_LPF1_H0 0x0347 +#define RT5659_DAC_L_EQ_BPF2_A1 0x0348 +#define RT5659_DAC_L_EQ_BPF2_A2 0x0349 +#define RT5659_DAC_L_EQ_BPF2_H0 0x034a +#define RT5659_DAC_R_EQ_BPF2_A1 0x034b +#define RT5659_DAC_R_EQ_BPF2_A2 0x034c +#define RT5659_DAC_R_EQ_BPF2_H0 0x034d +#define RT5659_DAC_L_EQ_BPF3_A1 0x034e +#define RT5659_DAC_L_EQ_BPF3_A2 0x034f +#define RT5659_DAC_L_EQ_BPF3_H0 0x0350 +#define RT5659_DAC_R_EQ_BPF3_A1 0x0351 +#define RT5659_DAC_R_EQ_BPF3_A2 0x0352 +#define RT5659_DAC_R_EQ_BPF3_H0 0x0353 +#define RT5659_DAC_L_EQ_BPF4_A1 0x0354 +#define RT5659_DAC_L_EQ_BPF4_A2 0x0355 +#define RT5659_DAC_L_EQ_BPF4_H0 0x0356 +#define RT5659_DAC_R_EQ_BPF4_A1 0x0357 +#define RT5659_DAC_R_EQ_BPF4_A2 0x0358 +#define RT5659_DAC_R_EQ_BPF4_H0 0x0359 +#define RT5659_DAC_L_EQ_HPF1_A1 0x035a +#define RT5659_DAC_L_EQ_HPF1_H0 0x035b +#define RT5659_DAC_R_EQ_HPF1_A1 0x035c +#define RT5659_DAC_R_EQ_HPF1_H0 0x035d +#define RT5659_DAC_L_EQ_HPF2_A1 0x035e +#define RT5659_DAC_L_EQ_HPF2_A2 0x035f +#define RT5659_DAC_L_EQ_HPF2_H0 0x0360 +#define RT5659_DAC_R_EQ_HPF2_A1 0x0361 +#define RT5659_DAC_R_EQ_HPF2_A2 0x0362 +#define RT5659_DAC_R_EQ_HPF2_H0 0x0363 +#define RT5659_DAC_L_BI_EQ_BPF1_H0_1 0x0364 +#define RT5659_DAC_L_BI_EQ_BPF1_H0_2 0x0365 +#define RT5659_DAC_L_BI_EQ_BPF1_B1_1 0x0366 +#define RT5659_DAC_L_BI_EQ_BPF1_B1_2 0x0367 +#define RT5659_DAC_L_BI_EQ_BPF1_B2_1 0x0368 +#define RT5659_DAC_L_BI_EQ_BPF1_B2_2 0x0369 +#define RT5659_DAC_L_BI_EQ_BPF1_A1_1 0x036a +#define RT5659_DAC_L_BI_EQ_BPF1_A1_2 0x036b +#define RT5659_DAC_L_BI_EQ_BPF1_A2_1 0x036c +#define RT5659_DAC_L_BI_EQ_BPF1_A2_2 0x036d +#define RT5659_DAC_R_BI_EQ_BPF1_H0_1 0x036e +#define RT5659_DAC_R_BI_EQ_BPF1_H0_2 0x036f +#define RT5659_DAC_R_BI_EQ_BPF1_B1_1 0x0370 +#define RT5659_DAC_R_BI_EQ_BPF1_B1_2 0x0371 +#define RT5659_DAC_R_BI_EQ_BPF1_B2_1 0x0372 +#define RT5659_DAC_R_BI_EQ_BPF1_B2_2 0x0373 +#define RT5659_DAC_R_BI_EQ_BPF1_A1_1 0x0374 +#define RT5659_DAC_R_BI_EQ_BPF1_A1_2 0x0375 +#define RT5659_DAC_R_BI_EQ_BPF1_A2_1 0x0376 +#define RT5659_DAC_R_BI_EQ_BPF1_A2_2 0x0377 +#define RT5659_ADC_L_EQ_LPF1_A1 0x03d0 +#define RT5659_ADC_R_EQ_LPF1_A1 0x03d1 +#define RT5659_ADC_L_EQ_LPF1_H0 0x03d2 +#define RT5659_ADC_R_EQ_LPF1_H0 0x03d3 +#define RT5659_ADC_L_EQ_BPF1_A1 0x03d4 +#define RT5659_ADC_R_EQ_BPF1_A1 0x03d5 +#define RT5659_ADC_L_EQ_BPF1_A2 0x03d6 +#define RT5659_ADC_R_EQ_BPF1_A2 0x03d7 +#define RT5659_ADC_L_EQ_BPF1_H0 0x03d8 +#define RT5659_ADC_R_EQ_BPF1_H0 0x03d9 +#define RT5659_ADC_L_EQ_BPF2_A1 0x03da +#define RT5659_ADC_R_EQ_BPF2_A1 0x03db +#define RT5659_ADC_L_EQ_BPF2_A2 0x03dc +#define RT5659_ADC_R_EQ_BPF2_A2 0x03dd +#define RT5659_ADC_L_EQ_BPF2_H0 0x03de +#define RT5659_ADC_R_EQ_BPF2_H0 0x03df +#define RT5659_ADC_L_EQ_BPF3_A1 0x03e0 +#define RT5659_ADC_R_EQ_BPF3_A1 0x03e1 +#define RT5659_ADC_L_EQ_BPF3_A2 0x03e2 +#define RT5659_ADC_R_EQ_BPF3_A2 0x03e3 +#define RT5659_ADC_L_EQ_BPF3_H0 0x03e4 +#define RT5659_ADC_R_EQ_BPF3_H0 0x03e5 +#define RT5659_ADC_L_EQ_BPF4_A1 0x03e6 +#define RT5659_ADC_R_EQ_BPF4_A1 0x03e7 +#define RT5659_ADC_L_EQ_BPF4_A2 0x03e8 +#define RT5659_ADC_R_EQ_BPF4_A2 0x03e9 +#define RT5659_ADC_L_EQ_BPF4_H0 0x03ea +#define RT5659_ADC_R_EQ_BPF4_H0 0x03eb +#define RT5659_ADC_L_EQ_HPF1_A1 0x03ec +#define RT5659_ADC_R_EQ_HPF1_A1 0x03ed +#define RT5659_ADC_L_EQ_HPF1_H0 0x03ee +#define RT5659_ADC_R_EQ_HPF1_H0 0x03ef +#define RT5659_ADC_L_EQ_PRE_VOL 0x03f0 +#define RT5659_ADC_R_EQ_PRE_VOL 0x03f1 +#define RT5659_ADC_L_EQ_POST_VOL 0x03f2 +#define RT5659_ADC_R_EQ_POST_VOL 0x03f3 + + + +/* global definition */ +#define RT5659_L_MUTE (0x1 << 15) +#define RT5659_L_MUTE_SFT 15 +#define RT5659_VOL_L_MUTE (0x1 << 14) +#define RT5659_VOL_L_SFT 14 +#define RT5659_R_MUTE (0x1 << 7) +#define RT5659_R_MUTE_SFT 7 +#define RT5659_VOL_R_MUTE (0x1 << 6) +#define RT5659_VOL_R_SFT 6 +#define RT5659_L_VOL_MASK (0x3f << 8) +#define RT5659_L_VOL_SFT 8 +#define RT5659_R_VOL_MASK (0x3f) +#define RT5659_R_VOL_SFT 0 + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5659_G_HP (0x1f << 8) +#define RT5659_G_HP_SFT 8 +#define RT5659_G_STO_DA_DMIX (0x1f) +#define RT5659_G_STO_DA_SFT 0 + +/* IN1/IN2 Control (0x000c) */ +#define RT5659_IN1_DF_MASK (0x1 << 15) +#define RT5659_IN1_DF 15 +#define RT5659_BST1_MASK (0x7f << 8) +#define RT5659_BST1_SFT 8 +#define RT5659_BST2_MASK (0x7f) +#define RT5659_BST2_SFT 0 + +/* IN3/IN4 Control (0x000d) */ +#define RT5659_IN3_DF_MASK (0x1 << 15) +#define RT5659_IN3_DF 15 +#define RT5659_BST3_MASK (0x7f << 8) +#define RT5659_BST3_SFT 8 +#define RT5659_IN4_DF_MASK (0x1 << 7) +#define RT5659_IN4_DF 7 +#define RT5659_BST4_MASK (0x7f) +#define RT5659_BST4_SFT 0 + +/* INL and INR Volume Control (0x000f) */ +#define RT5659_INL_VOL_MASK (0x1f << 8) +#define RT5659_INL_VOL_SFT 8 +#define RT5659_INR_VOL_MASK (0x1f) +#define RT5659_INR_VOL_SFT 0 + +/* Embeeded Jack and Type Detection Control 1 (0x0010) */ +#define RT5659_EMB_JD_EN (0x1 << 15) +#define RT5659_EMB_JD_EN_SFT 15 +#define RT5659_JD_MODE (0x1 << 13) +#define RT5659_JD_MODE_SFT 13 +#define RT5659_EXT_JD_EN (0x1 << 11) +#define RT5659_EXT_JD_EN_SFT 11 +#define RT5659_EXT_JD_DIG (0x1 << 9) + +/* Embeeded Jack and Type Detection Control 2 (0x0011) */ +#define RT5659_EXT_JD_SRC (0x7 << 4) +#define RT5659_EXT_JD_SRC_SFT 4 +#define RT5659_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5659_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5659_EXT_JD_SRC_JD1_1 (0x2 << 4) +#define RT5659_EXT_JD_SRC_JD1_2 (0x3 << 4) +#define RT5659_EXT_JD_SRC_JD2 (0x4 << 4) +#define RT5659_EXT_JD_SRC_JD3 (0x5 << 4) +#define RT5659_EXT_JD_SRC_MANUAL (0x6 << 4) + +/* Slience Detection Control (0x0015) */ +#define RT5659_SIL_DET_MASK (0x1 << 15) +#define RT5659_SIL_DET_DIS (0x0 << 15) +#define RT5659_SIL_DET_EN (0x1 << 15) + +/* Sidetone Control (0x0018) */ +#define RT5659_ST_SEL_MASK (0x7 << 9) +#define RT5659_ST_SEL_SFT 9 +#define RT5659_ST_EN (0x1 << 6) +#define RT5659_ST_EN_SFT 6 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5659_DAC_L1_VOL_MASK (0xff << 8) +#define RT5659_DAC_L1_VOL_SFT 8 +#define RT5659_DAC_R1_VOL_MASK (0xff) +#define RT5659_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x001a) */ +#define RT5659_DAC_L2_VOL_MASK (0xff << 8) +#define RT5659_DAC_L2_VOL_SFT 8 +#define RT5659_DAC_R2_VOL_MASK (0xff) +#define RT5659_DAC_R2_VOL_SFT 0 + +/* DAC2 Control (0x001b) */ +#define RT5659_M_DAC2_L_VOL (0x1 << 13) +#define RT5659_M_DAC2_L_VOL_SFT 13 +#define RT5659_M_DAC2_R_VOL (0x1 << 12) +#define RT5659_M_DAC2_R_VOL_SFT 12 +#define RT5659_DAC_L2_SEL_MASK (0x7 << 4) +#define RT5659_DAC_L2_SEL_SFT 4 +#define RT5659_DAC_R2_SEL_MASK (0x7 << 0) +#define RT5659_DAC_R2_SEL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5659_ADC_L_VOL_MASK (0x7f << 8) +#define RT5659_ADC_L_VOL_SFT 8 +#define RT5659_ADC_R_VOL_MASK (0x7f) +#define RT5659_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x001d) */ +#define RT5659_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5659_MONO_ADC_L_VOL_SFT 8 +#define RT5659_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5659_MONO_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5659_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_STO1_ADC_L_BST_SFT 14 +#define RT5659_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_STO1_ADC_R_BST_SFT 12 + +/* Mono ADC Boost Gain Control (0x0020) */ +#define RT5659_MONO_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_MONO_ADC_L_BST_SFT 14 +#define RT5659_MONO_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_MONO_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5659_STO2_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_STO2_ADC_L_BST_SFT 14 +#define RT5659_STO2_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_STO2_ADC_R_BST_SFT 12 + +/* Stereo ADC Mixer Control (0x0026) */ +#define RT5659_M_STO1_ADC_L1 (0x1 << 15) +#define RT5659_M_STO1_ADC_L1_SFT 15 +#define RT5659_M_STO1_ADC_L2 (0x1 << 14) +#define RT5659_M_STO1_ADC_L2_SFT 14 +#define RT5659_STO1_ADC1_SRC_MASK (0x1 << 13) +#define RT5659_STO1_ADC1_SRC_SFT 13 +#define RT5659_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5659_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5659_STO1_ADC_SRC_MASK (0x1 << 12) +#define RT5659_STO1_ADC_SRC_SFT 12 +#define RT5659_STO1_ADC_SRC_ADC1 (0x1 << 12) +#define RT5659_STO1_ADC_SRC_ADC2 (0x0 << 12) +#define RT5659_STO1_ADC2_SRC_MASK (0x1 << 11) +#define RT5659_STO1_ADC2_SRC_SFT 11 +#define RT5659_STO1_DMIC_SRC_MASK (0x1 << 8) +#define RT5659_STO1_DMIC_SRC_SFT 8 +#define RT5659_STO1_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5659_STO1_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5659_M_STO1_ADC_R1 (0x1 << 6) +#define RT5659_M_STO1_ADC_R1_SFT 6 +#define RT5659_M_STO1_ADC_R2 (0x1 << 5) +#define RT5659_M_STO1_ADC_R2_SFT 5 + +/* Mono1 ADC Mixer control (0x0027) */ +#define RT5659_M_MONO_ADC_L1 (0x1 << 15) +#define RT5659_M_MONO_ADC_L1_SFT 15 +#define RT5659_M_MONO_ADC_L2 (0x1 << 14) +#define RT5659_M_MONO_ADC_L2_SFT 14 +#define RT5659_MONO_ADC_L2_SRC_MASK (0x1 << 12) +#define RT5659_MONO_ADC_L2_SRC_SFT 12 +#define RT5659_MONO_ADC_L1_SRC_MASK (0x1 << 11) +#define RT5659_MONO_ADC_L1_SRC_SFT 11 +#define RT5659_MONO_ADC_L_SRC_MASK (0x3 << 9) +#define RT5659_MONO_ADC_L_SRC_SFT 9 +#define RT5659_MONO_DMIC_L_SRC_MASK (0x1 << 8) +#define RT5659_MONO_DMIC_L_SRC_SFT 8 +#define RT5659_M_MONO_ADC_R1 (0x1 << 7) +#define RT5659_M_MONO_ADC_R1_SFT 7 +#define RT5659_M_MONO_ADC_R2 (0x1 << 6) +#define RT5659_M_MONO_ADC_R2_SFT 6 +#define RT5659_STO2_ADC_SRC_MASK (0x1 << 5) +#define RT5659_STO2_ADC_SRC_SFT 5 +#define RT5659_MONO_ADC_R2_SRC_MASK (0x1 << 4) +#define RT5659_MONO_ADC_R2_SRC_SFT 4 +#define RT5659_MONO_ADC_R1_SRC_MASK (0x1 << 3) +#define RT5659_MONO_ADC_R1_SRC_SFT 3 +#define RT5659_MONO_ADC_R_SRC_MASK (0x3 << 1) +#define RT5659_MONO_ADC_R_SRC_SFT 1 +#define RT5659_MONO_DMIC_R_SRC_MASK 0x1 +#define RT5659_MONO_DMIC_R_SRC_SFT 0 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5659_M_ADCMIX_L (0x1 << 15) +#define RT5659_M_ADCMIX_L_SFT 15 +#define RT5659_M_DAC1_L (0x1 << 14) +#define RT5659_M_DAC1_L_SFT 14 +#define RT5659_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5659_DAC1_R_SEL_SFT 10 +#define RT5659_DAC1_R_SEL_IF1 (0x0 << 10) +#define RT5659_DAC1_R_SEL_IF2 (0x1 << 10) +#define RT5659_DAC1_R_SEL_IF3 (0x2 << 10) +#define RT5659_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5659_DAC1_L_SEL_SFT 8 +#define RT5659_DAC1_L_SEL_IF1 (0x0 << 8) +#define RT5659_DAC1_L_SEL_IF2 (0x1 << 8) +#define RT5659_DAC1_L_SEL_IF3 (0x2 << 8) +#define RT5659_M_ADCMIX_R (0x1 << 7) +#define RT5659_M_ADCMIX_R_SFT 7 +#define RT5659_M_DAC1_R (0x1 << 6) +#define RT5659_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x002a) */ +#define RT5659_M_DAC_L1_STO_L (0x1 << 15) +#define RT5659_M_DAC_L1_STO_L_SFT 15 +#define RT5659_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5659_G_DAC_L1_STO_L_SFT 14 +#define RT5659_M_DAC_R1_STO_L (0x1 << 13) +#define RT5659_M_DAC_R1_STO_L_SFT 13 +#define RT5659_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5659_G_DAC_R1_STO_L_SFT 12 +#define RT5659_M_DAC_L2_STO_L (0x1 << 11) +#define RT5659_M_DAC_L2_STO_L_SFT 11 +#define RT5659_G_DAC_L2_STO_L_MASK (0x1 << 10) +#define RT5659_G_DAC_L2_STO_L_SFT 10 +#define RT5659_M_DAC_R2_STO_L (0x1 << 9) +#define RT5659_M_DAC_R2_STO_L_SFT 9 +#define RT5659_G_DAC_R2_STO_L_MASK (0x1 << 8) +#define RT5659_G_DAC_R2_STO_L_SFT 8 +#define RT5659_M_DAC_L1_STO_R (0x1 << 7) +#define RT5659_M_DAC_L1_STO_R_SFT 7 +#define RT5659_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5659_G_DAC_L1_STO_R_SFT 6 +#define RT5659_M_DAC_R1_STO_R (0x1 << 5) +#define RT5659_M_DAC_R1_STO_R_SFT 5 +#define RT5659_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5659_G_DAC_R1_STO_R_SFT 4 +#define RT5659_M_DAC_L2_STO_R (0x1 << 3) +#define RT5659_M_DAC_L2_STO_R_SFT 3 +#define RT5659_G_DAC_L2_STO_R_MASK (0x1 << 2) +#define RT5659_G_DAC_L2_STO_R_SFT 2 +#define RT5659_M_DAC_R2_STO_R (0x1 << 1) +#define RT5659_M_DAC_R2_STO_R_SFT 1 +#define RT5659_G_DAC_R2_STO_R_MASK (0x1) +#define RT5659_G_DAC_R2_STO_R_SFT 0 + +/* Mono DAC Mixer Control (0x002b) */ +#define RT5659_M_DAC_L1_MONO_L (0x1 << 15) +#define RT5659_M_DAC_L1_MONO_L_SFT 15 +#define RT5659_G_DAC_L1_MONO_L_MASK (0x1 << 14) +#define RT5659_G_DAC_L1_MONO_L_SFT 14 +#define RT5659_M_DAC_R1_MONO_L (0x1 << 13) +#define RT5659_M_DAC_R1_MONO_L_SFT 13 +#define RT5659_G_DAC_R1_MONO_L_MASK (0x1 << 12) +#define RT5659_G_DAC_R1_MONO_L_SFT 12 +#define RT5659_M_DAC_L2_MONO_L (0x1 << 11) +#define RT5659_M_DAC_L2_MONO_L_SFT 11 +#define RT5659_G_DAC_L2_MONO_L_MASK (0x1 << 10) +#define RT5659_G_DAC_L2_MONO_L_SFT 10 +#define RT5659_M_DAC_R2_MONO_L (0x1 << 9) +#define RT5659_M_DAC_R2_MONO_L_SFT 9 +#define RT5659_G_DAC_R2_MONO_L_MASK (0x1 << 8) +#define RT5659_G_DAC_R2_MONO_L_SFT 8 +#define RT5659_M_DAC_L1_MONO_R (0x1 << 7) +#define RT5659_M_DAC_L1_MONO_R_SFT 7 +#define RT5659_G_DAC_L1_MONO_R_MASK (0x1 << 6) +#define RT5659_G_DAC_L1_MONO_R_SFT 6 +#define RT5659_M_DAC_R1_MONO_R (0x1 << 5) +#define RT5659_M_DAC_R1_MONO_R_SFT 5 +#define RT5659_G_DAC_R1_MONO_R_MASK (0x1 << 4) +#define RT5659_G_DAC_R1_MONO_R_SFT 4 +#define RT5659_M_DAC_L2_MONO_R (0x1 << 3) +#define RT5659_M_DAC_L2_MONO_R_SFT 3 +#define RT5659_G_DAC_L2_MONO_R_MASK (0x1 << 2) +#define RT5659_G_DAC_L2_MONO_R_SFT 2 +#define RT5659_M_DAC_R2_MONO_R (0x1 << 1) +#define RT5659_M_DAC_R2_MONO_R_SFT 1 +#define RT5659_G_DAC_R2_MONO_R_MASK (0x1) +#define RT5659_G_DAC_R2_MONO_R_SFT 0 + +/* Digital Mixer Control (0x002c) */ +#define RT5659_M_DAC_MIX_L (0x1 << 7) +#define RT5659_M_DAC_MIX_L_SFT 7 +#define RT5659_DAC_MIX_L_MASK (0x1 << 6) +#define RT5659_DAC_MIX_L_SFT 6 +#define RT5659_M_DAC_MIX_R (0x1 << 5) +#define RT5659_M_DAC_MIX_R_SFT 5 +#define RT5659_DAC_MIX_R_MASK (0x1 << 4) +#define RT5659_DAC_MIX_R_SFT 4 + +/* Analog DAC Input Source Control (0x002d) */ +#define RT5659_A_DACL1_SEL (0x1 << 3) +#define RT5659_A_DACL1_SFT 3 +#define RT5659_A_DACR1_SEL (0x1 << 2) +#define RT5659_A_DACR1_SFT 2 +#define RT5659_A_DACL2_SEL (0x1 << 1) +#define RT5659_A_DACL2_SFT 1 +#define RT5659_A_DACR2_SEL (0x1 << 0) +#define RT5659_A_DACR2_SFT 0 + +/* Digital Interface Data Control (0x002f) */ +#define RT5659_IF2_ADC3_IN_MASK (0x3 << 14) +#define RT5659_IF2_ADC3_IN_SFT 14 +#define RT5659_IF2_ADC_IN_MASK (0x3 << 12) +#define RT5659_IF2_ADC_IN_SFT 12 +#define RT5659_IF2_DAC_SEL_MASK (0x3 << 10) +#define RT5659_IF2_DAC_SEL_SFT 10 +#define RT5659_IF2_ADC_SEL_MASK (0x3 << 8) +#define RT5659_IF2_ADC_SEL_SFT 8 +#define RT5659_IF3_DAC_SEL_MASK (0x3 << 6) +#define RT5659_IF3_DAC_SEL_SFT 6 +#define RT5659_IF3_ADC_SEL_MASK (0x3 << 4) +#define RT5659_IF3_ADC_SEL_SFT 4 +#define RT5659_IF3_ADC_IN_MASK (0x3 << 0) +#define RT5659_IF3_ADC_IN_SFT 0 + +/* PDM Output Control (0x0031) */ +#define RT5659_PDM1_L_MASK (0x1 << 15) +#define RT5659_PDM1_L_SFT 15 +#define RT5659_M_PDM1_L (0x1 << 14) +#define RT5659_M_PDM1_L_SFT 14 +#define RT5659_PDM1_R_MASK (0x1 << 13) +#define RT5659_PDM1_R_SFT 13 +#define RT5659_M_PDM1_R (0x1 << 12) +#define RT5659_M_PDM1_R_SFT 12 +#define RT5659_PDM2_BUSY (0x1 << 7) +#define RT5659_PDM1_BUSY (0x1 << 6) +#define RT5659_PDM_PATTERN (0x1 << 5) +#define RT5659_PDM_GAIN (0x1 << 4) +#define RT5659_PDM_DIV_MASK (0x3) + +/*S/PDIF Output Control (0x0036) */ +#define RT5659_SPDIF_SEL_MASK (0x3 << 0) +#define RT5659_SPDIF_SEL_SFT 0 + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5659_M_BST1_RM1_L (0x1 << 5) +#define RT5659_M_BST1_RM1_L_SFT 5 +#define RT5659_M_BST2_RM1_L (0x1 << 4) +#define RT5659_M_BST2_RM1_L_SFT 4 +#define RT5659_M_BST3_RM1_L (0x1 << 3) +#define RT5659_M_BST3_RM1_L_SFT 3 +#define RT5659_M_BST4_RM1_L (0x1 << 2) +#define RT5659_M_BST4_RM1_L_SFT 2 +#define RT5659_M_INL_RM1_L (0x1 << 1) +#define RT5659_M_INL_RM1_L_SFT 1 +#define RT5659_M_SPKVOLL_RM1_L (0x1) +#define RT5659_M_SPKVOLL_RM1_L_SFT 0 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5659_M_BST1_RM1_R (0x1 << 5) +#define RT5659_M_BST1_RM1_R_SFT 5 +#define RT5659_M_BST2_RM1_R (0x1 << 4) +#define RT5659_M_BST2_RM1_R_SFT 4 +#define RT5659_M_BST3_RM1_R (0x1 << 3) +#define RT5659_M_BST3_RM1_R_SFT 3 +#define RT5659_M_BST4_RM1_R (0x1 << 2) +#define RT5659_M_BST4_RM1_R_SFT 2 +#define RT5659_M_INR_RM1_R (0x1 << 1) +#define RT5659_M_INR_RM1_R_SFT 1 +#define RT5659_M_HPOVOLR_RM1_R (0x1) +#define RT5659_M_HPOVOLR_RM1_R_SFT 0 + +/* SPK Left Mixer Control (0x0046) */ +#define RT5659_M_BST3_SM_L (0x1 << 4) +#define RT5659_M_BST3_SM_L_SFT 4 +#define RT5659_M_IN_R_SM_L (0x1 << 3) +#define RT5659_M_IN_R_SM_L_SFT 3 +#define RT5659_M_IN_L_SM_L (0x1 << 2) +#define RT5659_M_IN_L_SM_L_SFT 2 +#define RT5659_M_BST1_SM_L (0x1 << 1) +#define RT5659_M_BST1_SM_L_SFT 1 +#define RT5659_M_DAC_L2_SM_L (0x1) +#define RT5659_M_DAC_L2_SM_L_SFT 0 + +/* SPK Right Mixer Control (0x0047) */ +#define RT5659_M_BST3_SM_R (0x1 << 4) +#define RT5659_M_BST3_SM_R_SFT 4 +#define RT5659_M_IN_R_SM_R (0x1 << 3) +#define RT5659_M_IN_R_SM_R_SFT 3 +#define RT5659_M_IN_L_SM_R (0x1 << 2) +#define RT5659_M_IN_L_SM_R_SFT 2 +#define RT5659_M_BST4_SM_R (0x1 << 1) +#define RT5659_M_BST4_SM_R_SFT 1 +#define RT5659_M_DAC_R2_SM_R (0x1) +#define RT5659_M_DAC_R2_SM_R_SFT 0 + +/* SPO Amp Input and Gain Control (0x0048) */ +#define RT5659_M_DAC_L2_SPKOMIX (0x1 << 13) +#define RT5659_M_DAC_L2_SPKOMIX_SFT 13 +#define RT5659_M_SPKVOLL_SPKOMIX (0x1 << 12) +#define RT5659_M_SPKVOLL_SPKOMIX_SFT 12 +#define RT5659_M_DAC_R2_SPKOMIX (0x1 << 9) +#define RT5659_M_DAC_R2_SPKOMIX_SFT 9 +#define RT5659_M_SPKVOLR_SPKOMIX (0x1 << 8) +#define RT5659_M_SPKVOLR_SPKOMIX_SFT 8 + +/* MONOMIX Input and Gain Control (0x004b) */ +#define RT5659_M_MONOVOL_MA (0x1 << 9) +#define RT5659_M_MONOVOL_MA_SFT 9 +#define RT5659_M_DAC_L2_MA (0x1 << 8) +#define RT5659_M_DAC_L2_MA_SFT 8 +#define RT5659_M_BST3_MM (0x1 << 4) +#define RT5659_M_BST3_MM_SFT 4 +#define RT5659_M_BST2_MM (0x1 << 3) +#define RT5659_M_BST2_MM_SFT 3 +#define RT5659_M_BST1_MM (0x1 << 2) +#define RT5659_M_BST1_MM_SFT 2 +#define RT5659_M_DAC_R2_MM (0x1 << 1) +#define RT5659_M_DAC_R2_MM_SFT 1 +#define RT5659_M_DAC_L2_MM (0x1) +#define RT5659_M_DAC_L2_MM_SFT 0 + +/* Output Left Mixer Control 1 (0x004d) */ +#define RT5659_G_BST3_OM_L_MASK (0x7 << 12) +#define RT5659_G_BST3_OM_L_SFT 12 +#define RT5659_G_BST2_OM_L_MASK (0x7 << 9) +#define RT5659_G_BST2_OM_L_SFT 9 +#define RT5659_G_BST1_OM_L_MASK (0x7 << 6) +#define RT5659_G_BST1_OM_L_SFT 6 +#define RT5659_G_IN_L_OM_L_MASK (0x7 << 3) +#define RT5659_G_IN_L_OM_L_SFT 3 +#define RT5659_G_DAC_L2_OM_L_MASK (0x7 << 0) +#define RT5659_G_DAC_L2_OM_L_SFT 0 + +/* Output Left Mixer Input Control (0x004e) */ +#define RT5659_M_BST3_OM_L (0x1 << 4) +#define RT5659_M_BST3_OM_L_SFT 4 +#define RT5659_M_BST2_OM_L (0x1 << 3) +#define RT5659_M_BST2_OM_L_SFT 3 +#define RT5659_M_BST1_OM_L (0x1 << 2) +#define RT5659_M_BST1_OM_L_SFT 2 +#define RT5659_M_IN_L_OM_L (0x1 << 1) +#define RT5659_M_IN_L_OM_L_SFT 1 +#define RT5659_M_DAC_L2_OM_L (0x1) +#define RT5659_M_DAC_L2_OM_L_SFT 0 + +/* Output Right Mixer Input Control (0x0050) */ +#define RT5659_M_BST4_OM_R (0x1 << 4) +#define RT5659_M_BST4_OM_R_SFT 4 +#define RT5659_M_BST3_OM_R (0x1 << 3) +#define RT5659_M_BST3_OM_R_SFT 3 +#define RT5659_M_BST2_OM_R (0x1 << 2) +#define RT5659_M_BST2_OM_R_SFT 2 +#define RT5659_M_IN_R_OM_R (0x1 << 1) +#define RT5659_M_IN_R_OM_R_SFT 1 +#define RT5659_M_DAC_R2_OM_R (0x1) +#define RT5659_M_DAC_R2_OM_R_SFT 0 + +/* LOUT Mixer Control (0x0052) */ +#define RT5659_M_DAC_L2_LM (0x1 << 15) +#define RT5659_M_DAC_L2_LM_SFT 15 +#define RT5659_M_DAC_R2_LM (0x1 << 14) +#define RT5659_M_DAC_R2_LM_SFT 14 +#define RT5659_M_OV_L_LM (0x1 << 13) +#define RT5659_M_OV_L_LM_SFT 13 +#define RT5659_M_OV_R_LM (0x1 << 12) +#define RT5659_M_OV_R_LM_SFT 12 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5659_PWR_I2S1 (0x1 << 15) +#define RT5659_PWR_I2S1_BIT 15 +#define RT5659_PWR_I2S2 (0x1 << 14) +#define RT5659_PWR_I2S2_BIT 14 +#define RT5659_PWR_I2S3 (0x1 << 13) +#define RT5659_PWR_I2S3_BIT 13 +#define RT5659_PWR_SPDIF (0x1 << 12) +#define RT5659_PWR_SPDIF_BIT 12 +#define RT5659_PWR_DAC_L1 (0x1 << 11) +#define RT5659_PWR_DAC_L1_BIT 11 +#define RT5659_PWR_DAC_R1 (0x1 << 10) +#define RT5659_PWR_DAC_R1_BIT 10 +#define RT5659_PWR_DAC_L2 (0x1 << 9) +#define RT5659_PWR_DAC_L2_BIT 9 +#define RT5659_PWR_DAC_R2 (0x1 << 8) +#define RT5659_PWR_DAC_R2_BIT 8 +#define RT5659_PWR_LDO (0x1 << 7) +#define RT5659_PWR_LDO_BIT 7 +#define RT5659_PWR_ADC_L1 (0x1 << 4) +#define RT5659_PWR_ADC_L1_BIT 4 +#define RT5659_PWR_ADC_R1 (0x1 << 3) +#define RT5659_PWR_ADC_R1_BIT 3 +#define RT5659_PWR_ADC_L2 (0x1 << 2) +#define RT5659_PWR_ADC_L2_BIT 4 +#define RT5659_PWR_ADC_R2 (0x1 << 1) +#define RT5659_PWR_ADC_R2_BIT 1 +#define RT5659_PWR_CLS_D (0x1) +#define RT5659_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5659_PWR_ADC_S1F (0x1 << 15) +#define RT5659_PWR_ADC_S1F_BIT 15 +#define RT5659_PWR_ADC_S2F (0x1 << 14) +#define RT5659_PWR_ADC_S2F_BIT 14 +#define RT5659_PWR_ADC_MF_L (0x1 << 13) +#define RT5659_PWR_ADC_MF_L_BIT 13 +#define RT5659_PWR_ADC_MF_R (0x1 << 12) +#define RT5659_PWR_ADC_MF_R_BIT 12 +#define RT5659_PWR_DAC_S1F (0x1 << 10) +#define RT5659_PWR_DAC_S1F_BIT 10 +#define RT5659_PWR_DAC_MF_L (0x1 << 9) +#define RT5659_PWR_DAC_MF_L_BIT 9 +#define RT5659_PWR_DAC_MF_R (0x1 << 8) +#define RT5659_PWR_DAC_MF_R_BIT 8 +#define RT5659_PWR_PDM1 (0x1 << 7) +#define RT5659_PWR_PDM1_BIT 7 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5659_PWR_VREF1 (0x1 << 15) +#define RT5659_PWR_VREF1_BIT 15 +#define RT5659_PWR_FV1 (0x1 << 14) +#define RT5659_PWR_FV1_BIT 14 +#define RT5659_PWR_VREF2 (0x1 << 13) +#define RT5659_PWR_VREF2_BIT 13 +#define RT5659_PWR_FV2 (0x1 << 12) +#define RT5659_PWR_FV2_BIT 12 +#define RT5659_PWR_VREF3 (0x1 << 11) +#define RT5659_PWR_VREF3_BIT 11 +#define RT5659_PWR_FV3 (0x1 << 10) +#define RT5659_PWR_FV3_BIT 10 +#define RT5659_PWR_MB (0x1 << 9) +#define RT5659_PWR_MB_BIT 9 +#define RT5659_PWR_LM (0x1 << 8) +#define RT5659_PWR_LM_BIT 8 +#define RT5659_PWR_BG (0x1 << 7) +#define RT5659_PWR_BG_BIT 7 +#define RT5659_PWR_MA (0x1 << 6) +#define RT5659_PWR_MA_BIT 6 +#define RT5659_PWR_HA_L (0x1 << 5) +#define RT5659_PWR_HA_L_BIT 5 +#define RT5659_PWR_HA_R (0x1 << 4) +#define RT5659_PWR_HA_R_BIT 4 + +/* Power Management for Analog 2 (0x0064) */ +#define RT5659_PWR_BST1 (0x1 << 15) +#define RT5659_PWR_BST1_BIT 15 +#define RT5659_PWR_BST2 (0x1 << 14) +#define RT5659_PWR_BST2_BIT 14 +#define RT5659_PWR_BST3 (0x1 << 13) +#define RT5659_PWR_BST3_BIT 13 +#define RT5659_PWR_BST4 (0x1 << 12) +#define RT5659_PWR_BST4_BIT 12 +#define RT5659_PWR_MB1 (0x1 << 11) +#define RT5659_PWR_MB1_BIT 11 +#define RT5659_PWR_MB2 (0x1 << 10) +#define RT5659_PWR_MB2_BIT 10 +#define RT5659_PWR_MB3 (0x1 << 9) +#define RT5659_PWR_MB3_BIT 9 +#define RT5659_PWR_BST1_P (0x1 << 6) +#define RT5659_PWR_BST1_P_BIT 6 +#define RT5659_PWR_BST2_P (0x1 << 5) +#define RT5659_PWR_BST2_P_BIT 5 +#define RT5659_PWR_BST3_P (0x1 << 4) +#define RT5659_PWR_BST3_P_BIT 4 +#define RT5659_PWR_BST4_P (0x1 << 3) +#define RT5659_PWR_BST4_P_BIT 3 +#define RT5659_PWR_JD1 (0x1 << 2) +#define RT5659_PWR_JD1_BIT 2 +#define RT5659_PWR_JD2 (0x1 << 1) +#define RT5659_PWR_JD2_BIT 1 +#define RT5659_PWR_JD3 (0x1) +#define RT5659_PWR_JD3_BIT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5659_PWR_BST_L (0x1 << 8) +#define RT5659_PWR_BST_L_BIT 8 +#define RT5659_PWR_BST_R (0x1 << 7) +#define RT5659_PWR_BST_R_BIT 7 +#define RT5659_PWR_PLL (0x1 << 6) +#define RT5659_PWR_PLL_BIT 6 +#define RT5659_PWR_LDO5 (0x1 << 5) +#define RT5659_PWR_LDO5_BIT 5 +#define RT5659_PWR_LDO4 (0x1 << 4) +#define RT5659_PWR_LDO4_BIT 4 +#define RT5659_PWR_LDO3 (0x1 << 3) +#define RT5659_PWR_LDO3_BIT 3 +#define RT5659_PWR_LDO2 (0x1 << 2) +#define RT5659_PWR_LDO2_BIT 2 +#define RT5659_PWR_SVD (0x1 << 1) +#define RT5659_PWR_SVD_BIT 1 + +/* Power Management for Mixer (0x0066) */ +#define RT5659_PWR_OM_L (0x1 << 15) +#define RT5659_PWR_OM_L_BIT 15 +#define RT5659_PWR_OM_R (0x1 << 14) +#define RT5659_PWR_OM_R_BIT 14 +#define RT5659_PWR_SM_L (0x1 << 13) +#define RT5659_PWR_SM_L_BIT 13 +#define RT5659_PWR_SM_R (0x1 << 12) +#define RT5659_PWR_SM_R_BIT 12 +#define RT5659_PWR_RM1_L (0x1 << 11) +#define RT5659_PWR_RM1_L_BIT 11 +#define RT5659_PWR_RM1_R (0x1 << 10) +#define RT5659_PWR_RM1_R_BIT 10 +#define RT5659_PWR_MM (0x1 << 8) +#define RT5659_PWR_MM_BIT 8 +#define RT5659_PWR_RM2_L (0x1 << 3) +#define RT5659_PWR_RM2_L_BIT 3 +#define RT5659_PWR_RM2_R (0x1 << 2) +#define RT5659_PWR_RM2_R_BIT 2 + +/* Power Management for Volume (0x0067) */ +#define RT5659_PWR_SV_L (0x1 << 15) +#define RT5659_PWR_SV_L_BIT 15 +#define RT5659_PWR_SV_R (0x1 << 14) +#define RT5659_PWR_SV_R_BIT 14 +#define RT5659_PWR_OV_L (0x1 << 13) +#define RT5659_PWR_OV_L_BIT 13 +#define RT5659_PWR_OV_R (0x1 << 12) +#define RT5659_PWR_OV_R_BIT 12 +#define RT5659_PWR_IN_L (0x1 << 9) +#define RT5659_PWR_IN_L_BIT 9 +#define RT5659_PWR_IN_R (0x1 << 8) +#define RT5659_PWR_IN_R_BIT 8 +#define RT5659_PWR_MV (0x1 << 7) +#define RT5659_PWR_MV_BIT 7 +#define RT5659_PWR_MIC_DET (0x1 << 5) +#define RT5659_PWR_MIC_DET_BIT 5 + +/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */ +#define RT5659_I2S_MS_MASK (0x1 << 15) +#define RT5659_I2S_MS_SFT 15 +#define RT5659_I2S_MS_M (0x0 << 15) +#define RT5659_I2S_MS_S (0x1 << 15) +#define RT5659_I2S_O_CP_MASK (0x3 << 12) +#define RT5659_I2S_O_CP_SFT 12 +#define RT5659_I2S_O_CP_OFF (0x0 << 12) +#define RT5659_I2S_O_CP_U_LAW (0x1 << 12) +#define RT5659_I2S_O_CP_A_LAW (0x2 << 12) +#define RT5659_I2S_I_CP_MASK (0x3 << 10) +#define RT5659_I2S_I_CP_SFT 10 +#define RT5659_I2S_I_CP_OFF (0x0 << 10) +#define RT5659_I2S_I_CP_U_LAW (0x1 << 10) +#define RT5659_I2S_I_CP_A_LAW (0x2 << 10) +#define RT5659_I2S_BP_MASK (0x1 << 8) +#define RT5659_I2S_BP_SFT 8 +#define RT5659_I2S_BP_NOR (0x0 << 8) +#define RT5659_I2S_BP_INV (0x1 << 8) +#define RT5659_I2S_DL_MASK (0x3 << 4) +#define RT5659_I2S_DL_SFT 4 +#define RT5659_I2S_DL_16 (0x0 << 4) +#define RT5659_I2S_DL_20 (0x1 << 4) +#define RT5659_I2S_DL_24 (0x2 << 4) +#define RT5659_I2S_DL_8 (0x3 << 4) +#define RT5659_I2S_DF_MASK (0x7) +#define RT5659_I2S_DF_SFT 0 +#define RT5659_I2S_DF_I2S (0x0) +#define RT5659_I2S_DF_LEFT (0x1) +#define RT5659_I2S_DF_PCM_A (0x2) +#define RT5659_I2S_DF_PCM_B (0x3) +#define RT5659_I2S_DF_PCM_A_N (0x6) +#define RT5659_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5659_I2S_PD1_MASK (0x7 << 12) +#define RT5659_I2S_PD1_SFT 12 +#define RT5659_I2S_PD1_1 (0x0 << 12) +#define RT5659_I2S_PD1_2 (0x1 << 12) +#define RT5659_I2S_PD1_3 (0x2 << 12) +#define RT5659_I2S_PD1_4 (0x3 << 12) +#define RT5659_I2S_PD1_6 (0x4 << 12) +#define RT5659_I2S_PD1_8 (0x5 << 12) +#define RT5659_I2S_PD1_12 (0x6 << 12) +#define RT5659_I2S_PD1_16 (0x7 << 12) +#define RT5659_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5659_I2S_BCLK_MS2_SFT 11 +#define RT5659_I2S_BCLK_MS2_32 (0x0 << 11) +#define RT5659_I2S_BCLK_MS2_64 (0x1 << 11) +#define RT5659_I2S_PD2_MASK (0x7 << 8) +#define RT5659_I2S_PD2_SFT 8 +#define RT5659_I2S_PD2_1 (0x0 << 8) +#define RT5659_I2S_PD2_2 (0x1 << 8) +#define RT5659_I2S_PD2_3 (0x2 << 8) +#define RT5659_I2S_PD2_4 (0x3 << 8) +#define RT5659_I2S_PD2_6 (0x4 << 8) +#define RT5659_I2S_PD2_8 (0x5 << 8) +#define RT5659_I2S_PD2_12 (0x6 << 8) +#define RT5659_I2S_PD2_16 (0x7 << 8) +#define RT5659_I2S_BCLK_MS3_MASK (0x1 << 7) +#define RT5659_I2S_BCLK_MS3_SFT 7 +#define RT5659_I2S_BCLK_MS3_32 (0x0 << 7) +#define RT5659_I2S_BCLK_MS3_64 (0x1 << 7) +#define RT5659_I2S_PD3_MASK (0x7 << 4) +#define RT5659_I2S_PD3_SFT 4 +#define RT5659_I2S_PD3_1 (0x0 << 4) +#define RT5659_I2S_PD3_2 (0x1 << 4) +#define RT5659_I2S_PD3_3 (0x2 << 4) +#define RT5659_I2S_PD3_4 (0x3 << 4) +#define RT5659_I2S_PD3_6 (0x4 << 4) +#define RT5659_I2S_PD3_8 (0x5 << 4) +#define RT5659_I2S_PD3_12 (0x6 << 4) +#define RT5659_I2S_PD3_16 (0x7 << 4) +#define RT5659_DAC_OSR_MASK (0x3 << 2) +#define RT5659_DAC_OSR_SFT 2 +#define RT5659_DAC_OSR_128 (0x0 << 2) +#define RT5659_DAC_OSR_64 (0x1 << 2) +#define RT5659_DAC_OSR_32 (0x2 << 2) +#define RT5659_DAC_OSR_16 (0x3 << 2) +#define RT5659_ADC_OSR_MASK (0x3) +#define RT5659_ADC_OSR_SFT 0 +#define RT5659_ADC_OSR_128 (0x0) +#define RT5659_ADC_OSR_64 (0x1) +#define RT5659_ADC_OSR_32 (0x2) +#define RT5659_ADC_OSR_16 (0x3) + +/* Digital Microphone Control (0x0075) */ +#define RT5659_DMIC_1_EN_MASK (0x1 << 15) +#define RT5659_DMIC_1_EN_SFT 15 +#define RT5659_DMIC_1_DIS (0x0 << 15) +#define RT5659_DMIC_1_EN (0x1 << 15) +#define RT5659_DMIC_2_EN_MASK (0x1 << 14) +#define RT5659_DMIC_2_EN_SFT 14 +#define RT5659_DMIC_2_DIS (0x0 << 14) +#define RT5659_DMIC_2_EN (0x1 << 14) +#define RT5659_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5659_DMIC_1L_LH_SFT 13 +#define RT5659_DMIC_1L_LH_RISING (0x0 << 13) +#define RT5659_DMIC_1L_LH_FALLING (0x1 << 13) +#define RT5659_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5659_DMIC_1R_LH_SFT 12 +#define RT5659_DMIC_1R_LH_RISING (0x0 << 12) +#define RT5659_DMIC_1R_LH_FALLING (0x1 << 12) +#define RT5659_DMIC_2_DP_MASK (0x3 << 10) +#define RT5659_DMIC_2_DP_SFT 10 +#define RT5659_DMIC_2_DP_GPIO6 (0x0 << 10) +#define RT5659_DMIC_2_DP_GPIO10 (0x1 << 10) +#define RT5659_DMIC_2_DP_GPIO12 (0x2 << 10) +#define RT5659_DMIC_2_DP_IN2P (0x3 << 10) +#define RT5659_DMIC_CLK_MASK (0x7 << 5) +#define RT5659_DMIC_CLK_SFT 5 +#define RT5659_DMIC_1_DP_MASK (0x3 << 0) +#define RT5659_DMIC_1_DP_SFT 0 +#define RT5659_DMIC_1_DP_GPIO5 (0x0 << 0) +#define RT5659_DMIC_1_DP_GPIO9 (0x1 << 0) +#define RT5659_DMIC_1_DP_GPIO11 (0x2 << 0) +#define RT5659_DMIC_1_DP_IN2N (0x3 << 0) + +/* TDM control 1 (0x0078)*/ +#define RT5659_DS_ADC_SLOT01_SFT 14 +#define RT5659_DS_ADC_SLOT23_SFT 12 +#define RT5659_DS_ADC_SLOT45_SFT 10 +#define RT5659_DS_ADC_SLOT67_SFT 8 +#define RT5659_ADCDAT_SRC_MASK 0x1f +#define RT5659_ADCDAT_SRC_SFT 0 + +/* Global Clock Control (0x0080) */ +#define RT5659_SCLK_SRC_MASK (0x3 << 14) +#define RT5659_SCLK_SRC_SFT 14 +#define RT5659_SCLK_SRC_MCLK (0x0 << 14) +#define RT5659_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5659_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5659_PLL1_SRC_MASK (0x7 << 11) +#define RT5659_PLL1_SRC_SFT 11 +#define RT5659_PLL1_SRC_MCLK (0x0 << 11) +#define RT5659_PLL1_SRC_BCLK1 (0x1 << 11) +#define RT5659_PLL1_SRC_BCLK2 (0x2 << 11) +#define RT5659_PLL1_SRC_BCLK3 (0x3 << 11) +#define RT5659_PLL1_PD_MASK (0x1 << 3) +#define RT5659_PLL1_PD_SFT 3 +#define RT5659_PLL1_PD_1 (0x0 << 3) +#define RT5659_PLL1_PD_2 (0x1 << 3) + +#define RT5659_PLL_INP_MAX 40000000 +#define RT5659_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5659_PLL_N_MAX 0x001ff +#define RT5659_PLL_N_MASK (RT5659_PLL_N_MAX << 7) +#define RT5659_PLL_N_SFT 7 +#define RT5659_PLL_K_MAX 0x001f +#define RT5659_PLL_K_MASK (RT5659_PLL_K_MAX) +#define RT5659_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5659_PLL_M_MAX 0x00f +#define RT5659_PLL_M_MASK (RT5659_PLL_M_MAX << 12) +#define RT5659_PLL_M_SFT 12 +#define RT5659_PLL_M_BP (0x1 << 11) +#define RT5659_PLL_M_BP_SFT 11 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5659_I2S3_ASRC_MASK (0x1 << 13) +#define RT5659_I2S3_ASRC_SFT 13 +#define RT5659_I2S2_ASRC_MASK (0x1 << 12) +#define RT5659_I2S2_ASRC_SFT 12 +#define RT5659_I2S1_ASRC_MASK (0x1 << 11) +#define RT5659_I2S1_ASRC_SFT 11 +#define RT5659_DAC_STO_ASRC_MASK (0x1 << 10) +#define RT5659_DAC_STO_ASRC_SFT 10 +#define RT5659_DAC_MONO_L_ASRC_MASK (0x1 << 9) +#define RT5659_DAC_MONO_L_ASRC_SFT 9 +#define RT5659_DAC_MONO_R_ASRC_MASK (0x1 << 8) +#define RT5659_DAC_MONO_R_ASRC_SFT 8 +#define RT5659_DMIC_STO1_ASRC_MASK (0x1 << 7) +#define RT5659_DMIC_STO1_ASRC_SFT 7 +#define RT5659_DMIC_MONO_L_ASRC_MASK (0x1 << 5) +#define RT5659_DMIC_MONO_L_ASRC_SFT 5 +#define RT5659_DMIC_MONO_R_ASRC_MASK (0x1 << 4) +#define RT5659_DMIC_MONO_R_ASRC_SFT 4 +#define RT5659_ADC_STO1_ASRC_MASK (0x1 << 3) +#define RT5659_ADC_STO1_ASRC_SFT 3 +#define RT5659_ADC_MONO_L_ASRC_MASK (0x1 << 1) +#define RT5659_ADC_MONO_L_ASRC_SFT 1 +#define RT5659_ADC_MONO_R_ASRC_MASK (0x1) +#define RT5659_ADC_MONO_R_ASRC_SFT 0 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5659_DA_STO_T_MASK (0x7 << 12) +#define RT5659_DA_STO_T_SFT 12 +#define RT5659_DA_MONO_L_T_MASK (0x7 << 8) +#define RT5659_DA_MONO_L_T_SFT 8 +#define RT5659_DA_MONO_R_T_MASK (0x7 << 4) +#define RT5659_DA_MONO_R_T_SFT 4 +#define RT5659_AD_STO1_T_MASK (0x7) +#define RT5659_AD_STO1_T_SFT 0 + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5659_AD_STO2_T_MASK (0x7 << 8) +#define RT5659_AD_STO2_T_SFT 8 +#define RT5659_AD_MONO_L_T_MASK (0x7 << 4) +#define RT5659_AD_MONO_L_T_SFT 4 +#define RT5659_AD_MONO_R_T_MASK (0x7) +#define RT5659_AD_MONO_R_T_SFT 0 + +/* ASRC Control 4 (0x0086) */ +#define RT5659_I2S1_RATE_MASK (0xf << 12) +#define RT5659_I2S1_RATE_SFT 12 +#define RT5659_I2S2_RATE_MASK (0xf << 8) +#define RT5659_I2S2_RATE_SFT 8 +#define RT5659_I2S3_RATE_MASK (0xf << 4) +#define RT5659_I2S3_RATE_SFT 4 + +/* Depop Mode Control 1 (0x8e) */ +#define RT5659_SMT_TRIG_MASK (0x1 << 15) +#define RT5659_SMT_TRIG_SFT 15 +#define RT5659_SMT_TRIG_DIS (0x0 << 15) +#define RT5659_SMT_TRIG_EN (0x1 << 15) +#define RT5659_HP_L_SMT_MASK (0x1 << 9) +#define RT5659_HP_L_SMT_SFT 9 +#define RT5659_HP_L_SMT_DIS (0x0 << 9) +#define RT5659_HP_L_SMT_EN (0x1 << 9) +#define RT5659_HP_R_SMT_MASK (0x1 << 8) +#define RT5659_HP_R_SMT_SFT 8 +#define RT5659_HP_R_SMT_DIS (0x0 << 8) +#define RT5659_HP_R_SMT_EN (0x1 << 8) +#define RT5659_HP_CD_PD_MASK (0x1 << 7) +#define RT5659_HP_CD_PD_SFT 7 +#define RT5659_HP_CD_PD_DIS (0x0 << 7) +#define RT5659_HP_CD_PD_EN (0x1 << 7) +#define RT5659_RSTN_MASK (0x1 << 6) +#define RT5659_RSTN_SFT 6 +#define RT5659_RSTN_DIS (0x0 << 6) +#define RT5659_RSTN_EN (0x1 << 6) +#define RT5659_RSTP_MASK (0x1 << 5) +#define RT5659_RSTP_SFT 5 +#define RT5659_RSTP_DIS (0x0 << 5) +#define RT5659_RSTP_EN (0x1 << 5) +#define RT5659_HP_CO_MASK (0x1 << 4) +#define RT5659_HP_CO_SFT 4 +#define RT5659_HP_CO_DIS (0x0 << 4) +#define RT5659_HP_CO_EN (0x1 << 4) +#define RT5659_HP_CP_MASK (0x1 << 3) +#define RT5659_HP_CP_SFT 3 +#define RT5659_HP_CP_PD (0x0 << 3) +#define RT5659_HP_CP_PU (0x1 << 3) +#define RT5659_HP_SG_MASK (0x1 << 2) +#define RT5659_HP_SG_SFT 2 +#define RT5659_HP_SG_DIS (0x0 << 2) +#define RT5659_HP_SG_EN (0x1 << 2) +#define RT5659_HP_DP_MASK (0x1 << 1) +#define RT5659_HP_DP_SFT 1 +#define RT5659_HP_DP_PD (0x0 << 1) +#define RT5659_HP_DP_PU (0x1 << 1) +#define RT5659_HP_CB_MASK (0x1) +#define RT5659_HP_CB_SFT 0 +#define RT5659_HP_CB_PD (0x0) +#define RT5659_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5659_DEPOP_MASK (0x1 << 13) +#define RT5659_DEPOP_SFT 13 +#define RT5659_DEPOP_AUTO (0x0 << 13) +#define RT5659_DEPOP_MAN (0x1 << 13) +#define RT5659_RAMP_MASK (0x1 << 12) +#define RT5659_RAMP_SFT 12 +#define RT5659_RAMP_DIS (0x0 << 12) +#define RT5659_RAMP_EN (0x1 << 12) +#define RT5659_BPS_MASK (0x1 << 11) +#define RT5659_BPS_SFT 11 +#define RT5659_BPS_DIS (0x0 << 11) +#define RT5659_BPS_EN (0x1 << 11) +#define RT5659_FAST_UPDN_MASK (0x1 << 10) +#define RT5659_FAST_UPDN_SFT 10 +#define RT5659_FAST_UPDN_DIS (0x0 << 10) +#define RT5659_FAST_UPDN_EN (0x1 << 10) +#define RT5659_MRES_MASK (0x3 << 8) +#define RT5659_MRES_SFT 8 +#define RT5659_MRES_15MO (0x0 << 8) +#define RT5659_MRES_25MO (0x1 << 8) +#define RT5659_MRES_35MO (0x2 << 8) +#define RT5659_MRES_45MO (0x3 << 8) +#define RT5659_VLO_MASK (0x1 << 7) +#define RT5659_VLO_SFT 7 +#define RT5659_VLO_3V (0x0 << 7) +#define RT5659_VLO_32V (0x1 << 7) +#define RT5659_DIG_DP_MASK (0x1 << 6) +#define RT5659_DIG_DP_SFT 6 +#define RT5659_DIG_DP_DIS (0x0 << 6) +#define RT5659_DIG_DP_EN (0x1 << 6) +#define RT5659_DP_TH_MASK (0x3 << 4) +#define RT5659_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5659_CP_SYS_MASK (0x7 << 12) +#define RT5659_CP_SYS_SFT 12 +#define RT5659_CP_FQ1_MASK (0x7 << 8) +#define RT5659_CP_FQ1_SFT 8 +#define RT5659_CP_FQ2_MASK (0x7 << 4) +#define RT5659_CP_FQ2_SFT 4 +#define RT5659_CP_FQ3_MASK (0x7) +#define RT5659_CP_FQ3_SFT 0 +#define RT5659_CP_FQ_1_5_KHZ 0 +#define RT5659_CP_FQ_3_KHZ 1 +#define RT5659_CP_FQ_6_KHZ 2 +#define RT5659_CP_FQ_12_KHZ 3 +#define RT5659_CP_FQ_24_KHZ 4 +#define RT5659_CP_FQ_48_KHZ 5 +#define RT5659_CP_FQ_96_KHZ 6 +#define RT5659_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5659_OSW_L_MASK (0x1 << 11) +#define RT5659_OSW_L_SFT 11 +#define RT5659_OSW_L_DIS (0x0 << 11) +#define RT5659_OSW_L_EN (0x1 << 11) +#define RT5659_OSW_R_MASK (0x1 << 10) +#define RT5659_OSW_R_SFT 10 +#define RT5659_OSW_R_DIS (0x0 << 10) +#define RT5659_OSW_R_EN (0x1 << 10) +#define RT5659_PM_HP_MASK (0x3 << 8) +#define RT5659_PM_HP_SFT 8 +#define RT5659_PM_HP_LV (0x0 << 8) +#define RT5659_PM_HP_MV (0x1 << 8) +#define RT5659_PM_HP_HV (0x2 << 8) +#define RT5659_IB_HP_MASK (0x3 << 6) +#define RT5659_IB_HP_SFT 6 +#define RT5659_IB_HP_125IL (0x0 << 6) +#define RT5659_IB_HP_25IL (0x1 << 6) +#define RT5659_IB_HP_5IL (0x2 << 6) +#define RT5659_IB_HP_1IL (0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5659_PVDD_DET_MASK (0x1 << 15) +#define RT5659_PVDD_DET_SFT 15 +#define RT5659_PVDD_DET_DIS (0x0 << 15) +#define RT5659_PVDD_DET_EN (0x1 << 15) +#define RT5659_SPK_AG_MASK (0x1 << 14) +#define RT5659_SPK_AG_SFT 14 +#define RT5659_SPK_AG_DIS (0x0 << 14) +#define RT5659_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5659_MIC1_BS_MASK (0x1 << 15) +#define RT5659_MIC1_BS_SFT 15 +#define RT5659_MIC1_BS_9AV (0x0 << 15) +#define RT5659_MIC1_BS_75AV (0x1 << 15) +#define RT5659_MIC2_BS_MASK (0x1 << 14) +#define RT5659_MIC2_BS_SFT 14 +#define RT5659_MIC2_BS_9AV (0x0 << 14) +#define RT5659_MIC2_BS_75AV (0x1 << 14) +#define RT5659_MIC1_CLK_MASK (0x1 << 13) +#define RT5659_MIC1_CLK_SFT 13 +#define RT5659_MIC1_CLK_DIS (0x0 << 13) +#define RT5659_MIC1_CLK_EN (0x1 << 13) +#define RT5659_MIC2_CLK_MASK (0x1 << 12) +#define RT5659_MIC2_CLK_SFT 12 +#define RT5659_MIC2_CLK_DIS (0x0 << 12) +#define RT5659_MIC2_CLK_EN (0x1 << 12) +#define RT5659_MIC1_OVCD_MASK (0x1 << 11) +#define RT5659_MIC1_OVCD_SFT 11 +#define RT5659_MIC1_OVCD_DIS (0x0 << 11) +#define RT5659_MIC1_OVCD_EN (0x1 << 11) +#define RT5659_MIC1_OVTH_MASK (0x3 << 9) +#define RT5659_MIC1_OVTH_SFT 9 +#define RT5659_MIC1_OVTH_600UA (0x0 << 9) +#define RT5659_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5659_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5659_MIC2_OVCD_MASK (0x1 << 8) +#define RT5659_MIC2_OVCD_SFT 8 +#define RT5659_MIC2_OVCD_DIS (0x0 << 8) +#define RT5659_MIC2_OVCD_EN (0x1 << 8) +#define RT5659_MIC2_OVTH_MASK (0x3 << 6) +#define RT5659_MIC2_OVTH_SFT 6 +#define RT5659_MIC2_OVTH_600UA (0x0 << 6) +#define RT5659_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5659_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5659_PWR_MB_MASK (0x1 << 5) +#define RT5659_PWR_MB_SFT 5 +#define RT5659_PWR_MB_PD (0x0 << 5) +#define RT5659_PWR_MB_PU (0x1 << 5) +#define RT5659_PWR_CLK25M_MASK (0x1 << 4) +#define RT5659_PWR_CLK25M_SFT 4 +#define RT5659_PWR_CLK25M_PD (0x0 << 4) +#define RT5659_PWR_CLK25M_PU (0x1 << 4) + +/* REC Mixer 2 Left Control 2 (0x009c) */ +#define RT5659_M_BST1_RM2_L (0x1 << 5) +#define RT5659_M_BST1_RM2_L_SFT 5 +#define RT5659_M_BST2_RM2_L (0x1 << 4) +#define RT5659_M_BST2_RM2_L_SFT 4 +#define RT5659_M_BST3_RM2_L (0x1 << 3) +#define RT5659_M_BST3_RM2_L_SFT 3 +#define RT5659_M_BST4_RM2_L (0x1 << 2) +#define RT5659_M_BST4_RM2_L_SFT 2 +#define RT5659_M_OUTVOLL_RM2_L (0x1 << 1) +#define RT5659_M_OUTVOLL_RM2_L_SFT 1 +#define RT5659_M_SPKVOL_RM2_L (0x1) +#define RT5659_M_SPKVOL_RM2_L_SFT 0 + +/* REC Mixer 2 Right Control 2 (0x009e) */ +#define RT5659_M_BST1_RM2_R (0x1 << 5) +#define RT5659_M_BST1_RM2_R_SFT 5 +#define RT5659_M_BST2_RM2_R (0x1 << 4) +#define RT5659_M_BST2_RM2_R_SFT 4 +#define RT5659_M_BST3_RM2_R (0x1 << 3) +#define RT5659_M_BST3_RM2_R_SFT 3 +#define RT5659_M_BST4_RM2_R (0x1 << 2) +#define RT5659_M_BST4_RM2_R_SFT 2 +#define RT5659_M_OUTVOLR_RM2_R (0x1 << 1) +#define RT5659_M_OUTVOLR_RM2_R_SFT 1 +#define RT5659_M_MONOVOL_RM2_R (0x1) +#define RT5659_M_MONOVOL_RM2_R_SFT 0 + +/* Class D Output Control (0x00a0) */ +#define RT5659_POW_CLSD_DB_MASK (0x1 << 9) +#define RT5659_POW_CLSD_DB_EN (0x1 << 9) +#define RT5659_POW_CLSD_DB_DIS (0x0 << 9) + +/* EQ Control 1 (0x00b0) */ +#define RT5659_EQ_SRC_DAC (0x0 << 15) +#define RT5659_EQ_SRC_ADC (0x1 << 15) +#define RT5659_EQ_UPD (0x1 << 14) +#define RT5659_EQ_UPD_BIT 14 +#define RT5659_EQ_CD_MASK (0x1 << 13) +#define RT5659_EQ_CD_SFT 13 +#define RT5659_EQ_CD_DIS (0x0 << 13) +#define RT5659_EQ_CD_EN (0x1 << 13) +#define RT5659_EQ_DITH_MASK (0x3 << 8) +#define RT5659_EQ_DITH_SFT 8 +#define RT5659_EQ_DITH_NOR (0x0 << 8) +#define RT5659_EQ_DITH_LSB (0x1 << 8) +#define RT5659_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5659_EQ_DITH_LSB_2 (0x3 << 8) + +/* IRQ Control 1 (0x00b7) */ +#define RT5659_JD1_1_EN_MASK (0x1 << 15) +#define RT5659_JD1_1_EN_SFT 15 +#define RT5659_JD1_1_DIS (0x0 << 15) +#define RT5659_JD1_1_EN (0x1 << 15) +#define RT5659_JD1_2_EN_MASK (0x1 << 12) +#define RT5659_JD1_2_EN_SFT 12 +#define RT5659_JD1_2_DIS (0x0 << 12) +#define RT5659_JD1_2_EN (0x1 << 12) +#define RT5659_IL_IRQ_MASK (0x1 << 3) +#define RT5659_IL_IRQ_DIS (0x0 << 3) +#define RT5659_IL_IRQ_EN (0x1 << 3) + +/* IRQ Control 5 (0x00ba) */ +#define RT5659_IRQ_JD_EN (0x1 << 3) +#define RT5659_IRQ_JD_EN_SFT 3 + +/* GPIO Control 1 (0x00c0) */ +#define RT5659_GP1_PIN_MASK (0x1 << 15) +#define RT5659_GP1_PIN_SFT 15 +#define RT5659_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5659_GP1_PIN_IRQ (0x1 << 15) +#define RT5659_GP2_PIN_MASK (0x1 << 14) +#define RT5659_GP2_PIN_SFT 14 +#define RT5659_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5659_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5659_GP3_PIN_MASK (0x1 << 13) +#define RT5659_GP3_PIN_SFT 13 +#define RT5659_GP3_PIN_GPIO3 (0x0 << 13) +#define RT5659_GP3_PIN_PDM_SCL (0x1 << 13) +#define RT5659_GP4_PIN_MASK (0x1 << 12) +#define RT5659_GP4_PIN_SFT 12 +#define RT5659_GP4_PIN_GPIO4 (0x0 << 12) +#define RT5659_GP4_PIN_PDM_SDA (0x1 << 12) +#define RT5659_GP5_PIN_MASK (0x1 << 11) +#define RT5659_GP5_PIN_SFT 11 +#define RT5659_GP5_PIN_GPIO5 (0x0 << 11) +#define RT5659_GP5_PIN_DMIC1_SDA (0x1 << 11) +#define RT5659_GP6_PIN_MASK (0x1 << 10) +#define RT5659_GP6_PIN_SFT 10 +#define RT5659_GP6_PIN_GPIO6 (0x0 << 10) +#define RT5659_GP6_PIN_DMIC2_SDA (0x1 << 10) +#define RT5659_GP7_PIN_MASK (0x1 << 9) +#define RT5659_GP7_PIN_SFT 9 +#define RT5659_GP7_PIN_GPIO7 (0x0 << 9) +#define RT5659_GP7_PIN_PDM_SCL (0x1 << 9) +#define RT5659_GP8_PIN_MASK (0x1 << 8) +#define RT5659_GP8_PIN_SFT 8 +#define RT5659_GP8_PIN_GPIO8 (0x0 << 8) +#define RT5659_GP8_PIN_PDM_SDA (0x1 << 8) +#define RT5659_GP9_PIN_MASK (0x1 << 7) +#define RT5659_GP9_PIN_SFT 7 +#define RT5659_GP9_PIN_GPIO9 (0x0 << 7) +#define RT5659_GP9_PIN_DMIC1_SDA (0x1 << 7) +#define RT5659_GP10_PIN_MASK (0x1 << 6) +#define RT5659_GP10_PIN_SFT 6 +#define RT5659_GP10_PIN_GPIO10 (0x0 << 6) +#define RT5659_GP10_PIN_DMIC2_SDA (0x1 << 6) +#define RT5659_GP11_PIN_MASK (0x1 << 5) +#define RT5659_GP11_PIN_SFT 5 +#define RT5659_GP11_PIN_GPIO11 (0x0 << 5) +#define RT5659_GP11_PIN_DMIC1_SDA (0x1 << 5) +#define RT5659_GP12_PIN_MASK (0x1 << 4) +#define RT5659_GP12_PIN_SFT 4 +#define RT5659_GP12_PIN_GPIO12 (0x0 << 4) +#define RT5659_GP12_PIN_DMIC2_SDA (0x1 << 4) +#define RT5659_GP13_PIN_MASK (0x3 << 2) +#define RT5659_GP13_PIN_SFT 2 +#define RT5659_GP13_PIN_GPIO13 (0x0 << 2) +#define RT5659_GP13_PIN_SPDIF_SDA (0x1 << 2) +#define RT5659_GP13_PIN_DMIC2_SCL (0x2 << 2) +#define RT5659_GP13_PIN_PDM_SCL (0x3 << 2) +#define RT5659_GP15_PIN_MASK (0x3) +#define RT5659_GP15_PIN_SFT 0 +#define RT5659_GP15_PIN_GPIO15 (0x0) +#define RT5659_GP15_PIN_DMIC3_SCL (0x1) +#define RT5659_GP15_PIN_PDM_SDA (0x2) + +/* GPIO Control 2 (0x00c1)*/ +#define RT5659_GP1_PF_IN (0x0 << 2) +#define RT5659_GP1_PF_OUT (0x1 << 2) +#define RT5659_GP1_PF_MASK (0x1 << 2) +#define RT5659_GP1_PF_SFT 2 + +/* GPIO Control 3 (0x00c2) */ +#define RT5659_I2S2_PIN_MASK (0x1 << 15) +#define RT5659_I2S2_PIN_SFT 15 +#define RT5659_I2S2_PIN_I2S (0x0 << 15) +#define RT5659_I2S2_PIN_GPIO (0x1 << 15) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5659_SV_MASK (0x1 << 15) +#define RT5659_SV_SFT 15 +#define RT5659_SV_DIS (0x0 << 15) +#define RT5659_SV_EN (0x1 << 15) +#define RT5659_OUT_SV_MASK (0x1 << 13) +#define RT5659_OUT_SV_SFT 13 +#define RT5659_OUT_SV_DIS (0x0 << 13) +#define RT5659_OUT_SV_EN (0x1 << 13) +#define RT5659_HP_SV_MASK (0x1 << 12) +#define RT5659_HP_SV_SFT 12 +#define RT5659_HP_SV_DIS (0x0 << 12) +#define RT5659_HP_SV_EN (0x1 << 12) +#define RT5659_ZCD_DIG_MASK (0x1 << 11) +#define RT5659_ZCD_DIG_SFT 11 +#define RT5659_ZCD_DIG_DIS (0x0 << 11) +#define RT5659_ZCD_DIG_EN (0x1 << 11) +#define RT5659_ZCD_MASK (0x1 << 10) +#define RT5659_ZCD_SFT 10 +#define RT5659_ZCD_PD (0x0 << 10) +#define RT5659_ZCD_PU (0x1 << 10) +#define RT5659_SV_DLY_MASK (0xf) +#define RT5659_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0x00da) */ +#define RT5659_ZCD_HP_MASK (0x1 << 15) +#define RT5659_ZCD_HP_SFT 15 +#define RT5659_ZCD_HP_DIS (0x0 << 15) +#define RT5659_ZCD_HP_EN (0x1 << 15) + +/* 4 Button Inline Command Control 2 (0x00e0) */ +#define RT5659_4BTN_IL_MASK (0x1 << 15) +#define RT5659_4BTN_IL_EN (0x1 << 15) +#define RT5659_4BTN_IL_DIS (0x0 << 15) + +/* Analog JD Control 1 (0x00f0) */ +#define RT5659_JD1_MODE_MASK (0x3 << 0) +#define RT5659_JD1_MODE_0 (0x0 << 0) +#define RT5659_JD1_MODE_1 (0x1 << 0) +#define RT5659_JD1_MODE_2 (0x2 << 0) + +/* Jack Detect Control 3 (0x00f8) */ +#define RT5659_JD_TRI_HPO_SEL_MASK (0x7) +#define RT5659_JD_TRI_HPO_SEL_SFT (0) +#define RT5659_JD_HPO_GPIO_JD1 (0x0) +#define RT5659_JD_HPO_JD1_1 (0x1) +#define RT5659_JD_HPO_JD1_2 (0x2) +#define RT5659_JD_HPO_JD2 (0x3) +#define RT5659_JD_HPO_GPIO_JD2 (0x4) +#define RT5659_JD_HPO_JD3 (0x5) +#define RT5659_JD_HPO_JD_D (0x6) + +/* Digital Misc Control (0x00fa) */ +#define RT5659_AM_MASK (0x1 << 7) +#define RT5659_AM_EN (0x1 << 7) +#define RT5659_AM_DIS (0x1 << 7) +#define RT5659_DIG_GATE_CTRL 0x1 +#define RT5659_DIG_GATE_CTRL_SFT (0) + +/* Chopper and Clock control for ADC (0x011c)*/ +#define RT5659_M_RF_DIG_MASK (0x1 << 12) +#define RT5659_M_RF_DIG_SFT 12 +#define RT5659_M_RI_DIG (0x1 << 11) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5659_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5659_CKXEN_DAC1_SFT 13 +#define RT5659_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5659_CKGEN_DAC1_SFT 12 +#define RT5659_CKXEN_DAC2_MASK (0x1 << 5) +#define RT5659_CKXEN_DAC2_SFT 5 +#define RT5659_CKGEN_DAC2_MASK (0x1 << 4) +#define RT5659_CKGEN_DAC2_SFT 4 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5659_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5659_CKXEN_ADCC_SFT 13 +#define RT5659_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5659_CKGEN_ADCC_SFT 12 + +/* Test Mode Control 1 (0x0145) */ +#define RT5659_AD2DA_LB_MASK (0x1 << 9) +#define RT5659_AD2DA_LB_SFT 9 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5659_NG2_EN_MASK (0x1 << 15) +#define RT5659_NG2_EN (0x1 << 15) +#define RT5659_NG2_DIS (0x0 << 15) + +/* System Clock Source */ +enum { + RT5659_SCLK_S_MCLK, + RT5659_SCLK_S_PLL1, + RT5659_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5659_PLL1_S_MCLK, + RT5659_PLL1_S_BCLK1, + RT5659_PLL1_S_BCLK2, + RT5659_PLL1_S_BCLK3, + RT5659_PLL1_S_BCLK4, +}; + +enum { + RT5659_AIF1, + RT5659_AIF2, + RT5659_AIF3, + RT5659_AIF4, + RT5659_AIFS, +}; + +struct rt5659_pll_code { + bool m_bp; + int m_code; + int n_code; + int k_code; +}; + +struct rt5659_priv { + struct snd_soc_codec *codec; + struct rt5659_platform_data pdata; + struct regmap *regmap; + struct i2c_client *i2c; + struct gpio_desc *gpiod_ldo1_en; + struct gpio_desc *gpiod_reset; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + + int sysclk; + int sysclk_src; + int lrck[RT5659_AIFS]; + int bclk[RT5659_AIFS]; + int master[RT5659_AIFS]; + int v_id; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + +}; + +int rt5659_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); + +#endif /* __RT5659_H__ */ -- cgit v1.2.3 From 3de7c420a2b1737844d893cbfc689a9b2b5528cd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 9 Nov 2015 23:19:58 +0530 Subject: ASoC: core: refactor soc_link_dai_widgets() In soc_link_dai_widgets() we refer to local widget variables as playback/capture_widget, but they are really sink/source widgets, so change the names accordingly Suggested-by: Mark Brown Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 24b096066a07..d5e0bcbafb70 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1283,35 +1283,35 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *play_w, *capture_w; + struct snd_soc_dapm_widget *sink, *source; int ret; if (rtd->num_codecs > 1) dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); /* link the DAI widgets */ - play_w = codec_dai->playback_widget; - capture_w = cpu_dai->capture_widget; - if (play_w && capture_w) { + sink = codec_dai->playback_widget; + source = cpu_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } - play_w = cpu_dai->playback_widget; - capture_w = codec_dai->capture_widget; - if (play_w && capture_w) { + sink = cpu_dai->playback_widget; + source = codec_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } -- cgit v1.2.3 From a1e5e7e9b36f360bf75e4f0f7ceb899682f213bd Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Mon, 9 Nov 2015 23:20:00 +0530 Subject: ASoC: core: Pass kcontrol to bytes tlv callbacks Add kcontrol to the tlv callbacks in soc_bytes_ext, as it is needed for referencing the corresponding control in the driver code Also fix the only upstream user in topology core Signed-off-by: Mythri P K Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 6 ++++-- include/sound/soc.h | 6 ++++-- sound/soc/soc-ops.c | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 086cd7ff6ddc..5b68e3f5aa85 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -92,8 +92,10 @@ struct snd_soc_tplg_kcontrol_ops { /* Bytes ext operations, for TLV byte controls */ struct snd_soc_tplg_bytes_ext_ops { u32 id; - int (*get)(unsigned int __user *bytes, unsigned int size); - int (*put)(const unsigned int __user *bytes, unsigned int size); + int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes, + unsigned int size); + int (*put)(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, unsigned int size); }; /* diff --git a/include/sound/soc.h b/include/sound/soc.h index a8b4b9c8b1d2..6603155f50ca 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1225,8 +1225,10 @@ struct soc_bytes_ext { struct snd_soc_dobj dobj; /* used for TLV byte control */ - int (*get)(unsigned int __user *bytes, unsigned int size); - int (*put)(const unsigned int __user *bytes, unsigned int size); + int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes, + unsigned int size); + int (*put)(struct snd_kcontrol *kcontrol, const unsigned int __user *bytes, + unsigned int size); }; /* multi register control */ diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index ecd38e52285a..ba3e49010ac3 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -779,11 +779,11 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, switch (op_flag) { case SNDRV_CTL_TLV_OP_READ: if (params->get) - ret = params->get(tlv, count); + ret = params->get(kcontrol, tlv, count); break; case SNDRV_CTL_TLV_OP_WRITE: if (params->put) - ret = params->put(tlv, count); + ret = params->put(kcontrol, tlv, count); break; } return ret; -- cgit v1.2.3 From 28b5df1838b357c9e3e8eba02f684df3c0db05b3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 18 Nov 2015 16:24:56 +0800 Subject: ASoC: wm8904: Make undocumented registers non-readable Signed-off-by: Axel Lin Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 2aa23f1b9e3c..8172e499e6ed 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -312,7 +312,7 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg) case WM8904_FLL_NCO_TEST_1: return true; default: - return true; + return false; } } -- cgit v1.2.3 From b9a1a743818ea3265abf98f9431623afa8c50c86 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Nov 2015 15:25:23 +0100 Subject: ASoC: samsung: pass DMA channels as pointers ARM64 allmodconfig produces a bunch of warnings when building the samsung ASoC code: sound/soc/samsung/dmaengine.c: In function 'samsung_asoc_init_dma_data': sound/soc/samsung/dmaengine.c:53:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] playback_data->filter_data = (void *)playback->channel; sound/soc/samsung/dmaengine.c:60:31: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] capture_data->filter_data = (void *)capture->channel; We could easily shut up the warning by adding an intermediate cast, but there is a bigger underlying problem: The use of IORESOURCE_DMA to pass data from platform code to device drivers is dubious to start with, as what we really want is a pointer that can be passed into a filter function. Note that on s3c64xx, the pl08x DMA data is already a pointer, but gets cast to resource_size_t so we can pass it as a resource, and it then gets converted back to a pointer. In contrast, the data we pass for s3c24xx is an index into a device specific table, and we artificially convert that into a pointer for the filter function. Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/dev-audio.c | 41 ++++++++++++++----------- arch/arm/mach-s3c64xx/include/mach/dma.h | 52 ++++++++++++++++---------------- arch/arm/plat-samsung/devs.c | 11 +++++-- include/linux/platform_data/asoc-s3c.h | 4 +++ sound/soc/samsung/ac97.c | 26 +++------------- sound/soc/samsung/dma.h | 2 +- sound/soc/samsung/dmaengine.c | 4 +-- sound/soc/samsung/i2s.c | 26 +++------------- sound/soc/samsung/pcm.c | 20 +++--------- sound/soc/samsung/s3c2412-i2s.c | 4 +-- sound/soc/samsung/s3c24xx-i2s.c | 4 +-- sound/soc/samsung/spdif.c | 10 ++---- 12 files changed, 84 insertions(+), 120 deletions(-) (limited to 'sound') diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c index ff780a8d8366..9a42736ef4ac 100644 --- a/arch/arm/mach-s3c64xx/dev-audio.c +++ b/arch/arm/mach-s3c64xx/dev-audio.c @@ -54,12 +54,12 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev) static struct resource s3c64xx_iis0_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT), - [2] = DEFINE_RES_DMA(DMACH_I2S0_IN), }; -static struct s3c_audio_pdata i2sv3_pdata = { +static struct s3c_audio_pdata i2s0_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_playback = DMACH_I2S0_OUT, + .dma_capture = DMACH_I2S0_IN, }; struct platform_device s3c64xx_device_iis0 = { @@ -68,15 +68,19 @@ struct platform_device s3c64xx_device_iis0 = { .num_resources = ARRAY_SIZE(s3c64xx_iis0_resource), .resource = s3c64xx_iis0_resource, .dev = { - .platform_data = &i2sv3_pdata, + .platform_data = &i2s0_pdata, }, }; EXPORT_SYMBOL(s3c64xx_device_iis0); static struct resource s3c64xx_iis1_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT), - [2] = DEFINE_RES_DMA(DMACH_I2S1_IN), +}; + +static struct s3c_audio_pdata i2s1_pdata = { + .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_playback = DMACH_I2S1_OUT, + .dma_capture = DMACH_I2S1_IN, }; struct platform_device s3c64xx_device_iis1 = { @@ -85,19 +89,19 @@ struct platform_device s3c64xx_device_iis1 = { .num_resources = ARRAY_SIZE(s3c64xx_iis1_resource), .resource = s3c64xx_iis1_resource, .dev = { - .platform_data = &i2sv3_pdata, + .platform_data = &i2s1_pdata, }, }; EXPORT_SYMBOL(s3c64xx_device_iis1); static struct resource s3c64xx_iisv4_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX), - [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX), }; static struct s3c_audio_pdata i2sv4_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_playback = DMACH_HSI_I2SV40_TX, + .dma_capture = DMACH_HSI_I2SV40_RX, .type = { .i2s = { .quirks = QUIRK_PRI_6CHAN, @@ -142,12 +146,12 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) static struct resource s3c64xx_pcm0_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_PCM0_TX), - [2] = DEFINE_RES_DMA(DMACH_PCM0_RX), }; static struct s3c_audio_pdata s3c_pcm0_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_capture = DMACH_PCM0_RX, + .dma_playback = DMACH_PCM0_TX, }; struct platform_device s3c64xx_device_pcm0 = { @@ -163,12 +167,12 @@ EXPORT_SYMBOL(s3c64xx_device_pcm0); static struct resource s3c64xx_pcm1_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_PCM1_TX), - [2] = DEFINE_RES_DMA(DMACH_PCM1_RX), }; static struct s3c_audio_pdata s3c_pcm1_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_playback = DMACH_PCM1_TX, + .dma_capture = DMACH_PCM1_RX, }; struct platform_device s3c64xx_device_pcm1 = { @@ -196,13 +200,14 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev) static struct resource s3c64xx_ac97_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT), - [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN), - [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN), - [4] = DEFINE_RES_IRQ(IRQ_AC97), + [1] = DEFINE_RES_IRQ(IRQ_AC97), }; -static struct s3c_audio_pdata s3c_ac97_pdata; +static struct s3c_audio_pdata s3c_ac97_pdata = { + .dma_playback = DMACH_AC97_PCMOUT, + .dma_capture = DMACH_AC97_PCMIN, + .dma_capture_mic = DMACH_AC97_MICIN, +}; static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 096e14073bd9..9c739eafe95c 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -14,38 +14,38 @@ #define S3C64XX_DMA_CHAN(name) ((unsigned long)(name)) /* DMA0/SDMA0 */ -#define DMACH_UART0 S3C64XX_DMA_CHAN("uart0_tx") -#define DMACH_UART0_SRC2 S3C64XX_DMA_CHAN("uart0_rx") -#define DMACH_UART1 S3C64XX_DMA_CHAN("uart1_tx") -#define DMACH_UART1_SRC2 S3C64XX_DMA_CHAN("uart1_rx") -#define DMACH_UART2 S3C64XX_DMA_CHAN("uart2_tx") -#define DMACH_UART2_SRC2 S3C64XX_DMA_CHAN("uart2_rx") -#define DMACH_UART3 S3C64XX_DMA_CHAN("uart3_tx") -#define DMACH_UART3_SRC2 S3C64XX_DMA_CHAN("uart3_rx") -#define DMACH_PCM0_TX S3C64XX_DMA_CHAN("pcm0_tx") -#define DMACH_PCM0_RX S3C64XX_DMA_CHAN("pcm0_rx") -#define DMACH_I2S0_OUT S3C64XX_DMA_CHAN("i2s0_tx") -#define DMACH_I2S0_IN S3C64XX_DMA_CHAN("i2s0_rx") +#define DMACH_UART0 "uart0_tx" +#define DMACH_UART0_SRC2 "uart0_rx" +#define DMACH_UART1 "uart1_tx" +#define DMACH_UART1_SRC2 "uart1_rx" +#define DMACH_UART2 "uart2_tx" +#define DMACH_UART2_SRC2 "uart2_rx" +#define DMACH_UART3 "uart3_tx" +#define DMACH_UART3_SRC2 "uart3_rx" +#define DMACH_PCM0_TX "pcm0_tx" +#define DMACH_PCM0_RX "pcm0_rx" +#define DMACH_I2S0_OUT "i2s0_tx" +#define DMACH_I2S0_IN "i2s0_rx" #define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx") #define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx") -#define DMACH_HSI_I2SV40_TX S3C64XX_DMA_CHAN("i2s2_tx") -#define DMACH_HSI_I2SV40_RX S3C64XX_DMA_CHAN("i2s2_rx") +#define DMACH_HSI_I2SV40_TX "i2s2_tx" +#define DMACH_HSI_I2SV40_RX "i2s2_rx" /* DMA1/SDMA1 */ -#define DMACH_PCM1_TX S3C64XX_DMA_CHAN("pcm1_tx") -#define DMACH_PCM1_RX S3C64XX_DMA_CHAN("pcm1_rx") -#define DMACH_I2S1_OUT S3C64XX_DMA_CHAN("i2s1_tx") -#define DMACH_I2S1_IN S3C64XX_DMA_CHAN("i2s1_rx") +#define DMACH_PCM1_TX "pcm1_tx" +#define DMACH_PCM1_RX "pcm1_rx" +#define DMACH_I2S1_OUT "i2s1_tx" +#define DMACH_I2S1_IN "i2s1_rx" #define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx") #define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx") -#define DMACH_AC97_PCMOUT S3C64XX_DMA_CHAN("ac97_out") -#define DMACH_AC97_PCMIN S3C64XX_DMA_CHAN("ac97_in") -#define DMACH_AC97_MICIN S3C64XX_DMA_CHAN("ac97_mic") -#define DMACH_PWM S3C64XX_DMA_CHAN("pwm") -#define DMACH_IRDA S3C64XX_DMA_CHAN("irda") -#define DMACH_EXTERNAL S3C64XX_DMA_CHAN("external") -#define DMACH_SECURITY_RX S3C64XX_DMA_CHAN("sec_rx") -#define DMACH_SECURITY_TX S3C64XX_DMA_CHAN("sec_tx") +#define DMACH_AC97_PCMOUT "ac97_out" +#define DMACH_AC97_PCMIN "ac97_in" +#define DMACH_AC97_MICIN "ac97_mic" +#define DMACH_PWM "pwm" +#define DMACH_IRDA "irda" +#define DMACH_EXTERNAL "external" +#define DMACH_SECURITY_RX "sec_rx" +#define DMACH_SECURITY_TX "sec_tx" enum dma_ch { DMACH_MAX = 32 diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 82074625de5c..e212f9d804bd 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -65,6 +65,7 @@ #include #include #include +#include #include static u64 samsung_device_dma_mask = DMA_BIT_MASK(32); @@ -74,9 +75,12 @@ static u64 samsung_device_dma_mask = DMA_BIT_MASK(32); static struct resource s3c_ac97_resource[] = { [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97), [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97), - [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"), - [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"), - [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"), +}; + +static struct s3c_audio_pdata s3c_ac97_pdata = { + .dma_playback = (void *)DMACH_PCM_OUT, + .dma_capture = (void *)DMACH_PCM_IN, + .dma_capture_mic = (void *)DMACH_MIC_IN, }; struct platform_device s3c_device_ac97 = { @@ -87,6 +91,7 @@ struct platform_device s3c_device_ac97 = { .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_ac97_pdata, } }; #endif /* CONFIG_CPU_S3C2440 */ diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index 5e0bc779e6c5..33f88b4479e4 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h @@ -39,6 +39,10 @@ struct samsung_i2s { */ struct s3c_audio_pdata { int (*cfg_gpio)(struct platform_device *); + void *dma_playback; + void *dma_capture; + void *dma_play_sec; + void *dma_capture_mic; union { struct samsung_i2s i2s; } type; diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index e4145509d63c..9c5219392460 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -324,7 +324,7 @@ static const struct snd_soc_component_driver s3c_ac97_component = { static int s3c_ac97_probe(struct platform_device *pdev) { - struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; + struct resource *mem_res, *irq_res; struct s3c_audio_pdata *ac97_pdata; int ret; @@ -335,24 +335,6 @@ static int s3c_ac97_probe(struct platform_device *pdev) } /* Check for availability of necessary resource */ - dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmatx_res) { - dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n"); - return -ENXIO; - } - - dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!dmarx_res) { - dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n"); - return -ENXIO; - } - - dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (!dmamic_res) { - dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n"); - return -ENXIO; - } - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); @@ -364,11 +346,11 @@ static int s3c_ac97_probe(struct platform_device *pdev) if (IS_ERR(s3c_ac97.regs)) return PTR_ERR(s3c_ac97.regs); - s3c_ac97_pcm_out.channel = dmatx_res->start; + s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback; s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_pcm_in.channel = dmarx_res->start; + s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture; s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_mic_in.channel = dmamic_res->start; + s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic; s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; init_completion(&s3c_ac97.done); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 0e85dcfec023..085ef30f5ca2 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -15,7 +15,7 @@ #include struct s3c_dma_params { - int channel; /* Channel ID */ + void *slave; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ char *ch_name; diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 506f5bf6d082..727008d57d14 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -50,14 +50,14 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, if (playback) { playback_data = &playback->dma_data; - playback_data->filter_data = (void *)playback->channel; + playback_data->filter_data = playback->slave; playback_data->chan_name = playback->ch_name; playback_data->addr = playback->dma_addr; playback_data->addr_width = playback->dma_size; } if (capture) { capture_data = &capture->dma_data; - capture_data->filter_data = (void *)capture->channel; + capture_data->filter_data = capture->slave; capture_data->chan_name = capture->ch_name; capture_data->addr = capture->dma_addr; capture_data->addr_width = capture->dma_size; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index ea4ab374a223..0945b5de39e7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1257,27 +1257,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->lock = &pri_dai->spinlock; if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-TX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_playback.channel = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-RX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_capture.channel = res->start; - if (i2s_pdata == NULL) { dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); return -EINVAL; } + pri_dai->dma_playback.slave = i2s_pdata->dma_playback; + pri_dai->dma_capture.slave = i2s_pdata->dma_capture; + if (&i2s_pdata->type) i2s_cfg = &i2s_pdata->type.i2s; @@ -1338,11 +1325,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.ch_name = "tx-sec"; - if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (res) - sec_dai->dma_playback.channel = res->start; - } + if (!np) + sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec; sec_dai->dma_playback.dma_size = 4; sec_dai->addr = pri_dai->addr; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index b320a9d3fbf8..c77f324e0bb8 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -486,7 +486,7 @@ static const struct snd_soc_component_driver s3c_pcm_component = { static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; - struct resource *mem_res, *dmatx_res, *dmarx_res; + struct resource *mem_res; struct s3c_audio_pdata *pcm_pdata; int ret; @@ -499,18 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm_pdata = pdev->dev.platform_data; /* Check for availability of necessary resource */ - dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmatx_res) { - dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n"); - return -ENXIO; - } - - dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!dmarx_res) { - dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n"); - return -ENXIO; - } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "Unable to get register resource\n"); @@ -568,8 +556,10 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start + S3C_PCM_TXFIFO; - s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start; - s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start; + if (pcm_pdata) { + s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture; + s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback; + } pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 2b766d212ce0..77d27c85a32a 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -34,13 +34,13 @@ #include "s3c2412-i2s.h" static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { - .channel = DMACH_I2S_OUT, + .slave = (void *)(uintptr_t)DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 4, }; static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { - .channel = DMACH_I2S_IN, + .slave = (void *)(uintptr_t)DMACH_I2S_IN, .ch_name = "rx", .dma_size = 4, }; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 5bf723689692..9da3a77ea2c7 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -32,13 +32,13 @@ #include "s3c24xx-i2s.h" static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { - .channel = DMACH_I2S_OUT, + .slave = (void *)(uintptr_t)DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 2, }; static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { - .channel = DMACH_I2S_IN, + .slave = (void *)(uintptr_t)DMACH_I2S_IN, .ch_name = "rx", .dma_size = 2, }; diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 36dbc0e96004..9dd7ee6d03ff 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -359,7 +359,7 @@ static const struct snd_soc_component_driver samsung_spdif_component = { static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; - struct resource *mem_res, *dma_res; + struct resource *mem_res; struct samsung_spdif_info *spdif; int ret; @@ -367,12 +367,6 @@ static int spdif_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Entered %s\n", __func__); - dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dma_res) { - dev_err(&pdev->dev, "Unable to get dma resource.\n"); - return -ENXIO; - } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "Unable to get register resource.\n"); @@ -432,7 +426,7 @@ static int spdif_probe(struct platform_device *pdev) spdif_stereo_out.dma_size = 2; spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF; - spdif_stereo_out.channel = dma_res->start; + spdif_stereo_out.slave = spdif_pdata ? spdif_pdata->dma_playback : NULL; spdif->dma_playback = &spdif_stereo_out; -- cgit v1.2.3 From 359fdfa6fde04b3a752df5251b1dcd8866d436fa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Nov 2015 15:26:00 +0100 Subject: ASoC: s3c24xx-i2s: pass DMA channels as platform data This is a minor cleanup to make the s3c2412-i2s and s3c24xx-i2s drivers independent of the mach/dma.h header file and to allow removing the dependency on the specific dmaengine driver in the next patch. As a side not, only the s3c24xx-i2s driver seems to still be used, while the definition of the s3c2412-i2s platform device was removed in commit 6d259a25b56d ("ARM: SAMSUNG: use static declaration when it is not used in other files") after it had never been referenced since its introduction in f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). Apparently it should have been used by mach-jive.c, but that never happened. My patch at this point leaves the current state unchanged, we can decide whether to fix or delete the jive driver and s3c2412-i2s another time. Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- arch/arm/plat-samsung/devs.c | 6 ++++++ sound/soc/samsung/s3c2412-i2s.c | 12 ++++++++++-- sound/soc/samsung/s3c24xx-i2s.c | 12 ++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index e212f9d804bd..823de7b4e53b 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -571,6 +571,11 @@ static struct resource s3c_iis_resource[] = { [0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS), }; +static struct s3c_audio_pdata s3c_iis_platdata = { + .dma_playback = (void *)DMACH_I2S_OUT, + .dma_capture = (void *)DMACH_I2S_IN, +}; + struct platform_device s3c_device_iis = { .name = "s3c24xx-iis", .id = -1, @@ -579,6 +584,7 @@ struct platform_device s3c_device_iis = { .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_iis_platdata, } }; #endif /* CONFIG_PLAT_S3C24XX */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 77d27c85a32a..105317f523f2 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -33,14 +33,14 @@ #include "regs-i2s-v2.h" #include "s3c2412-i2s.h" +#include + static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { - .slave = (void *)(uintptr_t)DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 4, }; static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { - .slave = (void *)(uintptr_t)DMACH_I2S_IN, .ch_name = "rx", .dma_size = 4, }; @@ -152,6 +152,12 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; + struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data"); + return -ENXIO; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res); @@ -159,7 +165,9 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return PTR_ERR(s3c2412_i2s.regs); s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD; + s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback; s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD; + s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture; ret = s3c_i2sv2_register_component(&pdev->dev, -1, &s3c2412_i2s_component, diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 9da3a77ea2c7..9e6a5bc012e3 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -31,14 +31,14 @@ #include "dma.h" #include "s3c24xx-i2s.h" +#include + static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { - .slave = (void *)(uintptr_t)DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 2, }; static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { - .slave = (void *)(uintptr_t)DMACH_I2S_IN, .ch_name = "rx", .dma_size = 2, }; @@ -454,6 +454,12 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; + struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data"); + return -ENXIO; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -465,7 +471,9 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return PTR_ERR(s3c24xx_i2s.regs); s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback; s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture; ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); -- cgit v1.2.3 From 0928e8a54bf8889176175b2c3e5f2fc8ec1bb7ff Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 18 Nov 2015 19:11:46 +0530 Subject: ASoC: Intel: Skylake: Add I2C depends for SKL machine The i2c is dependency for the i2c codec drivers, so machine should depend on i2c. WIthout this we get build failures if I2C is not selected sound/soc/codecs/rl6347a.c: In function 'rl6347a_hw_write': >> sound/soc/codecs/rl6347a.c:66:8: error: implicit declaration of function >> 'i2c_master_send' [-Werror=implicit-function-declaration] ret = i2c_master_send(client, data, 4); ^ sound/soc/codecs/rl6347a.c: In function 'rl6347a_hw_read': >> sound/soc/codecs/rl6347a.c:114:8: error: implicit declaration of function >> 'i2c_transfer' [-Werror=implicit-function-declaration] ret = i2c_transfer(client->adapter, xfer, 2); Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 13a762172b5d..2903823ebee1 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -145,7 +145,7 @@ config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" - depends on X86 && ACPI + depends on X86 && ACPI && I2C select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 -- cgit v1.2.3 From e8e7b7bdc65c19f8d84c25f7e0d21176d598c870 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:09:52 +0000 Subject: ASoC: rsnd: remove Gen1 support from SRC This patch removes SRC Gen1 support which has no user on upstream. Historically, SRC Gen1 was created as prepare for SRC Gen2 support. It works well for Gen2 support, but Gen1 is not same as Gen2. So now, Gen1 support is no longer needed. Thanks Gen1 and Bye-bye. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 62 --------------- sound/soc/sh/rcar/gen.c | 38 +-------- sound/soc/sh/rcar/rsnd.h | 15 ---- sound/soc/sh/rcar/src.c | 199 ++--------------------------------------------- 4 files changed, 7 insertions(+), 307 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 1946ce8baf2e..1dffde3218be 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod, return rsnd_adg_set_src_timsel_gen2(src_mod, io, val); } -int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, - struct rsnd_mod *mod, - unsigned int src_rate, - unsigned int dst_rate) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct device *dev = rsnd_priv_to_dev(priv); - int idx, sel, div, shift; - u32 mask, val; - int id = rsnd_mod_id(mod); - unsigned int sel_rate [] = { - clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ - clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ - clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ - 0, /* 011: MLBCLK (not used) */ - adg->rbga_rate_for_441khz, /* 100: RBGA */ - adg->rbgb_rate_for_48khz, /* 101: RBGB */ - }; - - /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ - for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - for (div = 128, idx = 0; - div <= 2048; - div *= 2, idx++) { - if (src_rate == sel_rate[sel] / div) { - val = (idx << 4) | sel; - goto find_rate; - } - } - } - dev_err(dev, "can't find convert src clk\n"); - return -EINVAL; - -find_rate: - shift = (id % 4) * 8; - mask = 0xFF << shift; - val = val << shift; - - dev_dbg(dev, "adg convert src clk = %02x\n", val); - - switch (id / 4) { - case 0: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val); - break; - case 1: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val); - break; - case 2: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val); - break; - } - - /* - * Gen1 doesn't need dst_rate settings, - * since it uses SSI WS pin. - * see also rsnd_src_set_route_if_gen1() - */ - - return 0; -} - static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) { struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 76da7620904c..1808fc64646c 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -320,43 +320,12 @@ static int rsnd_gen2_probe(struct platform_device *pdev, static int rsnd_gen1_probe(struct platform_device *pdev, struct rsnd_priv *priv) { - struct rsnd_regmap_field_conf conf_sru[] = { - RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00), - RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08), - RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c), - RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10), - RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0), - RSND_GEN_S_REG(SSI_MODE0, 0xD0), - RSND_GEN_S_REG(SSI_MODE1, 0xD4), - RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4), - RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8), - RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), - RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), - RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), - RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), - RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), - RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), - RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), - /* - * ADD US - * - * SRC_STATUS - * SRC_INT_EN - * SCU_SYS_STATUS0 - * SCU_SYS_STATUS1 - * SCU_SYS_INT_EN0 - * SCU_SYS_INT_EN1 - */ - }; struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(SSICKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), - RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18), - RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c), - RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20), }; struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), @@ -365,17 +334,14 @@ static int rsnd_gen1_probe(struct platform_device *pdev, RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), }; - int ret_sru; int ret_adg; int ret_ssi; - ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru); ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); - if (ret_sru < 0 || - ret_adg < 0 || + if (ret_adg < 0 || ret_ssi < 0) - return ret_sru | ret_adg | ret_ssi; + return ret_adg | ret_ssi; return 0; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 8efa19fa2b6e..da671869f12a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -117,17 +117,6 @@ enum rsnd_reg { RSND_REG_MAX, }; -/* Gen1 only */ -#define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01 -#define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02 -#define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03 -#define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04 -#define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05 -#define RSND_REG_SRC_MNFSR RSND_REG_SHARE06 -#define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07 -#define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08 -#define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09 - /* Gen2 only */ #define RSND_REG_SRC_CTRL RSND_REG_SHARE01 #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 @@ -407,10 +396,6 @@ int rsnd_adg_probe(struct platform_device *pdev, struct rsnd_priv *priv); void rsnd_adg_remove(struct platform_device *pdev, struct rsnd_priv *priv); -int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, - struct rsnd_mod *mod, - unsigned int src_rate, - unsigned int dst_rate); int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, unsigned int src_rate, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 776b0efec4d6..0978221b2fe1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -309,187 +309,6 @@ static int rsnd_src_stop(struct rsnd_mod *mod) return 0; } -/* - * Gen1 functions - */ -static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct src_route_config { - u32 mask; - int shift; - } routes[] = { - { 0xF, 0, }, /* 0 */ - { 0xF, 4, }, /* 1 */ - { 0xF, 8, }, /* 2 */ - { 0x7, 12, }, /* 3 */ - { 0x7, 16, }, /* 4 */ - { 0x7, 20, }, /* 5 */ - { 0x7, 24, }, /* 6 */ - { 0x3, 28, }, /* 7 */ - { 0x3, 30, }, /* 8 */ - }; - u32 mask; - u32 val; - int id; - - id = rsnd_mod_id(mod); - if (id < 0 || id >= ARRAY_SIZE(routes)) - return -EIO; - - /* - * SRC_ROUTE_SELECT - */ - val = rsnd_io_is_play(io) ? 0x1 : 0x2; - val = val << routes[id].shift; - mask = routes[id].mask << routes[id].shift; - - rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); - - return 0; -} - -static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 mask; - u32 val; - int shift; - int id = rsnd_mod_id(mod); - int ret; - - /* - * SRC_TIMING_SELECT - */ - shift = (id % 4) * 8; - mask = 0x1F << shift; - - /* - * ADG is used as source clock if SRC was used, - * then, SSI WS is used as destination clock. - * SSI WS is used as source clock if SRC is not used - * (when playback, source/destination become reverse when capture) - */ - ret = 0; - if (convert_rate) { - /* use ADG */ - val = 0; - ret = rsnd_adg_set_convert_clk_gen1(priv, mod, - runtime->rate, - convert_rate); - } else if (8 == id) { - /* use SSI WS, but SRU8 is special */ - val = id << shift; - } else { - /* use SSI WS */ - val = (id + 1) << shift; - } - - if (ret < 0) - return ret; - - switch (id / 4) { - case 0: - rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); - break; - case 1: - rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); - break; - case 2: - rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); - break; - } - - return 0; -} - -static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - ret = rsnd_src_set_convert_rate(mod, io); - if (ret < 0) - return ret; - - /* Select SRC mode (fixed value) */ - rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); - - /* Set the restriction value of the FS ratio (98%) */ - rsnd_mod_write(mod, SRC_MNFSR, - rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); - - /* Gen1/Gen2 are not compatible */ - if (rsnd_src_convert_rate(io, src)) - rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); - - /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ - - return 0; -} - -static int rsnd_src_init_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_src_init(mod, priv); - if (ret < 0) - return ret; - - ret = rsnd_src_set_route_gen1(io, mod); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_rate_gen1(mod, io); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_timing_gen1(io, mod); - if (ret < 0) - return ret; - - return 0; -} - -static int rsnd_src_start_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int id = rsnd_mod_id(mod); - - rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); - - return rsnd_src_start(mod); -} - -static int rsnd_src_stop_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int id = rsnd_mod_id(mod); - - rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); - - return rsnd_src_stop(mod); -} - -static struct rsnd_mod_ops rsnd_src_gen1_ops = { - .name = SRC_NAME, - .dma_req = rsnd_src_dma_req, - .init = rsnd_src_init_gen1, - .quit = rsnd_src_quit, - .start = rsnd_src_start_gen1, - .stop = rsnd_src_stop_gen1, - .hw_params = rsnd_src_hw_params, -}; - /* * Gen2 functions */ @@ -927,22 +746,13 @@ int rsnd_src_probe(struct platform_device *pdev, struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_src *src; - struct rsnd_mod_ops *ops; struct clk *clk; char name[RSND_SRC_NAME_SIZE]; int i, nr, ret; - ops = NULL; - if (rsnd_is_gen1(priv)) { - ops = &rsnd_src_gen1_ops; - dev_warn(dev, "Gen1 support will be removed soon\n"); - } - if (rsnd_is_gen2(priv)) - ops = &rsnd_src_gen2_ops; - if (!ops) { - dev_err(dev, "unknown Generation\n"); - return -EIO; - } + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) + return 0; rsnd_of_parse_src(pdev, of_data, priv); @@ -970,7 +780,8 @@ int rsnd_src_probe(struct platform_device *pdev, src->info = &info->src_info[i]; - ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i); + ret = rsnd_mod_init(priv, rsnd_mod_get(src), + &rsnd_src_gen2_ops, clk, RSND_MOD_SRC, i); if (ret) return ret; } -- cgit v1.2.3 From d444080ef824bf45ead732f2c68cfeb5885bc53a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:10:18 +0000 Subject: ASoC: rsnd: cleanup RSND_REG_xxx SRC Gen1 support was removed. Current rsnd driver is sharing Gen1/Gen2 register index to reduce memory, but there is no effect anymore. Let's remove share definition and merge RSND_REG_xxx Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 93 ++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 63 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index da671869f12a..a3e42a4f4b19 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -34,9 +34,14 @@ * see gen1/gen2 for detail */ enum rsnd_reg { - /* SRU/SCU/SSIU */ + /* SCU (SRC/SSIU/MIX/CTU/DVC) */ RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, + RSND_REG_SSI_CTRL, /* Gen2 only */ + RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ + RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ + RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ RSND_REG_SRC_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, RSND_REG_SRC_SWRSR, @@ -45,9 +50,28 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, + RSND_REG_SRC_CTRL, /* Gen2 only */ + RSND_REG_SRC_BSDSR, /* Gen2 only */ + RSND_REG_SRC_BSISR, /* Gen2 only */ + RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ + RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ RSND_REG_SCU_SYS_STATUS0, + RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ RSND_REG_SCU_SYS_INT_EN0, + RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ + RSND_REG_CMD_CTRL, /* Gen2 only */ RSND_REG_CMD_ROUTE_SLCT, + RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, RSND_REG_MIX_SWRSR, @@ -68,13 +92,18 @@ enum rsnd_reg { RSND_REG_DVC_VOL0R, RSND_REG_DVC_VOL1R, RSND_REG_DVC_DVUER, + RSND_REG_DVC_VRCTR, /* Gen2 only */ + RSND_REG_DVC_VRPDR, /* Gen2 only */ + RSND_REG_DVC_VRDBR, /* Gen2 only */ /* ADG */ RSND_REG_BRRA, RSND_REG_BRRB, RSND_REG_SSICKR, + RSND_REG_DIV_EN, /* Gen2 only */ RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, + RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ /* SSI */ RSND_REG_SSICR, @@ -83,71 +112,9 @@ enum rsnd_reg { RSND_REG_SSIRDR, RSND_REG_SSIWSR, - /* SHARE see below */ - RSND_REG_SHARE01, - RSND_REG_SHARE02, - RSND_REG_SHARE03, - RSND_REG_SHARE04, - RSND_REG_SHARE05, - RSND_REG_SHARE06, - RSND_REG_SHARE07, - RSND_REG_SHARE08, - RSND_REG_SHARE09, - RSND_REG_SHARE10, - RSND_REG_SHARE11, - RSND_REG_SHARE12, - RSND_REG_SHARE13, - RSND_REG_SHARE14, - RSND_REG_SHARE15, - RSND_REG_SHARE16, - RSND_REG_SHARE17, - RSND_REG_SHARE18, - RSND_REG_SHARE19, - RSND_REG_SHARE20, - RSND_REG_SHARE21, - RSND_REG_SHARE22, - RSND_REG_SHARE23, - RSND_REG_SHARE24, - RSND_REG_SHARE25, - RSND_REG_SHARE26, - RSND_REG_SHARE27, - RSND_REG_SHARE28, - RSND_REG_SHARE29, - RSND_REG_MAX, }; -/* Gen2 only */ -#define RSND_REG_SRC_CTRL RSND_REG_SHARE01 -#define RSND_REG_SSI_CTRL RSND_REG_SHARE02 -#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 -#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 -#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05 -#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 -#define RSND_REG_SRC_BSISR RSND_REG_SHARE07 -#define RSND_REG_DIV_EN RSND_REG_SHARE08 -#define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09 -#define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10 -#define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11 -#define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12 -#define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13 -#define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14 -#define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15 -#define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16 -#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 -#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 -#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 -#define RSND_REG_CMD_CTRL RSND_REG_SHARE20 -#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 -#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22 -#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 -#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 -#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 -#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 -#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 -#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 -#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29 - struct rsnd_of_data; struct rsnd_priv; struct rsnd_mod; -- cgit v1.2.3 From 75916f6524f055bca134f50901f926d5b0693db5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:10:48 +0000 Subject: ASoC: rsnd: SRC settings matches to datasheet Current SRC settings order was rough. Now, Gen1 support was removed. This patch makes it cleanup and match to datasheet. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 424 +++++++++++++++++++----------------------------- 1 file changed, 166 insertions(+), 258 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 0978221b2fe1..d081a652f917 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -117,23 +117,12 @@ struct rsnd_src { * */ -/* - * Gen1/Gen2 common functions - */ static void rsnd_src_soft_reset(struct rsnd_mod *mod) { rsnd_mod_write(mod, SRC_SWRSR, 0); rsnd_mod_write(mod, SRC_SWRSR, 1); } - -#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) -#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) -static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) -{ - rsnd_mod_write(mod, SRC_SRCIR, enable); -} - static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -192,34 +181,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, return rate; } -static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 fsrate = 0; - - if (convert_rate) - fsrate = 0x0400000 / convert_rate * runtime->rate; - - /* Set channel number and output bit length */ - rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); - - /* Enable the initial value of IFS */ - if (fsrate) { - rsnd_mod_write(mod, SRC_IFSCR, 1); - - /* Set initial value of IFS */ - rsnd_mod_write(mod, SRC_IFSVR, fsrate); - } - - /* use DMA transfer */ - rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); - - return 0; -} - static int rsnd_src_hw_params(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_pcm_substream *substream, @@ -256,65 +217,106 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, return 0; } -static int rsnd_src_init(struct rsnd_mod *mod, - struct rsnd_priv *priv) +static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 convert_rate = rsnd_src_convert_rate(io, src); + u32 ifscr, fsrate, adinr; + u32 cr, route; + u32 bsdsr, bsisr; + uint ratio; - rsnd_mod_power_on(mod); - - rsnd_src_soft_reset(mod); - - rsnd_src_initialize_lock(mod); - - src->err = 0; - - /* reset sync convert_rate */ - src->sync.val = 0; + if (!runtime) + return; - return 0; -} + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ + if (!convert_rate) + ratio = 0; + else if (convert_rate > runtime->rate) + ratio = 100 * convert_rate / runtime->rate; + else + ratio = 100 * runtime->rate / convert_rate; -static int rsnd_src_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); + if (ratio > 600) { + dev_err(dev, "FSO/FSI ratio error\n"); + return; + } - rsnd_mod_power_off(mod); + /* + * SRC_ADINR + */ + adinr = rsnd_get_adinr_bit(mod, io); - if (src->err) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); + /* + * SRC_IFSCR / SRC_IFSVR + */ + ifscr = 0; + fsrate = 0; + if (convert_rate) { + ifscr = 1; + fsrate = 0x0400000 / convert_rate * runtime->rate; + } - src->convert_rate = 0; + /* + * SRC_SRCCR / SRC_ROUTE_MODE0 + */ + cr = 0x00011110; + route = 0x0; + if (convert_rate) { + route = 0x1; - /* reset sync convert_rate */ - src->sync.val = 0; + if (rsnd_enable_sync_convert(src)) { + cr |= 0x1; + route |= rsnd_io_is_play(io) ? + (0x1 << 24) : (0x1 << 25); + } + } - return 0; -} + /* + * SRC_BSDSR / SRC_BSISR + */ + switch (rsnd_mod_id(mod)) { + case 5: + case 6: + case 7: + case 8: + bsdsr = 0x02400000; /* 6 - 1/6 */ + bsisr = 0x00100060; /* 6 - 1/6 */ + break; + default: + bsdsr = 0x01800000; /* 6 - 1/6 */ + bsisr = 0x00100060 ;/* 6 - 1/6 */ + break; + } -static int rsnd_src_start(struct rsnd_mod *mod) -{ - rsnd_src_initialize_unlock(mod); + rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ + rsnd_mod_write(mod, SRC_ADINR, adinr); + rsnd_mod_write(mod, SRC_IFSCR, ifscr); + rsnd_mod_write(mod, SRC_IFSVR, fsrate); + rsnd_mod_write(mod, SRC_SRCCR, cr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr); + rsnd_mod_write(mod, SRC_BSISR, bsisr); + rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - return 0; -} + rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); + rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); -static int rsnd_src_stop(struct rsnd_mod *mod) -{ - /* nothing to do */ - return 0; + if (convert_rate) + rsnd_adg_set_convert_clk_gen2(mod, io, + runtime->rate, + convert_rate); + else + rsnd_adg_set_convert_timing_gen2(mod, io); } -/* - * Gen2 functions - */ -#define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1) -#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0) -static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) +#define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1) +#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0) +static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 sys_int_val, int_val, sys_int_mask; @@ -328,7 +330,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) /* * IRQ is not supported on non-DT * see - * rsnd_src_probe_gen2() + * rsnd_src_probe_() */ if ((irq <= 0) || !enable) { sys_int_val = 0; @@ -348,7 +350,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); } -static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) +static void rsnd_src_error_clear(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); @@ -356,7 +358,7 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); } -static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) +static bool rsnd_src_error_record(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val0, val1; @@ -381,22 +383,18 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) } /* clear error static */ - rsnd_src_error_clear_gen2(mod); + rsnd_src_error_clear(mod); return ret; } -static int rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_src_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; - val = rsnd_get_dalign(mod, io); - - rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); - /* * WORKAROUND * @@ -407,44 +405,74 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SRC_CTRL, val); - rsnd_src_error_clear_gen2(mod); - - rsnd_src_start(mod); - - rsnd_src_irq_enable_gen2(mod); - return 0; } -static int rsnd_src_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_src_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { - rsnd_src_irq_disable_gen2(mod); - /* * stop SRC output only - * see rsnd_src_quit_gen2 + * see rsnd_src_quit */ rsnd_mod_write(mod, SRC_CTRL, 0x01); - rsnd_src_error_record_gen2(mod); + return 0; +} + +static int rsnd_src_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); - return rsnd_src_stop(mod); + rsnd_mod_power_on(mod); + + rsnd_src_soft_reset(mod); + + rsnd_src_set_convert_rate(io, mod); + + rsnd_src_error_clear(mod); + + rsnd_src_irq_enable(mod); + + src->err = 0; + + /* reset sync convert_rate */ + src->sync.val = 0; + + return 0; } -static int rsnd_src_quit_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_src_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_src *src = rsnd_mod_to_src(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + rsnd_src_irq_disable(mod); + /* stop both out/in */ rsnd_mod_write(mod, SRC_CTRL, 0); - return rsnd_src_quit(mod, io, priv); + rsnd_mod_power_off(mod); + + if (src->err) + dev_warn(dev, "%s[%d] under/over flow err = %d\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); + + src->convert_rate = 0; + + /* reset sync convert_rate */ + src->sync.val = 0; + + return 0; } -static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +static void __rsnd_src_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_src *src = rsnd_mod_to_src(mod); @@ -454,119 +482,40 @@ static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, /* ignore all cases if not working */ if (!rsnd_io_is_working(io)) - goto rsnd_src_interrupt_gen2_out; + goto rsnd_src_interrupt_out; - if (rsnd_src_error_record_gen2(mod)) { + if (rsnd_src_error_record(mod)) { dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - rsnd_src_stop_gen2(mod, io, priv); - rsnd_src_start_gen2(mod, io, priv); + rsnd_src_stop(mod, io, priv); + rsnd_src_start(mod, io, priv); } if (src->err > 1024) { - rsnd_src_irq_disable_gen2(mod); + rsnd_src_irq_disable(mod); dev_warn(dev, "no more %s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); } -rsnd_src_interrupt_gen2_out: +rsnd_src_interrupt_out: spin_unlock(&priv->lock); } -static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) +static irqreturn_t rsnd_src_interrupt(int irq, void *data) { struct rsnd_mod *mod = data; - rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2); + rsnd_mod_interrupt(mod, __rsnd_src_interrupt); return IRQ_HANDLED; } -static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 cr, route; - uint ratio; - int ret; - - /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ - if (!convert_rate) - ratio = 0; - else if (convert_rate > runtime->rate) - ratio = 100 * convert_rate / runtime->rate; - else - ratio = 100 * runtime->rate / convert_rate; - - if (ratio > 600) { - dev_err(dev, "FSO/FSI ratio error\n"); - return -EINVAL; - } - - ret = rsnd_src_set_convert_rate(mod, io); - if (ret < 0) - return ret; - - cr = 0x00011110; - route = 0x0; - if (convert_rate) { - route = 0x1; - - if (rsnd_enable_sync_convert(src)) { - cr |= 0x1; - route |= rsnd_io_is_play(io) ? - (0x1 << 24) : (0x1 << 25); - } - } - - rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); - - switch (rsnd_mod_id(mod)) { - case 5: - case 6: - case 7: - case 8: - rsnd_mod_write(mod, SRC_BSDSR, 0x02400000); - break; - default: - rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); - break; - } - - rsnd_mod_write(mod, SRC_BSISR, 0x00100060); - - return 0; -} - -static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - int ret; - - if (convert_rate) - ret = rsnd_adg_set_convert_clk_gen2(mod, io, - runtime->rate, - convert_rate); - else - ret = rsnd_adg_set_convert_timing_gen2(mod, io); - - return ret; -} - -static int rsnd_src_probe_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_src_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); @@ -577,10 +526,10 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, /* * IRQ is not supported on non-DT * see - * rsnd_src_irq_enable_gen2() + * rsnd_src_irq_enable() */ ret = devm_request_irq(dev, irq, - rsnd_src_interrupt_gen2, + rsnd_src_interrupt, IRQF_SHARED, dev_name(dev), mod); if (ret) @@ -594,48 +543,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, return ret; } -static int rsnd_src_init_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_src_init(mod, priv); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_rate_gen2(mod, io); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_timing_gen2(io, mod); - if (ret < 0) - return ret; - - return 0; -} - -static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 fsrate; - - if (!runtime) - return; - - if (!convert_rate) - convert_rate = runtime->rate; - - fsrate = 0x0400000 / convert_rate * runtime->rate; - - /* update IFS */ - rsnd_mod_write(mod, SRC_IFSVR, fsrate); -} - -static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, +static int rsnd_src_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { @@ -660,7 +568,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate Switch" : "SRC In Rate Switch", - rsnd_src_reconvert_update, + rsnd_src_set_convert_rate, &src->sen, 1); if (ret < 0) return ret; @@ -669,22 +577,22 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate" : "SRC In Rate", - rsnd_src_reconvert_update, + rsnd_src_set_convert_rate, &src->sync, 192000); return ret; } -static struct rsnd_mod_ops rsnd_src_gen2_ops = { +static struct rsnd_mod_ops rsnd_src_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_gen2, - .init = rsnd_src_init_gen2, - .quit = rsnd_src_quit_gen2, - .start = rsnd_src_start_gen2, - .stop = rsnd_src_stop_gen2, + .probe = rsnd_src_probe_, + .init = rsnd_src_init, + .quit = rsnd_src_quit, + .start = rsnd_src_start, + .stop = rsnd_src_stop, .hw_params = rsnd_src_hw_params, - .pcm_new = rsnd_src_pcm_new_gen2, + .pcm_new = rsnd_src_pcm_new, }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) @@ -781,7 +689,7 @@ int rsnd_src_probe(struct platform_device *pdev, src->info = &info->src_info[i]; ret = rsnd_mod_init(priv, rsnd_mod_get(src), - &rsnd_src_gen2_ops, clk, RSND_MOD_SRC, i); + &rsnd_src_ops, clk, RSND_MOD_SRC, i); if (ret) return ret; } -- cgit v1.2.3 From 94e2710cd2ce447cde879177d869b9ac231bc459 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:11:18 +0000 Subject: ASoC: rsnd: remove platform boot support from core.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from core.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 280 +++++++++++++---------------------------------- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/dvc.c | 2 +- sound/soc/sh/rcar/mix.c | 2 +- sound/soc/sh/rcar/rsnd.h | 13 +++ sound/soc/sh/rcar/src.c | 2 - sound/soc/sh/rcar/ssi.c | 2 - 7 files changed, 95 insertions(+), 208 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 81250cf6788d..039d6cba8414 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -122,11 +122,6 @@ MODULE_DEVICE_TABLE(of, rsnd_of_match); (!(priv->info->func) ? 0 : \ priv->info->func(param)) -#define rsnd_is_enable_path(io, name) \ - ((io)->info ? (io)->info->name : NULL) -#define rsnd_info_id(priv, io, name) \ - ((io)->info->name - priv->info->name##_info) - /* * rsnd_mod functions */ @@ -573,140 +568,96 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; -#define rsnd_path_add(priv, io, _type) \ -({ \ - struct rsnd_mod *mod; \ - int ret = 0; \ - int id = -1; \ - \ - if (rsnd_is_enable_path(io, _type)) { \ - id = rsnd_info_id(priv, io, _type); \ - if (id >= 0) { \ - mod = rsnd_##_type##_mod_get(priv, id); \ - ret = rsnd_dai_connect(mod, io, mod->type);\ - } \ - } \ - ret; \ -}) - -static int rsnd_path_init(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) -{ - int ret; - - /* - * Gen1 is created by SRU/SSI, and this SRU is base module of - * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) - * - * Easy image is.. - * Gen1 SRU = Gen2 SCU + SSIU + etc - * - * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is - * using fixed path. - */ - - /* SSI */ - ret = rsnd_path_add(priv, io, ssi); - if (ret < 0) - return ret; - - /* SRC */ - ret = rsnd_path_add(priv, io, src); - if (ret < 0) - return ret; - - /* CTU */ - ret = rsnd_path_add(priv, io, ctu); - if (ret < 0) - return ret; - - /* MIX */ - ret = rsnd_path_add(priv, io, mix); - if (ret < 0) - return ret; - - /* DVC */ - ret = rsnd_path_add(priv, io, dvc); - if (ret < 0) - return ret; - - return ret; -} - -static void rsnd_of_parse_dai(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +static int rsnd_dai_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) { - struct device_node *dai_node, *dai_np; - struct device_node *ssi_node, *ssi_np; - struct device_node *src_node, *src_np; - struct device_node *ctu_node, *ctu_np; - struct device_node *mix_node, *mix_np; - struct device_node *dvc_node, *dvc_np; + struct device_node *dai_node; + struct device_node *dai_np, *np, *node; struct device_node *playback, *capture; - struct rsnd_dai_platform_info *dai_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct rsnd_dai_stream *io_playback; + struct rsnd_dai_stream *io_capture; + struct snd_soc_dai_driver *drv; + struct rsnd_dai *rdai; struct device *dev = &pdev->dev; - int nr, i; - int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i; + int nr, dai_i, io_i, np_i; + int ret; if (!of_data) - return; - - dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai"); - if (!dai_node) - return; + return 0; + dai_node = rsnd_dai_of_node(priv); nr = of_get_child_count(dai_node); - if (!nr) - return; - - dai_info = devm_kzalloc(dev, - sizeof(struct rsnd_dai_platform_info) * nr, - GFP_KERNEL); - if (!dai_info) { - dev_err(dev, "dai info allocation error\n"); - return; + if (!nr) { + ret = -EINVAL; + goto rsnd_dai_probe_done; } - info->dai_info_nr = nr; - info->dai_info = dai_info; - - ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); - src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); - ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); - mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); - dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); + drv = devm_kzalloc(dev, sizeof(*drv) * nr, GFP_KERNEL); + rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); + if (!drv || !rdai) { + ret = -ENOMEM; + goto rsnd_dai_probe_done; + } -#define mod_parse(name) \ -if (name##_node) { \ - struct rsnd_##name##_platform_info *name##_info; \ - \ - name##_i = 0; \ - for_each_child_of_node(name##_node, name##_np) { \ - name##_info = info->name##_info + name##_i; \ - \ - if (name##_np == playback) \ - dai_info->playback.name = name##_info; \ - if (name##_np == capture) \ - dai_info->capture.name = name##_info; \ - \ - name##_i++; \ - } \ -} + priv->rdai_nr = nr; + priv->daidrv = drv; + priv->rdai = rdai; /* * parse all dai */ dai_i = 0; for_each_child_of_node(dai_node, dai_np) { - dai_info = info->dai_info + dai_i; + rdai = rsnd_rdai_get(priv, dai_i); + drv = drv + dai_i; + io_playback = &rdai->playback; + io_capture = &rdai->capture; + + snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + + rdai->priv = priv; + drv->name = rdai->name; + drv->ops = &rsnd_soc_dai_ops; + + snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, + "DAI%d Playback", dai_i); + drv->playback.rates = RSND_RATES; + drv->playback.formats = RSND_FMTS; + drv->playback.channels_min = 2; + drv->playback.channels_max = 2; + drv->playback.stream_name = rdai->playback.name; + + snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, + "DAI%d Capture", dai_i); + drv->capture.rates = RSND_RATES; + drv->capture.formats = RSND_FMTS; + drv->capture.channels_min = 2; + drv->capture.channels_max = 2; + drv->capture.stream_name = rdai->capture.name; + + rdai->playback.rdai = rdai; + rdai->capture.rdai = rdai; - for (i = 0;; i++) { +#define mod_parse(name) \ +node = rsnd_##name##_of_node(priv); \ +if (node) { \ + struct rsnd_mod *mod; \ + np_i = 0; \ + for_each_child_of_node(node, np) { \ + mod = rsnd_##name##_mod_get(priv, np_i); \ + if (np == playback) \ + rsnd_dai_connect(mod, io_playback, mod->type); \ + if (np == capture) \ + rsnd_dai_connect(mod, io_capture, mod->type); \ + np_i++; \ + } \ + of_node_put(node); \ +} - playback = of_parse_phandle(dai_np, "playback", i); - capture = of_parse_phandle(dai_np, "capture", i); + for (io_i = 0;; io_i++) { + playback = of_parse_phandle(dai_np, "playback", io_i); + capture = of_parse_phandle(dai_np, "capture", io_i); if (!playback && !capture) break; @@ -722,91 +673,18 @@ if (name##_node) { \ } dai_i++; - } -} - -static int rsnd_dai_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct snd_soc_dai_driver *drv; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_dai *rdai; - struct rsnd_ssi_platform_info *pmod, *cmod; - struct device *dev = rsnd_priv_to_dev(priv); - int dai_nr; - int i; - - rsnd_of_parse_dai(pdev, of_data, priv); - dai_nr = info->dai_info_nr; - if (!dai_nr) { - dev_err(dev, "no dai\n"); - return -EIO; - } - - drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL); - rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL); - if (!drv || !rdai) { - dev_err(dev, "dai allocate failed\n"); - return -ENOMEM; + dev_dbg(dev, "%s (%s/%s)\n", rdai->name, + rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", + rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); } - priv->rdai_nr = dai_nr; - priv->daidrv = drv; - priv->rdai = rdai; - - for (i = 0; i < dai_nr; i++) { - - pmod = info->dai_info[i].playback.ssi; - cmod = info->dai_info[i].capture.ssi; - - /* - * init rsnd_dai - */ - snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); - rdai[i].priv = priv; - - /* - * init snd_soc_dai_driver - */ - drv[i].name = rdai[i].name; - drv[i].ops = &rsnd_soc_dai_ops; - if (pmod) { - snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE, - "DAI%d Playback", i); - - drv[i].playback.rates = RSND_RATES; - drv[i].playback.formats = RSND_FMTS; - drv[i].playback.channels_min = 2; - drv[i].playback.channels_max = 2; - drv[i].playback.stream_name = rdai[i].playback.name; - - rdai[i].playback.info = &info->dai_info[i].playback; - rdai[i].playback.rdai = rdai + i; - rsnd_path_init(priv, &rdai[i], &rdai[i].playback); - } - if (cmod) { - snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE, - "DAI%d Capture", i); - - drv[i].capture.rates = RSND_RATES; - drv[i].capture.formats = RSND_FMTS; - drv[i].capture.channels_min = 2; - drv[i].capture.channels_max = 2; - drv[i].capture.stream_name = rdai[i].capture.name; - - rdai[i].capture.info = &info->dai_info[i].capture; - rdai[i].capture.rdai = rdai + i; - rsnd_path_init(priv, &rdai[i], &rdai[i].capture); - } + ret = 0; - dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, - pmod ? "play" : " -- ", - cmod ? "capture" : " -- "); - } +rsnd_dai_probe_done: + of_node_put(dai_node); - return 0; + return ret; } /* diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 6b76ae6cf549..daa1017c8890 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -90,7 +90,7 @@ static void rsnd_of_parse_ctu(struct platform_device *pdev, if (!of_data) return; - node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); + node = rsnd_ctu_of_node(priv); if (!node) return; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 0dc8a2a99fa4..d2bd4804db0d 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -317,7 +317,7 @@ static void rsnd_of_parse_dvc(struct platform_device *pdev, if (!of_data) return; - node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); + node = rsnd_dvc_of_node(priv); if (!node) return; diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 2baa2d79bfc0..195bc748a32f 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -130,7 +130,7 @@ static void rsnd_of_parse_mix(struct platform_device *pdev, if (!of_data) return; - node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); + node = rsnd_mix_of_node(priv); if (!node) return; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a3e42a4f4b19..23507c8d79c2 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -338,6 +338,8 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); +#define rsnd_dai_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") /* * R-Car Gen1/Gen2 @@ -524,6 +526,9 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); +#define rsnd_ssi_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") + /* * R-Car SSIU */ @@ -547,6 +552,8 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct snd_pcm_runtime *runtime); +#define rsnd_src_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") /* * R-Car CTU @@ -558,6 +565,8 @@ int rsnd_ctu_probe(struct platform_device *pdev, void rsnd_ctu_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_ctu_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") /* * R-Car MIX @@ -569,6 +578,8 @@ int rsnd_mix_probe(struct platform_device *pdev, void rsnd_mix_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_mix_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") /* * R-Car DVC @@ -579,6 +590,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, void rsnd_dvc_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_dvc_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") /* * R-Car CMD diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index d081a652f917..230db9f81377 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -34,8 +34,6 @@ struct rsnd_src { #define rsnd_src_to_dma(src) ((src)->dma) #define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) -#define rsnd_src_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 60ef074082e8..61957f609e79 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -88,8 +88,6 @@ struct rsnd_ssi { #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) -#define rsnd_ssi_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { -- cgit v1.2.3 From 02534f2f80224531ab19bf5027224ed775fe2b39 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:11:35 +0000 Subject: ASoC: rsnd: remove platform boot support from ssi.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from ssi.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rcar_snd.h | 2 - sound/soc/sh/rcar/ssi.c | 145 +++++++++++++++++-------------------------- 2 files changed, 57 insertions(+), 90 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h index d8e33d38da43..18b27e6aecbc 100644 --- a/sound/soc/sh/rcar/rcar_snd.h +++ b/sound/soc/sh/rcar/rcar_snd.h @@ -32,8 +32,6 @@ * A : clock sharing settings * B : SSI direction */ -#define RSND_SSI_CLK_PIN_SHARE (1 << 31) -#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ #define RSND_SSI(_dma_id, _irq, _flags) \ { .dma_id = _dma_id, .irq = _irq, .flags = _flags } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 61957f609e79..1f1ecedabb5d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -61,32 +61,36 @@ #define SSI_NAME "ssi" struct rsnd_ssi { - struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ struct rsnd_ssi *parent; struct rsnd_mod mod; struct rsnd_mod *dma; + u32 flags; u32 cr_own; u32 cr_clk; u32 cr_mode; int chan; int rate; int err; + int irq; unsigned int usrcnt; }; +/* flags */ +#define RSND_SSI_CLK_PIN_SHARE (1 << 0) +#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ + #define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ (i < rsnd_ssi_nr(priv)) && \ ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ i++) +#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) #define rsnd_ssi_to_dma(mod) ((ssi)->dma) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_mode_flags(p) ((p)->info->flags) -#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) +#define rsnd_ssi_mode_flags(p) ((p)->flags) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) @@ -587,7 +591,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (ret < 0) return ret; - ret = devm_request_irq(dev, ssi->info->irq, + ret = devm_request_irq(dev, ssi->irq, rsnd_ssi_interrupt, IRQF_SHARED, dev_name(dev), mod); @@ -610,7 +614,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int dma_id = ssi->info->dma_id; + int dma_id = 0; /* not needed */ int ret; ret = rsnd_ssi_common_probe(mod, io, priv); @@ -630,7 +634,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->info->irq; + int irq = ssi->irq; /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); @@ -709,7 +713,7 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id); + return rsnd_mod_get(rsnd_ssi_get(priv, id)); } int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) @@ -719,73 +723,12 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -static void rsnd_of_parse_ssi(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct rsnd_ssi_platform_info *ssi_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr, i; - - node = rsnd_ssi_of_node(priv); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_ssi_end; - - ssi_info = devm_kzalloc(dev, - sizeof(struct rsnd_ssi_platform_info) * nr, - GFP_KERNEL); - if (!ssi_info) { - dev_err(dev, "ssi info allocation error\n"); - goto rsnd_of_parse_ssi_end; - } - - info->ssi_info = ssi_info; - info->ssi_info_nr = nr; - - i = -1; - for_each_child_of_node(node, np) { - i++; - - ssi_info = info->ssi_info + i; - - /* - * pin settings - */ - if (of_get_property(np, "shared-pin", NULL)) - ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE; - - /* - * irq - */ - ssi_info->irq = irq_of_parse_and_map(np, 0); - - /* - * DMA - */ - ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? - 0 : 1; - - if (of_get_property(np, "no-busif", NULL)) - ssi_info->flags |= RSND_SSI_NO_BUSIF; - } - -rsnd_of_parse_ssi_end: - of_node_put(node); -} - int rsnd_ssi_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_ssi_platform_info *pinfo; + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; struct clk *clk; @@ -793,44 +736,70 @@ int rsnd_ssi_probe(struct platform_device *pdev, char name[RSND_SSI_NAME_SIZE]; int i, nr, ret; - rsnd_of_parse_ssi(pdev, of_data, priv); + node = rsnd_ssi_of_node(priv); + if (!node) + return -EINVAL; + + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_ssi_probe_done; + } - /* - * init SSI - */ - nr = info->ssi_info_nr; ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); - if (!ssi) - return -ENOMEM; + if (!ssi) { + ret = -ENOMEM; + goto rsnd_ssi_probe_done; + } priv->ssi = ssi; priv->ssi_nr = nr; - for_each_rsnd_ssi(ssi, priv, i) { - pinfo = &info->ssi_info[i]; + i = 0; + for_each_child_of_node(node, np) { + ssi = rsnd_ssi_get(priv, i); snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", SSI_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_ssi_probe_done; + } - ssi->info = pinfo; + if (of_get_property(np, "shared-pin", NULL)) + ssi->flags |= RSND_SSI_CLK_PIN_SHARE; + + if (of_get_property(np, "no-busif", NULL)) + ssi->flags |= RSND_SSI_NO_BUSIF; + + ssi->irq = irq_of_parse_and_map(np, 0); + if (!ssi->irq) { + ret = -EINVAL; + goto rsnd_ssi_probe_done; + } ops = &rsnd_ssi_non_ops; - if (pinfo->dma_id > 0) - ops = &rsnd_ssi_dma_ops; - else if (rsnd_ssi_pio_available(ssi)) + if (of_get_property(np, "pio-transfer", NULL)) ops = &rsnd_ssi_pio_ops; + else + ops = &rsnd_ssi_dma_ops; ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, RSND_MOD_SSI, i); if (ret) - return ret; + goto rsnd_ssi_probe_done; + + i++; } - return 0; + ret = 0; + +rsnd_ssi_probe_done: + of_node_put(node); + + return ret; } void rsnd_ssi_remove(struct platform_device *pdev, -- cgit v1.2.3 From adf6a6815952c6c6092ae15e27c1b782fd96c6a3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:11:55 +0000 Subject: ASoC: rsnd: remove platform boot support from src.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from src.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 158 +++++++++++++----------------------------------- 1 file changed, 43 insertions(+), 115 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 230db9f81377..f965fea7aa50 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -20,17 +20,18 @@ #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) struct rsnd_src { - struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct rsnd_mod *dma; struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ int err; + int irq; }; #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) #define rsnd_src_to_dma(src) ((src)->dma) #define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) @@ -69,52 +70,6 @@ struct rsnd_src { * |-----------------| */ -/* - * How to use SRC bypass mode for debugging - * - * SRC has bypass mode, and it is useful for debugging. - * In Gen2 case, - * SRCm_MODE controls whether SRC is used or not - * SSI_MODE0 controls whether SSIU which receives SRC data - * is used or not. - * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC, - * but SRC bypass mode needs SSI_MODE0 only. - * - * This driver request - * struct rsnd_src_platform_info { - * u32 convert_rate; - * int dma_id; - * } - * - * rsnd_src_convert_rate() indicates - * above convert_rate, and it controls - * whether SRC is used or not. - * - * ex) doesn't use SRC - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], }, - * }; - * - * ex) uses SRC - * static struct rsnd_src_platform_info rsnd_src[] = { - * RSND_SCU(48000, 0), - * ... - * }; - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, - * }; - * - * ex) uses SRC bypass mode - * static struct rsnd_src_platform_info rsnd_src[] = { - * RSND_SCU(0, 0), - * ... - * }; - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, - * }; - * - */ - static void rsnd_src_soft_reset(struct rsnd_mod *mod) { rsnd_mod_write(mod, SRC_SWRSR, 0); @@ -187,9 +142,6 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, struct rsnd_src *src = rsnd_mod_to_src(mod); struct snd_soc_pcm_runtime *fe = substream->private_data; - /* default value (mainly for non-DT) */ - src->convert_rate = src->info->convert_rate; - /* * SRC assumes that it is used under DPCM if user want to use * sampling rate convert. Then, SRC should be FE. @@ -318,7 +270,7 @@ static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 sys_int_val, int_val, sys_int_mask; - int irq = src->info->irq; + int irq = src->irq; int id = rsnd_mod_id(mod); sys_int_val = @@ -517,7 +469,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); - int irq = src->info->irq; + int irq = src->irq; int ret; if (irq > 0) { @@ -534,7 +486,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; } - src->dma = rsnd_dma_attach(io, mod, src->info->dma_id); + src->dma = rsnd_dma_attach(io, mod, 0); if (IS_ERR(src->dma)) return PTR_ERR(src->dma); @@ -598,58 +550,15 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_src *)(priv->src) + id); -} - -static void rsnd_of_parse_src(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct device_node *src_node; - struct device_node *np; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_src_platform_info *src_info; - struct device *dev = &pdev->dev; - int nr, i; - - if (!of_data) - return; - - src_node = rsnd_src_of_node(priv); - if (!src_node) - return; - - nr = of_get_child_count(src_node); - if (!nr) - goto rsnd_of_parse_src_end; - - src_info = devm_kzalloc(dev, - sizeof(struct rsnd_src_platform_info) * nr, - GFP_KERNEL); - if (!src_info) { - dev_err(dev, "src info allocation error\n"); - goto rsnd_of_parse_src_end; - } - - info->src_info = src_info; - info->src_info_nr = nr; - - i = 0; - for_each_child_of_node(src_node, np) { - src_info[i].irq = irq_of_parse_and_map(np, 0); - - i++; - } - -rsnd_of_parse_src_end: - of_node_put(src_node); + return rsnd_mod_get(rsnd_src_get(priv, id)); } int rsnd_src_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_src *src; struct clk *clk; @@ -660,39 +569,58 @@ int rsnd_src_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_src(pdev, of_data, priv); + node = rsnd_src_of_node(priv); + if (!node) + return 0; /* not used is not error */ - /* - * init SRC - */ - nr = info->src_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_src_probe_done; + } src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); - if (!src) - return -ENOMEM; + if (!src) { + ret = -ENOMEM; + goto rsnd_src_probe_done; + } priv->src_nr = nr; priv->src = src; - for_each_rsnd_src(src, priv, i) { + i = 0; + for_each_child_of_node(node, np) { + src = rsnd_src_get(priv, i); + snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", SRC_NAME, i); - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); + src->irq = irq_of_parse_and_map(np, 0); + if (!src->irq) { + ret = -EINVAL; + goto rsnd_src_probe_done; + } - src->info = &info->src_info[i]; + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_src_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(src), &rsnd_src_ops, clk, RSND_MOD_SRC, i); if (ret) - return ret; + goto rsnd_src_probe_done; + + i++; } - return 0; + ret = 0; + +rsnd_src_probe_done: + of_node_put(node); + + return ret; } void rsnd_src_remove(struct platform_device *pdev, -- cgit v1.2.3 From cfe7c0390ac24c30bf8c79a6a05e637db56e3090 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:12:13 +0000 Subject: ASoC: rsnd: remove platform boot support from ctu.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from ctu.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 85 +++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 53 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index daa1017c8890..9506db4958bc 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -13,7 +13,6 @@ #define CTU_NAME "ctu" struct rsnd_ctu { - struct rsnd_ctu_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; }; @@ -24,6 +23,7 @@ struct rsnd_ctu { ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ i++) +#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) @@ -74,51 +74,15 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id); -} - -static void rsnd_of_parse_ctu(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct device_node *node; - struct rsnd_ctu_platform_info *ctu_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = rsnd_ctu_of_node(priv); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_ctu_end; - - ctu_info = devm_kzalloc(dev, - sizeof(struct rsnd_ctu_platform_info) * nr, - GFP_KERNEL); - if (!ctu_info) { - dev_err(dev, "ctu info allocation error\n"); - goto rsnd_of_parse_ctu_end; - } - - info->ctu_info = ctu_info; - info->ctu_info_nr = nr; - -rsnd_of_parse_ctu_end: - of_node_put(node); - + return rsnd_mod_get(rsnd_ctu_get(priv, id)); } int rsnd_ctu_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ctu *ctu; struct clk *clk; @@ -129,20 +93,29 @@ int rsnd_ctu_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_ctu(pdev, of_data, priv); + node = rsnd_ctu_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->ctu_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_ctu_probe_done; + } ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); - if (!ctu) - return -ENOMEM; + if (!ctu) { + ret = -ENOMEM; + goto rsnd_ctu_probe_done; + } priv->ctu_nr = nr; priv->ctu = ctu; - for_each_rsnd_ctu(ctu, priv, i) { + i = 0; + for_each_child_of_node(node, np) { + ctu = rsnd_ctu_get(priv, i); + /* * CTU00, CTU01, CTU02, CTU03 => CTU0 * CTU10, CTU11, CTU12, CTU13 => CTU1 @@ -151,18 +124,24 @@ int rsnd_ctu_probe(struct platform_device *pdev, CTU_NAME, i / 4); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ctu->info = &info->ctu_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_ctu_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, clk, RSND_MOD_CTU, i); if (ret) - return ret; + goto rsnd_ctu_probe_done; + + i++; } - return 0; + +rsnd_ctu_probe_done: + of_node_put(node); + + return ret; } void rsnd_ctu_remove(struct platform_device *pdev, -- cgit v1.2.3 From c7fe4be840026d7cdb0676e1d52b9f82e8b32d41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:12:32 +0000 Subject: ASoC: rsnd: remove platform boot support from mix.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from mix.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/mix.c | 85 ++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 54 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 195bc748a32f..8b615c7aecb4 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -13,10 +13,10 @@ #define MIX_NAME "mix" struct rsnd_mix { - struct rsnd_mix_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; }; +#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) #define rsnd_mix_nr(priv) ((priv)->mix_nr) #define for_each_rsnd_mix(pos, priv, i) \ for ((i) = 0; \ @@ -24,7 +24,6 @@ struct rsnd_mix { ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ i++) - static void rsnd_mix_soft_reset(struct rsnd_mod *mod) { rsnd_mod_write(mod, MIX_SWRSR, 0); @@ -114,51 +113,15 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id); -} - -static void rsnd_of_parse_mix(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct device_node *node; - struct rsnd_mix_platform_info *mix_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = rsnd_mix_of_node(priv); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_mix_end; - - mix_info = devm_kzalloc(dev, - sizeof(struct rsnd_mix_platform_info) * nr, - GFP_KERNEL); - if (!mix_info) { - dev_err(dev, "mix info allocation error\n"); - goto rsnd_of_parse_mix_end; - } - - info->mix_info = mix_info; - info->mix_info_nr = nr; - -rsnd_of_parse_mix_end: - of_node_put(node); - + return rsnd_mod_get(rsnd_mix_get(priv, id)); } int rsnd_mix_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mix *mix; struct clk *clk; @@ -169,36 +132,50 @@ int rsnd_mix_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_mix(pdev, of_data, priv); + node = rsnd_mix_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->mix_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_mix_probe_done; + } mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); - if (!mix) - return -ENOMEM; + if (!mix) { + ret = -ENOMEM; + goto rsnd_mix_probe_done; + } priv->mix_nr = nr; priv->mix = mix; - for_each_rsnd_mix(mix, priv, i) { + i = 0; + for_each_child_of_node(node, np) { + mix = rsnd_mix_get(priv, i); + snprintf(name, MIX_NAME_SIZE, "%s.%d", MIX_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - mix->info = &info->mix_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_mix_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, clk, RSND_MOD_MIX, i); if (ret) - return ret; + goto rsnd_mix_probe_done; + + i++; } - return 0; +rsnd_mix_probe_done: + of_node_put(node); + + return ret; } void rsnd_mix_remove(struct platform_device *pdev, -- cgit v1.2.3 From 9eaa1a6f7e31ead7e2b8eb762455e77376bd87cc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:12:50 +0000 Subject: ASoC: rsnd: remove platform boot support from dvc.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from dvc.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 83 ++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d2bd4804db0d..a550b75ff9ac 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -15,7 +15,6 @@ #define DVC_NAME "dvc" struct rsnd_dvc { - struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct rsnd_kctrl_cfg_m volume; struct rsnd_kctrl_cfg_m mute; @@ -24,6 +23,7 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ }; +#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") @@ -301,50 +301,15 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id); -} - -static void rsnd_of_parse_dvc(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct device_node *node; - struct rsnd_dvc_platform_info *dvc_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = rsnd_dvc_of_node(priv); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_dvc_end; - - dvc_info = devm_kzalloc(dev, - sizeof(struct rsnd_dvc_platform_info) * nr, - GFP_KERNEL); - if (!dvc_info) { - dev_err(dev, "dvc info allocation error\n"); - goto rsnd_of_parse_dvc_end; - } - - info->dvc_info = dvc_info; - info->dvc_info_nr = nr; - -rsnd_of_parse_dvc_end: - of_node_put(node); + return rsnd_mod_get(rsnd_dvc_get(priv, id)); } int rsnd_dvc_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dvc *dvc; struct clk *clk; @@ -355,36 +320,50 @@ int rsnd_dvc_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_dvc(pdev, of_data, priv); + node = rsnd_dvc_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->dvc_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_dvc_probe_done; + } dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); - if (!dvc) - return -ENOMEM; + if (!dvc) { + ret = -ENOMEM; + goto rsnd_dvc_probe_done; + } priv->dvc_nr = nr; priv->dvc = dvc; - for_each_rsnd_dvc(dvc, priv, i) { + i = 0; + for_each_child_of_node(node, np) { + dvc = rsnd_dvc_get(priv, i); + snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", DVC_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - dvc->info = &info->dvc_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_dvc_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, clk, RSND_MOD_DVC, i); if (ret) - return ret; + goto rsnd_dvc_probe_done; + + i++; } - return 0; +rsnd_dvc_probe_done: + of_node_put(node); + + return ret; } void rsnd_dvc_remove(struct platform_device *pdev, -- cgit v1.2.3 From 348d592c719da61a7dab289c7ce36e73c7caf063 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:13:12 +0000 Subject: ASoC: rsnd: remove platform boot support from gen.c No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. This patch removes platform boot support from gen.c Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 + sound/soc/sh/rcar/gen.c | 14 -------------- sound/soc/sh/rcar/rsnd.h | 7 ++++--- 3 files changed, 5 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 039d6cba8414..6043c71d10c9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1037,6 +1037,7 @@ static int rsnd_probe(struct platform_device *pdev) priv->pdev = pdev; priv->info = info; + priv->flags = of_data->flags; spin_lock_init(&priv->lock); /* diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 1808fc64646c..099a1cd2d245 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -349,18 +349,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev, /* * Gen */ -static void rsnd_of_parse_gen(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = priv->info; - - if (!of_data) - return; - - info->flags = of_data->flags; -} - int rsnd_gen_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) @@ -369,8 +357,6 @@ int rsnd_gen_probe(struct platform_device *pdev, struct rsnd_gen *gen; int ret; - rsnd_of_parse_gen(pdev, of_data, priv); - gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); if (!gen) { dev_err(dev, "GEN allocate failed\n"); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 23507c8d79c2..c1cf16db6405 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -352,9 +352,6 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, enum rsnd_reg reg); phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); -#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) -#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) - /* * R-Car ADG */ @@ -386,6 +383,7 @@ struct rsnd_priv { struct platform_device *pdev; struct rcar_snd_info *info; spinlock_t lock; + u32 flags; /* * below value will be filled on rsnd_gen_probe() @@ -456,6 +454,9 @@ struct rsnd_priv { #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) #define rsnd_priv_to_info(priv) ((priv)->info) +#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) +#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) + /* * rsnd_kctrl */ -- cgit v1.2.3 From e797f58ead6069478e535ae62b180da87b28a84f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:13:33 +0000 Subject: ASoC: rsnd: remove struct rsnd_of_data No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. Now, platform boot style was removed from driver. This is cleanup patch, and remove pointless struct rsnd_of_data Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 1 - sound/soc/sh/rcar/cmd.c | 1 - sound/soc/sh/rcar/core.c | 25 +++++-------------------- sound/soc/sh/rcar/ctu.c | 1 - sound/soc/sh/rcar/dma.c | 1 - sound/soc/sh/rcar/dvc.c | 1 - sound/soc/sh/rcar/gen.c | 1 - sound/soc/sh/rcar/mix.c | 1 - sound/soc/sh/rcar/rsnd.h | 15 --------------- sound/soc/sh/rcar/src.c | 1 - sound/soc/sh/rcar/ssi.c | 1 - sound/soc/sh/rcar/ssiu.c | 1 - 12 files changed, 5 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 1dffde3218be..ba80961a8fa8 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -516,7 +516,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } int rsnd_adg_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct rsnd_adg *adg; diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 47ef47c22217..2294c5c7a25a 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -128,7 +128,6 @@ struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) } int rsnd_cmd_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 6043c71d10c9..8b9d721acb41 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -99,18 +99,10 @@ #define RSND_RATES SNDRV_PCM_RATE_8000_96000 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) -static const struct rsnd_of_data rsnd_of_data_gen1 = { - .flags = RSND_GEN1, -}; - -static const struct rsnd_of_data rsnd_of_data_gen2 = { - .flags = RSND_GEN2, -}; - static const struct of_device_id rsnd_of_match[] = { - { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 }, - { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 }, - { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */ + { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, + { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, + { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */ {}, }; MODULE_DEVICE_TABLE(of, rsnd_of_match); @@ -569,7 +561,6 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { }; static int rsnd_dai_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *dai_node; @@ -583,9 +574,6 @@ static int rsnd_dai_probe(struct platform_device *pdev, int nr, dai_i, io_i, np_i; int ret; - if (!of_data) - return 0; - dai_node = rsnd_dai_of_node(priv); nr = of_get_child_count(dai_node); if (!nr) { @@ -1002,9 +990,7 @@ static int rsnd_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rsnd_dai *rdai; const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); - const struct rsnd_of_data *of_data; int (*probe_func[])(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) = { rsnd_gen_probe, rsnd_dma_probe, @@ -1024,7 +1010,6 @@ static int rsnd_probe(struct platform_device *pdev) GFP_KERNEL); if (!info) return -ENOMEM; - of_data = of_id->data; /* * init priv data @@ -1037,14 +1022,14 @@ static int rsnd_probe(struct platform_device *pdev) priv->pdev = pdev; priv->info = info; - priv->flags = of_data->flags; + priv->flags = (u32)of_id->data; spin_lock_init(&priv->lock); /* * init each module */ for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](pdev, of_data, priv); + ret = probe_func[i](pdev, priv); if (ret) return ret; } diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 9506db4958bc..3e36a5325ce4 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -78,7 +78,6 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) } int rsnd_ctu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *node; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 9917b985c403..e5f435361d96 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -702,7 +702,6 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, } int rsnd_dma_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index a550b75ff9ac..d2c03bd94fcb 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -305,7 +305,6 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) } int rsnd_dvc_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *node; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 099a1cd2d245..ced8acb7a7ec 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -350,7 +350,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev, * Gen */ int rsnd_gen_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 8b615c7aecb4..897e4f3d4c24 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -117,7 +117,6 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) } int rsnd_mix_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *node; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c1cf16db6405..0ad3d0d20a81 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -115,7 +115,6 @@ enum rsnd_reg { RSND_REG_MAX, }; -struct rsnd_of_data; struct rsnd_priv; struct rsnd_mod; struct rsnd_dai; @@ -150,7 +149,6 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); int rsnd_dma_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -345,7 +343,6 @@ int rsnd_dai_connect(struct rsnd_mod *mod, * R-Car Gen1/Gen2 */ int rsnd_gen_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, @@ -358,7 +355,6 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); int rsnd_adg_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_adg_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -374,10 +370,6 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, /* * R-Car sound priv */ -struct rsnd_of_data { - u32 flags; -}; - struct rsnd_priv { struct platform_device *pdev; @@ -515,7 +507,6 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, * R-Car SSI */ int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_ssi_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -536,7 +527,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int rsnd_ssiu_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod); int rsnd_ssiu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_ssiu_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -545,7 +535,6 @@ void rsnd_ssiu_remove(struct platform_device *pdev, * R-Car SRC */ int rsnd_src_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_src_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -560,7 +549,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, * R-Car CTU */ int rsnd_ctu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_ctu_remove(struct platform_device *pdev, @@ -573,7 +561,6 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); * R-Car MIX */ int rsnd_mix_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_mix_remove(struct platform_device *pdev, @@ -586,7 +573,6 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); * R-Car DVC */ int rsnd_dvc_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_dvc_remove(struct platform_device *pdev, struct rsnd_priv *priv); @@ -598,7 +584,6 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); * R-Car CMD */ int rsnd_cmd_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv); void rsnd_cmd_remove(struct platform_device *pdev, struct rsnd_priv *priv); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index f965fea7aa50..c0f7e2a4b688 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -554,7 +554,6 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) } int rsnd_src_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *node; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 1f1ecedabb5d..848c06436226 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -724,7 +724,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) } int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device_node *node; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index fc5ec17fe37e..89b1bc77cb8a 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -137,7 +137,6 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, } int rsnd_ssiu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); -- cgit v1.2.3 From 2ea2cc86db7c73dc4e3a9fc3232cb04fe1b1ab91 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:13:53 +0000 Subject: ASoC: rsnd: remove struct rcar_snd_info No board is using Renesas sound driver via platform boot now. This means all user is using DT boot. Platform boot support is no longer needed. But, it strongly depends on platform boot style. Now, platform boot style was removed from driver. This is cleanup patch, and remove pointless struct rcar_snd_info Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 21 -------- sound/soc/sh/rcar/rcar_snd.h | 115 ------------------------------------------- sound/soc/sh/rcar/rsnd.h | 16 ++++-- 3 files changed, 13 insertions(+), 139 deletions(-) delete mode 100644 sound/soc/sh/rcar/rcar_snd.h (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8b9d721acb41..8af166809629 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -107,13 +107,6 @@ static const struct of_device_id rsnd_of_match[] = { }; MODULE_DEVICE_TABLE(of, rsnd_of_match); -/* - * rsnd_platform functions - */ -#define rsnd_platform_call(priv, dai, func, param...) \ - (!(priv->info->func) ? 0 : \ - priv->info->func(param)) - /* * rsnd_mod functions */ @@ -457,7 +450,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct rsnd_priv *priv = rsnd_dai_to_priv(dai); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); int ret; unsigned long flags; @@ -467,10 +459,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: rsnd_dai_stream_init(io, substream); - ret = rsnd_platform_call(priv, dai, start, ssi_id); - if (ret < 0) - goto dai_trigger_end; - ret = rsnd_dai_call(init, io, priv); if (ret < 0) goto dai_trigger_end; @@ -484,8 +472,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret |= rsnd_dai_call(quit, io, priv); - ret |= rsnd_platform_call(priv, dai, stop, ssi_id); - rsnd_dai_stream_quit(io); break; default: @@ -985,7 +971,6 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, */ static int rsnd_probe(struct platform_device *pdev) { - struct rcar_snd_info *info; struct rsnd_priv *priv; struct device *dev = &pdev->dev; struct rsnd_dai *rdai; @@ -1006,11 +991,6 @@ static int rsnd_probe(struct platform_device *pdev) }; int ret, i; - info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - /* * init priv data */ @@ -1021,7 +1001,6 @@ static int rsnd_probe(struct platform_device *pdev) } priv->pdev = pdev; - priv->info = info; priv->flags = (u32)of_id->data; spin_lock_init(&priv->lock); diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h deleted file mode 100644 index 18b27e6aecbc..000000000000 --- a/sound/soc/sh/rcar/rcar_snd.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Renesas R-Car SRU/SCU/SSIU/SSI support - * - * Copyright (C) 2013 Renesas Solutions Corp. - * Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef RCAR_SND_H -#define RCAR_SND_H - - -#define RSND_GEN1_SRU 0 -#define RSND_GEN1_ADG 1 -#define RSND_GEN1_SSI 2 - -#define RSND_GEN2_SCU 0 -#define RSND_GEN2_ADG 1 -#define RSND_GEN2_SSIU 2 -#define RSND_GEN2_SSI 3 - -#define RSND_BASE_MAX 4 - -/* - * flags - * - * 0xAB000000 - * - * A : clock sharing settings - * B : SSI direction - */ - -#define RSND_SSI(_dma_id, _irq, _flags) \ -{ .dma_id = _dma_id, .irq = _irq, .flags = _flags } -#define RSND_SSI_UNUSED \ -{ .dma_id = -1, .irq = -1, .flags = 0 } - -struct rsnd_ssi_platform_info { - int dma_id; - int irq; - u32 flags; -}; - -#define RSND_SRC(rate, _dma_id) \ -{ .convert_rate = rate, .dma_id = _dma_id, } -#define RSND_SRC_UNUSED \ -{ .convert_rate = 0, .dma_id = -1, } - -struct rsnd_src_platform_info { - u32 convert_rate; /* sampling rate convert */ - int dma_id; /* for Gen2 SCU */ - int irq; -}; - -/* - * flags - */ -struct rsnd_ctu_platform_info { - u32 flags; -}; - -struct rsnd_mix_platform_info { - u32 flags; -}; - -struct rsnd_dvc_platform_info { - u32 flags; -}; - -struct rsnd_dai_path_info { - struct rsnd_ssi_platform_info *ssi; - struct rsnd_src_platform_info *src; - struct rsnd_ctu_platform_info *ctu; - struct rsnd_mix_platform_info *mix; - struct rsnd_dvc_platform_info *dvc; -}; - -struct rsnd_dai_platform_info { - struct rsnd_dai_path_info playback; - struct rsnd_dai_path_info capture; -}; - -/* - * flags - * - * 0x0000000A - * - * A : generation - */ -#define RSND_GEN_MASK (0xF << 0) -#define RSND_GEN1 (1 << 0) /* fixme */ -#define RSND_GEN2 (2 << 0) /* fixme */ - -struct rcar_snd_info { - u32 flags; - struct rsnd_ssi_platform_info *ssi_info; - int ssi_info_nr; - struct rsnd_src_platform_info *src_info; - int src_info_nr; - struct rsnd_ctu_platform_info *ctu_info; - int ctu_info_nr; - struct rsnd_mix_platform_info *mix_info; - int mix_info_nr; - struct rsnd_dvc_platform_info *dvc_info; - int dvc_info_nr; - struct rsnd_dai_platform_info *dai_info; - int dai_info_nr; - int (*start)(int id); - int (*stop)(int id); -}; - -#endif diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 0ad3d0d20a81..e6efac29113d 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -24,7 +24,16 @@ #include #include -#include "rcar_snd.h" +#define RSND_GEN1_SRU 0 +#define RSND_GEN1_ADG 1 +#define RSND_GEN1_SSI 2 + +#define RSND_GEN2_SCU 0 +#define RSND_GEN2_ADG 1 +#define RSND_GEN2_SSIU 2 +#define RSND_GEN2_SSI 3 + +#define RSND_BASE_MAX 4 /* * pseudo register @@ -373,9 +382,11 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, struct rsnd_priv { struct platform_device *pdev; - struct rcar_snd_info *info; spinlock_t lock; u32 flags; +#define RSND_GEN_MASK (0xF << 0) +#define RSND_GEN1 (1 << 0) +#define RSND_GEN2 (2 << 0) /* * below value will be filled on rsnd_gen_probe() @@ -444,7 +455,6 @@ struct rsnd_priv { #define rsnd_priv_to_pdev(priv) ((priv)->pdev) #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) -#define rsnd_priv_to_info(priv) ((priv)->info) #define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) -- cgit v1.2.3 From 2ea6b0749c366787dbf6e87c7642e23b448ca63b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 05:14:12 +0000 Subject: ASoC: rsnd: remove struct platform_device from probe/remove parameter Current Renesas sound driver requests struct platform_device on probe/remove for each modules. But driver can get it by rsnd_priv_to_pdev(). This patch removes unnecessary parameter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 6 ++---- sound/soc/sh/rcar/cmd.c | 6 ++---- sound/soc/sh/rcar/core.c | 15 ++++++------- sound/soc/sh/rcar/ctu.c | 6 ++---- sound/soc/sh/rcar/dma.c | 4 ++-- sound/soc/sh/rcar/dvc.c | 6 ++---- sound/soc/sh/rcar/gen.c | 13 +++++------ sound/soc/sh/rcar/mix.c | 6 ++---- sound/soc/sh/rcar/rsnd.h | 56 ++++++++++++++++-------------------------------- sound/soc/sh/rcar/src.c | 6 ++---- sound/soc/sh/rcar/ssi.c | 6 ++---- sound/soc/sh/rcar/ssiu.c | 6 ++---- 12 files changed, 47 insertions(+), 89 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index ba80961a8fa8..448f082ab56d 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -515,8 +515,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ckr, rbga, rbgb); } -int rsnd_adg_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_adg_probe(struct rsnd_priv *priv) { struct rsnd_adg *adg; struct device *dev = rsnd_priv_to_dev(priv); @@ -543,8 +542,7 @@ int rsnd_adg_probe(struct platform_device *pdev, return 0; } -void rsnd_adg_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_adg_remove(struct rsnd_priv *priv) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct clk *clk; diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 2294c5c7a25a..ab904c3f20b5 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -127,8 +127,7 @@ struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); } -int rsnd_cmd_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_cmd_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_cmd *cmd; @@ -160,8 +159,7 @@ int rsnd_cmd_probe(struct platform_device *pdev, return 0; } -void rsnd_cmd_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_cmd_remove(struct rsnd_priv *priv) { struct rsnd_cmd *cmd; int i; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8af166809629..8dceae4b731a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -546,8 +546,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; -static int rsnd_dai_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +static int rsnd_dai_probe(struct rsnd_priv *priv) { struct device_node *dai_node; struct device_node *dai_np, *np, *node; @@ -556,7 +555,7 @@ static int rsnd_dai_probe(struct platform_device *pdev, struct rsnd_dai_stream *io_capture; struct snd_soc_dai_driver *drv; struct rsnd_dai *rdai; - struct device *dev = &pdev->dev; + struct device *dev = rsnd_priv_to_dev(priv); int nr, dai_i, io_i, np_i; int ret; @@ -975,8 +974,7 @@ static int rsnd_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rsnd_dai *rdai; const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); - int (*probe_func[])(struct platform_device *pdev, - struct rsnd_priv *priv) = { + int (*probe_func[])(struct rsnd_priv *priv) = { rsnd_gen_probe, rsnd_dma_probe, rsnd_ssi_probe, @@ -1008,7 +1006,7 @@ static int rsnd_probe(struct platform_device *pdev) * init each module */ for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](pdev, priv); + ret = probe_func[i](priv); if (ret) return ret; } @@ -1061,8 +1059,7 @@ static int rsnd_remove(struct platform_device *pdev) { struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); struct rsnd_dai *rdai; - void (*remove_func[])(struct platform_device *pdev, - struct rsnd_priv *priv) = { + void (*remove_func[])(struct rsnd_priv *priv) = { rsnd_ssi_remove, rsnd_ssiu_remove, rsnd_src_remove, @@ -1082,7 +1079,7 @@ static int rsnd_remove(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(remove_func); i++) - remove_func[i](pdev, priv); + remove_func[i](priv); snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 3e36a5325ce4..7c1e190cd389 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -77,8 +77,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get(rsnd_ctu_get(priv, id)); } -int rsnd_ctu_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_ctu_probe(struct rsnd_priv *priv) { struct device_node *node; struct device_node *np; @@ -143,8 +142,7 @@ rsnd_ctu_probe_done: return ret; } -void rsnd_ctu_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_ctu_remove(struct rsnd_priv *priv) { struct rsnd_ctu *ctu; int i; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index e5f435361d96..33eb37331498 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -701,9 +701,9 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, return rsnd_mod_get(dma); } -int rsnd_dma_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_dma_probe(struct rsnd_priv *priv) { + struct platform_device *pdev = rsnd_priv_to_pdev(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dma_ctrl *dmac; struct resource *res; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d2c03bd94fcb..0f61e1344431 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -304,8 +304,7 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get(rsnd_dvc_get(priv, id)); } -int rsnd_dvc_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_dvc_probe(struct rsnd_priv *priv) { struct device_node *node; struct device_node *np; @@ -365,8 +364,7 @@ rsnd_dvc_probe_done: return ret; } -void rsnd_dvc_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_dvc_remove(struct rsnd_priv *priv) { struct rsnd_dvc *dvc; int i; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index ced8acb7a7ec..84f8bb223439 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -211,8 +211,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, /* * Gen2 */ -static int rsnd_gen2_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +static int rsnd_gen2_probe(struct rsnd_priv *priv) { struct rsnd_regmap_field_conf conf_ssiu[] = { RSND_GEN_S_REG(SSI_MODE0, 0x800), @@ -317,8 +316,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, * Gen1 */ -static int rsnd_gen1_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +static int rsnd_gen1_probe(struct rsnd_priv *priv) { struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), @@ -349,8 +347,7 @@ static int rsnd_gen1_probe(struct platform_device *pdev, /* * Gen */ -int rsnd_gen_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_gen_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen; @@ -366,9 +363,9 @@ int rsnd_gen_probe(struct platform_device *pdev, ret = -ENODEV; if (rsnd_is_gen1(priv)) - ret = rsnd_gen1_probe(pdev, priv); + ret = rsnd_gen1_probe(priv); else if (rsnd_is_gen2(priv)) - ret = rsnd_gen2_probe(pdev, priv); + ret = rsnd_gen2_probe(priv); if (ret < 0) dev_err(dev, "unknown generation R-Car sound device\n"); diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 897e4f3d4c24..57ac453adcef 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -116,8 +116,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get(rsnd_mix_get(priv, id)); } -int rsnd_mix_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_mix_probe(struct rsnd_priv *priv) { struct device_node *node; struct device_node *np; @@ -177,8 +176,7 @@ rsnd_mix_probe_done: return ret; } -void rsnd_mix_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_mix_remove(struct rsnd_priv *priv) { struct rsnd_mix *mix; int i; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e6efac29113d..ae69670c5c0c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -157,8 +157,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); */ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, int id); -int rsnd_dma_probe(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -351,8 +350,7 @@ int rsnd_dai_connect(struct rsnd_mod *mod, /* * R-Car Gen1/Gen2 */ -int rsnd_gen_probe(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_gen_probe(struct rsnd_priv *priv); void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); @@ -363,10 +361,8 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); */ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); -int rsnd_adg_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_adg_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_adg_probe(struct rsnd_priv *priv); +void rsnd_adg_remove(struct rsnd_priv *priv); int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, unsigned int src_rate, @@ -516,10 +512,8 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, /* * R-Car SSI */ -int rsnd_ssi_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_ssi_probe(struct rsnd_priv *priv); +void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); @@ -536,18 +530,14 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); */ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod); -int rsnd_ssiu_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_ssiu_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_ssiu_probe(struct rsnd_priv *priv); +void rsnd_ssiu_remove(struct rsnd_priv *priv); /* * R-Car SRC */ -int rsnd_src_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_src_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_src_probe(struct rsnd_priv *priv); +void rsnd_src_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, @@ -558,11 +548,8 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, /* * R-Car CTU */ -int rsnd_ctu_probe(struct platform_device *pdev, - struct rsnd_priv *priv); - -void rsnd_ctu_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_ctu_probe(struct rsnd_priv *priv); +void rsnd_ctu_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); #define rsnd_ctu_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") @@ -570,11 +557,8 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); /* * R-Car MIX */ -int rsnd_mix_probe(struct platform_device *pdev, - struct rsnd_priv *priv); - -void rsnd_mix_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_mix_probe(struct rsnd_priv *priv); +void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); #define rsnd_mix_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") @@ -582,10 +566,8 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); /* * R-Car DVC */ -int rsnd_dvc_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_dvc_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_dvc_probe(struct rsnd_priv *priv); +void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") @@ -593,10 +575,8 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); /* * R-Car CMD */ -int rsnd_cmd_probe(struct platform_device *pdev, - struct rsnd_priv *priv); -void rsnd_cmd_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_cmd_probe(struct rsnd_priv *priv); +void rsnd_cmd_remove(struct rsnd_priv *priv); int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c0f7e2a4b688..c103aa775e96 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -553,8 +553,7 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) return rsnd_mod_get(rsnd_src_get(priv, id)); } -int rsnd_src_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_src_probe(struct rsnd_priv *priv) { struct device_node *node; struct device_node *np; @@ -622,8 +621,7 @@ rsnd_src_probe_done: return ret; } -void rsnd_src_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_src_remove(struct rsnd_priv *priv) { struct rsnd_src *src; int i; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 848c06436226..0fe5e3068b6b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -723,8 +723,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -int rsnd_ssi_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_ssi_probe(struct rsnd_priv *priv) { struct device_node *node; struct device_node *np; @@ -801,8 +800,7 @@ rsnd_ssi_probe_done: return ret; } -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_ssi_remove(struct rsnd_priv *priv) { struct rsnd_ssi *ssi; int i; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 89b1bc77cb8a..bc245047e904 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -136,8 +136,7 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, return rsnd_dai_connect(mod, io, mod->type); } -int rsnd_ssiu_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +int rsnd_ssiu_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ssiu *ssiu; @@ -168,8 +167,7 @@ int rsnd_ssiu_probe(struct platform_device *pdev, return 0; } -void rsnd_ssiu_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_ssiu_remove(struct rsnd_priv *priv) { struct rsnd_ssiu *ssiu; int i; -- cgit v1.2.3 From 9bf5c3d11f1fbaf43399d189f05fb20ceb46ee5d Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 11 Nov 2015 13:12:51 +0100 Subject: ASoC: ac97: add gpio chip The AC97 specification provides a guide for 16 GPIOs in the codecs. If the gpiolib is compiled in the kernel, declare a gpio chip. This was tested with a pxa27x board (mioa701) and a wm9713 codec. Signed-off-by: Robert Jarzmik Signed-off-by: Mark Brown --- include/sound/ac97_codec.h | 3 ++ sound/soc/soc-ac97.c | 125 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) (limited to 'sound') diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 74bc85473b58..15aa5f07c955 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -417,11 +417,13 @@ #define AC97_RATES_MIC_ADC 4 #define AC97_RATES_SPDIF 5 +#define AC97_NUM_GPIOS 16 /* * */ struct snd_ac97; +struct snd_ac97_gpio_priv; struct snd_pcm_chmap; struct snd_ac97_build_ops { @@ -529,6 +531,7 @@ struct snd_ac97 { struct delayed_work power_work; #endif struct device dev; + struct snd_ac97_gpio_priv *gpio_priv; struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */ }; diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index d40efc9fe0a9..ae563e379a72 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,14 @@ struct snd_ac97_reset_cfg { int gpio_reset; }; +struct snd_ac97_gpio_priv { +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif + unsigned int gpios_set; + struct snd_soc_codec *codec; +}; + static struct snd_ac97_bus soc_ac97_bus = { .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ }; @@ -47,6 +56,117 @@ static void soc_ac97_device_release(struct device *dev) kfree(to_ac97_t(dev)); } +#ifdef CONFIG_GPIOLIB +static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip) +{ + struct snd_ac97_gpio_priv *gpio_priv = + container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + + return gpio_priv->codec; +} + +static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + if (offset >= AC97_NUM_GPIOS) + return -EINVAL; + + return 0; +} + +static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, + unsigned offset) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + + dev_dbg(codec->dev, "set gpio %d to output\n", offset); + return snd_soc_update_bits(codec, AC97_GPIO_CFG, + 1 << offset, 1 << offset); +} + +static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + int ret; + + ret = snd_soc_read(codec, AC97_GPIO_STATUS); + dev_dbg(codec->dev, "get gpio %d : %d\n", offset, + ret < 0 ? ret : ret & (1 << offset)); + + return ret < 0 ? ret : ret & (1 << offset); +} + +static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct snd_ac97_gpio_priv *gpio_priv = + container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + struct snd_soc_codec *codec = gpio_to_codec(chip); + + gpio_priv->gpios_set &= ~(1 << offset); + gpio_priv->gpios_set |= (!!value) << offset; + snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set); + dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value); +} + +static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + + dev_dbg(codec->dev, "set gpio %d to output\n", offset); + snd_soc_ac97_gpio_set(chip, offset, value); + return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0); +} + +static struct gpio_chip snd_soc_ac97_gpio_chip = { + .label = "snd_soc_ac97", + .owner = THIS_MODULE, + .request = snd_soc_ac97_gpio_request, + .direction_input = snd_soc_ac97_gpio_direction_in, + .get = snd_soc_ac97_gpio_get, + .direction_output = snd_soc_ac97_gpio_direction_out, + .set = snd_soc_ac97_gpio_set, + .can_sleep = 1, +}; + +static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, + struct snd_soc_codec *codec) +{ + struct snd_ac97_gpio_priv *gpio_priv; + int ret; + + gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL); + if (!gpio_priv) + return -ENOMEM; + ac97->gpio_priv = gpio_priv; + gpio_priv->codec = codec; + gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip; + gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS; + gpio_priv->gpio_chip.dev = codec->dev; + gpio_priv->gpio_chip.base = -1; + + ret = gpiochip_add(&gpio_priv->gpio_chip); + if (ret != 0) + dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); + return ret; +} + +static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) +{ + gpiochip_remove(&ac97->gpio_priv->gpio_chip); +} +#else +static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, + struct snd_soc_codec *codec) +{ + return 0; +} + +static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) +{ +} +#endif + /** * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device * @codec: The CODEC for which to create the AC'97 device @@ -119,6 +239,10 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, if (ret) goto err_put_device; + ret = snd_soc_ac97_init_gpio(ac97, codec); + if (ret) + goto err_put_device; + return ac97; err_put_device: @@ -135,6 +259,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); */ void snd_soc_free_ac97_codec(struct snd_ac97 *ac97) { + snd_soc_ac97_free_gpio(ac97); device_del(&ac97->dev); ac97->bus = NULL; put_device(&ac97->dev); -- cgit v1.2.3 From 5015920a1732cabd1178cfe342f09ee3488a1791 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 18 Nov 2015 02:34:01 -0500 Subject: ASoC: Vendor drivers get a link's runtime by snd_soc_get_pcm_runtime() Vendor drivers no longer access a DAI link's runtime by the link index but by matching the link name via snd_soc_get_pcm_runtime(). We assume each DAI link has a unique name. This is preparation for changing runtimes from an array to a list later. Vendor drivers changed: sound/soc/fsl/fsl-asoc-card.c sound/soc/fsl/imx-wm8962.c sound/soc/pxa/mioa701_wm9713.c sound/soc/samsung/bells.c sound/soc/samsung/littlemill.c sound/soc/samsung/odroidx2_max98090.c sound/soc/samsung/snow.c sound/soc/samsung/speyside.c sound/soc/samsung/tobermory.c sound/soc/tegra/tegra_wm8903 Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 5 ++++- sound/soc/fsl/imx-wm8962.c | 10 +++++++-- sound/soc/pxa/mioa701_wm9713.c | 6 +++++- sound/soc/samsung/bells.c | 40 ++++++++++++++++++++++++++--------- sound/soc/samsung/littlemill.c | 32 ++++++++++++++++++++++------ sound/soc/samsung/odroidx2_max98090.c | 9 ++++++-- sound/soc/samsung/snow.c | 9 ++++++-- sound/soc/samsung/speyside.c | 12 +++++++++-- sound/soc/samsung/tobermory.c | 21 ++++++++++++++---- sound/soc/tegra/tegra_wm8903.c | 3 ++- 10 files changed, 116 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 1b05d1c5d9fd..f4b6c53146d5 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -222,12 +222,15 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, enum snd_soc_bias_level level) { struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct codec_priv *codec_priv = &priv->codec_priv; struct device *dev = card->dev; unsigned int pll_out; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; if (dapm->dev != codec_dai->dev) return 0; diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index b38b98cae855..201a70d1027a 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -69,13 +69,16 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct imx_priv *priv = &card_priv; struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; unsigned int pll_out; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; if (dapm->dev != codec_dai->dev) return 0; @@ -135,12 +138,15 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, static int imx_wm8962_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct imx_priv *priv = &card_priv; struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, data->clk_frequency, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 29bc60e85e92..5c8f9db50a47 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -81,8 +81,12 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power) static int rear_amp_event(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kctl, int event) { - struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec; + struct snd_soc_card *card = widget->dapm->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); } diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index e5f05e62fa3c..3dd246fa0059 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -58,11 +58,16 @@ static int bells_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_codec *codec; struct bells_drvdata *bells = card->drvdata; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec_dai = rtd->codec_dai; + codec = codec_dai->codec; + if (dapm->dev != codec_dai->dev) return 0; @@ -99,11 +104,16 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_codec *codec; struct bells_drvdata *bells = card->drvdata; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec_dai = rtd->codec_dai; + codec = codec_dai->codec; + if (dapm->dev != codec_dai->dev) return 0; @@ -137,14 +147,22 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, static int bells_late_probe(struct snd_soc_card *card) { struct bells_drvdata *bells = card->drvdata; - struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; - struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; - struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *wm0010; + struct snd_soc_codec *codec; + struct snd_soc_dai *aif1_dai; struct snd_soc_dai *aif2_dai; struct snd_soc_dai *aif3_dai; struct snd_soc_dai *wm9081_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name); + wm0010 = rtd->codec; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec = rtd->codec; + aif1_dai = rtd->codec_dai; + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, bells->sysclk_rate, @@ -181,7 +199,8 @@ static int bells_late_probe(struct snd_soc_card *card) return ret; } - aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name); + aif2_dai = rtd->cpu_dai; ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); if (ret != 0) { @@ -192,8 +211,9 @@ static int bells_late_probe(struct snd_soc_card *card) if (card->num_rtd == DAI_CODEC_SUB) return 0; - aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; - wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name); + aif3_dai = rtd->cpu_dai; + wm9081_dai = rtd->codec_dai; ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); if (ret != 0) { diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 31a820eb0ac3..7cb204e649ca 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -23,9 +23,13 @@ static int littlemill_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + aif1_dai = rtd->codec_dai; + if (dapm->dev != aif1_dai->dev) return 0; @@ -66,9 +70,13 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + aif1_dai = rtd->codec_dai; + if (dapm->dev != aif1_dai->dev) return 0; @@ -168,9 +176,13 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_card *card = w->dapm->card; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif2_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + aif2_dai = rtd->cpu_dai; + switch (event) { case SND_SOC_DAPM_PRE_PMU: ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, @@ -245,11 +257,19 @@ static struct snd_soc_jack littlemill_headset; static int littlemill_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + struct snd_soc_dai *aif1_dai; + struct snd_soc_dai *aif2_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; + aif1_dai = rtd->codec_dai; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + aif2_dai = rtd->cpu_dai; + ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 32768, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 596f1180a369..04217279fe25 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -25,10 +25,15 @@ static struct snd_soc_dai_link odroidx2_dai[]; static int odroidx2_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + cpu_dai = rtd->cpu_dai; + ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, SND_SOC_CLOCK_IN); diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 07ce2cfa4845..d8ac907bbb0d 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -35,10 +35,15 @@ static struct snd_soc_dai_link snow_dai[] = { static int snow_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + cpu_dai = rtd->cpu_dai; + /* Set the MCLK rate for the codec */ ret = snd_soc_dai_set_sysclk(codec_dai, 0, FIN_PLL_RATE, SND_SOC_CLOCK_IN); diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index d1ae21c5e253..083ef5e21b17 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -25,9 +25,13 @@ static int speyside_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -57,9 +61,13 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 85ccfb7188cb..3310eda7cf53 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -23,9 +23,13 @@ static int tobermory_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -62,9 +66,13 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -170,10 +178,15 @@ static struct snd_soc_jack_pin tobermory_headset_pins[] = { static int tobermory_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; + codec_dai = rtd->codec_dai; + ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, 32768, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 21604009bc1a..e485278e027a 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -199,7 +199,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) static int tegra_wm8903_remove(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]); + struct snd_soc_pcm_runtime *rtd = + snd_soc_get_pcm_runtime(card, card->dai_link[0].name); struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = codec_dai->codec; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); -- cgit v1.2.3 From 1a497983a5ae62b4970187183fb3b40e68515a24 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 18 Nov 2015 02:34:11 -0500 Subject: ASoC: Change the PCM runtime array to a list Currently the number of DAI links is statically defined by the machine driver at build time using an array. This makes it difficult to shrink/ grow the number of DAI links at runtime in order to reflect any changes in topology. We can change the DAI link array in the core to a list so that PCMs and FE DAI links can be added and deleted at runtime to reflect changes in use case and DSP topology. The machine driver can still register DAI links as an array. As the 1st step, this patch change the PCM runtime array to a list. A new PCM runtime is added to the list when a DAI link is bound successfully. Later patches will further implement the DAI link list. More: - define snd_soc_new/free_pcm_runtime() to create/free a runtime. - define soc_add_pcm_runtime() to add a runtime to the rtd list. - define soc_remove_pcm_runtimes() to clean up the runtime list. - traverse the rtd list to probe the link components and dais. - Add a field "num" to PCM runtime struct, used to specify the device number when creating the pcm device, and for a soc card to access its dai_props array. - The following 3rd party machine/platform drivers iterate the rtd list to check the runtimes: sound/soc/intel/atom/sst-mfld-platform-pcm.c sound/soc/intel/boards/cht_bsw_rt5645.c sound/soc/intel/boards/cht_bsw_rt5672.c sound/soc/intel/boards/cht_bsw_max98090_ti.c Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +- sound/soc/generic/simple-card.c | 12 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 12 +- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 +- sound/soc/intel/boards/cht_bsw_rt5672.c | 7 +- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsrc-card.c | 6 +- sound/soc/soc-core.c | 263 ++++++++++++++++----------- sound/soc/soc-dapm.c | 7 +- sound/soc/soc-pcm.c | 22 +-- 11 files changed, 191 insertions(+), 159 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index a8b4b9c8b1d2..232b30d3fa68 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1106,7 +1106,7 @@ struct snd_soc_card { /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; int num_links; - struct snd_soc_pcm_runtime *rtd; + struct list_head rtd_list; int num_rtd; /* optional codec specific configuration */ @@ -1201,6 +1201,9 @@ struct snd_soc_pcm_runtime { struct dentry *debugfs_dpcm_root; struct dentry *debugfs_dpcm_state; #endif + + unsigned int num; /* 0-based and monotonic increasing */ + struct list_head list; /* rtd list of the soc card */ }; /* mixer control */ diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 54c33204541f..1ded8811598e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -45,7 +45,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; int ret; ret = clk_prepare_enable(dai_props->cpu_dai.clk); @@ -64,7 +64,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -78,8 +78,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -174,10 +173,9 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; struct simple_dai_props *dai_props; - int num, ret; + int ret; - num = rtd - rtd->card->rtd; - dai_props = &priv->dai_props[num]; + dai_props = &priv->dai_props[rtd->num]; ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai); if (ret < 0) return ret; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 0487cfaac538..8e475e823205 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -760,15 +760,15 @@ static int sst_platform_remove(struct platform_device *pdev) static int sst_soc_prepare(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* suspend all pcms first */ snd_soc_suspend(drv->soc_card->dev); snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { send_ssp_cmd(dai, dai->name, 0); @@ -782,11 +782,11 @@ static int sst_soc_prepare(struct device *dev) static void sst_soc_complete(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* restart SSPs */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { sst_handle_vb_timer(dai, true); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 4e2fcf188dd1..e36dad302bed 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -41,12 +41,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 38d65a3529c4..1d2525a53bff 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -47,12 +47,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; - - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_pcm_runtime *rtd; - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 5621ccd92992..77fb3c419ca4 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -46,12 +46,9 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index deed48ef28b8..8c4f54b0cb92 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1040,7 +1040,7 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = name, .info = rsnd_kctrl_info, - .index = rtd - soc_card->rtd, + .index = rtd->num, .get = rsnd_kctrl_get, .put = rsnd_kctrl_put, .private_value = (unsigned long)cfg, diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index d61db9c385ea..94d23d8f2869 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -75,7 +75,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); return clk_prepare_enable(dai_props->clk); } @@ -85,7 +85,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->clk); } @@ -101,7 +101,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; struct rsrc_card_dai *dai_props; - int num = rtd - rtd->card->rtd; + int num = rtd->num; int ret; dai_link = rsrc_priv_to_link(priv, num); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 24b096066a07..2c95de723d8f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -537,26 +537,75 @@ static inline void snd_soc_debugfs_exit(void) struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (card->rtd[i].dai_link->no_pcm && - !strcmp(card->rtd[i].dai_link->name, dai_link)) - return card->rtd[i].pcm->streams[stream].substream; + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->no_pcm && + !strcmp(rtd->dai_link->name, dai_link)) + return rtd->pcm->streams[stream].substream; } dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); +static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( + struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); + if (!rtd) + return NULL; + + rtd->card = card; + rtd->dai_link = dai_link; + rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) * + dai_link->num_codecs, + GFP_KERNEL); + if (!rtd->codec_dais) { + kfree(rtd); + return NULL; + } + + return rtd; +} + +static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) +{ + if (rtd && rtd->codec_dais) + kfree(rtd->codec_dais); + kfree(rtd); +} + +static void soc_add_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + list_add_tail(&rtd->list, &card->rtd_list); + rtd->num = card->num_rtd; + card->num_rtd++; +} + +static void soc_remove_pcm_runtimes(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd, *_rtd; + + list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + list_del(&rtd->list); + soc_free_pcm_runtime(rtd); + } + + card->num_rtd = 0; +} + struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, const char *dai_link) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (!strcmp(card->rtd[i].dai_link->name, dai_link)) - return &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strcmp(rtd->dai_link->name, dai_link)) + return rtd; } dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); return NULL; @@ -578,7 +627,8 @@ int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); struct snd_soc_codec *codec; - int i, j; + struct snd_soc_pcm_runtime *rtd; + int i; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) @@ -595,13 +645,13 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -610,20 +660,20 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - for (i = 0; i < card->num_rtd; i++) { - if (card->rtd[i].dai_link->ignore_suspend) + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->ignore_suspend) continue; - snd_pcm_suspend_all(card->rtd[i].pcm); + snd_pcm_suspend_all(rtd->pcm); } if (card->suspend_pre) card->suspend_pre(card); - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) @@ -631,19 +681,19 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for (i = 0; i < card->num_rtd; i++) - flush_delayed_work(&card->rtd[i].delayed_work); + list_for_each_entry(rtd, &card->rtd_list, list) + flush_delayed_work(&rtd->delayed_work); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_SUSPEND); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_SUSPEND); } @@ -690,10 +740,10 @@ int snd_soc_suspend(struct device *dev) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) @@ -717,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work) { struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); + struct snd_soc_pcm_runtime *rtd; struct snd_soc_codec *codec; - int i, j; + int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, * so userspace apps are blocked from touching us @@ -733,10 +784,10 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) @@ -751,28 +802,28 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_RESUME); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_RESUME); } /* unmute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -780,10 +831,10 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) @@ -808,15 +859,14 @@ int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); bool bus_control = false; - int i; + struct snd_soc_pcm_runtime *rtd; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) return 0; /* activate pins from sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -837,8 +887,8 @@ int snd_soc_resume(struct device *dev) * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } if (bus_control) { @@ -913,16 +963,20 @@ static struct snd_soc_dai *snd_soc_find_dai( static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); + rtd = soc_new_pcm_runtime(card, dai_link); + if (!rtd) + return -ENOMEM; + cpu_dai_component.name = dai_link->cpu_name; cpu_dai_component.of_node = dai_link->cpu_of_node; cpu_dai_component.dai_name = dai_link->cpu_dai_name; @@ -930,18 +984,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); - return -EPROBE_DEFER; + goto _err_defer; } rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); - return -EPROBE_DEFER; + goto _err_defer; } } @@ -973,9 +1028,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return -EPROBE_DEFER; } - card->num_rtd++; - + soc_add_pcm_runtime(card, rtd); return 0; + +_err_defer: + soc_free_pcm_runtime(rtd); + return -EPROBE_DEFER; } static void soc_remove_component(struct snd_soc_component *component) @@ -1014,9 +1072,9 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) } } -static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) +static void soc_remove_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; int i; /* unregister the rtd device */ @@ -1032,10 +1090,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) soc_remove_dai(rtd->cpu_dai, order); } -static void soc_remove_link_components(struct snd_soc_card *card, int num, - int order) +static void soc_remove_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; @@ -1061,21 +1118,20 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, static void soc_remove_dai_links(struct snd_soc_card *card) { - int dai, order; + int order; + struct snd_soc_pcm_runtime *rtd; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_dais(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_components(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_components(card, rtd, order); } - - card->num_rtd = 0; } static void soc_set_name_prefix(struct snd_soc_card *card, @@ -1220,10 +1276,10 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, return 0; } -static int soc_probe_link_components(struct snd_soc_card *card, int num, +static int soc_probe_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; int i, ret; @@ -1319,15 +1375,15 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) +static int soc_probe_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int i, ret; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", - card->name, num, order); + card->name, rtd->num, order); /* set default power off timeout */ rtd->pmdown_time = pmdown_time; @@ -1372,7 +1428,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->compress_new) { /*create compress_device"*/ - ret = cpu_dai->driver->compress_new(rtd, num); + ret = cpu_dai->driver->compress_new(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); @@ -1382,7 +1438,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (!dai_link->params) { /* create the pcm */ - ret = soc_new_pcm(rtd, num); + ret = soc_new_pcm(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); @@ -1552,6 +1608,7 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; + struct snd_soc_pcm_runtime *rtd; int ret, i, order; mutex_lock(&client_mutex); @@ -1624,8 +1681,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_components(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1638,8 +1695,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_dais(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1733,6 +1790,7 @@ card_probe_error: snd_card_free(card->snd_card); base_error: + soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -1763,13 +1821,12 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { + struct snd_soc_pcm_runtime *rtd; int i; /* make sure any delayed work runs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } /* remove auxiliary devices */ for (i = 0; i < card->num_aux_devs; i++) @@ -1777,6 +1834,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); soc_cleanup_card_debugfs(card); @@ -1803,29 +1861,26 @@ static int soc_remove(struct platform_device *pdev) int snd_soc_poweroff(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; if (!card->instantiated) return 0; /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int j; + int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2337,6 +2392,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, int snd_soc_register_card(struct snd_soc_card *card) { int i, j, ret; + struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2408,25 +2464,15 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); - card->rtd = devm_kzalloc(card->dev, + INIT_LIST_HEAD(&card->rtd_list); + card->num_rtd = 0; + + card->rtd_aux = devm_kzalloc(card->dev, sizeof(struct snd_soc_pcm_runtime) * - (card->num_links + card->num_aux_devs), + card->num_aux_devs, GFP_KERNEL); - if (card->rtd == NULL) + if (card->rtd_aux == NULL) return -ENOMEM; - card->num_rtd = 0; - card->rtd_aux = &card->rtd[card->num_links]; - - for (i = 0; i < card->num_links; i++) { - card->rtd[i].card = card; - card->rtd[i].dai_link = &card->dai_link[i]; - card->rtd[i].codec_dais = devm_kzalloc(card->dev, - sizeof(struct snd_soc_dai *) * - (card->rtd[i].dai_link->num_codecs), - GFP_KERNEL); - if (card->rtd[i].codec_dais == NULL) - return -ENOMEM; - } for (i = 0; i < card->num_aux_devs; i++) card->rtd_aux[i].card = card; @@ -2442,8 +2488,7 @@ int snd_soc_register_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 016eba10b1ec..3eba72c6f9dd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3893,13 +3893,10 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = card->rtd; - int i; + struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - for (i = 0; i < card->num_rtd; i++) { - rtd = &card->rtd[i]; - + list_for_each_entry(rtd, &card->rtd_list, list) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96e8986..bbeaa87a36f4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1213,11 +1213,10 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; - int i, j; + int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1225,16 +1224,15 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->playback_widget == widget) return be; } } } else { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1242,8 +1240,8 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->capture_widget == widget) return be; } @@ -2343,12 +2341,12 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) */ int soc_dpcm_runtime_update(struct snd_soc_card *card) { - int i, old, new, paths; + struct snd_soc_pcm_runtime *fe; + int old, new, paths; mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(fe, &card->rtd_list, list) { struct snd_soc_dapm_widget_list *list; - struct snd_soc_pcm_runtime *fe = &card->rtd[i]; /* make sure link is FE */ if (!fe->dai_link->dynamic) -- cgit v1.2.3 From c80fd4da68cd7784a19c584d01294e362a7b61a3 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 5 Nov 2015 22:53:06 +0530 Subject: ASoC: Intel: Skylake: Add support for SSP1 BE cpu dai Adds new BE cpu dai to support SSP1 port. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index e652d58bd9a9..c8d942887348 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -626,6 +626,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, +{ + .name = "SSP1 Pin", + .ops = &skl_be_ssp_dai_ops, + .playback = { + .stream_name = "ssp1 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "ssp1 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, { .name = "iDisp Pin", .ops = &skl_link_dai_ops, -- cgit v1.2.3 From a86d505783e42d2f824e32489a1f2b0c3454d9fe Mon Sep 17 00:00:00 2001 From: Harsha Priya Date: Thu, 5 Nov 2015 22:53:07 +0530 Subject: ASoC: Intel: Skylake: Adding nau88l25+ssm4567 machine driver Add i2s machine driver with NAU88L25 and SSM4567 codecs Signed-off-by: Harsha Priya Signed-off-by: Conrad Cooke Signed-off-by: Naveen M Signed-off-by: Sathya Prakash M R Signed-off-by: Yong Zhi Signed-off-by: Fang, Yang A Signed-off-by: Sathyanarayana Nujella Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 14 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 368 ++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 sound/soc/intel/boards/skl_nau88l25_ssm4567.c (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2903823ebee1..aee2a5c75e0d 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -155,3 +155,17 @@ config SND_SOC_INTEL_SKL_RT286_MACH with RT286 I2S audio codec. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH + tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_NAU8825 + select SND_SOC_SSM4567 + select SND_SOC_DMIC + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for NAU88L25 + SSM4567. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 371c4565cad8..a59f76277cee 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -7,6 +7,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -17,3 +18,4 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c new file mode 100644 index 000000000000..3f5a96b585b8 --- /dev/null +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -0,0 +1,368 @@ +/* + * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" +#define SKL_SSM_CODEC_DAI "ssm4567-hifi" + +static struct snd_soc_jack skylake_headset; +static struct snd_soc_card skylake_audio_card; + +static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) +{ + int i; + + for (i = 0; i < card->num_rtd; i++) { + struct snd_soc_pcm_runtime *rtd; + + rtd = card->rtd + i; + if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI, + strlen(SKL_NUVOTON_CODEC_DAI))) + return rtd->codec_dai; + } + + return NULL; +} + +static const struct snd_kcontrol_new skylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Speaker"), + SOC_DAPM_PIN_SWITCH("Right Speaker"), +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = skl_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } + return ret; +} + +static const struct snd_soc_dapm_widget skylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Speaker", NULL), + SND_SOC_DAPM_SPK("Right Speaker", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route skylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + {"Headphone Jack", NULL, "HPOL"}, + {"Headphone Jack", NULL, "HPOR"}, + + /* speaker */ + {"Left Speaker", NULL, "Left OUT"}, + {"Right Speaker", NULL, "Right OUT"}, + + /* other jacks */ + {"MIC", NULL, "Headset Mic"}, + {"DMIC AIF", NULL, "SoC DMIC"}, + + /* CODEC BE connections */ + { "Left Playback", NULL, "ssp0 Tx"}, + { "Right Playback", NULL, "ssp0 Tx"}, + { "ssp0 Tx", NULL, "codec0_out"}, + + { "AIF1 Playback", NULL, "ssp1 Tx"}, + { "ssp1 Tx", NULL, "codec1_out"}, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "AIF1 Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "Capture" }, + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static struct snd_soc_codec_conf ssm4567_codec_conf[] = { + { + .dev_name = "i2c-INT343B:00", + .name_prefix = "Left", + }, + { + .dev_name = "i2c-INT343B:01", + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component ssm4567_codec_components[] = { + { /* Left */ + .name = "i2c-INT343B:00", + .dai_name = SKL_SSM_CODEC_DAI, + }, + { /* Right */ + .name = "i2c-INT343B:01", + .dai_name = SKL_SSM_CODEC_DAI, + }, +}; + +static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + + /* Slot 1 for left */ + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48); + if (ret < 0) + return ret; + + /* Slot 2 for right */ + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48); + if (ret < 0) + return ret; + + return ret; +} + +static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_codec *codec = rtd->codec; + + /* + * 4 buttons here map to the google Reference headset + * The use of these buttons can be decided by the user space. + */ + ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + nau8825_enable_jack_detect(codec, &skylake_headset); + + return ret; +} + +static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + +static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops skylake_nau8825_ops = { + .hw_params = skylake_nau8825_hw_params, +}; + +/* skylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link skylake_dais[] = { + /* Front End DAI links */ + { + .name = "Skl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + }, + { + .name = "Skl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + }, + { + .name = "Skl Audio Reference cap", + .stream_name = "refcap", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + }, + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .be_id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssm4567_codec_components, + .num_codecs = ARRAY_SIZE(ssm4567_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .init = skylake_ssm4567_codec_init, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .be_id = 0, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10508825:00", + .codec_dai_name = SKL_NUVOTON_CODEC_DAI, + .init = skylake_nau8825_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .ops = &skylake_nau8825_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .be_id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, +}; + +/* skylake audio machine driver for SPT + NAU88L25 */ +static struct snd_soc_card skylake_audio_card = { + .name = "sklnau8825adi", + .owner = THIS_MODULE, + .dai_link = skylake_dais, + .num_links = ARRAY_SIZE(skylake_dais), + .controls = skylake_controls, + .num_controls = ARRAY_SIZE(skylake_controls), + .dapm_widgets = skylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), + .dapm_routes = skylake_map, + .num_dapm_routes = ARRAY_SIZE(skylake_map), + .codec_conf = ssm4567_codec_conf, + .num_configs = ARRAY_SIZE(ssm4567_codec_conf), +}; + +static int skylake_audio_probe(struct platform_device *pdev) +{ + skylake_audio_card.dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); +} + +static struct platform_driver skylake_audio = { + .probe = skylake_audio_probe, + .driver = { + .name = "skl_nau88l25_ssm4567_i2s", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skylake_audio) + +/* Module information */ +MODULE_AUTHOR("Conrad Cooke "); +MODULE_AUTHOR("Harsha Priya "); +MODULE_AUTHOR("Naveen M "); +MODULE_AUTHOR("Sathya Prakash M R "); +MODULE_AUTHOR("Yong Zhi "); +MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s"); -- cgit v1.2.3 From 02cc23555dfeec9ab87340f052541dd906fb440c Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Thu, 5 Nov 2015 22:53:08 +0530 Subject: ASoC: Intel: Skylake: add adi + nau8825 machine driver entry This patch adds skl_nau8825_ssn4567_i2s machine driver into machine table Signed-off-by: Fang, Yang A Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 390f839d6168..8ead864f354a 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -587,6 +587,8 @@ static void skl_remove(struct pci_dev *pci) static struct sst_acpi_mach sst_skl_devdata[] = { { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, + { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin", + NULL, NULL, NULL }, {} }; -- cgit v1.2.3 From 28823f1538ce2f67b7c21e30d6b84c3e86f8c0fd Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:05 +0530 Subject: ASoC: Intel: Skylake: remove pm_runtime_get/put calls The ASoC core already does pm_runtime_get/put in the core before opening/closing the devices. So we do not need to do this is driver, hence remove Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c8d942887348..dae332beea3f 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -112,12 +112,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; - int ret; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - ret = pm_runtime_get_sync(dai->dev); - if (ret < 0) - return ret; stream = snd_hdac_ext_stream_assign(ebus, substream, skl_get_host_stream_type(ebus)); @@ -262,8 +258,6 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, */ snd_soc_dai_set_dma_data(dai, substream, NULL); - pm_runtime_mark_last_busy(dai->dev); - pm_runtime_put_autosuspend(dai->dev); kfree(dma_params); } @@ -512,19 +506,6 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, return 0; } -static int skl_be_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - return pm_runtime_get_sync(dai->dev); -} - -static void skl_be_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - pm_runtime_mark_last_busy(dai->dev); - pm_runtime_put_autosuspend(dai->dev); -} - static struct snd_soc_dai_ops skl_pcm_dai_ops = { .startup = skl_pcm_open, .shutdown = skl_pcm_close, @@ -535,24 +516,18 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = { }; static struct snd_soc_dai_ops skl_dmic_dai_ops = { - .startup = skl_be_startup, .hw_params = skl_be_hw_params, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { - .startup = skl_be_startup, .hw_params = skl_be_hw_params, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_ops skl_link_dai_ops = { - .startup = skl_be_startup, .prepare = skl_link_pcm_prepare, .hw_params = skl_link_hw_params, .hw_free = skl_link_hw_free, .trigger = skl_link_pcm_trigger, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_driver skl_platform_dai[] = { -- cgit v1.2.3 From a71e269728ce42216cca8ce5145e97e777a36467 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:06 +0530 Subject: ASoC: Intel: Skylake: Don't enable WAKEENABLE on suspend For HDA codecs WAKEENABLE bit is to programmed if codec event change has to wake the system when suspended. In skylake I2S systems which are currently supported we have only HDMI codec, which doesn't use this capability to detect a HDMI connect/ disconnect event. HDMI HDA codec uses display interface to detect connect/disconnect event. This patch removes the WAKEBIT enabling during device D0/D3 as this seems to cause spurious wakes on the system Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 8ead864f354a..bdb99dcbfdca 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -191,9 +191,6 @@ static int skl_runtime_suspend(struct device *dev) dev_dbg(bus->dev, "in %s\n", __func__); - /* enable controller wake up event */ - snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK); - return _skl_suspend(ebus); } @@ -203,17 +200,11 @@ static int skl_runtime_resume(struct device *dev) struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl *skl = ebus_to_skl(ebus); - int status; dev_dbg(bus->dev, "in %s\n", __func__); - /* Read STATESTS before controller reset */ - status = snd_hdac_chip_readw(bus, STATESTS); - skl_init_pci(skl); snd_hdac_bus_init_chip(bus, true); - /* disable controller Wake Up event */ - snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); return _skl_resume(ebus); } -- cgit v1.2.3 From e03fc82d7c474b2f9bcdb0f6a5ef26c6c3ab24ee Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:07 +0530 Subject: ASoC: Intel: Skylake: Remove redundant init in resume Since we call _skl_resume which also initializes the chip we no need to call these explicitly, so remove the duplication Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index bdb99dcbfdca..d3e87b6f93fe 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -199,13 +199,9 @@ static int skl_runtime_resume(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *skl = ebus_to_skl(ebus); dev_dbg(bus->dev, "in %s\n", __func__); - skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); - return _skl_resume(ebus); } #endif /* CONFIG_PM */ -- cgit v1.2.3 From ae395937ab95b8c62806af6a17a6cdfe6086401e Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:08 +0530 Subject: ASoC: Intel: Skylake: Fix cleanup of dma buffer During firmware download, dma buffers are allocated in prepare and never freed on clean up. This patch frees the allocated dma buffer in cldma controller clean up. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 5 +++++ sound/soc/intel/skylake/skl-sst.c | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44748ba98da2..4ddabe30b62a 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -137,6 +137,11 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx) sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); + + if (&ctx->cl_dev.dmab_data) + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + if (&ctx->cl_dev.dmab_bdl) + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); } static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 0c5039f2bd09..51f07f0e4735 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -115,27 +115,28 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) dev_err(ctx->dev, "Timeout waiting for ROM init done, reg:0x%x\n", reg); ret = -EIO; - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size); if (ret < 0) { dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } else { ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); if (ret == 0) { dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); ret = -EIO; - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); } return 0; - +transfer_firmware_failed: + ctx->cl_dev.ops.cl_cleanup_controller(ctx); skl_load_base_firmware_failed: skl_dsp_disable_core(ctx); release_firmware(ctx->fw); @@ -277,7 +278,6 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { skl_ipc_free(&ctx->ipc); - ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); ctx->dsp->ops->free(ctx->dsp); } EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); -- cgit v1.2.3 From 53afce2c5764ebf5e933efe9a2dd58cbc316c854 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:09 +0530 Subject: ASoC: Intel: Skylake: Reset the DSP when set D3 fails Sometimes firmware D3 IPC fails causing firmware to be in invalid state. To recover we need to reset the DSP and then shut it down, so don't return on error and continue resetting to recover. On D0, firmware will be redownloaded and DSP will be back in clean state Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 51f07f0e4735..e1d34d5c3f9a 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" @@ -176,10 +177,15 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx) dx.core_mask = SKL_DSP_CORE0_MASK; dx.dx_mask = SKL_IPC_D3_MASK; ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); - return ret; - } + if (ret < 0) + dev_err(ctx->dev, + "D3 request to FW failed, continuing reset: %d", ret); + + /* disable Interrupt */ + ctx->cl_dev.ops.cl_cleanup_controller(ctx); + skl_cldma_int_disable(ctx); + skl_ipc_op_int_disable(ctx); + skl_ipc_int_disable(ctx); ret = skl_dsp_disable_core(ctx); if (ret < 0) { @@ -188,12 +194,6 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx) } skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); - /* disable Interrupt */ - ctx->cl_dev.ops.cl_cleanup_controller(ctx); - skl_cldma_int_disable(ctx); - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - return ret; } -- cgit v1.2.3 From e797af53b8814dfbc3c6ac134c528b8ab480f275 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:10 +0530 Subject: ASoC: Intel: Skylake: Fix CLDMA buffer wrap case When downloading the firmware/module, if the ring buffer boundary is reached, we need to wrap to the zeroth position. On next copy we need to copy till end of buffer and the remaining buffer needs to be copied from zeroth position. In this case copy was not handled correctly when wrap condition is reached which caused invalid data to be copied resulting in invalid hash failure. This patch fixes the issue by handling copy at the boundary condition correctly. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 4ddabe30b62a..b03d9db0acad 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -180,6 +180,21 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, ctx->cl_dev.dma_buffer_offset, trigger); dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + /* + * Check if the size exceeds buffer boundary. If it exceeds + * max_buffer size, then copy till buffer size and then copy + * remaining buffer from the start of ring buffer. + */ + if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) { + unsigned int size_b = ctx->cl_dev.bufsize - + ctx->cl_dev.dma_buffer_offset; + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size_b); + size -= size_b; + curr_pos += size_b; + ctx->cl_dev.dma_buffer_offset = 0; + } + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, curr_pos, size); -- cgit v1.2.3 From 0ed95d769c8d6c1030dd9f94cf6fb2a6ed98a4ce Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:11 +0530 Subject: ASoC: Intel: Skylake: Fix null ptr dereferenced in skl_tplg_bind_sinks This patch fixes the below warning form smatch and makes the skl_tplg_bind_sinks take the next sink as argument which is true when the current sink is valid sound/soc/intel/skylake/skl-topology.c:453 skl_tplg_bind_sinks() error: we previously assumed 'sink' could be null (see line 452) sound/soc/intel/skylake/skl-topology.c 451 452 if (!sink) ^^^^ New check. Reversed? 453 return skl_tplg_bind_sinks(sink, skl, src_mconfig); ^^^^ This is dereferenced inside the function. 454 455 return 0; Reported-by: Dan Carpenter Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2b6ee22b5ea2..0937ea2129c1 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -408,7 +408,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *sink = NULL; + struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; struct skl_module_cfg *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; int ret; @@ -420,7 +420,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); - sink = p->sink; + next_sink = p->sink; /* * here we will check widgets in sink pipelines, so that * can be any widgets type and we are only interested if @@ -450,7 +450,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, } if (!sink) - return skl_tplg_bind_sinks(sink, skl, src_mconfig); + return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); return 0; } -- cgit v1.2.3 From 5eab6ab9c7882f63d7dd544b736293a9d2b8106c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 13 Nov 2015 19:22:12 +0530 Subject: ASoC: Intel: Skylake: Constrain the audio devices In ref configuration for Skylake, we support only 16bit, 48KHz, stereo audio, so specify these as constrains for the devices Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index e6af48491229..9c67e05a24b3 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -104,6 +104,53 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * on this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_rt286_fe_ops = { + .startup = skl_fe_startup, +}; static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) @@ -160,6 +207,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dpcm_playback = 1, + .ops = &skylake_rt286_fe_ops, }, { .name = "Skl Audio Capture Port", @@ -175,6 +223,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dpcm_capture = 1, + .ops = &skylake_rt286_fe_ops, }, { .name = "Skl Audio Reference cap", -- cgit v1.2.3 From 314038e40a62c7cdfc07aad0fe14dcd4383bc34d Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 13 Nov 2015 19:22:13 +0530 Subject: ASoC: Intel: Skylake: Add pm ops for skl_rt286 machine The PM ops are required so that DAPM will suspend and resume the DSP pipelines properly Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 9c67e05a24b3..57333a476136 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -299,6 +299,7 @@ static struct platform_driver skylake_audio = { .probe = skylake_audio_probe, .driver = { .name = "skl_alc286s_i2s", + .pm = &snd_soc_pm_ops, }, }; -- cgit v1.2.3 From d190106d5a6b300b782a55ad24a1e1da71fa630b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 16:11:10 +0000 Subject: ASoC: wm5110: Add DAPM/routing hookup for the ANC block The wm5110 device contains a hardware ANC block, this patch connects up controls and routing for this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 119 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 7 +++ sound/soc/codecs/wm5110.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index b3ea24d64c50..e76ecc7cc775 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -702,6 +702,100 @@ const struct soc_enum arizona_in_dmic_osr[] = { }; EXPORT_SYMBOL_GPL(arizona_in_dmic_osr); +static const char * const arizona_anc_input_src_text[] = { + "None", "IN1", "IN2", "IN3", "IN4", +}; + +static const char * const arizona_anc_channel_src_text[] = { + "None", "Left", "Right", "Combine", +}; + +const struct soc_enum arizona_anc_input_src[] = { + SOC_ENUM_SINGLE(ARIZONA_ANC_SRC, + ARIZONA_IN_RXANCL_SEL_SHIFT, + ARRAY_SIZE(arizona_anc_input_src_text), + arizona_anc_input_src_text), + SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL, + ARIZONA_FCL_MIC_MODE_SEL, + ARRAY_SIZE(arizona_anc_channel_src_text), + arizona_anc_channel_src_text), + SOC_ENUM_SINGLE(ARIZONA_ANC_SRC, + ARIZONA_IN_RXANCR_SEL_SHIFT, + ARRAY_SIZE(arizona_anc_input_src_text), + arizona_anc_input_src_text), + SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL, + ARIZONA_FCR_MIC_MODE_SEL, + ARRAY_SIZE(arizona_anc_channel_src_text), + arizona_anc_channel_src_text), +}; +EXPORT_SYMBOL_GPL(arizona_anc_input_src); + +static const char * const arizona_anc_ng_texts[] = { + "None", + "Internal", + "External", +}; + +SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0, + arizona_anc_ng_texts); +EXPORT_SYMBOL_GPL(arizona_anc_ng_enum); + +static const char * const arizona_output_anc_src_text[] = { + "None", "RXANCL", "RXANCR", +}; + +const struct soc_enum arizona_output_anc_src[] = { + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, + ARIZONA_OUT1L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R, + ARIZONA_OUT1R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, + ARIZONA_OUT2L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R, + ARIZONA_OUT2R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, + ARIZONA_OUT3L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R, + ARIZONA_OUT3R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L, + ARIZONA_OUT4L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R, + ARIZONA_OUT4R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L, + ARIZONA_OUT5L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R, + ARIZONA_OUT5R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L, + ARIZONA_OUT6L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R, + ARIZONA_OUT6R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), +}; +EXPORT_SYMBOL_GPL(arizona_output_anc_src); + static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); @@ -1023,6 +1117,31 @@ void arizona_init_dvfs(struct arizona_priv *priv) } EXPORT_SYMBOL_GPL(arizona_init_dvfs); +int arizona_anc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int mask = 0x3 << w->shift; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = 1 << w->shift; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 1 << (w->shift + 1); + break; + default: + return 0; + } + + snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val); + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_anc_ev); + static unsigned int arizona_opclk_ref_48k_rates[] = { 6144000, 12288000, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index fea8b8ae8e1a..01a367caefd8 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -242,6 +242,10 @@ extern const struct soc_enum arizona_in_dmic_osr[]; extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[]; +extern const struct soc_enum arizona_anc_input_src[]; +extern const struct soc_enum arizona_anc_ng_enum; +extern const struct soc_enum arizona_output_anc_src[]; + extern int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -251,6 +255,9 @@ extern int arizona_out_ev(struct snd_soc_dapm_widget *w, extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_anc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event); extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index c04c0bc6f58a..e93e5420943e 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -575,6 +575,33 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \ SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0) +#define WM5110_RXANC_INPUT_ROUTES(widget, name) \ + { widget, NULL, name " NG Mux" }, \ + { name " NG Internal", NULL, "RXANC NG Clock" }, \ + { name " NG Internal", NULL, name " Channel" }, \ + { name " NG External", NULL, "RXANC NG External Clock" }, \ + { name " NG External", NULL, name " Channel" }, \ + { name " NG Mux", "None", name " Channel" }, \ + { name " NG Mux", "Internal", name " NG Internal" }, \ + { name " NG Mux", "External", name " NG External" }, \ + { name " Channel", "Left", name " Left Input" }, \ + { name " Channel", "Combine", name " Left Input" }, \ + { name " Channel", "Right", name " Right Input" }, \ + { name " Channel", "Combine", name " Right Input" }, \ + { name " Left Input", "IN1", "IN1L PGA" }, \ + { name " Right Input", "IN1", "IN1R PGA" }, \ + { name " Left Input", "IN2", "IN2L PGA" }, \ + { name " Right Input", "IN2", "IN2R PGA" }, \ + { name " Left Input", "IN3", "IN3L PGA" }, \ + { name " Right Input", "IN3", "IN3R PGA" }, \ + { name " Left Input", "IN4", "IN4L PGA" }, \ + { name " Right Input", "IN4", "IN4R PGA" } + +#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \ + { widget, NULL, name " ANC Source" }, \ + { name " ANC Source", "RXANCL", "RXANCL" }, \ + { name " ANC Source", "RXANCR", "RXANCR" } + static const struct snd_kcontrol_new wm5110_snd_controls[] = { SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]), SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]), @@ -639,6 +666,15 @@ SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R, SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), +SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START, + ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1), +SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1), +SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START, + ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1), +SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1), +SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START, + ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), @@ -995,6 +1031,31 @@ static const struct soc_enum wm5110_aec_loopback = static const struct snd_kcontrol_new wm5110_aec_loopback_mux = SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback); +static const struct snd_kcontrol_new wm5110_anc_input_mux[] = { + SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]), + SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]), + SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]), + SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]), +}; + +static const struct snd_kcontrol_new wm5110_anc_ng_mux = + SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum); + +static const struct snd_kcontrol_new wm5110_output_anc_src[] = { + SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]), + SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]), + SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]), + SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]), + SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]), + SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]), + SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]), + SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]), + SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]), + SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]), + SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]), + SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]), +}; + static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU), @@ -1185,6 +1246,65 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux), +SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM, + ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM, + ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[0]), +SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[0]), +SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[1]), +SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux), +SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[2]), +SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[2]), +SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[3]), +SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux), + +SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT, + 0, NULL, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT, + 0, NULL, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[0]), +SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[1]), +SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[2]), +SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[3]), +SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[4]), +SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[5]), +SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[6]), +SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[7]), +SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[8]), +SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[9]), +SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[10]), +SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[11]), + SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, @@ -1838,6 +1958,22 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "SPKDAT2L", NULL, "OUT6L" }, { "SPKDAT2R", NULL, "OUT6R" }, + WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"), + WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"), + + WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"), + WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"), + WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"), + { "MICSUPP", NULL, "SYSCLK" }, { "DRC1 Signal Activity", NULL, "DRC1L" }, -- cgit v1.2.3 From d1afdf34fc17bd2e1c96dc6196c562fa8906a026 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 10:32:44 +0100 Subject: ASoC: pxa: remove incorrect do_div() call The new optimized do_div implementation (now in asm-generic/next) exposes a glitch in the brownstone audio driver by producing a compile-time warning: sound/soc/pxa/brownstone.c: In function 'brownstone_wm8994_hw_params': sound/soc/pxa/brownstone.c:67:85: warning: comparison of distinct pointer types lacks a cast sound/soc/pxa/brownstone.c:67:10125: warning: right shift count >= width of type [-Wshift-count-overflow] sound/soc/pxa/brownstone.c:67:10254: warning: passing argument 1 of '__div64_32' from incompatible pointer type [-Wincompatible-pointer-types] The driver just divides two plain integer values, so it should not use do_div to start with, but has apparently done so ever since the code was first merged. This replaces do_div with a simple division operator. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/brownstone.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 6147e86e9b0f..416ea646c3b1 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -63,8 +63,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, sysclk = params_rate(params) * 512; sspa_mclk = params_rate(params) * 64; } - sspa_div = freq_out; - do_div(sspa_div, sspa_mclk); + sspa_div = freq_out / sspa_mclk; snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); -- cgit v1.2.3 From 5547ba616b964de05ba48ec4d529ed1ac22a4326 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2015 04:22:14 +0000 Subject: ASoC: ak4613: tidyup vendor prefix from ak4613 to asahi-kasei a3af0c65("ASoC: ak4613: add single-end optional property for IN/OUT pins") added IN/OUT pin single-end optional property, but it used "ak4613" as vendor prefix. This patch fixup to asahi-kasei. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak4613.txt | 16 ++++++++-------- sound/soc/codecs/ak4613.c | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt index 3cf63e7f8e77..1783f9ef0930 100644 --- a/Documentation/devicetree/bindings/sound/ak4613.txt +++ b/Documentation/devicetree/bindings/sound/ak4613.txt @@ -8,14 +8,14 @@ Required properties: - reg : The chip select number on the I2C bus Optional properties: -- ak4613,in1-single-end : Boolean. Indicate input / output pins are single-ended. -- ak4613,in2-single-end rather than differential. -- ak4613,out1-single-end -- ak4613,out2-single-end -- ak4613,out3-single-end -- ak4613,out4-single-end -- ak4613,out5-single-end -- ak4613,out6-single-end +- asahi-kasei,in1-single-end : Boolean. Indicate input / output pins are single-ended. +- asahi-kasei,in2-single-end rather than differential. +- asahi-kasei,out1-single-end +- asahi-kasei,out2-single-end +- asahi-kasei,out3-single-end +- asahi-kasei,out4-single-end +- asahi-kasei,out5-single-end +- asahi-kasei,out6-single-end Example: diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 62c08a6395af..647f69de6baa 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -464,14 +464,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv, /* Input 1 - 2 */ for (i = 0; i < 2; i++) { - snprintf(prop, sizeof(prop), "ak4613,in%d-single-end", i + 1); + snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); if (!of_get_property(np, prop, NULL)) priv->ic |= 1 << i; } /* Output 1 - 6 */ for (i = 0; i < 6; i++) { - snprintf(prop, sizeof(prop), "ak4613,out%d-single-end", i + 1); + snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); if (!of_get_property(np, prop, NULL)) priv->oc |= 1 << i; } -- cgit v1.2.3 From c51eb1c66e55bf23af4a10dd6e71c5a82c0e6d81 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2015 04:22:56 +0000 Subject: ASoC: rsnd: tidyup void* cast for 64bit compiler 64bit compiler indicates this without this patch linux/sound/soc/sh/rcar/core.c: In function 'rsnd_probe': linux/sound/soc/sh/rcar/core.c:1002:16: warning: cast from pointer to\ integer of different size [-Wpointer-to-int-cast] Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8dceae4b731a..81a6bdb6848c 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -999,7 +999,7 @@ static int rsnd_probe(struct platform_device *pdev) } priv->pdev = pdev; - priv->flags = (u32)of_id->data; + priv->flags = (unsigned long)of_id->data; spin_lock_init(&priv->lock); /* diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ae69670c5c0c..42d2ac5cb0d1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -379,7 +379,7 @@ struct rsnd_priv { struct platform_device *pdev; spinlock_t lock; - u32 flags; + unsigned long flags; #define RSND_GEN_MASK (0xF << 0) #define RSND_GEN1 (1 << 0) #define RSND_GEN2 (2 << 0) -- cgit v1.2.3 From 07c55d395041c5b4cbdffd39a1bba41a61f87fe9 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Thu, 19 Nov 2015 11:45:32 +0800 Subject: ASoC: Atmel: ClassD: supports mono audio Modify the code to support mono audio. Signed-off-by: Songjun Wu Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-classd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 8276675730ef..dca614177fef 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -106,7 +106,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = { .rates = ATMEL_CLASSD_RATES, .rate_min = 8000, .rate_max = 96000, - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 256, @@ -145,7 +145,7 @@ static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { static struct snd_soc_dai_driver atmel_classd_cpu_dai = { .playback = { - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, @@ -171,9 +171,13 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream, return -EINVAL; } + if (params_channels(params) == 1) + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config->direction = DMA_MEM_TO_DEV; slave_config->dst_addr = dd->phy_base + CLASSD_THR; - slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; slave_config->dst_maxburst = 1; slave_config->src_maxburst = 1; slave_config->device_fc = false; @@ -486,7 +490,7 @@ static struct snd_soc_dai_driver atmel_classd_codec_dai = { .name = ATMEL_CLASSD_CODEC_DAI_NAME, .playback = { .stream_name = "Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, -- cgit v1.2.3 From abd657b1278c9cbf42cdd9654352f082b37e2793 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 20 Nov 2015 22:45:20 +0530 Subject: ASoC: fsl-asoc-card: Update the rtd query sound card rtd was an array and was updated to a list so update the driver to use a list Reported-by: Stephen Rothwell Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index f4b6c53146d5..c63d89da51f1 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -417,14 +417,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, static int fsl_asoc_card_late_probe(struct snd_soc_card *card) { struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd = list_first_entry( + &card->rtd_list, struct snd_soc_pcm_runtime, list); + struct snd_soc_dai *codec_dai = rtd->codec_dai; struct codec_priv *codec_priv = &priv->codec_priv; struct device *dev = card->dev; int ret; if (fsl_asoc_card_is_ac97(priv)) { #if IS_ENABLED(CONFIG_SND_AC97_CODEC) - struct snd_soc_codec *codec = card->rtd[0].codec; + struct snd_soc_codec *codec = rtd->codec; struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); /* -- cgit v1.2.3 From 85af2a665144f40cdf60c0e0e7fe88e40c20b0fa Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 20 Nov 2015 22:34:41 +0530 Subject: ASoC: Intel: Skylake: Update the rtd query sound card rtd was an array and was updated to a list so update the driver to use a list Reported-by: Stephen Rothwell Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 3f5a96b585b8..65c65d4c422c 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -35,12 +35,10 @@ static struct snd_soc_card skylake_audio_card; static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; + list_for_each_entry(rtd, &card->rtd_list, list) { - rtd = card->rtd + i; if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI, strlen(SKL_NUVOTON_CODEC_DAI))) return rtd->codec_dai; -- cgit v1.2.3 From 18560a4e3b07438113b50589e78532d95f907029 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 20 Nov 2015 15:43:06 -0800 Subject: ASoC: qcom: Specify LE device endianness This is a little endian device, but so far we've been relying on the regmap mmio bus handling this for us without explicitly stating that fact. After commit 4a98da2164cf (regmap-mmio: Use native endianness for read/write, 2015-10-29), the regmap mmio bus will read/write with the __raw_*() IO accessors, instead of using the readl/writel() APIs that do proper byte swapping for little endian devices. So if we're running on a big endian processor and haven't specified the endianness explicitly in the regmap config or in DT, we're going to switch from doing little endian byte swapping to big endian accesses without byte swapping, leading to some confusing results. Specify the endianness explicitly so that the regmap core properly byte swaps the accesses for us. Cc: Kenneth Westfield Cc: Kevin Hilman Cc: Tyler Baker Cc: Simon Arlott Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e5101e0d2d37..00b6c9d039cf 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -355,6 +355,7 @@ static struct regmap_config lpass_cpu_regmap_config = { .readable_reg = lpass_cpu_regmap_readable, .volatile_reg = lpass_cpu_regmap_volatile, .cache_type = REGCACHE_FLAT, + .val_format_endian = REGMAP_ENDIAN_LITTLE, }; int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) -- cgit v1.2.3 From e6e969f1fd332e7525c577c0d8cfcbe898409abd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Nov 2015 22:16:48 +0100 Subject: ASoC: sh: fix fsi build warnings for 64 bit As this driver can now be compiled for ARM64, we get a new warning as a result of passing a DMA filter data pointer through an 'int': sound/soc/sh/fsi.c: In function 'fsi_dma_probe': sound/soc/sh/fsi.c:1372:24: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] shdma_chan_filter, (void *)io->dma_id, We already know that we only need the legacy filter function on arch/sh, so we can hide the legacy DMA interface function behind an #ifdef. This has the other advantage of no longer depending on the shdma_chan_filter function to be visible. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0215c78cbddf..ead520182e26 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1362,15 +1362,18 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) { - dma_cap_mask_t mask; int is_play = fsi_stream_is_play(fsi, io); +#ifdef CONFIG_SUPERH + dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - io->chan = dma_request_slave_channel_compat(mask, - shdma_chan_filter, (void *)io->dma_id, - dev, is_play ? "tx" : "rx"); + io->chan = dma_request_channel(mask, shdma_chan_filter, + (void *)io->dma_id); +#else + io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx"); +#endif if (io->chan) { struct dma_slave_config cfg = {}; int ret; -- cgit v1.2.3 From 9bdca822cbd6b66124f2298504b6c4526599dc8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Nov 2015 22:31:11 +0100 Subject: ASoC: samsung: pass filter function as pointer As we are now passing the filter data as pointers to the drivers, we can take the final step and also pass the filter function the same way. I'm keeping this change separate, as there it's less obvious that this is a net win. Upsides of this are: - The ASoC drivers are completely independent from the DMA engine implementation, which simplifies the Kconfig logic and in theory allows the same sound drivers to be built in a kernel that supports different kinds of dmaengine drivers. - Consistency with other subsystems and drivers On the other hand, we have a few downsides: - The s3c24xx-dma driver now needs to be built-in for the ac97 platform device to be instantiated on s3c2440. - samsung_dmaengine_pcm_config cannot be marked 'const' any more because the filter function pointer needs to be set at runtime. This is safe as long we don't have multiple different DMA engines in thet same system at runtime, but is nonetheless ugly. Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/dev-audio.c | 6 ++++++ arch/arm/plat-samsung/devs.c | 6 ++++++ drivers/dma/Kconfig | 2 +- include/linux/platform_data/asoc-s3c.h | 4 ++++ sound/soc/samsung/Kconfig | 2 -- sound/soc/samsung/ac97.c | 3 ++- sound/soc/samsung/dma.h | 4 +++- sound/soc/samsung/dmaengine.c | 16 +++++----------- sound/soc/samsung/i2s.c | 11 ++++++++--- sound/soc/samsung/pcm.c | 5 ++++- sound/soc/samsung/s3c2412-i2s.c | 4 ++-- sound/soc/samsung/s3c24xx-i2s.c | 4 ++-- sound/soc/samsung/spdif.c | 9 +++++++-- 13 files changed, 50 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c index 9a42736ef4ac..b57783371d52 100644 --- a/arch/arm/mach-s3c64xx/dev-audio.c +++ b/arch/arm/mach-s3c64xx/dev-audio.c @@ -58,6 +58,7 @@ static struct resource s3c64xx_iis0_resource[] = { static struct s3c_audio_pdata i2s0_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, .dma_playback = DMACH_I2S0_OUT, .dma_capture = DMACH_I2S0_IN, }; @@ -79,6 +80,7 @@ static struct resource s3c64xx_iis1_resource[] = { static struct s3c_audio_pdata i2s1_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, .dma_playback = DMACH_I2S1_OUT, .dma_capture = DMACH_I2S1_IN, }; @@ -100,6 +102,7 @@ static struct resource s3c64xx_iisv4_resource[] = { static struct s3c_audio_pdata i2sv4_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, .dma_playback = DMACH_HSI_I2SV40_TX, .dma_capture = DMACH_HSI_I2SV40_RX, .type = { @@ -150,6 +153,7 @@ static struct resource s3c64xx_pcm0_resource[] = { static struct s3c_audio_pdata s3c_pcm0_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_filter = pl08x_filter_id, .dma_capture = DMACH_PCM0_RX, .dma_playback = DMACH_PCM0_TX, }; @@ -171,6 +175,7 @@ static struct resource s3c64xx_pcm1_resource[] = { static struct s3c_audio_pdata s3c_pcm1_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_filter = pl08x_filter_id, .dma_playback = DMACH_PCM1_TX, .dma_capture = DMACH_PCM1_RX, }; @@ -205,6 +210,7 @@ static struct resource s3c64xx_ac97_resource[] = { static struct s3c_audio_pdata s3c_ac97_pdata = { .dma_playback = DMACH_AC97_PCMOUT, + .dma_filter = pl08x_filter_id, .dma_capture = DMACH_AC97_PCMIN, .dma_capture_mic = DMACH_AC97_MICIN, }; diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 823de7b4e53b..7263e95a6f35 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -78,6 +78,9 @@ static struct resource s3c_ac97_resource[] = { }; static struct s3c_audio_pdata s3c_ac97_pdata = { +#ifdef CONFIG_S3C24XX_DMAC + .dma_filter = s3c24xx_dma_filter, +#endif .dma_playback = (void *)DMACH_PCM_OUT, .dma_capture = (void *)DMACH_PCM_IN, .dma_capture_mic = (void *)DMACH_MIC_IN, @@ -572,6 +575,9 @@ static struct resource s3c_iis_resource[] = { }; static struct s3c_audio_pdata s3c_iis_platdata = { +#ifdef CONFIG_S3C24XX_DMAC + .dma_filter = s3c24xx_dma_filter, +#endif .dma_playback = (void *)DMACH_I2S_OUT, .dma_capture = (void *)DMACH_I2S_IN, }; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index e6cd1a32025a..17655d9ba518 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -432,7 +432,7 @@ config STE_DMA40 Support for ST-Ericsson DMA40 controller config S3C24XX_DMAC - tristate "Samsung S3C24XX DMA support" + bool "Samsung S3C24XX DMA support" depends on ARCH_S3C24XX select DMA_ENGINE select DMA_VIRTUAL_CHANNELS diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index 33f88b4479e4..15bf56ee8af7 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h @@ -13,6 +13,9 @@ */ #define S3C64XX_AC97_GPD 0 #define S3C64XX_AC97_GPE 1 + +#include + extern void s3c64xx_ac97_setup_gpio(int); struct samsung_i2s { @@ -39,6 +42,7 @@ struct samsung_i2s { */ struct s3c_audio_pdata { int (*cfg_gpio)(struct platform_device *); + dma_filter_fn dma_filter; void *dma_playback; void *dma_capture; void *dma_play_sec; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 3744c9ed5370..78baa26e938b 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,8 +1,6 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" depends on (PLAT_SAMSUNG || ARCH_EXYNOS) - depends on S3C64XX_PL080 || !ARCH_S3C64XX - depends on S3C24XX_DMAC || !ARCH_S3C24XX select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 9c5219392460..4a7a503fe13c 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -388,7 +388,8 @@ static int s3c_ac97_probe(struct platform_device *pdev) if (ret) goto err5; - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + ac97_pdata->dma_filter); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err5; diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 085ef30f5ca2..a7616cc9b39e 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -13,6 +13,7 @@ #define _S3C_AUDIO_H #include +#include struct s3c_dma_params { void *slave; /* Channel ID */ @@ -25,6 +26,7 @@ struct s3c_dma_params { void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, struct s3c_dma_params *playback, struct s3c_dma_params *capture); -int samsung_asoc_dma_platform_register(struct device *dev); +int samsung_asoc_dma_platform_register(struct device *dev, + dma_filter_fn fn); #endif diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 727008d57d14..063125937311 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -28,17 +28,8 @@ #include "dma.h" -#ifdef CONFIG_ARCH_S3C64XX -#define filter_fn pl08x_filter_id -#elif defined(CONFIG_ARCH_S3C24XX) -#define filter_fn s3c24xx_dma_filter -#else -#define filter_fn NULL -#endif - -static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { +static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .compat_filter_fn = filter_fn, }; void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, @@ -67,8 +58,11 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); -int samsung_asoc_dma_platform_register(struct device *dev) +int samsung_asoc_dma_platform_register(struct device *dev, + dma_filter_fn filter) { + samsung_dmaengine_pcm_config.compat_filter_fn = filter; + return devm_snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config, SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME | diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 0945b5de39e7..84d9e77c0fbe 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -89,6 +89,7 @@ struct i2s_dai { struct s3c_dma_params dma_playback; struct s3c_dma_params dma_capture; struct s3c_dma_params idma_playback; + dma_filter_fn filter; u32 quirks; u32 suspend_i2smod; u32 suspend_i2scon; @@ -1244,7 +1245,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret != 0) return ret; - return samsung_asoc_dma_platform_register(&pdev->dev); + return samsung_asoc_dma_platform_register(&pdev->dev, + sec_dai->filter); } pri_dai = i2s_alloc_dai(pdev, false); @@ -1264,6 +1266,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_playback.slave = i2s_pdata->dma_playback; pri_dai->dma_capture.slave = i2s_pdata->dma_capture; + pri_dai->filter = i2s_pdata->dma_filter; if (&i2s_pdata->type) i2s_cfg = &i2s_pdata->type.i2s; @@ -1325,8 +1328,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.ch_name = "tx-sec"; - if (!np) + if (!np) { sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec; + sec_dai->filter = i2s_pdata->dma_filter; + } sec_dai->dma_playback.dma_size = 4; sec_dai->addr = pri_dai->addr; @@ -1348,7 +1353,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter); if (ret != 0) return ret; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c77f324e0bb8..498f563a4c9c 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -488,6 +488,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) struct s3c_pcm_info *pcm; struct resource *mem_res; struct s3c_audio_pdata *pcm_pdata; + dma_filter_fn filter; int ret; /* Check for valid device index */ @@ -556,9 +557,11 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start + S3C_PCM_TXFIFO; + filter = NULL; if (pcm_pdata) { s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture; s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback; + filter = pcm_pdata->dma_filter; } pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; @@ -573,7 +576,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) goto err5; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err5; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 105317f523f2..204029d12f5b 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -177,7 +176,8 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + pdata->dma_filter); if (ret) pr_err("failed to register the DMA: %d\n", ret); diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 9e6a5bc012e3..b3a475d73ba7 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include "regs-iis.h" @@ -482,7 +481,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + pdata->dma_filter); if (ret) pr_err("failed to register the dma: %d\n", ret); diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 9dd7ee6d03ff..4687f521197c 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -361,6 +361,7 @@ static int spdif_probe(struct platform_device *pdev) struct s3c_audio_pdata *spdif_pdata; struct resource *mem_res; struct samsung_spdif_info *spdif; + dma_filter_fn filter; int ret; spdif_pdata = pdev->dev.platform_data; @@ -426,11 +427,15 @@ static int spdif_probe(struct platform_device *pdev) spdif_stereo_out.dma_size = 2; spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF; - spdif_stereo_out.slave = spdif_pdata ? spdif_pdata->dma_playback : NULL; + filter = NULL; + if (spdif_pdata) { + spdif_stereo_out.slave = spdif_pdata->dma_playback; + filter = spdif_pdata->dma_filter; + } spdif->dma_playback = &spdif_stereo_out; - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); if (ret) { dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); goto err4; -- cgit v1.2.3 From d16a2b9f2465b5486f830178fbfb7d203e0a17ae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Nov 2015 13:04:20 +0300 Subject: ASoC: Intel: pass correct parameter in sst_alloc_stream_mrfld() "data" is always NULL in this function. I think we should be passing "&data" to sst_prepare_and_post_msg() instead of "data". Fixes: 3d9ff34622ba ('ASoC: Intel: sst: add stream operations') Signed-off-by: Dan Carpenter Tested-by: Dinesh Mirche Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index a74c64c7053c..4ccc80e5e8cc 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -108,7 +108,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), - &alloc_param, data, true, true, false, true); + &alloc_param, &data, true, true, false, true); if (ret < 0) { dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); -- cgit v1.2.3 From 18382ead3640b5aab9bf4545249d84b51bbcba49 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 10 Nov 2015 18:42:06 +0530 Subject: ASoC: hdac-hdmi: Add hdmi driver This adds HDA based HDMI driver to be used in platforms like SKL and onwards Register the hdmi driver with hda bus and register dais. Also parse the widget and initialize identified pin and converter widgets. For simplification, currently only one pin and one converter widget are enabled on board, as well as limit the rates supported to simples ones and not based on ELD. This things will come eventually once basic support for this is merged Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdac_hdmi.c | 344 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 351 insertions(+) create mode 100644 sound/soc/codecs/hdac_hdmi.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..b2b0b71f0bcf 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -67,6 +67,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES8328_I2C if I2C select SND_SOC_GTM601 select SND_SOC_ICS43432 + select SND_SOC_HDAC_HDMI select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -454,6 +455,10 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDAC_HDMI + tristate + select SND_HDA_EXT_CORE + config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..6359bdcf7f89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -60,6 +60,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-ics43432-objs := ics43432.o +snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -255,6 +256,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o +obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c new file mode 100644 index 000000000000..d37d688fa40a --- /dev/null +++ b/sound/soc/codecs/hdac_hdmi.c @@ -0,0 +1,344 @@ +/* + * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Samreen Nilofer + * Subhransu S. Prusty + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include "../../hda/local.h" + +#define PIN_OUT (AC_PINCTL_OUT_EN) +#define HDA_MAX_CONNECTIONS 32 + +struct hdac_hdmi_cvt_params { + unsigned int channels_min; + unsigned int channels_max; + u32 rates; + u64 formats; + unsigned int maxbps; +}; + +struct hdac_hdmi_cvt { + hda_nid_t nid; + struct hdac_hdmi_cvt_params params; +}; + +struct hdac_hdmi_pin { + hda_nid_t nid; + int num_mux_nids; + hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; +}; + +struct hdac_hdmi_dai_pin_map { + int dai_id; + struct hdac_hdmi_pin pin; + struct hdac_hdmi_cvt cvt; +}; + +struct hdac_hdmi_priv { + hda_nid_t pin_nid[3]; + hda_nid_t cvt_nid[3]; + struct hdac_hdmi_dai_pin_map dai_map[3]; +}; + +static int +hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) +{ + int err; + + /* Only stereo supported as of now */ + cvt->params.channels_min = cvt->params.channels_max = 2; + + err = snd_hdac_query_supported_pcm(hdac, cvt->nid, + &cvt->params.rates, + &cvt->params.formats, + &cvt->params.maxbps); + if (err < 0) + dev_err(&hdac->dev, + "Failed to query pcm params for nid %d: %d\n", + cvt->nid, err); + + return err; +} + +static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin) +{ + if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { + dev_warn(&hdac->hdac.dev, + "HDMI: pin %d wcaps %#x does not support connection list\n", + pin->nid, get_wcaps(&hdac->hdac, pin->nid)); + return -EINVAL; + } + + pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + pin->mux_nids, HDA_MAX_CONNECTIONS); + if (pin->num_mux_nids == 0) { + dev_err(&hdac->hdac.dev, "No connections found\n"); + return -ENODEV; + } + + return pin->num_mux_nids; +} + +static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_type id, + const char *wname, const char *stream) +{ + w->id = id; + w->name = wname; + w->sname = stream; + w->reg = SND_SOC_NOPM; + w->shift = 0; + w->kcontrol_news = NULL; + w->num_kcontrols = 0; + w->priv = NULL; +} + +static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, + const char *sink, const char *control, const char *src) +{ + route->sink = sink; + route->source = src; + route->control = control; + route->connected = NULL; +} + +static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, + struct hdac_hdmi_dai_pin_map *dai_map) +{ + struct snd_soc_dapm_route route[1]; + struct snd_soc_dapm_widget widgets[2] = { {0} }; + + memset(&route, 0, sizeof(route)); + + hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, + "hif1 Output", NULL); + hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, + "Coverter 1", "hif1"); + + hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); + + snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); + snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); +} + +static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map, + hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id) +{ + int ret; + + dai_map->dai_id = dai_id; + dai_map->pin.nid = pin_nid; + + ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); + if (ret < 0) { + dev_err(&edev->hdac.dev, + "Error querying connection list: %d\n", ret); + return ret; + } + + dai_map->cvt.nid = cvt_nid; + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); + + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); + + snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, 0); + + return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt); +} + +/* + * Parse all nodes and store the cvt/pin nids in array + * Add one time initialization for pin and cvt widgets + */ +static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) +{ + hda_nid_t nid; + int i; + struct hdac_device *hdac = &edev->hdac; + struct hdac_hdmi_priv *hdmi = edev->private_data; + int cvt_nid = 0, pin_nid = 0; + + hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); + if (!nid || hdac->num_nodes < 0) { + dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); + return -EINVAL; + } + + hdac->start_nid = nid; + + for (i = 0; i < hdac->num_nodes; i++, nid++) { + unsigned int caps; + unsigned int type; + + caps = get_wcaps(hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + switch (type) { + + case AC_WID_AUD_OUT: + hdmi->cvt_nid[cvt_nid] = nid; + cvt_nid++; + break; + + case AC_WID_PIN: + hdmi->pin_nid[pin_nid] = nid; + pin_nid++; + break; + } + } + + hdac->end_nid = nid; + + if (!pin_nid || !cvt_nid) + return -EIO; + + /* + * Currently on board only 1 pin and 1 converter is enabled for + * simplification, more will be added eventually + * So using fixed map for dai_id:pin:cvt + */ + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], + hdmi->cvt_nid[0], 0); +} + +static int hdmi_codec_probe(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(&codec->component); + + edev->scodec = codec; + + create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); + + /* Imp: Store the card pointer in hda_codec */ + edev->card = dapm->card->snd_card; + + return 0; +} + +static struct snd_soc_codec_driver hdmi_hda_codec = { + .probe = hdmi_codec_probe, + .idle_bias_off = true, +}; + +static struct snd_soc_dai_driver hdmi_dais[] = { + { .name = "intel-hdmi-hif1", + .playback = { + .stream_name = "hif1", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + + }, + }, +}; + +static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) +{ + struct hdac_device *codec = &edev->hdac; + struct hdac_hdmi_priv *hdmi_priv; + int ret = 0; + + hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); + if (hdmi_priv == NULL) + return -ENOMEM; + + edev->private_data = hdmi_priv; + + dev_set_drvdata(&codec->dev, edev); + + ret = hdac_hdmi_parse_and_map_nid(edev); + if (ret < 0) + return ret; + + /* ASoC specific initialization */ + return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, + hdmi_dais, ARRAY_SIZE(hdmi_dais)); +} + +static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) +{ + snd_soc_unregister_codec(&edev->hdac.dev); + + return 0; +} + +static const struct hda_device_id hdmi_list[] = { + HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), + {} +}; + +MODULE_DEVICE_TABLE(hdaudio, hdmi_list); + +static struct hdac_ext_driver hdmi_driver = { + . hdac = { + .driver = { + .name = "HDMI HDA Codec", + }, + .id_table = hdmi_list, + }, + .probe = hdac_hdmi_dev_probe, + .remove = hdac_hdmi_dev_remove, +}; + +static int __init hdmi_init(void) +{ + return snd_hda_ext_driver_register(&hdmi_driver); +} + +static void __exit hdmi_exit(void) +{ + snd_hda_ext_driver_unregister(&hdmi_driver); +} + +module_init(hdmi_init); +module_exit(hdmi_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HDMI HD codec"); +MODULE_AUTHOR("Samreen Nilofer"); +MODULE_AUTHOR("Subhransu S. Prusty"); -- cgit v1.2.3 From e342ac08d0d57be81e5defb131f014b4ce27b107 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 10 Nov 2015 18:42:07 +0530 Subject: ASoC: hdac_hdmi: Add PM support for HDMI Power up/down the AFG node during runtime resume/suspend. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d37d688fa40a..45dfc4f608e5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -60,6 +60,13 @@ struct hdac_hdmi_priv { struct hdac_hdmi_dai_pin_map dai_map[3]; }; +static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) +{ + struct hdac_device *hdac = container_of(dev, struct hdac_device, dev); + + return container_of(hdac, struct hdac_ext_device, hdac); +} + static int hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) { @@ -250,11 +257,28 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; + /* + * hdac_device core already sets the state to active and calls + * get_noresume. So enable runtime and set the device to suspend. + */ + pm_runtime_enable(&edev->hdac.dev); + pm_runtime_put(&edev->hdac.dev); + pm_runtime_suspend(&edev->hdac.dev); + + return 0; +} + +static int hdmi_codec_remove(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + + pm_runtime_disable(&edev->hdac.dev); return 0; } static struct snd_soc_codec_driver hdmi_hda_codec = { .probe = hdmi_codec_probe, + .remove = hdmi_codec_remove, .idle_bias_off = true, }; @@ -307,6 +331,45 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) return 0; } +#ifdef CONFIG_PM +static int hdac_hdmi_runtime_suspend(struct device *dev) +{ + struct hdac_ext_device *edev = to_hda_ext_device(dev); + struct hdac_device *hdac = &edev->hdac; + + dev_dbg(dev, "Enter: %s\n", __func__); + + /* Power down afg */ + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) + snd_hdac_codec_write(hdac, hdac->afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + return 0; +} + +static int hdac_hdmi_runtime_resume(struct device *dev) +{ + struct hdac_ext_device *edev = to_hda_ext_device(dev); + struct hdac_device *hdac = &edev->hdac; + + dev_dbg(dev, "Enter: %s\n", __func__); + + /* Power up afg */ + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) + snd_hdac_codec_write(hdac, hdac->afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + return 0; +} +#else +#define hdac_hdmi_runtime_suspend NULL +#define hdac_hdmi_runtime_resume NULL +#endif + +static const struct dev_pm_ops hdac_hdmi_pm = { + SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) +}; + static const struct hda_device_id hdmi_list[] = { HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), {} @@ -318,6 +381,7 @@ static struct hdac_ext_driver hdmi_driver = { . hdac = { .driver = { .name = "HDMI HDA Codec", + .pm = &hdac_hdmi_pm, }, .id_table = hdmi_list, }, -- cgit v1.2.3 From b0362adbeb95b57d9739b0744772eaf9feaa6e5e Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 10 Nov 2015 18:42:08 +0530 Subject: ASoC: hdac_hdmi: Add hdac hdmi dai ops The DAI ops are used for triggering HDMI streams and configuring the parameters Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 162 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 45dfc4f608e5..f96bd2fb634b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -26,7 +26,10 @@ #include #include "../../hda/local.h" +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 #define PIN_OUT (AC_PINCTL_OUT_EN) + #define HDA_MAX_CONNECTIONS 32 struct hdac_hdmi_cvt_params { @@ -67,6 +70,156 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) return container_of(hdac, struct hdac_ext_device, hdac); } +static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, + hda_nid_t cvt_nid, hda_nid_t pin_nid, + u32 stream_tag, int format) +{ + unsigned int val; + + dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", + cvt_nid, pin_nid, stream_tag, format); + + val = (stream_tag << 4); + + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, val); + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_STREAM_FORMAT, format); + + return 0; +} + +static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) +{ + /* Power up pin widget */ + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); + + /* Power up converter */ + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); +} + +static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_ext_dma_params *dd; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dai_map = &hdmi->dai_map[dai->id]; + + dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); + dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", + dd->stream_tag, dd->format); + + return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, + dd->stream_tag, dd->format); +} + +static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_ext_dma_params *dd; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + dd->format = snd_hdac_calc_stream_format(params_rate(hparams), + params_channels(hparams), params_format(hparams), + 24, 0); + + snd_soc_dai_set_dma_data(dai, substream, (void *)dd); + + return 0; +} + +static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_ext_dma_params *dd; + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + + dai_map = &hdmi->dai_map[dai->id]; + + snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + AC_VERB_SET_STREAM_FORMAT, 0); + + dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + + kfree(dd); + + return 0; +} + +static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + int val; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dai_map = &hdmi->dai_map[dai->id]; + + val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); + + if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) { + dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val); + return -ENODEV; + } + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); + + snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + + return 0; +} + +static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + + dai_map = &hdmi->dai_map[dai->id]; + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); + + snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); +} + static int hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) { @@ -282,6 +435,14 @@ static struct snd_soc_codec_driver hdmi_hda_codec = { .idle_bias_off = true, }; +static struct snd_soc_dai_ops hdmi_dai_ops = { + .startup = hdac_hdmi_pcm_open, + .shutdown = hdac_hdmi_pcm_close, + .hw_params = hdac_hdmi_set_hw_params, + .prepare = hdac_hdmi_playback_prepare, + .hw_free = hdac_hdmi_playback_cleanup, +}; + static struct snd_soc_dai_driver hdmi_dais[] = { { .name = "intel-hdmi-hif1", .playback = { @@ -298,6 +459,7 @@ static struct snd_soc_dai_driver hdmi_dais[] = { SNDRV_PCM_FMTBIT_S32_LE, }, + .ops = &hdmi_dai_ops, }, }; -- cgit v1.2.3 From a657f1d05fd3eadb61f771e659f5d42940003d93 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 10 Nov 2015 18:42:09 +0530 Subject: ASoC: hdac_hdmi: Setup and start infoframe This patch uses hdmi framework in video to fill audio infoframe. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f96bd2fb634b..c02e6d3a6314 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,60 @@ static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, return 0; } +static void +hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, + hda_nid_t cvt_nid, hda_nid_t pin_nid) +{ + uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; + struct hdmi_audio_infoframe frame; + u8 *dip = (u8 *)&frame; + int ret; + int i; + + hdmi_audio_infoframe_init(&frame); + + /* Default stereo for now */ + frame.channels = 2; + + /* setup channel count */ + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1); + + ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (ret < 0) + return ret; + + /* stop infoframe transmission */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); + + + /* Fill infoframe. Index auto-incremented */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + for (i = 0; i < sizeof(frame); i++) + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_DATA, dip[i]); + + /* Start infoframe */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); + + return 0; +} + static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) { @@ -110,6 +165,7 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_ext_dma_params *dd; + int ret; if (dai->id > 0) { dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); @@ -122,6 +178,11 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dd->stream_tag, dd->format); + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid, + dai_map->pin.nid); + if (ret < 0) + return ret; + return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, dd->stream_tag, dd->format); } -- cgit v1.2.3 From 07f083aba92ffdd97df41516de6f80ef27a4a21b Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 10 Nov 2015 18:42:10 +0530 Subject: ASoC: hdac_hdmi: Use i915 component framework for PM Use the component framework to keep the display on till the playback in progress. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c02e6d3a6314..d1552620257f 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "../../hda/local.h" #define AMP_OUT_MUTE 0xb080 @@ -559,14 +560,26 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; + struct hdac_bus *bus = hdac->bus; + int err; dev_dbg(dev, "Enter: %s\n", __func__); + /* controller may not have been initialized for the first time */ + if (!bus) + return 0; + /* Power down afg */ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) snd_hdac_codec_write(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + return err; + } + return 0; } @@ -574,9 +587,21 @@ static int hdac_hdmi_runtime_resume(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; + struct hdac_bus *bus = hdac->bus; + int err; dev_dbg(dev, "Enter: %s\n", __func__); + /* controller may not have been initialized for the first time */ + if (!bus) + return 0; + + err = snd_hdac_display_power(bus, true); + if (err < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + return err; + } + /* Power up afg */ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) snd_hdac_codec_write(hdac, hdac->afg, 0, -- cgit v1.2.3 From 7a7a2df434cec5614271666b84b2ea1f41048e91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 21 Nov 2015 12:01:22 +0100 Subject: ALSA: azt3328: Remove unnecessary synchronize_irq() before free_irq() Calling synchronize_irq() right before free_irq() is quite useless. On one hand the IRQ can easily fire again before free_irq() is entered, on the other hand free_irq() itself calls synchronize_irq() internally (in a race condition free way) before any state associated with the IRQ is freed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 07a4acc99541..5e2ef0bb7057 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2294,8 +2294,6 @@ snd_azf3328_free(struct snd_azf3328 *chip) snd_azf3328_timer_stop(chip->timer); snd_azf3328_gameport_free(chip); - if (chip->irq >= 0) - synchronize_irq(chip->irq); __end_hw: if (chip->irq >= 0) free_irq(chip->irq, chip); -- cgit v1.2.3 From efdbe3c3edb6c8c98a8be863f60916780a5375c1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 22 Nov 2015 08:55:07 +0100 Subject: ALSA: midi: constify snd_rawmidi_global_ops structures The snd_rawmidi_global_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 2 +- sound/core/seq/seq_virmidi.c | 2 +- sound/usb/midi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index f6cbef78db62..fdabbb4ddba9 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -130,7 +130,7 @@ struct snd_rawmidi { int ossreg; #endif - struct snd_rawmidi_global_ops *ops; + const struct snd_rawmidi_global_ops *ops; struct snd_rawmidi_str streams[2]; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 56e0f4cd3f82..3da2d48610b3 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -468,7 +468,7 @@ static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi) /* * */ -static struct snd_rawmidi_global_ops snd_virmidi_global_ops = { +static const struct snd_rawmidi_global_ops snd_virmidi_global_ops = { .dev_register = snd_virmidi_dev_register, .dev_unregister = snd_virmidi_dev_unregister, }; diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 5b4c58c3e2c5..ee212e71f180 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2206,7 +2206,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi, return 0; } -static struct snd_rawmidi_global_ops snd_usbmidi_ops = { +static const struct snd_rawmidi_global_ops snd_usbmidi_ops = { .get_port_info = snd_usbmidi_get_port_info, }; -- cgit v1.2.3 From cd470fae88042570e0b9f50a725ca39ee333583f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 22 Nov 2015 16:24:57 +0530 Subject: ASoC: Intel: Skylake: Fix test of a field address Skylake driver uses snd_dma_buffer for data and buffer, these are variables and not pointer so do not test field addresses. Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index b03d9db0acad..947a08e42e86 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -138,10 +138,8 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx) sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); - if (&ctx->cl_dev.dmab_data) - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); - if (&ctx->cl_dev.dmab_bdl) - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); } static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) -- cgit v1.2.3 From 96b96a743c65969ebf13c343837db2faff1a8a84 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 22 Nov 2015 16:24:58 +0530 Subject: ASoC: hdac-hdmi: make driver select CONFIG_HDMI Since driver use infoframe symbols from video/hdmi.c we should select this symbol for this driver Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b2b0b71f0bcf..5c584dad0af0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -458,6 +458,7 @@ config SND_SOC_DMIC config SND_SOC_HDAC_HDMI tristate select SND_HDA_EXT_CORE + select HDMI config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" -- cgit v1.2.3 From decbc00eb889d199edad737630fa882c0308d0ae Mon Sep 17 00:00:00 2001 From: ZhengShunQian Date: Mon, 9 Nov 2015 10:10:19 +0800 Subject: ASoC: rk3036: Inno codec driver for RK3036 SoC RK3036 SoC integrated with an Inno audio codec. This driver implements the functions of it. There is not need a special machine driver, since the simple-card machine driver works perfect in this case. Signed-off-by: ZhengShunQian Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/inno_rk3036.c | 491 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/inno_rk3036.h | 123 +++++++++++ 4 files changed, 620 insertions(+) create mode 100644 sound/soc/codecs/inno_rk3036.c create mode 100644 sound/soc/codecs/inno_rk3036.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..89d789e3a2d0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -67,6 +67,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES8328_I2C if I2C select SND_SOC_GTM601 select SND_SOC_ICS43432 + select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -471,6 +472,9 @@ config SND_SOC_GTM601 config SND_SOC_ICS43432 tristate +config SND_SOC_INNO_RK3036 + tristate "Inno codec driver for RK3036 SoC" + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..2f6bc6c01178 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -60,6 +60,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-ics43432-objs := ics43432.o +snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -255,6 +256,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o +obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c new file mode 100644 index 000000000000..24677a831c00 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.c @@ -0,0 +1,491 @@ +/* + * Driver of Inno codec for rk3036 by Rockchip Inc. + * + * Author: Rockchip Inc. + * Author: Zheng ShunQian + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inno_rk3036.h" + +struct rk3036_codec_priv { + void __iomem *base; + struct clk *pclk; + struct regmap *regmap; + struct device *dev; +}; + +static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0); + +static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int val, ret, regval; + + ret = snd_soc_component_read(component, INNO_R09, ®val); + if (ret) + return ret; + val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) & + INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; + ucontrol->value.integer.value[0] = val; + + val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) & + INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; + ucontrol->value.integer.value[1] = val; + + return 0; +} + +static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int val, ret, regmsk; + + val = (ucontrol->value.integer.value[0] ? + INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << + INNO_R09_HPL_ANITPOP_SHIFT; + val |= (ucontrol->value.integer.value[1] ? + INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << + INNO_R09_HPR_ANITPOP_SHIFT; + + regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT | + INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT; + + ret = snd_soc_component_update_bits(component, INNO_R09, + regmsk, val); + if (ret < 0) + return ret; + + return 0; +} + +#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \ + .put = rk3036_codec_antipop_put, } + +static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08, + INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB, + INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv), + SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT, + INNO_R06_VOUTR_CZ_SHIFT, 1, 0), + SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT, + INNO_R09_HPR_MUTE_SHIFT, 1, 0), + SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = { + SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09, + INNO_R09_DACL_SWITCH_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = { + SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09, + INNO_R09_DACR_SWITCH_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = { + SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05, + INNO_R05_HPL_WORK_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = { + SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05, + INNO_R05_HPR_WORK_SHIFT, 1, 0), +}; + +static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06, + INNO_R06_DAC_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04, + INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04, + INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06, + INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06, + INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04, + INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04, + INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04, + INNO_R04_DACL_SW_SHIFT, 0), + SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04, + INNO_R04_DACR_SW_SHIFT, 0), + + SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpl_mixer_controls, + ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpr_mixer_controls, + ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)), + + SND_SOC_DAPM_PGA("HP Left Out", INNO_R05, + INNO_R05_HPL_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HP Right Out", INNO_R05, + INNO_R05_HPR_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HP Left Switch", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpl_switch_controls, + ARRAY_SIZE(rk3036_codec_hpl_switch_controls)), + SND_SOC_DAPM_MIXER("HP Right Switch", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpr_switch_controls, + ARRAY_SIZE(rk3036_codec_hpr_switch_controls)), + + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + +static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = { + {"DACL VREF", NULL, "DAC PWR"}, + {"DACR VREF", NULL, "DAC PWR"}, + {"DACL HiLo VREF", NULL, "DAC PWR"}, + {"DACR HiLo VREF", NULL, "DAC PWR"}, + {"DACL CLK", NULL, "DAC PWR"}, + {"DACR CLK", NULL, "DAC PWR"}, + + {"DACL", NULL, "DACL VREF"}, + {"DACL", NULL, "DACL HiLo VREF"}, + {"DACL", NULL, "DACL CLK"}, + {"DACR", NULL, "DACR VREF"}, + {"DACR", NULL, "DACR HiLo VREF"}, + {"DACR", NULL, "DACR CLK"}, + + {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"}, + {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"}, + {"HP Left Out", NULL, "Left Headphone Mixer"}, + {"HP Right Out", NULL, "Right Headphone Mixer"}, + + {"HP Left Switch", "HP Left Out Switch", "HP Left Out"}, + {"HP Right Switch", "HP Right Out Switch", "HP Right Out"}, + + {"HPL", NULL, "HP Left Switch"}, + {"HPR", NULL, "HP Right Switch"}, +}; + +static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg01_val = 0, reg02_val = 0, reg03_val = 0; + + dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + reg01_val |= INNO_R01_PINDIR_IN_SLAVE | + INNO_R01_I2SMODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + reg01_val |= INNO_R01_PINDIR_OUT_MASTER | + INNO_R01_I2SMODE_MASTER; + break; + default: + dev_err(codec->dev, "invalid fmt\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + reg02_val |= INNO_R02_DACM_PCM; + break; + case SND_SOC_DAIFMT_I2S: + reg02_val |= INNO_R02_DACM_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + reg02_val |= INNO_R02_DACM_RJM; + break; + case SND_SOC_DAIFMT_LEFT_J: + reg02_val |= INNO_R02_DACM_LJM; + break; + default: + dev_err(codec->dev, "set dai format failed\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_BCP_NORMAL; + break; + case SND_SOC_DAIFMT_IB_IF: + reg02_val |= INNO_R02_LRCP_REVERSAL; + reg03_val |= INNO_R03_BCP_REVERSAL; + break; + case SND_SOC_DAIFMT_IB_NF: + reg02_val |= INNO_R02_LRCP_REVERSAL; + reg03_val |= INNO_R03_BCP_NORMAL; + break; + case SND_SOC_DAIFMT_NB_IF: + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_BCP_REVERSAL; + break; + default: + dev_err(codec->dev, "set dai format failed\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK | + INNO_R01_PINDIR_MSK, reg01_val); + snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | + INNO_R02_DACM_MSK, reg02_val); + snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val); + + return 0; +} + +static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg02_val = 0, reg03_val = 0; + + switch (params_format(hw_params)) { + case SNDRV_PCM_FORMAT_S16_LE: + reg02_val |= INNO_R02_VWL_16BIT; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + reg02_val |= INNO_R02_VWL_20BIT; + break; + case SNDRV_PCM_FORMAT_S24_LE: + reg02_val |= INNO_R02_VWL_24BIT; + break; + case SNDRV_PCM_FORMAT_S32_LE: + reg02_val |= INNO_R02_VWL_32BIT; + break; + default: + return -EINVAL; + } + + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK; + + snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | + INNO_R02_VWL_MSK, reg02_val); + snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK | + INNO_R03_FWL_MSK, reg03_val); + return 0; +} + +#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000) + +#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops rk3036_codec_dai_ops = { + .set_fmt = rk3036_codec_dai_set_fmt, + .hw_params = rk3036_codec_dai_hw_params, +}; + +static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = { + { + .name = "rk3036-codec-dai", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RK3036_CODEC_RATES, + .formats = RK3036_CODEC_FMTS, + }, + .ops = &rk3036_codec_dai_ops, + .symmetric_rates = 1, + }, +}; + +static void rk3036_codec_reset(struct snd_soc_codec *codec) +{ + snd_soc_write(codec, INNO_R00, + INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET); + snd_soc_write(codec, INNO_R00, + INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK); +} + +static int rk3036_codec_probe(struct snd_soc_codec *codec) +{ + rk3036_codec_reset(codec); + return 0; +} + +static int rk3036_codec_remove(struct snd_soc_codec *codec) +{ + rk3036_codec_reset(codec); + return 0; +} + +static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_STANDBY: + /* set a big current for capacitor charging. */ + snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); + /* start precharge */ + snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE); + + break; + + case SND_SOC_BIAS_OFF: + /* set a big current for capacitor discharging. */ + snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); + /* start discharge. */ + snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE); + + break; + default: + break; + } + + return 0; +} + +static struct snd_soc_codec_driver rk3036_codec_driver = { + .probe = rk3036_codec_probe, + .remove = rk3036_codec_remove, + .set_bias_level = rk3036_codec_set_bias_level, + .controls = rk3036_codec_dapm_controls, + .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), + .dapm_routes = rk3036_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), + .dapm_widgets = rk3036_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), +}; + +static const struct regmap_config rk3036_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +#define GRF_SOC_CON0 0x00140 +#define GRF_ACODEC_SEL (BIT(10) | BIT(16 + 10)) + +static int rk3036_codec_platform_probe(struct platform_device *pdev) +{ + struct rk3036_codec_priv *priv; + struct device_node *of_node = pdev->dev.of_node; + struct resource *res; + void __iomem *base; + struct regmap *grf; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv->base = base; + priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base, + &rk3036_codec_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&pdev->dev, "init regmap failed\n"); + return PTR_ERR(priv->regmap); + } + + grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, "needs 'rockchip,grf' property\n"); + return PTR_ERR(grf); + } + ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL); + if (ret) { + dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + + priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk"); + if (IS_ERR(priv->pclk)) + return PTR_ERR(priv->pclk); + + ret = clk_prepare_enable(priv->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clk\n"); + return ret; + } + + priv->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, priv); + + ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver, + rk3036_codec_dai_driver, + ARRAY_SIZE(rk3036_codec_dai_driver)); + if (ret) { + clk_disable_unprepare(priv->pclk); + dev_set_drvdata(&pdev->dev, NULL); + } + + return ret; +} + +static int rk3036_codec_platform_remove(struct platform_device *pdev) +{ + struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->pclk); + + return 0; +} + +static const struct of_device_id rk3036_codec_of_match[] = { + { .compatible = "rockchip,rk3036-codec", }, + {} +}; +MODULE_DEVICE_TABLE(of, rk3036_codec_of_match); + +static struct platform_driver rk3036_codec_platform_driver = { + .driver = { + .name = "rk3036-codec-platform", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rk3036_codec_of_match), + }, + .probe = rk3036_codec_platform_probe, + .remove = rk3036_codec_platform_remove, +}; + +module_platform_driver(rk3036_codec_platform_driver); + +MODULE_AUTHOR("Rockchip Inc."); +MODULE_DESCRIPTION("Rockchip rk3036 codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h new file mode 100644 index 000000000000..da759c6c7501 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.h @@ -0,0 +1,123 @@ +/* + * Driver of Inno Codec for rk3036 by Rockchip Inc. + * + * Author: Zheng ShunQian + */ + +#ifndef _INNO_RK3036_CODEC_H +#define _INNO_RK3036_CODEC_H + +/* codec registers */ +#define INNO_R00 0x00 +#define INNO_R01 0x0c +#define INNO_R02 0x10 +#define INNO_R03 0x14 +#define INNO_R04 0x88 +#define INNO_R05 0x8c +#define INNO_R06 0x90 +#define INNO_R07 0x94 +#define INNO_R08 0x98 +#define INNO_R09 0x9c +#define INNO_R10 0xa0 + +/* register bit filed */ +#define INNO_R00_CSR_RESET (0x0 << 0) /*codec system reset*/ +#define INNO_R00_CSR_WORK (0x1 << 0) +#define INNO_R00_CDCR_RESET (0x0 << 1) /*codec digital core reset*/ +#define INNO_R00_CDCR_WORK (0x1 << 1) +#define INNO_R00_PRB_DISABLE (0x0 << 6) /*power reset bypass*/ +#define INNO_R00_PRB_ENABLE (0x1 << 6) + +#define INNO_R01_I2SMODE_MSK (0x1 << 4) +#define INNO_R01_I2SMODE_SLAVE (0x0 << 4) +#define INNO_R01_I2SMODE_MASTER (0x1 << 4) +#define INNO_R01_PINDIR_MSK (0x1 << 5) +#define INNO_R01_PINDIR_IN_SLAVE (0x0 << 5) /*direction of pin*/ +#define INNO_R01_PINDIR_OUT_MASTER (0x1 << 5) + +#define INNO_R02_LRS_MSK (0x1 << 2) +#define INNO_R02_LRS_NORMAL (0x0 << 2) /*DAC Left Right Swap*/ +#define INNO_R02_LRS_SWAP (0x1 << 2) +#define INNO_R02_DACM_MSK (0x3 << 3) +#define INNO_R02_DACM_PCM (0x3 << 3) /*DAC Mode*/ +#define INNO_R02_DACM_I2S (0x2 << 3) +#define INNO_R02_DACM_LJM (0x1 << 3) +#define INNO_R02_DACM_RJM (0x0 << 3) +#define INNO_R02_VWL_MSK (0x3 << 5) +#define INNO_R02_VWL_32BIT (0x3 << 5) /*1/2Frame Valid Word Len*/ +#define INNO_R02_VWL_24BIT (0x2 << 5) +#define INNO_R02_VWL_20BIT (0x1 << 5) +#define INNO_R02_VWL_16BIT (0x0 << 5) +#define INNO_R02_LRCP_MSK (0x1 << 7) +#define INNO_R02_LRCP_NORMAL (0x0 << 7) /*Left Right Polarity*/ +#define INNO_R02_LRCP_REVERSAL (0x1 << 7) + +#define INNO_R03_BCP_MSK (0x1 << 0) +#define INNO_R03_BCP_NORMAL (0x0 << 0) /*DAC bit clock polarity*/ +#define INNO_R03_BCP_REVERSAL (0x1 << 0) +#define INNO_R03_DACR_MSK (0x1 << 1) +#define INNO_R03_DACR_RESET (0x0 << 1) /*DAC Reset*/ +#define INNO_R03_DACR_WORK (0x1 << 1) +#define INNO_R03_FWL_MSK (0x3 << 2) +#define INNO_R03_FWL_32BIT (0x3 << 2) /*1/2Frame Word Length*/ +#define INNO_R03_FWL_24BIT (0x2 << 2) +#define INNO_R03_FWL_20BIT (0x1 << 2) +#define INNO_R03_FWL_16BIT (0x0 << 2) + +#define INNO_R04_DACR_SW_SHIFT 0 +#define INNO_R04_DACL_SW_SHIFT 1 +#define INNO_R04_DACR_CLK_SHIFT 2 +#define INNO_R04_DACL_CLK_SHIFT 3 +#define INNO_R04_DACR_VREF_SHIFT 4 +#define INNO_R04_DACL_VREF_SHIFT 5 + +#define INNO_R05_HPR_EN_SHIFT 0 +#define INNO_R05_HPL_EN_SHIFT 1 +#define INNO_R05_HPR_WORK_SHIFT 2 +#define INNO_R05_HPL_WORK_SHIFT 3 + +#define INNO_R06_VOUTR_CZ_SHIFT 0 +#define INNO_R06_VOUTL_CZ_SHIFT 1 +#define INNO_R06_DACR_HILO_VREF_SHIFT 2 +#define INNO_R06_DACL_HILO_VREF_SHIFT 3 +#define INNO_R06_DAC_EN_SHIFT 5 + +#define INNO_R06_DAC_PRECHARGE (0x0 << 4) /*PreCharge control for DAC*/ +#define INNO_R06_DAC_DISCHARGE (0x1 << 4) + +#define INNO_HP_GAIN_SHIFT 0 +/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */ +#define INNO_HP_GAIN_0DB 0x1a +#define INNO_HP_GAIN_N39DB 0x0 + +#define INNO_R09_HP_ANTIPOP_MSK 0x3 +#define INNO_R09_HP_ANTIPOP_OFF 0x1 +#define INNO_R09_HP_ANTIPOP_ON 0x2 +#define INNO_R09_HPR_ANITPOP_SHIFT 0 +#define INNO_R09_HPL_ANITPOP_SHIFT 2 +#define INNO_R09_HPR_MUTE_SHIFT 4 +#define INNO_R09_HPL_MUTE_SHIFT 5 +#define INNO_R09_DACR_SWITCH_SHIFT 6 +#define INNO_R09_DACL_SWITCH_SHIFT 7 + +#define INNO_R10_CHARGE_SEL_CUR_400I_YES (0x0 << 0) +#define INNO_R10_CHARGE_SEL_CUR_400I_NO (0x1 << 0) +#define INNO_R10_CHARGE_SEL_CUR_260I_YES (0x0 << 1) +#define INNO_R10_CHARGE_SEL_CUR_260I_NO (0x1 << 1) +#define INNO_R10_CHARGE_SEL_CUR_130I_YES (0x0 << 2) +#define INNO_R10_CHARGE_SEL_CUR_130I_NO (0x1 << 2) +#define INNO_R10_CHARGE_SEL_CUR_100I_YES (0x0 << 3) +#define INNO_R10_CHARGE_SEL_CUR_100I_NO (0x1 << 3) +#define INNO_R10_CHARGE_SEL_CUR_050I_YES (0x0 << 4) +#define INNO_R10_CHARGE_SEL_CUR_050I_NO (0x1 << 4) +#define INNO_R10_CHARGE_SEL_CUR_027I_YES (0x0 << 5) +#define INNO_R10_CHARGE_SEL_CUR_027I_NO (0x1 << 5) + +#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \ + INNO_R10_CHARGE_SEL_CUR_260I_YES | \ + INNO_R10_CHARGE_SEL_CUR_130I_YES | \ + INNO_R10_CHARGE_SEL_CUR_100I_YES | \ + INNO_R10_CHARGE_SEL_CUR_050I_YES | \ + INNO_R10_CHARGE_SEL_CUR_027I_YES) + +#endif -- cgit v1.2.3 From da46cd9e12397ef609431b52e2ce5f595cff78cf Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 9 Nov 2015 11:13:55 +0800 Subject: ASoC: rk3036: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/inno_rk3036.c:480:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/inno_rk3036.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 24677a831c00..9b6e8840a1b5 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -477,7 +477,6 @@ MODULE_DEVICE_TABLE(of, rk3036_codec_of_match); static struct platform_driver rk3036_codec_platform_driver = { .driver = { .name = "rk3036-codec-platform", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rk3036_codec_of_match), }, .probe = rk3036_codec_platform_probe, -- cgit v1.2.3 From 8d33ab24242c5ce2f8e4add8c04d5409e36a330c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 23 Nov 2015 17:45:13 +0530 Subject: ASoC: hdac_hdmi: fix possible NULL dereference kzalloc() can return NULL if it fails, and then we will be dereferencing a NULL pointer. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d1552620257f..205f2c27263d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -200,6 +200,8 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, } dd = kzalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; dd->format = snd_hdac_calc_stream_format(params_rate(hparams), params_channels(hparams), params_format(hparams), 24, 0); -- cgit v1.2.3 From 9049a48a33f7e03b69589a5fbb1444cc606d3292 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Nov 2015 14:43:06 +0000 Subject: ASoC: hdac: Fix Makefile and Kconfig sorting Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 12 ++++++------ sound/soc/codecs/Makefile | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5c584dad0af0..8bba374b8860 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -66,8 +66,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C select SND_SOC_GTM601 - select SND_SOC_ICS43432 select SND_SOC_HDAC_HDMI + select SND_SOC_ICS43432 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -455,11 +455,6 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate -config SND_SOC_HDAC_HDMI - tristate - select SND_HDA_EXT_CORE - select HDMI - config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" @@ -474,6 +469,11 @@ config SND_SOC_ES8328_SPI config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' +config SND_SOC_HDAC_HDMI + tristate + select SND_HDA_EXT_CORE + select HDMI + config SND_SOC_ICS43432 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6359bdcf7f89..bcd5ad6b6fb0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -59,8 +59,8 @@ snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o -snd-soc-ics43432-objs := ics43432.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-ics43432-objs := ics43432.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -255,8 +255,8 @@ obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o -obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o -- cgit v1.2.3 From a92ea59b74e231cc0a969afa8d71fa314d5860f2 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Tue, 24 Nov 2015 22:01:21 +0800 Subject: ASoC: Intel: sst: only select sst-firmware when DW DMAC is built-in The previous commit ef3e199a49c8 ("ASoC: Intel: sst: only use sst-firmware when DW DMAC is available") does not fix the 0day building errors thoroughly: sound/built-in.o: In function 'dw_dma_remove' sound/built-in.o: In function 'dw_dma_probe' Here we fallback to select sst-firmware only when DW DMAC is built-in selected. We may need to refactor sst common driver and split DW related codes to platform driver, but ATM, this fallback may be the smallest fix. Please be noticed that after applying this patch, we may need select DW DMAC manually in DMA driver menu, before we can prompt and select HSW/BDW and old BYT machines. Signed-off-by: Jie Yang Cc: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 8 ++++---- sound/soc/intel/common/Makefile | 4 +--- sound/soc/intel/common/sst-dsp.c | 2 +- sound/soc/intel/common/sst-dsp.h | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index aee2a5c75e0d..2d3b12401db1 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -44,7 +44,7 @@ config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 @@ -57,7 +57,7 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 @@ -68,7 +68,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 @@ -80,7 +80,7 @@ config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 658edce16761..3b9332e7a094 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -2,9 +2,7 @@ snd-soc-sst-dsp-objs := sst-dsp.o snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o snd-soc-sst-ipc-objs := sst-ipc.o -ifneq ($(CONFIG_DW_DMAC_CORE),) -snd-soc-sst-dsp-objs += sst-firmware.o -endif +snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index c9452e02e0dd..b5bbdf4fe93a 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -420,7 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) } EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); -#if IS_ENABLED(CONFIG_DW_DMAC_CORE) +#ifdef CONFIG_DW_DMAC_CORE struct sst_dsp *sst_dsp_new(struct device *dev, struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) { diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 859f0de00339..0b84c719ec48 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -216,7 +216,7 @@ struct sst_pdata { void *dsp; }; -#if IS_ENABLED(CONFIG_DW_DMAC_CORE) +#ifdef CONFIG_DW_DMAC_CORE /* Initialization */ struct sst_dsp *sst_dsp_new(struct device *dev, struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); -- cgit v1.2.3 From c1df29648f1e3ffb8bac38e27a22b50f5c019adf Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Tue, 24 Nov 2015 15:31:54 +0800 Subject: ASoC: fsl_sai: add tdm slots operation support Add tdm slots operation support. If tdm slots and slot width have been configured in machine driver, we should use these values. Otherwise, using relevant channels and word length to set slots and slot width. SAI will generate BCLK depends on sample rate, slots and slot width. And there may be unused BCLK cycles before each LRCLK transition. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 31 +++++++++++++++++++++++++------ sound/soc/fsl/fsl_sai.h | 3 +++ 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 520dbadaa8b1..43ba5dc26775 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -126,6 +126,17 @@ out: return IRQ_HANDLED; } +static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + + sai->slots = slots; + sai->slot_width = slot_width; + + return 0; +} + static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { @@ -395,11 +406,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); u32 word_width = snd_pcm_format_width(params_format(params)); u32 val_cr4 = 0, val_cr5 = 0; + u32 slots = (channels == 1) ? 2 : channels; + u32 slot_width = word_width; int ret; + if (sai->slots) + slots = sai->slots; + + if (sai->slot_width) + slot_width = sai->slot_width; + if (!sai->is_slave_mode) { ret = fsl_sai_set_bclk(cpu_dai, tx, - 2 * word_width * params_rate(params)); + slots * slot_width * params_rate(params)); if (ret) return ret; @@ -411,21 +430,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, sai->mclk_streams |= BIT(substream->stream); } - } if (!sai->is_dsp_mode) - val_cr4 |= FSL_SAI_CR4_SYWD(word_width); + val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); - val_cr5 |= FSL_SAI_CR5_WNW(word_width); - val_cr5 |= FSL_SAI_CR5_W0W(word_width); + val_cr5 |= FSL_SAI_CR5_WNW(slot_width); + val_cr5 |= FSL_SAI_CR5_W0W(slot_width); if (sai->is_lsb_first) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); - val_cr4 |= FSL_SAI_CR4_FRSZ(channels); + val_cr4 |= FSL_SAI_CR4_FRSZ(slots); /* * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will @@ -591,6 +609,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index b95fbc3f68eb..d9ed7be8cb34 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -143,6 +143,9 @@ struct fsl_sai { unsigned int mclk_id[2]; unsigned int mclk_streams; + unsigned int slots; + unsigned int slot_width; + struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; -- cgit v1.2.3 From 4ca730436a676afebbe6b77d65b5b4c4d7d38b9c Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Tue, 24 Nov 2015 15:32:09 +0800 Subject: ASoC: fsl: using params_width function to simplify code using params_width function to simplify code. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 2 +- sound/soc/fsl/fsl_esai.c | 2 +- sound/soc/fsl/fsl_sai.c | 2 +- sound/soc/fsl/fsl_ssi.c | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 9f087d4f73ed..6d0636605ed2 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -447,7 +447,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); - int width = snd_pcm_format_width(params_format(params)); + int width = params_width(params); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; unsigned int channels = params_channels(params); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 504e7318f225..45d4319b2079 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -510,7 +510,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 width = snd_pcm_format_width(params_format(params)); + u32 width = params_width(params); u32 channels = params_channels(params); u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 slot_width = width; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index dc0cc65406f5..3da278313591 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -404,7 +404,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); - u32 word_width = snd_pcm_format_width(params_format(params)); + u32 word_width = params_width(params); u32 val_cr4 = 0, val_cr5 = 0; u32 slots = (channels == 1) ? 2 : channels; u32 slot_width = word_width; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 674abf778715..e3abad5f980a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -767,8 +767,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); struct regmap *regs = ssi_private->regs; unsigned int channels = params_channels(hw_params); - unsigned int sample_size = - snd_pcm_format_width(params_format(hw_params)); + unsigned int sample_size = params_width(hw_params); u32 wl = CCSR_SSI_SxCCR_WL(sample_size); int ret; u32 scr_val; -- cgit v1.2.3 From a2a4d6049aa18c0e105d9b53e3236cb50ea5bfa1 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 24 Nov 2015 17:19:32 +0800 Subject: ASoC: fsl_esai: spba clock is needed by esai device ESAI need to enable the spba clock, when sdma is using share peripheral script. In this case, there is two spba master port is used, if don't enable the clock, the spba bus will have arbitration issue, which may cause read/write wrong data from/to ESAI registers. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,esai.txt | 5 +++++ sound/soc/fsl/fsl_esai.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index d3b6b5f48010..cd3ee5d84f03 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -27,6 +27,11 @@ Required properties: derive HCK, SCK and FS. "fsys" The system clock derived from ahb clock used to derive HCK, SCK and FS. + "spba" The spba clock is required when ESAI is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - fsl,fifo-depth : The number of elements in the transmit and receive FIFOs. This number is the maximum allowed value for diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 59f234e51971..6746f76a8c7f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -35,6 +35,7 @@ * @coreclk: clock source to access register * @extalclk: esai clock source to derive HCK, SCK and FS * @fsysclk: system clock source to derive HCK, SCK and FS + * @spbaclk: SPBA clock (optional, depending on SoC design) * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots @@ -54,6 +55,7 @@ struct fsl_esai { struct clk *coreclk; struct clk *extalclk; struct clk *fsysclk; + struct clk *spbaclk; u32 fifo_depth; u32 slot_width; u32 slots; @@ -469,6 +471,11 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, ret = clk_prepare_enable(esai_priv->coreclk); if (ret) return ret; + if (!IS_ERR(esai_priv->spbaclk)) { + ret = clk_prepare_enable(esai_priv->spbaclk); + if (ret) + goto err_spbaclk; + } if (!IS_ERR(esai_priv->extalclk)) { ret = clk_prepare_enable(esai_priv->extalclk); if (ret) @@ -499,6 +506,9 @@ err_fsysclk: if (!IS_ERR(esai_priv->extalclk)) clk_disable_unprepare(esai_priv->extalclk); err_extalck: + if (!IS_ERR(esai_priv->spbaclk)) + clk_disable_unprepare(esai_priv->spbaclk); +err_spbaclk: clk_disable_unprepare(esai_priv->coreclk); return ret; @@ -564,6 +574,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(esai_priv->fsysclk); if (!IS_ERR(esai_priv->extalclk)) clk_disable_unprepare(esai_priv->extalclk); + if (!IS_ERR(esai_priv->spbaclk)) + clk_disable_unprepare(esai_priv->spbaclk); clk_disable_unprepare(esai_priv->coreclk); } @@ -819,6 +831,11 @@ static int fsl_esai_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n", PTR_ERR(esai_priv->fsysclk)); + esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(esai_priv->spbaclk)) + dev_warn(&pdev->dev, "failed to get spba clock: %ld\n", + PTR_ERR(esai_priv->spbaclk)); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); -- cgit v1.2.3 From 0bc5680af8c436d292797d58991b83bca570d079 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 24 Nov 2015 17:19:33 +0800 Subject: ASoC: fsl_spdif: spba clk is needed by spdif device SPDIF need to enable the spba clock, when sdma is using share peripheral script. In this case, there is two spba master port is used, if don't enable the clock, the spba bus will have arbitration issue, which may cause read/write wrong data from/to SPDIF registers. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,spdif.txt | 5 +++++ sound/soc/fsl/fsl_spdif.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt index b5ee32ee3706..4ca39ddc0417 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt @@ -27,6 +27,11 @@ Required properties: Transceiver Clock Diagram" of SoC reference manual. It can also be referred to TxClk_Source bit of register SPDIF_STC. + "spba" The spba clock is required when SPDIF is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - big-endian : If this property is absent, the native endian mode will be in use as default, or the big endian mode diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3d59bb6719f2..fa36e6753799 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -88,6 +88,7 @@ struct spdif_mixer_control { * @rxclk: rx clock sources for capture * @coreclk: core clock for register access via DMA * @sysclk: system clock for rx clock rate measurement + * @spbaclk: SPBA clock (optional, depending on SoC design) * @dma_params_tx: DMA parameters for transmit channel * @dma_params_rx: DMA parameters for receive channel */ @@ -106,6 +107,7 @@ struct fsl_spdif_priv { struct clk *rxclk; struct clk *coreclk; struct clk *sysclk; + struct clk *spbaclk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; /* regcache for SRPC */ @@ -474,6 +476,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, return ret; } + if (!IS_ERR(spdif_priv->spbaclk)) { + ret = clk_prepare_enable(spdif_priv->spbaclk); + if (ret) { + dev_err(&pdev->dev, "failed to enable spba clock\n"); + goto err_spbaclk; + } + } + ret = spdif_softreset(spdif_priv); if (ret) { dev_err(&pdev->dev, "failed to soft reset\n"); @@ -515,6 +525,9 @@ disable_txclk: for (i--; i >= 0; i--) clk_disable_unprepare(spdif_priv->txclk[i]); err: + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); +err_spbaclk: clk_disable_unprepare(spdif_priv->coreclk); return ret; @@ -548,6 +561,8 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, spdif_intr_status_clear(spdif_priv); regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, SCR_LOW_POWER); + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); clk_disable_unprepare(spdif_priv->coreclk); } } @@ -1261,6 +1276,10 @@ static int fsl_spdif_probe(struct platform_device *pdev) return PTR_ERR(spdif_priv->coreclk); } + spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(spdif_priv->spbaclk)) + dev_warn(&pdev->dev, "no spba clock in devicetree\n"); + /* Select clock source for rx/tx clock */ spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); if (IS_ERR(spdif_priv->rxclk)) { -- cgit v1.2.3 From 13b8a97a760eee021558dc48fd65e77e8a362909 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 24 Nov 2015 17:19:34 +0800 Subject: ASoC: fsl_asrc: spba clock is needed by asrc device ASRC need to enable the spba clock, when sdma is using share peripheral script. In this case, there is two spba master port is used, if don't enable the clock, the spba bus will have arbitration issue, which may cause read/write wrong data from/to ASRC registers Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,asrc.txt | 5 +++++ sound/soc/fsl/fsl_asrc.c | 14 ++++++++++++++ sound/soc/fsl/fsl_asrc.h | 2 ++ 3 files changed, 21 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt index b93362a570be..3e26a9478e57 100644 --- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -25,6 +25,11 @@ Required properties: "mem" Peripheral access clock to access registers. "ipg" Peripheral clock to driver module. "asrck_<0-f>" Clock sources for input and output clock. + "spba" The spba clock is required when ASRC is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - big-endian : If this property is absent, the little endian mode will be in use as default. Otherwise, the big endian diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 9f087d4f73ed..cf382475670b 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -859,6 +859,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) return PTR_ERR(asrc_priv->ipg_clk); } + asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(asrc_priv->spba_clk)) + dev_warn(&pdev->dev, "failed to get spba clock\n"); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { sprintf(tmp, "asrck_%x", i); asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); @@ -939,6 +943,11 @@ static int fsl_asrc_runtime_resume(struct device *dev) ret = clk_prepare_enable(asrc_priv->ipg_clk); if (ret) goto disable_mem_clk; + if (!IS_ERR(asrc_priv->spba_clk)) { + ret = clk_prepare_enable(asrc_priv->spba_clk); + if (ret) + goto disable_ipg_clk; + } for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); if (ret) @@ -950,6 +959,9 @@ static int fsl_asrc_runtime_resume(struct device *dev) disable_asrck_clk: for (i--; i >= 0; i--) clk_disable_unprepare(asrc_priv->asrck_clk[i]); + if (!IS_ERR(asrc_priv->spba_clk)) + clk_disable_unprepare(asrc_priv->spba_clk); +disable_ipg_clk: clk_disable_unprepare(asrc_priv->ipg_clk); disable_mem_clk: clk_disable_unprepare(asrc_priv->mem_clk); @@ -963,6 +975,8 @@ static int fsl_asrc_runtime_suspend(struct device *dev) for (i = 0; i < ASRC_CLK_MAX_NUM; i++) clk_disable_unprepare(asrc_priv->asrck_clk[i]); + if (!IS_ERR(asrc_priv->spba_clk)) + clk_disable_unprepare(asrc_priv->spba_clk); clk_disable_unprepare(asrc_priv->ipg_clk); clk_disable_unprepare(asrc_priv->mem_clk); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 4aed63c4b431..68802cdc3f28 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -426,6 +426,7 @@ struct fsl_asrc_pair { * @paddr: physical address to the base address of registers * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral + * @spba_clk: SPBA clock (optional, depending on SoC design) * @asrck_clk: clock sources to driver ASRC internal logic * @lock: spin lock for resource protection * @pair: pair pointers @@ -442,6 +443,7 @@ struct fsl_asrc { unsigned long paddr; struct clk *mem_clk; struct clk *ipg_clk; + struct clk *spba_clk; struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; spinlock_t lock; -- cgit v1.2.3 From 0d3f3c9a48d758454b0f57ca3eccd9ea3f6a4724 Mon Sep 17 00:00:00 2001 From: Moise Gergaud Date: Tue, 24 Nov 2015 14:16:35 +0100 Subject: ASoC: sti: set iec958 channel status sampling freq Previously, the iec958 channels status sampling freq was set only if not already set. It means that it is not updated for next PCM sessions. With this patch, we ensure the iec958 channels status sampling freq is set to the runtime rate for each PCM session. Signed-off-by: Moise Gergaud Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif_player.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 843f037a317d..148bcd7dbf03 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -251,8 +251,7 @@ static void uni_player_set_channel_status(struct uniperif *player, * set one. */ mutex_lock(&player->ctrl_lock); - if (runtime && (player->stream_settings.iec958.status[3] - == IEC958_AES3_CON_FS_NOTID)) { + if (runtime) { switch (runtime->rate) { case 22050: player->stream_settings.iec958.status[3] = -- cgit v1.2.3 From 56b4437f15ed2003413b857e08740576332e72d7 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 23 Nov 2015 21:22:30 +0530 Subject: ASoC: dapm: add a dapm sink widget DAPM models various widgets but lacks a sink widget. DSPs can have modules which take audio data, process it and are capable of generating events thus acting as a sink of data. To make the dapm graph complete for such paths we need a dapm sink widget for these modules, so add a SND_SOC_DAPM_SINK to declare such a widget. This widget will be treated as SND_SOC_DAPM_EP_SINK endpoint in the dapm graph Signed-off-by: Vinod Koul Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 4 ++++ sound/soc/soc-dapm.c | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7855cfe46b69..fe19dd3abb00 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -49,6 +49,9 @@ struct device; #define SND_SOC_DAPM_SIGGEN(wname) \ { .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } +#define SND_SOC_DAPM_SINK(wname) \ +{ .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_INPUT(wname) \ { .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } @@ -484,6 +487,7 @@ enum snd_soc_dapm_type { snd_soc_dapm_aif_in, /* audio interface input */ snd_soc_dapm_aif_out, /* audio interface output */ snd_soc_dapm_siggen, /* signal generator */ + snd_soc_dapm_sink, snd_soc_dapm_dai_in, /* link to DAI structure */ snd_soc_dapm_dai_out, snd_soc_dapm_dai_link, /* link between two DAI structures */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 016eba10b1ec..6760044f6aae 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3351,6 +3351,11 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_always_on_check_power; break; + case snd_soc_dapm_sink: + w->is_ep = SND_SOC_DAPM_EP_SINK; + w->power_check = dapm_always_on_check_power; + break; + case snd_soc_dapm_mux: case snd_soc_dapm_demux: case snd_soc_dapm_switch: -- cgit v1.2.3 From a29d0f3ef934dd9eb2fbb51eb0f112f48046ee91 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Nov 2015 10:35:54 +0100 Subject: ASoC: rcar: remove unused variable After a recent cleanup, the soc_card variable became unused and now produces a warning: soc/sh/rcar/core.c: In function '__rsnd_kctrl_new': soc/sh/rcar/core.c:801:23: warning: unused variable 'soc_card' [-Wunused-variable] This removes the variable. Fixes: 1a497983a5ae ("ASoC: Change the PCM runtime array to a list") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8c4f54b0cb92..e1da5654fa25 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1033,7 +1033,6 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod)) { - struct snd_soc_card *soc_card = rtd->card; struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; struct snd_kcontrol_new knew = { -- cgit v1.2.3 From 7e3a17d311ca89a74cfd39e02e96d29d92849d34 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 23 Nov 2015 22:26:24 +0530 Subject: ASoC: Intel: Skylake: Reconfigure HDA stream register in prepare/resume PCM prepare callbacks can be called multiple times. During S3 the stream registers will be reset when Controller is reset. When stream is resumed, these stream registers needs to reconfigured. This patch removes the check in prepare callback() if stream already prepared, which will allow reconfiguring of stream registers and also decouple stream when stream is resumed to route audio via DSP. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index dae332beea3f..3c891d78ba58 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -181,10 +181,6 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, int err; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - if (hdac_stream(stream)->prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } format_val = skl_get_format(substream, dai); dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", @@ -342,6 +338,8 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct skl *skl = get_skl_ctx(dai->dev); struct skl_sst *ctx = skl->skl_sst; struct skl_module_cfg *mconfig; + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); int ret; mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); @@ -349,15 +347,17 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, return -EIO; switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + skl_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: /* * Start HOST DMA and Start FE Pipe.This is to make sure that * there are no underrun/overrun in the case when the FE * pipeline is started but there is a delay in starting the * DMA channel on the host. */ + snd_hdac_ext_stream_decouple(ebus, stream, true); ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; @@ -377,6 +377,8 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, return ret; ret = skl_decoupled_trigger(substream, cmd); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(ebus, stream, false); break; default: -- cgit v1.2.3 From 98256f83d2895fda3e596824797762937ab79f6b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 23 Nov 2015 22:26:25 +0530 Subject: ASoC: Intel: Skylake: Fix to update bit depth for module params Module hw param fixup will change the valid bit depth based on the fixup flag. If valid bit depth changes, need to set the bit depth according to valid bit depth. This patch fixes this issue of updating bit depth correctly. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 0937ea2129c1..698c4aa03933 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -147,8 +147,24 @@ static void skl_tplg_update_params(struct skl_module_fmt *fmt, fmt->s_freq = params->s_freq; if (fixup & SKL_CH_FIXUP_MASK) fmt->channels = params->ch; - if (fixup & SKL_FMT_FIXUP_MASK) - fmt->valid_bit_depth = params->s_fmt; + if (fixup & SKL_FMT_FIXUP_MASK) { + fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); + + /* + * 16 bit is 16 bit container whereas 24 bit is in 32 bit + * container so update bit depth accordingly + */ + switch (fmt->valid_bit_depth) { + case SKL_DEPTH_16BIT: + fmt->bit_depth = fmt->valid_bit_depth; + break; + + default: + fmt->bit_depth = SKL_DEPTH_32BIT; + break; + } + } + } /* -- cgit v1.2.3 From 06b23d9379d4cd034b7a5edad323ea9419ab2016 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 23 Nov 2015 22:26:26 +0530 Subject: ASoC: Intel: Skylake: Update pcm capability This patch adds pcm capability to support 16/8k rates and 32 bit formats Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 3c891d78ba58..c79bbff00cb7 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -39,9 +39,12 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ SNDRV_PCM_INFO_HAS_LINK_ATIME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_8000, + .rate_min = 8000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, -- cgit v1.2.3 From 2434caf098588856d1c332d2f60b8a2d8a198450 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 23 Nov 2015 22:26:27 +0530 Subject: ASoC: Intel: Skylake: Poll CLDMA RUN bit when set This patch adds polling of CLDMA stream run bit when set to confirm the HW reports the same value. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 947a08e42e86..8c7e8576cba3 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" @@ -33,6 +34,32 @@ void skl_cldma_int_disable(struct sst_dsp *ctx) SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); } +static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable) +{ + unsigned char val; + int timeout; + + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable)); + + udelay(3); + timeout = 300; + do { + /* waiting for hardware to report that the stream Run bit set */ + val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) & + CL_SD_CTL_RUN_MASK; + if (enable && val) + break; + else if (!enable && !val) + break; + udelay(3); + } while (--timeout); + + if (timeout == 0) + dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable); +} + /* Code loader helper APIs */ static void skl_cldma_setup_bdle(struct sst_dsp *ctx, struct snd_dma_buffer *dmab_data, @@ -107,18 +134,6 @@ static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); } -static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) -{ - if (enable) - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); - else - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); -} - static void skl_cldma_cleanup(struct sst_dsp *ctx) { skl_cldma_cleanup_spb(ctx); @@ -167,7 +182,7 @@ cleanup: static void skl_cldma_stop(struct sst_dsp *ctx) { - ctx->cl_dev.ops.cl_trigger(ctx, false); + skl_cldma_stream_run(ctx, false); } static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, @@ -309,7 +324,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx) ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; - ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run; ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; -- cgit v1.2.3 From 65976878ca692566ed066f4fa977de517f697c59 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 23 Nov 2015 22:26:29 +0530 Subject: ASoC: Intel: Skylake: Move up pipe mem free The MCPS is freed first thing in pmd events but non memory. So if we face error during teardown we leak this mem, so move the code up Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 698c4aa03933..f221c758d601 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -652,6 +652,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, int ret = 0; skl_tplg_free_pipe_mcps(skl, mconfig); + skl_tplg_free_pipe_mem(skl, mconfig); list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; @@ -670,7 +671,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, } ret = skl_delete_pipe(ctx, mconfig->pipe); - skl_tplg_free_pipe_mem(skl, mconfig); return ret; } -- cgit v1.2.3 From 923c5e61ecd9b0ca006a7707583287439f36c2e9 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 23 Nov 2015 11:01:49 -0500 Subject: ASoC: Define soc_init_dai_link() to wrap link intialization. Define soc_init_dai_link() to wrap link initialization, to reuse it later by snd_soc_instantiate_card() when adding new DAI links from topology in component probing phase. Move static func snd_soc_init_multicodec(), so that it can be reused by soc_init_dai_link(). This saves adding a function declaration for snd_soc_init_multicodec(). Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 181 ++++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 83 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c95de723d8f..2ecd09475d88 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1134,6 +1134,100 @@ static void soc_remove_dai_links(struct snd_soc_card *card) } } +static int snd_soc_init_multicodec(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + /* Legacy codec/codec_dai link is a single entry in multicodec */ + if (dai_link->codec_name || dai_link->codec_of_node || + dai_link->codec_dai_name) { + dai_link->num_codecs = 1; + + dai_link->codecs = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!dai_link->codecs) + return -ENOMEM; + + dai_link->codecs[0].name = dai_link->codec_name; + dai_link->codecs[0].of_node = dai_link->codec_of_node; + dai_link->codecs[0].dai_name = dai_link->codec_dai_name; + } + + if (!dai_link->codecs) { + dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); + return -EINVAL; + } + + return 0; +} + +static int soc_init_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + int i, ret; + + ret = snd_soc_init_multicodec(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multicodec\n"); + return ret; + } + + for (i = 0; i < link->num_codecs; i++) { + /* + * Codec must be specified by 1 of name or OF node, + * not both or neither. + */ + if (!!link->codecs[i].name == + !!link->codecs[i].of_node) { + dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* Codec DAI name must be specified */ + if (!link->codecs[i].dai_name) { + dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", + link->name); + return -EINVAL; + } + } + + /* + * Platform may be specified by either name or OF node, but + * can be left unspecified, and a dummy platform will be used. + */ + if (link->platform_name && link->platform_of_node) { + dev_err(card->dev, + "ASoC: Both platform name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + /* + * CPU device may be specified by either name or OF node, but + * can be left unspecified, and will be matched based on DAI + * name alone.. + */ + if (link->cpu_name && link->cpu_of_node) { + dev_err(card->dev, + "ASoC: Neither/both cpu name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* + * At least one of CPU DAI name or CPU device name/node must be + * specified + */ + if (!link->cpu_dai_name && + !(link->cpu_name || link->cpu_of_node)) { + dev_err(card->dev, + "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + return 0; +} + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { @@ -2356,33 +2450,6 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -static int snd_soc_init_multicodec(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) -{ - /* Legacy codec/codec_dai link is a single entry in multicodec */ - if (dai_link->codec_name || dai_link->codec_of_node || - dai_link->codec_dai_name) { - dai_link->num_codecs = 1; - - dai_link->codecs = devm_kzalloc(card->dev, - sizeof(struct snd_soc_dai_link_component), - GFP_KERNEL); - if (!dai_link->codecs) - return -ENOMEM; - - dai_link->codecs[0].name = dai_link->codec_name; - dai_link->codecs[0].of_node = dai_link->codec_of_node; - dai_link->codecs[0].dai_name = dai_link->codec_dai_name; - } - - if (!dai_link->codecs) { - dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); - return -EINVAL; - } - - return 0; -} - /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2391,7 +2458,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, j, ret; + int i, ret; struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) @@ -2400,63 +2467,11 @@ int snd_soc_register_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai_link *link = &card->dai_link[i]; - ret = snd_soc_init_multicodec(card, link); + ret = soc_init_dai_link(card, link); if (ret) { - dev_err(card->dev, "ASoC: failed to init multicodec\n"); - return ret; - } - - for (j = 0; j < link->num_codecs; j++) { - /* - * Codec must be specified by 1 of name or OF node, - * not both or neither. - */ - if (!!link->codecs[j].name == - !!link->codecs[j].of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* Codec DAI name must be specified */ - if (!link->codecs[j].dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } - } - - /* - * Platform may be specified by either name or OF node, but - * can be left unspecified, and a dummy platform will be used. - */ - if (link->platform_name && link->platform_of_node) { - dev_err(card->dev, - "ASoC: Both platform name/of_node are set for %s\n", + dev_err(card->dev, "ASoC: failed to init link %s\n", link->name); - return -EINVAL; - } - - /* - * CPU device may be specified by either name or OF node, but - * can be left unspecified, and will be matched based on DAI - * name alone.. - */ - if (link->cpu_name && link->cpu_of_node) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified - */ - if (!link->cpu_dai_name && - !(link->cpu_name || link->cpu_of_node)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; + return ret; } } -- cgit v1.2.3 From 6f2f1ff0de83ad69f5a823ae77d1e0f77cc75d45 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 23 Nov 2015 11:03:52 -0500 Subject: ASoC: Change 2nd argument of soc_bind_dai_link() to DAI link pointer Just code refactoring, to reuse it if new DAI Links are added later based on topology in component probing phase. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ecd09475d88..878a9fe92686 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -960,9 +960,9 @@ static struct snd_soc_dai *snd_soc_find_dai( return NULL; } -static int soc_bind_dai_link(struct snd_soc_card *card, int num) +static int soc_bind_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; @@ -971,7 +971,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) const char *platform_name; int i; - dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); + dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); rtd = soc_new_pcm_runtime(card, dai_link); if (!rtd) @@ -1710,7 +1710,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* bind DAIs */ for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, i); + ret = soc_bind_dai_link(card, &card->dai_link[i]); if (ret != 0) goto base_error; } -- cgit v1.2.3 From 04d1300fd3f5c070a9abe391860d29dfcda89c87 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 26 Nov 2015 14:01:52 +0000 Subject: ASoC: wm_adsp: Expand the list of available firmwares Expand the list of available firmware names to include a good selection of generic uses for the DSP cores. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 49 +++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0bb415a28723..905ae993440b 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -201,27 +201,48 @@ static void wm_adsp_buf_free(struct list_head *list) } } -#define WM_ADSP_NUM_FW 4 - -#define WM_ADSP_FW_MBC_VSS 0 -#define WM_ADSP_FW_TX 1 -#define WM_ADSP_FW_TX_SPK 2 -#define WM_ADSP_FW_RX_ANC 3 +#define WM_ADSP_FW_MBC_VSS 0 +#define WM_ADSP_FW_HIFI 1 +#define WM_ADSP_FW_TX 2 +#define WM_ADSP_FW_TX_SPK 3 +#define WM_ADSP_FW_RX 4 +#define WM_ADSP_FW_RX_ANC 5 +#define WM_ADSP_FW_CTRL 6 +#define WM_ADSP_FW_ASR 7 +#define WM_ADSP_FW_TRACE 8 +#define WM_ADSP_FW_SPK_PROT 9 +#define WM_ADSP_FW_MISC 10 + +#define WM_ADSP_NUM_FW 11 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { - [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", - [WM_ADSP_FW_TX] = "Tx", - [WM_ADSP_FW_TX_SPK] = "Tx Speaker", - [WM_ADSP_FW_RX_ANC] = "Rx ANC", + [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", + [WM_ADSP_FW_HIFI] = "MasterHiFi", + [WM_ADSP_FW_TX] = "Tx", + [WM_ADSP_FW_TX_SPK] = "Tx Speaker", + [WM_ADSP_FW_RX] = "Rx", + [WM_ADSP_FW_RX_ANC] = "Rx ANC", + [WM_ADSP_FW_CTRL] = "Voice Ctrl", + [WM_ADSP_FW_ASR] = "ASR Assist", + [WM_ADSP_FW_TRACE] = "Dbg Trace", + [WM_ADSP_FW_SPK_PROT] = "Protection", + [WM_ADSP_FW_MISC] = "Misc", }; static struct { const char *file; } wm_adsp_fw[WM_ADSP_NUM_FW] = { - [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, - [WM_ADSP_FW_TX] = { .file = "tx" }, - [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, - [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, + [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, + [WM_ADSP_FW_HIFI] = { .file = "hifi" }, + [WM_ADSP_FW_TX] = { .file = "tx" }, + [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, + [WM_ADSP_FW_RX] = { .file = "rx" }, + [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, + [WM_ADSP_FW_CTRL] = { .file = "ctrl" }, + [WM_ADSP_FW_ASR] = { .file = "asr" }, + [WM_ADSP_FW_TRACE] = { .file = "trace" }, + [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, + [WM_ADSP_FW_MISC] = { .file = "misc" }, }; struct wm_coeff_ctl_ops { -- cgit v1.2.3 From 0719ecf7cb86cb7b6012baa0b329063d67dca670 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Nov 2015 08:43:59 +0000 Subject: ASoC: rsnd: indicate register name for debug Current rsnd driver is indicating how to use regmap debug method on gen.c comment area. regmap debug method indicates address and value, but rsnd driver is using too many IPs (SSI/SSIU/SRC/CTU/MIX/DVC/CMD), and address. Thus, we would like to know more useful information for debugging. This patch indicates address name for debugging. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 52 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 84f8bb223439..15d770662482 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -31,29 +31,33 @@ struct rsnd_gen { /* RSND_REG_MAX base */ struct regmap_field *regs[RSND_REG_MAX]; + const char *reg_name[RSND_REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) +#define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) struct rsnd_regmap_field_conf { int idx; unsigned int reg_offset; unsigned int id_offset; + const char *reg_name; }; -#define RSND_REG_SET(id, offset, _id_offset) \ +#define RSND_REG_SET(id, offset, _id_offset, n) \ { \ .idx = id, \ .reg_offset = offset, \ .id_offset = _id_offset, \ + .reg_name = n, \ } /* single address mapping */ #define RSND_GEN_S_REG(id, offset) \ - RSND_REG_SET(RSND_REG_##id, offset, 0) + RSND_REG_SET(RSND_REG_##id, offset, 0, #id) /* multi address mapping */ #define RSND_GEN_M_REG(id, offset, _id_offset) \ - RSND_REG_SET(RSND_REG_##id, offset, _id_offset) + RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id) /* * basic function @@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv, regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); - dev_dbg(dev, "r %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val); + dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, val); return val; } @@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "w %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); - regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); + + dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data); } void rsnd_force_write(struct rsnd_priv *priv, @@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "w %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); - regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); + + dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data); } void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, @@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); - regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), mask, data); + + dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data, mask); + } phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) @@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, int id_size, int reg_id, const char *name, - struct rsnd_regmap_field_conf *conf, + const struct rsnd_regmap_field_conf *conf, int conf_size) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); @@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, /* RSND_REG_MAX base */ gen->regs[conf[i].idx] = regs; + gen->reg_name[conf[i].idx] = conf[i].reg_name; } return 0; @@ -213,7 +223,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, */ static int rsnd_gen2_probe(struct rsnd_priv *priv) { - struct rsnd_regmap_field_conf conf_ssiu[] = { + const static struct rsnd_regmap_field_conf conf_ssiu[] = { RSND_GEN_S_REG(SSI_MODE0, 0x800), RSND_GEN_S_REG(SSI_MODE1, 0x804), /* FIXME: it needs SSI_MODE2/3 in the future */ @@ -223,7 +233,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; - struct rsnd_regmap_field_conf conf_scu[] = { + const static struct rsnd_regmap_field_conf conf_scu[] = { RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), @@ -267,7 +277,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), }; - struct rsnd_regmap_field_conf conf_adg[] = { + const static struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(SSICKR, 0x08), @@ -287,7 +297,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), }; - struct rsnd_regmap_field_conf conf_ssi[] = { + const static struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), RSND_GEN_M_REG(SSISR, 0x04, 0x40), RSND_GEN_M_REG(SSITDR, 0x08, 0x40), @@ -318,14 +328,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) static int rsnd_gen1_probe(struct rsnd_priv *priv) { - struct rsnd_regmap_field_conf conf_adg[] = { + const static struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(SSICKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), }; - struct rsnd_regmap_field_conf conf_ssi[] = { + const static struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), RSND_GEN_M_REG(SSISR, 0x04, 0x40), RSND_GEN_M_REG(SSITDR, 0x08, 0x40), -- cgit v1.2.3 From 8cc225f713a42eab098d51a4353998db979f0f8a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Nov 2015 11:11:03 +0000 Subject: ASoC: rsnd: tidyup semantics of rsnd_src_record_error() rsnd_src_error_record() should recorde error, but it clears error too. this patch fixes up semantic of rsnd_src_error_record that it records error but doesn't clear error. And this patch renames rsnd_src_error_clear() to rsnd_src_status_clear() rsnd_src_error_record() to rsnd_src_record_error() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c103aa775e96..6d93c4ed8275 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -300,7 +300,7 @@ static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); } -static void rsnd_src_error_clear(struct rsnd_mod *mod) +static void rsnd_src_status_clear(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); @@ -308,7 +308,7 @@ static void rsnd_src_error_clear(struct rsnd_mod *mod) rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); } -static bool rsnd_src_error_record(struct rsnd_mod *mod) +static bool rsnd_src_record_error(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val0, val1; @@ -332,9 +332,6 @@ static bool rsnd_src_error_record(struct rsnd_mod *mod) ret = true; } - /* clear error static */ - rsnd_src_error_clear(mod); - return ret; } @@ -383,7 +380,7 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_src_set_convert_rate(io, mod); - rsnd_src_error_clear(mod); + rsnd_src_status_clear(mod); rsnd_src_irq_enable(mod); @@ -434,7 +431,7 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod, if (!rsnd_io_is_working(io)) goto rsnd_src_interrupt_out; - if (rsnd_src_error_record(mod)) { + if (rsnd_src_record_error(mod)) { dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); @@ -450,7 +447,9 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod, rsnd_mod_name(mod), rsnd_mod_id(mod)); } + rsnd_src_status_clear(mod); rsnd_src_interrupt_out: + spin_unlock(&priv->lock); } -- cgit v1.2.3 From 5342dff23263933060d0485cece864f36c0b5d32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 26 Nov 2015 11:13:40 +0000 Subject: ASoC: rsnd: tidyup semantics of rsnd_ssi_record_error() rsnd_ssi_record_error() should recorde error, but it clears error too. this patch fixes up semantic of rsnd_ssi_record_error that it records error but doesn't clear error. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0fe5e3068b6b..40d5b587cbe9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -396,13 +396,9 @@ static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) u32 status = rsnd_ssi_status_get(mod); /* under/over flow error */ - if (status & (UIRQ | OIRQ)) { + if (status & (UIRQ | OIRQ)) ssi->err++; - /* clear error status */ - rsnd_ssi_status_clear(mod); - } - return status; } @@ -537,6 +533,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, rsnd_mod_name(mod), rsnd_mod_id(mod)); } + rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: spin_unlock(&priv->lock); -- cgit v1.2.3 From b17154cfd800b8fdbb34586b9d85e8e824a82833 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 29 Nov 2015 16:36:40 +0100 Subject: ALSA: pcm: constify action_ops structures The action_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a8b27cdc2844..fadd3eb8e8bb 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -875,7 +875,7 @@ struct action_ops { * Note: the stream state might be changed also on failure * Note2: call with calling stream lock + link lock */ -static int snd_pcm_action_group(struct action_ops *ops, +static int snd_pcm_action_group(const struct action_ops *ops, struct snd_pcm_substream *substream, int state, int do_lock) { @@ -932,7 +932,7 @@ static int snd_pcm_action_group(struct action_ops *ops, /* * Note: call with stream lock */ -static int snd_pcm_action_single(struct action_ops *ops, +static int snd_pcm_action_single(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -952,7 +952,7 @@ static int snd_pcm_action_single(struct action_ops *ops, /* * Note: call with stream lock */ -static int snd_pcm_action(struct action_ops *ops, +static int snd_pcm_action(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -984,7 +984,7 @@ static int snd_pcm_action(struct action_ops *ops, /* * Note: don't use any locks before */ -static int snd_pcm_action_lock_irq(struct action_ops *ops, +static int snd_pcm_action_lock_irq(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -998,7 +998,7 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, /* */ -static int snd_pcm_action_nonatomic(struct action_ops *ops, +static int snd_pcm_action_nonatomic(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -1056,7 +1056,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART); } -static struct action_ops snd_pcm_action_start = { +static const struct action_ops snd_pcm_action_start = { .pre_action = snd_pcm_pre_start, .do_action = snd_pcm_do_start, .undo_action = snd_pcm_undo_start, @@ -1107,7 +1107,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) wake_up(&runtime->tsleep); } -static struct action_ops snd_pcm_action_stop = { +static const struct action_ops snd_pcm_action_stop = { .pre_action = snd_pcm_pre_stop, .do_action = snd_pcm_do_stop, .post_action = snd_pcm_post_stop @@ -1224,7 +1224,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) } } -static struct action_ops snd_pcm_action_pause = { +static const struct action_ops snd_pcm_action_pause = { .pre_action = snd_pcm_pre_pause, .do_action = snd_pcm_do_pause, .undo_action = snd_pcm_undo_pause, @@ -1273,7 +1273,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) wake_up(&runtime->tsleep); } -static struct action_ops snd_pcm_action_suspend = { +static const struct action_ops snd_pcm_action_suspend = { .pre_action = snd_pcm_pre_suspend, .do_action = snd_pcm_do_suspend, .post_action = snd_pcm_post_suspend @@ -1375,7 +1375,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME); } -static struct action_ops snd_pcm_action_resume = { +static const struct action_ops snd_pcm_action_resume = { .pre_action = snd_pcm_pre_resume, .do_action = snd_pcm_do_resume, .undo_action = snd_pcm_undo_resume, @@ -1478,7 +1478,7 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state) snd_pcm_playback_silence(substream, ULONG_MAX); } -static struct action_ops snd_pcm_action_reset = { +static const struct action_ops snd_pcm_action_reset = { .pre_action = snd_pcm_pre_reset, .do_action = snd_pcm_do_reset, .post_action = snd_pcm_post_reset @@ -1522,7 +1522,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); } -static struct action_ops snd_pcm_action_prepare = { +static const struct action_ops snd_pcm_action_prepare = { .pre_action = snd_pcm_pre_prepare, .do_action = snd_pcm_do_prepare, .post_action = snd_pcm_post_prepare @@ -1618,7 +1618,7 @@ static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int sta { } -static struct action_ops snd_pcm_action_drain_init = { +static const struct action_ops snd_pcm_action_drain_init = { .pre_action = snd_pcm_pre_drain_init, .do_action = snd_pcm_do_drain_init, .post_action = snd_pcm_post_drain_init -- cgit v1.2.3 From 5df29bca125277eec68fc31c0c0ba41b9a3cb78b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 29 Nov 2015 18:25:24 +0100 Subject: ALSA: i2c: constify snd_i2c_ops structures The snd_i2c_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- include/sound/i2c.h | 2 +- sound/i2c/i2c.c | 2 +- sound/pci/ice1712/delta.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/i2c.h b/include/sound/i2c.h index d125ff8c85e8..835254de2039 100644 --- a/include/sound/i2c.h +++ b/include/sound/i2c.h @@ -66,7 +66,7 @@ struct snd_i2c_bus { struct snd_i2c_bit_ops *bit; void *ops; } hw_ops; /* lowlevel operations */ - struct snd_i2c_ops *ops; /* midlevel operations */ + const struct snd_i2c_ops *ops; /* midlevel operations */ unsigned long private_value; void *private_data; diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index 4677037f0c8e..ef2a9afe9e19 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c @@ -39,7 +39,7 @@ static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr); -static struct snd_i2c_ops snd_i2c_bit_ops = { +static const struct snd_i2c_ops snd_i2c_bit_ops = { .sendbytes = snd_i2c_bit_sendbytes, .readbytes = snd_i2c_bit_readbytes, .probeaddr = snd_i2c_bit_probeaddr, diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 496dbd0ad5db..3bfdc78cbc5f 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -174,7 +174,7 @@ static int ap_cs8427_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) return -ENOENT; } -static struct snd_i2c_ops ap_cs8427_i2c_ops = { +static const struct snd_i2c_ops ap_cs8427_i2c_ops = { .sendbytes = ap_cs8427_sendbytes, .readbytes = ap_cs8427_readbytes, .probeaddr = ap_cs8427_probeaddr, -- cgit v1.2.3 From 3174272474862c545d0cb7bf17b25a0f75800966 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 25 Nov 2015 13:00:23 +0000 Subject: ALSA: compress: Add procfs info file for compressed nodes This patch implements a procfs info file for compr nodes when SND_VERBOSE_PROCFS is enabled. This is equivalent to what the PCM core already does for pcm nodes. Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 5 +++ sound/core/compress_offload.c | 73 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index fa1d05512c09..85c4237bfe06 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -152,6 +152,11 @@ struct snd_compr { unsigned int direction; struct mutex lock; int device; +#ifdef CONFIG_SND_VERBOSE_PROCFS + char id[64]; + struct snd_info_entry *proc_root; + struct snd_info_entry *proc_info_entry; +#endif }; /* compress device register APIs */ diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index b123c42e7dc8..1258e9d81fac 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -891,11 +892,76 @@ static int snd_compress_dev_disconnect(struct snd_device *device) return 0; } +#ifdef CONFIG_SND_VERBOSE_PROCFS +static void snd_compress_proc_info_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_compr *compr = (struct snd_compr *)entry->private_data; + + snd_iprintf(buffer, "card: %d\n", compr->card->number); + snd_iprintf(buffer, "device: %d\n", compr->device); + snd_iprintf(buffer, "stream: %s\n", + compr->direction == SND_COMPRESS_PLAYBACK + ? "PLAYBACK" : "CAPTURE"); + snd_iprintf(buffer, "id: %s\n", compr->id); +} + +static int snd_compress_proc_init(struct snd_compr *compr) +{ + struct snd_info_entry *entry; + char name[16]; + + sprintf(name, "compr%i", compr->device); + entry = snd_info_create_card_entry(compr->card, name, + compr->card->proc_root); + if (!entry) + return -ENOMEM; + entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + return -ENOMEM; + } + compr->proc_root = entry; + + entry = snd_info_create_card_entry(compr->card, "info", + compr->proc_root); + if (entry) { + snd_info_set_text_ops(entry, compr, + snd_compress_proc_info_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + compr->proc_info_entry = entry; + + return 0; +} + +static void snd_compress_proc_done(struct snd_compr *compr) +{ + snd_info_free_entry(compr->proc_info_entry); + compr->proc_info_entry = NULL; + snd_info_free_entry(compr->proc_root); + compr->proc_root = NULL; +} +#else +static inline int snd_compress_proc_init(struct snd_compr *compr) +{ + return 0; +} + +static inline void snd_compress_proc_done(struct snd_compr *compr) +{ +} +#endif + static int snd_compress_dev_free(struct snd_device *device) { struct snd_compr *compr; compr = device->device_data; + snd_compress_proc_done(compr); put_device(&compr->dev); return 0; } @@ -915,6 +981,7 @@ int snd_compress_new(struct snd_card *card, int device, .dev_register = snd_compress_dev_register, .dev_disconnect = snd_compress_dev_disconnect, }; + int ret; compr->card = card; compr->device = device; @@ -923,7 +990,11 @@ int snd_compress_new(struct snd_card *card, int device, snd_device_initialize(&compr->dev, card); dev_set_name(&compr->dev, "comprC%iD%i", card->number, device); - return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); + ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); + if (ret == 0) + snd_compress_proc_init(compr); + + return ret; } EXPORT_SYMBOL_GPL(snd_compress_new); -- cgit v1.2.3 From e5241a8c4b22b678dd9b07527ba9f178f02e160e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 25 Nov 2015 13:00:24 +0000 Subject: ALSA: compress: Pass id string to snd_compress_new Make snd_compress_new take an id string (like snd_pcm_new). This string can be included in the procfs info. This patch also updates soc_new_compress() to create an ID based on the stream and dai name, as done for PCM streams. Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 2 +- sound/core/compress_offload.c | 13 ++++++++++++- sound/soc/soc-compress.c | 8 +++++++- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 85c4237bfe06..c0abcdc11470 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -163,7 +163,7 @@ struct snd_compr { int snd_compress_register(struct snd_compr *device); int snd_compress_deregister(struct snd_compr *device); int snd_compress_new(struct snd_card *card, int device, - int type, struct snd_compr *compr); + int type, const char *id, struct snd_compr *compr); /* dsp driver callback apis * For playback: driver should call snd_compress_fragment_elapsed() to let the diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 1258e9d81fac..2c52510967f0 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -945,6 +945,11 @@ static void snd_compress_proc_done(struct snd_compr *compr) snd_info_free_entry(compr->proc_root); compr->proc_root = NULL; } + +static inline void snd_compress_set_id(struct snd_compr *compr, const char *id) +{ + strlcpy(compr->id, id, sizeof(compr->id)); +} #else static inline int snd_compress_proc_init(struct snd_compr *compr) { @@ -954,6 +959,10 @@ static inline int snd_compress_proc_init(struct snd_compr *compr) static inline void snd_compress_proc_done(struct snd_compr *compr) { } + +static inline void snd_compress_set_id(struct snd_compr *compr, const char *id) +{ +} #endif static int snd_compress_dev_free(struct snd_device *device) @@ -974,7 +983,7 @@ static int snd_compress_dev_free(struct snd_device *device) * @compr: compress device pointer */ int snd_compress_new(struct snd_card *card, int device, - int dirn, struct snd_compr *compr) + int dirn, const char *id, struct snd_compr *compr) { static struct snd_device_ops ops = { .dev_free = snd_compress_dev_free, @@ -987,6 +996,8 @@ int snd_compress_new(struct snd_card *card, int device, compr->device = device; compr->direction = dirn; + snd_compress_set_id(compr, id); + snd_device_initialize(&compr->dev, card); dev_set_name(&compr->dev, "comprC%iD%i", card->number, device); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 12a9820feac1..fffbe6f87273 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -689,7 +689,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) compr->ops->copy = soc_compr_copy; mutex_init(&compr->lock); - ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); + + snprintf(new_name, sizeof(new_name), "%s %s-%d", + rtd->dai_link->stream_name, + rtd->codec_dai->name, num); + + ret = snd_compress_new(rtd->card->snd_card, num, direction, + new_name, compr); if (ret < 0) { pr_err("compress asoc: can't create compress for codec %s\n", codec->component.name); -- cgit v1.2.3 From 4d50934abd2261fd467320d52c470efff309fd74 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 25 Nov 2015 14:24:38 +0000 Subject: ASoC: da7218: Add da7218 codec driver This adds support for DA7217 and DA7218 audio codecs. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- include/sound/da7218.h | 109 ++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/da7218.c | 3305 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/da7218.h | 1414 +++++++++++++++++++ 5 files changed, 4834 insertions(+) create mode 100644 include/sound/da7218.h create mode 100644 sound/soc/codecs/da7218.c create mode 100644 sound/soc/codecs/da7218.h (limited to 'sound') diff --git a/include/sound/da7218.h b/include/sound/da7218.h new file mode 100644 index 000000000000..0dbb818ac116 --- /dev/null +++ b/include/sound/da7218.h @@ -0,0 +1,109 @@ +/* + * da7218.h - DA7218 ASoC Codec Driver Platform Data + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _DA7218_PDATA_H +#define _DA7218_PDATA_H + +/* Mic Bias */ +enum da7218_micbias_voltage { + DA7218_MICBIAS_1_2V = -1, + DA7218_MICBIAS_1_6V, + DA7218_MICBIAS_1_8V, + DA7218_MICBIAS_2_0V, + DA7218_MICBIAS_2_2V, + DA7218_MICBIAS_2_4V, + DA7218_MICBIAS_2_6V, + DA7218_MICBIAS_2_8V, + DA7218_MICBIAS_3_0V, +}; + +enum da7218_mic_amp_in_sel { + DA7218_MIC_AMP_IN_SEL_DIFF = 0, + DA7218_MIC_AMP_IN_SEL_SE_P, + DA7218_MIC_AMP_IN_SEL_SE_N, +}; + +/* DMIC */ +enum da7218_dmic_data_sel { + DA7218_DMIC_DATA_LRISE_RFALL = 0, + DA7218_DMIC_DATA_LFALL_RRISE, +}; + +enum da7218_dmic_samplephase { + DA7218_DMIC_SAMPLE_ON_CLKEDGE = 0, + DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE, +}; + +enum da7218_dmic_clk_rate { + DA7218_DMIC_CLK_3_0MHZ = 0, + DA7218_DMIC_CLK_1_5MHZ, +}; + +/* Headphone Detect */ +enum da7218_hpldet_jack_rate { + DA7218_HPLDET_JACK_RATE_5US = 0, + DA7218_HPLDET_JACK_RATE_10US, + DA7218_HPLDET_JACK_RATE_20US, + DA7218_HPLDET_JACK_RATE_40US, + DA7218_HPLDET_JACK_RATE_80US, + DA7218_HPLDET_JACK_RATE_160US, + DA7218_HPLDET_JACK_RATE_320US, + DA7218_HPLDET_JACK_RATE_640US, +}; + +enum da7218_hpldet_jack_debounce { + DA7218_HPLDET_JACK_DEBOUNCE_OFF = 0, + DA7218_HPLDET_JACK_DEBOUNCE_2, + DA7218_HPLDET_JACK_DEBOUNCE_3, + DA7218_HPLDET_JACK_DEBOUNCE_4, +}; + +enum da7218_hpldet_jack_thr { + DA7218_HPLDET_JACK_THR_84PCT = 0, + DA7218_HPLDET_JACK_THR_88PCT, + DA7218_HPLDET_JACK_THR_92PCT, + DA7218_HPLDET_JACK_THR_96PCT, +}; + +struct da7218_hpldet_pdata { + enum da7218_hpldet_jack_rate jack_rate; + enum da7218_hpldet_jack_debounce jack_debounce; + enum da7218_hpldet_jack_thr jack_thr; + bool comp_inv; + bool hyst; + bool discharge; +}; + +struct da7218_pdata { + /* Mic */ + enum da7218_micbias_voltage micbias1_lvl; + enum da7218_micbias_voltage micbias2_lvl; + enum da7218_mic_amp_in_sel mic1_amp_in_sel; + enum da7218_mic_amp_in_sel mic2_amp_in_sel; + + /* DMIC */ + enum da7218_dmic_data_sel dmic1_data_sel; + enum da7218_dmic_data_sel dmic2_data_sel; + enum da7218_dmic_samplephase dmic1_samplephase; + enum da7218_dmic_samplephase dmic2_samplephase; + enum da7218_dmic_clk_rate dmic1_clk_rate; + enum da7218_dmic_clk_rate dmic2_clk_rate; + + /* HP Diff Supply - DA7217 only */ + bool hp_diff_single_supply; + + /* HP Detect - DA7218 only */ + struct da7218_hpldet_pdata *hpldet_pdata; +}; + +#endif /* _DA7218_PDATA_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..6dd87ee2c463 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -58,6 +58,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI select SND_SOC_DA7213 if I2C + select SND_SOC_DA7218 if I2C select SND_SOC_DA7219 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C @@ -439,6 +440,9 @@ config SND_SOC_DA7210 config SND_SOC_DA7213 tristate +config SND_SOC_DA7218 + tristate + config SND_SOC_DA7219 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..02057d6582c4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -50,6 +50,7 @@ snd-soc-cs4349-objs := cs4349.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o +snd-soc-da7218-objs := da7218.o snd-soc-da7219-objs := da7219.o da7219-aad.o snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o @@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o +obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c new file mode 100644 index 000000000000..ed0c9a26065b --- /dev/null +++ b/sound/soc/codecs/da7218.c @@ -0,0 +1,3305 @@ +/* + * da7218.c - DA7218 ALSA SoC Codec Driver + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "da7218.h" + + +/* + * TLVs and Enums + */ + +/* Input TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0); +static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0); + +/* Input/Output TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0); + +/* Output TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0); +static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0); + +/* Input Enums */ +static const char * const da7218_alc_attack_rate_txt[] = { + "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs", + "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs", + "30024/fs", +}; + +static const struct soc_enum da7218_alc_attack_rate = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT, + DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt); + +static const char * const da7218_alc_release_rate_txt[] = { + "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs", + "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs", +}; + +static const struct soc_enum da7218_alc_release_rate = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT, + DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt); + +static const char * const da7218_alc_hold_time_txt[] = { + "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", + "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", + "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" +}; + +static const struct soc_enum da7218_alc_hold_time = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT, + DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt); + +static const char * const da7218_alc_anticlip_step_txt[] = { + "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs", +}; + +static const struct soc_enum da7218_alc_anticlip_step = + SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL, + DA7218_ALC_ANTICLIP_STEP_SHIFT, + DA7218_ALC_ANTICLIP_STEP_MAX, + da7218_alc_anticlip_step_txt); + +static const char * const da7218_integ_rate_txt[] = { + "1/4", "1/16", "1/256", "1/65536" +}; + +static const struct soc_enum da7218_integ_attack_rate = + SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT, + DA7218_INTEG_MAX, da7218_integ_rate_txt); + +static const struct soc_enum da7218_integ_release_rate = + SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT, + DA7218_INTEG_MAX, da7218_integ_rate_txt); + +/* Input/Output Enums */ +static const char * const da7218_gain_ramp_rate_txt[] = { + "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8", + "Nominal Rate / 16", +}; + +static const struct soc_enum da7218_gain_ramp_rate = + SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT, + DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt); + +static const char * const da7218_hpf_mode_txt[] = { + "Disabled", "Audio", "Voice", +}; + +static const unsigned int da7218_hpf_mode_val[] = { + DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN, +}; + +static const struct soc_enum da7218_in1_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const struct soc_enum da7218_in2_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const struct soc_enum da7218_out1_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const char * const da7218_audio_hpf_corner_txt[] = { + "2Hz", "4Hz", "8Hz", "16Hz", +}; + +static const struct soc_enum da7218_in1_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const struct soc_enum da7218_in2_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const struct soc_enum da7218_out1_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const char * const da7218_voice_hpf_corner_txt[] = { + "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz", +}; + +static const struct soc_enum da7218_in1_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const struct soc_enum da7218_in2_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const struct soc_enum da7218_out1_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const char * const da7218_tonegen_dtmf_key_txt[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", + "*", "#" +}; + +static const struct soc_enum da7218_tonegen_dtmf_key = + SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT, + DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt); + +static const char * const da7218_tonegen_swg_sel_txt[] = { + "Sum", "SWG1", "SWG2", "SWG1_1-Cos" +}; + +static const struct soc_enum da7218_tonegen_swg_sel = + SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT, + DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt); + +/* Output Enums */ +static const char * const da7218_dgs_rise_coeff_txt[] = { + "1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", +}; + +static const struct soc_enum da7218_dgs_rise_coeff = + SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT, + DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt); + +static const char * const da7218_dgs_fall_coeff_txt[] = { + "1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536", +}; + +static const struct soc_enum da7218_dgs_fall_coeff = + SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT, + DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt); + +static const char * const da7218_dac_ng_setup_time_txt[] = { + "256 Samples", "512 Samples", "1024 Samples", "2048 Samples" +}; + +static const struct soc_enum da7218_dac_ng_setup_time = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_SETUP_TIME_SHIFT, + DA7218_DAC_NG_SETUP_TIME_MAX, + da7218_dac_ng_setup_time_txt); + +static const char * const da7218_dac_ng_rampup_txt[] = { + "0.22ms/dB", "0.0138ms/dB" +}; + +static const struct soc_enum da7218_dac_ng_rampup_rate = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_RAMPUP_RATE_SHIFT, + DA7218_DAC_NG_RAMPUP_RATE_MAX, + da7218_dac_ng_rampup_txt); + +static const char * const da7218_dac_ng_rampdown_txt[] = { + "0.88ms/dB", "14.08ms/dB" +}; + +static const struct soc_enum da7218_dac_ng_rampdown_rate = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_RAMPDN_RATE_SHIFT, + DA7218_DAC_NG_RAMPDN_RATE_MAX, + da7218_dac_ng_rampdown_txt); + +static const char * const da7218_cp_mchange_txt[] = { + "Largest Volume", "DAC Volume", "Signal Magnitude" +}; + +static const unsigned int da7218_cp_mchange_val[] = { + DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL, + DA7218_CP_MCHANGE_SIG_MAG +}; + +static const struct soc_enum da7218_cp_mchange = + SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT, + DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX, + da7218_cp_mchange_txt, da7218_cp_mchange_val); + +static const char * const da7218_cp_fcontrol_txt[] = { + "1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz" +}; + +static const struct soc_enum da7218_cp_fcontrol = + SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT, + DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt); + +static const char * const da7218_cp_tau_delay_txt[] = { + "0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms" +}; + +static const struct soc_enum da7218_cp_tau_delay = + SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT, + DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt); + +/* + * Control Functions + */ + +/* ALC */ +static void da7218_alc_calib(struct snd_soc_codec *codec) +{ + u8 mic_1_ctrl, mic_2_ctrl; + u8 mixin_1_ctrl, mixin_2_ctrl; + u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl; + u8 in_1_hpf_ctrl, in_2_hpf_ctrl; + u8 calib_ctrl; + int i = 0; + bool calibrated = false; + + /* Save current state of MIC control registers */ + mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL); + mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL); + + /* Save current state of input mixer control registers */ + mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL); + mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL); + + /* Save current state of input filter control registers */ + in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL); + in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL); + in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL); + in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL); + + /* Save current state of input HPF control registers */ + in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL); + in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL); + + /* Enable then Mute MIC PGAs */ + snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK, + DA7218_MIC_1_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK, + DA7218_MIC_2_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_MUTE_EN_MASK, + DA7218_MIC_1_AMP_MUTE_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_MUTE_EN_MASK, + DA7218_MIC_2_AMP_MUTE_EN_MASK); + + /* Enable input mixers unmuted */ + snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_EN_MASK | + DA7218_MIXIN_1_AMP_MUTE_EN_MASK, + DA7218_MIXIN_1_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_EN_MASK | + DA7218_MIXIN_2_AMP_MUTE_EN_MASK, + DA7218_MIXIN_2_AMP_EN_MASK); + + /* Enable input filters unmuted */ + snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_FILTER_EN_MASK | + DA7218_IN_1L_MUTE_EN_MASK, + DA7218_IN_1L_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_MASK | + DA7218_IN_1R_MUTE_EN_MASK, + DA7218_IN_1R_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_FILTER_EN_MASK | + DA7218_IN_2L_MUTE_EN_MASK, + DA7218_IN_2L_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_FILTER_EN_MASK | + DA7218_IN_2R_MUTE_EN_MASK, + DA7218_IN_2R_FILTER_EN_MASK); + + /* + * Make sure input HPFs voice mode is disabled, otherwise for sampling + * rates above 32KHz the ADC signals will be stopped and will cause + * calibration to lock up. + */ + snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_VOICE_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_VOICE_EN_MASK, 0); + + /* Perform auto calibration */ + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK, + DA7218_CALIB_AUTO_EN_MASK); + do { + calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL); + if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) { + ++i; + usleep_range(DA7218_ALC_CALIB_DELAY_MIN, + DA7218_ALC_CALIB_DELAY_MAX); + } else { + calibrated = true; + } + + } while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated)); + + /* If auto calibration fails, disable DC offset, hybrid ALC */ + if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) { + dev_warn(codec->dev, + "ALC auto calibration failed - %s\n", + (calibrated) ? "overflow" : "timeout"); + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, + DA7218_CALIB_OFFSET_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_ALC_CTRL1, + DA7218_ALC_SYNC_MODE_MASK, 0); + + } else { + /* Enable DC offset cancellation */ + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, + DA7218_CALIB_OFFSET_EN_MASK, + DA7218_CALIB_OFFSET_EN_MASK); + + /* Enable ALC hybrid mode */ + snd_soc_update_bits(codec, DA7218_ALC_CTRL1, + DA7218_ALC_SYNC_MODE_MASK, + DA7218_ALC_SYNC_MODE_CH1 | + DA7218_ALC_SYNC_MODE_CH2); + } + + /* Restore input HPF control registers to original states */ + snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl); + snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl); + + /* Restore input filter control registers to original states */ + snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl); + snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl); + snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl); + snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl); + + /* Restore input mixer control registers to original state */ + snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl); + snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl); + + /* Restore MIC control registers to original states */ + snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl); + snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl); +} + +static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + /* + * If ALC in operation and value of control has been updated, + * make sure calibrated offsets are updated. + */ + if ((ret == 1) && (da7218->alc_en)) + da7218_alc_calib(codec); + + return ret; +} + +static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *) kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + unsigned int lvalue = ucontrol->value.integer.value[0]; + unsigned int rvalue = ucontrol->value.integer.value[1]; + unsigned int lshift = mc->shift; + unsigned int rshift = mc->rshift; + unsigned int mask = (mc->max << lshift) | (mc->max << rshift); + + /* Force ALC offset calibration if enabling ALC */ + if ((lvalue || rvalue) && (!da7218->alc_en)) + da7218_alc_calib(codec); + + /* Update bits to detail which channels are enabled/disabled */ + da7218->alc_en &= ~mask; + da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift); + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + +/* ToneGen */ +static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int reg = mixer_ctrl->reg; + u16 val; + int ret; + + /* + * Frequency value spans two 8-bit registers, lower then upper byte. + * Therefore we need to convert to host endianness here. + */ + ret = regmap_raw_read(da7218->regmap, reg, &val, 2); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = le16_to_cpu(val); + + return 0; +} + +static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int reg = mixer_ctrl->reg; + u16 val; + + /* + * Frequency value spans two 8-bit registers, lower then upper byte. + * Therefore we need to convert to little endian here to align with + * HW registers. + */ + val = cpu_to_le16(ucontrol->value.integer.value[0]); + + return regmap_raw_write(da7218->regmap, reg, &val, 2); +} + +static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int lvalue = ucontrol->value.integer.value[0]; + unsigned int rvalue = ucontrol->value.integer.value[1]; + unsigned int lshift = mixer_ctrl->shift; + unsigned int rshift = mixer_ctrl->rshift; + unsigned int mask = (mixer_ctrl->max << lshift) | + (mixer_ctrl->max << rshift); + da7218->mic_lvl_det_en &= ~mask; + da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift); + + /* + * Here we only enable the feature on paths which are already + * powered. If a channel is enabled here for level detect, but that path + * isn't powered, then the channel will actually be enabled when we do + * power the path (IN_FILTER widget events). This handling avoids + * unwanted level detect events. + */ + return snd_soc_write(codec, mixer_ctrl->reg, + (da7218->in_filt_en & da7218->mic_lvl_det_en)); +} + +static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int lshift = mixer_ctrl->shift; + unsigned int rshift = mixer_ctrl->rshift; + unsigned int lmask = (mixer_ctrl->max << lshift); + unsigned int rmask = (mixer_ctrl->max << rshift); + + ucontrol->value.integer.value[0] = + (da7218->mic_lvl_det_en & lmask) >> lshift; + ucontrol->value.integer.value[1] = + (da7218->mic_lvl_det_en & rmask) >> rshift; + + return 0; +} + +static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + + /* Determine which BiQuads we're setting based on size of config data */ + switch (bytes_ext->max) { + case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE: + memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff, + bytes_ext->max); + break; + case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE: + memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff, + bytes_ext->max); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + u8 reg, out_filt1l; + u8 cfg[DA7218_BIQ_CFG_SIZE]; + int i; + + /* + * Determine which BiQuads we're setting based on size of config data, + * and stored the data for use by get function. + */ + switch (bytes_ext->max) { + case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE: + reg = DA7218_OUT_1_BIQ_5STAGE_DATA; + memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data, + bytes_ext->max); + break; + case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE: + reg = DA7218_SIDETONE_BIQ_3STAGE_DATA; + memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data, + bytes_ext->max); + break; + default: + return -EINVAL; + } + + /* Make sure at least out filter1 enabled to allow programming */ + out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL); + snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, + out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK); + + for (i = 0; i < bytes_ext->max; ++i) { + cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i]; + cfg[DA7218_BIQ_CFG_ADDR] = i; + regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE); + } + + /* Restore filter to previous setting */ + snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l); + + return 0; +} + + +/* + * KControls + */ + +static const struct snd_kcontrol_new da7218_snd_controls[] = { + /* Mics */ + SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN, + DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_mic_gain_tlv), + SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN, + DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_mic_gain_tlv), + SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Mixer Input */ + SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN, + DA7218_MIXIN_1_AMP_GAIN_SHIFT, + DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_mixin_gain_put, + da7218_mixin_gain_tlv), + SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN, + DA7218_MIXIN_2_AMP_GAIN_SHIFT, + DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_mixin_gain_put, + da7218_mixin_gain_tlv), + SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* ADCs */ + SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL, + DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL, + DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE, + DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* Input Filters */ + SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN, + DA7218_IN_1L_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN, + DA7218_IN_1R_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter1R Gain Ramp Switch", + DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN, + DA7218_IN_2L_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN, + DA7218_IN_2R_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter2R Gain Ramp Switch", + DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* AGS */ + SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER, + DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX, + DA7218_INVERT, da7218_ags_trigger_tlv), + SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX, + DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX, + DA7218_NO_INVERT, da7218_ags_att_max_tlv), + SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL, + DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE, + DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE, + DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* ALC */ + SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate), + SOC_ENUM("ALC Release Rate", da7218_alc_release_rate), + SOC_ENUM("ALC Hold Time", da7218_alc_hold_time), + SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE, + DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN, + DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX, + DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS, + DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_gain_tlv), + SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS, + DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS, + DA7218_ALC_ANA_GAIN_MIN_SHIFT, + DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_ana_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS, + DA7218_ALC_ANA_GAIN_MAX_SHIFT, + DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_ana_gain_tlv), + SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step), + SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL, + DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1, + DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_alc_sw_put), + SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1, + DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_alc_sw_put), + + /* Envelope Tracking */ + SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate), + SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate), + + /* Input High-Pass Filters */ + SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode), + SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner), + SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner), + SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode), + SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner), + SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner), + + /* Mic Level Detect */ + SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL, + DA7218_LVL_DET_EN_CHAN1L_SHIFT, + DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get, + da7218_mic_lvl_det_sw_put), + SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL, + DA7218_LVL_DET_EN_CHAN2L_SHIFT, + DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get, + da7218_mic_lvl_det_sw_put), + SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL, + DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX, + DA7218_NO_INVERT), + + /* Digital Mixer (Input) */ + SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, + DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, + DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, + DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, + DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, + DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, + DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, + DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, + DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, + DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, + DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, + DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, + DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, + DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, + DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, + DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, + DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, + DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, + DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, + DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, + DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, + DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, + DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, + DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, + DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, + DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, + DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, + DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, + DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + /* Digital Mixer (Output) */ + SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, + DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, + DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, + DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, + DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, + DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, + DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, + DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, + DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, + DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, + DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, + DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, + DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, + DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, + DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + /* Sidetone Filter */ + SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients", + DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE, + da7218_biquad_coeff_get, da7218_biquad_coeff_put), + SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN, + DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX, + DA7218_NO_INVERT, da7218_dmix_gain_tlv), + SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL, + DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Tone Generator */ + SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key), + SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1, + DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel), + SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L, + DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT, + da7218_tonegen_freq_get, da7218_tonegen_freq_put), + SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L, + DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT, + da7218_tonegen_freq_get, da7218_tonegen_freq_put), + SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER, + DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER, + DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX, + DA7218_NO_INVERT), + + /* Gain ramping */ + SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate), + + /* DGS */ + SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER, + DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX, + DA7218_INVERT, da7218_dgs_trigger_tlv), + SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff), + SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff), + SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY, + DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2, + DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3, + DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS, + DA7218_DGS_ANTICLIP_LVL_SHIFT, + DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT, + da7218_dgs_anticlip_tlv), + SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS, + DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX, + DA7218_INVERT, da7218_dgs_signal_tlv), + SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT, + DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* Output High-Pass Filter */ + SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode), + SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner), + SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner), + + /* 5-Band Equaliser */ + SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL, + DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* BiQuad Filters */ + SND_SOC_BYTES_EXT("BiQuad Coefficients", + DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE, + da7218_biquad_coeff_get, da7218_biquad_coeff_put), + SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL, + DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Output Filters */ + SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN, + DA7218_OUT_1R_GAIN, + DA7218_OUT_1L_DIGITAL_GAIN_SHIFT, + DA7218_OUT_DIGITAL_GAIN_MIN, + DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_out_dig_gain_tlv), + SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_INVERT), + SOC_DOUBLE_R("Out Filter Gain Subrange Switch", + DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* Mixer Output */ + SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN, + DA7218_MIXOUT_R_GAIN, + DA7218_MIXOUT_L_AMP_GAIN_SHIFT, + DA7218_MIXOUT_AMP_GAIN_MIN, + DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT, + da7218_mixout_gain_tlv), + + /* DAC Noise Gate */ + SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time), + SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate), + SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate), + SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH, + DA7218_DAC_NG_OFF_THRESHOLD_SHIFT, + DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT, + da7218_dac_ng_threshold_tlv), + SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH, + DA7218_DAC_NG_ON_THRESHOLD_SHIFT, + DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT, + da7218_dac_ng_threshold_tlv), + SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* CP */ + SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange), + SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol), + SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay), + SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1, + DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX, + DA7218_NO_INVERT), + + /* Headphones */ + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN, + DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT, + DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_hp_gain_tlv), + SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL, + DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL, + DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL, + DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), +}; + + +/* + * DAPM Mux Controls + */ + +static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" }; + +static const struct soc_enum da7218_mic1_sel = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text), + da7218_mic_sel_text); + +static const struct snd_kcontrol_new da7218_mic1_sel_mux = + SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel); + +static const struct soc_enum da7218_mic2_sel = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text), + da7218_mic_sel_text); + +static const struct snd_kcontrol_new da7218_mic2_sel_mux = + SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel); + +static const char * const da7218_sidetone_in_sel_txt[] = { + "In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R" +}; + +static const struct soc_enum da7218_sidetone_in_sel = + SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT, + DA7218_SIDETONE_IN_SELECT_SHIFT, + DA7218_SIDETONE_IN_SELECT_MAX, + da7218_sidetone_in_sel_txt); + +static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux = + SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel); + +static const char * const da7218_out_filt_biq_sel_txt[] = { + "Bypass", "Enabled" +}; + +static const struct soc_enum da7218_out_filtl_biq_sel = + SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT, + DA7218_OUT_BIQ_5STAGE_SEL_MAX, + da7218_out_filt_biq_sel_txt); + +static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux = + SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel); + +static const struct soc_enum da7218_out_filtr_biq_sel = + SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT, + DA7218_OUT_BIQ_5STAGE_SEL_MAX, + da7218_out_filt_biq_sel_txt); + +static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux = + SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel); + + +/* + * DAPM Mixer Controls + */ + +#define DA7218_DMIX_CTRLS(reg) \ + SOC_DAPM_SINGLE("In Filter1L Switch", reg, \ + DA7218_DMIX_SRC_INFILT1L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter1R Switch", reg, \ + DA7218_DMIX_SRC_INFILT1R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter2L Switch", reg, \ + DA7218_DMIX_SRC_INFILT2L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter2R Switch", reg, \ + DA7218_DMIX_SRC_INFILT2R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("ToneGen Switch", reg, \ + DA7218_DMIX_SRC_TONEGEN, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT) + +static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L), +}; + +static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R), +}; + +static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L), +}; + +static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R), +}; + +static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L), +}; + +static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R), +}; + +#define DA7218_DMIX_ST_CTRLS(reg) \ + SOC_DAPM_SINGLE("Out FilterL Switch", reg, \ + DA7218_DMIX_ST_SRC_OUTFILT1L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("Out FilterR Switch", reg, \ + DA7218_DMIX_ST_SRC_OUTFILT1R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("Sidetone Switch", reg, \ + DA7218_DMIX_ST_SRC_SIDETONE, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT) \ + +static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = { + DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L), +}; + +static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = { + DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R), +}; + + +/* + * DAPM Events + */ + +/* + * We keep track of which input filters are enabled. This is used in the logic + * for controlling the mic level detect feature. + */ +static int da7218_in_filter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 mask; + + switch (w->reg) { + case DA7218_IN_1L_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT); + break; + case DA7218_IN_1R_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT); + break; + case DA7218_IN_2L_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT); + break; + case DA7218_IN_2R_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT); + break; + default: + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + da7218->in_filt_en |= mask; + /* + * If we're enabling path for mic level detect, wait for path + * to settle before enabling feature to avoid incorrect and + * unwanted detect events. + */ + if (mask & da7218->mic_lvl_det_en) + msleep(DA7218_MIC_LVL_DET_DELAY); + break; + case SND_SOC_DAPM_PRE_PMD: + da7218->in_filt_en &= ~mask; + break; + default: + return -EINVAL; + } + + /* Enable configured level detection paths */ + snd_soc_write(codec, DA7218_LVL_DET_CTRL, + (da7218->in_filt_en & da7218->mic_lvl_det_en)); + + return 0; +} + +static int da7218_dai_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 pll_ctrl, pll_status, refosc_cal; + int i; + bool success; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (da7218->master) + /* Enable DAI clks for master mode */ + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_CLK_EN_MASK, + DA7218_DAI_CLK_EN_MASK); + + /* Tune reference oscillator */ + snd_soc_write(codec, DA7218_PLL_REFOSC_CAL, + DA7218_PLL_REFOSC_CAL_START_MASK); + snd_soc_write(codec, DA7218_PLL_REFOSC_CAL, + DA7218_PLL_REFOSC_CAL_START_MASK | + DA7218_PLL_REFOSC_CAL_EN_MASK); + + /* Check tuning complete */ + i = 0; + success = false; + do { + refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL); + if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) { + success = true; + } else { + ++i; + usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN, + DA7218_REF_OSC_CHECK_DELAY_MAX); + } + } while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success)); + + if (!success) + dev_warn(codec->dev, + "Reference oscillator failed calibration\n"); + + /* PC synchronised to DAI */ + snd_soc_write(codec, DA7218_PC_COUNT, + DA7218_PC_RESYNC_AUTO_MASK); + + /* If SRM not enabled, we don't need to check status */ + pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL); + if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM) + return 0; + + /* Check SRM has locked */ + i = 0; + success = false; + do { + pll_status = snd_soc_read(codec, DA7218_PLL_STATUS); + if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) { + success = true; + } else { + ++i; + msleep(DA7218_SRM_CHECK_DELAY); + } + } while ((i < DA7218_SRM_CHECK_TRIES) & (!success)); + + if (!success) + dev_warn(codec->dev, "SRM failed to lock\n"); + + return 0; + case SND_SOC_DAPM_POST_PMD: + /* PC free-running */ + snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK); + + if (da7218->master) + /* Disable DAI clks for master mode */ + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_CLK_EN_MASK, 0); + + return 0; + default: + return -EINVAL; + } +} + +static int da7218_cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + /* + * If this is DA7217 and we're using single supply for differential + * output, we really don't want to touch the charge pump. + */ + if (da7218->hp_single_supply) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK, + DA7218_CP_EN_MASK); + return 0; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK, + 0); + return 0; + default: + return -EINVAL; + } +} + +static int da7218_hp_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Enable headphone output */ + snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, + DA7218_HP_AMP_OE_MASK); + return 0; + case SND_SOC_DAPM_PRE_PMD: + /* Headphone output high impedance */ + snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0); + return 0; + default: + return -EINVAL; + } +} + + +/* + * DAPM Widgets + */ + +static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = { + /* Input Supplies */ + SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN, + DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN, + DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL, + DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL, + DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL, + DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL, + DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("DMIC1L"), + SND_SOC_DAPM_INPUT("DMIC1R"), + SND_SOC_DAPM_INPUT("DMIC2L"), + SND_SOC_DAPM_INPUT("DMIC2R"), + + /* Input Mixer Supplies */ + SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Input PGAs */ + SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Mic/DMic Muxes */ + SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux), + SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux), + + /* Input Filters */ + SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Tone Generator */ + SND_SOC_DAPM_SIGGEN("TONE"), + SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1, + DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0), + + /* Sidetone Input */ + SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, + &da7218_sidetone_in_sel_mux), + SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL, + DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT), + + /* Input Mixers */ + SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0, + da7218_out_dai1l_mix_controls, + ARRAY_SIZE(da7218_out_dai1l_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0, + da7218_out_dai1r_mix_controls, + ARRAY_SIZE(da7218_out_dai1r_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0, + da7218_out_dai2l_mix_controls, + ARRAY_SIZE(da7218_out_dai2l_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0, + da7218_out_dai2r_mix_controls, + ARRAY_SIZE(da7218_out_dai2r_mix_controls)), + + /* DAI Supply */ + SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT, + DA7218_NO_INVERT, da7218_dai_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* DAI */ + SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0, + da7218_out_filtl_mix_controls, + ARRAY_SIZE(da7218_out_filtl_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0, + da7218_out_filtr_mix_controls, + ARRAY_SIZE(da7218_out_filtr_mix_controls)), + + /* BiQuad Filters */ + SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0, + &da7218_out_filtl_biq_sel_mux), + SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0, + &da7218_out_filtr_biq_sel_mux), + SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL, + DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT, + DA7218_NO_INVERT), + + /* Sidetone Mixers */ + SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0, + da7218_st_out_filtl_mix_controls, + ARRAY_SIZE(da7218_st_out_filtl_mix_controls)), + SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0, + da7218_st_out_filtr_mix_controls, + ARRAY_SIZE(da7218_st_out_filtr_mix_controls)), + + /* Output Filters */ + SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT), + SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT), + + /* Output PGAs */ + SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL, + DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL, + DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL, + DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0, + da7218_hp_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL, + DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0, + da7218_hp_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Output Supplies */ + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + + +/* + * DAPM Mixer Routes + */ + +#define DA7218_DMIX_ROUTES(name) \ + {name, "In Filter1L Switch", "In Filter1L"}, \ + {name, "In Filter1R Switch", "In Filter1R"}, \ + {name, "In Filter2L Switch", "In Filter2L"}, \ + {name, "In Filter2R Switch", "In Filter2R"}, \ + {name, "ToneGen Switch", "Tone Generator"}, \ + {name, "DAIL Switch", "DAIIN"}, \ + {name, "DAIR Switch", "DAIIN"} + +#define DA7218_DMIX_ST_ROUTES(name) \ + {name, "Out FilterL Switch", "Out FilterL BiQuad Mux"}, \ + {name, "Out FilterR Switch", "Out FilterR BiQuad Mux"}, \ + {name, "Sidetone Switch", "Sidetone Filter"} + + +/* + * DAPM audio route definition + */ + +static const struct snd_soc_dapm_route da7218_audio_map[] = { + /* Input paths */ + {"MIC1", NULL, "Mic Bias1"}, + {"MIC2", NULL, "Mic Bias2"}, + {"DMIC1L", NULL, "Mic Bias1"}, + {"DMIC1L", NULL, "DMic1 Left"}, + {"DMIC1R", NULL, "Mic Bias1"}, + {"DMIC1R", NULL, "DMic1 Right"}, + {"DMIC2L", NULL, "Mic Bias2"}, + {"DMIC2L", NULL, "DMic2 Left"}, + {"DMIC2R", NULL, "Mic Bias2"}, + {"DMIC2R", NULL, "DMic2 Right"}, + + {"Mic1 PGA", NULL, "MIC1"}, + {"Mic2 PGA", NULL, "MIC2"}, + + {"Mixin1 PGA", NULL, "Mixin1 Supply"}, + {"Mixin2 PGA", NULL, "Mixin2 Supply"}, + + {"Mixin1 PGA", NULL, "Mic1 PGA"}, + {"Mixin2 PGA", NULL, "Mic2 PGA"}, + + {"Mic1 Mux", "Analog", "Mixin1 PGA"}, + {"Mic1 Mux", "Digital", "DMIC1L"}, + {"Mic1 Mux", "Digital", "DMIC1R"}, + {"Mic2 Mux", "Analog", "Mixin2 PGA"}, + {"Mic2 Mux", "Digital", "DMIC2L"}, + {"Mic2 Mux", "Digital", "DMIC2R"}, + + {"In Filter1L", NULL, "Mic1 Mux"}, + {"In Filter1R", NULL, "Mic1 Mux"}, + {"In Filter2L", NULL, "Mic2 Mux"}, + {"In Filter2R", NULL, "Mic2 Mux"}, + + {"Tone Generator", NULL, "TONE"}, + + {"Sidetone Mux", "In Filter1L", "In Filter1L"}, + {"Sidetone Mux", "In Filter1R", "In Filter1R"}, + {"Sidetone Mux", "In Filter2L", "In Filter2L"}, + {"Sidetone Mux", "In Filter2R", "In Filter2R"}, + {"Sidetone Filter", NULL, "Sidetone Mux"}, + + DA7218_DMIX_ROUTES("Mixer DAI1L"), + DA7218_DMIX_ROUTES("Mixer DAI1R"), + DA7218_DMIX_ROUTES("Mixer DAI2L"), + DA7218_DMIX_ROUTES("Mixer DAI2R"), + + {"DAIOUT", NULL, "Mixer DAI1L"}, + {"DAIOUT", NULL, "Mixer DAI1R"}, + {"DAIOUT", NULL, "Mixer DAI2L"}, + {"DAIOUT", NULL, "Mixer DAI2R"}, + + {"DAIOUT", NULL, "DAI"}, + + /* Output paths */ + {"DAIIN", NULL, "DAI"}, + + DA7218_DMIX_ROUTES("Mixer Out FilterL"), + DA7218_DMIX_ROUTES("Mixer Out FilterR"), + + {"BiQuad Filter", NULL, "Mixer Out FilterL"}, + {"BiQuad Filter", NULL, "Mixer Out FilterR"}, + + {"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"}, + {"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"}, + {"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"}, + {"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"}, + + DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"), + DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"), + + {"Out FilterL", NULL, "ST Mixer Out FilterL"}, + {"Out FilterR", NULL, "ST Mixer Out FilterR"}, + + {"Mixout Left PGA", NULL, "Out FilterL"}, + {"Mixout Right PGA", NULL, "Out FilterR"}, + + {"Headphone Left PGA", NULL, "Mixout Left PGA"}, + {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + + {"HPL", NULL, "Headphone Left PGA"}, + {"HPR", NULL, "Headphone Right PGA"}, + + {"HPL", NULL, "Charge Pump"}, + {"HPR", NULL, "Charge Pump"}, +}; + + +/* + * DAI operations + */ + +static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + if (da7218->mclk_rate == freq) + return 0; + + if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { + dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + freq); + return -EINVAL; + } + + switch (clk_id) { + case DA7218_CLKSRC_MCLK_SQR: + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MCLK_SQR_EN_MASK, + DA7218_PLL_MCLK_SQR_EN_MASK); + break; + case DA7218_CLKSRC_MCLK: + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MCLK_SQR_EN_MASK, 0); + break; + default: + dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + return -EINVAL; + } + + if (da7218->mclk) { + freq = clk_round_rate(da7218->mclk, freq); + ret = clk_set_rate(da7218->mclk, freq); + if (ret) { + dev_err(codec_dai->dev, "Failed to set clock rate %d\n", + freq); + return ret; + } + } + + da7218->mclk_rate = freq; + + return 0; +} + +static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + u8 pll_ctrl, indiv_bits, indiv; + u8 pll_frac_top, pll_frac_bot, pll_integer; + u32 freq_ref; + u64 frac_div; + + /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7218->mclk_rate == 32768) { + indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate < 2000000) { + dev_err(codec->dev, "PLL input clock %d below valid range\n", + da7218->mclk_rate); + return -EINVAL; + } else if (da7218->mclk_rate <= 5000000) { + indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate <= 10000000) { + indiv_bits = DA7218_PLL_INDIV_5_10_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate <= 20000000) { + indiv_bits = DA7218_PLL_INDIV_10_20_MHZ; + indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL; + } else if (da7218->mclk_rate <= 40000000) { + indiv_bits = DA7218_PLL_INDIV_20_40_MHZ; + indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL; + } else if (da7218->mclk_rate <= 54000000) { + indiv_bits = DA7218_PLL_INDIV_40_54_MHZ; + indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL; + } else { + dev_err(codec->dev, "PLL input clock %d above valid range\n", + da7218->mclk_rate); + return -EINVAL; + } + freq_ref = (da7218->mclk_rate / indiv); + pll_ctrl = indiv_bits; + + /* Configure PLL */ + switch (source) { + case DA7218_SYSCLK_MCLK: + pll_ctrl |= DA7218_PLL_MODE_BYPASS; + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_INDIV_MASK | + DA7218_PLL_MODE_MASK, pll_ctrl); + return 0; + case DA7218_SYSCLK_PLL: + pll_ctrl |= DA7218_PLL_MODE_NORMAL; + break; + case DA7218_SYSCLK_PLL_SRM: + pll_ctrl |= DA7218_PLL_MODE_SRM; + break; + case DA7218_SYSCLK_PLL_32KHZ: + pll_ctrl |= DA7218_PLL_MODE_32KHZ; + break; + default: + dev_err(codec->dev, "Invalid PLL config\n"); + return -EINVAL; + } + + /* Calculate dividers for PLL */ + pll_integer = fout / freq_ref; + frac_div = (u64)(fout % freq_ref) * 8192ULL; + do_div(frac_div, freq_ref); + pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK; + pll_frac_bot = (frac_div) & DA7218_BYTE_MASK; + + /* Write PLL config & dividers */ + snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top); + snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot); + snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer); + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK, + pll_ctrl); + + return 0; +} + +static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 dai_clk_mode = 0, dai_ctrl = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + da7218->master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + da7218->master = false; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | DA7218_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_ctrl |= DA7218_DAI_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J; + break; + case SND_SOC_DAIFMT_DSP_B: + dai_ctrl |= DA7218_DAI_FORMAT_DSP; + break; + default: + return -EINVAL; + } + + /* By default 64 BCLKs per WCLK is supported */ + dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64; + + snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode); + snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK, + dai_ctrl); + + return 0; +} + +static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + u8 dai_bclks_per_wclk; + u32 frame_size; + + /* No channels enabled so disable TDM, revert to 64-bit frames */ + if (!tx_mask) { + snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL, + DA7218_DAI_TDM_CH_EN_MASK | + DA7218_DAI_TDM_MODE_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_BCLKS_PER_WCLK_MASK, + DA7218_DAI_BCLKS_PER_WCLK_64); + return 0; + } + + /* Check we have valid slots */ + if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) { + dev_err(codec->dev, "Invalid number of slots, max = %d\n", + DA7218_DAI_TDM_MAX_SLOTS); + return -EINVAL; + } + + /* Check we have a valid offset given (first 2 bytes of rx_mask) */ + if (rx_mask >> DA7218_2BYTE_SHIFT) { + dev_err(codec->dev, "Invalid slot offset, max = %d\n", + DA7218_2BYTE_MASK); + return -EINVAL; + } + + /* Calculate & validate frame size based on slot info provided. */ + frame_size = slots * slot_width; + switch (frame_size) { + case 32: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256; + break; + default: + dev_err(codec->dev, "Invalid frame size\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER, + (rx_mask & DA7218_BYTE_MASK)); + snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER, + ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK)); + snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL, + DA7218_DAI_TDM_CH_EN_MASK | + DA7218_DAI_TDM_MODE_EN_MASK, + (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) | + DA7218_DAI_TDM_MODE_EN_MASK); + + return 0; +} + +static int da7218_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u8 dai_ctrl = 0, fs; + unsigned int channels; + + switch (params_width(params)) { + case 16: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE; + break; + case 20: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE; + break; + case 24: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE; + break; + case 32: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE; + break; + default: + return -EINVAL; + } + + channels = params_channels(params); + if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) { + dev_err(codec->dev, + "Invalid number of channels, only 1 to %d supported\n", + DA7218_DAI_CH_NUM_MAX); + return -EINVAL; + } + dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT; + + switch (params_rate(params)) { + case 8000: + fs = DA7218_SR_8000; + break; + case 11025: + fs = DA7218_SR_11025; + break; + case 12000: + fs = DA7218_SR_12000; + break; + case 16000: + fs = DA7218_SR_16000; + break; + case 22050: + fs = DA7218_SR_22050; + break; + case 24000: + fs = DA7218_SR_24000; + break; + case 32000: + fs = DA7218_SR_32000; + break; + case 44100: + fs = DA7218_SR_44100; + break; + case 48000: + fs = DA7218_SR_48000; + break; + case 88200: + fs = DA7218_SR_88200; + break; + case 96000: + fs = DA7218_SR_96000; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7218_DAI_CTRL, + DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK, + dai_ctrl); + /* SRs tied for ADCs and DACs. */ + snd_soc_write(codec, DA7218_SR, + (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT)); + + return 0; +} + +static const struct snd_soc_dai_ops da7218_dai_ops = { + .hw_params = da7218_hw_params, + .set_sysclk = da7218_set_dai_sysclk, + .set_pll = da7218_set_dai_pll, + .set_fmt = da7218_set_dai_fmt, + .set_tdm_slot = da7218_set_dai_tdm_slot, +}; + +#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver da7218_dai = { + .name = "da7218-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 4, /* Only 2 channels of data */ + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7218_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7218_FORMATS, + }, + .ops = &da7218_dai_ops, + .symmetric_rates = 1, + .symmetric_channels = 1, + .symmetric_samplebits = 1, +}; + + +/* + * HP Detect + */ + +int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + if (da7218->dev_id == DA7217_DEV_ID) + return -EINVAL; + + da7218->jack = jack; + snd_soc_update_bits(codec, DA7218_HPLDET_JACK, + DA7218_HPLDET_JACK_EN_MASK, + jack ? DA7218_HPLDET_JACK_EN_MASK : 0); + + return 0; +} +EXPORT_SYMBOL_GPL(da7218_hpldet); + +static void da7218_hpldet_irq(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 jack_status; + int report; + + jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS); + + if (jack_status & DA7218_HPLDET_JACK_STS_MASK) + report = SND_JACK_HEADPHONE; + else + report = 0; + + snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE); +} + +/* + * IRQ + */ + +static irqreturn_t da7218_irq_thread(int irq, void *data) +{ + struct snd_soc_codec *codec = data; + u8 status; + + /* Read IRQ status reg */ + status = snd_soc_read(codec, DA7218_EVENT); + if (!status) + return IRQ_NONE; + + /* HP detect */ + if (status & DA7218_HPLDET_JACK_EVENT_MASK) + da7218_hpldet_irq(codec); + + /* Clear interrupts */ + snd_soc_write(codec, DA7218_EVENT, status); + + return IRQ_HANDLED; +} + +/* + * DT + */ + +static const struct of_device_id da7218_of_match[] = { + { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID }, + { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID }, + { } +}; +MODULE_DEVICE_TABLE(of, da7218_of_match); + +static inline int da7218_of_get_id(struct device *dev) +{ + const struct of_device_id *id = of_match_device(da7218_of_match, dev); + + if (id) + return (int) id->data; + else + return -EINVAL; +} + +static enum da7218_micbias_voltage + da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 1200: + return DA7218_MICBIAS_1_2V; + case 1600: + return DA7218_MICBIAS_1_6V; + case 1800: + return DA7218_MICBIAS_1_8V; + case 2000: + return DA7218_MICBIAS_2_0V; + case 2200: + return DA7218_MICBIAS_2_2V; + case 2400: + return DA7218_MICBIAS_2_4V; + case 2600: + return DA7218_MICBIAS_2_6V; + case 2800: + return DA7218_MICBIAS_2_8V; + case 3000: + return DA7218_MICBIAS_3_0V; + default: + dev_warn(codec->dev, "Invalid micbias level"); + return DA7218_MICBIAS_1_6V; + } +} + +static enum da7218_mic_amp_in_sel + da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "diff")) { + return DA7218_MIC_AMP_IN_SEL_DIFF; + } else if (!strcmp(str, "se_p")) { + return DA7218_MIC_AMP_IN_SEL_SE_P; + } else if (!strcmp(str, "se_n")) { + return DA7218_MIC_AMP_IN_SEL_SE_N; + } else { + dev_warn(codec->dev, "Invalid mic input type selection"); + return DA7218_MIC_AMP_IN_SEL_DIFF; + } +} + +static enum da7218_dmic_data_sel + da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "lrise_rfall")) { + return DA7218_DMIC_DATA_LRISE_RFALL; + } else if (!strcmp(str, "lfall_rrise")) { + return DA7218_DMIC_DATA_LFALL_RRISE; + } else { + dev_warn(codec->dev, "Invalid DMIC data type selection"); + return DA7218_DMIC_DATA_LRISE_RFALL; + } +} + +static enum da7218_dmic_samplephase + da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "on_clkedge")) { + return DA7218_DMIC_SAMPLE_ON_CLKEDGE; + } else if (!strcmp(str, "between_clkedge")) { + return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE; + } else { + dev_warn(codec->dev, "Invalid DMIC sample phase"); + return DA7218_DMIC_SAMPLE_ON_CLKEDGE; + } +} + +static enum da7218_dmic_clk_rate + da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 1500000: + return DA7218_DMIC_CLK_1_5MHZ; + case 3000000: + return DA7218_DMIC_CLK_3_0MHZ; + default: + dev_warn(codec->dev, "Invalid DMIC clock rate"); + return DA7218_DMIC_CLK_3_0MHZ; + } +} + +static enum da7218_hpldet_jack_rate + da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 5: + return DA7218_HPLDET_JACK_RATE_5US; + case 10: + return DA7218_HPLDET_JACK_RATE_10US; + case 20: + return DA7218_HPLDET_JACK_RATE_20US; + case 40: + return DA7218_HPLDET_JACK_RATE_40US; + case 80: + return DA7218_HPLDET_JACK_RATE_80US; + case 160: + return DA7218_HPLDET_JACK_RATE_160US; + case 320: + return DA7218_HPLDET_JACK_RATE_320US; + case 640: + return DA7218_HPLDET_JACK_RATE_640US; + default: + dev_warn(codec->dev, "Invalid jack detect rate"); + return DA7218_HPLDET_JACK_RATE_40US; + } +} + +static enum da7218_hpldet_jack_debounce + da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 0: + return DA7218_HPLDET_JACK_DEBOUNCE_OFF; + case 2: + return DA7218_HPLDET_JACK_DEBOUNCE_2; + case 3: + return DA7218_HPLDET_JACK_DEBOUNCE_3; + case 4: + return DA7218_HPLDET_JACK_DEBOUNCE_4; + default: + dev_warn(codec->dev, "Invalid jack debounce"); + return DA7218_HPLDET_JACK_DEBOUNCE_2; + } +} + +static enum da7218_hpldet_jack_thr + da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 84: + return DA7218_HPLDET_JACK_THR_84PCT; + case 88: + return DA7218_HPLDET_JACK_THR_88PCT; + case 92: + return DA7218_HPLDET_JACK_THR_92PCT; + case 96: + return DA7218_HPLDET_JACK_THR_96PCT; + default: + dev_warn(codec->dev, "Invalid jack threshold level"); + return DA7218_HPLDET_JACK_THR_84PCT; + } +} + +static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct device_node *np = codec->dev->of_node; + struct device_node *hpldet_np; + struct da7218_pdata *pdata; + struct da7218_hpldet_pdata *hpldet_pdata; + const char *of_str; + u32 of_val32; + + pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_warn(codec->dev, "Failed to allocate memory for pdata\n"); + return NULL; + } + + if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0) + pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32); + else + pdata->micbias1_lvl = DA7218_MICBIAS_1_6V; + + if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0) + pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32); + else + pdata->micbias2_lvl = DA7218_MICBIAS_1_6V; + + if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str)) + pdata->mic1_amp_in_sel = + da7218_of_mic_amp_in_sel(codec, of_str); + else + pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF; + + if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str)) + pdata->mic2_amp_in_sel = + da7218_of_mic_amp_in_sel(codec, of_str); + else + pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF; + + if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str)) + pdata->dmic1_data_sel = da7218_of_dmic_data_sel(codec, of_str); + else + pdata->dmic1_data_sel = DA7218_DMIC_DATA_LRISE_RFALL; + + if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str)) + pdata->dmic1_samplephase = + da7218_of_dmic_samplephase(codec, of_str); + else + pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE; + + if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0) + pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32); + else + pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ; + + if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str)) + pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str); + else + pdata->dmic2_data_sel = DA7218_DMIC_DATA_LRISE_RFALL; + + if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str)) + pdata->dmic2_samplephase = + da7218_of_dmic_samplephase(codec, of_str); + else + pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE; + + if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0) + pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32); + else + pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ; + + if (da7218->dev_id == DA7217_DEV_ID) { + if (of_property_read_bool(np, "dlg,hp-diff-single-supply")) + pdata->hp_diff_single_supply = true; + } + + if (da7218->dev_id == DA7218_DEV_ID) { + hpldet_np = of_find_node_by_name(np, "da7218_hpldet"); + if (!hpldet_np) + return pdata; + + hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata), + GFP_KERNEL); + if (!hpldet_pdata) { + dev_warn(codec->dev, + "Failed to allocate memory for hpldet pdata\n"); + of_node_put(hpldet_np); + return pdata; + } + pdata->hpldet_pdata = hpldet_pdata; + + if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us", + &of_val32) >= 0) + hpldet_pdata->jack_rate = + da7218_of_jack_rate(codec, of_val32); + else + hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US; + + if (of_property_read_u32(hpldet_np, "dlg,jack-debounce", + &of_val32) >= 0) + hpldet_pdata->jack_debounce = + da7218_of_jack_debounce(codec, of_val32); + else + hpldet_pdata->jack_debounce = + DA7218_HPLDET_JACK_DEBOUNCE_2; + + if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct", + &of_val32) >= 0) + hpldet_pdata->jack_thr = + da7218_of_jack_thr(codec, of_val32); + else + hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT; + + if (of_property_read_bool(hpldet_np, "dlg,comp-inv")) + hpldet_pdata->comp_inv = true; + + if (of_property_read_bool(hpldet_np, "dlg,hyst")) + hpldet_pdata->hyst = true; + + if (of_property_read_bool(hpldet_np, "dlg,discharge")) + hpldet_pdata->discharge = true; + + of_node_put(hpldet_np); + } + + return pdata; +} + + +/* + * Codec driver functions + */ + +static int da7218_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + /* MCLK */ + if (da7218->mclk) { + ret = clk_prepare_enable(da7218->mclk); + if (ret) { + dev_err(codec->dev, + "Failed to enable mclk\n"); + return ret; + } + } + + /* Master bias */ + snd_soc_update_bits(codec, DA7218_REFERENCES, + DA7218_BIAS_EN_MASK, + DA7218_BIAS_EN_MASK); + + /* Internal LDO */ + snd_soc_update_bits(codec, DA7218_LDO_CTRL, + DA7218_LDO_EN_MASK, + DA7218_LDO_EN_MASK); + } + break; + case SND_SOC_BIAS_OFF: + /* Only disable if jack detection disabled */ + if (!da7218->jack) { + /* Internal LDO */ + snd_soc_update_bits(codec, DA7218_LDO_CTRL, + DA7218_LDO_EN_MASK, 0); + + /* Master bias */ + snd_soc_update_bits(codec, DA7218_REFERENCES, + DA7218_BIAS_EN_MASK, 0); + } + + /* MCLK */ + if (da7218->mclk) + clk_disable_unprepare(da7218->mclk); + break; + } + + return 0; +} + +static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = { + [DA7218_SUPPLY_VDD] = "VDD", + [DA7218_SUPPLY_VDDMIC] = "VDDMIC", + [DA7218_SUPPLY_VDDIO] = "VDDIO", +}; + +static int da7218_handle_supplies(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct regulator *vddio; + u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V; + int i, ret; + + /* Get required supplies */ + for (i = 0; i < DA7218_NUM_SUPPLIES; ++i) + da7218->supplies[i].supply = da7218_supply_names[i]; + + ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES, + da7218->supplies); + if (ret) { + dev_err(codec->dev, "Failed to get supplies\n"); + return ret; + } + + /* Determine VDDIO voltage provided */ + vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer; + ret = regulator_get_voltage(vddio); + if (ret < 1500000) + dev_warn(codec->dev, "Invalid VDDIO voltage\n"); + else if (ret < 2500000) + io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V; + + /* Enable main supplies */ + ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies); + if (ret) { + dev_err(codec->dev, "Failed to enable supplies\n"); + return ret; + } + + /* Ensure device in active mode */ + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK); + + /* Update IO voltage level range */ + snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl); + + return 0; +} + +static void da7218_handle_pdata(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct da7218_pdata *pdata = da7218->pdata; + + if (pdata) { + u8 micbias_lvl = 0, dmic_cfg = 0; + + /* Mic Bias voltages */ + switch (pdata->micbias1_lvl) { + case DA7218_MICBIAS_1_2V: + micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK; + break; + case DA7218_MICBIAS_1_6V: + case DA7218_MICBIAS_1_8V: + case DA7218_MICBIAS_2_0V: + case DA7218_MICBIAS_2_2V: + case DA7218_MICBIAS_2_4V: + case DA7218_MICBIAS_2_6V: + case DA7218_MICBIAS_2_8V: + case DA7218_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias1_lvl << + DA7218_MICBIAS_1_LEVEL_SHIFT); + break; + } + + switch (pdata->micbias2_lvl) { + case DA7218_MICBIAS_1_2V: + micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK; + break; + case DA7218_MICBIAS_1_6V: + case DA7218_MICBIAS_1_8V: + case DA7218_MICBIAS_2_0V: + case DA7218_MICBIAS_2_2V: + case DA7218_MICBIAS_2_4V: + case DA7218_MICBIAS_2_6V: + case DA7218_MICBIAS_2_8V: + case DA7218_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias2_lvl << + DA7218_MICBIAS_2_LEVEL_SHIFT); + break; + } + + snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl); + + /* Mic */ + switch (pdata->mic1_amp_in_sel) { + case DA7218_MIC_AMP_IN_SEL_DIFF: + case DA7218_MIC_AMP_IN_SEL_SE_P: + case DA7218_MIC_AMP_IN_SEL_SE_N: + snd_soc_write(codec, DA7218_MIC_1_SELECT, + pdata->mic1_amp_in_sel); + break; + } + + switch (pdata->mic2_amp_in_sel) { + case DA7218_MIC_AMP_IN_SEL_DIFF: + case DA7218_MIC_AMP_IN_SEL_SE_P: + case DA7218_MIC_AMP_IN_SEL_SE_N: + snd_soc_write(codec, DA7218_MIC_2_SELECT, + pdata->mic2_amp_in_sel); + break; + } + + /* DMic */ + switch (pdata->dmic1_data_sel) { + case DA7218_DMIC_DATA_LFALL_RRISE: + case DA7218_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic1_data_sel << + DA7218_DMIC_1_DATA_SEL_SHIFT); + break; + } + + switch (pdata->dmic1_samplephase) { + case DA7218_DMIC_SAMPLE_ON_CLKEDGE: + case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic1_samplephase << + DA7218_DMIC_1_SAMPLEPHASE_SHIFT); + break; + } + + switch (pdata->dmic1_clk_rate) { + case DA7218_DMIC_CLK_3_0MHZ: + case DA7218_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic1_clk_rate << + DA7218_DMIC_1_CLK_RATE_SHIFT); + break; + } + + snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL, + DA7218_DMIC_1_DATA_SEL_MASK | + DA7218_DMIC_1_SAMPLEPHASE_MASK | + DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg); + + dmic_cfg = 0; + switch (pdata->dmic2_data_sel) { + case DA7218_DMIC_DATA_LFALL_RRISE: + case DA7218_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic2_data_sel << + DA7218_DMIC_2_DATA_SEL_SHIFT); + break; + } + + switch (pdata->dmic2_samplephase) { + case DA7218_DMIC_SAMPLE_ON_CLKEDGE: + case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic2_samplephase << + DA7218_DMIC_2_SAMPLEPHASE_SHIFT); + break; + } + + switch (pdata->dmic2_clk_rate) { + case DA7218_DMIC_CLK_3_0MHZ: + case DA7218_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic2_clk_rate << + DA7218_DMIC_2_CLK_RATE_SHIFT); + break; + } + + snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL, + DA7218_DMIC_2_DATA_SEL_MASK | + DA7218_DMIC_2_SAMPLEPHASE_MASK | + DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg); + + /* DA7217 Specific */ + if (da7218->dev_id == DA7217_DEV_ID) { + da7218->hp_single_supply = + pdata->hp_diff_single_supply; + + if (da7218->hp_single_supply) { + snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK, + DA7218_HP_DIFF_UNLOCK_VAL); + snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL, + DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK, + DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK); + } + } + + /* DA7218 Specific */ + if ((da7218->dev_id == DA7218_DEV_ID) && + (pdata->hpldet_pdata)) { + struct da7218_hpldet_pdata *hpldet_pdata = + pdata->hpldet_pdata; + u8 hpldet_cfg = 0; + + switch (hpldet_pdata->jack_rate) { + case DA7218_HPLDET_JACK_RATE_5US: + case DA7218_HPLDET_JACK_RATE_10US: + case DA7218_HPLDET_JACK_RATE_20US: + case DA7218_HPLDET_JACK_RATE_40US: + case DA7218_HPLDET_JACK_RATE_80US: + case DA7218_HPLDET_JACK_RATE_160US: + case DA7218_HPLDET_JACK_RATE_320US: + case DA7218_HPLDET_JACK_RATE_640US: + hpldet_cfg |= + (hpldet_pdata->jack_rate << + DA7218_HPLDET_JACK_RATE_SHIFT); + break; + } + + switch (hpldet_pdata->jack_debounce) { + case DA7218_HPLDET_JACK_DEBOUNCE_OFF: + case DA7218_HPLDET_JACK_DEBOUNCE_2: + case DA7218_HPLDET_JACK_DEBOUNCE_3: + case DA7218_HPLDET_JACK_DEBOUNCE_4: + hpldet_cfg |= + (hpldet_pdata->jack_debounce << + DA7218_HPLDET_JACK_DEBOUNCE_SHIFT); + break; + } + + switch (hpldet_pdata->jack_thr) { + case DA7218_HPLDET_JACK_THR_84PCT: + case DA7218_HPLDET_JACK_THR_88PCT: + case DA7218_HPLDET_JACK_THR_92PCT: + case DA7218_HPLDET_JACK_THR_96PCT: + hpldet_cfg |= + (hpldet_pdata->jack_thr << + DA7218_HPLDET_JACK_THR_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7218_HPLDET_JACK, + DA7218_HPLDET_JACK_RATE_MASK | + DA7218_HPLDET_JACK_DEBOUNCE_MASK | + DA7218_HPLDET_JACK_THR_MASK, + hpldet_cfg); + + hpldet_cfg = 0; + if (hpldet_pdata->comp_inv) + hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK; + + if (hpldet_pdata->hyst) + hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK; + + if (hpldet_pdata->discharge) + hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK; + + snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg); + } + } +} + +static int da7218_probe(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + /* Regulator configuration */ + ret = da7218_handle_supplies(codec); + if (ret) + return ret; + + /* Handle DT/Platform data */ + if (codec->dev->of_node) + da7218->pdata = da7218_of_to_pdata(codec); + else + da7218->pdata = dev_get_platdata(codec->dev); + + da7218_handle_pdata(codec); + + /* Check if MCLK provided, if not the clock is NULL */ + da7218->mclk = devm_clk_get(codec->dev, "mclk"); + if (IS_ERR(da7218->mclk)) { + if (PTR_ERR(da7218->mclk) != -ENOENT) { + ret = PTR_ERR(da7218->mclk); + goto err_disable_reg; + } else { + da7218->mclk = NULL; + } + } + + /* Default PC to free-running */ + snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK); + + /* + * Default Output Filter mixers to off otherwise DAPM will power + * Mic to HP passthrough paths by default at startup. + */ + snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0); + snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0); + + /* Default CP to normal load, power mode */ + snd_soc_update_bits(codec, DA7218_CP_CTRL, + DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0); + + /* Default gain ramping */ + snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_RAMP_EN_MASK, + DA7218_MIXIN_1_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_RAMP_EN_MASK, + DA7218_MIXIN_2_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_RAMP_EN_MASK, + DA7218_IN_1L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_RAMP_EN_MASK, + DA7218_IN_1R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_RAMP_EN_MASK, + DA7218_IN_2L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_RAMP_EN_MASK, + DA7218_IN_2R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL, + DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_RAMP_EN_MASK, + DA7218_OUT_1L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1R_RAMP_EN_MASK, + DA7218_OUT_1R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_HP_L_CTRL, + DA7218_HP_L_AMP_RAMP_EN_MASK, + DA7218_HP_L_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_HP_R_CTRL, + DA7218_HP_R_AMP_RAMP_EN_MASK, + DA7218_HP_R_AMP_RAMP_EN_MASK); + + /* Default infinite tone gen, start/stop by Kcontrol */ + snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK); + + /* DA7217 specific config */ + if (da7218->dev_id == DA7217_DEV_ID) { + snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL, + DA7218_HP_AMP_DIFF_MODE_EN_MASK, + DA7218_HP_AMP_DIFF_MODE_EN_MASK); + + /* Only DA7218 supports HP detect, mask off for DA7217 */ + snd_soc_write(codec, DA7218_EVENT_MASK, + DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK); + } + + if (da7218->irq) { + /* Mask off mic level events, currently not handled */ + snd_soc_update_bits(codec, DA7218_EVENT_MASK, + DA7218_LVL_DET_EVENT_MSK_MASK, + DA7218_LVL_DET_EVENT_MSK_MASK); + + ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL, + da7218_irq_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "da7218", codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to request IRQ %d: %d\n", + da7218->irq, ret); + goto err_disable_reg; + } + + } + + return 0; + +err_disable_reg: + regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies); + + return ret; +} + +static int da7218_remove(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies); + + return 0; +} + +#ifdef CONFIG_PM +static int da7218_suspend(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + da7218_set_bias_level(codec, SND_SOC_BIAS_OFF); + + /* Put device into standby mode if jack detection disabled */ + if (!da7218->jack) + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0); + + return 0; +} + +static int da7218_resume(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + /* Put device into active mode if previously moved to standby */ + if (!da7218->jack) + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, + DA7218_SYSTEM_ACTIVE_MASK); + + da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define da7218_suspend NULL +#define da7218_resume NULL +#endif + +static struct snd_soc_codec_driver soc_codec_dev_da7218 = { + .probe = da7218_probe, + .remove = da7218_remove, + .suspend = da7218_suspend, + .resume = da7218_resume, + .set_bias_level = da7218_set_bias_level, + + .controls = da7218_snd_controls, + .num_controls = ARRAY_SIZE(da7218_snd_controls), + + .dapm_widgets = da7218_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7218_dapm_widgets), + .dapm_routes = da7218_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7218_audio_map), +}; + + +/* + * Regmap configs + */ + +static struct reg_default da7218_reg_defaults[] = { + { DA7218_SYSTEM_ACTIVE, 0x00 }, + { DA7218_CIF_CTRL, 0x00 }, + { DA7218_SPARE1, 0x00 }, + { DA7218_SR, 0xAA }, + { DA7218_PC_COUNT, 0x02 }, + { DA7218_GAIN_RAMP_CTRL, 0x00 }, + { DA7218_CIF_TIMEOUT_CTRL, 0x01 }, + { DA7218_SYSTEM_MODES_INPUT, 0x00 }, + { DA7218_SYSTEM_MODES_OUTPUT, 0x00 }, + { DA7218_IN_1L_FILTER_CTRL, 0x00 }, + { DA7218_IN_1R_FILTER_CTRL, 0x00 }, + { DA7218_IN_2L_FILTER_CTRL, 0x00 }, + { DA7218_IN_2R_FILTER_CTRL, 0x00 }, + { DA7218_OUT_1L_FILTER_CTRL, 0x40 }, + { DA7218_OUT_1R_FILTER_CTRL, 0x40 }, + { DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 }, + { DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 }, + { DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 }, + { DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 }, + { DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 }, + { DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 }, + { DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 }, + { DA7218_MIXIN_1_CTRL, 0x48 }, + { DA7218_MIXIN_1_GAIN, 0x03 }, + { DA7218_MIXIN_2_CTRL, 0x48 }, + { DA7218_MIXIN_2_GAIN, 0x03 }, + { DA7218_ALC_CTRL1, 0x00 }, + { DA7218_ALC_CTRL2, 0x00 }, + { DA7218_ALC_CTRL3, 0x00 }, + { DA7218_ALC_NOISE, 0x3F }, + { DA7218_ALC_TARGET_MIN, 0x3F }, + { DA7218_ALC_TARGET_MAX, 0x00 }, + { DA7218_ALC_GAIN_LIMITS, 0xFF }, + { DA7218_ALC_ANA_GAIN_LIMITS, 0x71 }, + { DA7218_ALC_ANTICLIP_CTRL, 0x00 }, + { DA7218_AGS_ENABLE, 0x00 }, + { DA7218_AGS_TRIGGER, 0x09 }, + { DA7218_AGS_ATT_MAX, 0x00 }, + { DA7218_AGS_TIMEOUT, 0x00 }, + { DA7218_AGS_ANTICLIP_CTRL, 0x00 }, + { DA7218_ENV_TRACK_CTRL, 0x00 }, + { DA7218_LVL_DET_CTRL, 0x00 }, + { DA7218_LVL_DET_LEVEL, 0x7F }, + { DA7218_DGS_TRIGGER, 0x24 }, + { DA7218_DGS_ENABLE, 0x00 }, + { DA7218_DGS_RISE_FALL, 0x50 }, + { DA7218_DGS_SYNC_DELAY, 0xA3 }, + { DA7218_DGS_SYNC_DELAY2, 0x31 }, + { DA7218_DGS_SYNC_DELAY3, 0x11 }, + { DA7218_DGS_LEVELS, 0x01 }, + { DA7218_DGS_GAIN_CTRL, 0x74 }, + { DA7218_DROUTING_OUTDAI_1L, 0x01 }, + { DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_1R, 0x04 }, + { DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTFILT_1L, 0x01 }, + { DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTFILT_1R, 0x04 }, + { DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_2L, 0x04 }, + { DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_2R, 0x08 }, + { DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DAI_CTRL, 0x28 }, + { DA7218_DAI_TDM_CTRL, 0x40 }, + { DA7218_DAI_OFFSET_LOWER, 0x00 }, + { DA7218_DAI_OFFSET_UPPER, 0x00 }, + { DA7218_DAI_CLK_MODE, 0x01 }, + { DA7218_PLL_CTRL, 0x04 }, + { DA7218_PLL_FRAC_TOP, 0x00 }, + { DA7218_PLL_FRAC_BOT, 0x00 }, + { DA7218_PLL_INTEGER, 0x20 }, + { DA7218_DAC_NG_CTRL, 0x00 }, + { DA7218_DAC_NG_SETUP_TIME, 0x00 }, + { DA7218_DAC_NG_OFF_THRESH, 0x00 }, + { DA7218_DAC_NG_ON_THRESH, 0x00 }, + { DA7218_TONE_GEN_CFG2, 0x00 }, + { DA7218_TONE_GEN_FREQ1_L, 0x55 }, + { DA7218_TONE_GEN_FREQ1_U, 0x15 }, + { DA7218_TONE_GEN_FREQ2_L, 0x00 }, + { DA7218_TONE_GEN_FREQ2_U, 0x40 }, + { DA7218_TONE_GEN_CYCLES, 0x00 }, + { DA7218_TONE_GEN_ON_PER, 0x02 }, + { DA7218_TONE_GEN_OFF_PER, 0x01 }, + { DA7218_CP_CTRL, 0x60 }, + { DA7218_CP_DELAY, 0x11 }, + { DA7218_CP_VOL_THRESHOLD1, 0x0E }, + { DA7218_MIC_1_CTRL, 0x40 }, + { DA7218_MIC_1_GAIN, 0x01 }, + { DA7218_MIC_1_SELECT, 0x00 }, + { DA7218_MIC_2_CTRL, 0x40 }, + { DA7218_MIC_2_GAIN, 0x01 }, + { DA7218_MIC_2_SELECT, 0x00 }, + { DA7218_IN_1_HPF_FILTER_CTRL, 0x80 }, + { DA7218_IN_2_HPF_FILTER_CTRL, 0x80 }, + { DA7218_ADC_1_CTRL, 0x07 }, + { DA7218_ADC_2_CTRL, 0x07 }, + { DA7218_MIXOUT_L_CTRL, 0x00 }, + { DA7218_MIXOUT_L_GAIN, 0x03 }, + { DA7218_MIXOUT_R_CTRL, 0x00 }, + { DA7218_MIXOUT_R_GAIN, 0x03 }, + { DA7218_HP_L_CTRL, 0x40 }, + { DA7218_HP_L_GAIN, 0x3B }, + { DA7218_HP_R_CTRL, 0x40 }, + { DA7218_HP_R_GAIN, 0x3B }, + { DA7218_HP_DIFF_CTRL, 0x00 }, + { DA7218_HP_DIFF_UNLOCK, 0xC3 }, + { DA7218_HPLDET_JACK, 0x0B }, + { DA7218_HPLDET_CTRL, 0x00 }, + { DA7218_REFERENCES, 0x08 }, + { DA7218_IO_CTRL, 0x00 }, + { DA7218_LDO_CTRL, 0x00 }, + { DA7218_SIDETONE_CTRL, 0x40 }, + { DA7218_SIDETONE_IN_SELECT, 0x00 }, + { DA7218_SIDETONE_GAIN, 0x1C }, + { DA7218_DROUTING_ST_OUTFILT_1L, 0x01 }, + { DA7218_DROUTING_ST_OUTFILT_1R, 0x02 }, + { DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 }, + { DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 }, + { DA7218_EVENT_MASK, 0x00 }, + { DA7218_DMIC_1_CTRL, 0x00 }, + { DA7218_DMIC_2_CTRL, 0x00 }, + { DA7218_IN_1L_GAIN, 0x6F }, + { DA7218_IN_1R_GAIN, 0x6F }, + { DA7218_IN_2L_GAIN, 0x6F }, + { DA7218_IN_2R_GAIN, 0x6F }, + { DA7218_OUT_1L_GAIN, 0x6F }, + { DA7218_OUT_1R_GAIN, 0x6F }, + { DA7218_MICBIAS_CTRL, 0x00 }, + { DA7218_MICBIAS_EN, 0x00 }, +}; + +static bool da7218_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7218_STATUS1: + case DA7218_SOFT_RESET: + case DA7218_SYSTEM_STATUS: + case DA7218_CALIB_CTRL: + case DA7218_CALIB_OFFSET_AUTO_M_1: + case DA7218_CALIB_OFFSET_AUTO_U_1: + case DA7218_CALIB_OFFSET_AUTO_M_2: + case DA7218_CALIB_OFFSET_AUTO_U_2: + case DA7218_PLL_STATUS: + case DA7218_PLL_REFOSC_CAL: + case DA7218_TONE_GEN_CFG1: + case DA7218_ADC_MODE: + case DA7218_HP_SNGL_CTRL: + case DA7218_HPLDET_TEST: + case DA7218_EVENT_STATUS: + case DA7218_EVENT: + return 1; + default: + return 0; + } +} + +static const struct regmap_config da7218_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = DA7218_MICBIAS_EN, + .reg_defaults = da7218_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults), + .volatile_reg = da7218_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + + +/* + * I2C layer + */ + +static int da7218_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da7218_priv *da7218; + int ret; + + da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv), + GFP_KERNEL); + if (!da7218) + return -ENOMEM; + + i2c_set_clientdata(i2c, da7218); + + if (i2c->dev.of_node) + da7218->dev_id = da7218_of_get_id(&i2c->dev); + else + da7218->dev_id = id->driver_data; + + if ((da7218->dev_id != DA7217_DEV_ID) && + (da7218->dev_id != DA7218_DEV_ID)) { + dev_err(&i2c->dev, "Invalid device Id\n"); + return -EINVAL; + } + + da7218->irq = i2c->irq; + + da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config); + if (IS_ERR(da7218->regmap)) { + ret = PTR_ERR(da7218->regmap); + dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_da7218, &da7218_dai, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n", + ret); + } + return ret; +} + +static int da7218_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id da7218_i2c_id[] = { + { "da7217", DA7217_DEV_ID }, + { "da7218", DA7218_DEV_ID }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7218_i2c_id); + +static struct i2c_driver da7218_i2c_driver = { + .driver = { + .name = "da7218", + .of_match_table = of_match_ptr(da7218_of_match), + }, + .probe = da7218_i2c_probe, + .remove = da7218_i2c_remove, + .id_table = da7218_i2c_id, +}; + +module_i2c_driver(da7218_i2c_driver); + +MODULE_DESCRIPTION("ASoC DA7218 Codec driver"); +MODULE_AUTHOR("Adam Thomson "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h new file mode 100644 index 000000000000..c2c59049a2ad --- /dev/null +++ b/sound/soc/codecs/da7218.h @@ -0,0 +1,1414 @@ +/* + * da7218.h - DA7218 ALSA SoC Codec Driver + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _DA7218_H +#define _DA7218_H + +#include +#include +#include + + +/* + * Registers + */ +#define DA7218_SYSTEM_ACTIVE 0x0 +#define DA7218_CIF_CTRL 0x1 +#define DA7218_CHIP_ID1 0x4 +#define DA7218_CHIP_ID2 0x5 +#define DA7218_CHIP_REVISION 0x6 +#define DA7218_SPARE1 0x7 +#define DA7218_STATUS1 0x8 +#define DA7218_SOFT_RESET 0x9 +#define DA7218_SR 0xB +#define DA7218_PC_COUNT 0xC +#define DA7218_GAIN_RAMP_CTRL 0xD +#define DA7218_CIF_TIMEOUT_CTRL 0x10 +#define DA7218_SYSTEM_MODES_INPUT 0x14 +#define DA7218_SYSTEM_MODES_OUTPUT 0x15 +#define DA7218_SYSTEM_STATUS 0x16 +#define DA7218_IN_1L_FILTER_CTRL 0x18 +#define DA7218_IN_1R_FILTER_CTRL 0x19 +#define DA7218_IN_2L_FILTER_CTRL 0x1A +#define DA7218_IN_2R_FILTER_CTRL 0x1B +#define DA7218_OUT_1L_FILTER_CTRL 0x20 +#define DA7218_OUT_1R_FILTER_CTRL 0x21 +#define DA7218_OUT_1_HPF_FILTER_CTRL 0x24 +#define DA7218_OUT_1_EQ_12_FILTER_CTRL 0x25 +#define DA7218_OUT_1_EQ_34_FILTER_CTRL 0x26 +#define DA7218_OUT_1_EQ_5_FILTER_CTRL 0x27 +#define DA7218_OUT_1_BIQ_5STAGE_CTRL 0x28 +#define DA7218_OUT_1_BIQ_5STAGE_DATA 0x29 +#define DA7218_OUT_1_BIQ_5STAGE_ADDR 0x2A +#define DA7218_MIXIN_1_CTRL 0x2C +#define DA7218_MIXIN_1_GAIN 0x2D +#define DA7218_MIXIN_2_CTRL 0x2E +#define DA7218_MIXIN_2_GAIN 0x2F +#define DA7218_ALC_CTRL1 0x30 +#define DA7218_ALC_CTRL2 0x31 +#define DA7218_ALC_CTRL3 0x32 +#define DA7218_ALC_NOISE 0x33 +#define DA7218_ALC_TARGET_MIN 0x34 +#define DA7218_ALC_TARGET_MAX 0x35 +#define DA7218_ALC_GAIN_LIMITS 0x36 +#define DA7218_ALC_ANA_GAIN_LIMITS 0x37 +#define DA7218_ALC_ANTICLIP_CTRL 0x38 +#define DA7218_AGS_ENABLE 0x3C +#define DA7218_AGS_TRIGGER 0x3D +#define DA7218_AGS_ATT_MAX 0x3E +#define DA7218_AGS_TIMEOUT 0x3F +#define DA7218_AGS_ANTICLIP_CTRL 0x40 +#define DA7218_CALIB_CTRL 0x44 +#define DA7218_CALIB_OFFSET_AUTO_M_1 0x45 +#define DA7218_CALIB_OFFSET_AUTO_U_1 0x46 +#define DA7218_CALIB_OFFSET_AUTO_M_2 0x47 +#define DA7218_CALIB_OFFSET_AUTO_U_2 0x48 +#define DA7218_ENV_TRACK_CTRL 0x4C +#define DA7218_LVL_DET_CTRL 0x50 +#define DA7218_LVL_DET_LEVEL 0x51 +#define DA7218_DGS_TRIGGER 0x54 +#define DA7218_DGS_ENABLE 0x55 +#define DA7218_DGS_RISE_FALL 0x56 +#define DA7218_DGS_SYNC_DELAY 0x57 +#define DA7218_DGS_SYNC_DELAY2 0x58 +#define DA7218_DGS_SYNC_DELAY3 0x59 +#define DA7218_DGS_LEVELS 0x5A +#define DA7218_DGS_GAIN_CTRL 0x5B +#define DA7218_DROUTING_OUTDAI_1L 0x5C +#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN 0x5D +#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN 0x5E +#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN 0x5F +#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN 0x60 +#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN 0x61 +#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN 0x62 +#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN 0x63 +#define DA7218_DROUTING_OUTDAI_1R 0x64 +#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN 0x65 +#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN 0x66 +#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN 0x67 +#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN 0x68 +#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN 0x69 +#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN 0x6A +#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN 0x6B +#define DA7218_DROUTING_OUTFILT_1L 0x6C +#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN 0x6D +#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN 0x6E +#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN 0x6F +#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN 0x70 +#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN 0x71 +#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN 0x72 +#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN 0x73 +#define DA7218_DROUTING_OUTFILT_1R 0x74 +#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN 0x75 +#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN 0x76 +#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN 0x77 +#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN 0x78 +#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN 0x79 +#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN 0x7A +#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN 0x7B +#define DA7218_DROUTING_OUTDAI_2L 0x7C +#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN 0x7D +#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN 0x7E +#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN 0x7F +#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN 0x80 +#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN 0x81 +#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN 0x82 +#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN 0x83 +#define DA7218_DROUTING_OUTDAI_2R 0x84 +#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN 0x85 +#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN 0x86 +#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN 0x87 +#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN 0x88 +#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN 0x89 +#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN 0x8A +#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN 0x8B +#define DA7218_DAI_CTRL 0x8C +#define DA7218_DAI_TDM_CTRL 0x8D +#define DA7218_DAI_OFFSET_LOWER 0x8E +#define DA7218_DAI_OFFSET_UPPER 0x8F +#define DA7218_DAI_CLK_MODE 0x90 +#define DA7218_PLL_CTRL 0x91 +#define DA7218_PLL_FRAC_TOP 0x92 +#define DA7218_PLL_FRAC_BOT 0x93 +#define DA7218_PLL_INTEGER 0x94 +#define DA7218_PLL_STATUS 0x95 +#define DA7218_PLL_REFOSC_CAL 0x98 +#define DA7218_DAC_NG_CTRL 0x9C +#define DA7218_DAC_NG_SETUP_TIME 0x9D +#define DA7218_DAC_NG_OFF_THRESH 0x9E +#define DA7218_DAC_NG_ON_THRESH 0x9F +#define DA7218_TONE_GEN_CFG1 0xA0 +#define DA7218_TONE_GEN_CFG2 0xA1 +#define DA7218_TONE_GEN_FREQ1_L 0xA2 +#define DA7218_TONE_GEN_FREQ1_U 0xA3 +#define DA7218_TONE_GEN_FREQ2_L 0xA4 +#define DA7218_TONE_GEN_FREQ2_U 0xA5 +#define DA7218_TONE_GEN_CYCLES 0xA6 +#define DA7218_TONE_GEN_ON_PER 0xA7 +#define DA7218_TONE_GEN_OFF_PER 0xA8 +#define DA7218_CP_CTRL 0xAC +#define DA7218_CP_DELAY 0xAD +#define DA7218_CP_VOL_THRESHOLD1 0xAE +#define DA7218_MIC_1_CTRL 0xB4 +#define DA7218_MIC_1_GAIN 0xB5 +#define DA7218_MIC_1_SELECT 0xB7 +#define DA7218_MIC_2_CTRL 0xB8 +#define DA7218_MIC_2_GAIN 0xB9 +#define DA7218_MIC_2_SELECT 0xBB +#define DA7218_IN_1_HPF_FILTER_CTRL 0xBC +#define DA7218_IN_2_HPF_FILTER_CTRL 0xBD +#define DA7218_ADC_1_CTRL 0xC0 +#define DA7218_ADC_2_CTRL 0xC1 +#define DA7218_ADC_MODE 0xC2 +#define DA7218_MIXOUT_L_CTRL 0xCC +#define DA7218_MIXOUT_L_GAIN 0xCD +#define DA7218_MIXOUT_R_CTRL 0xCE +#define DA7218_MIXOUT_R_GAIN 0xCF +#define DA7218_HP_L_CTRL 0xD0 +#define DA7218_HP_L_GAIN 0xD1 +#define DA7218_HP_R_CTRL 0xD2 +#define DA7218_HP_R_GAIN 0xD3 +#define DA7218_HP_SNGL_CTRL 0xD4 +#define DA7218_HP_DIFF_CTRL 0xD5 +#define DA7218_HP_DIFF_UNLOCK 0xD7 +#define DA7218_HPLDET_JACK 0xD8 +#define DA7218_HPLDET_CTRL 0xD9 +#define DA7218_HPLDET_TEST 0xDA +#define DA7218_REFERENCES 0xDC +#define DA7218_IO_CTRL 0xE0 +#define DA7218_LDO_CTRL 0xE1 +#define DA7218_SIDETONE_CTRL 0xE4 +#define DA7218_SIDETONE_IN_SELECT 0xE5 +#define DA7218_SIDETONE_GAIN 0xE6 +#define DA7218_DROUTING_ST_OUTFILT_1L 0xE8 +#define DA7218_DROUTING_ST_OUTFILT_1R 0xE9 +#define DA7218_SIDETONE_BIQ_3STAGE_DATA 0xEA +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR 0xEB +#define DA7218_EVENT_STATUS 0xEC +#define DA7218_EVENT 0xED +#define DA7218_EVENT_MASK 0xEE +#define DA7218_DMIC_1_CTRL 0xF0 +#define DA7218_DMIC_2_CTRL 0xF1 +#define DA7218_IN_1L_GAIN 0xF4 +#define DA7218_IN_1R_GAIN 0xF5 +#define DA7218_IN_2L_GAIN 0xF6 +#define DA7218_IN_2R_GAIN 0xF7 +#define DA7218_OUT_1L_GAIN 0xF8 +#define DA7218_OUT_1R_GAIN 0xF9 +#define DA7218_MICBIAS_CTRL 0xFC +#define DA7218_MICBIAS_EN 0xFD + + +/* + * Bit Fields + */ + +#define DA7218_SWITCH_EN_MAX 0x1 + +/* DA7218_SYSTEM_ACTIVE = 0x0 */ +#define DA7218_SYSTEM_ACTIVE_SHIFT 0 +#define DA7218_SYSTEM_ACTIVE_MASK (0x1 << 0) + +/* DA7218_CIF_CTRL = 0x1 */ +#define DA7218_CIF_I2C_WRITE_MODE_SHIFT 0 +#define DA7218_CIF_I2C_WRITE_MODE_MASK (0x1 << 0) + +/* DA7218_CHIP_ID1 = 0x4 */ +#define DA7218_CHIP_ID1_SHIFT 0 +#define DA7218_CHIP_ID1_MASK (0xFF << 0) + +/* DA7218_CHIP_ID2 = 0x5 */ +#define DA7218_CHIP_ID2_SHIFT 0 +#define DA7218_CHIP_ID2_MASK (0xFF << 0) + +/* DA7218_CHIP_REVISION = 0x6 */ +#define DA7218_CHIP_MINOR_SHIFT 0 +#define DA7218_CHIP_MINOR_MASK (0xF << 0) +#define DA7218_CHIP_MAJOR_SHIFT 4 +#define DA7218_CHIP_MAJOR_MASK (0xF << 4) + +/* DA7218_SPARE1 = 0x7 */ +#define DA7218_SPARE1_SHIFT 0 +#define DA7218_SPARE1_MASK (0xFF << 0) + +/* DA7218_STATUS1 = 0x8 */ +#define DA7218_STATUS_SPARE1_SHIFT 0 +#define DA7218_STATUS_SPARE1_MASK (0xFF << 0) + +/* DA7218_SOFT_RESET = 0x9 */ +#define DA7218_CIF_REG_SOFT_RESET_SHIFT 7 +#define DA7218_CIF_REG_SOFT_RESET_MASK (0x1 << 7) + +/* DA7218_SR = 0xB */ +#define DA7218_SR_ADC_SHIFT 0 +#define DA7218_SR_ADC_MASK (0xF << 0) +#define DA7218_SR_DAC_SHIFT 4 +#define DA7218_SR_DAC_MASK (0xF << 4) +#define DA7218_SR_8000 0x01 +#define DA7218_SR_11025 0x02 +#define DA7218_SR_12000 0x03 +#define DA7218_SR_16000 0x05 +#define DA7218_SR_22050 0x06 +#define DA7218_SR_24000 0x07 +#define DA7218_SR_32000 0x09 +#define DA7218_SR_44100 0x0A +#define DA7218_SR_48000 0x0B +#define DA7218_SR_88200 0x0E +#define DA7218_SR_96000 0x0F + +/* DA7218_PC_COUNT = 0xC */ +#define DA7218_PC_FREERUN_SHIFT 0 +#define DA7218_PC_FREERUN_MASK (0x1 << 0) +#define DA7218_PC_RESYNC_AUTO_SHIFT 1 +#define DA7218_PC_RESYNC_AUTO_MASK (0x1 << 1) + +/* DA7218_GAIN_RAMP_CTRL = 0xD */ +#define DA7218_GAIN_RAMP_RATE_SHIFT 0 +#define DA7218_GAIN_RAMP_RATE_MASK (0x3 << 0) +#define DA7218_GAIN_RAMP_RATE_MAX 4 + +/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */ +#define DA7218_I2C_TIMEOUT_EN_SHIFT 0 +#define DA7218_I2C_TIMEOUT_EN_MASK (0x1 << 0) + +/* DA7218_SYSTEM_MODES_INPUT = 0x14 */ +#define DA7218_MODE_SUBMIT_SHIFT 0 +#define DA7218_MODE_SUBMIT_MASK (0x1 << 0) +#define DA7218_ADC_MODE_SHIFT 1 +#define DA7218_ADC_MODE_MASK (0x7F << 1) + +/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */ +#define DA7218_MODE_SUBMIT_SHIFT 0 +#define DA7218_MODE_SUBMIT_MASK (0x1 << 0) +#define DA7218_DAC_MODE_SHIFT 1 +#define DA7218_DAC_MODE_MASK (0x7F << 1) + +/* DA7218_SYSTEM_STATUS = 0x16 */ +#define DA7218_SC1_BUSY_SHIFT 0 +#define DA7218_SC1_BUSY_MASK (0x1 << 0) +#define DA7218_SC2_BUSY_SHIFT 1 +#define DA7218_SC2_BUSY_MASK (0x1 << 1) + +/* DA7218_IN_1L_FILTER_CTRL = 0x18 */ +#define DA7218_IN_1L_RAMP_EN_SHIFT 5 +#define DA7218_IN_1L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_1L_MUTE_EN_SHIFT 6 +#define DA7218_IN_1L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_1L_FILTER_EN_SHIFT 7 +#define DA7218_IN_1L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_1R_FILTER_CTRL = 0x19 */ +#define DA7218_IN_1R_RAMP_EN_SHIFT 5 +#define DA7218_IN_1R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_1R_MUTE_EN_SHIFT 6 +#define DA7218_IN_1R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_1R_FILTER_EN_SHIFT 7 +#define DA7218_IN_1R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_2L_FILTER_CTRL = 0x1A */ +#define DA7218_IN_2L_RAMP_EN_SHIFT 5 +#define DA7218_IN_2L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_2L_MUTE_EN_SHIFT 6 +#define DA7218_IN_2L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_2L_FILTER_EN_SHIFT 7 +#define DA7218_IN_2L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_2R_FILTER_CTRL = 0x1B */ +#define DA7218_IN_2R_RAMP_EN_SHIFT 5 +#define DA7218_IN_2R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_2R_MUTE_EN_SHIFT 6 +#define DA7218_IN_2R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_2R_FILTER_EN_SHIFT 7 +#define DA7218_IN_2R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */ +#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT 3 +#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK (0x1 << 3) +#define DA7218_OUT_BIQ_5STAGE_SEL_MAX 2 +#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT 4 +#define DA7218_OUT_1L_SUBRANGE_EN_MASK (0x1 << 4) +#define DA7218_OUT_1L_RAMP_EN_SHIFT 5 +#define DA7218_OUT_1L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_OUT_1L_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1L_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */ +#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT 3 +#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK (0x1 << 3) +#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT 4 +#define DA7218_OUT_1R_SUBRANGE_EN_MASK (0x1 << 4) +#define DA7218_OUT_1R_RAMP_EN_SHIFT 5 +#define DA7218_OUT_1R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_OUT_1R_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1R_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */ +#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_VOICE_HPF_CORNER_MAX 8 +#define DA7218_OUT_1_VOICE_EN_SHIFT 3 +#define DA7218_OUT_1_VOICE_EN_MASK (0x1 << 3) +#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_AUDIO_HPF_CORNER_MAX 4 +#define DA7218_OUT_1_HPF_EN_SHIFT 7 +#define DA7218_OUT_1_HPF_EN_MASK (0x1 << 7) +#define DA7218_HPF_MODE_SHIFT 0 +#define DA7218_HPF_DISABLED ((0x0 << 3) | (0x0 << 7)) +#define DA7218_HPF_AUDIO_EN ((0x0 << 3) | (0x1 << 7)) +#define DA7218_HPF_VOICE_EN ((0x1 << 3) | (0x1 << 7)) +#define DA7218_HPF_MODE_MASK ((0x1 << 3) | (0x1 << 7)) +#define DA7218_HPF_MODE_MAX 3 + +/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */ +#define DA7218_OUT_1_EQ_BAND1_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND1_MASK (0xF << 0) +#define DA7218_OUT_EQ_BAND_MAX 0xF +#define DA7218_OUT_1_EQ_BAND2_SHIFT 4 +#define DA7218_OUT_1_EQ_BAND2_MASK (0xF << 4) + +/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */ +#define DA7218_OUT_1_EQ_BAND3_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND3_MASK (0xF << 0) +#define DA7218_OUT_1_EQ_BAND4_SHIFT 4 +#define DA7218_OUT_1_EQ_BAND4_MASK (0xF << 4) + +/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */ +#define DA7218_OUT_1_EQ_BAND5_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND5_MASK (0xF << 0) +#define DA7218_OUT_1_EQ_EN_SHIFT 7 +#define DA7218_OUT_1_EQ_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */ +#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */ +#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT 0 +#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK (0xFF << 0) + +/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */ +#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT 0 +#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK (0x3F << 0) +#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE 50 + +/* DA7218_MIXIN_1_CTRL = 0x2C */ +#define DA7218_MIXIN_1_MIX_SEL_SHIFT 3 +#define DA7218_MIXIN_1_MIX_SEL_MASK (0x1 << 3) +#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT 4 +#define DA7218_MIXIN_1_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT 5 +#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIXIN_1_AMP_EN_SHIFT 7 +#define DA7218_MIXIN_1_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXIN_1_GAIN = 0x2D */ +#define DA7218_MIXIN_1_AMP_GAIN_SHIFT 0 +#define DA7218_MIXIN_1_AMP_GAIN_MASK (0xF << 0) +#define DA7218_MIXIN_AMP_GAIN_MAX 0xF + +/* DA7218_MIXIN_2_CTRL = 0x2E */ +#define DA7218_MIXIN_2_MIX_SEL_SHIFT 3 +#define DA7218_MIXIN_2_MIX_SEL_MASK (0x1 << 3) +#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT 4 +#define DA7218_MIXIN_2_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT 5 +#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIXIN_2_AMP_EN_SHIFT 7 +#define DA7218_MIXIN_2_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXIN_2_GAIN = 0x2F */ +#define DA7218_MIXIN_2_AMP_GAIN_SHIFT 0 +#define DA7218_MIXIN_2_AMP_GAIN_MASK (0xF << 0) + +/* DA7218_ALC_CTRL1 = 0x30 */ +#define DA7218_ALC_EN_SHIFT 0 +#define DA7218_ALC_EN_MASK (0xF << 0) +#define DA7218_ALC_CHAN1_L_EN_SHIFT 0 +#define DA7218_ALC_CHAN1_R_EN_SHIFT 1 +#define DA7218_ALC_CHAN2_L_EN_SHIFT 2 +#define DA7218_ALC_CHAN2_R_EN_SHIFT 3 +#define DA7218_ALC_SYNC_MODE_SHIFT 4 +#define DA7218_ALC_SYNC_MODE_MASK (0xF << 4) +#define DA7218_ALC_SYNC_MODE_CH1 (0x1 << 4) +#define DA7218_ALC_SYNC_MODE_CH2 (0x4 << 4) + +/* DA7218_ALC_CTRL2 = 0x31 */ +#define DA7218_ALC_ATTACK_SHIFT 0 +#define DA7218_ALC_ATTACK_MASK (0xF << 0) +#define DA7218_ALC_ATTACK_MAX 13 +#define DA7218_ALC_RELEASE_SHIFT 4 +#define DA7218_ALC_RELEASE_MASK (0xF << 4) +#define DA7218_ALC_RELEASE_MAX 11 + +/* DA7218_ALC_CTRL3 = 0x32 */ +#define DA7218_ALC_HOLD_SHIFT 0 +#define DA7218_ALC_HOLD_MASK (0xF << 0) +#define DA7218_ALC_HOLD_MAX 16 + +/* DA7218_ALC_NOISE = 0x33 */ +#define DA7218_ALC_NOISE_SHIFT 0 +#define DA7218_ALC_NOISE_MASK (0x3F << 0) +#define DA7218_ALC_THRESHOLD_MAX 0x3F + +/* DA7218_ALC_TARGET_MIN = 0x34 */ +#define DA7218_ALC_THRESHOLD_MIN_SHIFT 0 +#define DA7218_ALC_THRESHOLD_MIN_MASK (0x3F << 0) + +/* DA7218_ALC_TARGET_MAX = 0x35 */ +#define DA7218_ALC_THRESHOLD_MAX_SHIFT 0 +#define DA7218_ALC_THRESHOLD_MAX_MASK (0x3F << 0) + +/* DA7218_ALC_GAIN_LIMITS = 0x36 */ +#define DA7218_ALC_ATTEN_MAX_SHIFT 0 +#define DA7218_ALC_ATTEN_MAX_MASK (0xF << 0) +#define DA7218_ALC_ATTEN_GAIN_MAX 0xF +#define DA7218_ALC_GAIN_MAX_SHIFT 4 +#define DA7218_ALC_GAIN_MAX_MASK (0xF << 4) + +/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */ +#define DA7218_ALC_ANA_GAIN_MIN_SHIFT 0 +#define DA7218_ALC_ANA_GAIN_MIN_MASK (0x7 << 0) +#define DA7218_ALC_ANA_GAIN_MIN 0x1 +#define DA7218_ALC_ANA_GAIN_MAX 0x7 +#define DA7218_ALC_ANA_GAIN_MAX_SHIFT 4 +#define DA7218_ALC_ANA_GAIN_MAX_MASK (0x7 << 4) + +/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */ +#define DA7218_ALC_ANTICLIP_STEP_SHIFT 0 +#define DA7218_ALC_ANTICLIP_STEP_MASK (0x3 << 0) +#define DA7218_ALC_ANTICLIP_STEP_MAX 4 +#define DA7218_ALC_ANTICLIP_EN_SHIFT 7 +#define DA7218_ALC_ANTICLIP_EN_MASK (0x1 << 7) + +/* DA7218_AGS_ENABLE = 0x3C */ +#define DA7218_AGS_ENABLE_SHIFT 0 +#define DA7218_AGS_ENABLE_MASK (0x3 << 0) +#define DA7218_AGS_ENABLE_CHAN1_SHIFT 0 +#define DA7218_AGS_ENABLE_CHAN2_SHIFT 1 + +/* DA7218_AGS_TRIGGER = 0x3D */ +#define DA7218_AGS_TRIGGER_SHIFT 0 +#define DA7218_AGS_TRIGGER_MASK (0xF << 0) +#define DA7218_AGS_TRIGGER_MAX 0xF + +/* DA7218_AGS_ATT_MAX = 0x3E */ +#define DA7218_AGS_ATT_MAX_SHIFT 0 +#define DA7218_AGS_ATT_MAX_MASK (0x7 << 0) +#define DA7218_AGS_ATT_MAX_MAX 0x7 + +/* DA7218_AGS_TIMEOUT = 0x3F */ +#define DA7218_AGS_TIMEOUT_EN_SHIFT 0 +#define DA7218_AGS_TIMEOUT_EN_MASK (0x1 << 0) + +/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */ +#define DA7218_AGS_ANTICLIP_EN_SHIFT 7 +#define DA7218_AGS_ANTICLIP_EN_MASK (0x1 << 7) + +/* DA7218_CALIB_CTRL = 0x44 */ +#define DA7218_CALIB_OFFSET_EN_SHIFT 0 +#define DA7218_CALIB_OFFSET_EN_MASK (0x1 << 0) +#define DA7218_CALIB_AUTO_EN_SHIFT 2 +#define DA7218_CALIB_AUTO_EN_MASK (0x1 << 2) +#define DA7218_CALIB_OVERFLOW_SHIFT 3 +#define DA7218_CALIB_OVERFLOW_MASK (0x1 << 3) + +/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */ +#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK (0xFF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */ +#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK (0xF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */ +#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK (0xFF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */ +#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK (0xF << 0) + +/* DA7218_ENV_TRACK_CTRL = 0x4C */ +#define DA7218_INTEG_ATTACK_SHIFT 0 +#define DA7218_INTEG_ATTACK_MASK (0x3 << 0) +#define DA7218_INTEG_RELEASE_SHIFT 4 +#define DA7218_INTEG_RELEASE_MASK (0x3 << 4) +#define DA7218_INTEG_MAX 4 + +/* DA7218_LVL_DET_CTRL = 0x50 */ +#define DA7218_LVL_DET_EN_SHIFT 0 +#define DA7218_LVL_DET_EN_MASK (0xF << 0) +#define DA7218_LVL_DET_EN_CHAN1L_SHIFT 0 +#define DA7218_LVL_DET_EN_CHAN1R_SHIFT 1 +#define DA7218_LVL_DET_EN_CHAN2L_SHIFT 2 +#define DA7218_LVL_DET_EN_CHAN2R_SHIFT 3 + +/* DA7218_LVL_DET_LEVEL = 0x51 */ +#define DA7218_LVL_DET_LEVEL_SHIFT 0 +#define DA7218_LVL_DET_LEVEL_MASK (0x7F << 0) +#define DA7218_LVL_DET_LEVEL_MAX 0x7F + +/* DA7218_DGS_TRIGGER = 0x54 */ +#define DA7218_DGS_TRIGGER_LVL_SHIFT 0 +#define DA7218_DGS_TRIGGER_LVL_MASK (0x3F << 0) +#define DA7218_DGS_TRIGGER_MAX 0x3F + +/* DA7218_DGS_ENABLE = 0x55 */ +#define DA7218_DGS_ENABLE_SHIFT 0 +#define DA7218_DGS_ENABLE_MASK (0x3 << 0) +#define DA7218_DGS_ENABLE_L_SHIFT 0 +#define DA7218_DGS_ENABLE_R_SHIFT 1 + +/* DA7218_DGS_RISE_FALL = 0x56 */ +#define DA7218_DGS_RISE_COEFF_SHIFT 0 +#define DA7218_DGS_RISE_COEFF_MASK (0x7 << 0) +#define DA7218_DGS_RISE_COEFF_MAX 7 +#define DA7218_DGS_FALL_COEFF_SHIFT 4 +#define DA7218_DGS_FALL_COEFF_MASK (0x7 << 4) +#define DA7218_DGS_FALL_COEFF_MAX 8 + +/* DA7218_DGS_SYNC_DELAY = 0x57 */ +#define DA7218_DGS_SYNC_DELAY_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY_MASK (0xFF << 0) +#define DA7218_DGS_SYNC_DELAY_MAX 0xFF + +/* DA7218_DGS_SYNC_DELAY2 = 0x58 */ +#define DA7218_DGS_SYNC_DELAY2_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY2_MASK (0xFF << 0) + +/* DA7218_DGS_SYNC_DELAY3 = 0x59 */ +#define DA7218_DGS_SYNC_DELAY3_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY3_MASK (0x7F << 0) +#define DA7218_DGS_SYNC_DELAY3_MAX 0x7F + +/* DA7218_DGS_LEVELS = 0x5A */ +#define DA7218_DGS_ANTICLIP_LVL_SHIFT 0 +#define DA7218_DGS_ANTICLIP_LVL_MASK (0x7 << 0) +#define DA7218_DGS_ANTICLIP_LVL_MAX 0x7 +#define DA7218_DGS_SIGNAL_LVL_SHIFT 4 +#define DA7218_DGS_SIGNAL_LVL_MASK (0xF << 4) +#define DA7218_DGS_SIGNAL_LVL_MAX 0xF + +/* DA7218_DGS_GAIN_CTRL = 0x5B */ +#define DA7218_DGS_STEPS_SHIFT 0 +#define DA7218_DGS_STEPS_MASK (0x1F << 0) +#define DA7218_DGS_STEPS_MAX 0x1F +#define DA7218_DGS_RAMP_EN_SHIFT 5 +#define DA7218_DGS_RAMP_EN_MASK (0x1 << 5) +#define DA7218_DGS_SUBR_EN_SHIFT 6 +#define DA7218_DGS_SUBR_EN_MASK (0x1 << 6) + +/* DA7218_DROUTING_OUTDAI_1L = 0x5C */ +#define DA7218_OUTDAI_1L_SRC_SHIFT 0 +#define DA7218_OUTDAI_1L_SRC_MASK (0x7F << 0) +#define DA7218_DMIX_SRC_INFILT1L 0 +#define DA7218_DMIX_SRC_INFILT1R 1 +#define DA7218_DMIX_SRC_INFILT2L 2 +#define DA7218_DMIX_SRC_INFILT2R 3 +#define DA7218_DMIX_SRC_TONEGEN 4 +#define DA7218_DMIX_SRC_DAIL 5 +#define DA7218_DMIX_SRC_DAIR 6 + +/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */ +#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK (0x1F << 0) +#define DA7218_DMIX_GAIN_MAX 0x1F + +/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */ +#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */ +#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */ +#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */ +#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */ +#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */ +#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_1R = 0x64 */ +#define DA7218_OUTDAI_1R_SRC_SHIFT 0 +#define DA7218_OUTDAI_1R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */ +#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */ +#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */ +#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */ +#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */ +#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */ +#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */ +#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTFILT_1L = 0x6C */ +#define DA7218_OUTFILT_1L_SRC_SHIFT 0 +#define DA7218_OUTFILT_1L_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */ +#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */ +#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */ +#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */ +#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */ +#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */ +#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */ +#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTFILT_1R = 0x74 */ +#define DA7218_OUTFILT_1R_SRC_SHIFT 0 +#define DA7218_OUTFILT_1R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */ +#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */ +#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */ +#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */ +#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */ +#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */ +#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */ +#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_2L = 0x7C */ +#define DA7218_OUTDAI_2L_SRC_SHIFT 0 +#define DA7218_OUTDAI_2L_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */ +#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */ +#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */ +#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */ +#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */ +#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */ +#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */ +#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_2R = 0x84 */ +#define DA7218_OUTDAI_2R_SRC_SHIFT 0 +#define DA7218_OUTDAI_2R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */ +#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */ +#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */ +#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */ +#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */ +#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */ +#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */ +#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DAI_CTRL = 0x8C */ +#define DA7218_DAI_FORMAT_SHIFT 0 +#define DA7218_DAI_FORMAT_MASK (0x3 << 0) +#define DA7218_DAI_FORMAT_I2S (0x0 << 0) +#define DA7218_DAI_FORMAT_LEFT_J (0x1 << 0) +#define DA7218_DAI_FORMAT_RIGHT_J (0x2 << 0) +#define DA7218_DAI_FORMAT_DSP (0x3 << 0) +#define DA7218_DAI_WORD_LENGTH_SHIFT 2 +#define DA7218_DAI_WORD_LENGTH_MASK (0x3 << 2) +#define DA7218_DAI_WORD_LENGTH_S16_LE (0x0 << 2) +#define DA7218_DAI_WORD_LENGTH_S20_LE (0x1 << 2) +#define DA7218_DAI_WORD_LENGTH_S24_LE (0x2 << 2) +#define DA7218_DAI_WORD_LENGTH_S32_LE (0x3 << 2) +#define DA7218_DAI_CH_NUM_SHIFT 4 +#define DA7218_DAI_CH_NUM_MASK (0x7 << 4) +#define DA7218_DAI_CH_NUM_MAX 4 +#define DA7218_DAI_EN_SHIFT 7 +#define DA7218_DAI_EN_MASK (0x1 << 7) + +/* DA7218_DAI_TDM_CTRL = 0x8D */ +#define DA7218_DAI_TDM_CH_EN_SHIFT 0 +#define DA7218_DAI_TDM_CH_EN_MASK (0xF << 0) +#define DA7218_DAI_TDM_MAX_SLOTS 4 +#define DA7218_DAI_OE_SHIFT 6 +#define DA7218_DAI_OE_MASK (0x1 << 6) +#define DA7218_DAI_TDM_MODE_EN_SHIFT 7 +#define DA7218_DAI_TDM_MODE_EN_MASK (0x1 << 7) + +/* DA7218_DAI_OFFSET_LOWER = 0x8E */ +#define DA7218_DAI_OFFSET_LOWER_SHIFT 0 +#define DA7218_DAI_OFFSET_LOWER_MASK (0xFF << 0) + +/* DA7218_DAI_OFFSET_UPPER = 0x8F */ +#define DA7218_DAI_OFFSET_UPPER_SHIFT 0 +#define DA7218_DAI_OFFSET_UPPER_MASK (0x7 << 0) + +/* DA7218_DAI_CLK_MODE = 0x90 */ +#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT 0 +#define DA7218_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_64 (0x1 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_128 (0x2 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_256 (0x3 << 0) +#define DA7218_DAI_CLK_POL_SHIFT 2 +#define DA7218_DAI_CLK_POL_MASK (0x1 << 2) +#define DA7218_DAI_CLK_POL_INV (0x1 << 2) +#define DA7218_DAI_WCLK_POL_SHIFT 3 +#define DA7218_DAI_WCLK_POL_MASK (0x1 << 3) +#define DA7218_DAI_WCLK_POL_INV (0x1 << 3) +#define DA7218_DAI_WCLK_TRI_STATE_SHIFT 4 +#define DA7218_DAI_WCLK_TRI_STATE_MASK (0x1 << 4) +#define DA7218_DAI_CLK_EN_SHIFT 7 +#define DA7218_DAI_CLK_EN_MASK (0x1 << 7) + +/* DA7218_PLL_CTRL = 0x91 */ +#define DA7218_PLL_INDIV_SHIFT 0 +#define DA7218_PLL_INDIV_MASK (0x7 << 0) +#define DA7218_PLL_INDIV_2_5_MHZ (0x0 << 0) +#define DA7218_PLL_INDIV_5_10_MHZ (0x1 << 0) +#define DA7218_PLL_INDIV_10_20_MHZ (0x2 << 0) +#define DA7218_PLL_INDIV_20_40_MHZ (0x3 << 0) +#define DA7218_PLL_INDIV_40_54_MHZ (0x4 << 0) +#define DA7218_PLL_INDIV_2_10_MHZ_VAL 2 +#define DA7218_PLL_INDIV_10_20_MHZ_VAL 4 +#define DA7218_PLL_INDIV_20_40_MHZ_VAL 8 +#define DA7218_PLL_INDIV_40_54_MHZ_VAL 16 +#define DA7218_PLL_MCLK_SQR_EN_SHIFT 4 +#define DA7218_PLL_MCLK_SQR_EN_MASK (0x1 << 4) +#define DA7218_PLL_MODE_SHIFT 6 +#define DA7218_PLL_MODE_MASK (0x3 << 6) +#define DA7218_PLL_MODE_BYPASS (0x0 << 6) +#define DA7218_PLL_MODE_NORMAL (0x1 << 6) +#define DA7218_PLL_MODE_SRM (0x2 << 6) +#define DA7218_PLL_MODE_32KHZ (0x3 << 6) + +/* DA7218_PLL_FRAC_TOP = 0x92 */ +#define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT 0 +#define DA7218_PLL_FBDIV_FRAC_TOP_MASK (0x1F << 0) + +/* DA7218_PLL_FRAC_BOT = 0x93 */ +#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT 0 +#define DA7218_PLL_FBDIV_FRAC_BOT_MASK (0xFF << 0) + +/* DA7218_PLL_INTEGER = 0x94 */ +#define DA7218_PLL_FBDIV_INTEGER_SHIFT 0 +#define DA7218_PLL_FBDIV_INTEGER_MASK (0x7F << 0) + +/* DA7218_PLL_STATUS = 0x95 */ +#define DA7218_PLL_SRM_STATUS_SHIFT 0 +#define DA7218_PLL_SRM_STATUS_MASK (0xFF << 0) +#define DA7218_PLL_SRM_STATUS_SRM_LOCK (0x1 << 7) + +/* DA7218_PLL_REFOSC_CAL = 0x98 */ +#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT 0 +#define DA7218_PLL_REFOSC_CAL_CTRL_MASK (0x1F << 0) +#define DA7218_PLL_REFOSC_CAL_START_SHIFT 6 +#define DA7218_PLL_REFOSC_CAL_START_MASK (0x1 << 6) +#define DA7218_PLL_REFOSC_CAL_EN_SHIFT 7 +#define DA7218_PLL_REFOSC_CAL_EN_MASK (0x1 << 7) + +/* DA7218_DAC_NG_CTRL = 0x9C */ +#define DA7218_DAC_NG_EN_SHIFT 7 +#define DA7218_DAC_NG_EN_MASK (0x1 << 7) + +/* DA7218_DAC_NG_SETUP_TIME = 0x9D */ +#define DA7218_DAC_NG_SETUP_TIME_SHIFT 0 +#define DA7218_DAC_NG_SETUP_TIME_MASK (0x3 << 0) +#define DA7218_DAC_NG_SETUP_TIME_MAX 4 +#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT 2 +#define DA7218_DAC_NG_RAMPUP_RATE_MASK (0x1 << 2) +#define DA7218_DAC_NG_RAMPUP_RATE_MAX 2 +#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT 3 +#define DA7218_DAC_NG_RAMPDN_RATE_MASK (0x1 << 3) +#define DA7218_DAC_NG_RAMPDN_RATE_MAX 2 + +/* DA7218_DAC_NG_OFF_THRESH = 0x9E */ +#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT 0 +#define DA7218_DAC_NG_OFF_THRESHOLD_MASK (0x7 << 0) +#define DA7218_DAC_NG_THRESHOLD_MAX 0x7 + +/* DA7218_DAC_NG_ON_THRESH = 0x9F */ +#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT 0 +#define DA7218_DAC_NG_ON_THRESHOLD_MASK (0x7 << 0) + +/* DA7218_TONE_GEN_CFG1 = 0xA0 */ +#define DA7218_DTMF_REG_SHIFT 0 +#define DA7218_DTMF_REG_MASK (0xF << 0) +#define DA7218_DTMF_REG_MAX 16 +#define DA7218_DTMF_EN_SHIFT 4 +#define DA7218_DTMF_EN_MASK (0x1 << 4) +#define DA7218_START_STOPN_SHIFT 7 +#define DA7218_START_STOPN_MASK (0x1 << 7) + +/* DA7218_TONE_GEN_CFG2 = 0xA1 */ +#define DA7218_SWG_SEL_SHIFT 0 +#define DA7218_SWG_SEL_MASK (0x3 << 0) +#define DA7218_SWG_SEL_MAX 4 + +/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */ +#define DA7218_FREQ1_L_SHIFT 0 +#define DA7218_FREQ1_L_MASK (0xFF << 0) +#define DA7218_FREQ_MAX 0xFFFF + +/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */ +#define DA7218_FREQ1_U_SHIFT 0 +#define DA7218_FREQ1_U_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */ +#define DA7218_FREQ2_L_SHIFT 0 +#define DA7218_FREQ2_L_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */ +#define DA7218_FREQ2_U_SHIFT 0 +#define DA7218_FREQ2_U_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_CYCLES = 0xA6 */ +#define DA7218_BEEP_CYCLES_SHIFT 0 +#define DA7218_BEEP_CYCLES_MASK (0x7 << 0) + +/* DA7218_TONE_GEN_ON_PER = 0xA7 */ +#define DA7218_BEEP_ON_PER_SHIFT 0 +#define DA7218_BEEP_ON_PER_MASK (0x3F << 0) + +/* DA7218_TONE_GEN_OFF_PER = 0xA8 */ +#define DA7218_BEEP_OFF_PER_SHIFT 0 +#define DA7218_BEEP_OFF_PER_MASK (0x3F << 0) +#define DA7218_BEEP_ON_OFF_MAX 0x3F + +/* DA7218_CP_CTRL = 0xAC */ +#define DA7218_CP_MOD_SHIFT 2 +#define DA7218_CP_MOD_MASK (0x3 << 2) +#define DA7218_CP_MCHANGE_SHIFT 4 +#define DA7218_CP_MCHANGE_MASK (0x3 << 4) +#define DA7218_CP_MCHANGE_REL_MASK 0x3 +#define DA7218_CP_MCHANGE_MAX 3 +#define DA7218_CP_MCHANGE_LARGEST_VOL 0x1 +#define DA7218_CP_MCHANGE_DAC_VOL 0x2 +#define DA7218_CP_MCHANGE_SIG_MAG 0x3 +#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT 6 +#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK (0x1 << 6) +#define DA7218_CP_EN_SHIFT 7 +#define DA7218_CP_EN_MASK (0x1 << 7) + +/* DA7218_CP_DELAY = 0xAD */ +#define DA7218_CP_FCONTROL_SHIFT 0 +#define DA7218_CP_FCONTROL_MASK (0x7 << 0) +#define DA7218_CP_FCONTROL_MAX 6 +#define DA7218_CP_TAU_DELAY_SHIFT 3 +#define DA7218_CP_TAU_DELAY_MASK (0x7 << 3) +#define DA7218_CP_TAU_DELAY_MAX 8 + +/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */ +#define DA7218_CP_THRESH_VDD2_SHIFT 0 +#define DA7218_CP_THRESH_VDD2_MASK (0x3F << 0) +#define DA7218_CP_THRESH_VDD2_MAX 0x3F + +/* DA7218_MIC_1_CTRL = 0xB4 */ +#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIC_1_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIC_1_AMP_EN_SHIFT 7 +#define DA7218_MIC_1_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIC_1_GAIN = 0xB5 */ +#define DA7218_MIC_1_AMP_GAIN_SHIFT 0 +#define DA7218_MIC_1_AMP_GAIN_MASK (0x7 << 0) +#define DA7218_MIC_AMP_GAIN_MAX 0x7 + +/* DA7218_MIC_1_SELECT = 0xB7 */ +#define DA7218_MIC_1_AMP_IN_SEL_SHIFT 0 +#define DA7218_MIC_1_AMP_IN_SEL_MASK (0x3 << 0) + +/* DA7218_MIC_2_CTRL = 0xB8 */ +#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIC_2_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIC_2_AMP_EN_SHIFT 7 +#define DA7218_MIC_2_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIC_2_GAIN = 0xB9 */ +#define DA7218_MIC_2_AMP_GAIN_SHIFT 0 +#define DA7218_MIC_2_AMP_GAIN_MASK (0x7 << 0) + +/* DA7218_MIC_2_SELECT = 0xBB */ +#define DA7218_MIC_2_AMP_IN_SEL_SHIFT 0 +#define DA7218_MIC_2_AMP_IN_SEL_MASK (0x3 << 0) + +/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */ +#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_IN_1_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_IN_VOICE_HPF_CORNER_MAX 8 +#define DA7218_IN_1_VOICE_EN_SHIFT 3 +#define DA7218_IN_1_VOICE_EN_MASK (0x1 << 3) +#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_IN_1_HPF_EN_SHIFT 7 +#define DA7218_IN_1_HPF_EN_MASK (0x1 << 7) + +/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */ +#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_IN_2_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_IN_2_VOICE_EN_SHIFT 3 +#define DA7218_IN_2_VOICE_EN_MASK (0x1 << 3) +#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_IN_2_HPF_EN_SHIFT 7 +#define DA7218_IN_2_HPF_EN_MASK (0x1 << 7) + +/* DA7218_ADC_1_CTRL = 0xC0 */ +#define DA7218_ADC_1_AAF_EN_SHIFT 2 +#define DA7218_ADC_1_AAF_EN_MASK (0x1 << 2) + +/* DA7218_ADC_2_CTRL = 0xC1 */ +#define DA7218_ADC_2_AAF_EN_SHIFT 2 +#define DA7218_ADC_2_AAF_EN_MASK (0x1 << 2) + +/* DA7218_ADC_MODE = 0xC2 */ +#define DA7218_ADC_LP_MODE_SHIFT 0 +#define DA7218_ADC_LP_MODE_MASK (0x1 << 0) +#define DA7218_ADC_LVLDET_MODE_SHIFT 1 +#define DA7218_ADC_LVLDET_MODE_MASK (0x1 << 1) +#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT 2 +#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK (0x1 << 2) + +/* DA7218_MIXOUT_L_CTRL = 0xCC */ +#define DA7218_MIXOUT_L_AMP_EN_SHIFT 7 +#define DA7218_MIXOUT_L_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXOUT_L_GAIN = 0xCD */ +#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT 0 +#define DA7218_MIXOUT_L_AMP_GAIN_MASK (0x3 << 0) +#define DA7218_MIXOUT_AMP_GAIN_MIN 0x1 +#define DA7218_MIXOUT_AMP_GAIN_MAX 0x3 + +/* DA7218_MIXOUT_R_CTRL = 0xCE */ +#define DA7218_MIXOUT_R_AMP_EN_SHIFT 7 +#define DA7218_MIXOUT_R_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXOUT_R_GAIN = 0xCF */ +#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT 0 +#define DA7218_MIXOUT_R_AMP_GAIN_MASK (0x3 << 0) + +/* DA7218_HP_L_CTRL = 0xD0 */ +#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT 2 +#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK (0x1 << 2) +#define DA7218_HP_L_AMP_OE_SHIFT 3 +#define DA7218_HP_L_AMP_OE_MASK (0x1 << 3) +#define DA7218_HP_L_AMP_ZC_EN_SHIFT 4 +#define DA7218_HP_L_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_HP_L_AMP_RAMP_EN_SHIFT 5 +#define DA7218_HP_L_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_HP_L_AMP_MUTE_EN_SHIFT 6 +#define DA7218_HP_L_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_HP_L_AMP_EN_SHIFT 7 +#define DA7218_HP_L_AMP_EN_MASK (0x1 << 7) +#define DA7218_HP_AMP_OE_MASK (0x1 << 3) + +/* DA7218_HP_L_GAIN = 0xD1 */ +#define DA7218_HP_L_AMP_GAIN_SHIFT 0 +#define DA7218_HP_L_AMP_GAIN_MASK (0x3F << 0) +#define DA7218_HP_AMP_GAIN_MIN 0x15 +#define DA7218_HP_AMP_GAIN_MAX 0x3F + +/* DA7218_HP_R_CTRL = 0xD2 */ +#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT 2 +#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK (0x1 << 2) +#define DA7218_HP_R_AMP_OE_SHIFT 3 +#define DA7218_HP_R_AMP_OE_MASK (0x1 << 3) +#define DA7218_HP_R_AMP_ZC_EN_SHIFT 4 +#define DA7218_HP_R_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_HP_R_AMP_RAMP_EN_SHIFT 5 +#define DA7218_HP_R_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_HP_R_AMP_MUTE_EN_SHIFT 6 +#define DA7218_HP_R_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_HP_R_AMP_EN_SHIFT 7 +#define DA7218_HP_R_AMP_EN_MASK (0x1 << 7) + +/* DA7218_HP_R_GAIN = 0xD3 */ +#define DA7218_HP_R_AMP_GAIN_SHIFT 0 +#define DA7218_HP_R_AMP_GAIN_MASK (0x3F << 0) + +/* DA7218_HP_SNGL_CTRL = 0xD4 */ +#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT 0 +#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK (0x1 << 0) +#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT 1 +#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 1) +#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT 2 +#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 2) +#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT 6 +#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK (0x1 << 6) +#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT 7 +#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK (0x1 << 7) + +/* DA7218_HP_DIFF_CTRL = 0xD5 */ +#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT 0 +#define DA7218_HP_AMP_DIFF_MODE_EN_MASK (0x1 << 0) +#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT 4 +#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK (0x1 << 4) + +/* DA7218_HP_DIFF_UNLOCK = 0xD7 */ +#define DA7218_HP_DIFF_UNLOCK_SHIFT 0 +#define DA7218_HP_DIFF_UNLOCK_MASK (0x1 << 0) +#define DA7218_HP_DIFF_UNLOCK_VAL 0xC3 + +/* DA7218_HPLDET_JACK = 0xD8 */ +#define DA7218_HPLDET_JACK_RATE_SHIFT 0 +#define DA7218_HPLDET_JACK_RATE_MASK (0x7 << 0) +#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT 3 +#define DA7218_HPLDET_JACK_DEBOUNCE_MASK (0x3 << 3) +#define DA7218_HPLDET_JACK_THR_SHIFT 5 +#define DA7218_HPLDET_JACK_THR_MASK (0x3 << 5) +#define DA7218_HPLDET_JACK_EN_SHIFT 7 +#define DA7218_HPLDET_JACK_EN_MASK (0x1 << 7) + +/* DA7218_HPLDET_CTRL = 0xD9 */ +#define DA7218_HPLDET_COMP_INV_SHIFT 0 +#define DA7218_HPLDET_COMP_INV_MASK (0x1 << 0) +#define DA7218_HPLDET_HYST_EN_SHIFT 1 +#define DA7218_HPLDET_HYST_EN_MASK (0x1 << 1) +#define DA7218_HPLDET_DISCHARGE_EN_SHIFT 7 +#define DA7218_HPLDET_DISCHARGE_EN_MASK (0x1 << 7) + +/* DA7218_HPLDET_TEST = 0xDA */ +#define DA7218_HPLDET_COMP_STS_SHIFT 4 +#define DA7218_HPLDET_COMP_STS_MASK (0x1 << 4) + +/* DA7218_REFERENCES = 0xDC */ +#define DA7218_BIAS_EN_SHIFT 3 +#define DA7218_BIAS_EN_MASK (0x1 << 3) + +/* DA7218_IO_CTRL = 0xE0 */ +#define DA7218_IO_VOLTAGE_LEVEL_SHIFT 0 +#define DA7218_IO_VOLTAGE_LEVEL_MASK (0x1 << 0) +#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V 0 +#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V 1 + +/* DA7218_LDO_CTRL = 0xE1 */ +#define DA7218_LDO_LEVEL_SELECT_SHIFT 4 +#define DA7218_LDO_LEVEL_SELECT_MASK (0x3 << 4) +#define DA7218_LDO_EN_SHIFT 7 +#define DA7218_LDO_EN_MASK (0x1 << 7) + +/* DA7218_SIDETONE_CTRL = 0xE4 */ +#define DA7218_SIDETONE_MUTE_EN_SHIFT 6 +#define DA7218_SIDETONE_MUTE_EN_MASK (0x1 << 6) +#define DA7218_SIDETONE_FILTER_EN_SHIFT 7 +#define DA7218_SIDETONE_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_SIDETONE_IN_SELECT = 0xE5 */ +#define DA7218_SIDETONE_IN_SELECT_SHIFT 0 +#define DA7218_SIDETONE_IN_SELECT_MASK (0x3 << 0) +#define DA7218_SIDETONE_IN_SELECT_MAX 4 + +/* DA7218_SIDETONE_GAIN = 0xE6 */ +#define DA7218_SIDETONE_GAIN_SHIFT 0 +#define DA7218_SIDETONE_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */ +#define DA7218_OUTFILT_ST_1L_SRC_SHIFT 0 +#define DA7218_OUTFILT_ST_1L_SRC_MASK (0x7 << 0) +#define DA7218_DMIX_ST_SRC_OUTFILT1L 0 +#define DA7218_DMIX_ST_SRC_OUTFILT1R 1 +#define DA7218_DMIX_ST_SRC_SIDETONE 2 + +/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */ +#define DA7218_OUTFILT_ST_1R_SRC_SHIFT 0 +#define DA7218_OUTFILT_ST_1R_SRC_MASK (0x7 << 0) + +/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */ +#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT 0 +#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK (0xFF << 0) + +/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */ +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT 0 +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK (0x1F << 0) +#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE 30 + +/* DA7218_EVENT_STATUS = 0xEC */ +#define DA7218_HPLDET_JACK_STS_SHIFT 7 +#define DA7218_HPLDET_JACK_STS_MASK (0x1 << 7) + +/* DA7218_EVENT = 0xED */ +#define DA7218_LVL_DET_EVENT_SHIFT 0 +#define DA7218_LVL_DET_EVENT_MASK (0x1 << 0) +#define DA7218_HPLDET_JACK_EVENT_SHIFT 7 +#define DA7218_HPLDET_JACK_EVENT_MASK (0x1 << 7) + +/* DA7218_EVENT_MASK = 0xEE */ +#define DA7218_LVL_DET_EVENT_MSK_SHIFT 0 +#define DA7218_LVL_DET_EVENT_MSK_MASK (0x1 << 0) +#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT 7 +#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK (0x1 << 7) + +/* DA7218_DMIC_1_CTRL = 0xF0 */ +#define DA7218_DMIC_1_DATA_SEL_SHIFT 0 +#define DA7218_DMIC_1_DATA_SEL_MASK (0x1 << 0) +#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT 1 +#define DA7218_DMIC_1_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7218_DMIC_1_CLK_RATE_SHIFT 2 +#define DA7218_DMIC_1_CLK_RATE_MASK (0x1 << 2) +#define DA7218_DMIC_1L_EN_SHIFT 6 +#define DA7218_DMIC_1L_EN_MASK (0x1 << 6) +#define DA7218_DMIC_1R_EN_SHIFT 7 +#define DA7218_DMIC_1R_EN_MASK (0x1 << 7) + +/* DA7218_DMIC_2_CTRL = 0xF1 */ +#define DA7218_DMIC_2_DATA_SEL_SHIFT 0 +#define DA7218_DMIC_2_DATA_SEL_MASK (0x1 << 0) +#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT 1 +#define DA7218_DMIC_2_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7218_DMIC_2_CLK_RATE_SHIFT 2 +#define DA7218_DMIC_2_CLK_RATE_MASK (0x1 << 2) +#define DA7218_DMIC_2L_EN_SHIFT 6 +#define DA7218_DMIC_2L_EN_MASK (0x1 << 6) +#define DA7218_DMIC_2R_EN_SHIFT 7 +#define DA7218_DMIC_2R_EN_MASK (0x1 << 7) + +/* DA7218_IN_1L_GAIN = 0xF4 */ +#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_1L_DIGITAL_GAIN_MASK (0x7F << 0) +#define DA7218_IN_DIGITAL_GAIN_MAX 0x7F + +/* DA7218_IN_1R_GAIN = 0xF5 */ +#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_1R_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_IN_2L_GAIN = 0xF6 */ +#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_2L_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_IN_2R_GAIN = 0xF7 */ +#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_2R_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_OUT_1L_GAIN = 0xF8 */ +#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_OUT_1L_DIGITAL_GAIN_MASK (0xFF << 0) +#define DA7218_OUT_DIGITAL_GAIN_MIN 0x0 +#define DA7218_OUT_DIGITAL_GAIN_MAX 0x97 + +/* DA7218_OUT_1R_GAIN = 0xF9 */ +#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_OUT_1R_DIGITAL_GAIN_MASK (0xFF << 0) + +/* DA7218_MICBIAS_CTRL = 0xFC */ +#define DA7218_MICBIAS_1_LEVEL_SHIFT 0 +#define DA7218_MICBIAS_1_LEVEL_MASK (0x7 << 0) +#define DA7218_MICBIAS_1_LP_MODE_SHIFT 3 +#define DA7218_MICBIAS_1_LP_MODE_MASK (0x1 << 3) +#define DA7218_MICBIAS_2_LEVEL_SHIFT 4 +#define DA7218_MICBIAS_2_LEVEL_MASK (0x7 << 4) +#define DA7218_MICBIAS_2_LP_MODE_SHIFT 7 +#define DA7218_MICBIAS_2_LP_MODE_MASK (0x1 << 7) + +/* DA7218_MICBIAS_EN = 0xFD */ +#define DA7218_MICBIAS_1_EN_SHIFT 0 +#define DA7218_MICBIAS_1_EN_MASK (0x1 << 0) +#define DA7218_MICBIAS_2_EN_SHIFT 4 +#define DA7218_MICBIAS_2_EN_MASK (0x1 << 4) + + +/* + * General defines & data + */ + +/* Register inversion */ +#define DA7218_NO_INVERT 0 +#define DA7218_INVERT 1 + +/* Byte related defines */ +#define DA7218_BYTE_SHIFT 8 +#define DA7218_BYTE_MASK 0xFF +#define DA7218_2BYTE_SHIFT 16 +#define DA7218_2BYTE_MASK 0xFFFF + +/* PLL Output Frequencies */ +#define DA7218_PLL_FREQ_OUT_90316 90316800 +#define DA7218_PLL_FREQ_OUT_98304 98304000 + +/* ALC Calibration */ +#define DA7218_ALC_CALIB_DELAY_MIN 2500 +#define DA7218_ALC_CALIB_DELAY_MAX 5000 +#define DA7218_ALC_CALIB_MAX_TRIES 5 + +/* Ref Oscillator */ +#define DA7218_REF_OSC_CHECK_DELAY_MIN 5000 +#define DA7218_REF_OSC_CHECK_DELAY_MAX 10000 +#define DA7218_REF_OSC_CHECK_TRIES 4 + +/* SRM */ +#define DA7218_SRM_CHECK_DELAY 50 +#define DA7218_SRM_CHECK_TRIES 8 + +/* Mic Level Detect */ +#define DA7218_MIC_LVL_DET_DELAY 50 + +enum da7218_biq_cfg { + DA7218_BIQ_CFG_DATA = 0, + DA7218_BIQ_CFG_ADDR, + DA7218_BIQ_CFG_SIZE, +}; + +enum da7218_clk_src { + DA7218_CLKSRC_MCLK = 0, + DA7218_CLKSRC_MCLK_SQR, +}; + +enum da7218_sys_clk { + DA7218_SYSCLK_MCLK = 0, + DA7218_SYSCLK_PLL, + DA7218_SYSCLK_PLL_SRM, + DA7218_SYSCLK_PLL_32KHZ +}; + +enum da7218_dev_id { + DA7217_DEV_ID = 0, + DA7218_DEV_ID, +}; + +/* Regulators */ +enum da7218_supplies { + DA7218_SUPPLY_VDD = 0, + DA7218_SUPPLY_VDDMIC, + DA7218_SUPPLY_VDDIO, + DA7218_NUM_SUPPLIES, +}; + +/* Private data */ +struct da7218_priv { + struct da7218_pdata *pdata; + + struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES]; + struct regmap *regmap; + int dev_id; + + struct snd_soc_jack *jack; + int irq; + + struct clk *mclk; + unsigned int mclk_rate; + + bool hp_single_supply; + bool master; + u8 alc_en; + u8 in_filt_en; + u8 mic_lvl_det_en; + + u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE]; + u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE]; +}; + +/* HP detect control */ +int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack); + +#endif /* _DA7218_H */ -- cgit v1.2.3 From 9761c0f65d3a4c7ae8ceec86ac9d8d2c64197d57 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 30 Nov 2015 14:10:21 +0800 Subject: ASoC: rt5645: merge DMI tables of google projects There are more and more google projects need to use DMI to get the platform data configuration. And those projects use the same configuration. To clean those redundant code, we define a general DMI for those projects with the same platform data configuration. Signed-off-by: Oder Chiou Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 79 +++++++++++------------------------------------ 1 file changed, 18 insertions(+), 61 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 7b140ccf9d2e..3e8d66661b7e 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3514,69 +3514,23 @@ static struct acpi_device_id rt5645_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); #endif -static struct rt5645_platform_data *rt5645_pdata; - -static struct rt5645_platform_data strago_platform_data = { +static struct rt5645_platform_data general_platform_data = { .dmic1_data_pin = RT5645_DMIC1_DISABLE, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, }; -static int strago_quirk_cb(const struct dmi_system_id *id) -{ - rt5645_pdata = &strago_platform_data; - - return 1; -} - static const struct dmi_system_id dmi_platform_intel_braswell[] = { { .ident = "Intel Strago", - .callback = strago_quirk_cb, .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), }, }, { - .ident = "Google Celes", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), - }, - }, - { - .ident = "Google Ultima", - .callback = strago_quirk_cb, + .ident = "Google Chrome", .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"), - }, - }, - { - .ident = "Google Reks", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Reks"), - }, - }, - { - .ident = "Google Edgar", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"), - }, - }, - { - .ident = "Google Wizpig", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"), - }, - }, - { - .ident = "Google Terra", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Terra"), + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), }, }, { } @@ -3589,17 +3543,9 @@ static struct rt5645_platform_data buddy_platform_data = { .jd_invert = true, }; -static int buddy_quirk_cb(const struct dmi_system_id *id) -{ - rt5645_pdata = &buddy_platform_data; - - return 1; -} - static struct dmi_system_id dmi_platform_intel_broadwell[] = { { .ident = "Chrome Buddy", - .callback = buddy_quirk_cb, .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"), }, @@ -3607,6 +3553,16 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = { { } }; +static bool rt5645_check_dp(struct device *dev) +{ + if (device_property_present(dev, "realtek,in2-differential") || + device_property_present(dev, "realtek,dmic1-data-pin") || + device_property_present(dev, "realtek,dmic2-data-pin") || + device_property_present(dev, "realtek,jd-mode")) + return true; + + return false; +} static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) { @@ -3641,11 +3597,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (pdata) rt5645->pdata = *pdata; - else if (dmi_check_system(dmi_platform_intel_braswell) || - dmi_check_system(dmi_platform_intel_broadwell)) - rt5645->pdata = *rt5645_pdata; - else + else if (dmi_check_system(dmi_platform_intel_broadwell)) + rt5645->pdata = buddy_platform_data; + else if (rt5645_check_dp(&i2c->dev)) rt5645_parse_dt(rt5645, &i2c->dev); + else if (dmi_check_system(dmi_platform_intel_braswell)) + rt5645->pdata = general_platform_data; rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", GPIOD_IN); -- cgit v1.2.3 From 1fb34b48361eac63850513a045ed2eb9a7fd6168 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 30 Nov 2015 16:37:47 +0100 Subject: ASoC: sun4i: Implement MIC1 capture One of the input path used in the Allwinner codec is the MIC1. Add support for it. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 228 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 197 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index bcbf4da168b6..30c9e9260491 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -69,6 +69,7 @@ /* Codec ADC register offsets and bit fields */ #define SUN4I_CODEC_ADC_FIFOC (0x1c) +#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24) #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8) @@ -102,6 +103,7 @@ struct sun4i_codec { struct clk *clk_apb; struct clk *clk_module; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -136,26 +138,54 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) 0); } +static void sun4i_codec_start_capture(struct sun4i_codec *scodec) +{ + /* + * FIXME: according to the BSP, we might need to drive a PA + * GPIO high here on some boards + */ + + /* Enable ADC DRQ */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); +} + +static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) +{ + /* + * FIXME: according to the BSP, we might need to drive a PA + * GPIO low here on some boards + */ + + /* Disable ADC DRQ */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); +} + static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - sun4i_codec_start_playback(scodec); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sun4i_codec_start_playback(scodec); + else + sun4i_codec_start_capture(scodec); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - sun4i_codec_stop_playback(scodec); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sun4i_codec_stop_playback(scodec); + else + sun4i_codec_stop_capture(scodec); break; default: @@ -165,15 +195,54 @@ static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int sun4i_codec_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - u32 val; - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; + + /* Flush RX FIFO */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); + + + /* Set RX FIFO trigger level */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, + 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); + + /* + * FIXME: Undocumented in the datasheet, but + * Allwinner's code mentions that it is related + * related to microphone gain + */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, + 0x3 << 25, + 0x1 << 25); + + if (of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun7i-a20-codec")) + /* FIXME: Undocumented bits */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE, + 0x3 << 8, + 0x1 << 8); + + /* Fill most significant bits with valid data MSB */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); + + return 0; +} + +static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); + u32 val; /* Flush the TX FIFO */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, @@ -202,6 +271,15 @@ static int sun4i_codec_prepare(struct snd_pcm_substream *substream, 0); return 0; +}; + +static int sun4i_codec_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return sun4i_codec_prepare_playback(substream, dai); + + return sun4i_codec_prepare_capture(substream, dai); } static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params) @@ -276,30 +354,34 @@ static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params) } } -static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, + struct snd_pcm_hw_params *params, + unsigned int hwrate) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - unsigned long clk_freq; - int ret, hwrate; u32 val; - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; + /* Set ADC sample rate */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, + hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); - clk_freq = sun4i_codec_get_mod_freq(params); - if (!clk_freq) - return -EINVAL; + /* Set the number of channels we want to use */ + if (params_channels(params) == 1) + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); + else + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); - ret = clk_set_rate(scodec->clk_module, clk_freq); - if (ret) - return ret; + return 0; +} - hwrate = sun4i_codec_get_hw_rate(params); - if (hwrate < 0) - return hwrate; +static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, + struct snd_pcm_hw_params *params, + unsigned int hwrate) +{ + u32 val; /* Set DAC sample rate */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, @@ -344,6 +426,34 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, return 0; } +static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); + unsigned long clk_freq; + int hwrate; + + clk_freq = sun4i_codec_get_mod_freq(params); + if (!clk_freq) + return -EINVAL; + + if (clk_set_rate(scodec->clk_module, clk_freq)) + return -EINVAL; + + hwrate = sun4i_codec_get_hw_rate(params); + if (hwrate < 0) + return hwrate; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return sun4i_codec_hw_params_playback(scodec, params, + hwrate); + + return sun4i_codec_hw_params_capture(scodec, params, + hwrate); +} + static int sun4i_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -394,6 +504,20 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { SNDRV_PCM_FMTBIT_S32_LE, .sig_bits = 24, }, + .capture = { + .stream_name = "Codec Capture", + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000 | + SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 24, + }, }; /*** Codec ***/ @@ -429,11 +553,22 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { }; static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC, + SUN4I_CODEC_ADC_FIFOC_EN_AD, 0, + NULL, 0), + /* Digital parts of the DACs */ SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC, SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + /* Analog parts of the ADCs */ + SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0), + SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0), + /* Analog parts of the DACs */ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_DACAENL, 0), @@ -452,6 +587,14 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0), + /* VMIC */ + SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0), + + /* Mic Pre-Amplifiers */ + SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0), + /* Pre-Amplifier */ SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, SUN4I_CODEC_ADC_ACTL_PA_EN, 0, @@ -460,15 +603,19 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("Mic1"), + SND_SOC_DAPM_OUTPUT("HP Right"), SND_SOC_DAPM_OUTPUT("HP Left"), }; static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { - /* Left DAC Routes */ + /* Left ADC / DAC Routes */ + { "Left ADC", NULL, "ADC" }, { "Left DAC", NULL, "DAC" }, - /* Right DAC Routes */ + /* Right ADC / DAC Routes */ + { "Right ADC", NULL, "ADC" }, { "Right DAC", NULL, "DAC" }, /* Right Mixer Routes */ @@ -490,6 +637,12 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { { "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" }, { "HP Right", NULL, "Pre-Amplifier Mute" }, { "HP Left", NULL, "Pre-Amplifier Mute" }, + + /* Mic1 Routes */ + { "Left ADC", NULL, "MIC1 Pre-Amplifier" }, + { "Right ADC", NULL, "MIC1 Pre-Amplifier" }, + { "MIC1 Pre-Amplifier", NULL, "Mic1"}, + { "Mic1", NULL, "VMIC" }, }; static struct snd_soc_codec_driver sun4i_codec_codec = { @@ -515,7 +668,7 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data, - NULL); + &scodec->capture_dma_data); return 0; } @@ -531,6 +684,14 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SUN4I_CODEC_RATES, + .formats = SUN4I_CODEC_FORMATS, + .sig_bits = 24, + }, }; static const struct regmap_config sun4i_codec_regmap_config = { @@ -638,6 +799,11 @@ static int sun4i_codec_probe(struct platform_device *pdev) scodec->playback_dma_data.maxburst = 4; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + /* DMA configuration for RX FIFO */ + scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; + scodec->capture_dma_data.maxburst = 4; + scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, &sun4i_codec_dai, 1); if (ret) { -- cgit v1.2.3 From 94458364304161551906d276f0164efd3dc30576 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:49:15 +0000 Subject: ASoC: rsnd: don't use normal *mod in adg.c adg.c is used from ssi/src/cmd. Thus don't use confusable *mod here. This patch rename it to ssi_mod/src_mod/cmd_mod Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 448f082ab56d..6d3ef366d536 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div) static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) { - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - int id = rsnd_mod_id(mod); + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + int id = rsnd_mod_id(ssi_mod); int ws = id; if (rsnd_ssi_is_pin_sharing(io)) { @@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) return (0x6 + ws) << 8; } -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int id = rsnd_mod_id(mod); + int id = rsnd_mod_id(cmd_mod); int shift = (id % 2) ? 16 : 0; u32 mask, val; @@ -275,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) } } -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) { - /* - * "mod" = "ssi" here. - * we can get "ssi id" from mod - */ - rsnd_adg_set_ssi_clk(mod, 0); + rsnd_adg_set_ssi_clk(ssi_mod, 0); return 0; } -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; @@ -332,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) found_clock: - /* - * This "mod" = "ssi" here. - * we can get "ssi id" from mod - */ - rsnd_adg_set_ssi_clk(mod, data); + rsnd_adg_set_ssi_clk(ssi_mod, data); dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); return 0; -- cgit v1.2.3 From c45f7263a805e1c5d8579569884d32141330589f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:49:33 +0000 Subject: ASoC: rsnd: add missing ADINR::CHNUM on DVC/SRC/SSIU DVC/SRC/SSIU needs ADINR::CHNUM settings too. This patch adds these missing value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 6 +++++- sound/soc/sh/rcar/src.c | 3 ++- sound/soc/sh/rcar/ssiu.c | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 0f61e1344431..c622dec24362 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -97,11 +97,15 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 adinr = 0; u32 dvucr = 0; u32 vrctr = 0; u32 vrpdr = 0; u32 vrdbr = 0; + adinr = rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io); + /* Enable Digital Volume, Zero Cross Mute Mode */ dvucr |= 0x101; @@ -124,7 +128,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, rsnd_mod_write(mod, DVC_DVUIR, 1); /* General Information */ - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); + rsnd_mod_write(mod, DVC_ADINR, adinr); rsnd_mod_write(mod, DVC_DVUCR, dvucr); /* Volume Ramp Parameter */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 6d93c4ed8275..30cad79deab0 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -199,7 +199,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_ADINR */ - adinr = rsnd_get_adinr_bit(mod, io); + adinr = rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io); /* * SRC_IFSCR / SRC_IFSVR diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index bc245047e904..6120b0a66958 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -82,7 +82,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, u32 val = rsnd_get_dalign(mod, io); rsnd_mod_write(mod, SSI_BUSIF_ADINR, - rsnd_get_adinr_bit(mod, io)); + rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io)); rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); } -- cgit v1.2.3 From bf4e8d7c371ae0d7acc1872a153c2f980f5523fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:50:08 +0000 Subject: ASoC: rsnd: add missing SRC_O_BUSIF_MODE register SRC_BUSIF_MODE has both IN/OUT register. Current src driver sets IN register only. This patch sets missing OUT register. IN/OUT register are using default setting, so, there is no HW effect. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 4 +++- sound/soc/sh/rcar/rsnd.h | 3 ++- sound/soc/sh/rcar/src.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 15d770662482..364708c73418 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -233,8 +233,10 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; + const static struct rsnd_regmap_field_conf conf_scu[] = { - RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), + RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), + RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 42d2ac5cb0d1..bb2c29cdc892 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -51,7 +51,8 @@ enum rsnd_reg { RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ - RSND_REG_SRC_BUSIF_MODE, + RSND_REG_SRC_I_BUSIF_MODE, + RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, RSND_REG_SRC_SWRSR, RSND_REG_SRC_SRCIR, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 30cad79deab0..27b3ffe8c9a0 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -254,7 +254,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); - rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); + rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1); + rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); if (convert_rate) -- cgit v1.2.3 From 98efeeaeeb5f2a66603ba7c9cb9b4f7a02dd3c01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:50:32 +0000 Subject: ASoC: rsnd: src: rename rsnd_src_soft_reset() to rsnd_src_activation() Based on datasheet naming Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 27b3ffe8c9a0..5239c3d7a3d0 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -70,7 +70,7 @@ struct rsnd_src { * |-----------------| */ -static void rsnd_src_soft_reset(struct rsnd_mod *mod) +static void rsnd_src_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, SRC_SWRSR, 0); rsnd_mod_write(mod, SRC_SWRSR, 1); @@ -378,7 +378,7 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_mod_power_on(mod); - rsnd_src_soft_reset(mod); + rsnd_src_activation(mod); rsnd_src_set_convert_rate(io, mod); -- cgit v1.2.3 From 4fe32521d706e3541095ef173669e46666df2865 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:50:51 +0000 Subject: ASoC: rsnd: mix: rename rsnd_mix_soft_reset() to rsnd_mix_activation() Based on datasheet naming Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/mix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 57ac453adcef..b2f22bd7e3a9 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -24,7 +24,7 @@ struct rsnd_mix { ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ i++) -static void rsnd_mix_soft_reset(struct rsnd_mod *mod) +static void rsnd_mix_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, MIX_SWRSR, 0); rsnd_mod_write(mod, MIX_SWRSR, 1); @@ -83,7 +83,7 @@ static int rsnd_mix_init(struct rsnd_mod *mod, { rsnd_mod_power_on(mod); - rsnd_mix_soft_reset(mod); + rsnd_mix_activation(mod); rsnd_mix_volume_init(io, mod); -- cgit v1.2.3 From 87a6c5a815f5da390ea74187344342df03205358 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:51:15 +0000 Subject: ASoC: rsnd: dvc: rename rsnd_dvc_soft_reset() to rsnd_dvc_activation() Based on datasheet naming Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index c622dec24362..b69a6e5cafef 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -64,7 +64,7 @@ static const char * const dvc_ramp_rate[] = { "0.125 dB/8192 steps", /* 10111 */ }; -static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) +static void rsnd_dvc_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, DVC_SWRSR, 0); rsnd_mod_write(mod, DVC_SWRSR, 1); @@ -206,7 +206,7 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, { rsnd_mod_power_on(mod); - rsnd_dvc_soft_reset(mod); + rsnd_dvc_activation(mod); rsnd_dvc_volume_init(io, mod); -- cgit v1.2.3 From 475a361a6f2c7c690fd59a8f5224615e781cc3bd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:51:35 +0000 Subject: ASoC: rsnd: src: add rsnd_src_halt() Based on datasheet process Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 5239c3d7a3d0..b438538a0a69 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -76,6 +76,12 @@ static void rsnd_src_activation(struct rsnd_mod *mod) rsnd_mod_write(mod, SRC_SWRSR, 1); } +static void rsnd_src_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SRCIR, 1); + rsnd_mod_write(mod, SRC_SWRSR, 0); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -406,6 +412,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod, /* stop both out/in */ rsnd_mod_write(mod, SRC_CTRL, 0); + rsnd_src_halt(mod); + rsnd_mod_power_off(mod); if (src->err) -- cgit v1.2.3 From 95e6b0ddb002e0dc89fef99b31685197da2eca9e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:51:52 +0000 Subject: ASoC: rsnd: mix: add rsnd_mix_halt() Based on datasheet process Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/mix.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index b2f22bd7e3a9..b34957ab75b9 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -30,6 +30,12 @@ static void rsnd_mix_activation(struct rsnd_mod *mod) rsnd_mod_write(mod, MIX_SWRSR, 1); } +static void rsnd_mix_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_MIXIR, 1); + rsnd_mod_write(mod, MIX_SWRSR, 0); +} + static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -96,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_mix_halt(mod); + rsnd_mod_power_off(mod); return 0; -- cgit v1.2.3 From f13edb8b281cf7fa762b14323238d6884df38792 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:52:21 +0000 Subject: ASoC: rsnd: dvc: add rsnd_dvc_halt() Based on datasheet process Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index b69a6e5cafef..91c86ee1fecb 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -70,6 +70,12 @@ static void rsnd_dvc_activation(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_SWRSR, 1); } +static void rsnd_dvc_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, DVC_DVUIR, 1); + rsnd_mod_write(mod, DVC_SWRSR, 0); +} + #define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) #define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) @@ -219,6 +225,8 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_dvc_halt(mod); + rsnd_mod_power_off(mod); return 0; -- cgit v1.2.3 From 840ada3b04275d47a24f35a8c559bc584962f315 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:52:38 +0000 Subject: ASoC: rsnd: add rsnd_ssi_config_init() In order to enhance code readability, this patch adds rsnd_ssi_config_init() and moves SSICR register settings to it. This is prepare patch for TDM support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 98 ++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 40d5b587cbe9..31e26bd481cf 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -253,6 +253,55 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, rsnd_adg_ssi_clk_stop(mod); } +static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 cr_own; + u32 cr_mode; + + /* + * always use 32bit system word. + * see also rsnd_ssi_master_clk_enable() + */ + cr_own = FORCE | SWL_32 | PDTA; + + if (rdai->bit_clk_inv) + cr_own |= SCKP; + if (rdai->frm_clk_inv) + cr_own |= SWSP; + if (rdai->data_alignment) + cr_own |= SDTA; + if (rdai->sys_delay) + cr_own |= DEL; + if (rsnd_io_is_play(io)) + cr_own |= TRMD; + + switch (runtime->sample_bits) { + case 16: + cr_own |= DWL_16; + break; + case 32: + cr_own |= DWL_24; + break; + default: + return -EINVAL; + } + + if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) { + cr_mode = UIEN | OIEN | /* over/under run */ + DMEN; /* DMA : enable DMA */ + } else { + cr_mode = DIEN; /* PIO : enable Data interrupt */ + } + + ssi->cr_own = cr_own; + ssi->cr_mode = cr_mode; + + return 0; +} + /* * SSI mod common functions */ @@ -261,9 +310,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 cr; int ret; ssi->usrcnt++; @@ -277,49 +323,9 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (rsnd_ssi_is_parent(mod, io)) return 0; - cr = FORCE | PDTA; - - /* - * always use 32bit system word for easy clock calculation. - * see also rsnd_ssi_master_clk_enable() - */ - cr |= SWL_32; - - /* - * init clock settings for SSICR - */ - switch (runtime->sample_bits) { - case 16: - cr |= DWL_16; - break; - case 32: - cr |= DWL_24; - break; - default: - return -EIO; - } - - if (rdai->bit_clk_inv) - cr |= SCKP; - if (rdai->frm_clk_inv) - cr |= SWSP; - if (rdai->data_alignment) - cr |= SDTA; - if (rdai->sys_delay) - cr |= DEL; - if (rsnd_io_is_play(io)) - cr |= TRMD; - - ssi->cr_own = cr; - - if (rsnd_ssi_is_dma_mode(mod)) { - cr = UIEN | OIEN | /* over/under run */ - DMEN; /* DMA : enable DMA */ - } else { - cr = DIEN; /* PIO : enable Data interrupt */ - } - - ssi->cr_mode = cr; + ret = rsnd_ssi_config_init(ssi, io); + if (ret < 0) + return ret; ssi->err = -1; /* ignore 1st error */ -- cgit v1.2.3 From 08bada26fe8089f908484a3a4580f38e78502ac7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:53:04 +0000 Subject: ASoC: rsnd: set SSIWSR setting on rsnd_ssi_config_init() It will have TDM settings on SSIWSR. Actually, we would like to set it on rsnd_ssi_config_init(), but we can't. Because SSI might be used as clock master (It doesn't need to call rsnd_ssi_config_init() when clock master mode). This patch adds new ssi->wsr and set it on rsnd_ssi_start(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 31e26bd481cf..d97f365f1b41 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -69,6 +69,7 @@ struct rsnd_ssi { u32 cr_own; u32 cr_clk; u32 cr_mode; + u32 wsr; int chan; int rate; int err; @@ -214,11 +215,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, if (0 == ret) { ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(j); + ssi->wsr = CONT; ssi->rate = rate; - rsnd_mod_write(mod, SSIWSR, CONT); - dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), rsnd_mod_id(mod), rate); @@ -421,6 +421,7 @@ static int __rsnd_ssi_start(struct rsnd_mod *mod, EN; rsnd_mod_write(mod, SSICR, cr); + rsnd_mod_write(mod, SSIWSR, ssi->wsr); return 0; } -- cgit v1.2.3 From 8ec85e7f7e9a2f9c36a92596db53c30b1ca45f17 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:53:27 +0000 Subject: ASoC: rsnd: ssi enables non-stereo sound Current SSI is assuming that the sound is always stereo. But, SSI needs to calculate its frequency when master mode. Then This frequency depends on each SSI's slots, and TDM mode (= TDM Extend Mode, TDM split Mode, TDM Multichannel Mode). This patch enables to use non-stereo sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 29 +++++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 6 ++++++ sound/soc/sh/rcar/ssi.c | 5 +++-- 3 files changed, 38 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 81a6bdb6848c..f990b4cb7192 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -191,6 +191,34 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return !!io->substream; } +int rsnd_get_slot_rdai(struct rsnd_dai *rdai) +{ + return rdai->slots; +} + +int rsnd_get_slot_runtime(struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int chan = rsnd_get_slot_rdai(rdai); + + if (runtime->channels < chan) + chan = runtime->channels; + + return chan; +} + +int rsnd_get_slot_extend(struct rsnd_dai_stream *io) +{ + int chan = rsnd_get_slot_runtime(io); + + /* TDM Extend Mode needs 8ch */ + if (chan == 6) + chan = 8; + + return chan; +} + /* * ADINR function */ @@ -611,6 +639,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) rdai->playback.rdai = rdai; rdai->capture.rdai = rdai; + rdai->slots = 2; /* default */ #define mod_parse(name) \ node = rsnd_##name##_of_node(priv); \ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index bb2c29cdc892..38fd212ffe5a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -285,6 +285,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); +int rsnd_get_slot_rdai(struct rsnd_dai *rdai); +int rsnd_get_slot_runtime(struct rsnd_dai_stream *io); +int rsnd_get_slot_extend(struct rsnd_dai_stream *io); + /* * R-Car sound DAI */ @@ -321,6 +325,8 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; + int slots; + unsigned int clk_master:1; unsigned int bit_clk_inv:1; unsigned int frm_clk_inv:1; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d97f365f1b41..44e914132b02 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -177,6 +177,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + int slots = rsnd_get_slot_extend(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -206,10 +207,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, /* * this driver is assuming that - * system word is 64fs (= 2 x 32bit) + * system word is 32bit x slots * see rsnd_ssi_init() */ - main_rate = rate * 32 * 2 * ssi_clk_mul_table[j]; + main_rate = rate * 32 * slots * ssi_clk_mul_table[j]; ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); if (0 == ret) { -- cgit v1.2.3 From 42ab9a791bd1fb6ad5a47ad66727dcd66093b1ae Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:53:44 +0000 Subject: ASoC: rsnd: dvc enables non-stereo sound Current DVC is assuming that the sound is always stereo. This patch makes it more flexible Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 +++++- sound/soc/sh/rcar/dvc.c | 14 ++++++++++++-- sound/soc/sh/rcar/gen.c | 6 ++++++ sound/soc/sh/rcar/rsnd.h | 9 ++++++++- 4 files changed, 31 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f990b4cb7192..7d364d7505a1 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -871,10 +871,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg_m *_cfg, + int ch_size, u32 max) { + if (ch_size > RSND_DVC_CHANNELS) + return -EINVAL; + _cfg->cfg.max = max; - _cfg->cfg.size = RSND_DVC_CHANNELS; + _cfg->cfg.size = ch_size; _cfg->cfg.val = _cfg->val; return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); } diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 91c86ee1fecb..66aeea8e0069 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -97,6 +97,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, /* Enable Digital Volume */ rsnd_mod_write(mod, DVC_VOL0R, val[0]); rsnd_mod_write(mod, DVC_VOL1R, val[1]); + rsnd_mod_write(mod, DVC_VOL2R, val[2]); + rsnd_mod_write(mod, DVC_VOL3R, val[3]); + rsnd_mod_write(mod, DVC_VOL4R, val[4]); + rsnd_mod_write(mod, DVC_VOL5R, val[5]); + rsnd_mod_write(mod, DVC_VOL6R, val[6]); + rsnd_mod_write(mod, DVC_VOL7R, val[7]); } static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, @@ -236,8 +242,10 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); int is_play = rsnd_io_is_play(io); + int slots = rsnd_get_slot_rdai(rdai); int ret; /* Volume */ @@ -245,7 +253,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, is_play ? "DVC Out Playback Volume" : "DVC In Capture Volume", rsnd_dvc_volume_update, - &dvc->volume, 0x00800000 - 1); + &dvc->volume, slots, + 0x00800000 - 1); if (ret < 0) return ret; @@ -254,7 +263,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, is_play ? "DVC Out Mute Switch" : "DVC In Mute Switch", rsnd_dvc_volume_update, - &dvc->mute, 1); + &dvc->mute, slots, + 1); if (ret < 0) return ret; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 364708c73418..2151aa5e161b 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -277,6 +277,12 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), + RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), + RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), + RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), + RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), + RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), + RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), }; const static struct rsnd_regmap_field_conf conf_adg[] = { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 38fd212ffe5a..2111bf32e789 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -101,6 +101,12 @@ enum rsnd_reg { RSND_REG_DVC_ZCMCR, RSND_REG_DVC_VOL0R, RSND_REG_DVC_VOL1R, + RSND_REG_DVC_VOL2R, + RSND_REG_DVC_VOL3R, + RSND_REG_DVC_VOL4R, + RSND_REG_DVC_VOL5R, + RSND_REG_DVC_VOL6R, + RSND_REG_DVC_VOL7R, RSND_REG_DVC_DVUER, RSND_REG_DVC_VRCTR, /* Gen2 only */ RSND_REG_DVC_VRPDR, /* Gen2 only */ @@ -476,7 +482,7 @@ struct rsnd_kctrl_cfg { struct snd_kcontrol *kctrl; }; -#define RSND_DVC_CHANNELS 2 +#define RSND_DVC_CHANNELS 8 struct rsnd_kctrl_cfg_m { struct rsnd_kctrl_cfg cfg; u32 val[RSND_DVC_CHANNELS]; @@ -497,6 +503,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg_m *_cfg, + int ch_size, u32 max); int rsnd_kctrl_new_s(struct rsnd_mod *mod, struct rsnd_dai_stream *io, -- cgit v1.2.3 From 186fadc132f0d634c7b43202a240fbd3654b6623 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2015 08:54:03 +0000 Subject: ASoC: rsnd: add TDM Extend Mode support Renesas R-Car can out TDM by 1) 6ch x 1 DAI as TDM Extend Mode 2) 2ch x 4 x 1 DAI as TDM split Mode 3) 2ch x 3 DAI or 2ch x 4 DAI as TDM Multichannel Mode This patch adds 1) TDM Extend Mode. Because of HW design, this 6ch data will be outputed via 8ch data width. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 30 ++++++++++++++++++++++++++---- sound/soc/sh/rcar/gen.c | 1 + sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 18 +++++++++++++++++- sound/soc/sh/rcar/ssiu.c | 9 +++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7d364d7505a1..b187a8927e29 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -247,9 +247,9 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - u32 chan = runtime->channels; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + u32 chan = rsnd_get_slot_rdai(rdai); switch (chan) { case 1: @@ -569,9 +569,31 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, + u32 tx_mask, u32 rx_mask, + int slots, int slot_width) +{ + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct device *dev = rsnd_priv_to_dev(priv); + + switch (slots) { + case 6: + /* TDM Extend Mode */ + rdai->slots = slots; + break; + default: + dev_err(dev, "unsupported TDM slots (%d)\n", slots); + return -EINVAL; + } + + return 0; +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, }; static int rsnd_dai_probe(struct rsnd_priv *priv) @@ -626,7 +648,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) drv->playback.rates = RSND_RATES; drv->playback.formats = RSND_FMTS; drv->playback.channels_min = 2; - drv->playback.channels_max = 2; + drv->playback.channels_max = 6; drv->playback.stream_name = rdai->playback.name; snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, @@ -634,7 +656,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) drv->capture.rates = RSND_RATES; drv->capture.formats = RSND_FMTS; drv->capture.channels_min = 2; - drv->capture.channels_max = 2; + drv->capture.channels_max = 6; drv->capture.stream_name = rdai->capture.name; rdai->playback.rdai = rdai; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 2151aa5e161b..50fc73042b7e 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -230,6 +230,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), + RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 2111bf32e789..970e1301f7c6 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -44,6 +44,7 @@ */ enum rsnd_reg { /* SCU (SRC/SSIU/MIX/CTU/DVC) */ + RSND_REG_SSI_MODE, /* Gen2 only */ RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, RSND_REG_SSI_CTRL, /* Gen2 only */ diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 44e914132b02..628739f13f99 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -24,7 +24,9 @@ #define OIEN (1 << 26) /* Overflow Interrupt Enable */ #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ #define DIEN (1 << 24) /* Data Interrupt Enable */ - +#define CHNL_4 (1 << 22) /* Channels */ +#define CHNL_6 (2 << 22) /* Channels */ +#define CHNL_8 (3 << 22) /* Channels */ #define DWL_8 (0 << 19) /* Data Word Length */ #define DWL_16 (1 << 19) /* Data Word Length */ #define DWL_18 (2 << 19) /* Data Word Length */ @@ -57,6 +59,7 @@ * SSIWSR */ #define CONT (1 << 8) /* WS Continue Function */ +#define WS_MODE (1 << 0) /* WS Mode */ #define SSI_NAME "ssi" @@ -261,6 +264,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 cr_own; u32 cr_mode; + u32 wsr; /* * always use 32bit system word. @@ -297,8 +301,20 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, cr_mode = DIEN; /* PIO : enable Data interrupt */ } + /* + * TDM Extend Mode + * see + * rsnd_ssiu_init_gen2() + */ + wsr = ssi->wsr; + if (rsnd_get_slot_runtime(io) >= 6) { + wsr |= WS_MODE; + cr_own |= CHNL_8; + } + ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; + ssi->wsr = wsr; return 0; } diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 6120b0a66958..326550114299 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -78,6 +78,15 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; + if (rsnd_get_slot_runtime(io) >= 6) { + /* + * TDM Extend Mode + * see + * rsnd_ssi_config_init() + */ + rsnd_mod_write(mod, SSI_MODE, 0x1); + } + if (rsnd_ssi_use_busif(io)) { u32 val = rsnd_get_dalign(mod, io); -- cgit v1.2.3 From 2ff2ecca06d5302782c73626b841a509a9b01ef6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Dec 2015 08:31:38 +0000 Subject: ASoC: rsnd: fixup wrong snd_soc_dai_driver pointer access drv pointer should be "base + offset" instead of "current + offset". This patch fixup this issue, otherwise third and subsequent pointer will be broken Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index b187a8927e29..f1d7af114a31 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -603,7 +603,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) struct device_node *playback, *capture; struct rsnd_dai_stream *io_playback; struct rsnd_dai_stream *io_capture; - struct snd_soc_dai_driver *drv; + struct snd_soc_dai_driver *rdrv, *drv; struct rsnd_dai *rdai; struct device *dev = rsnd_priv_to_dev(priv); int nr, dai_i, io_i, np_i; @@ -616,15 +616,15 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) goto rsnd_dai_probe_done; } - drv = devm_kzalloc(dev, sizeof(*drv) * nr, GFP_KERNEL); + rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); - if (!drv || !rdai) { + if (!rdrv || !rdai) { ret = -ENOMEM; goto rsnd_dai_probe_done; } priv->rdai_nr = nr; - priv->daidrv = drv; + priv->daidrv = rdrv; priv->rdai = rdai; /* @@ -633,7 +633,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) dai_i = 0; for_each_child_of_node(dai_node, dai_np) { rdai = rsnd_rdai_get(priv, dai_i); - drv = drv + dai_i; + drv = rdrv + dai_i; io_playback = &rdai->playback; io_capture = &rdai->capture; -- cgit v1.2.3 From 575f1f929f5a2ed80130c294aa7b2dc40dba74f2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Dec 2015 08:33:23 +0000 Subject: ASoC: rsnd: rsrc-card: check return value of snd_soc_of_get_dai_name() This patch adds missing check of snd_soc_of_get_dai_name(). It might not be able to use sound card, because it might returns -EPROBE_DEFER. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsrc-card.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index d61db9c385ea..a3ec13f6271e 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -208,7 +208,9 @@ static int rsrc_card_parse_links(struct device_node *np, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; dai_link->cpu_of_node = args.np; - snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + if (ret < 0) + return ret; /* set dai_name */ snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", @@ -240,7 +242,9 @@ static int rsrc_card_parse_links(struct device_node *np, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; dai_link->codec_of_node = args.np; - snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); + ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); + if (ret < 0) + return ret; /* additional name prefix */ if (of_data) { -- cgit v1.2.3 From 800f297e8ef91901b93c280425863684dff2d9c6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 30 Nov 2015 17:37:28 +0000 Subject: ASoC: arizona: Add 32uS delay after putting FLL into freerun When switching between two clock sources using the FLL freerun to smooth the transition we should wait 32uS after putting the FLL into freerun before we proceed. In practice we appear to be getting enough delay from the surrounding code, but better to make it explicit. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e76ecc7cc775..a23f7d15324a 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2212,9 +2212,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) /* Facilitate smooth refclk across the transition */ regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); - regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, - ARIZONA_FLL1_FREERUN); + regmap_update_bits(fll->arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); + udelay(32); } /* -- cgit v1.2.3 From 0837d8780c766bffe1fc5a5da54fb2620923a6d0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 1 Dec 2015 12:06:46 +0100 Subject: ASoC: sunxi: Remove useless comments and variable The comment is misleading on how we should support external power amps, and the variable is not used and generates a warning. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 30c9e9260491..516c7c2b479a 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -109,11 +109,6 @@ struct sun4i_codec { static void sun4i_codec_start_playback(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO high here on some boards - */ - /* Flush TX FIFO */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), @@ -127,11 +122,6 @@ static void sun4i_codec_start_playback(struct sun4i_codec *scodec) static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO low here on some boards - */ - /* Disable DAC DRQ */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), @@ -140,11 +130,6 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) static void sun4i_codec_start_capture(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO high here on some boards - */ - /* Enable ADC DRQ */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), @@ -153,11 +138,6 @@ static void sun4i_codec_start_capture(struct sun4i_codec *scodec) static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO low here on some boards - */ - /* Disable ADC DRQ */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); @@ -358,8 +338,6 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, struct snd_pcm_hw_params *params, unsigned int hwrate) { - u32 val; - /* Set ADC sample rate */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, -- cgit v1.2.3 From 8400ddf4ac4907323c7704fe57e4d138d04ae3b3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 1 Dec 2015 12:06:47 +0100 Subject: ASoC: sun4i-codec: pass through clk_set_rate error Commit 1fb34b48361e ('ASoC: sun4i: Implement MIC1 capture') added back some code that disregards the clk_set_rate error code and always returns -EINVAL. Fix that and return the code in order to have more clue about what's going on. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 516c7c2b479a..0dc11f547937 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -411,14 +411,15 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); unsigned long clk_freq; - int hwrate; + int ret, hwrate; clk_freq = sun4i_codec_get_mod_freq(params); if (!clk_freq) return -EINVAL; - if (clk_set_rate(scodec->clk_module, clk_freq)) - return -EINVAL; + ret = clk_set_rate(scodec->clk_module, clk_freq); + if (ret) + return ret; hwrate = sun4i_codec_get_hw_rate(params); if (hwrate < 0) -- cgit v1.2.3 From 319c32597fc22a58b946a6146f2be1fd208582e0 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 1 Dec 2015 16:09:51 +0530 Subject: ASoC: tegra_alc5632: check return value We have been returning success even if snd_soc_card_jack_new() fails. Lets check the return value and return error if it fails. Fixes: 12cc6d1dca4d ("ASoC: tegra_alc5632: Register jacks at the card level") Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_alc5632.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index ba272e21a6fa..deb597f7c302 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -101,12 +101,16 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = { static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) { + int ret; struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, - &tegra_alc5632_hs_jack, - tegra_alc5632_hs_jack_pins, - ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, + &tegra_alc5632_hs_jack, + tegra_alc5632_hs_jack_pins, + ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); + if (ret) + return ret; if (gpio_is_valid(machine->gpio_hp_det)) { tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; -- cgit v1.2.3 From 3c83ac23253c6a1b6d3ebcb4bb05eabb8337c9df Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 1 Dec 2015 14:29:35 +0530 Subject: ASoC: hdac_hdmi: check error return As hdac->num_nodes is unsigned we can not check if snd_hdac_get_sub_nodes() has returned error or success. Lets have a temporary int to check the error value. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 205f2c27263d..1a2f33b4abfc 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -409,17 +409,18 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) { hda_nid_t nid; - int i; + int i, num_nodes; struct hdac_device *hdac = &edev->hdac; struct hdac_hdmi_priv *hdmi = edev->private_data; int cvt_nid = 0, pin_nid = 0; - hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); - if (!nid || hdac->num_nodes < 0) { + num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); + if (!nid || num_nodes < 0) { dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } + hdac->num_nodes = num_nodes; hdac->start_nid = nid; for (i = 0; i < hdac->num_nodes; i++, nid++) { -- cgit v1.2.3 From 112446aa2e1262c41fddfc664fa418ce2d615328 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 1 Dec 2015 02:40:51 +0800 Subject: ASoC: da7218: fix boolreturn.cocci warnings sound/soc/codecs/da7218.c:3214:9-10: WARNING: return of 0/1 in function 'da7218_volatile_register' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index ed0c9a26065b..4fee7aeaadc7 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3211,9 +3211,9 @@ static bool da7218_volatile_register(struct device *dev, unsigned int reg) case DA7218_HPLDET_TEST: case DA7218_EVENT_STATUS: case DA7218_EVENT: - return 1; + return true; default: - return 0; + return false; } } -- cgit v1.2.3 From 8f35bf3f71f7b367511e0912eb7b70834b39ef77 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 28 Nov 2015 15:01:46 +0530 Subject: ASoC: Intel: Skylake: Update DMIC DAIs and capabilities On Skylake we can support upton 4DMICs on the PDM port, so update the PCM capabilities accordingly Also add a new DAI for DMIC pin which can be used for getting raw DMIC data Signed-off-by: Jeeja KP Signed-off-by: Dharageswari.R Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c79bbff00cb7..6570e5753e49 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -28,6 +28,7 @@ #define HDA_MONO 1 #define HDA_STEREO 2 +#define HDA_QUAD 4 static struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -46,8 +47,8 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_RATE_8000, .rate_min = 8000, .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = HDA_QUAD, .buffer_bytes_max = AZX_MAX_BUF_SIZE, .period_bytes_min = 128, .period_bytes_max = AZX_MAX_BUF_SIZE / 2, @@ -560,7 +561,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .capture = { .stream_name = "Reference Capture", .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, + .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, @@ -587,6 +588,18 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "DMIC Pin", + .ops = &skl_pcm_dai_ops, + .capture = { + .stream_name = "DMIC Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_QUAD, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, + /* BE CPU Dais */ { .name = "SSP0 Pin", @@ -640,8 +653,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .ops = &skl_dmic_dai_ops, .capture = { .stream_name = "DMIC01 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_min = HDA_MONO, + .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, -- cgit v1.2.3 From 9939a9c331ae8b9f859802af352477388b73c700 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 28 Nov 2015 15:01:47 +0530 Subject: ASoC: Intel: Skylake: Add helper routines to handle module params Some DSP modules have user configurable parameters. These parameters are required by modules in the following scenario - during initialization - after initialization using set parameter This patch adds helper routine to set module parameters using large config set IPC message and removes params to be passed as init module routine. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 16 +++++++++++++++- sound/soc/intel/skylake/skl-topology.c | 2 +- sound/soc/intel/skylake/skl-topology.h | 6 ++++-- 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index d71b58322cc7..30762734d859 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -556,7 +556,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max, * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper */ int skl_init_module(struct skl_sst *ctx, - struct skl_module_cfg *mconfig, char *param) + struct skl_module_cfg *mconfig) { u16 module_config_size = 0; void *param_data = NULL; @@ -855,3 +855,17 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) return 0; } + +/* Algo parameter set helper function */ +int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg) +{ + struct skl_ipc_large_config_msg msg; + + msg.module_id = mcfg->id.module_id; + msg.instance_id = mcfg->id.instance_id; + msg.param_data_size = size; + msg.large_param_id = param_id; + + return skl_ipc_set_large_config(&ctx->ipc, &msg, params); +} diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index f221c758d601..7a03bea48a9a 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -340,7 +340,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) * FE/BE params */ skl_tplg_update_module_params(w, ctx); - ret = skl_init_module(ctx, mconfig, NULL); + ret = skl_init_module(ctx, mconfig); if (ret < 0) return ret; } diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 57cb7b8dd269..5ba985b36227 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -312,8 +312,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); -int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config, - char *param); +int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); @@ -321,5 +320,8 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); +int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg); + enum skl_bitdepth skl_get_bit_depth(int params); #endif -- cgit v1.2.3 From 399b210bef097ce01d9e7b03ce5d4435f0624111 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 28 Nov 2015 15:01:48 +0530 Subject: ASoC: Intel: Skylake: Add helper routine to handle Algo parameter Some DSP modules has user configurable parameters, which are required by some modules at module initialization. To configure the module algorithm parameter during initialization we add helpers here Signed-off-by: Divya Prakash Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 31 ++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 5 +++++ sound/soc/intel/skylake/skl-tplg-interface.h | 3 ++- 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 30762734d859..7770a7e4162f 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -387,6 +387,28 @@ static void skl_set_copier_format(struct skl_sst *ctx, skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig); } +/* + * Algo module are DSP pre processing modules. Algo module take base module + * configuration and params + */ + +static void skl_set_algo_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_algo_cfg *algo_mcfg) +{ + struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg; + + skl_set_base_module_format(ctx, mconfig, base_cfg); + + if (mconfig->formats_config.caps_size == 0) + return; + + memcpy(algo_mcfg->params, + mconfig->formats_config.caps, + mconfig->formats_config.caps_size); + +} + static u16 skl_get_module_param_size(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { @@ -404,6 +426,11 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, case SKL_MODULE_TYPE_UPDWMIX: return sizeof(struct skl_up_down_mixer_cfg); + case SKL_MODULE_TYPE_ALGO: + param_size = sizeof(struct skl_base_cfg); + param_size += mconfig->formats_config.caps_size; + return param_size; + default: /* * return only base cfg when no specific module type is @@ -450,6 +477,10 @@ static int skl_set_module_format(struct skl_sst *ctx, skl_set_updown_mixer_format(ctx, module_config, *param_data); break; + case SKL_MODULE_TYPE_ALGO: + skl_set_algo_format(ctx, module_config, *param_data); + break; + default: skl_set_base_module_format(ctx, module_config, *param_data); break; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 5ba985b36227..0a66fab59828 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -140,6 +140,11 @@ struct skl_up_down_mixer_cfg { s32 coeff[UP_DOWN_MIXER_MAX_COEFF]; } __packed; +struct skl_algo_cfg { + struct skl_base_cfg base_cfg; + char params[0]; +} __packed; + enum skl_dma_type { SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, SKL_DMA_HDA_HOST_INPUT_CLASS = 1, diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 20c068754d08..63c83a3eeb7e 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -81,7 +81,8 @@ enum skl_module_type { SKL_MODULE_TYPE_MIXER = 0, SKL_MODULE_TYPE_COPIER, SKL_MODULE_TYPE_UPDWMIX, - SKL_MODULE_TYPE_SRCINT + SKL_MODULE_TYPE_SRCINT, + SKL_MODULE_TYPE_ALGO }; enum skl_core_affinity { -- cgit v1.2.3 From abb740033b56a2f57582e8e26bb9ea3650b6a3cc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 28 Nov 2015 15:01:49 +0530 Subject: ASoC: Intel: Skylake: Add support to configure module params This adds support to configure module parameter during module initialization or after module init using set module param required by the DSP firmware sequence. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 87 +++++++++++++++++++++++++++++++++- sound/soc/intel/skylake/skl-topology.h | 9 ++++ 2 files changed, 95 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 7a03bea48a9a..bfc138df56bc 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -313,6 +313,83 @@ static int skl_tplg_alloc_pipe_widget(struct device *dev, return 0; } +/* + * some modules can have multiple params set from user control and + * need to be set after module is initialized. If set_param flag is + * set module params will be done after module is initialised. + */ +static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, + struct skl_sst *ctx) +{ + int i, ret; + struct skl_module_cfg *mconfig = w->priv; + const struct snd_kcontrol_new *k; + struct soc_bytes_ext *sb; + struct skl_algo_data *bc; + struct skl_specific_cfg *sp_cfg; + + if (mconfig->formats_config.caps_size > 0 && + mconfig->formats_config.set_params) { + sp_cfg = &mconfig->formats_config; + ret = skl_set_module_params(ctx, sp_cfg->caps, + sp_cfg->caps_size, + sp_cfg->param_id, mconfig); + if (ret < 0) + return ret; + } + + for (i = 0; i < w->num_kcontrols; i++) { + k = &w->kcontrol_news[i]; + if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (void *) k->private_value; + bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->set_params) { + ret = skl_set_module_params(ctx, + (u32 *)bc->params, bc->max, + bc->param_id, mconfig); + if (ret < 0) + return ret; + } + } + } + + return 0; +} + +/* + * some module param can set from user control and this is required as + * when module is initailzed. if module param is required in init it is + * identifed by set_param flag. if set_param flag is not set, then this + * parameter needs to set as part of module init. + */ +static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) +{ + const struct snd_kcontrol_new *k; + struct soc_bytes_ext *sb; + struct skl_algo_data *bc; + struct skl_module_cfg *mconfig = w->priv; + int i; + + for (i = 0; i < w->num_kcontrols; i++) { + k = &w->kcontrol_news[i]; + if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (struct soc_bytes_ext *)k->private_value; + bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->set_params) + continue; + + mconfig->formats_config.caps = (u32 *)&bc->params; + mconfig->formats_config.caps_size = bc->max; + + break; + } + } + + return 0; +} + /* * Inside a pipe instance, we can have various modules. These modules need * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by @@ -340,9 +417,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) * FE/BE params */ skl_tplg_update_module_params(w, ctx); + + skl_tplg_set_module_init_data(w); ret = skl_init_module(ctx, mconfig); if (ret < 0) return ret; + + ret = skl_tplg_set_module_params(w, ctx); + if (ret < 0) + return ret; } return 0; @@ -1215,7 +1298,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, return -ENOMEM; memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, - dfw_config->caps.caps_size); + dfw_config->caps.caps_size); + mconfig->formats_config.param_id = dfw_config->caps.param_id; + mconfig->formats_config.set_params = dfw_config->caps.set_params; bind_event: if (tplg_w->event_type == 0) { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 0a66fab59828..51e785424a37 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -206,6 +206,8 @@ struct skl_module_pin { }; struct skl_specific_cfg { + bool set_params; + u32 param_id; u32 caps_size; u32 *caps; }; @@ -284,6 +286,13 @@ struct skl_module_cfg { struct skl_specific_cfg formats_config; }; +struct skl_algo_data { + u32 param_id; + bool set_params; + u32 max; + char *params; +}; + struct skl_pipeline { struct skl_pipe *pipe; struct list_head node; -- cgit v1.2.3 From 140adfba5280617487a848a0fa84f7523d999cf3 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 28 Nov 2015 15:01:50 +0530 Subject: ASoC: Intel: Skylake: Add tlv byte kcontrols This adds tlv bytes topology control creation and control load to initialize kcontrol data. And this also adds the callbacks for the these tlv byte kcontrols Signed-off-by: Mythri P K Signed-off-by: Divya Prakash Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 121 +++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-tplg-interface.h | 7 +- 2 files changed, 123 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index bfc138df56bc..622f7430e100 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -875,6 +875,60 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, return 0; } +static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct soc_bytes_ext *sb = + (struct soc_bytes_ext *)kcontrol->private_value; + struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->params) { + if (copy_to_user(data, &bc->param_id, sizeof(u32))) + return -EFAULT; + if (copy_to_user(data + sizeof(u32), &size, sizeof(u32))) + return -EFAULT; + if (copy_to_user(data + 2 * sizeof(u32), bc->params, size)) + return -EFAULT; + } + + return 0; +} + +#define SKL_PARAM_VENDOR_ID 0xff + +static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, + const unsigned int __user *data, unsigned int size) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct soc_bytes_ext *sb = + (struct soc_bytes_ext *)kcontrol->private_value; + struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; + struct skl *skl = get_skl_ctx(w->dapm->dev); + + if (ac->params) { + /* + * if the param_is is of type Vendor, firmware expects actual + * parameter id and size from the control. + */ + if (ac->param_id == SKL_PARAM_VENDOR_ID) { + if (copy_from_user(ac->params, data, size)) + return -EFAULT; + } else { + if (copy_from_user(ac->params, + data + 2 * sizeof(u32), size)) + return -EFAULT; + } + + if (w->power) + return skl_set_module_params(skl->skl_sst, + (u32 *)ac->params, ac->max, + ac->param_id, mconfig); + } + + return 0; +} + /* * The FE params are passed by hw_params of the DAI. * On hw_params, the params are stored in Gateway module of the FE and we @@ -1125,6 +1179,11 @@ static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { {SKL_PGA_EVENT, skl_tplg_pga_event}, }; +static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { + {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, + skl_tplg_tlv_control_set}, +}; + /* * The topology binary passes the pin info for a module so initialize the pin * info passed into module instance @@ -1321,8 +1380,70 @@ bind_event: return 0; } +static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, + struct snd_soc_tplg_bytes_control *bc) +{ + struct skl_algo_data *ac; + struct skl_dfw_algo_data *dfw_ac = + (struct skl_dfw_algo_data *)bc->priv.data; + + ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); + if (!ac) + return -ENOMEM; + + /* Fill private data */ + ac->max = dfw_ac->max; + ac->param_id = dfw_ac->param_id; + ac->set_params = dfw_ac->set_params; + + if (ac->max) { + ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + if (!ac->params) + return -ENOMEM; + + if (dfw_ac->params) + memcpy(ac->params, dfw_ac->params, ac->max); + } + + be->dobj.private = ac; + return 0; +} + +static int skl_tplg_control_load(struct snd_soc_component *cmpnt, + struct snd_kcontrol_new *kctl, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct soc_bytes_ext *sb; + struct snd_soc_tplg_bytes_control *tplg_bc; + struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + switch (hdr->ops.info) { + case SND_SOC_TPLG_CTL_BYTES: + tplg_bc = container_of(hdr, + struct snd_soc_tplg_bytes_control, hdr); + if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (struct soc_bytes_ext *)kctl->private_value; + if (tplg_bc->priv.size) + return skl_init_algo_data( + bus->dev, sb, tplg_bc); + } + break; + + default: + dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", + hdr->ops.get, hdr->ops.put, hdr->ops.info); + break; + } + + return 0; +} + static struct snd_soc_tplg_ops skl_tplg_ops = { .widget_load = skl_tplg_widget_load, + .control_load = skl_tplg_control_load, + .bytes_ext_ops = skl_tlv_ops, + .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), }; /* This will be read from topology manifest, currently defined here */ diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 63c83a3eeb7e..3f1908e3ae80 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -23,10 +23,7 @@ * Default types range from 0~12. type can range from 0 to 0xff * SST types start at higher to avoid any overlapping in future */ -#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS 0x100 -#define SOC_CONTROL_TYPE_HDA_SST_MUX 0x101 -#define SOC_CONTROL_TYPE_HDA_SST_MIX 0x101 -#define SOC_CONTROL_TYPE_HDA_SST_BYTE 0x103 +#define SKL_CONTROL_TYPE_BYTE_TLV 0x100 #define HDA_SST_CFG_MAX 900 /* size of copier cfg*/ #define MAX_IN_QUEUE 8 @@ -218,8 +215,8 @@ struct skl_dfw_module { struct skl_dfw_algo_data { u32 set_params:1; u32 rsvd:31; - u32 param_id; u32 max; + u32 param_id; char params[0]; } __packed; -- cgit v1.2.3 From f98ed119a7c5feacb1fc1c8d7f6c68934cd27384 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Dec 2015 07:34:28 +0000 Subject: ASoC: rsnd: care SWSP bit for TDM/non-TDM SSICR::SWSP bit controls WS signal low/high, but in case of TDM it is inverted. This patch solves this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 628739f13f99..79c3211a1e7f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -265,6 +265,9 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, u32 cr_own; u32 cr_mode; u32 wsr; + int is_tdm; + + is_tdm = (rsnd_get_slot_runtime(io) >= 6) ? 1 : 0; /* * always use 32bit system word. @@ -274,7 +277,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, if (rdai->bit_clk_inv) cr_own |= SCKP; - if (rdai->frm_clk_inv) + if (rdai->frm_clk_inv ^ is_tdm) cr_own |= SWSP; if (rdai->data_alignment) cr_own |= SDTA; @@ -307,7 +310,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, * rsnd_ssiu_init_gen2() */ wsr = ssi->wsr; - if (rsnd_get_slot_runtime(io) >= 6) { + if (is_tdm) { wsr |= WS_MODE; cr_own |= CHNL_8; } -- cgit v1.2.3 From 20bb0184f24df64d1ed4fa07c8feeeffda9b7721 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 2 Dec 2015 10:22:16 +0000 Subject: ASoC: dapm: Make enable/disable_pin work with always on widgets Always on widgets currently have some odd interactions with DAPM. Enabling/disabling a widget (snd_soc_dapm_enable_pin) then connecting it to a path works as expected, ie. when the widget is disabled the path doesn't power up and it does when the widget is enabled. However once in a path enabling the widget does not cause anything to power up, dapm_widget_set_power will return the current power state of the widget as 1, meaning we never check peer power states. This patch updates dapm_always_on_check_power to return w->connected such that it is effected by snd_soc_dapm_enable_pin and the like. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6760044f6aae..4ecacdcba484 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1300,7 +1300,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w) { - return 1; + return w->connected; } static int dapm_seq_compare(struct snd_soc_dapm_widget *a, -- cgit v1.2.3 From 82bd59bcb310898ea3a0303b847935a85ea24d8c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Dec 2015 11:49:53 +0000 Subject: ALSA: usx2y: fix inconsistent indenting on if statement minor change, indenting is one tab out. Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/usb/usx2y/usbusx2yaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 61d5dc2a3421..dd40ca9d858a 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -166,7 +166,7 @@ static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs, /* set the buffer pointer */ urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride; if ((subs->hwptr += count) >= runtime->buffer_size) - subs->hwptr -= runtime->buffer_size; + subs->hwptr -= runtime->buffer_size; } else urb->transfer_buffer = subs->tmpbuf; -- cgit v1.2.3 From b03d61d646c596efd02db64df43d287ea596b663 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 3 Dec 2015 15:46:57 +0100 Subject: ALSA: hda - Enable power_save_node for CX20722 I've tested it on one device and it works fine, no clicks. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c8b8ef5246a6..19b3deba23e4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -901,6 +901,9 @@ static int patch_conexant_auto(struct hda_codec *codec) snd_hda_pick_fixup(codec, cxt5051_fixup_models, cxt5051_fixups, cxt_fixups); break; + case 0x14f150f2: + codec->power_save_node = 1; + /* Fall through */ default: codec->pin_amp_workaround = 1; snd_hda_pick_fixup(codec, cxt5066_fixup_models, -- cgit v1.2.3 From eb399d3c99d8b411bfc46e67ea329ddc1ca64e87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2015 14:53:35 +0100 Subject: ALSA: hda - Skip ELD notification during PM process The ELD notification can be received asynchronously from the graphics side, and this may happen just at the moment the sound driver is processing the suspend or the resume, and it would confuse the whole procedure. Since the ELD and connection states are updated in anyway at the end of the resume, we can skip it when received during PM process. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 4b6fb668c91c..da264e8acce2 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2357,6 +2357,9 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) */ if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) return; + /* ditto during suspend/resume process itself */ + if (atomic_read(&(codec)->core.in_pm)) + return; check_presence_and_report(codec, pin_nid); } -- cgit v1.2.3 From 83266b6b60b6727af986e84a133dae24d394c3e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Dec 2015 17:19:31 +0100 Subject: ALSA: Fix compat_ioctl handling for OSS emulations The ALSA PCM, mixer and sequencer OSS emulations provide the 32bit compatible ioctl, but they just call the 64bit native ioctl as is. Although this works in most cases, passing the argument value as-is isn't guaranteed to work on all architectures. We need to convert it via compat_ptr() instead. This patch addresses the missing conversions. Since all relevant ioctls in these functions take the argument as a pointer, we do the pointer conversion in each compat_ioctl and pass it as a 64bit value to the native ioctl. Signed-off-by: Takashi Iwai --- sound/core/oss/mixer_oss.c | 8 +++++++- sound/core/oss/pcm_oss.c | 7 ++++++- sound/core/seq/oss/seq_oss.c | 7 ++++++- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 7a8c79dd9734..2ff9c12d664a 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -397,7 +398,12 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l #ifdef CONFIG_COMPAT /* all compatible */ -#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl +static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_mixer_oss_ioctl1(file->private_data, cmd, + (unsigned long)compat_ptr(arg)); +} #else #define snd_mixer_oss_ioctl_compat NULL #endif diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 58550cc93f28..e557dbe469f4 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2648,7 +2649,11 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long #ifdef CONFIG_COMPAT /* all compatible */ -#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl +static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} #else #define snd_pcm_oss_ioctl_compat NULL #endif diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 7354b8bed860..8db156b207f1 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -189,7 +190,11 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -#define odev_ioctl_compat odev_ioctl +static long odev_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return odev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} #else #define odev_ioctl_compat NULL #endif -- cgit v1.2.3 From 141bc6a620e114d3c4daeaf6e70b9ab96d914152 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 3 Dec 2015 18:15:06 +0000 Subject: ASoC: arizona: Correct types of mixer texts and values The core expects "const char * const" and "unsigned int" for enum controls, various places in Arizona use "const char *" and "int". This patch corrects the type of these arrays. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 8 ++++---- sound/soc/codecs/arizona.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a23f7d15324a..d2731cf439c6 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -310,7 +310,7 @@ int arizona_init_gpio(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(arizona_init_gpio); -const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { +const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", "Tone Generator 2", @@ -418,7 +418,7 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { }; EXPORT_SYMBOL_GPL(arizona_mixer_texts); -int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { +unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { 0x00, /* None */ 0x04, /* Tone */ 0x05, @@ -555,12 +555,12 @@ const char *arizona_sample_rate_val_to_name(unsigned int rate_val) } EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name); -const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { +const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate", }; EXPORT_SYMBOL_GPL(arizona_rate_text); -const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { +const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { 0, 1, 2, 8, }; EXPORT_SYMBOL_GPL(arizona_rate_val); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 01a367caefd8..b4f1867ae9d6 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -96,8 +96,8 @@ struct arizona_priv { #define ARIZONA_NUM_MIXER_INPUTS 104 extern const unsigned int arizona_mixer_tlv[]; -extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; -extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; +extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; +extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_GAINMUX_CONTROLS(name, base) \ SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1, \ @@ -216,8 +216,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_RATE_ENUM_SIZE 4 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14 -extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; -extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; +extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; +extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; -- cgit v1.2.3 From 1f0e1eae1521e9a00f1dfbcf7c51d785ade4179c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 3 Dec 2015 18:15:07 +0000 Subject: ASoC: arizona: Fix type of clock rate pointer in arizona_set_sysclk Both the sysclk and asyncclk members of arizona_priv are signed by we refer to them through an unsigned pointer. This patch fixes this small harmless error. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index d2731cf439c6..d90b3c51019a 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1214,7 +1214,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, unsigned int reg; unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; - unsigned int *clk; + int *clk; switch (clk_id) { case ARIZONA_CLK_SYSCLK: -- cgit v1.2.3 From 18014fd793d5e73eec5f2c22eaa37a32b44748eb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Nov 2015 12:51:49 +0100 Subject: ALSA: hda - Do zero-clear in snd_hdmi_parse_eld() itself Instead of doing in each caller side, snd_hdmi_parse_eld() does zero-clear of the parsed data by itself. This is safer and simplifies the upcoming code changes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 1 + sound/pci/hda/patch_hdmi.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 563984dd2562..bc2e08257c2e 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -253,6 +253,7 @@ int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, int mnl; int i; + memset(e, 0, sizeof(*e)); e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index da264e8acce2..901a3a7248ed 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1570,7 +1570,6 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) &eld->eld_size) < 0) eld->eld_valid = false; else { - memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; -- cgit v1.2.3 From e90247f9fceeebe5bdaac2d87e301e73bae9bc1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Nov 2015 09:12:12 +0100 Subject: ALSA: hda - Split ELD update code from hdmi_present_sense() This is a preliminary patch for the later change to support ELD/jack handling with i915 audio component. This splits the ELD update code from hdmi_present_sense() so that it can be called from other places. Just a code refactoring, no functional change. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 108 ++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 54 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 901a3a7248ed..a918377d3e9b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1530,6 +1530,56 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return 0; } +/* update per_pin ELD from the given new ELD; + * setup info frame and notification accordingly + */ +static void update_eld(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + struct hdmi_eld *eld) +{ + struct hdmi_eld *pin_eld = &per_pin->sink_eld; + bool old_eld_valid = pin_eld->eld_valid; + bool eld_changed; + + if (eld->eld_valid) + snd_hdmi_show_eld(codec, &eld->info); + + eld_changed = (pin_eld->eld_valid != eld->eld_valid); + if (eld->eld_valid && pin_eld->eld_valid) + if (pin_eld->eld_size != eld->eld_size || + memcmp(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size) != 0) + eld_changed = true; + + pin_eld->eld_valid = eld->eld_valid; + pin_eld->eld_size = eld->eld_size; + if (eld->eld_valid) + memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size); + pin_eld->info = eld->info; + + /* + * Re-setup pin and infoframe. This is needed e.g. when + * - sink is first plugged-in + * - transcoder can change during stream playback on Haswell + * and this can make HW reset converter selection on a pin. + */ + if (eld->eld_valid && !old_eld_valid && per_pin->setup) { + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, per_pin->pin_nid, + per_pin->mux_idx); + } + + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + } + + if (eld_changed) + snd_ctl_notify(codec->card, + SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, + &per_pin->eld_ctl->id); +} + static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) { struct hda_jack_tbl *jack; @@ -1547,8 +1597,6 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * the unsolicited response to avoid custom WARs. */ int present; - bool update_eld = false; - bool eld_changed = false; bool ret; snd_hda_power_up_pm(codec); @@ -1574,61 +1622,13 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) eld->eld_size) < 0) eld->eld_valid = false; } - - if (eld->eld_valid) { - snd_hdmi_show_eld(codec, &eld->info); - update_eld = true; - } - else if (repoll) { - schedule_delayed_work(&per_pin->work, - msecs_to_jiffies(300)); - goto unlock; - } } - if (pin_eld->eld_valid != eld->eld_valid) - eld_changed = true; - - if (pin_eld->eld_valid && !eld->eld_valid) - update_eld = true; - - if (update_eld) { - bool old_eld_valid = pin_eld->eld_valid; - pin_eld->eld_valid = eld->eld_valid; - if (pin_eld->eld_size != eld->eld_size || - memcmp(pin_eld->eld_buffer, eld->eld_buffer, - eld->eld_size) != 0) { - memcpy(pin_eld->eld_buffer, eld->eld_buffer, - eld->eld_size); - eld_changed = true; - } - pin_eld->eld_size = eld->eld_size; - pin_eld->info = eld->info; - - /* - * Re-setup pin and infoframe. This is needed e.g. when - * - sink is first plugged-in (infoframe is not set up if !monitor_present) - * - transcoder can change during stream playback on Haswell - * and this can make HW reset converter selection on a pin. - */ - if (eld->eld_valid && !old_eld_valid && per_pin->setup) { - if (is_haswell_plus(codec) || - is_valleyview_plus(codec)) { - intel_verify_pin_cvt_connect(codec, per_pin); - intel_not_share_assigned_cvt(codec, pin_nid, - per_pin->mux_idx); - } - - hdmi_setup_audio_infoframe(codec, per_pin, - per_pin->non_pcm); - } - } + if (!eld->eld_valid && repoll) + schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300)); + else + update_eld(codec, per_pin, eld); - if (eld_changed) - snd_ctl_notify(codec->card, - SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, - &per_pin->eld_ctl->id); - unlock: ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid; jack = snd_hda_jack_tbl_get(codec, pin_nid); -- cgit v1.2.3 From 6603249dcdbb6aab0b726bdf372d6f20c0d2d611 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2015 16:49:35 +0100 Subject: ALSA: hda - Enable audio component for old Intel PCH devices As i915 graphics driver provides the notification via audio component, not only the currently implemented HSW+ and VLV+ platforms but also all other PCH-based platforms (e.g. Cougar Point, Panther Point, etc) can use this infrastructure. It'll improve the reliability and the power consumption significantly, especially once when we implement the ELD notification via component. As a preliminary, this patch enables the usage of audio component for all PCH platforms. The HDA controller just needs to set AZX_DCAPS_I915_POWERWELL flag appropriately. The name of the flag is a bit confusing, but this actually works even on the chips without the powerwell but accesses only the other component ops. In the HDMI/DP codec driver side, we just need to register/unregister the notifier for such chips. This can be identified by checking the audio_component field in the assigned hdac_bus. One caveat is that PCH for Haswell and Broadwell must not be bound with i915 audio component, as there are dedicated HD-audio HDMI controllers on these platforms. Ditto for Poulsbo and Oaktrail as they use gma500 graphics, not i915. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 14 ++++++++++---- sound/pci/hda/patch_hdmi.c | 6 ++++-- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 963f82430938..ee0e316401f9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -284,13 +284,19 @@ enum { (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE) /* quirks for Intel PCH */ -#define AZX_DCAPS_INTEL_PCH_NOPM \ +#define AZX_DCAPS_INTEL_PCH_BASE \ (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) +/* PCH up to IVB; bound with i915 audio component for HDMI, no runtime PM */ +#define AZX_DCAPS_INTEL_PCH_NOPM \ + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_POWERWELL) + +/* PCH for HSW/BDW; with runtime PM, but no i915 binding */ #define AZX_DCAPS_INTEL_PCH \ - (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME) +/* HSW HDMI */ #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ @@ -2146,10 +2152,10 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Poulsbo */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, /* BayTrail */ { PCI_DEVICE(0x8086, 0x0f04), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL }, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index a918377d3e9b..85342d261043 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -152,6 +152,8 @@ struct hdmi_spec { struct i915_audio_component_audio_ops i915_audio_ops; }; +#define codec_has_acomp(codec) \ + ((codec)->bus->core.audio_component != NULL) struct hdmi_audio_infoframe { u8 type; /* 0x84 */ @@ -2218,7 +2220,7 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + if (codec_has_acomp(codec)) snd_hdac_i915_register_notifier(NULL); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { @@ -2390,7 +2392,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) is_broxton(codec)) codec->core.link_power_control = 1; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { + if (codec_has_acomp(codec)) { codec->depop_delay = 0; spec->i915_audio_ops.audio_ptr = codec; spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; -- cgit v1.2.3 From c10368897e104c008c610915a218f0fe5fa4ec96 Mon Sep 17 00:00:00 2001 From: Ravindra Lokhande Date: Mon, 7 Dec 2015 12:08:31 +0530 Subject: ALSA: compress: add support for 32bit calls in a 64bit kernel Compress offload does not support ioctl calls from a 32bit userspace in a 64 bit kernel. This patch adds support for ioctls from a 32bit userspace in a 64bit kernel Signed-off-by: Ravindra Lokhande Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- sound/core/compress_offload.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 2c52510967f0..18b8dc45bb8f 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -848,6 +849,15 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return retval; } +/* support of 32bit userspace on 64bit platforms */ +#ifdef CONFIG_COMPAT +static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_compr_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static const struct file_operations snd_compr_file_ops = { .owner = THIS_MODULE, .open = snd_compr_open, @@ -855,6 +865,9 @@ static const struct file_operations snd_compr_file_ops = { .write = snd_compr_write, .read = snd_compr_read, .unlocked_ioctl = snd_compr_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = snd_compr_ioctl_compat, +#endif .mmap = snd_compr_mmap, .poll = snd_compr_poll, }; -- cgit v1.2.3 From f48303122d2fd94b719e546cf8a39d412c7eee69 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 4 Dec 2015 18:40:31 -0500 Subject: ASoC: dwc: add runtime suspend/resume functionality When DW controller is in master mode, it can disable/enable clock during the device runtime suspend/resume sequence. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/dwc/designware_i2s.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 6e6a70c5c2bd..3d7754c115ec 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -394,6 +395,23 @@ static const struct snd_soc_component_driver dw_i2s_component = { }; #ifdef CONFIG_PM +static int dw_i2s_runtime_suspend(struct device *dev) +{ + struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); + + if (dw_dev->capability & DW_I2S_MASTER) + clk_disable(dw_dev->clk); + return 0; +} + +static int dw_i2s_runtime_resume(struct device *dev) +{ + struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); + + if (dw_dev->capability & DW_I2S_MASTER) + clk_enable(dw_dev->clk); + return 0; +} static int dw_i2s_suspend(struct snd_soc_dai *dai) { @@ -649,7 +667,7 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } } - + pm_runtime_enable(&pdev->dev); return 0; err_clk_disable: @@ -665,6 +683,7 @@ static int dw_i2s_remove(struct platform_device *pdev) if (dev->capability & DW_I2S_MASTER) clk_disable_unprepare(dev->clk); + pm_runtime_disable(&pdev->dev); return 0; } @@ -677,12 +696,17 @@ static const struct of_device_id dw_i2s_of_match[] = { MODULE_DEVICE_TABLE(of, dw_i2s_of_match); #endif +static const struct dev_pm_ops dwc_pm_ops = { + SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL) +}; + static struct platform_driver dw_i2s_driver = { .probe = dw_i2s_probe, .remove = dw_i2s_remove, .driver = { .name = "designware-i2s", .of_match_table = of_match_ptr(dw_i2s_of_match), + .pm = &dwc_pm_ops, }, }; -- cgit v1.2.3 From e164835a0270cc01c93794536027cc70cd00d0ff Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 4 Dec 2015 18:40:32 -0500 Subject: ASoC: dwc: add quirk for different register offset DWC in ACP 2.x IP has different offsets for I2S_COMP_PARAM_* registers. Added a quirk to support the same. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- include/sound/designware_i2s.h | 5 +++++ sound/soc/dwc/designware_i2s.c | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index 8966ba7c9629..e0bb45807f29 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -45,6 +45,11 @@ struct i2s_platform_data { u32 snd_fmts; u32 snd_rates; + #define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0) + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; + void *play_dma_data; void *capture_dma_data; bool (*filter)(struct dma_chan *chan, void *slave); diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 3d7754c115ec..940c88136a34 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -94,6 +94,9 @@ struct dw_i2s_dev { struct clk *clk; int active; unsigned int capability; + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; struct device *dev; /* data related to DMA transfers b/w i2s and DMAC */ @@ -477,8 +480,8 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, * Read component parameter registers to extract * the I2S block's configuration. */ - u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); - u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); + u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); u32 idx; if (COMP1_TX_ENABLED(comp1)) { @@ -521,7 +524,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, struct resource *res, const struct i2s_platform_data *pdata) { - u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); u32 idx = COMP1_APB_DATA_WIDTH(comp1); int ret; @@ -625,6 +628,14 @@ static int dw_i2s_probe(struct platform_device *pdev) if (pdata) { dev->capability = pdata->cap; clk_id = NULL; + dev->quirks = pdata->quirks; + if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) { + dev->i2s_reg_comp1 = pdata->i2s_reg_comp1; + dev->i2s_reg_comp2 = pdata->i2s_reg_comp2; + } else { + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; + } ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); } else { clk_id = "i2sclk"; -- cgit v1.2.3 From 0032e9dbc5d8add10345ccda48e3803bb7cfd650 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 4 Dec 2015 18:40:33 -0500 Subject: ASoC: dwc: reconfigure dwc in 'resume' from 'suspend' DWC IP can be powered off during system suspend in some platforms. After system is resumed, dwc needs to be programmed again to continue audio use case. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/dwc/designware_i2s.c | 70 ++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 940c88136a34..825a1f480aab 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -98,6 +98,8 @@ struct dw_i2s_dev { unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp2; struct device *dev; + u32 ccr; + u32 xfer_resolution; /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; @@ -217,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream, return 0; } +static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) +{ + u32 ch_reg, irq; + struct i2s_clk_config_data *config = &dev->config; + + + i2s_disable_channels(dev, stream); + + for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); + i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); + } else { + i2s_write_reg(dev->i2s_base, RCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); + i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); + } + + } +} + static int dw_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); struct i2s_clk_config_data *config = &dev->config; - u32 ccr, xfer_resolution, ch_reg, irq; int ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config->data_width = 16; - ccr = 0x00; - xfer_resolution = 0x02; + dev->ccr = 0x00; + dev->xfer_resolution = 0x02; break; case SNDRV_PCM_FORMAT_S24_LE: config->data_width = 24; - ccr = 0x08; - xfer_resolution = 0x04; + dev->ccr = 0x08; + dev->xfer_resolution = 0x04; break; case SNDRV_PCM_FORMAT_S32_LE: config->data_width = 32; - ccr = 0x10; - xfer_resolution = 0x05; + dev->ccr = 0x10; + dev->xfer_resolution = 0x05; break; default: @@ -262,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - i2s_disable_channels(dev, substream->stream); + dw_i2s_config(dev, substream->stream); - for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - i2s_write_reg(dev->i2s_base, TCR(ch_reg), - xfer_resolution); - i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); - } else { - i2s_write_reg(dev->i2s_base, RCR(ch_reg), - xfer_resolution); - i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); - } - } - - i2s_write_reg(dev->i2s_base, CCR, ccr); + i2s_write_reg(dev->i2s_base, CCR, dev->ccr); config->sample_rate = params_rate(params); @@ -431,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) if (dev->capability & DW_I2S_MASTER) clk_enable(dev->clk); + + if (dai->playback_active) + dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK); + if (dai->capture_active) + dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE); return 0; } -- cgit v1.2.3 From 1e73bf781546f3969039fe60bff1eca44c87c241 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2015 11:47:31 +0100 Subject: ALSA: hda - Remove unused snd_hda_get_nid_path() An exported helper function snd_hda_get_nid_path() is nowhere used. Let's remove it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 16 ---------------- sound/pci/hda/hda_generic.h | 2 -- 2 files changed, 18 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c6e8a651cea1..a644fc3302f0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -278,22 +278,6 @@ static struct nid_path *get_nid_path(struct hda_codec *codec, return NULL; } -/** - * snd_hda_get_nid_path - get the path between the given NIDs - * @codec: the HDA codec - * @from_nid: the NID where the path start from - * @to_nid: the NID where the path ends at - * - * Return the found nid_path object or NULL for error. - * Passing 0 to either @from_nid or @to_nid behaves as a wildcard. - */ -struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, - hda_nid_t from_nid, hda_nid_t to_nid) -{ - return get_nid_path(codec, from_nid, to_nid, 0); -} -EXPORT_SYMBOL_GPL(snd_hda_get_nid_path); - /** * snd_hda_get_path_idx - get the index number corresponding to the path * instance diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 56e4139b9032..692510e59365 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -306,8 +306,6 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec); int snd_hda_gen_init(struct hda_codec *codec); void snd_hda_gen_free(struct hda_codec *codec); -struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, - hda_nid_t from_nid, hda_nid_t to_nid); int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, -- cgit v1.2.3 From c4a58c308a459901827ac941d40d5db047a1cb71 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2015 11:48:39 +0100 Subject: ALSA: hda - Make snd_hda_parse_nid_path() local An exported function snd_hda_parse_nid_path() is used only inside hda_generic.c. Let's make it a static local function for a better code optimization. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 5 ++--- sound/pci/hda/hda_generic.h | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index a644fc3302f0..f3c058f6c831 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -435,7 +435,7 @@ static bool __parse_nid_path(struct hda_codec *codec, return true; } -/** +/* * snd_hda_parse_nid_path - parse the widget path from the given nid to * the target nid * @codec: the HDA codec @@ -454,7 +454,7 @@ static bool __parse_nid_path(struct hda_codec *codec, * with the negative of given value are excluded, only other paths are chosen. * when @anchor_nid is zero, no special handling about path selection. */ -bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, +static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid, int anchor_nid, struct nid_path *path) { @@ -465,7 +465,6 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, } return false; } -EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path); /** * snd_hda_add_new_path - parse the path between the given NIDs and diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 692510e59365..f66fc7e25e07 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -308,9 +308,6 @@ void snd_hda_gen_free(struct hda_codec *codec); int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); -bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, - hda_nid_t to_nid, int anchor_nid, - struct nid_path *path); struct nid_path * snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid, int anchor_nid); -- cgit v1.2.3 From a504b1ee417ffd1e3c272b4594213edf14af3ef1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Dec 2015 05:38:23 +0000 Subject: ASoC: rsnd: tidyup data align position for capture L/R channel data has been treated as inverted on R-Car sound 16bit mode, Thus, 4689032b1("ASoC: rsnd: tidyup data align position") tidyuped data align position. But it couldn't care about capture case. This patch cares both playback/capture Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 1 + sound/soc/sh/rcar/core.c | 13 +++++++++++-- sound/soc/sh/rcar/gen.c | 1 + sound/soc/sh/rcar/rsnd.h | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index ab904c3f20b5..cd1f064e63c4 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -80,6 +80,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, dev_dbg(dev, "ctu/mix path = 0x%08x", data); rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); + rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); rsnd_adg_set_cmd_timsel_gen2(mod, io); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f1d7af114a31..849c1ad93df2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -272,13 +272,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *target = src ? src : ssi; + struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; u32 mask = ~0; + if (rsnd_io_is_play(io)) { + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + + target = src ? src : ssi; + } else { + struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); + + target = cmd ? cmd : ssi; + } + mask <<= runtime->channels * 4; val = val & mask; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 50fc73042b7e..7c5485e46fd7 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -242,6 +242,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), + RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20), RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 970e1301f7c6..ad854d6719ea 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -81,6 +81,7 @@ enum rsnd_reg { RSND_REG_SCU_SYS_INT_EN0, RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ RSND_REG_CMD_CTRL, /* Gen2 only */ + RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ RSND_REG_CTU_CTUIR, @@ -319,6 +320,7 @@ struct rsnd_dai_stream { #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) +#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) -- cgit v1.2.3 From e7fdd52779a6c2b49d457f452296a77c8cffef6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2015 17:00:42 +0100 Subject: ALSA: hda - Implement loopback control switch for Realtek and other codecs Many codecs, typically found on Realtek codecs, have the analog loopback path merged to the secondary input of the middle of the output paths. Currently, we don't offer the dynamic switching in such configuration but let each loopback path mute by itself. This should work well in theory, but in reality, we often see that such a dead loopback path causes some background noises even if all the elements get muted. Such a problem has been fixed by adding the quirk accordingly to disable aamix, and it's the right fix, per se. The only problem is that it's not so trivial to achieve it; user needs to pass a hint string via patch module option or sysfs. This patch gives a bit improvement on the situation: it adds "Loopback Mixing" control element for such codecs like other codecs (e.g. IDT or VIA codecs) with the individual loopback paths. User can turn on/off the loopback path simply via a mixer app. For keeping the compatibility, the loopback is still enabled on these codecs. But user can try to turn it off if experiencing a suspicious background or click noise on the fly, then build a static fixup later once after the problem is addressed. Other than the addition of the loopback enable/disablement control, there should be no changes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 87 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index f3c058f6c831..30c8efe0f80a 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -754,9 +754,6 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps; unsigned int mask, val; - if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) - return; - caps = query_amp_caps(codec, nid, dir); val = get_amp_val_to_activate(codec, nid, dir, caps, enable); mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); @@ -767,12 +764,22 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, update_amp(codec, nid, dir, idx, mask, val); } +static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int idx_to_check, + bool enable) +{ + /* check whether the given amp is still used by others */ + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + activate_amp(codec, nid, dir, idx, idx_to_check, enable); +} + static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, int i, bool enable) { hda_nid_t nid = path->path[i]; init_amp(codec, nid, HDA_OUTPUT, 0); - activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); + check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); } static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, @@ -800,9 +807,16 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, * when aa-mixer is available, we need to enable the path as well */ for (n = 0; n < nums; n++) { - if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) - continue; - activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + if (n != idx) { + if (conn[n] != spec->mixer_merge_nid) + continue; + /* when aamix is disabled, force to off */ + if (!add_aamix) { + activate_amp(codec, nid, HDA_INPUT, n, n, false); + continue; + } + } + check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable); } } @@ -1563,6 +1577,12 @@ static bool map_singles(struct hda_codec *codec, int outs, return found; } +static inline bool has_aamix_out_paths(struct hda_gen_spec *spec) +{ + return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2]; +} + /* create a new path including aamix if available, and return its index */ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) { @@ -2405,25 +2425,51 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix, } } +/* re-initialize the output paths; only called from loopback_mixing_put() */ +static void update_output_paths(struct hda_codec *codec, int num_outs, + const int *paths) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, + spec->aamix_mode); + } +} + static int loopback_mixing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int val = ucontrol->value.enumerated.item[0]; if (val == spec->aamix_mode) return 0; spec->aamix_mode = val; - update_aamix_paths(codec, val, spec->out_paths[0], - spec->aamix_out_paths[0], - spec->autocfg.line_out_type); - update_aamix_paths(codec, val, spec->hp_paths[0], - spec->aamix_out_paths[1], - AUTO_PIN_HP_OUT); - update_aamix_paths(codec, val, spec->speaker_paths[0], - spec->aamix_out_paths[2], - AUTO_PIN_SPEAKER_OUT); + if (has_aamix_out_paths(spec)) { + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + cfg->line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + } else { + update_output_paths(codec, cfg->line_outs, spec->out_paths); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + update_output_paths(codec, cfg->hp_outs, spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + update_output_paths(codec, cfg->speaker_outs, + spec->speaker_paths); + } return 1; } @@ -2441,12 +2487,13 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) if (!spec->mixer_nid) return 0; - if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || - spec->aamix_out_paths[2])) - return 0; if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) return -ENOMEM; spec->have_aamix_ctl = 1; + /* if no explicit aamix path is present (e.g. for Realtek codecs), + * enable aamix as default -- just for compatibility + */ + spec->aamix_mode = !has_aamix_out_paths(spec); return 0; } @@ -5647,6 +5694,8 @@ static void init_aamix_paths(struct hda_codec *codec) if (!spec->have_aamix_ctl) return; + if (!has_aamix_out_paths(spec)) + return; update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], spec->aamix_out_paths[0], spec->autocfg.line_out_type); -- cgit v1.2.3 From 8d6f88ce961cf62137696627448cfd6038f07f41 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Thu, 3 Dec 2015 15:53:28 +0800 Subject: ASoC: mediatek: Use current HW pointer for pointer callback Previously we recorded "last interrupt position" and used it in pointer callback. This is not correct implementation, and it causes underruns when user space monitors buffer level to decide when to send next data chunk in low latency application. Remove position recording in IRQ handler and also hw_ptr in struct mtk_afe_memif used to record that, and let pointer callback reports current HW pointer instead. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-common.h | 1 - sound/soc/mediatek/mtk-afe-pcm.c | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index cc4393cb1130..9b1af1a70874 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -92,7 +92,6 @@ struct mtk_afe_memif_data { struct mtk_afe_memif { unsigned int phys_buf_addr; int buffer_size; - unsigned int hw_ptr; /* Previous IRQ's HW ptr */ struct snd_pcm_substream *substream; const struct mtk_afe_memif_data *data; const struct mtk_afe_irq_data *irqdata; diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 7f7134397f73..5399a0eead3e 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -175,8 +175,17 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + unsigned int hw_ptr; + int ret; + + ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr); + if (ret || hw_ptr == 0) { + dev_err(afe->dev, "%s hw_ptr err\n", __func__); + hw_ptr = memif->phys_buf_addr; + } - return bytes_to_frames(substream->runtime, memif->hw_ptr); + return bytes_to_frames(substream->runtime, + hw_ptr - memif->phys_buf_addr); } static const struct snd_pcm_ops mtk_afe_pcm_ops = { @@ -602,7 +611,6 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, memif->phys_buf_addr = substream->runtime->dma_addr; memif->buffer_size = substream->runtime->dma_bytes; - memif->hw_ptr = 0; /* start */ regmap_write(afe->regmap, @@ -737,7 +745,6 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, /* and clear pending IRQ */ regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << memif->data->irq_clr_shift); - memif->hw_ptr = 0; return 0; default: return -EINVAL; @@ -1081,7 +1088,7 @@ static const struct regmap_config mtk_afe_regmap_config = { static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) { struct mtk_afe *afe = dev_id; - unsigned int reg_value, hw_ptr; + unsigned int reg_value; int i, ret; ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, ®_value); @@ -1097,13 +1104,6 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) if (!(reg_value & (1 << memif->data->irq_clr_shift))) continue; - ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, - &hw_ptr); - if (ret || hw_ptr == 0) { - dev_err(afe->dev, "%s hw_ptr err\n", __func__); - hw_ptr = memif->phys_buf_addr; - } - memif->hw_ptr = hw_ptr - memif->phys_buf_addr; snd_pcm_period_elapsed(memif->substream); } -- cgit v1.2.3 From 6c5768b3aa6f554a719834591ad2c6b4e1291397 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Thu, 3 Dec 2015 23:29:50 +0530 Subject: ASoC: Intel: Skylake: Add support for Loadable modules A module is loaded when the path consisting the module is opened. The module binary(ies) is loaded from file system and cached in kernel memory for future use. This is downloaded to DSP using DMA and invoking Load module IPCs This patch adds support for load/unload module IPCs, DMAing modules and manging the modules Signed-off-by: Dharageswari R Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.h | 14 +++ sound/soc/intel/skylake/skl-sst-ipc.c | 53 ++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 6 ++ sound/soc/intel/skylake/skl-sst.c | 175 +++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.c | 29 +++++- 5 files changed, 276 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index f2a69d9e56b3..5d0947935e2b 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -114,6 +114,9 @@ struct skl_dsp_fw_ops { int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); + int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name); + int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); + }; struct skl_dsp_loader_ops { @@ -123,6 +126,17 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); }; +struct skl_load_module_info { + u16 mod_id; + const struct firmware *fw; +}; + +struct skl_module_table { + struct skl_load_module_info *mod_info; + unsigned int usage_cnt; + struct list_head list; +}; + void skl_cldma_process_intr(struct sst_dsp *ctx); void skl_cldma_int_disable(struct sst_dsp *ctx); int skl_cldma_prepare(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 95679c02c6ee..33860d2311c4 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -130,6 +130,11 @@ #define IPC_SRC_QUEUE_MASK 0x7 #define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ << IPC_SRC_QUEUE_SHIFT) +/* Load Module count */ +#define IPC_LOAD_MODULE_SHIFT 0 +#define IPC_LOAD_MODULE_MASK 0xFF +#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ + << IPC_LOAD_MODULE_SHIFT) /* Save pipeline messgae extension register */ #define IPC_DMA_ID_SHIFT 0 @@ -728,6 +733,54 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, } EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); +/* + * In order to load a module we need to send IPC to initiate that. DMA will + * performed to load the module memory. The FW supports multiple module load + * at single shot, so we can send IPC with N modules represented by + * module_cnt + */ +int skl_ipc_load_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); + header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt), NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_load_modules); + +int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, + void *data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); + header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt), NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); + int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param) { diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index f1a154e45dc3..e17012778560 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -108,6 +108,12 @@ int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc, int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, struct skl_ipc_bind_unbind_msg *msg); +int skl_ipc_load_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data); + +int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data); + int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index e1d34d5c3f9a..8cd5cdb21fd5 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -38,6 +38,8 @@ #define SKL_INSTANCE_ID 0 #define SKL_BASE_FW_MODULE_ID 0 +#define SKL_NUM_MODULES 1 + static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) { u32 cur_sts; @@ -202,11 +204,182 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx) return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); } +/* + * since get/set_module are called from DAPM context, + * we don't need lock for usage count + */ +static unsigned int skl_get_module(struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return ++module->usage_cnt; + } + + return -EINVAL; +} + +static unsigned int skl_put_module(struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return --module->usage_cnt; + } + + return -EINVAL; +} + +static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx, + char *mod_name, int mod_id) +{ + const struct firmware *fw; + struct skl_module_table *skl_module; + unsigned int size; + int ret; + + ret = request_firmware(&fw, mod_name, ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request Module %s failed :%d\n", + mod_name, ret); + return NULL; + } + + skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL); + if (skl_module == NULL) { + release_firmware(fw); + return NULL; + } + + size = sizeof(*skl_module->mod_info); + skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL); + if (skl_module->mod_info == NULL) { + release_firmware(fw); + return NULL; + } + + skl_module->mod_info->mod_id = mod_id; + skl_module->mod_info->fw = fw; + list_add(&skl_module->list, &ctx->module_list); + + return skl_module; +} + +/* get a module from it's unique ID */ +static struct skl_module_table *skl_module_get_from_id( + struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + if (list_empty(&ctx->module_list)) { + dev_err(ctx->dev, "Module list is empty\n"); + return NULL; + } + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return module; + } + + return NULL; +} + +static int skl_transfer_module(struct sst_dsp *ctx, + struct skl_load_module_info *module) +{ + int ret; + struct skl_sst *skl = ctx->thread_context; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data, + module->fw->size); + if (ret < 0) + return ret; + + ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, + (void *)&module->mod_id); + if (ret < 0) + dev_err(ctx->dev, "Failed to Load module: %d\n", ret); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid) +{ + struct skl_module_table *module_entry = NULL; + int ret = 0; + char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ + + snprintf(mod_name, sizeof(mod_name), "%s%s%s", + "intel/dsp_fw_", guid, ".bin"); + + module_entry = skl_module_get_from_id(ctx, mod_id); + if (module_entry == NULL) { + module_entry = skl_fill_module_table(ctx, mod_name, mod_id); + if (module_entry == NULL) { + dev_err(ctx->dev, "Failed to Load module\n"); + return -EINVAL; + } + } + + if (!module_entry->usage_cnt) { + ret = skl_transfer_module(ctx, module_entry->mod_info); + if (ret < 0) { + dev_err(ctx->dev, "Failed to Load module\n"); + return ret; + } + } + + ret = skl_get_module(ctx, mod_id); + + return ret; +} + +static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) +{ + unsigned int usage_cnt; + struct skl_sst *skl = ctx->thread_context; + int ret = 0; + + usage_cnt = skl_put_module(ctx, mod_id); + if (usage_cnt < 0) { + dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); + return -EIO; + } + ret = skl_ipc_unload_modules(&skl->ipc, + SKL_NUM_MODULES, &mod_id); + if (ret < 0) { + dev_err(ctx->dev, "Failed to UnLoad module\n"); + skl_get_module(ctx, mod_id); + return ret; + } + + return ret; +} + +static void skl_clear_module_table(struct sst_dsp *ctx) +{ + struct skl_module_table *module, *tmp; + + if (list_empty(&ctx->module_list)) + return; + + list_for_each_entry_safe(module, tmp, &ctx->module_list, list) { + list_del(&module->list); + release_firmware(module->mod_info->fw); + } +} + static struct skl_dsp_fw_ops skl_fw_ops = { .set_state_D0 = skl_set_dsp_D0, .set_state_D3 = skl_set_dsp_D3, .load_fw = skl_load_base_firmware, .get_fw_errcode = skl_get_errorcode, + .load_mod = skl_load_module, + .unload_mod = skl_unload_module, }; static struct sst_ops skl_ops = { @@ -251,6 +424,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + INIT_LIST_HEAD(&sst->module_list); sst->dsp_ops = dsp_ops; sst->fw_ops = skl_fw_ops; @@ -277,6 +451,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + skl_clear_module_table(ctx->dsp); skl_ipc_free(&ctx->ipc); ctx->dsp->ops->free(ctx->dsp); } diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 622f7430e100..32735eff386c 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -26,6 +26,8 @@ #include "skl-topology.h" #include "skl.h" #include "skl-tplg-interface.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" #define SKL_CH_FIXUP_MASK (1 << 0) #define SKL_RATE_FIXUP_MASK (1 << 1) @@ -412,6 +414,13 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) return -ENOMEM; + if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { + ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, + mconfig->id.module_id, mconfig->guid); + if (ret < 0) + return ret; + } + /* * apply fix/conversion to module params based on * FE/BE params @@ -431,6 +440,24 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) return 0; } +static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, + struct skl_pipe *pipe) +{ + struct skl_pipe_module *w_module = NULL; + struct skl_module_cfg *mconfig = NULL; + + list_for_each_entry(w_module, &pipe->w_list, node) { + mconfig = w_module->w->priv; + + if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod) + return ctx->dsp->fw_ops.unload_mod(ctx->dsp, + mconfig->id.module_id); + } + + /* no modules to unload in this path, so return */ + return 0; +} + /* * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we * need create the pipeline. So we do following: @@ -755,7 +782,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, ret = skl_delete_pipe(ctx, mconfig->pipe); - return ret; + return skl_tplg_unload_pipe_modules(ctx, s_pipe); } /* -- cgit v1.2.3 From b18c458de143d22773e770fc785c521614c24487 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 3 Dec 2015 23:29:51 +0530 Subject: ASoC: Intel: Skylake: Add memory pages to widget data. A module can require extra memory for processing, like audio algorithms. The memory for these modules needs to be represented in base module configuration and passed to DSP on init, so add the memory pages as a field in widget data Signed-off-by: Dharageswari.R Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 1 + sound/soc/intel/skylake/skl-topology.c | 1 + sound/soc/intel/skylake/skl-topology.h | 1 + 3 files changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 7770a7e4162f..5297b345839a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -212,6 +212,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->cps = mconfig->mcps; base_cfg->ibs = mconfig->ibs; base_cfg->obs = mconfig->obs; + base_cfg->is_pages = mconfig->mem_pages; } /* diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 32735eff386c..be02214e80db 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1339,6 +1339,7 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->converter = dfw_config->converter; mconfig->m_type = dfw_config->module_type; mconfig->vbus_id = dfw_config->vbus_id; + mconfig->mem_pages = dfw_config->mem_pages; pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); if (pipe) diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 51e785424a37..04318e2091fd 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -277,6 +277,7 @@ struct skl_module_cfg { u32 params_fixup; u32 converter; u32 vbus_id; + u32 mem_pages; struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; -- cgit v1.2.3 From fd18110f1480d51f416cea6d5f63b83f85b14043 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Thu, 3 Dec 2015 23:29:52 +0530 Subject: ASoC: Intel: Skylake: Add support for Mic Select module Mic select is a DSP module which is used to select one or many inputs to form an output. This is useful to select data selectively from PDM input and hence the name. This module is of generic module type. This patch adds support to add and configure Mic select module in firmware topology. Signed-off-by: Dharageswari R Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 26 ++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 5 +++++ sound/soc/intel/skylake/skl-tplg-interface.h | 3 ++- 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 5297b345839a..a91161be7f5d 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -410,6 +410,25 @@ static void skl_set_algo_format(struct skl_sst *ctx, } +/* + * Mic select module allows selecting one or many input channels, thus + * acting as a demux. + * + * Mic select module take base module configuration and out-format + * configuration + */ +static void skl_set_base_outfmt_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_base_outfmt_cfg *base_outfmt_mcfg) +{ + struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; + struct skl_base_cfg *base_cfg = + (struct skl_base_cfg *)base_outfmt_mcfg; + + skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_setup_out_format(ctx, mconfig, out_fmt); +} + static u16 skl_get_module_param_size(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { @@ -432,6 +451,9 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, param_size += mconfig->formats_config.caps_size; return param_size; + case SKL_MODULE_TYPE_BASE_OUTFMT: + return sizeof(struct skl_base_outfmt_cfg); + default: /* * return only base cfg when no specific module type is @@ -482,6 +504,10 @@ static int skl_set_module_format(struct skl_sst *ctx, skl_set_algo_format(ctx, module_config, *param_data); break; + case SKL_MODULE_TYPE_BASE_OUTFMT: + skl_set_base_outfmt_format(ctx, module_config, *param_data); + break; + default: skl_set_base_module_format(ctx, module_config, *param_data); break; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 04318e2091fd..349f2a3b6613 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -145,6 +145,11 @@ struct skl_algo_cfg { char params[0]; } __packed; +struct skl_base_outfmt_cfg { + struct skl_base_cfg base_cfg; + struct skl_audio_data_format out_fmt; +} __packed; + enum skl_dma_type { SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, SKL_DMA_HDA_HOST_INPUT_CLASS = 1, diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 3f1908e3ae80..626b148317fe 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -79,7 +79,8 @@ enum skl_module_type { SKL_MODULE_TYPE_COPIER, SKL_MODULE_TYPE_UPDWMIX, SKL_MODULE_TYPE_SRCINT, - SKL_MODULE_TYPE_ALGO + SKL_MODULE_TYPE_ALGO, + SKL_MODULE_TYPE_BASE_OUTFMT }; enum skl_core_affinity { -- cgit v1.2.3 From 4ced182763286a7c26cf671b27d1ddd58cf6cec8 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 3 Dec 2015 23:29:53 +0530 Subject: ASoC: Intel: Skylake: Fix module init data correctly Module initialization parameter data can be set by - INIT_INSTANCE IPC by using the default value - SET_PARAMS immediately after INIT_INSTANCE - SET_PARAMS data from kcontrol values set this patch add param type to identify the parameters has to be sent to DSP. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 6 +++--- sound/soc/intel/skylake/skl-topology.h | 4 ++-- sound/soc/intel/skylake/skl-tplg-interface.h | 16 +++++++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index be02214e80db..eb31235f7040 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -331,7 +331,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, struct skl_specific_cfg *sp_cfg; if (mconfig->formats_config.caps_size > 0 && - mconfig->formats_config.set_params) { + mconfig->formats_config.set_params == SKL_PARAM_SET) { sp_cfg = &mconfig->formats_config; ret = skl_set_module_params(ctx, sp_cfg->caps, sp_cfg->caps_size, @@ -346,7 +346,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, sb = (void *) k->private_value; bc = (struct skl_algo_data *)sb->dobj.private; - if (bc->set_params) { + if (bc->set_params == SKL_PARAM_SET) { ret = skl_set_module_params(ctx, (u32 *)bc->params, bc->max, bc->param_id, mconfig); @@ -379,7 +379,7 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) sb = (struct soc_bytes_ext *)k->private_value; bc = (struct skl_algo_data *)sb->dobj.private; - if (bc->set_params) + if (bc->set_params != SKL_PARAM_INIT) continue; mconfig->formats_config.caps = (u32 *)&bc->params; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 349f2a3b6613..6ba0bdc7753c 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -211,7 +211,7 @@ struct skl_module_pin { }; struct skl_specific_cfg { - bool set_params; + u32 set_params; u32 param_id; u32 caps_size; u32 *caps; @@ -294,7 +294,7 @@ struct skl_module_cfg { struct skl_algo_data { u32 param_id; - bool set_params; + u32 set_params; u32 max; char *params; }; diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 626b148317fe..c9ae010b3cc8 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -141,6 +141,12 @@ enum module_pin_type { SKL_PIN_TYPE_HETEROGENEOUS, }; +enum skl_module_param_type { + SKL_PARAM_DEFAULT = 0, + SKL_PARAM_INIT, + SKL_PARAM_SET +}; + struct skl_dfw_module_pin { u16 module_id; u16 instance_id; @@ -158,8 +164,8 @@ struct skl_dfw_module_fmt { } __packed; struct skl_dfw_module_caps { - u32 set_params:1; - u32 rsvd:31; + u32 set_params:2; + u32 rsvd:30; u32 param_id; u32 caps_size; u32 caps[HDA_SST_CFG_MAX]; @@ -214,10 +220,10 @@ struct skl_dfw_module { } __packed; struct skl_dfw_algo_data { - u32 set_params:1; - u32 rsvd:31; - u32 max; + u32 set_params:2; + u32 rsvd:30; u32 param_id; + u32 max; char params[0]; } __packed; -- cgit v1.2.3 From c99b80564c1badfa0cd14f4ebf3193fd77e412e9 Mon Sep 17 00:00:00 2001 From: Omair M Abdullah Date: Thu, 3 Dec 2015 23:29:54 +0530 Subject: ASoC: Intel: Skylake: update mailbox uplink window offset and size SKL actual mailbox size is 0x10000 and initial values were 0x800, so update these accordingly Signed-off-by: Omair M Abdullah Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 5d0947935e2b..cbb40751c37e 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -58,9 +58,9 @@ struct sst_dsp_device; #define SKL_ADSP_MMIO_LEN 0x10000 -#define SKL_ADSP_W0_STAT_SZ 0x800 +#define SKL_ADSP_W0_STAT_SZ 0x1000 -#define SKL_ADSP_W0_UP_SZ 0x800 +#define SKL_ADSP_W0_UP_SZ 0x1000 #define SKL_ADSP_W1_SZ 0x1000 -- cgit v1.2.3 From cce1c7f383e829651e0729d4b0b2cb78ea5cb2d6 Mon Sep 17 00:00:00 2001 From: Mousami Jana Date: Thu, 3 Dec 2015 23:29:55 +0530 Subject: ASoC: Intel: Skylake: add LARGE_CONFIG_GET IPC support For messages which have larger payload than mailbox data, we need to split the payload using set of messages containing mailbox size as payload. For sending such payload we already support LARGE_CONFIG_SET IPCs and now to query such payload add LARGE_CONFIG_GET IPC Signed-off-by: Mousami Jana Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 53 +++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 3 ++ 2 files changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 33860d2311c4..62e665a3b8f7 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -349,6 +349,8 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, switch (reply) { case IPC_GLB_REPLY_SUCCESS: dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); + /* copy the rx data from the mailbox */ + sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); break; case IPC_GLB_REPLY_OUT_OF_MEMORY: @@ -834,3 +836,54 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); + +int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret = 0; + size_t sz_remaining, rx_size, data_offset; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); + header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); + header.extension |= IPC_FINAL_BLOCK(1); + header.extension |= IPC_INITIAL_BLOCK(1); + + sz_remaining = msg->param_data_size; + data_offset = 0; + + while (sz_remaining != 0) { + rx_size = sz_remaining > SKL_ADSP_W1_SZ + ? SKL_ADSP_W1_SZ : sz_remaining; + if (rx_size == sz_remaining) + header.extension |= IPC_FINAL_BLOCK(1); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, + ((char *)param) + data_offset, + msg->param_data_size); + if (ret < 0) { + dev_err(ipc->dev, + "ipc: get large config fail, err: %d\n", ret); + return ret; + } + sz_remaining -= rx_size; + data_offset = msg->param_data_size - sz_remaining; + + /* clear the fields */ + header.extension &= IPC_INITIAL_BLOCK_CLEAR; + header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; + /* fill the fields */ + header.extension |= IPC_INITIAL_BLOCK(1); + header.extension |= IPC_DATA_OFFSET_SZ(data_offset); + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index e17012778560..1bbcdb471cf2 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -120,6 +120,9 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); +int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); -- cgit v1.2.3 From 7d9f29119d3e4db6ae817881d8e305650424032c Mon Sep 17 00:00:00 2001 From: Omair M Abdullah Date: Thu, 3 Dec 2015 23:29:56 +0530 Subject: ASoC: Intel: Skylake: read params from DSP if module is on If a module is ON then we should read the module parameters from DSP rather than driver cached values Signed-off-by: Omair M Abdullah Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 13 +++++++++++++ sound/soc/intel/skylake/skl-topology.c | 7 +++++++ sound/soc/intel/skylake/skl-topology.h | 2 ++ 3 files changed, 22 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index a91161be7f5d..46310d9ac008 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -927,3 +927,16 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, return skl_ipc_set_large_config(&ctx->ipc, &msg, params); } + +int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg) +{ + struct skl_ipc_large_config_msg msg; + + msg.module_id = mcfg->id.module_id; + msg.instance_id = mcfg->id.instance_id; + msg.param_data_size = size; + msg.large_param_id = param_id; + + return skl_ipc_get_large_config(&ctx->ipc, &msg, params); +} diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index eb31235f7040..b824450edcb4 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -908,6 +908,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *sb = (struct soc_bytes_ext *)kcontrol->private_value; struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct skl *skl = get_skl_ctx(w->dapm->dev); + + if (w->power) + skl_get_module_params(skl->skl_sst, (u32 *)bc->params, + bc->max, bc->param_id, mconfig); if (bc->params) { if (copy_to_user(data, &bc->param_id, sizeof(u32))) diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 6ba0bdc7753c..9aa2a2b6598a 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -342,6 +342,8 @@ int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); +int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg); enum skl_bitdepth skl_get_bit_depth(int params); #endif -- cgit v1.2.3 From 4386b76753c49dfdb940c0e5eeef09b61feaf712 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 3 Dec 2015 23:29:57 +0530 Subject: ASoC: Intel: Skylake: Add dai link for DMIC capture Since in Skylake we support another DAI for DMIC quad capture, add a dailink for this as well. Also specify constrains for DMIC FE devices and fixup for DMIC BEs Signed-off-by: Dharageswari.R Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 57333a476136..e4fc8a1ce471 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -190,6 +190,42 @@ static struct snd_soc_ops skylake_rt286_ops = { .hw_params = skylake_rt286_hw_params, }; +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_rt286_dais[] = { /* Front End DAI links */ @@ -238,6 +274,20 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .nonatomic = 1, .dynamic = 1, }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, + }, /* Back End DAI links */ { @@ -267,6 +317,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = skylake_dmic_fixup, .ignore_suspend = 1, .dpcm_capture = 1, .no_pcm = 1, -- cgit v1.2.3 From b34e24d2406f123d5dbbff4fdeebbc2af76b0acd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Dec 2015 23:29:58 +0530 Subject: ASoC: Intel: Skylake: add wov as int sink Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index e4fc8a1ce471..0a924901b9b6 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -52,6 +52,7 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("DMIC2", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), }; static const struct snd_soc_dapm_route skylake_rt286_map[] = { @@ -69,6 +70,8 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMIC AIF", NULL, "SoC DMIC"}, + {"WoV Sink", NULL, "hwd_in sink"}, + /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, -- cgit v1.2.3 From 820f339fe9fcabee17d3d2ba2b48a51368a51bf4 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Dec 2015 23:29:59 +0530 Subject: ASoC: Intel: Skylake: Fix the dapm machine map DAPM Machine map for machine was not specifying the paths correctly. The correct order should be: "DMIC01 Rx" (SoC DMIC BE), connected to "DMIC AIF" (DMic Codec AIF) and then "DMic" (DMic codec Input) connected to "SoC DMIC" (Machine DMIC MIC Widget) Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 0a924901b9b6..51c4eb87e6ec 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -68,7 +68,7 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { /* digital mics */ {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMIC AIF", NULL, "SoC DMIC"}, + {"DMic", NULL, "SoC DMIC"}, {"WoV Sink", NULL, "hwd_in sink"}, @@ -82,7 +82,7 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { { "ssp0 Rx", NULL, "AIF1 Capture" }, { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, { "hif1", NULL, "iDisp Tx"}, { "iDisp Tx", NULL, "iDisp_out"}, -- cgit v1.2.3 From 4557c305d4fc9356563a1d41fa6fe29e494f0460 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 3 Dec 2015 23:30:00 +0530 Subject: ASoC: Intel: Skylake: Add support for active suspend Some of the usecases can be marked as 'ignore_suspend' by machine. For these on suspend we should keep audio controller ON by saving the state and not suspending the device For this we need to maintain a counter for these streams and be active on suspend when such a stream is opened. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 27 +++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.c | 28 ++++++++++++++++++++++++++-- sound/soc/intel/skylake/skl.h | 2 ++ 3 files changed, 55 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 6570e5753e49..b89ae6f7c096 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -109,6 +109,31 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e return HDAC_EXT_STREAM_TYPE_COUPLED; } +/* + * check if the stream opened is marked as ignore_suspend by machine, if so + * then enable suspend_active refcount + * + * The count supend_active does not need lock as it is used in open/close + * and suspend context + */ +static void skl_set_suspend_active(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, bool enable) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_soc_dapm_widget *w; + struct skl *skl = ebus_to_skl(ebus); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + if (w->ignore_suspend && enable) + skl->supend_active++; + else if (w->ignore_suspend && !enable) + skl->supend_active--; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -146,6 +171,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream tag set in dma params=%d\n", dma_params->stream_tag); + skl_set_suspend_active(substream, dai, true); snd_pcm_set_sync(substream); return 0; @@ -257,6 +283,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, * dma_params */ snd_soc_dai_set_dma_data(dai, substream, NULL); + skl_set_suspend_active(substream, dai, false); kfree(dma_params); } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index d3e87b6f93fe..2c16325d1ce1 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -169,16 +169,40 @@ static int skl_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); - return _skl_suspend(ebus); + /* + * Do not suspend if streams which are marked ignore suspend are + * running, we need to save the state for these and continue + */ + if (skl->supend_active) { + pci_save_state(pci); + pci_disable_device(pci); + return 0; + } else { + return _skl_suspend(ebus); + } } static int skl_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + int ret; - return _skl_resume(ebus); + /* + * resume only when we are not in suspend active, otherwise need to + * restore the device + */ + if (skl->supend_active) { + pci_restore_state(pci); + ret = pci_enable_device(pci); + } else { + ret = _skl_resume(ebus); + } + + return ret; } #endif /* CONFIG_PM_SLEEP */ diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 774c29cf84dc..3d167eed0f59 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -70,6 +70,8 @@ struct skl { struct list_head ppl_list; const char *fw_name; + + int supend_active; }; #define skl_to_ebus(s) (&(s)->ebus) -- cgit v1.2.3 From 9ec2053b13f75d7ad9c0e6db9763954bd1a1b9ae Mon Sep 17 00:00:00 2001 From: Praveen Diwakar Date: Thu, 3 Dec 2015 23:30:01 +0530 Subject: ASoC: Intel: Skylake: Update ignore suspend for rt286 machine We should only add ignore suspend flag for some DAIs and not all. This patches removes it from the DAIs where we do not support this It also marks the endpoints for which ignore_suspend should be enabled Signed-off-by: Praveen Diwakar Signed-off-by: Vunny Sodhi Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 51c4eb87e6ec..7396ddb427d8 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -89,6 +89,17 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { }; +static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; @@ -104,6 +115,9 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) rt286_mic_detect(codec, &skylake_headset); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); + return 0; } @@ -241,6 +255,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", + .init = skylake_rt286_fe_init, .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST @@ -286,7 +301,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .platform_name = "0000:00:1f.3", .init = NULL, .dpcm_capture = 1, - .ignore_suspend = 1, .nonatomic = 1, .dynamic = 1, .ops = &skylake_dmic_ops, @@ -306,7 +320,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .ignore_suspend = 1, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp0_fixup, .ops = &skylake_rt286_ops, -- cgit v1.2.3 From f8f80361d07d503093940097e967a7edaa134ca2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:22 +0800 Subject: ASoC: Implement DAI links in a list & define API to add/remove a link Implement a dai link list for the soc card. Add APIs to add/remove a DAI links dynamically, e.g. by topology. And a dobj is embedded into the struct snd_soc_dai_link. Topology can use the dobj to find the links created by it and remove them when the topology component is unloaded. The predefined DAI links are reserved to keep backward compatibility. And they will also be added to the list. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 15 ++++++++-- sound/soc/soc-core.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 232b30d3fa68..410cb0b422be 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1037,6 +1037,9 @@ struct snd_soc_dai_link { /* pmdown_time is ignored at stop */ unsigned int ignore_pmdown_time:1; + + struct list_head list; /* DAI link list of the soc card */ + struct snd_soc_dobj dobj; /* For topology */ }; struct snd_soc_codec_conf { @@ -1104,8 +1107,11 @@ struct snd_soc_card { long pmdown_time; /* CPU <--> Codec DAI links */ - struct snd_soc_dai_link *dai_link; - int num_links; + struct snd_soc_dai_link *dai_link; /* predefined links only */ + int num_links; /* predefined links only */ + struct list_head dai_link_list; /* all links */ + int num_dai_links; + struct list_head rtd_list; int num_rtd; @@ -1647,6 +1653,11 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, struct device_node *of_node, struct snd_soc_dai_link *dai_link); +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); + #include #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 878a9fe92686..bf4bccfc4b91 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1120,6 +1120,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) { int order; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *link, *_link; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { @@ -1132,6 +1133,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card) list_for_each_entry(rtd, &card->rtd_list, list) soc_remove_link_components(card, rtd, order); } + + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) + dev_warn(card->dev, "Topology forgot to remove link %s?\n", + link->name); + + list_del(&link->list); + card->num_dai_links--; + } } static int snd_soc_init_multicodec(struct snd_soc_card *card, @@ -1228,6 +1238,68 @@ static int soc_init_dai_link(struct snd_soc_card *card, return 0; } +/** + * snd_soc_add_dai_link - Add a DAI link dynamically + * @card: The ASoC card to which the DAI link is added + * @dai_link: The new DAI link to add + * + * This function adds a DAI link to the ASoC card's link list. + * + * Note: Topology can use this API to add DAI links when probing the + * topology component. And machine drivers can still define static + * DAI links in dai_link array. + */ +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return -EINVAL; + } + + lockdep_assert_held(&client_mutex); + list_add_tail(&dai_link->list, &card->dai_link_list); + card->num_dai_links++; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); + +/** + * snd_soc_remove_dai_link - Remove a DAI link from the list + * @card: The ASoC card that owns the link + * @dai_link: The DAI link to remove + * + * This function removes a DAI link from the ASoC card's link list. + * + * For DAI links previously added by topology, topology should + * remove them by using the dobj embedded in the link. + */ +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link *link, *_link; + + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return; + } + + lockdep_assert_held(&client_mutex); + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link == dai_link) { + list_del(&link->list); + card->num_dai_links--; + return; + } + } +} +EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { @@ -1722,6 +1794,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto base_error; } + /* add predefined DAI links to the list */ + for (i = 0; i < card->num_links; i++) + snd_soc_add_dai_link(card, card->dai_link+i); + /* initialize the register cache for each available codec */ list_for_each_entry(codec, &codec_list, list) { if (codec->cache_init) @@ -2479,6 +2555,9 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); + INIT_LIST_HEAD(&card->dai_link_list); + card->num_dai_links = 0; + INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; -- cgit v1.2.3 From d6f220ea13edfd3430fb42e09ff92e321ffb5762 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:32 +0800 Subject: ASoC: Define add/remove_dai_link ops for a soc card A machine driver can register the two ops. When a DAI link is added or removed by a component's topology, the ASoC core can call the ops to notify the machine driver for extra intialization or destruction. E.g. topology can create FE DAI links from a cpu DAI component, and the machine driver may define an add_dai_link ops to set machine-specific .init ops for the DAI link. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 410cb0b422be..af347bcdc2f6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1104,6 +1104,11 @@ struct snd_soc_card { struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); + int (*add_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + void (*remove_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + long pmdown_time; /* CPU <--> Codec DAI links */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bf4bccfc4b91..094856fa8cec 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1260,6 +1260,12 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra initialization + * on the link created by topology. + */ + if (dai_link->dobj.type && card->add_dai_link) + card->add_dai_link(card, dai_link); + list_add_tail(&dai_link->list, &card->dai_link_list); card->num_dai_links++; @@ -1290,6 +1296,12 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra destruction + * on the link created by topology. + */ + if (dai_link->dobj.type && card->remove_dai_link) + card->remove_dai_link(card, dai_link); + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { if (link == dai_link) { list_del(&link->list); -- cgit v1.2.3 From 49a5ba1cd9da4fb04e7ce1e0d94f6a5a9b7be48e Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:40 +0800 Subject: ASoC: soc_bind_dai_link() directly returns success for a bound DAI link This function will return success immediately for a bound DAI link. No need to look for the cpu/codec DAIs again. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 094856fa8cec..11d073b6ce33 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -960,6 +960,19 @@ static struct snd_soc_dai *snd_soc_find_dai( return NULL; } +static bool soc_is_dai_link_bound(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link == dai_link) + return true; + } + + return false; +} + static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -977,6 +990,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!rtd) return -ENOMEM; + if (soc_is_dai_link_bound(card, dai_link)) { + dev_dbg(card->dev, "ASoC: dai link %s already bound\n", + dai_link->name); + return 0; + } + cpu_dai_component.name = dai_link->cpu_name; cpu_dai_component.of_node = dai_link->cpu_of_node; cpu_dai_component.dai_name = dai_link->cpu_dai_name; -- cgit v1.2.3 From 61b0088b6a5b98608ce00c18a057b1f5bcb5f8b3 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:48 +0800 Subject: ASoC: Bind new DAI links after probing components Probing components can bring new DAI or DAI links based on the topology info. This patch finds the unbound DAI links and bind them. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 11d073b6ce33..6b1982dcedf1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1806,6 +1806,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *dai_link; int ret, i, order; mutex_lock(&client_mutex); @@ -1893,6 +1894,21 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + /* Find new DAI links added during probing components and bind them. + * Components with topology may bring new DAIs and DAI links. + */ + list_for_each_entry(dai_link, &card->dai_link_list, list) { + if (soc_is_dai_link_bound(card, dai_link)) + continue; + + ret = soc_init_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + ret = soc_bind_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + } + /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { -- cgit v1.2.3 From 34e684fa04fadd513e028fa48123f357deac77e8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Dec 2015 16:35:51 +0100 Subject: ASoC: fsl: use correct format string for dma_addr_t We get a warning for the imx-pcm-fiq driver when CONFIG_LPAE is enabled on ARM, because dma_addr_t is 64-bit then: sound/soc/fsl/imx-pcm-fiq.c: In function 'snd_imx_pcm_mmap': sound/soc/fsl/imx-pcm-fiq.c:223:107: warning: format '%x' expects argument of type 'unsigned int', but argument 6 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=] This changes the printk to use the correct format string for printing a dma_addr_t. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 7abf6a079574..49d7513f429e 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -220,9 +220,9 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, ret = dma_mmap_writecombine(substream->pcm->card->dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); - pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, + pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret, runtime->dma_area, - runtime->dma_addr, + &runtime->dma_addr, runtime->dma_bytes); return ret; } -- cgit v1.2.3 From ff793af4ce13afa9836f6a396552d623ff880099 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Dec 2015 16:12:54 +0100 Subject: ASoC: da7218: avoid 64-bit compile warning When building the da7218 driver on a 64-bit architecture, we get a harmless warning: sound/soc/codecs/da7218.c: In function 'da7218_of_get_id': sound/soc/codecs/da7218.c:2261:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] This changes the code to use uintptr_t to ensure we have an integer type of the same size as a pointer and won't get a warning on any architecture. Signed-off-by: Arnd Bergmann Fixes: 4d50934abd22 ("ASoC: da7218: Add da7218 codec driver") Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 4fee7aeaadc7..eacde128c4d6 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -2258,7 +2258,7 @@ static inline int da7218_of_get_id(struct device *dev) const struct of_device_id *id = of_match_device(da7218_of_match, dev); if (id) - return (int) id->data; + return (uintptr_t)id->data; else return -EINVAL; } -- cgit v1.2.3 From 6ee8eeb4af0e91975a7cd4795925e499cc79503c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2015 07:13:48 +0100 Subject: ALSA: hda - Less grumbling about lack of i915 binding The recent commit [6603249dcdbb: ALSA: hda - Enable audio component for old Intel PCH devices] enabled the i915 binding for HDMI/DP on old Intel PCHs. But many boards are without HDMI/DP, and they actually don't need i915 binding, and yet the driver has a check of i915 binding and complains like Haswell must be built with CONFIG_SND_HDA_I915 This error is false-positive, and it should be put only for HSW/BDW, instead of all devices that may be bound with i915. This patch fixes the condition to check, as well as rephrasing the message specific to HSW/BDW HDMI/DP. Fixes: 6603249dcdbb ('ALSA: hda - Enable audio component for old Intel PCH devices') Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ee0e316401f9..b49547f3c2e9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1954,8 +1954,8 @@ static int azx_probe(struct pci_dev *pci, #endif /* CONFIG_SND_HDA_PATCH_LOADER */ #ifndef CONFIG_SND_HDA_I915 - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n"); + if (CONTROLLER_IN_GPU(pci)) + dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n"); #endif if (schedule_probe) -- cgit v1.2.3 From fbaf9f9f6158a9c07652df88dd0bd68132b93292 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2015 07:21:49 +0100 Subject: ALSA: hda - Don't try to bind i915 unless CONFIG_SND_HDA_I915 is set snd-hda-intel driver tries to bind with i915 audio component always when AZX_DCAPS_I915_POWERWELL is set in the driver caps. This was mostly OK in the past, as the flag was applied only to a limited set of devices, namely, Haswell and Broadwell. On these machines, i915 graphics is almost mandatory as long as HDMI/DP is concerned. Recently the application of i915 binding was widened to more Intel chips. On these chips, the chance of a kernel without i915 graphics is much higher, and such user would hit an error like: snd_hda_intel 0000:00:1b.0: failed to add i915 component master (-19) Although the error itself is harmless, it's certainly superfluous even to try binding with i915, if we already know that there isn't any. This patch fixes it by simply defining AZX_DCAPS_I915_POWERWELL as 0 in the case without i915. Then all codes referring to this flag will be optimized out by the compiler. Fixes: 6603249dcdbb ('ALSA: hda - Enable audio component for old Intel PCH devices') Reported-by: kernel test robot Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 7b635d68cfe1..c1d28a657f19 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -46,7 +46,11 @@ #define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ +#ifdef CONFIG_SND_HDA_I915 #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ +#else +#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ +#endif #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ -- cgit v1.2.3 From c83d1b37d45a2ecaea7a6ba4ea010f717bdb2740 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Dec 2015 14:37:05 +0100 Subject: sound/oss: remove VIRT_TO_BUS dependency The OSS sound drivers used to rely on virt_to_bus(), but don't any more, so we can remove the Kconfig dependency. As a lot of architectures don't provide VIRT_TO_BUS any more, removing the dependency in sounds/oss/ would make the deprecated drivers appear there, which we probably don't want. Instead I'm replacing the simple dependency with 'VIRT_TO_BUS || RPC || NETWINDER' so we can still build these sound drivers for the platforms that need them, but don't change anything on other architectures. As a follow-up, we can remove the virt_to_bus() implementation and Kconfig symbol in the ARM architecture. Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/oss/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 48568fdf847f..4033fe58f0cf 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -240,7 +240,7 @@ config MSND_FIFOSIZE menuconfig SOUND_OSS tristate "OSS sound modules" - depends on ISA_DMA_API && VIRT_TO_BUS + depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER) depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN help OSS is the Open Sound System suite of sound card drivers. They make -- cgit v1.2.3 From eba65d179c1149cf79e68608d452631f33d7f017 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Wed, 9 Dec 2015 10:32:26 +0000 Subject: ASoC: rockchip: i2s: separate capture and playback If we only clear the tx/rx state when both are disabled it is not possible to start/stop one multiple times while the other is running. Since the two are independently controlled, treat them as such and remove the false dependency between capture and playback. Signed-off-by: John Keeping Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 72 +++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 83b1b9c9e017..acc6225d8d9d 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | I2S_XFER_RXS_START, - I2S_XFER_TXS_START | I2S_XFER_RXS_START); + I2S_XFER_TXS_START, + I2S_XFER_TXS_START); i2s->tx_start = true; } else { @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); - if (!i2s->rx_start) { - regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | - I2S_XFER_RXS_START, - I2S_XFER_TXS_STOP | - I2S_XFER_RXS_STOP); + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_START, + I2S_XFER_TXS_STOP); - regmap_update_bits(i2s->regmap, I2S_CLR, - I2S_CLR_TXC | I2S_CLR_RXC, - I2S_CLR_TXC | I2S_CLR_RXC); + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_TXC, + I2S_CLR_TXC); - regmap_read(i2s->regmap, I2S_CLR, &val); + regmap_read(i2s->regmap, I2S_CLR, &val); - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - break; - } + /* Should wait for clear operation to finish */ + while (val & I2S_CLR_TXC) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; } } } @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | I2S_XFER_RXS_START, - I2S_XFER_TXS_START | I2S_XFER_RXS_START); + I2S_XFER_RXS_START, + I2S_XFER_RXS_START); i2s->rx_start = true; } else { @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); - if (!i2s->tx_start) { - regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | - I2S_XFER_RXS_START, - I2S_XFER_TXS_STOP | - I2S_XFER_RXS_STOP); + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_RXS_START, + I2S_XFER_RXS_STOP); - regmap_update_bits(i2s->regmap, I2S_CLR, - I2S_CLR_TXC | I2S_CLR_RXC, - I2S_CLR_TXC | I2S_CLR_RXC); + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_RXC, + I2S_CLR_RXC); - regmap_read(i2s->regmap, I2S_CLR, &val); + regmap_read(i2s->regmap, I2S_CLR, &val); - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - break; - } + /* Should wait for clear operation to finish */ + while (val & I2S_CLR_RXC) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; } } } -- cgit v1.2.3 From 5938448b99275cba95167c3f9d39ca9225fdad38 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Wed, 9 Dec 2015 10:32:27 +0000 Subject: ASoC: rockchip: i2s: remove unused variables The previous commit removed the only use of these variables. Signed-off-by: John Keeping Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index acc6225d8d9d..8b0a588ed622 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -34,13 +34,6 @@ struct rk_i2s_dev { struct regmap *regmap; -/* - * Used to indicate the tx/rx status. - * I2S controller hopes to start the tx and rx together, - * also to stop them when they are both try to stop. -*/ - bool tx_start; - bool rx_start; bool is_master_mode; }; @@ -84,11 +77,7 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) regmap_update_bits(i2s->regmap, I2S_XFER, I2S_XFER_TXS_START, I2S_XFER_TXS_START); - - i2s->tx_start = true; } else { - i2s->tx_start = false; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); @@ -126,11 +115,7 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) regmap_update_bits(i2s->regmap, I2S_XFER, I2S_XFER_RXS_START, I2S_XFER_RXS_START); - - i2s->rx_start = true; } else { - i2s->rx_start = false; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); -- cgit v1.2.3 From f4e3040bf0e94ff86ba2c970a4d7691100dc69d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Dec 2015 13:01:28 +0100 Subject: ALSA: hda - Optimize audio component check in patch_hdmi.c The audio component is enabled only when CONFIG_SND_HDA_I915 is set. Give a dummy macro for allowing the compiler optimize out the relevant codes when this Kconfig isn't set. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 85342d261043..44d0d2374bb6 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -152,8 +152,12 @@ struct hdmi_spec { struct i915_audio_component_audio_ops i915_audio_ops; }; +#ifdef CONFIG_SND_HDA_I915 #define codec_has_acomp(codec) \ ((codec)->bus->core.audio_component != NULL) +#else +#define codec_has_acomp(codec) false +#endif struct hdmi_audio_infoframe { u8 type; /* 0x84 */ -- cgit v1.2.3 From 55913110dde2d9c1cf751481525848644f9041da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Dec 2015 13:03:29 +0100 Subject: ALSA: hda - Allow i915 binding later in codec driver Due to the recent change, HDA controller driver for Intel PCH tries to bind i915 audio component always at the probe time no matter whether HDMI/DP codec is found. This is, however, superflulous for old chipsets (e.g. on IVB) where they don't have always the HDMI/DP codecs but often have only a discrete GPU instead. For the newer chipsets, we need already the i915 binding from the beginning due to power well control. Meanwhile, for older chipsets where we don't need power well, we don't need the i915 binding at the controller level. This patch removes again the i915 binding in the HDA controller driver for old Intel PCHs, but adds the binding in HDMI/DP codec driver instead. This allows still the use of the direct notification from the graphics driver while we can avoid the unnecessary load of i915 driver for machines only with another GPU. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 6 +++--- sound/pci/hda/patch_hdmi.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b49547f3c2e9..fe9bef339cea 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -288,11 +288,11 @@ enum { (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) -/* PCH up to IVB; bound with i915 audio component for HDMI, no runtime PM */ +/* PCH up to IVB; no runtime PM */ #define AZX_DCAPS_INTEL_PCH_NOPM \ - (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE) -/* PCH for HSW/BDW; with runtime PM, but no i915 binding */ +/* PCH for HSW/BDW; with runtime PM */ #define AZX_DCAPS_INTEL_PCH \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 44d0d2374bb6..35a78a6f87a6 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -150,6 +150,7 @@ struct hdmi_spec { /* i915/powerwell (Haswell+/Valleyview+) specific */ struct i915_audio_component_audio_ops i915_audio_ops; + bool i915_bound; /* was i915 bound in this driver? */ }; #ifdef CONFIG_SND_HDA_I915 @@ -2234,6 +2235,8 @@ static void generic_hdmi_free(struct hda_codec *codec) eld_proc_free(per_pin); } + if (spec->i915_bound) + snd_hdac_i915_exit(&codec->bus->core); hdmi_array_free(spec); kfree(spec); } @@ -2381,6 +2384,12 @@ static int patch_generic_hdmi(struct hda_codec *codec) codec->spec = spec; hdmi_array_init(spec, 4); + /* Try to bind with i915 for any Intel codecs (if not done yet) */ + if (!codec_has_acomp(codec) && + (codec->core.vendor_id >> 16) == 0x8086) + if (!snd_hdac_i915_init(&codec->bus->core)) + spec->i915_bound = true; + if (is_haswell_plus(codec)) { intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); @@ -2404,6 +2413,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) } if (hdmi_parse_codec(codec) < 0) { + if (spec->i915_bound) + snd_hdac_i915_exit(&codec->bus->core); codec->spec = NULL; kfree(spec); return -EINVAL; -- cgit v1.2.3 From 9a5e5234bafeaa2e9d15881d443c38d3d82d0b38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Dec 2015 14:35:09 +0100 Subject: ALSA: hda - Fix superfluous HDMI jack repoll The recent commit [e90247f9fcee: ALSA: hda - Split ELD update code from hdmi_present_sense()] rewrote the HDMI jack handling code, but a slight behavior change sneaked in unexpectedly. When the jack isn't connected, it tries repoll unnecessarily. This patch addresses the flaw, to the right behavior as before. Fixes: e90247f9fcee ('ALSA: hda - Split ELD update code from hdmi_present_sense()') Reported-and-tested-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 35a78a6f87a6..2a7d29a07f31 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1605,6 +1605,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) */ int present; bool ret; + bool do_repoll = false; snd_hda_power_up_pm(codec); present = snd_hda_pin_sense(codec, pin_nid); @@ -1629,9 +1630,11 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) eld->eld_size) < 0) eld->eld_valid = false; } + if (!eld->eld_valid && repoll) + do_repoll = true; } - if (!eld->eld_valid && repoll) + if (do_repoll) schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300)); else update_eld(codec, per_pin, eld); -- cgit v1.2.3 From 788d441a164caea0a5d82e1d5bcd161820bfe62a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Nov 2015 15:36:13 +0100 Subject: ALSA: hda - Use component ops for i915 HDMI/DP audio jack handling Since we have a new audio component ops to fetch the current ELD and state now, we can reduce the usage of unsol event of HDMI/DP pins. The unsol event isn't only unreliable, but it also needs the power up/down of the codec and link at each time, which is a significant power and time loss. In this patch, the jack creation and unsol/jack event handling are modified to use the audio component for the dedicated Intel chips. The jack handling got slightly more codes than a simple usage of hda_jack layer since we need to deal directly with snd_jack object; the hda_jack layer is basically designed for the pin sense read and unsol events, both of which aren't used any longer in our case. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 111 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2a7d29a07f31..e91a3223fe5f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -83,6 +83,7 @@ struct hdmi_spec_per_pin { struct mutex lock; struct delayed_work work; struct snd_kcontrol *eld_ctl; + struct snd_jack *acomp_jack; /* jack via audio component */ int repoll_count; bool setup; /* the stream has been set up by prepare callback */ int channels; /* current number of channels */ @@ -1442,6 +1443,17 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec, } } +/* There is a fixed mapping between audio pin node and display port + * on current Intel platforms: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + */ +static int intel_pin2port(hda_nid_t pin_nid) +{ + return pin_nid - 4; +} + /* * HDA PCM callbacks */ @@ -1587,7 +1599,9 @@ static void update_eld(struct hda_codec *codec, &per_pin->eld_ctl->id); } -static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +/* update ELD and jack state via HD-audio verbs */ +static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, + int repoll) { struct hda_jack_tbl *jack; struct hda_codec *codec = per_pin->codec; @@ -1650,6 +1664,56 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) return ret; } +/* update ELD and jack state via audio component */ +static void sync_eld_via_acomp(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + struct i915_audio_component *acomp = codec->bus->core.audio_component; + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld = &spec->temp_eld; + int size; + + if (acomp && acomp->ops && acomp->ops->get_eld) { + mutex_lock(&per_pin->lock); + size = acomp->ops->get_eld(acomp->dev, + intel_pin2port(per_pin->pin_nid), + &eld->monitor_present, + eld->eld_buffer, + ELD_MAX_SIZE); + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (snd_hdmi_parse_eld(codec, &eld->info, + eld->eld_buffer, size) < 0) + size = -EINVAL; + } + + if (size > 0) { + eld->eld_valid = true; + eld->eld_size = size; + } else { + eld->eld_valid = false; + eld->eld_size = 0; + } + + update_eld(codec, per_pin, eld); + snd_jack_report(per_pin->acomp_jack, + eld->monitor_present ? SND_JACK_AVOUT : 0); + mutex_unlock(&per_pin->lock); + } +} + +static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +{ + struct hda_codec *codec = per_pin->codec; + + if (codec_has_acomp(codec)) { + sync_eld_via_acomp(codec, per_pin); + return false; /* don't call snd_hda_jack_report_sync() */ + } else { + return hdmi_present_sense_via_verbs(per_pin, repoll); + } +} + static void hdmi_repoll_eld(struct work_struct *work) { struct hdmi_spec_per_pin *per_pin = @@ -1785,17 +1849,6 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) return non_pcm; } -/* There is a fixed mapping between audio pin node and display port - * on current Intel platforms: - * Pin Widget 5 - PORT B (port = 1 in i915 driver) - * Pin Widget 6 - PORT C (port = 2 in i915 driver) - * Pin Widget 7 - PORT D (port = 3 in i915 driver) - */ -static int intel_pin2port(hda_nid_t pin_nid) -{ - return pin_nid - 4; -} - /* * HDMI callbacks */ @@ -2100,6 +2153,30 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) return 0; } +static void free_acomp_jack_priv(struct snd_jack *jack) +{ + struct hdmi_spec_per_pin *per_pin = jack->private_data; + + per_pin->acomp_jack = NULL; +} + +static int add_acomp_jack_kctl(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + const char *name) +{ + struct snd_jack *jack; + int err; + + err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack, + true, false); + if (err < 0) + return err; + per_pin->acomp_jack = jack; + jack->private_data = per_pin; + jack->private_free = free_acomp_jack_priv; + return 0; +} + static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) { char hdmi_str[32] = "HDMI/DP"; @@ -2110,6 +2187,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + if (codec_has_acomp(codec)) + return add_acomp_jack_kctl(codec, per_pin, hdmi_str); phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid); if (phantom_jack) strncat(hdmi_str, " Phantom", @@ -2205,8 +2284,10 @@ static int generic_hdmi_init(struct hda_codec *codec) hda_nid_t pin_nid = per_pin->pin_nid; hdmi_init_pin(codec, pin_nid); - snd_hda_jack_detect_enable_callback(codec, pin_nid, - codec->jackpoll_interval > 0 ? jack_callback : NULL); + if (!codec_has_acomp(codec)) + snd_hda_jack_detect_enable_callback(codec, pin_nid, + codec->jackpoll_interval > 0 ? + jack_callback : NULL); } return 0; } @@ -2236,6 +2317,8 @@ static void generic_hdmi_free(struct hda_codec *codec) cancel_delayed_work_sync(&per_pin->work); eld_proc_free(per_pin); + if (per_pin->acomp_jack) + snd_device_free(codec->card, per_pin->acomp_jack); } if (spec->i915_bound) -- cgit v1.2.3 From e2dc7d7d8ed3019f72855af1c3dcda3fb456b488 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2015 12:39:38 +0100 Subject: ALSA: hda - Move audio component accesses to hdac_i915.c A couple of i915_audio_component ops have been added and accessed directly from patch_hdmi.c. Ideally all these should be factored out into hdac_i915.c. This patch does it, adds two new helper functions for setting N/CTS and fetching ELD bytes. One bonus is that the hackish widget vs port mapping is also moved to hdac_i915.c, so that it can be fixed / enhanced more cleanly. Reviewed-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/hda_i915.h | 14 ++++++++++ sound/hda/hdac_i915.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/patch_hdmi.c | 69 +++++++++++++++++----------------------------- 3 files changed, 106 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h index 930b41e5acf4..fa341fcb5829 100644 --- a/include/sound/hda_i915.h +++ b/include/sound/hda_i915.h @@ -10,6 +10,9 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); +int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate); +int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, int max_bytes); int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_exit(struct hdac_bus *bus); int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *); @@ -26,6 +29,17 @@ static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) { return 0; } +static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, + int rate) +{ + return 0; +} +static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, + int max_bytes) +{ + return -ENODEV; +} static inline int snd_hdac_i915_init(struct hdac_bus *bus) { return -ENODEV; diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 8fef1b8d1fd8..c50177fb469f 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -118,6 +118,72 @@ int snd_hdac_get_display_clk(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); +/* There is a fixed mapping between audio pin node and display port + * on current Intel platforms: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + */ +static int pin2port(hda_nid_t pin_nid) +{ + return pin_nid - 4; +} + +/** + * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate + * @bus: HDA core bus + * @nid: the pin widget NID + * @rate: the sample rate to set + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function sets N/CTS value based on the given sample rate. + * Returns zero for success, or a negative error code. + */ +int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate) + return -ENODEV; + return acomp->ops->sync_audio_rate(acomp->dev, pin2port(nid), rate); +} +EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate); + +/** + * snd_hdac_acomp_get_eld - Get the audio state and ELD via component + * @bus: HDA core bus + * @nid: the pin widget NID + * @audio_enabled: the pointer to store the current audio state + * @buffer: the buffer pointer to store ELD bytes + * @max_bytes: the max bytes to be stored on @buffer + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function queries the current state of the audio on the given + * digital port and fetches the ELD bytes onto the given buffer. + * It returns the number of bytes for the total ELD data, zero for + * invalid ELD, or a negative error code. + * + * The return size is the total bytes required for the whole ELD bytes, + * thus it may be over @max_bytes. If it's over @max_bytes, it implies + * that only a part of ELD bytes have been fetched. + */ +int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, int max_bytes) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp || !acomp->ops || !acomp->ops->get_eld) + return -ENODEV; + + return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled, + buffer, max_bytes); +} +EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld); + static int hdac_component_master_bind(struct device *dev) { struct i915_audio_component *acomp = hdac_acomp; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index e91a3223fe5f..cd9b0ffc91dc 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1443,17 +1443,6 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec, } } -/* There is a fixed mapping between audio pin node and display port - * on current Intel platforms: - * Pin Widget 5 - PORT B (port = 1 in i915 driver) - * Pin Widget 6 - PORT C (port = 2 in i915 driver) - * Pin Widget 7 - PORT D (port = 3 in i915 driver) - */ -static int intel_pin2port(hda_nid_t pin_nid) -{ - return pin_nid - 4; -} - /* * HDA PCM callbacks */ @@ -1668,38 +1657,36 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, static void sync_eld_via_acomp(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin) { - struct i915_audio_component *acomp = codec->bus->core.audio_component; struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; int size; - if (acomp && acomp->ops && acomp->ops->get_eld) { - mutex_lock(&per_pin->lock); - size = acomp->ops->get_eld(acomp->dev, - intel_pin2port(per_pin->pin_nid), - &eld->monitor_present, - eld->eld_buffer, - ELD_MAX_SIZE); - if (size > 0) { - size = min(size, ELD_MAX_SIZE); - if (snd_hdmi_parse_eld(codec, &eld->info, - eld->eld_buffer, size) < 0) - size = -EINVAL; - } - - if (size > 0) { - eld->eld_valid = true; - eld->eld_size = size; - } else { - eld->eld_valid = false; - eld->eld_size = 0; - } - - update_eld(codec, per_pin, eld); - snd_jack_report(per_pin->acomp_jack, - eld->monitor_present ? SND_JACK_AVOUT : 0); - mutex_unlock(&per_pin->lock); + mutex_lock(&per_pin->lock); + size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid, + &eld->monitor_present, eld->eld_buffer, + ELD_MAX_SIZE); + if (size < 0) + goto unlock; + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (snd_hdmi_parse_eld(codec, &eld->info, + eld->eld_buffer, size) < 0) + size = -EINVAL; + } + + if (size > 0) { + eld->eld_valid = true; + eld->eld_size = size; + } else { + eld->eld_valid = false; + eld->eld_size = 0; } + + update_eld(codec, per_pin, eld); + snd_jack_report(per_pin->acomp_jack, + eld->monitor_present ? SND_JACK_AVOUT : 0); + unlock: + mutex_unlock(&per_pin->lock); } static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) @@ -1865,7 +1852,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; struct snd_pcm_runtime *runtime = substream->runtime; - struct i915_audio_component *acomp = codec->bus->core.audio_component; bool non_pcm; int pinctl; @@ -1884,10 +1870,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Todo: add DP1.2 MST audio support later */ - if (acomp && acomp->ops && acomp->ops->sync_audio_rate) - acomp->ops->sync_audio_rate(acomp->dev, - intel_pin2port(pin_nid), - runtime->rate); + snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); -- cgit v1.2.3 From 17074c1a5f1bbbf352fe071b2947a498db42661f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Dec 2015 15:52:37 +0100 Subject: ALSA: usb-audio: constify usb_protocol_ops structures The usb_protocol_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/usb/midi.c b/sound/usb/midi.c index ee212e71f180..cc39f63299ef 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -112,7 +112,7 @@ struct snd_usb_midi { struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; - struct usb_protocol_ops *usb_protocol_ops; + const struct usb_protocol_ops *usb_protocol_ops; struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; @@ -671,31 +671,32 @@ static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep, } } -static struct usb_protocol_ops snd_usbmidi_standard_ops = { +static const struct usb_protocol_ops snd_usbmidi_standard_ops = { .input = snd_usbmidi_standard_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_midiman_ops = { +static const struct usb_protocol_ops snd_usbmidi_midiman_ops = { .input = snd_usbmidi_midiman_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_midiman_packet, }; -static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { +static const +struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { .input = snd_usbmidi_maudio_broken_running_status_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_cme_ops = { +static const struct usb_protocol_ops snd_usbmidi_cme_ops = { .input = snd_usbmidi_cme_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { +static const struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { .input = ch345_broken_sysex_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, @@ -795,7 +796,7 @@ static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep, } } -static struct usb_protocol_ops snd_usbmidi_akai_ops = { +static const struct usb_protocol_ops snd_usbmidi_akai_ops = { .input = snd_usbmidi_akai_input, .output = snd_usbmidi_akai_output, }; @@ -835,7 +836,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = 2 + count; } -static struct usb_protocol_ops snd_usbmidi_novation_ops = { +static const struct usb_protocol_ops snd_usbmidi_novation_ops = { .input = snd_usbmidi_novation_input, .output = snd_usbmidi_novation_output, }; @@ -867,7 +868,7 @@ static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = count; } -static struct usb_protocol_ops snd_usbmidi_raw_ops = { +static const struct usb_protocol_ops snd_usbmidi_raw_ops = { .input = snd_usbmidi_raw_input, .output = snd_usbmidi_raw_output, }; @@ -883,7 +884,7 @@ static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint *ep, snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); } -static struct usb_protocol_ops snd_usbmidi_ftdi_ops = { +static const struct usb_protocol_ops snd_usbmidi_ftdi_ops = { .input = snd_usbmidi_ftdi_input, .output = snd_usbmidi_raw_output, }; @@ -927,7 +928,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = ep->max_transfer; } -static struct usb_protocol_ops snd_usbmidi_122l_ops = { +static const struct usb_protocol_ops snd_usbmidi_122l_ops = { .input = snd_usbmidi_us122l_input, .output = snd_usbmidi_us122l_output, }; @@ -1060,7 +1061,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = ep->max_transfer - buf_free; } -static struct usb_protocol_ops snd_usbmidi_emagic_ops = { +static const struct usb_protocol_ops snd_usbmidi_emagic_ops = { .input = snd_usbmidi_emagic_input, .output = snd_usbmidi_emagic_output, .init_out_endpoint = snd_usbmidi_emagic_init_out, -- cgit v1.2.3 From a9b17a638af5ae374677c5349653114231483419 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Tue, 8 Dec 2015 15:59:00 +0000 Subject: ASoC: pcm3168a: Add driver for pcm3168a codec Add driver for Texas Instruments pcm3168a codec Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 17 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/pcm3168a-i2c.c | 66 ++++ sound/soc/codecs/pcm3168a-spi.c | 65 ++++ sound/soc/codecs/pcm3168a.c | 767 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/pcm3168a.h | 100 ++++++ 6 files changed, 1021 insertions(+) create mode 100644 sound/soc/codecs/pcm3168a-i2c.c create mode 100644 sound/soc/codecs/pcm3168a-spi.c create mode 100644 sound/soc/codecs/pcm3168a.c create mode 100644 sound/soc/codecs/pcm3168a.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..012bdcf6d175 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -85,6 +85,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 + select SND_SOC_PCM3168A_I2C if I2C + select SND_SOC_PCM3168A_SPI if SPI_MASTER select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C @@ -506,6 +508,21 @@ config SND_SOC_PCM1792A config SND_SOC_PCM3008 tristate +config SND_SOC_PCM3168A + tristate + +config SND_SOC_PCM3168A_I2C + tristate "Texas Instruments PCM3168A CODEC - I2C" + depends on I2C + select SND_SOC_PCM3168A + select REGMAP_I2C + +config SND_SOC_PCM3168A_SPI + tristate "Texas Instruments PCM3168A CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_PCM3168A + select REGMAP_SPI + config SND_SOC_PCM512x tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..890ae5571a00 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -78,6 +78,9 @@ snd-soc-nau8825-objs := nau8825.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm3168a-objs := pcm3168a.o +snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o +snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o @@ -273,6 +276,9 @@ obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o +obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o +obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c new file mode 100644 index 000000000000..6feb0901dfeb --- /dev/null +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -0,0 +1,66 @@ +/* + * PCM3168A codec i2c driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "pcm3168a.h" + +static int pcm3168a_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm3168a_probe(&i2c->dev, regmap); +} + +static int pcm3168a_i2c_remove(struct i2c_client *i2c) +{ + pcm3168a_remove(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id pcm3168a_i2c_id[] = { + { "pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id); + +static const struct of_device_id pcm3168a_of_match[] = { + { .compatible = "ti,pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm3168a_of_match); + +static struct i2c_driver pcm3168a_i2c_driver = { + .probe = pcm3168a_i2c_probe, + .remove = pcm3168a_i2c_remove, + .id_table = pcm3168a_i2c_id, + .driver = { + .name = "pcm3168a", + .of_match_table = pcm3168a_of_match, + .pm = &pcm3168a_pm_ops, + }, +}; +module_i2c_driver(pcm3168a_i2c_driver); + +MODULE_DESCRIPTION("PCM3168A I2C codec driver"); +MODULE_AUTHOR("Damien Horsley "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c new file mode 100644 index 000000000000..03945a27ae40 --- /dev/null +++ b/sound/soc/codecs/pcm3168a-spi.c @@ -0,0 +1,65 @@ +/* + * PCM3168A codec spi driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "pcm3168a.h" + +static int pcm3168a_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm3168a_probe(&spi->dev, regmap); +} + +static int pcm3168a_spi_remove(struct spi_device *spi) +{ + pcm3168a_remove(&spi->dev); + + return 0; +} + +static const struct spi_device_id pcm3168a_spi_id[] = { + { "pcm3168a", }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id); + +static const struct of_device_id pcm3168a_of_match[] = { + { .compatible = "ti,pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm3168a_of_match); + +static struct spi_driver pcm3168a_spi_driver = { + .probe = pcm3168a_spi_probe, + .remove = pcm3168a_spi_remove, + .id_table = pcm3168a_spi_id, + .driver = { + .name = "pcm3168a", + .of_match_table = pcm3168a_of_match, + .pm = &pcm3168a_pm_ops, + }, +}; +module_spi_driver(pcm3168a_spi_driver); + +MODULE_DESCRIPTION("PCM3168A SPI codec driver"); +MODULE_AUTHOR("Damien Horsley "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c new file mode 100644 index 000000000000..44b268aa4dd8 --- /dev/null +++ b/sound/soc/codecs/pcm3168a.c @@ -0,0 +1,767 @@ +/* + * PCM3168A codec driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pcm3168a.h" + +#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define PCM3168A_FMT_I2S 0x0 +#define PCM3168A_FMT_LEFT_J 0x1 +#define PCM3168A_FMT_RIGHT_J 0x2 +#define PCM3168A_FMT_RIGHT_J_16 0x3 +#define PCM3168A_FMT_DSP_A 0x4 +#define PCM3168A_FMT_DSP_B 0x5 +#define PCM3168A_FMT_DSP_MASK 0x4 + +#define PCM3168A_NUM_SUPPLIES 6 +static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { + "VDD1", + "VDD2", + "VCCAD1", + "VCCAD2", + "VCCDA1", + "VCCDA2" +}; + +struct pcm3168a_priv { + struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; + struct regmap *regmap; + struct clk *scki; + bool adc_master_mode; + bool dac_master_mode; + unsigned long sysclk; + unsigned int adc_fmt; + unsigned int dac_fmt; +}; + +static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off); + +static const char *const pcm3168a_volume_type[] = { + "Individual", "Master + Individual" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type); + +static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult); + +static const char *const pcm3168a_demp[] = { + "Disabled", "48khz", "44.1khz", "32khz" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp); + +static const char *const pcm3168a_zf_func[] = { + "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND", + "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func); + +static const char *const pcm3168a_pol[] = { "Active High", "Active Low" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol); + +static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" }; + +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD, + 0, 1, pcm3168a_con); +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD, + 2, 3, pcm3168a_con); +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD, + 4, 5, pcm3168a_con); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol); + +/* -100db to 0db, register values 0-54 cause mute */ +static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1); + +/* -100db to 20db, register values 0-14 cause mute */ +static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1); + +static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { + SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT, + PCM3168A_DAC_PSMDA_SHIFT, 1, 1), + SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off), + SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off), + SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off), + SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off), + SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0), + SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), + SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), + SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), + SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0), + SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0), + SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0), + SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0), + SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), + SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), + SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), + SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func), + SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol), + SOC_SINGLE_RANGE_TLV("Master Playback Volume", + PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0, + pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START, + PCM3168A_DAC_VOL_CHAN_START + 1, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 2, + PCM3168A_DAC_VOL_CHAN_START + 3, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 4, + PCM3168A_DAC_VOL_CHAN_START + 5, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 6, + PCM3168A_DAC_VOL_CHAN_START + 7, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT, 1, 1), + SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT + 1, 1, 1), + SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT + 2, 1, 1), + SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con), + SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con), + SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con), + SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0), + SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0), + SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0), + SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), + SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), + SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), + SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0), + SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0), + SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0), + SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), + SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), + SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), + SOC_SINGLE_RANGE_TLV("Master Capture Volume", + PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0, + pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START, + PCM3168A_ADC_VOL_CHAN_START + 1, + 0, 14, 255, 0, pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START + 2, + PCM3168A_ADC_VOL_CHAN_START + 3, + 0, 14, 255, 0, pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START + 4, + PCM3168A_ADC_VOL_CHAN_START + 5, + 0, 14, 255, 0, pcm3168a_adc_tlv) +}; + +static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT, 1), + SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 1, 1), + SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 2, 1), + SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 3, 1), + + SND_SOC_DAPM_OUTPUT("AOUT1L"), + SND_SOC_DAPM_OUTPUT("AOUT1R"), + SND_SOC_DAPM_OUTPUT("AOUT2L"), + SND_SOC_DAPM_OUTPUT("AOUT2R"), + SND_SOC_DAPM_OUTPUT("AOUT3L"), + SND_SOC_DAPM_OUTPUT("AOUT3R"), + SND_SOC_DAPM_OUTPUT("AOUT4L"), + SND_SOC_DAPM_OUTPUT("AOUT4R"), + + SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT, 1), + SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT + 1, 1), + SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT + 2, 1), + + SND_SOC_DAPM_INPUT("AIN1L"), + SND_SOC_DAPM_INPUT("AIN1R"), + SND_SOC_DAPM_INPUT("AIN2L"), + SND_SOC_DAPM_INPUT("AIN2R"), + SND_SOC_DAPM_INPUT("AIN3L"), + SND_SOC_DAPM_INPUT("AIN3R") +}; + +static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = { + /* Playback */ + { "AOUT1L", NULL, "DAC1" }, + { "AOUT1R", NULL, "DAC1" }, + + { "AOUT2L", NULL, "DAC2" }, + { "AOUT2R", NULL, "DAC2" }, + + { "AOUT3L", NULL, "DAC3" }, + { "AOUT3R", NULL, "DAC3" }, + + { "AOUT4L", NULL, "DAC4" }, + { "AOUT4R", NULL, "DAC4" }, + + /* Capture */ + { "ADC1", NULL, "AIN1L" }, + { "ADC1", NULL, "AIN1R" }, + + { "ADC2", NULL, "AIN2L" }, + { "ADC2", NULL, "AIN2R" }, + + { "ADC3", NULL, "AIN3L" }, + { "ADC3", NULL, "AIN3R" } +}; + +static unsigned int pcm3168a_scki_ratios[] = { + 768, + 512, + 384, + 256, + 192, + 128 +}; + +#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios) +#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2) + +#define PCM1368A_MAX_SYSCLK 36864000 + +static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a) +{ + int ret; + + ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0); + if (ret) + return ret; + + /* Internal reset is de-asserted after 3846 SCKI cycles */ + msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); + + return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, + PCM3168A_MRST_MASK | PCM3168A_SRST_MASK); +} + +static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + + regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0); + + return 0; +} + +static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec); + + if (freq > PCM1368A_MAX_SYSCLK) + return -EINVAL; + + pcm3168a->sysclk = freq; + + return 0; +} + +static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int format, bool dac) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + u32 fmt, reg, mask, shift; + bool master_mode; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + fmt = PCM3168A_FMT_LEFT_J; + break; + case SND_SOC_DAIFMT_I2S: + fmt = PCM3168A_FMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + fmt = PCM3168A_FMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + fmt = PCM3168A_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + fmt = PCM3168A_FMT_DSP_B; + break; + default: + dev_err(codec->dev, "unsupported dai format\n"); + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + master_mode = false; + break; + case SND_SOC_DAIFMT_CBM_CFM: + master_mode = true; + break; + default: + dev_err(codec->dev, "unsupported master/slave mode\n"); + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + if (dac) { + reg = PCM3168A_DAC_PWR_MST_FMT; + mask = PCM3168A_DAC_FMT_MASK; + shift = PCM3168A_DAC_FMT_SHIFT; + pcm3168a->dac_master_mode = master_mode; + pcm3168a->dac_fmt = fmt; + } else { + reg = PCM3168A_ADC_MST_FMT; + mask = PCM3168A_ADC_FMTAD_MASK; + shift = PCM3168A_ADC_FMTAD_SHIFT; + pcm3168a->adc_master_mode = master_mode; + pcm3168a->adc_fmt = fmt; + } + + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + + return 0; +} + +static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai, + unsigned int format) +{ + return pcm3168a_set_dai_fmt(dai, format, true); +} + +static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai, + unsigned int format) +{ + return pcm3168a_set_dai_fmt(dai, format, false); +} + +static int pcm3168a_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + bool tx, master_mode; + u32 val, mask, shift, reg; + unsigned int rate, channels, fmt, ratio, max_ratio; + int i, min_frame_size; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + ratio = pcm3168a->sysclk / rate; + + tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + if (tx) { + max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; + reg = PCM3168A_DAC_PWR_MST_FMT; + mask = PCM3168A_DAC_MSDA_MASK; + shift = PCM3168A_DAC_MSDA_SHIFT; + master_mode = pcm3168a->dac_master_mode; + fmt = pcm3168a->dac_fmt; + } else { + max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; + reg = PCM3168A_ADC_MST_FMT; + mask = PCM3168A_ADC_MSAD_MASK; + shift = PCM3168A_ADC_MSAD_SHIFT; + master_mode = pcm3168a->adc_master_mode; + fmt = pcm3168a->adc_fmt; + } + + for (i = 0; i < max_ratio; i++) { + if (pcm3168a_scki_ratios[i] == ratio) + break; + } + + if (i == max_ratio) { + dev_err(codec->dev, "unsupported sysclk ratio\n"); + return -EINVAL; + } + + min_frame_size = params_width(params) * 2; + switch (min_frame_size) { + case 32: + if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) { + dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n"); + return -EINVAL; + } + fmt = PCM3168A_FMT_RIGHT_J_16; + break; + case 48: + if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) { + dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n"); + return -EINVAL; + } + break; + case 64: + break; + default: + dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size); + return -EINVAL; + } + + if (master_mode) + val = ((i + 1) << shift); + else + val = 0; + + regmap_update_bits(pcm3168a->regmap, reg, mask, val); + + if (tx) { + mask = PCM3168A_DAC_FMT_MASK; + shift = PCM3168A_DAC_FMT_SHIFT; + } else { + mask = PCM3168A_ADC_FMTAD_MASK; + shift = PCM3168A_ADC_FMTAD_SHIFT; + } + + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + + return 0; +} + +static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { + .set_fmt = pcm3168a_set_dai_fmt_dac, + .set_sysclk = pcm3168a_set_dai_sysclk, + .hw_params = pcm3168a_hw_params, + .digital_mute = pcm3168a_digital_mute +}; + +static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { + .set_fmt = pcm3168a_set_dai_fmt_adc, + .set_sysclk = pcm3168a_set_dai_sysclk, + .hw_params = pcm3168a_hw_params +}; + +static struct snd_soc_dai_driver pcm3168a_dais[] = { + { + .name = "pcm3168a-dac", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = PCM3168A_FORMATS + }, + .ops = &pcm3168a_dac_dai_ops + }, + { + .name = "pcm3168a-adc", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = PCM3168A_FORMATS + }, + .ops = &pcm3168a_adc_dai_ops + }, +}; + +static const struct reg_default pcm3168a_reg_default[] = { + { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK }, + { PCM3168A_DAC_PWR_MST_FMT, 0x00 }, + { PCM3168A_DAC_OP_FLT, 0x00 }, + { PCM3168A_DAC_INV, 0x00 }, + { PCM3168A_DAC_MUTE, 0x00 }, + { PCM3168A_DAC_ZERO, 0x00 }, + { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 }, + { PCM3168A_DAC_VOL_MASTER, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff }, + { PCM3168A_ADC_SMODE, 0x00 }, + { PCM3168A_ADC_MST_FMT, 0x00 }, + { PCM3168A_ADC_PWR_HPFB, 0x00 }, + { PCM3168A_ADC_SEAD, 0x00 }, + { PCM3168A_ADC_INV, 0x00 }, + { PCM3168A_ADC_MUTE, 0x00 }, + { PCM3168A_ADC_OV, 0x00 }, + { PCM3168A_ADC_ATT_OVF, 0x00 }, + { PCM3168A_ADC_VOL_MASTER, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 } +}; + +static bool pcm3168a_readable_register(struct device *dev, unsigned int reg) +{ + if (reg >= PCM3168A_RST_SMODE) + return true; + else + return false; +} + +static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PCM3168A_DAC_ZERO: + case PCM3168A_ADC_OV: + return true; + default: + return false; + } +} + +static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg < PCM3168A_RST_SMODE) + return false; + + switch (reg) { + case PCM3168A_DAC_ZERO: + case PCM3168A_ADC_OV: + return false; + default: + return true; + } +} + +const struct regmap_config pcm3168a_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = PCM3168A_ADC_VOL_CHAN_START + 5, + .reg_defaults = pcm3168a_reg_default, + .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default), + .readable_reg = pcm3168a_readable_register, + .volatile_reg = pcm3168a_volatile_register, + .writeable_reg = pcm3168a_writeable_register, + .cache_type = REGCACHE_FLAT +}; +EXPORT_SYMBOL_GPL(pcm3168a_regmap); + +static const struct snd_soc_codec_driver pcm3168a_driver = { + .idle_bias_off = true, + .controls = pcm3168a_snd_controls, + .num_controls = ARRAY_SIZE(pcm3168a_snd_controls), + .dapm_widgets = pcm3168a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets), + .dapm_routes = pcm3168a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes) +}; + +int pcm3168a_probe(struct device *dev, struct regmap *regmap) +{ + struct pcm3168a_priv *pcm3168a; + int ret, i; + + pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL); + if (pcm3168a == NULL) + return -ENOMEM; + + dev_set_drvdata(dev, pcm3168a); + + pcm3168a->scki = devm_clk_get(dev, "scki"); + if (IS_ERR(pcm3168a->scki)) { + ret = PTR_ERR(pcm3168a->scki); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to acquire clock 'scki': %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(pcm3168a->scki); + if (ret) { + dev_err(dev, "Failed to enable mclk: %d\n", ret); + return ret; + } + + pcm3168a->sysclk = clk_get_rate(pcm3168a->scki); + + for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++) + pcm3168a->supplies[i].supply = pcm3168a_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_clk; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + if (ret) { + dev_err(dev, "failed to enable supplies: %d\n", ret); + goto err_clk; + } + + pcm3168a->regmap = regmap; + if (IS_ERR(pcm3168a->regmap)) { + ret = PTR_ERR(pcm3168a->regmap); + dev_err(dev, "failed to allocate regmap: %d\n", ret); + goto err_regulator; + } + + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais, + ARRAY_SIZE(pcm3168a_dais)); + if (ret) { + dev_err(dev, "failed to register codec: %d\n", ret); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); +err_clk: + clk_disable_unprepare(pcm3168a->scki); + + return ret; +} +EXPORT_SYMBOL_GPL(pcm3168a_probe); + +void pcm3168a_remove(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + snd_soc_unregister_codec(dev); + pm_runtime_disable(dev); + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + clk_disable_unprepare(pcm3168a->scki); +} +EXPORT_SYMBOL_GPL(pcm3168a_remove); + +#ifdef CONFIG_PM +static int pcm3168a_rt_resume(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(pcm3168a->scki); + if (ret) { + dev_err(dev, "Failed to enable mclk: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + goto err_clk; + } + + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } + + regcache_cache_only(pcm3168a->regmap, false); + + regcache_mark_dirty(pcm3168a->regmap); + + ret = regcache_sync(pcm3168a->regmap); + if (ret) { + dev_err(dev, "Failed to sync regmap: %d\n", ret); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); +err_clk: + clk_disable_unprepare(pcm3168a->scki); + + return ret; +} + +static int pcm3168a_rt_suspend(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + regcache_cache_only(pcm3168a->regmap, true); + + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + + clk_disable_unprepare(pcm3168a->scki); + + return 0; +} +#endif + +const struct dev_pm_ops pcm3168a_pm_ops = { + SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL) +}; +EXPORT_SYMBOL_GPL(pcm3168a_pm_ops); + +MODULE_DESCRIPTION("PCM3168A codec driver"); +MODULE_AUTHOR("Damien Horsley "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h new file mode 100644 index 000000000000..56c8332d82fb --- /dev/null +++ b/sound/soc/codecs/pcm3168a.h @@ -0,0 +1,100 @@ +/* + * PCM3168A codec driver header + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#ifndef __PCM3168A_H__ +#define __PCM3168A_H__ + +extern const struct dev_pm_ops pcm3168a_pm_ops; +extern const struct regmap_config pcm3168a_regmap; + +extern int pcm3168a_probe(struct device *dev, struct regmap *regmap); +extern void pcm3168a_remove(struct device *dev); + +#define PCM3168A_RST_SMODE 0x40 +#define PCM3168A_MRST_MASK 0x80 +#define PCM3168A_SRST_MASK 0x40 +#define PCM3168A_DAC_SRDA_SHIFT 0 +#define PCM3168A_DAC_SRDA_MASK 0x3 + +#define PCM3168A_DAC_PWR_MST_FMT 0x41 +#define PCM3168A_DAC_PSMDA_SHIFT 7 +#define PCM3168A_DAC_PSMDA_MASK 0x80 +#define PCM3168A_DAC_MSDA_SHIFT 4 +#define PCM3168A_DAC_MSDA_MASK 0x70 +#define PCM3168A_DAC_FMT_SHIFT 0 +#define PCM3168A_DAC_FMT_MASK 0xf + +#define PCM3168A_DAC_OP_FLT 0x42 +#define PCM3168A_DAC_OPEDA_SHIFT 4 +#define PCM3168A_DAC_OPEDA_MASK 0xf0 +#define PCM3168A_DAC_FLT_SHIFT 0 +#define PCM3168A_DAC_FLT_MASK 0xf + +#define PCM3168A_DAC_INV 0x43 + +#define PCM3168A_DAC_MUTE 0x44 + +#define PCM3168A_DAC_ZERO 0x45 + +#define PCM3168A_DAC_ATT_DEMP_ZF 0x46 +#define PCM3168A_DAC_ATMDDA_MASK 0x80 +#define PCM3168A_DAC_ATMDDA_SHIFT 7 +#define PCM3168A_DAC_ATSPDA_MASK 0x40 +#define PCM3168A_DAC_ATSPDA_SHIFT 6 +#define PCM3168A_DAC_DEMP_SHIFT 4 +#define PCM3168A_DAC_DEMP_MASK 0x30 +#define PCM3168A_DAC_AZRO_SHIFT 1 +#define PCM3168A_DAC_AZRO_MASK 0xe +#define PCM3168A_DAC_ZREV_MASK 0x1 +#define PCM3168A_DAC_ZREV_SHIFT 0 + +#define PCM3168A_DAC_VOL_MASTER 0x47 + +#define PCM3168A_DAC_VOL_CHAN_START 0x48 + +#define PCM3168A_ADC_SMODE 0x50 +#define PCM3168A_ADC_SRAD_SHIFT 0 +#define PCM3168A_ADC_SRAD_MASK 0x3 + +#define PCM3168A_ADC_MST_FMT 0x51 +#define PCM3168A_ADC_MSAD_SHIFT 4 +#define PCM3168A_ADC_MSAD_MASK 0x70 +#define PCM3168A_ADC_FMTAD_SHIFT 0 +#define PCM3168A_ADC_FMTAD_MASK 0x7 + +#define PCM3168A_ADC_PWR_HPFB 0x52 +#define PCM3168A_ADC_PSVAD_SHIFT 4 +#define PCM3168A_ADC_PSVAD_MASK 0x70 +#define PCM3168A_ADC_BYP_SHIFT 0 +#define PCM3168A_ADC_BYP_MASK 0x7 + +#define PCM3168A_ADC_SEAD 0x53 + +#define PCM3168A_ADC_INV 0x54 + +#define PCM3168A_ADC_MUTE 0x55 + +#define PCM3168A_ADC_OV 0x56 + +#define PCM3168A_ADC_ATT_OVF 0x57 +#define PCM3168A_ADC_ATMDAD_MASK 0x80 +#define PCM3168A_ADC_ATMDAD_SHIFT 7 +#define PCM3168A_ADC_ATSPAD_MASK 0x40 +#define PCM3168A_ADC_ATSPAD_SHIFT 6 +#define PCM3168A_ADC_OVFP_MASK 0x1 +#define PCM3168A_ADC_OVFP_SHIFT 0 + +#define PCM3168A_ADC_VOL_MASTER 0x58 + +#define PCM3168A_ADC_VOL_CHAN_START 0x59 + +#endif -- cgit v1.2.3 From 078e71838cdff1c2a1a33e65459954adda9a4641 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Dec 2015 16:08:26 +0000 Subject: ASoC: wm_adsp: Replace debugfs lock with more general DSP power lock Most events around the DSP just need to be locked to ensure that the DSP can't change power state whilst they are happening. This includes the debugfs entries and this will make sorting the rest of the locking simpler. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 75 ++++++++++++++++++++++++++-------------------- sound/soc/codecs/wm_adsp.h | 3 +- 2 files changed, 44 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 905ae993440b..19f05933de54 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -275,30 +275,24 @@ static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - mutex_lock(&dsp->debugfs_lock); kfree(dsp->wmfw_file_name); dsp->wmfw_file_name = tmp; - mutex_unlock(&dsp->debugfs_lock); } static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - mutex_lock(&dsp->debugfs_lock); kfree(dsp->bin_file_name); dsp->bin_file_name = tmp; - mutex_unlock(&dsp->debugfs_lock); } static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) { - mutex_lock(&dsp->debugfs_lock); kfree(dsp->wmfw_file_name); kfree(dsp->bin_file_name); dsp->wmfw_file_name = NULL; dsp->bin_file_name = NULL; - mutex_unlock(&dsp->debugfs_lock); } static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, @@ -308,7 +302,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, struct wm_adsp *dsp = file->private_data; ssize_t ret; - mutex_lock(&dsp->debugfs_lock); + mutex_lock(&dsp->pwr_lock); if (!dsp->wmfw_file_name || !dsp->running) ret = 0; @@ -317,7 +311,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, dsp->wmfw_file_name, strlen(dsp->wmfw_file_name)); - mutex_unlock(&dsp->debugfs_lock); + mutex_unlock(&dsp->pwr_lock); return ret; } @@ -328,7 +322,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, struct wm_adsp *dsp = file->private_data; ssize_t ret; - mutex_lock(&dsp->debugfs_lock); + mutex_lock(&dsp->pwr_lock); if (!dsp->bin_file_name || !dsp->running) ret = 0; @@ -337,7 +331,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, dsp->bin_file_name, strlen(dsp->bin_file_name)); - mutex_unlock(&dsp->debugfs_lock); + mutex_unlock(&dsp->pwr_lock); return ret; } @@ -1799,9 +1793,8 @@ int wm_adsp1_init(struct wm_adsp *dsp) { INIT_LIST_HEAD(&dsp->alg_regions); -#ifdef CONFIG_DEBUG_FS - mutex_init(&dsp->debugfs_lock); -#endif + mutex_init(&dsp->pwr_lock); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp1_init); @@ -1820,6 +1813,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, dsp->card = codec->component.card; + mutex_lock(&dsp->pwr_lock); + switch (event) { case SND_SOC_DAPM_POST_PMU: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, @@ -1834,7 +1829,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, if (ret != 0) { adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); - return ret; + goto err_mutex; } val = (val & dsp->sysclk_mask) @@ -1846,31 +1841,31 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, if (ret != 0) { adsp_err(dsp, "Failed to set clock rate: %d\n", ret); - return ret; + goto err_mutex; } } ret = wm_adsp_load(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp1_setup_algs(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp_load_coeff(dsp); if (ret != 0) - goto err; + goto err_ena; /* Initialize caches for enabled and unset controls */ ret = wm_coeff_init_control_caches(dsp); if (ret != 0) - goto err; + goto err_ena; /* Sync set controls */ ret = wm_coeff_sync_controls(dsp); if (ret != 0) - goto err; + goto err_ena; /* Start the core running */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, @@ -1905,11 +1900,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, break; } + mutex_unlock(&dsp->pwr_lock); + return 0; -err: +err_ena: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_SYS_ENA, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); + return ret; } EXPORT_SYMBOL_GPL(wm_adsp1_event); @@ -1955,6 +1955,8 @@ static void wm_adsp2_boot_work(struct work_struct *work) int ret; unsigned int val; + mutex_lock(&dsp->pwr_lock); + /* * For simplicity set the DSP clock rate to be the * SYSCLK rate rather than making it configurable. @@ -1962,7 +1964,7 @@ static void wm_adsp2_boot_work(struct work_struct *work) ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); if (ret != 0) { adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); - return; + goto err_mutex; } val = (val & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; @@ -1972,42 +1974,46 @@ static void wm_adsp2_boot_work(struct work_struct *work) ADSP2_CLK_SEL_MASK, val); if (ret != 0) { adsp_err(dsp, "Failed to set clock rate: %d\n", ret); - return; + goto err_mutex; } ret = wm_adsp2_ena(dsp); if (ret != 0) - return; + goto err_mutex; ret = wm_adsp_load(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp2_setup_algs(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp_load_coeff(dsp); if (ret != 0) - goto err; + goto err_ena; /* Initialize caches for enabled and unset controls */ ret = wm_coeff_init_control_caches(dsp); if (ret != 0) - goto err; + goto err_ena; /* Sync set controls */ ret = wm_coeff_sync_controls(dsp); if (ret != 0) - goto err; + goto err_ena; dsp->running = true; + mutex_unlock(&dsp->pwr_lock); + return; -err: +err_ena: regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); } int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, @@ -2060,6 +2066,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, /* Log firmware state, it can be useful for analysis */ wm_adsp2_show_fw_status(dsp); + mutex_lock(&dsp->pwr_lock); + wm_adsp_debugfs_clear(dsp); dsp->fw_id = 0; @@ -2086,6 +2094,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, kfree(alg_region); } + mutex_unlock(&dsp->pwr_lock); + adsp_dbg(dsp, "Shutdown complete\n"); break; @@ -2138,9 +2148,8 @@ int wm_adsp2_init(struct wm_adsp *dsp) INIT_LIST_HEAD(&dsp->ctl_list); INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); -#ifdef CONFIG_DEBUG_FS - mutex_init(&dsp->debugfs_lock); -#endif + mutex_init(&dsp->pwr_lock); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_init); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 2d117cf0e953..93764139313b 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -59,9 +59,10 @@ struct wm_adsp { struct work_struct boot_work; + struct mutex pwr_lock; + #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; - struct mutex debugfs_lock; char *wmfw_file_name; char *bin_file_name; #endif -- cgit v1.2.3 From d27c5e155c69a4c45e9833fbf66aa580dcd01624 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Dec 2015 16:08:28 +0000 Subject: ASoC: wm_adsp: Add power lock for firmware change control We should hold the DSP power lock whilst changing the firmware since we need to check if it is running first. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 19f05933de54..fd85a8cc7234 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -451,6 +451,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + int ret = 0; if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw) return 0; @@ -458,12 +459,16 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) return -EINVAL; + mutex_lock(&dsp[e->shift_l].pwr_lock); + if (dsp[e->shift_l].running) - return -EBUSY; + ret = -EBUSY; + else + dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; - dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; + mutex_unlock(&dsp[e->shift_l].pwr_lock); - return 0; + return ret; } static const struct soc_enum wm_adsp_fw_enum[] = { -- cgit v1.2.3 From 7585a5b0ab5511376f032e421f7de72fe7e160d5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Dec 2015 16:08:25 +0000 Subject: ASoC: wm_adsp: Fixup some minor formatting and checkpatch errors Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 27 +++++++++++++-------------- sound/soc/codecs/wm_adsp.h | 4 ++-- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index fd85a8cc7234..3a314f2a3f61 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -543,10 +543,10 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) be16_to_cpu(scratch[3])); } -static int wm_coeff_info(struct snd_kcontrol *kcontrol, +static int wm_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = ctl->len; @@ -592,10 +592,10 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, return 0; } -static int wm_coeff_put(struct snd_kcontrol *kcontrol, +static int wm_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; memcpy(ctl->cache, p, ctl->len); @@ -646,10 +646,10 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, return 0; } -static int wm_coeff_get(struct snd_kcontrol *kcontrol, +static int wm_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { @@ -828,8 +828,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, break; } - list_for_each_entry(ctl, &dsp->ctl_list, - list) { + list_for_each_entry(ctl, &dsp->ctl_list, list) { if (!strcmp(ctl->name, name)) { if (!ctl->enabled) ctl->enabled = 1; @@ -1108,7 +1107,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) goto out_fw; } - header = (void*)&firmware->data[0]; + header = (void *)&firmware->data[0]; if (memcmp(&header->magic[0], "WMFW", 4) != 0) { adsp_err(dsp, "%s: invalid magic\n", file); @@ -1188,7 +1187,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) offset = le32_to_cpu(region->offset) & 0xffffff; type = be32_to_cpu(region->type) & 0xff; mem = wm_adsp_find_region(dsp, type); - + switch (type) { case WMFW_NAME_TEXT: region_name = "Firmware name"; @@ -1645,7 +1644,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) goto out_fw; } - hdr = (void*)&firmware->data[0]; + hdr = (void *)&firmware->data[0]; if (memcmp(hdr->magic, "WMDR", 4) != 0) { adsp_err(dsp, "%s: invalid magic\n", file); goto out_fw; @@ -1671,7 +1670,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) blocks = 0; while (pos < firmware->size && pos - firmware->size > sizeof(*blk)) { - blk = (void*)(&firmware->data[pos]); + blk = (void *)(&firmware->data[pos]); type = le16_to_cpu(blk->type); offset = le16_to_cpu(blk->offset); @@ -1814,7 +1813,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct wm_adsp_alg_region *alg_region; struct wm_coeff_ctl *ctl; int ret; - int val; + unsigned int val; dsp->card = codec->component.card; @@ -1829,7 +1828,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, * For simplicity set the DSP clock rate to be the * SYSCLK rate rather than making it configurable. */ - if(dsp->sysclk_reg) { + if (dsp->sysclk_reg) { ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); if (ret != 0) { adsp_err(dsp, "Failed to read SYSCLK state: %d\n", diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 93764139313b..d2a8c78ed50b 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -45,8 +45,8 @@ struct wm_adsp { struct list_head alg_regions; - int fw_id; - int fw_id_version; + unsigned int fw_id; + unsigned int fw_id_version; const struct wm_adsp_region *mem; int num_mems; -- cgit v1.2.3 From 168d10e74c4efd945a37adeb134f096505e62b49 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 8 Dec 2015 16:08:27 +0000 Subject: ASoC: wm_adsp: Add locking to DSP firmware controls Locking is currently missing from the DSP firmware controls, which can lead to some race conditions if the controls are accessed as the DSP powers up or down. This patch adds them to the new power lock. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 3a314f2a3f61..b083642718f0 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -597,14 +597,19 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, { struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); memcpy(ctl->cache, p, ctl->len); ctl->set = 1; - if (!ctl->enabled) - return 0; + if (ctl->enabled) + ret = wm_coeff_write_control(ctl, p, ctl->len); - return wm_coeff_write_control(ctl, p, ctl->len); + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; } static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, @@ -651,17 +656,22 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, { struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled) - return wm_coeff_read_control(ctl, p, ctl->len); + ret = wm_coeff_read_control(ctl, p, ctl->len); else - return -EPERM; + ret = -EPERM; + } else { + memcpy(p, ctl->cache, ctl->len); } - memcpy(p, ctl->cache, ctl->len); + mutex_unlock(&ctl->dsp->pwr_lock); - return 0; + return ret; } struct wmfw_ctl_work { -- cgit v1.2.3 From 395036225390a940cba7cec5c2306a6999d13d94 Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Thu, 10 Dec 2015 14:40:12 +0000 Subject: ASoC: img: Add driver for Pistachio internal DAC Add driver for Pistachio Internal DAC Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/img/Kconfig | 8 + sound/soc/img/Makefile | 2 + sound/soc/img/pistachio-internal-dac.c | 287 +++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 sound/soc/img/pistachio-internal-dac.c (limited to 'sound') diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig index d08537ecb915..857a9510ee1c 100644 --- a/sound/soc/img/Kconfig +++ b/sound/soc/img/Kconfig @@ -42,3 +42,11 @@ config SND_SOC_IMG_SPDIF_OUT help Say Y or M if you want to add support for SPDIF out driver for Imagination Technologies SPDIF out device. + + +config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC + tristate "Support for Pistachio SoC Internal DAC Driver" + depends on SND_SOC_IMG + help + Say Y or M if you want to add support for Pistachio internal DAC + driver for Imagination Technologies Pistachio internal DAC device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile index 1a44fb4b08fe..0508c1ced636 100644 --- a/sound/soc/img/Makefile +++ b/sound/soc/img/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o + +obj-$(CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC) += pistachio-internal-dac.o diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c new file mode 100644 index 000000000000..162a0fd68c7b --- /dev/null +++ b/sound/soc/img/pistachio-internal-dac.c @@ -0,0 +1,287 @@ +/* + * Pistachio internal dac driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PISTACHIO_INTERNAL_DAC_CTRL 0x40 +#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2 +#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_SRST 0x44 +#define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000 + +#define PISTACHIO_INTERNAL_DAC_PWR 0x1 +#define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* codec private data */ +struct pistachio_internal_dac { + struct regmap *regmap; + struct regulator *supply; + bool mute; +}; + +static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = { + SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1) +}; + +static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("AOUTL"), + SND_SOC_DAPM_OUTPUT("AOUTR"), +}; + +static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = { + { "AOUTL", NULL, "DAC" }, + { "AOUTR", NULL, "DAC" }, +}; + +static void pistachio_internal_dac_reg_writel(struct regmap *top_regs, + u32 val, u32 reg) +{ + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK, + reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK, + val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0); +} + +static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac) +{ + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK); + + pistachio_internal_dac_reg_writel(dac->regmap, 0, + PISTACHIO_INTERNAL_DAC_PWR); +} + +static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac) +{ + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, + PISTACHIO_INTERNAL_DAC_SRST_MASK, + PISTACHIO_INTERNAL_DAC_SRST_MASK); + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, + PISTACHIO_INTERNAL_DAC_SRST_MASK, 0); + + pistachio_internal_dac_reg_writel(dac->regmap, + PISTACHIO_INTERNAL_DAC_PWR_MASK, + PISTACHIO_INTERNAL_DAC_PWR); + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0); +} + +static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = { + { + .name = "pistachio_internal_dac", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = PISTACHIO_INTERNAL_DAC_FORMATS, + } + }, +}; + +static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec) +{ + struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec); + + snd_soc_codec_init_regmap(codec, dac->regmap); + + return 0; +} + +static const struct snd_soc_codec_driver pistachio_internal_dac_driver = { + .probe = pistachio_internal_dac_codec_probe, + .idle_bias_off = true, + .controls = pistachio_internal_dac_snd_controls, + .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls), + .dapm_widgets = pistachio_internal_dac_widgets, + .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets), + .dapm_routes = pistachio_internal_dac_routes, + .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), +}; + +static int pistachio_internal_dac_probe(struct platform_device *pdev) +{ + struct pistachio_internal_dac *dac; + int ret, voltage; + struct device *dev = &pdev->dev; + u32 reg; + + dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL); + + if (!dac) + return -ENOMEM; + + platform_set_drvdata(pdev, dac); + + dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "img,cr-top"); + if (IS_ERR(dac->regmap)) + return PTR_ERR(dac->regmap); + + dac->supply = devm_regulator_get(dev, "VDD"); + if (IS_ERR(dac->supply)) { + ret = PTR_ERR(dac->supply); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret); + return ret; + } + + ret = regulator_enable(dac->supply); + if (ret) { + dev_err(dev, "failed to enable supply: %d\n", ret); + return ret; + } + + voltage = regulator_get_voltage(dac->supply); + + switch (voltage) { + case 1800000: + reg = 0; + break; + case 3300000: + reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK; + break; + default: + dev_err(dev, "invalid voltage: %d\n", voltage); + ret = -EINVAL; + goto err_regulator; + } + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg); + + pistachio_internal_dac_pwr_off(dac); + pistachio_internal_dac_pwr_on(dac); + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver, + pistachio_internal_dac_dais, + ARRAY_SIZE(pistachio_internal_dac_dais)); + if (ret) { + dev_err(dev, "failed to register codec: %d\n", ret); + goto err_pwr; + } + + return 0; + +err_pwr: + pm_runtime_disable(&pdev->dev); + pistachio_internal_dac_pwr_off(dac); +err_regulator: + regulator_disable(dac->supply); + + return ret; +} + +static int pistachio_internal_dac_remove(struct platform_device *pdev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pistachio_internal_dac_pwr_off(dac); + regulator_disable(dac->supply); + + return 0; +} + +#ifdef CONFIG_PM +static int pistachio_internal_dac_rt_resume(struct device *dev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(dac->supply); + if (ret) { + dev_err(dev, "failed to enable supply: %d\n", ret); + return ret; + } + + pistachio_internal_dac_pwr_on(dac); + + return 0; +} + +static int pistachio_internal_dac_rt_suspend(struct device *dev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(dev); + + pistachio_internal_dac_pwr_off(dac); + + regulator_disable(dac->supply); + + return 0; +} +#endif + +static const struct dev_pm_ops pistachio_internal_dac_pm_ops = { + SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend, + pistachio_internal_dac_rt_resume, NULL) +}; + +static const struct of_device_id pistachio_internal_dac_of_match[] = { + { .compatible = "img,pistachio-internal-dac" }, + {} +}; +MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match); + +static struct platform_driver pistachio_internal_dac_plat_driver = { + .driver = { + .name = "img-pistachio-internal-dac", + .of_match_table = pistachio_internal_dac_of_match, + .pm = &pistachio_internal_dac_pm_ops + }, + .probe = pistachio_internal_dac_probe, + .remove = pistachio_internal_dac_remove +}; +module_platform_driver(pistachio_internal_dac_plat_driver); + +MODULE_DESCRIPTION("Pistachio Internal DAC driver"); +MODULE_AUTHOR("Damien Horsley "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 32e69bad8ed9ed4e1bf1fd8217b61d5f87996253 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Fri, 11 Dec 2015 11:07:37 +0800 Subject: ASoC: Atmel: ClassD: unregister codec when error occurs Add code to unregister codec in probe function, when the error occurs after the codec is registered. Signed-off-by: Songjun Wu Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-classd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 8276675730ef..f3ffb39bfe27 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -636,8 +636,10 @@ static int atmel_classd_probe(struct platform_device *pdev) /* register sound card */ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); - if (!card) - return -ENOMEM; + if (!card) { + ret = -ENOMEM; + goto unregister_codec; + } snd_soc_card_set_drvdata(card, dd); platform_set_drvdata(pdev, card); @@ -645,16 +647,20 @@ static int atmel_classd_probe(struct platform_device *pdev) ret = atmel_classd_asoc_card_init(dev, card); if (ret) { dev_err(dev, "failed to init sound card\n"); - return ret; + goto unregister_codec; } ret = devm_snd_soc_register_card(dev, card); if (ret) { dev_err(dev, "failed to register sound card: %d\n", ret); - return ret; + goto unregister_codec; } return 0; + +unregister_codec: + snd_soc_unregister_codec(dev); + return ret; } static int atmel_classd_remove(struct platform_device *pdev) -- cgit v1.2.3 From 906c7d690c3b80e4321178c083db8c14afb56bf8 Mon Sep 17 00:00:00 2001 From: PC Liao Date: Fri, 11 Dec 2015 11:33:51 +0800 Subject: ASoC: dpcm: Apply symmetry for DPCM DPCM does not fully support symmetry attributes. soc_pcm_apply_symmetry() is skipped in soc_pcm_open() for DPCM, without being applied elsewhere. So HW parameters cannot be correctly limited, and user space can do playback/capture at different rates while HW actually does not support it. soc_pcm_params_symmetry() will return error and the second stream stops. This patch adds soc_pcm_apply_symmetry() for FE, BE, and codec DAIs in DPCM path that was skipped in soc_pcm_open(). Signed-off-by: PC Liao Signed-off-by: Koro Chen Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c48232211c56..37de8af91f13 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1616,6 +1616,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, snd_pcm_stream_unlock_irq(substream); } +static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, + int stream) +{ + struct snd_soc_dpcm *dpcm; + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai; + int err; + + /* apply symmetry for FE */ + if (soc_pcm_has_symmetry(fe_substream)) + fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (fe_cpu_dai->active) { + err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); + if (err < 0) + return err; + } + + /* apply symmetry for BE */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + struct snd_pcm_substream *be_substream = + snd_soc_dpcm_get_substream(be, stream); + struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + int i; + + if (soc_pcm_has_symmetry(be_substream)) + be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (rtd->cpu_dai->active) { + err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai); + if (err < 0) + return err; + } + + for (i = 0; i < rtd->num_codecs; i++) { + if (rtd->codec_dais[i]->active) { + err = soc_pcm_apply_symmetry(be_substream, + rtd->codec_dais[i]); + if (err < 0) + return err; + } + } + } + + return 0; +} + static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) { struct snd_soc_pcm_runtime *fe = fe_substream->private_data; @@ -1644,6 +1694,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dpcm_set_fe_runtime(fe_substream); snd_pcm_limit_hw_rates(runtime); + ret = dpcm_apply_symmetry(fe_substream, stream); + if (ret < 0) { + dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n", + ret); + goto unwind; + } + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); return 0; -- cgit v1.2.3 From e6415b485059af183873e907662a3cdeefacb58b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 11 Dec 2015 19:43:56 +0100 Subject: ASoC: sun4i-codec: Rename codec dapm widgets and routes Rename the codec dapm widgets and routes with a _codec prefix. This is a preparation patch for adding card dapm widgets and routes. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 7a3fe1dca178..519ccb3444e8 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -532,7 +532,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0), }; -static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { +static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { /* Digital parts of the ADCs */ SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC, SUN4I_CODEC_ADC_FIFOC_EN_AD, 0, @@ -589,7 +589,7 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HP Left"), }; -static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { +static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { /* Left ADC / DAC Routes */ { "Left ADC", NULL, "ADC" }, { "Left DAC", NULL, "DAC" }, @@ -628,10 +628,10 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { static struct snd_soc_codec_driver sun4i_codec_codec = { .controls = sun4i_codec_widgets, .num_controls = ARRAY_SIZE(sun4i_codec_widgets), - .dapm_widgets = sun4i_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_dapm_widgets), - .dapm_routes = sun4i_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sun4i_codec_dapm_routes), + .dapm_widgets = sun4i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), + .dapm_routes = sun4i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), }; static const struct snd_soc_component_driver sun4i_codec_component = { -- cgit v1.2.3 From 405926276bfb316915c16e57a3943eb2cf4dd8fa Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 11 Dec 2015 19:43:57 +0100 Subject: ASoC: sun4i-codec: Add support for PA gpio pin Add support for PA gpio pin for controlling an external amplifier as used on some Allwinner boards. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 3 ++ sound/soc/sunxi/sun4i-codec.c | 35 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index c92966bd5488..0dce690f78f5 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -14,6 +14,9 @@ Required properties: - "apb": the parent APB clock for this controller - "codec": the parent module clock +Optional properties: +- allwinner,pa-gpios: gpio to enable external amplifier + Example: codec: codec@01c22c00 { #sound-dai-cells = <0>; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 519ccb3444e8..e6cc6a14718a 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,7 @@ struct sun4i_codec { struct regmap *regmap; struct clk *clk_apb; struct clk *clk_module; + struct gpio_desc *gpio_pa; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -709,6 +711,26 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, return link; }; +static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card); + + if (scodec->gpio_pa) + gpiod_set_value_cansleep(scodec->gpio_pa, + !!SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = { + { "Speaker", NULL, "Power Amplifier" }, +}; + static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) { struct snd_soc_card *card; @@ -723,6 +745,10 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) card->dev = dev; card->name = "sun4i-codec"; + card->dapm_widgets = sun4i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets); + card->dapm_routes = sun4i_codec_card_dapm_routes; + card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes); return card; }; @@ -774,6 +800,15 @@ static int sun4i_codec_probe(struct platform_device *pdev) return -EINVAL; } + scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", + GPIOD_OUT_LOW); + if (IS_ERR(scodec->gpio_pa)) { + ret = PTR_ERR(scodec->gpio_pa); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret); + return ret; + } + /* DMA configuration for TX FIFO */ scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; scodec->playback_dma_data.maxburst = 4; -- cgit v1.2.3 From af1086ba051aa33c559350a5fdb533acfe98a80c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 14 Dec 2015 20:06:13 +0800 Subject: ASoC: Intel: sst: fix the IRQ locked issue If driver received a message that it can't handle, it won't clear the corresponding bit and unmask interrupt, this may lock the IRQ and DSP can't send message anymore. To fix the issue, we should Always update IMRX after IPC. Here we always clear the DONE/BUSY bit and unmask the IRQ source, even when IPC failures have occurred previously. Signed-off-by: Liam Girdwood Modified-by: Jie Yang Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index b27f25f70730..ac60f1301e21 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -778,7 +778,6 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); struct sst_generic_ipc *ipc = &hsw->ipc; u32 ipcx, ipcd; - int handled; unsigned long flags; spin_lock_irqsave(&sst->spinlock, flags); @@ -790,34 +789,30 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) if (ipcx & SST_IPCX_DONE) { /* Handle Immediate reply from DSP Core */ - handled = hsw_process_reply(hsw, ipcx); + hsw_process_reply(hsw, ipcx); - if (handled > 0) { - /* clear DONE bit - tell DSP we have completed */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, - SST_IPCX_DONE, 0); + /* clear DONE bit - tell DSP we have completed */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, + SST_IPCX_DONE, 0); - /* unmask Done interrupt */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, - SST_IMRX_DONE, 0); - } + /* unmask Done interrupt */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, + SST_IMRX_DONE, 0); } /* new message from DSP */ if (ipcd & SST_IPCD_BUSY) { /* Handle Notification and Delayed reply from DSP Core */ - handled = hsw_process_notification(hsw); + hsw_process_notification(hsw); /* clear BUSY bit and set DONE bit - accept new messages */ - if (handled > 0) { - sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, - SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); + sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, + SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); - /* unmask busy interrupt */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, - SST_IMRX_BUSY, 0); - } + /* unmask busy interrupt */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, + SST_IMRX_BUSY, 0); } spin_unlock_irqrestore(&sst->spinlock, flags); -- cgit v1.2.3 From 4f0189be3d0b2ba7f23b46295e4063fa3298aa74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Dec 2015 16:44:08 +0100 Subject: ALSA: hda - Clean up the code to check bdl_pos_adj option Just a minor cleanup; instead of passing an array, pass the assigned bdl_pos_adj option value directory in struct azx. Also split the code to get the default bdl_pos_adj value for the change that will follow after this. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 3 +-- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 29 ++++++++++++++++------------- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 22dbfa563919..10c77074b4dc 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1050,8 +1050,7 @@ int azx_bus_init(struct azx *chip, const char *model, if (chip->get_position[0] != azx_get_pos_lpib || chip->get_position[1] != azx_get_pos_lpib) bus->core.use_posbuf = true; - if (chip->bdl_pos_adj) - bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index]; + bus->core.bdl_pos_adj = chip->bdl_pos_adj; if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) bus->core.corbrp_self_clear = true; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c1d28a657f19..a32ec9004edd 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -147,7 +147,7 @@ struct azx { #endif /* flags */ - const int *bdl_pos_adj; + int bdl_pos_adj; int poll_count; unsigned int running:1; unsigned int single_cmd:1; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index fe9bef339cea..a17bf0467edc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -632,7 +632,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 && pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2) /* NG - it's below the first next period boundary */ - return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1; + return chip->bdl_pos_adj ? 0 : -1; azx_dev->core.start_wallclk += wallclk; return 1; /* OK, it's fine */ } @@ -1488,6 +1488,17 @@ static void azx_probe_work(struct work_struct *work) azx_probe_continue(&hda->chip); } +static int default_bdl_pos_adj(struct azx *chip) +{ + switch (chip->driver_type) { + case AZX_DRIVER_ICH: + case AZX_DRIVER_PCH: + return 1; + default: + return 32; + } +} + /* * constructor */ @@ -1541,18 +1552,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, chip->single_cmd = single_cmd; azx_check_snoop_available(chip); - if (bdl_pos_adj[dev] < 0) { - switch (chip->driver_type) { - case AZX_DRIVER_ICH: - case AZX_DRIVER_PCH: - bdl_pos_adj[dev] = 1; - break; - default: - bdl_pos_adj[dev] = 32; - break; - } - } - chip->bdl_pos_adj = bdl_pos_adj; + if (bdl_pos_adj[dev] < 0) + chip->bdl_pos_adj = default_bdl_pos_adj(chip); + else + chip->bdl_pos_adj = bdl_pos_adj[dev]; err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); if (err < 0) { -- cgit v1.2.3 From 2cf721db4b78c11cb57d5a30888eb25ca04d9a29 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Dec 2015 16:49:36 +0100 Subject: ALSA: hda - Increase default bdl_pos_adj for Baytrail/Braswell Intel Atom processors seem to have a problem at recording when bdl_pos_adj is set to an odd value. When a value like 1 is used, it may drop the samples unexpectedly. Actually, for the old Atoms, we used to set AZX_DRIVER_SCH type, and this assigns 32 as default. Meanwhile the newer chips, Baytrail and Braswell, are set as AZX_DRIVER_PCH, and the lower default value, 1, is assigned. This patch changes the default values for these chipsets to a safer default, 32, again. Since changing the driver type (AZX_DRIVER_XXX) leads to the rename of the driver string, it would result in a possible regression. So, we can't change the type. Instead, in this patch, manual (ugly) PCI ID checks are added on top. A drawback by this increase is the slight increase of the latency, but it's a sub-ms order in normal situations, so mostly negligible. Reported-and-tested-by: Jochen Henneberg Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a17bf0467edc..56ef6b6fb546 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1490,6 +1490,15 @@ static void azx_probe_work(struct work_struct *work) static int default_bdl_pos_adj(struct azx *chip) { + /* some exceptions: Atoms seem problematic with value 1 */ + if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) { + switch (chip->pci->device) { + case 0x0f04: /* Baytrail */ + case 0x2284: /* Braswell */ + return 32; + } + } + switch (chip->driver_type) { case AZX_DRIVER_ICH: case AZX_DRIVER_PCH: -- cgit v1.2.3 From f3a0e32a6f6005f775174cbed9e46f7691800709 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 15 Dec 2015 23:56:17 +0900 Subject: ALSA: oxfw: rename a file for control elements so that it's for model-specific In ALSA firewire stack, drivers basically has no control elements. This is due to the fact that each model has own functionality even if they use the same communication chipset. Implementing all of the functionalities in kernel space unreasonably increases our efforts to maintain the stack. In most case, these functionalities can be implemented in userspace via Linux fw character devices. However, ALSA OXFW driver has control elements comes from old firewire-speakers driver. Adding the elements is in a file names as 'oxfw-control.c', while the elements are really model-specific. The name is confusing because it gives an idea to handle control elements for all of OXFW-based models. This commit renames the file so that it's just for models supported by old firewire-speakers driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/Makefile | 4 +- sound/firewire/oxfw/oxfw-control.c | 283 ------------------------------------- sound/firewire/oxfw/oxfw-spkr.c | 283 +++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 285 deletions(-) delete mode 100644 sound/firewire/oxfw/oxfw-control.c create mode 100644 sound/firewire/oxfw/oxfw-spkr.c (limited to 'sound') diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 06ff50f4e6c0..4e54ba9f4394 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,3 +1,3 @@ -snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \ - oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o +snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \ + oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw.o obj-$(CONFIG_SND_OXFW) += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-control.c deleted file mode 100644 index 02a1cb90f20d..000000000000 --- a/sound/firewire/oxfw/oxfw-control.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * oxfw_stream.c - a part of driver for OXFW970/971 based devices - * - * Copyright (c) Clemens Ladisch - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include "oxfw.h" - -enum control_action { CTL_READ, CTL_WRITE }; -enum control_attribute { - CTL_MIN = 0x02, - CTL_MAX = 0x03, - CTL_CURRENT = 0x10, -}; - -static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(11, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ - buf[5] = 0x10; /* control attribute: current */ - buf[6] = 0x02; /* selector length */ - buf[7] = 0x00; /* audio channel number */ - buf[8] = 0x01; /* control selector: mute */ - buf[9] = 0x01; /* control data length */ - if (action == CTL_READ) - buf[10] = 0xff; - else - buf[10] = *value ? 0x70 : 0x60; - - err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); - if (err < 0) - goto error; - if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = buf[10] == 0x70; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ - buf[5] = attribute; /* control attribute */ - buf[6] = 0x02; /* selector length */ - buf[7] = channel; /* audio channel number */ - buf[8] = 0x02; /* control selector: volume */ - buf[9] = 0x02; /* control data length */ - if (action == CTL_READ) { - buf[10] = 0xff; - buf[11] = 0xff; - } else { - buf[10] = *value >> 8; - buf[11] = *value; - } - - err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); - if (err < 0) - goto error; - if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = (buf[10] << 8) | buf[11]; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_mute_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - - value->value.integer.value[0] = !oxfw->mute; - - return 0; -} - -static int oxfw_mute_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - bool mute; - int err; - - mute = !value->value.integer.value[0]; - - if (mute == oxfw->mute) - return 0; - - err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); - if (err < 0) - return err; - oxfw->mute = mute; - - return 1; -} - -static int oxfw_volume_info(struct snd_kcontrol *control, - struct snd_ctl_elem_info *info) -{ - struct snd_oxfw *oxfw = control->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; - - return 0; -} - -static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; - -static int oxfw_volume_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; - - return 0; -} - -static int oxfw_volume_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i, changed_channels; - bool equal_values = true; - s16 volume; - int err; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) - return -EINVAL; - if (value->value.integer.value[i] != - value->value.integer.value[0]) - equal_values = false; - } - - changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) - changed_channels |= 1 << (i + 1); - - if (equal_values && changed_channels != 0) - changed_channels = 1 << 0; - - for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { - volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; - if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); - if (err < 0) - return err; - } - if (i > 0) - oxfw->volume[i - 1] = volume; - } - - return changed_channels != 0; -} - -int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) -{ - static const struct snd_kcontrol_new controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, - }, - }; - unsigned int i, first_ch; - int err; - - err = oxfw_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); - if (err < 0) - return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); - if (err < 0) - return err; - - err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); - if (err < 0) - return err; - - first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); - if (err < 0) - return err; - } - - for (i = 0; i < ARRAY_SIZE(controls); ++i) { - err = snd_ctl_add(oxfw->card, - snd_ctl_new1(&controls[i], oxfw)); - if (err < 0) - return err; - } - - return 0; -} diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c new file mode 100644 index 000000000000..22d853665683 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -0,0 +1,283 @@ +/* + * oxfw-spkr.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +enum control_action { CTL_READ, CTL_WRITE }; +enum control_attribute { + CTL_MIN = 0x02, + CTL_MAX = 0x03, + CTL_CURRENT = 0x10, +}; + +static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(11, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[5] = 0x10; /* control attribute: current */ + buf[6] = 0x02; /* selector length */ + buf[7] = 0x00; /* audio channel number */ + buf[8] = 0x01; /* control selector: mute */ + buf[9] = 0x01; /* control data length */ + if (action == CTL_READ) + buf[10] = 0xff; + else + buf[10] = *value ? 0x70 : 0x60; + + err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + if (err < 0) + goto error; + if (err < 11) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "mute command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = buf[10] == 0x70; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[5] = attribute; /* control attribute */ + buf[6] = 0x02; /* selector length */ + buf[7] = channel; /* audio channel number */ + buf[8] = 0x02; /* control selector: volume */ + buf[9] = 0x02; /* control data length */ + if (action == CTL_READ) { + buf[10] = 0xff; + buf[11] = 0xff; + } else { + buf[10] = *value >> 8; + buf[11] = *value; + } + + err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + if (err < 0) + goto error; + if (err < 12) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "volume command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = (buf[10] << 8) | buf[11]; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_mute_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + + value->value.integer.value[0] = !oxfw->mute; + + return 0; +} + +static int oxfw_mute_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + bool mute; + int err; + + mute = !value->value.integer.value[0]; + + if (mute == oxfw->mute) + return 0; + + err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + if (err < 0) + return err; + oxfw->mute = mute; + + return 1; +} + +static int oxfw_volume_info(struct snd_kcontrol *control, + struct snd_ctl_elem_info *info) +{ + struct snd_oxfw *oxfw = control->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = oxfw->device_info->mixer_channels; + info->value.integer.min = oxfw->volume_min; + info->value.integer.max = oxfw->volume_max; + + return 0; +} + +static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; + +static int oxfw_volume_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + + return 0; +} + +static int oxfw_volume_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i, changed_channels; + bool equal_values = true; + s16 volume; + int err; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + if (value->value.integer.value[i] < oxfw->volume_min || + value->value.integer.value[i] > oxfw->volume_max) + return -EINVAL; + if (value->value.integer.value[i] != + value->value.integer.value[0]) + equal_values = false; + } + + changed_channels = 0; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + if (value->value.integer.value[channel_map[i]] != + oxfw->volume[i]) + changed_channels |= 1 << (i + 1); + + if (equal_values && changed_channels != 0) + changed_channels = 1 << 0; + + for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; + if (changed_channels & (1 << i)) { + err = oxfw_volume_command(oxfw, &volume, i, + CTL_CURRENT, CTL_WRITE); + if (err < 0) + return err; + } + if (i > 0) + oxfw->volume[i - 1] = volume; + } + + return changed_channels != 0; +} + +int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) +{ + static const struct snd_kcontrol_new controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = oxfw_mute_get, + .put = oxfw_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = oxfw_volume_info, + .get = oxfw_volume_get, + .put = oxfw_volume_put, + }, + }; + unsigned int i, first_ch; + int err; + + err = oxfw_volume_command(oxfw, &oxfw->volume_min, + 0, CTL_MIN, CTL_READ); + if (err < 0) + return err; + err = oxfw_volume_command(oxfw, &oxfw->volume_max, + 0, CTL_MAX, CTL_READ); + if (err < 0) + return err; + + err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + if (err < 0) + return err; + + first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + err = oxfw_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(controls); ++i) { + err = snd_ctl_add(oxfw->card, + snd_ctl_new1(&controls[i], oxfw)); + if (err < 0) + return err; + } + + return 0; +} -- cgit v1.2.3 From 29aa09acb20485ee682de38903734cb3a0e582cd Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 15 Dec 2015 23:56:18 +0900 Subject: ALSA: oxfw: rename local functions for control elements so that they represent as local This commit renames local functions with prefix 'spkr_', so that they're for firewire-speakers. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-spkr.c | 40 ++++++++++++++++++++-------------------- sound/firewire/oxfw/oxfw.c | 2 +- sound/firewire/oxfw/oxfw.h | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index 22d853665683..fde6b765fe31 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -14,7 +14,7 @@ enum control_attribute { CTL_CURRENT = 0x10, }; -static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, +static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, enum control_action action) { u8 *buf; @@ -70,7 +70,7 @@ error: return err; } -static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, +static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, unsigned int channel, enum control_attribute attribute, enum control_action action) @@ -131,7 +131,7 @@ error: return err; } -static int oxfw_mute_get(struct snd_kcontrol *control, +static int spkr_mute_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -141,7 +141,7 @@ static int oxfw_mute_get(struct snd_kcontrol *control, return 0; } -static int oxfw_mute_put(struct snd_kcontrol *control, +static int spkr_mute_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -153,7 +153,7 @@ static int oxfw_mute_put(struct snd_kcontrol *control, if (mute == oxfw->mute) return 0; - err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + err = spkr_mute_command(oxfw, &mute, CTL_WRITE); if (err < 0) return err; oxfw->mute = mute; @@ -161,7 +161,7 @@ static int oxfw_mute_put(struct snd_kcontrol *control, return 1; } -static int oxfw_volume_info(struct snd_kcontrol *control, +static int spkr_volume_info(struct snd_kcontrol *control, struct snd_ctl_elem_info *info) { struct snd_oxfw *oxfw = control->private_data; @@ -176,7 +176,7 @@ static int oxfw_volume_info(struct snd_kcontrol *control, static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; -static int oxfw_volume_get(struct snd_kcontrol *control, +static int spkr_volume_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -188,7 +188,7 @@ static int oxfw_volume_get(struct snd_kcontrol *control, return 0; } -static int oxfw_volume_put(struct snd_kcontrol *control, +static int spkr_volume_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; @@ -218,7 +218,7 @@ static int oxfw_volume_put(struct snd_kcontrol *control, for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, + err = spkr_volume_command(oxfw, &volume, i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; @@ -230,44 +230,44 @@ static int oxfw_volume_put(struct snd_kcontrol *control, return changed_channels != 0; } -int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) { static const struct snd_kcontrol_new controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, + .get = spkr_mute_get, + .put = spkr_mute_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, + .info = spkr_volume_info, + .get = spkr_volume_get, + .put = spkr_volume_put, }, }; unsigned int i, first_ch; int err; - err = oxfw_volume_command(oxfw, &oxfw->volume_min, + err = spkr_volume_command(oxfw, &oxfw->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, + err = spkr_volume_command(oxfw, &oxfw->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err; - err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + err = spkr_mute_command(oxfw, &oxfw->mute, CTL_READ); if (err < 0) return err; first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); + err = spkr_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 588b93f20c2e..0304d4549f44 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -205,7 +205,7 @@ static int oxfw_probe(struct fw_unit *unit, goto error; if (oxfw->device_info) { - err = snd_oxfw_create_mixer(oxfw); + err = snd_oxfw_add_spkr(oxfw); if (err < 0) goto error; } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 8392c424ad1d..9efdc026fdad 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -138,10 +138,10 @@ void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw); int snd_oxfw_create_pcm(struct snd_oxfw *oxfw); -int snd_oxfw_create_mixer(struct snd_oxfw *oxfw); - void snd_oxfw_proc_init(struct snd_oxfw *oxfw); int snd_oxfw_create_midi(struct snd_oxfw *oxfw); int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); + +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw); -- cgit v1.2.3 From eab8e4e4619643f49167c2089749acc40ad7f95d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 15 Dec 2015 23:56:19 +0900 Subject: ALSA: oxfw: change function prototype for AV/C Audio Subunit command ALSA OXFW driver uses AV/C Audio Subunit commands to control some models. The commands get/set the state of Feature function block of the subunit. The commands are not specific to OXFW, thus there's a possibility to use them in the other drivers. Currently, helper functions for the commands require 'struct snd_oxfw', although, it's not necessarily required. It's better to change prototype of the functions without the structure for future use. This commit changes the prototype. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-spkr.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index fde6b765fe31..d733a15cdec7 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -14,8 +14,8 @@ enum control_attribute { CTL_CURRENT = 0x10, }; -static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) +static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value, + enum control_action action) { u8 *buf; u8 response_ok; @@ -35,7 +35,7 @@ static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = 0x10; /* control attribute: current */ buf[6] = 0x02; /* selector length */ buf[7] = 0x00; /* audio channel number */ @@ -46,16 +46,16 @@ static int spkr_mute_command(struct snd_oxfw *oxfw, bool *value, else buf[10] = *value ? 0x70 : 0x60; - err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe); if (err < 0) goto error; if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); + dev_err(&unit->device, "mute command failed\n"); err = -EIO; goto error; } @@ -70,10 +70,10 @@ error: return err; } -static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) +static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) { u8 *buf; u8 response_ok; @@ -93,7 +93,7 @@ static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = attribute; /* control attribute */ buf[6] = 0x02; /* selector length */ buf[7] = channel; /* audio channel number */ @@ -107,16 +107,16 @@ static int spkr_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[11] = *value; } - err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe); if (err < 0) goto error; if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); + dev_err(&unit->device, "volume command failed\n"); err = -EIO; goto error; } @@ -153,7 +153,8 @@ static int spkr_mute_put(struct snd_kcontrol *control, if (mute == oxfw->mute) return 0; - err = spkr_mute_command(oxfw, &mute, CTL_WRITE); + err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, + &mute, CTL_WRITE); if (err < 0) return err; oxfw->mute = mute; @@ -218,8 +219,10 @@ static int spkr_volume_put(struct snd_kcontrol *control, for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { - err = spkr_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->mute_fb_id, + &volume, + i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; } @@ -251,22 +254,27 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) unsigned int i, first_ch; int err; - err = spkr_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = spkr_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err; - err = spkr_mute_command(oxfw, &oxfw->mute, CTL_READ); + err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, + &oxfw->mute, CTL_READ); if (err < 0) return err; first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = spkr_volume_command(oxfw, &oxfw->volume[i], + err = avc_audio_feature_volume(oxfw->unit, + oxfw->device_info->volume_fb_id, + &oxfw->volume[i], first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err; -- cgit v1.2.3 From 27e66635016fc5bd3d36355daedf741f0a7329bb Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 15 Dec 2015 23:56:20 +0900 Subject: ALSA: oxfw: reuse driver entry to detect quirks Currently, assignment to model-dependent quirk is corresponding to asynchronous transactions on IEEE 1394 bus. This is also achieved with device entry. This commit changes the processing of model-dependent quirk with the entry. As a result, the transactions are sent only for Loud models. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw.c | 38 ++++++++++++++++++++++---------------- sound/firewire/oxfw/oxfw.h | 2 ++ 2 files changed, 24 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 0304d4549f44..836d75777973 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -59,6 +59,7 @@ static bool detect_loud_models(struct fw_unit *unit) static int name_card(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); + const struct device_info *info; char vendor[24]; char model[32]; const char *d, *v, *m; @@ -84,10 +85,12 @@ static int name_card(struct snd_oxfw *oxfw) be32_to_cpus(&firmware); /* to apply card definitions */ - if (oxfw->device_info) { - d = oxfw->device_info->driver_name; - v = oxfw->device_info->vendor_name; - m = oxfw->device_info->model_name; + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || + oxfw->entry->vendor_id == VENDOR_LACIE) { + info = (const struct device_info *)oxfw->entry->driver_data; + d = info->driver_name; + v = info->vendor_name; + m = info->model_name; } else { d = "OXFW"; v = vendor; @@ -139,6 +142,16 @@ static void detect_quirks(struct snd_oxfw *oxfw) int key, val; int vendor, model; + /* + * TASCAM FireOne has physical control and requires a pair of additional + * MIDI ports. + */ + if (oxfw->entry->vendor_id == VENDOR_TASCAM) { + oxfw->midi_input_ports++; + oxfw->midi_output_ports++; + return; + } + /* Seek from Root Directory of Config ROM. */ vendor = model = 0; fw_csr_iterator_init(&it, fw_dev->config_rom + 5); @@ -155,25 +168,16 @@ static void detect_quirks(struct snd_oxfw *oxfw) */ if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) oxfw->wrong_dbs = true; - - /* - * TASCAM FireOne has physical control and requires a pair of additional - * MIDI ports. - */ - if (vendor == VENDOR_TASCAM) { - oxfw->midi_input_ports++; - oxfw->midi_output_ports++; - } } static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *id) + const struct ieee1394_device_id *entry) { struct snd_card *card; struct snd_oxfw *oxfw; int err; - if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit)) + if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) return -ENODEV; err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, @@ -186,7 +190,7 @@ static int oxfw_probe(struct fw_unit *unit, oxfw->card = card; mutex_init(&oxfw->mutex); oxfw->unit = fw_unit_get(unit); - oxfw->device_info = (const struct device_info *)id->driver_data; + oxfw->entry = entry; spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); @@ -205,6 +209,8 @@ static int oxfw_probe(struct fw_unit *unit, goto error; if (oxfw->device_info) { + oxfw->device_info = + (const struct device_info *)entry->driver_data; err = snd_oxfw_add_spkr(oxfw); if (err < 0) goto error; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 9efdc026fdad..f3e14fff4ba0 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -72,6 +72,8 @@ struct snd_oxfw { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + const struct ieee1394_device_id *entry; }; /* -- cgit v1.2.3 From 5ce8cc48443596e500586007b443e1eea6334efc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 15 Dec 2015 23:56:21 +0900 Subject: ALSA: oxfw: gather model-dependent conditions to a function Adding control elements is just for models supported by old firewire-speakers modules. The processing should be in a function to add model-dependent quirk. This commit moves the codes to the function. As a result, the function should handle error state, thus this commit also changes prototype of the function. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 836d75777973..d4fb3c10163a 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -135,13 +135,24 @@ static void oxfw_card_free(struct snd_card *card) mutex_destroy(&oxfw->mutex); } -static void detect_quirks(struct snd_oxfw *oxfw) +static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); struct fw_csr_iterator it; int key, val; int vendor, model; + /* + * Add ALSA control elements for two models to keep compatibility to + * old firewire-speaker module. + */ + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || + oxfw->entry->vendor_id == VENDOR_LACIE) { + oxfw->device_info = + (const struct device_info *)oxfw->entry->driver_data; + return snd_oxfw_add_spkr(oxfw); + } + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. @@ -149,7 +160,7 @@ static void detect_quirks(struct snd_oxfw *oxfw) if (oxfw->entry->vendor_id == VENDOR_TASCAM) { oxfw->midi_input_ports++; oxfw->midi_output_ports++; - return; + return 0; } /* Seek from Root Directory of Config ROM. */ @@ -168,6 +179,8 @@ static void detect_quirks(struct snd_oxfw *oxfw) */ if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) oxfw->wrong_dbs = true; + + return 0; } static int oxfw_probe(struct fw_unit *unit, @@ -198,7 +211,9 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - detect_quirks(oxfw); + err = detect_quirks(oxfw); + if (err < 0) + goto error; err = name_card(oxfw); if (err < 0) @@ -208,14 +223,6 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - if (oxfw->device_info) { - oxfw->device_info = - (const struct device_info *)entry->driver_data; - err = snd_oxfw_add_spkr(oxfw); - if (err < 0) - goto error; - } - snd_oxfw_proc_init(oxfw); err = snd_oxfw_create_midi(oxfw); -- cgit v1.2.3 From 76ca9970322118610681af5f929aba62f346082b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Dec 2015 12:04:54 +0000 Subject: rcar: ctu: Avoid use of ret uninitialised We use ret as the return value from the rsnd_ctu_probe() but if there are no child nodes and no errors then we will never initialize ret leading to build warnings. Ensure ret is initialized before we iterate over the child nodes to avoid this. Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 7c1e190cd389..d53a225d19e9 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -111,6 +111,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) priv->ctu = ctu; i = 0; + ret = 0; for_each_child_of_node(node, np) { ctu = rsnd_ctu_get(priv, i); -- cgit v1.2.3 From 2e4118dac3d6765186dd1faf1fd3cede37b74e73 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Dec 2015 12:05:17 +0000 Subject: rcar: dvc: Avoid use of ret uninitialised We use ret as the return value from the rsnd_dvc_probe() but if there are no child nodes and no errors then we will never initialize ret leading to build warnings. Ensure ret is initialized before we iterate over the child nodes to avoid this. Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 66aeea8e0069..42e6a230a3d1 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -360,6 +360,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) priv->dvc = dvc; i = 0; + ret = 0; for_each_child_of_node(node, np) { dvc = rsnd_dvc_get(priv, i); -- cgit v1.2.3 From 2b235a3da5560d65df6865ea436389e55a0f41ad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Dec 2015 12:05:28 +0000 Subject: rcar: mux: Avoid use of ret uninitialised We use ret as the return value from the rsnd_mix_probe() but if there are no child nodes and no errors then we will never initialize ret leading to build warnings. Ensure ret is initialized before we iterate over the child nodes to avoid this. Signed-off-by: Mark Brown --- sound/soc/sh/rcar/mix.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index b34957ab75b9..65542b6a89e9 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -158,6 +158,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) priv->mix = mix; i = 0; + ret = 0; for_each_child_of_node(node, np) { mix = rsnd_mix_get(priv, i); -- cgit v1.2.3 From 1cf8dfd90fe50ac660f79d4b94f47b8e721a1178 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Mon, 14 Dec 2015 22:27:13 +0800 Subject: ASoC: Intel: sst: fix sst_memcpy32 wrong with non-4x bytes issue sst_memcpy32() only copied bytes/4 32bits, which means it dropped the remaining bytes%4 bytes wrongly. Here add copying those missing bytes, first to a 32bits tmp, and then write the tmp to 32bits iomem. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-firmware.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index bee04a9707d8..ef4881e7753a 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -51,8 +51,22 @@ struct sst_dma { static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) { + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + + m = bytes / 4; + n = bytes % 4; + /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy((void *)dest, src, bytes/4); + __iowrite32_copy((void *)dest, src, m); + + if (n) { + for (i = 0; i < n; i++) + tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); + __iowrite32_copy((void *)(dest + m * 4), &tmp, 1); + } + } static void sst_dma_transfer_complete(void *arg) -- cgit v1.2.3 From db4e561378b539230feb4db5e7d5d548c2db2cd4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Dec 2015 12:20:14 +0300 Subject: ASoC: Intel: Skylake: Fix a couple signedness bugs These need to be signed because they hold negative error codes. Signed-off-by: Dan Carpenter Acked-by Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 8cd5cdb21fd5..e26f4746afb7 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -208,7 +208,7 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx) * since get/set_module are called from DAPM context, * we don't need lock for usage count */ -static unsigned int skl_get_module(struct sst_dsp *ctx, u16 mod_id) +static int skl_get_module(struct sst_dsp *ctx, u16 mod_id) { struct skl_module_table *module; @@ -220,7 +220,7 @@ static unsigned int skl_get_module(struct sst_dsp *ctx, u16 mod_id) return -EINVAL; } -static unsigned int skl_put_module(struct sst_dsp *ctx, u16 mod_id) +static int skl_put_module(struct sst_dsp *ctx, u16 mod_id) { struct skl_module_table *module; @@ -340,7 +340,7 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid) static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) { - unsigned int usage_cnt; + int usage_cnt; struct skl_sst *skl = ctx->thread_context; int ret = 0; -- cgit v1.2.3 From 3451eb485aee78f31a8dd127e3385f89946c813b Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 16 Dec 2015 17:06:24 +0000 Subject: ASoC: arizona: In arizona_calc_fratio make new codecs the default case This patch rearranges the switch statement in arizona_calc_fratio so that older codecs are the special cases, with the default case applying to newer codecs (WM8998 and later). This is preferable because it avoids having to patch new cases in every time a new codec is added. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index d90b3c51019a..38a73e3da508 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2020,18 +2020,18 @@ static int arizona_calc_fratio(struct arizona_fll *fll, } switch (fll->arizona->type) { + case WM5102: + case WM8997: + return init_ratio; case WM5110: case WM8280: if (fll->arizona->rev < 3 || sync) return init_ratio; break; - case WM8998: - case WM1814: + default: if (sync) return init_ratio; break; - default: - return init_ratio; } cfg->fratio = init_ratio - 1; -- cgit v1.2.3 From 1aa844cd56c7a2b94824f02495ff7ae5d52a7e91 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Tue, 15 Dec 2015 13:51:25 -0800 Subject: ASoC: rt5677: Reconfigure PLL1 after resume Sometimes PLL1 stops working if the codec loses power during suspend (when pow-ldo2 or reset gpio is used). MX-7Bh(RT5677_PLL1_CTRL2) is cleared and won't be restored by regcache since it's volatile. MX-7Bh has one status bit and M code for PLL1. rt5677_set_dai_pll doesn't reconfigure PLL1 after resume because it thinks the PLL params are not changed. This patch clears the cached PLL params at resume so that rt5677_set_dai_pll can reconfigure the PLL after resume. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f73fd125e49c..c404f515376e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4792,6 +4792,9 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { + rt5677->pll_src = 0; + rt5677->pll_in = 0; + rt5677->pll_out = 0; gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); gpiod_set_value_cansleep(rt5677->reset_pin, 0); if (rt5677->pow_ldo2 || rt5677->reset_pin) -- cgit v1.2.3 From e8bc3c99fa982f616e74aec4445945400a9c56f3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 8 Dec 2015 08:53:22 +0300 Subject: ASoC: Intel: Skylake: pointer math issue "data" is a u32 pointer so this copies the information to wrong place entirely. Fixes: 140adfba5280 ('ASoC: Intel: Skylake: Add tlv byte kcontrols') Signed-off-by: Dan Carpenter Acked-by: Vinod Koul Tested-by: Dharageswari R Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b824450edcb4..34f2f7351f66 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -919,9 +919,9 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, if (bc->params) { if (copy_to_user(data, &bc->param_id, sizeof(u32))) return -EFAULT; - if (copy_to_user(data + sizeof(u32), &size, sizeof(u32))) + if (copy_to_user(data + 1, &size, sizeof(u32))) return -EFAULT; - if (copy_to_user(data + 2 * sizeof(u32), bc->params, size)) + if (copy_to_user(data + 2, bc->params, size)) return -EFAULT; } -- cgit v1.2.3 From ef85f299c74e6c5dd98ec0230183be33f4c2813d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2015 08:12:37 +0100 Subject: ALSA: hda - Merge RIRB_PRE_DELAY into CTX_WORKAROUND caps AZX_DCAPS_RIRB_PRE_DELAY is always tied with AZX_DCAPS_CTX_WORKAROUND, which is Creative's XFi specific. So, we can replace it and reduce one more bit free for DCAPS. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 10c77074b4dc..34022a36e5c5 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -956,7 +956,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) { - if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) udelay(80); snd_hdac_bus_update_rirb(bus); } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a32ec9004edd..c723bcc7fcef 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -33,7 +33,7 @@ #define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ #define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ #define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ -#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +/* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ #define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 56ef6b6fb546..2d2f14830df7 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2314,14 +2314,12 @@ static const struct pci_device_id azx_ids[] = { .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_NO_64BIT | - AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, + AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_NO_64BIT | - AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, + AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #endif /* CM8888 */ { PCI_DEVICE(0x13f6, 0x5011), -- cgit v1.2.3 From 7d9a180895ee8c301df7f9447429009795c56c21 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2015 08:23:39 +0100 Subject: ALSA: hda - Raise AZX_DCAPS_RIRB_DELAY handling into top drivers AZX_DCAPS_RIRB_DELAY is dedicated only for Nvidia and its purpose is just to set a flag in bus. So it's better to be set in the toplevel driver, either hda_intel.c or hda_tegra.c, instead of the common hda_controller.c. This also allows us to strip this flag from dcaps, so save one more bit there. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 5 ----- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 7 ++++++- sound/pci/hda/hda_tegra.c | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 34022a36e5c5..37cf9cee9835 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1054,11 +1054,6 @@ int azx_bus_init(struct azx *chip, const char *model, if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) bus->core.corbrp_self_clear = true; - if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { - dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); - bus->needs_damn_long_delay = 1; - } - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) bus->core.align_bdle_4k = true; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c723bcc7fcef..65401372a7c8 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -32,7 +32,7 @@ #define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ #define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ #define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ -#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ +/* 13 unused */ /* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2d2f14830df7..bcb526103ecb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -338,7 +338,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ + (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ AZX_DCAPS_SNOOP_TYPE(NVIDIA)) @@ -1573,6 +1573,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, return err; } + if (chip->driver_type == AZX_DRIVER_NVIDIA) { + dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); + chip->bus.needs_damn_long_delay = 1; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device [card]!\n"); diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 58c0aad37284..17fd81736d3d 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -464,6 +464,8 @@ static int hda_tegra_create(struct snd_card *card, if (err < 0) return err; + chip->bus.needs_damn_long_delay = 1; + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device\n"); @@ -481,8 +483,7 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match); static int hda_tegra_probe(struct platform_device *pdev) { - const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY | - AZX_DCAPS_CORBRP_SELF_CLEAR; + const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR; struct snd_card *card; struct azx *chip; struct hda_tegra *hda; -- cgit v1.2.3 From 26f0571781da98ea996c0cd7e03b733055b70f1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2015 08:29:53 +0100 Subject: ALSA: hda - Drop AZX_DCAPS_POSFIX_VIA bit AZX_DCAPS_POSFIX_VIA is coupled always with AZX_DRIVER_VIA type, so we don't have to keep this bit in dcaps. Save one more! Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 65401372a7c8..a288ac1b5451 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -36,7 +36,7 @@ /* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ -#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +/* 17 unused */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bcb526103ecb..67e672a77576 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1325,7 +1325,7 @@ static int check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { + if (chip->driver_type == AZX_DRIVER_VIA) { dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } @@ -2284,8 +2284,7 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x1002, 0xaae8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), - .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, + { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */ { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ -- cgit v1.2.3 From bcb337d166044cf389d3b9d3e6063c1ec4ca685d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2015 08:31:45 +0100 Subject: ALSA: hda - Drop unused AZX_DCAPS_REVERSE_ASSIGN AZX_DCAPS_REVERSE_ASSIGN is no longer referred by any code. Let's drop it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a288ac1b5451..ec63bbf1ec6d 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -43,7 +43,7 @@ #define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */ /* 22 unused */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ +/* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ #ifdef CONFIG_SND_HDA_I915 diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 67e672a77576..1465f6a0e010 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -286,7 +286,7 @@ enum { /* quirks for Intel PCH */ #define AZX_DCAPS_INTEL_PCH_BASE \ (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ - AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) /* PCH up to IVB; no runtime PM */ #define AZX_DCAPS_INTEL_PCH_NOPM \ -- cgit v1.2.3 From bc1765d6e81a70be36a7290bcc829a7714101bbb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 17 Dec 2015 10:05:59 +0000 Subject: ASoC: wm_adsp: Mimic legacy behaviour of reading controls when DSP is on Older firmwares don't specify access flags for the controls, unfortunately the usage of some of these firmware relies on being able to read back values from the DSP. The current control code will only do this for volatile controls. This patch will read the control from the hardware if no flags are specified and the control is currently enabled, which should cover these legacy use-cases. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b083642718f0..d1e0826c7db2 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -666,6 +666,9 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, else ret = -EPERM; } else { + if (!ctl->flags && ctl->enabled) + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); + memcpy(p, ctl->cache, ctl->len); } -- cgit v1.2.3 From 6dad9758a5e3e75de91871a636572d64806b240f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:48:23 +0000 Subject: ASoC: rsrc-card: enable to use tdm_slot on DT Renesas sound driver will use tdm slot on TDM Multi Mode support. This patch enables tdm slot on rsrc card driver on DT. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsrc-card.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index a3ec13f6271e..3c308e2d696e 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -50,6 +50,10 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match); struct rsrc_card_dai { unsigned int fmt; unsigned int sysclk; + unsigned int tx_slot_mask; + unsigned int rx_slot_mask; + int slots; + int slot_width; struct clk *clk; char dai_name[DAI_NAME_NUM]; }; @@ -126,6 +130,18 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) } } + if (dai_props->slots) { + ret = snd_soc_dai_set_tdm_slot(dai, + dai_props->tx_slot_mask, + dai_props->rx_slot_mask, + dai_props->slots, + dai_props->slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dai->dev, "set_tdm_slot error\n"); + goto err; + } + } + ret = 0; err: @@ -198,6 +214,15 @@ static int rsrc_card_parse_links(struct device_node *np, if (ret) return ret; + /* Parse TDM slot */ + ret = snd_soc_of_parse_tdm_slot(np, + &dai_props->tx_slot_mask, + &dai_props->rx_slot_mask, + &dai_props->slots, + &dai_props->slot_width); + if (ret) + return ret; + if (is_fe) { /* BE is dummy */ dai_link->codec_of_node = NULL; -- cgit v1.2.3 From ae638b725ee00afe3253e30df617a5531ea30ea2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:48:58 +0000 Subject: ASoC: rsrc-card: Remove support for setting differing DAI formats 1efb53a220 ("ASoC: simple-card: Remove support for setting differing DAI formats") removed set_fmt support from simple-card. rsrc-card follows same style, because it is based on simple-card. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsrc-card.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 3c308e2d696e..9f522ba881fa 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -48,7 +48,6 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match); #define DAI_NAME_NUM 32 struct rsrc_card_dai { - unsigned int fmt; unsigned int sysclk; unsigned int tx_slot_mask; unsigned int rx_slot_mask; @@ -114,14 +113,6 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - if (dai_props->fmt) { - ret = snd_soc_dai_set_fmt(dai, dai_props->fmt); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "set_fmt error\n"); - goto err; - } - } - if (dai_props->sysclk) { ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); if (ret && ret != -ENOTSUPP) { @@ -168,7 +159,7 @@ static int rsrc_card_parse_daifmt(struct device_node *node, struct rsrc_card_priv *priv, int idx, bool is_fe) { - struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; struct device_node *codec = is_fe ? NULL : np; @@ -188,7 +179,7 @@ static int rsrc_card_parse_daifmt(struct device_node *node, daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; - dai_props->fmt = daifmt; + dai_link->dai_fmt = daifmt; of_node_put(bitclkmaster); of_node_put(framemaster); @@ -340,6 +331,7 @@ static int rsrc_card_dai_link_of(struct device_node *node, int idx) { struct device *dev = rsrc_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); bool is_fe = false; int ret; @@ -361,7 +353,7 @@ static int rsrc_card_dai_link_of(struct device_node *node, dev_dbg(dev, "\t%s / %04x / %d\n", dai_props->dai_name, - dai_props->fmt, + dai_link->dai_fmt, dai_props->sysclk); return ret; -- cgit v1.2.3 From af998f853124231ef3bff05621f157a19af05d20 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:49:43 +0000 Subject: ASoC: rsrc-card: tidyup dai format for DPCM rsrc-card is DPCM supported version of simple-card. Thus it has similar DT format. OTOH, snd_soc_dai_link requests cpu/codec, but one of them will be snd-soc-dummy in DPCM case, and DPCM requests frontend/backend dai_link. This means it might have multi backend/codec. And, SND_SOC_DAIFMT_xxx is based on "codec". Because of these difference, current rsrc card can't detect correct dai_fmt. This patch detect correct dai fmt from 1st "codec". Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsrc-card.c | 82 +++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 9f522ba881fa..5fe0b51cdb44 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -155,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, } static int rsrc_card_parse_daifmt(struct device_node *node, - struct device_node *np, + struct device_node *codec, struct rsrc_card_priv *priv, - int idx, bool is_fe) + struct snd_soc_dai_link *dai_link, + unsigned int *retfmt) { - struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; - struct device_node *codec = is_fe ? NULL : np; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, NULL, @@ -179,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node, daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; - dai_link->dai_fmt = daifmt; - of_node_put(bitclkmaster); of_node_put(framemaster); + *retfmt = daifmt; + return 0; } @@ -325,24 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np, return 0; } -static int rsrc_card_dai_link_of(struct device_node *node, - struct device_node *np, - struct rsrc_card_priv *priv, - int idx) +static int rsrc_card_dai_sub_link_of(struct device_node *node, + struct device_node *np, + struct rsrc_card_priv *priv, + int idx, bool is_fe) { struct device *dev = rsrc_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); - bool is_fe = false; int ret; - if (0 == strcmp(np->name, "cpu")) - is_fe = true; - - ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe); - if (ret < 0) - return ret; - ret = rsrc_card_parse_links(np, priv, idx, is_fe); if (ret < 0) return ret; @@ -359,6 +350,48 @@ static int rsrc_card_dai_link_of(struct device_node *node, return ret; } +static int rsrc_card_dai_link_of(struct device_node *node, + struct rsrc_card_priv *priv) +{ + struct snd_soc_dai_link *dai_link; + struct device_node *np; + unsigned int daifmt = 0; + int ret, i; + bool is_fe; + + /* find 1st codec */ + i = 0; + for_each_child_of_node(node, np) { + dai_link = rsrc_priv_to_link(priv, i); + + if (strcmp(np->name, "codec") == 0) { + ret = rsrc_card_parse_daifmt(node, np, priv, + dai_link, &daifmt); + if (ret < 0) + return ret; + break; + } + i++; + } + + i = 0; + for_each_child_of_node(node, np) { + dai_link = rsrc_priv_to_link(priv, i); + dai_link->dai_fmt = daifmt; + + is_fe = false; + if (strcmp(np->name, "cpu") == 0) + is_fe = true; + + ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe); + if (ret < 0) + return ret; + i++; + } + + return 0; +} + static int rsrc_card_parse_of(struct device_node *node, struct rsrc_card_priv *priv, struct device *dev) @@ -366,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node, const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); struct rsrc_card_dai *props; struct snd_soc_dai_link *links; - struct device_node *np; int ret; - int i, num; + int num; if (!node) return -EINVAL; @@ -409,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.name ? priv->snd_card.name : "", priv->convert_rate); - i = 0; - for_each_child_of_node(node, np) { - ret = rsrc_card_dai_link_of(node, np, priv, i); - if (ret < 0) - return ret; - i++; - } + ret = rsrc_card_dai_link_of(node, priv); + if (ret < 0) + return ret; if (!priv->snd_card.name) priv->snd_card.name = priv->snd_card.dai_link->name; -- cgit v1.2.3 From a7664ab29af7d7eca57ae525b5063f71fa006ff4 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Thu, 17 Dec 2015 17:49:59 +0800 Subject: ASoC: atmel-pdmic: add the Pulse Density Modulation Interface Controller Add driver for the Pulse Density Modulation Interface Controller. It comes with digitallly controlled gain, a High-Pass and a SINCC filter. Signed-off-by: Songjun Wu Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 9 + sound/soc/atmel/Makefile | 2 + sound/soc/atmel/atmel-pdmic.c | 738 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/atmel/atmel-pdmic.h | 80 +++++ 4 files changed, 829 insertions(+) create mode 100644 sound/soc/atmel/atmel-pdmic.c create mode 100644 sound/soc/atmel/atmel-pdmic.h (limited to 'sound') diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 2d30464b81ce..06e099e802df 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -68,4 +68,13 @@ config SND_ATMEL_SOC_CLASSD help Say Y if you want to add support for Atmel ASoC driver for boards using CLASSD. + +config SND_ATMEL_SOC_PDMIC + tristate "Atmel ASoC driver for boards using PDMIC" + depends on OF && (ARCH_AT91 || COMPILE_TEST) + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to add support for Atmel ASoC driver for boards using + PDMIC. endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index f6f7db428216..a2b127bd9c87 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -12,8 +12,10 @@ snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o snd-atmel-soc-wm8904-objs := atmel_wm8904.o snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o +snd-atmel-soc-pdmic-objs := atmel-pdmic.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o +obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c new file mode 100644 index 000000000000..aee4787a0b89 --- /dev/null +++ b/sound/soc/atmel/atmel-pdmic.c @@ -0,0 +1,738 @@ +/* Atmel PDMIC driver + * + * Copyright (C) 2015 Atmel + * + * Author: Songjun Wu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or later + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atmel-pdmic.h" + +struct atmel_pdmic_pdata { + u32 mic_min_freq; + u32 mic_max_freq; + s32 mic_offset; + const char *card_name; +}; + +struct atmel_pdmic { + dma_addr_t phy_base; + struct regmap *regmap; + struct clk *pclk; + struct clk *gclk; + int irq; + struct snd_pcm_substream *substream; + const struct atmel_pdmic_pdata *pdata; +}; + +static const struct of_device_id atmel_pdmic_of_match[] = { + { + .compatible = "atmel,sama5d2-pdmic", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_pdmic_of_match); + +#define PDMIC_OFFSET_MAX_VAL S16_MAX +#define PDMIC_OFFSET_MIN_VAL S16_MIN + +static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct atmel_pdmic_pdata *pdata; + + if (!np) { + dev_err(dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + if (of_property_read_string(np, "atmel,model", &pdata->card_name)) + pdata->card_name = "PDMIC"; + + if (of_property_read_u32(np, "atmel,mic-min-freq", + &pdata->mic_min_freq)) { + dev_err(dev, "failed to get mic-min-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_u32(np, "atmel,mic-max-freq", + &pdata->mic_max_freq)) { + dev_err(dev, "failed to get mic-max-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (pdata->mic_max_freq < pdata->mic_min_freq) { + dev_err(dev, + "mic-max-freq should not less than mic-min-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_s32(np, "atmel,mic-offset", &pdata->mic_offset)) + pdata->mic_offset = 0; + + if (pdata->mic_offset > PDMIC_OFFSET_MAX_VAL) { + dev_warn(dev, + "mic-offset value %d is larger than the max value %d, the max value is specified\n", + pdata->mic_offset, PDMIC_OFFSET_MAX_VAL); + pdata->mic_offset = PDMIC_OFFSET_MAX_VAL; + } else if (pdata->mic_offset < PDMIC_OFFSET_MIN_VAL) { + dev_warn(dev, + "mic-offset value %d is less than the min value %d, the min value is specified\n", + pdata->mic_offset, PDMIC_OFFSET_MIN_VAL); + pdata->mic_offset = PDMIC_OFFSET_MIN_VAL; + } + + return pdata; +} + +/* cpu dai component */ +static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = clk_prepare_enable(dd->gclk); + if (ret) + return ret; + + ret = clk_prepare_enable(dd->pclk); + if (ret) + return ret; + + /* Clear all bits in the Control Register(PDMIC_CR) */ + regmap_write(dd->regmap, PDMIC_CR, 0); + + dd->substream = substream; + + /* Enable the overrun error interrupt */ + regmap_write(dd->regmap, PDMIC_IER, PDMIC_IER_OVRE); + + return 0; +} + +static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + + /* Disable the overrun error interrupt */ + regmap_write(dd->regmap, PDMIC_IDR, PDMIC_IDR_OVRE); + + clk_disable_unprepare(dd->gclk); + clk_disable_unprepare(dd->pclk); +} + +static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + u32 val; + + /* Clean the PDMIC Converted Data Register */ + return regmap_read(dd->regmap, PDMIC_CDR, &val); +} + +static const struct snd_soc_dai_ops atmel_pdmic_cpu_dai_ops = { + .startup = atmel_pdmic_cpu_dai_startup, + .shutdown = atmel_pdmic_cpu_dai_shutdown, + .prepare = atmel_pdmic_cpu_dai_prepare, +}; + +#define ATMEL_PDMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver atmel_pdmic_cpu_dai = { + .capture = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ATMEL_PDMIC_FORMATS,}, + .ops = &atmel_pdmic_cpu_dai_ops, +}; + +static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = { + .name = "atmel-pdmic", +}; + +/* platform */ +#define ATMEL_PDMIC_MAX_BUF_SIZE (64 * 1024) +#define ATMEL_PDMIC_PREALLOC_BUF_SIZE ATMEL_PDMIC_MAX_BUF_SIZE + +static const struct snd_pcm_hardware atmel_pdmic_hw = { + .info = SNDRV_PCM_INFO_MMAP + | SNDRV_PCM_INFO_MMAP_VALID + | SNDRV_PCM_INFO_INTERLEAVED + | SNDRV_PCM_INFO_RESUME + | SNDRV_PCM_INFO_PAUSE, + .formats = ATMEL_PDMIC_FORMATS, + .buffer_bytes_max = ATMEL_PDMIC_MAX_BUF_SIZE, + .period_bytes_min = 256, + .period_bytes_max = 32 * 1024, + .periods_min = 2, + .periods_max = 256, +}; + +static int +atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = snd_hwparams_to_dma_slave_config(substream, params, + slave_config); + if (ret) { + dev_err(rtd->platform->dev, + "hw params to dma slave configure failed\n"); + return ret; + } + + slave_config->src_addr = dd->phy_base + PDMIC_CDR; + slave_config->src_maxburst = 1; + slave_config->dst_maxburst = 1; + + return 0; +} + +static const struct snd_dmaengine_pcm_config +atmel_pdmic_dmaengine_pcm_config = { + .prepare_slave_config = atmel_pdmic_platform_configure_dma, + .pcm_hardware = &atmel_pdmic_hw, + .prealloc_buffer_size = ATMEL_PDMIC_PREALLOC_BUF_SIZE, +}; + +/* codec */ +/* Mic Gain = dgain * 2^(-scale) */ +struct mic_gain { + unsigned int dgain; + unsigned int scale; +}; + +/* range from -90 dB to 90 dB */ +static const struct mic_gain mic_gain_table[] = { +{ 1, 15}, { 1, 14}, /* -90, -84 dB */ +{ 3, 15}, { 1, 13}, { 3, 14}, { 1, 12}, /* -81, -78, -75, -72 dB */ +{ 5, 14}, { 13, 15}, /* -70, -68 dB */ +{ 9, 14}, { 21, 15}, { 23, 15}, { 13, 14}, /* -65 ~ -62 dB */ +{ 29, 15}, { 33, 15}, { 37, 15}, { 41, 15}, /* -61 ~ -58 dB */ +{ 23, 14}, { 13, 13}, { 58, 15}, { 65, 15}, /* -57 ~ -54 dB */ +{ 73, 15}, { 41, 14}, { 23, 13}, { 13, 12}, /* -53 ~ -50 dB */ +{ 29, 13}, { 65, 14}, { 73, 14}, { 41, 13}, /* -49 ~ -46 dB */ +{ 23, 12}, { 207, 15}, { 29, 12}, { 65, 13}, /* -45 ~ -42 dB */ +{ 73, 13}, { 41, 12}, { 23, 11}, { 413, 15}, /* -41 ~ -38 dB */ +{ 463, 15}, { 519, 15}, { 583, 15}, { 327, 14}, /* -37 ~ -34 dB */ +{ 367, 14}, { 823, 15}, { 231, 13}, { 1036, 15}, /* -33 ~ -30 dB */ +{ 1163, 15}, { 1305, 15}, { 183, 12}, { 1642, 15}, /* -29 ~ -26 dB */ +{ 1843, 15}, { 2068, 15}, { 145, 11}, { 2603, 15}, /* -25 ~ -22 dB */ +{ 365, 12}, { 3277, 15}, { 3677, 15}, { 4125, 15}, /* -21 ~ -18 dB */ +{ 4629, 15}, { 5193, 15}, { 5827, 15}, { 3269, 14}, /* -17 ~ -14 dB */ +{ 917, 12}, { 8231, 15}, { 9235, 15}, { 5181, 14}, /* -13 ~ -10 dB */ +{11627, 15}, {13045, 15}, {14637, 15}, {16423, 15}, /* -9 ~ -6 dB */ +{18427, 15}, {20675, 15}, { 5799, 13}, {26029, 15}, /* -5 ~ -2 dB */ +{ 7301, 13}, { 1, 0}, {18383, 14}, {10313, 13}, /* -1 ~ 2 dB */ +{23143, 14}, {25967, 14}, {29135, 14}, {16345, 13}, /* 3 ~ 6 dB */ +{ 4585, 11}, {20577, 13}, { 1443, 9}, {25905, 13}, /* 7 ~ 10 dB */ +{14533, 12}, { 8153, 11}, { 2287, 9}, {20529, 12}, /* 11 ~ 14 dB */ +{11517, 11}, { 6461, 10}, {28997, 12}, { 4067, 9}, /* 15 ~ 18 dB */ +{18253, 11}, { 10, 0}, {22979, 11}, {25783, 11}, /* 19 ~ 22 dB */ +{28929, 11}, {32459, 11}, { 9105, 9}, {20431, 10}, /* 23 ~ 26 dB */ +{22925, 10}, {12861, 9}, { 7215, 8}, {16191, 9}, /* 27 ~ 30 dB */ +{ 9083, 8}, {20383, 9}, {11435, 8}, { 6145, 7}, /* 31 ~ 34 dB */ +{ 3599, 6}, {32305, 9}, {18123, 8}, {20335, 8}, /* 35 ~ 38 dB */ +{ 713, 3}, { 100, 0}, { 7181, 6}, { 8057, 6}, /* 39 ~ 42 dB */ +{ 565, 2}, {20287, 7}, {11381, 6}, {25539, 7}, /* 43 ~ 46 dB */ +{ 1791, 3}, { 4019, 4}, { 9019, 5}, {20239, 6}, /* 47 ~ 50 dB */ +{ 5677, 4}, {25479, 6}, { 7147, 4}, { 8019, 4}, /* 51 ~ 54 dB */ +{17995, 5}, {20191, 5}, {11327, 4}, {12709, 4}, /* 55 ~ 58 dB */ +{ 3565, 2}, { 1000, 0}, { 1122, 0}, { 1259, 0}, /* 59 ~ 62 dB */ +{ 2825, 1}, {12679, 3}, { 7113, 2}, { 7981, 2}, /* 63 ~ 66 dB */ +{ 8955, 2}, {20095, 3}, {22547, 3}, {12649, 2}, /* 67 ~ 70 dB */ +{28385, 3}, { 3981, 0}, {17867, 2}, {20047, 2}, /* 71 ~ 74 dB */ +{11247, 1}, {12619, 1}, {14159, 1}, {31773, 2}, /* 75 ~ 78 dB */ +{17825, 1}, {10000, 0}, {11220, 0}, {12589, 0}, /* 79 ~ 82 dB */ +{28251, 1}, {15849, 0}, {17783, 0}, {19953, 0}, /* 83 ~ 86 dB */ +{22387, 0}, {25119, 0}, {28184, 0}, {31623, 0}, /* 87 ~ 90 dB */ +}; + +static const DECLARE_TLV_DB_RANGE(mic_gain_tlv, + 0, 1, TLV_DB_SCALE_ITEM(-9000, 600, 0), + 2, 5, TLV_DB_SCALE_ITEM(-8100, 300, 0), + 6, 7, TLV_DB_SCALE_ITEM(-7000, 200, 0), + 8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0), +); + +int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int dgain_val, scale_val; + int i; + + dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK) + >> PDMIC_DSPR1_DGAIN_SHIFT; + + scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK) + >> PDMIC_DSPR0_SCALE_SHIFT; + + for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) { + if ((mic_gain_table[i].dgain == dgain_val) && + (mic_gain_table[i].scale == scale_val)) + ucontrol->value.integer.value[0] = i; + } + + return 0; +} + +static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int max = mc->max; + unsigned int val; + int ret; + + val = ucontrol->value.integer.value[0]; + + if (val > max) + return -EINVAL; + + ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK, + mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT); + if (ret < 0) + return ret; + + ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK, + mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_kcontrol_new atmel_pdmic_snd_controls[] = { +SOC_SINGLE_EXT_TLV("Mic Capture Volume", PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_SHIFT, + ARRAY_SIZE(mic_gain_table)-1, 0, + pdmic_get_mic_volsw, pdmic_put_mic_volsw, mic_gain_tlv), + +SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0, + PDMIC_DSPR0_HPFBYP_SHIFT, 1, 1), + +SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1), +}; + +static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec); + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card); + + snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK, + (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT)); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_pdmic = { + .probe = atmel_pdmic_codec_probe, + .controls = atmel_pdmic_snd_controls, + .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls), +}; + +/* codec dai component */ +#define PDMIC_MR_PRESCAL_MAX_VAL 127 + +static int +atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = codec_dai->codec; + unsigned int rate_min = substream->runtime->hw.rate_min; + unsigned int rate_max = substream->runtime->hw.rate_max; + int fs = params_rate(params); + int bits = params_width(params); + unsigned long pclk_rate, gclk_rate; + unsigned int f_pdmic; + u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal; + + if (params_channels(params) != 1) { + dev_err(codec->dev, + "only supports one channel\n"); + return -EINVAL; + } + + if ((fs < rate_min) || (fs > rate_max)) { + dev_err(codec->dev, + "sample rate is %dHz, min rate is %dHz, max rate is %dHz\n", + fs, rate_min, rate_max); + + return -EINVAL; + } + + switch (bits) { + case 16: + dspr0_val = (PDMIC_DSPR0_SIZE_16_BITS + << PDMIC_DSPR0_SIZE_SHIFT); + break; + case 32: + dspr0_val = (PDMIC_DSPR0_SIZE_32_BITS + << PDMIC_DSPR0_SIZE_SHIFT); + break; + default: + return -EINVAL; + } + + if ((fs << 7) > (rate_max << 6)) { + f_pdmic = fs << 6; + dspr0_val |= PDMIC_DSPR0_OSR_64 << PDMIC_DSPR0_OSR_SHIFT; + } else { + f_pdmic = fs << 7; + dspr0_val |= PDMIC_DSPR0_OSR_128 << PDMIC_DSPR0_OSR_SHIFT; + } + + pclk_rate = clk_get_rate(dd->pclk); + gclk_rate = clk_get_rate(dd->gclk); + + /* PRESCAL = SELCK/(2*f_pdmic) - 1*/ + pclk_prescal = (u32)(pclk_rate/(f_pdmic << 1)) - 1; + gclk_prescal = (u32)(gclk_rate/(f_pdmic << 1)) - 1; + + if ((pclk_prescal > PDMIC_MR_PRESCAL_MAX_VAL) || + (gclk_rate/((gclk_prescal + 1) << 1) < + pclk_rate/((pclk_prescal + 1) << 1))) { + mr_val = gclk_prescal << PDMIC_MR_PRESCAL_SHIFT; + mr_val |= PDMIC_MR_CLKS_GCK << PDMIC_MR_CLKS_SHIFT; + } else { + mr_val = pclk_prescal << PDMIC_MR_PRESCAL_SHIFT; + mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT; + } + + snd_soc_update_bits(codec, PDMIC_MR, + PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val); + + snd_soc_update_bits(codec, PDMIC_DSPR0, + PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val); + + return 0; +} + +static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, + PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT); + + return 0; +} + +static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 val; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = PDMIC_CR_ENPDM_EN << PDMIC_CR_ENPDM_SHIFT; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val); + + return 0; +} + +static const struct snd_soc_dai_ops atmel_pdmic_codec_dai_ops = { + .hw_params = atmel_pdmic_codec_dai_hw_params, + .prepare = atmel_pdmic_codec_dai_prepare, + .trigger = atmel_pdmic_codec_dai_trigger, +}; + +#define ATMEL_PDMIC_CODEC_DAI_NAME "atmel-pdmic-hifi" + +static struct snd_soc_dai_driver atmel_pdmic_codec_dai = { + .name = ATMEL_PDMIC_CODEC_DAI_NAME, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ATMEL_PDMIC_FORMATS, + }, + .ops = &atmel_pdmic_codec_dai_ops, +}; + +/* ASoC sound card */ +static int atmel_pdmic_asoc_card_init(struct device *dev, + struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card); + + dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL); + if (!dai_link) + return -ENOMEM; + + dai_link->name = "PDMIC"; + dai_link->stream_name = "PDMIC PCM"; + dai_link->codec_dai_name = ATMEL_PDMIC_CODEC_DAI_NAME; + dai_link->cpu_dai_name = dev_name(dev); + dai_link->codec_name = dev_name(dev); + dai_link->platform_name = dev_name(dev); + + card->dai_link = dai_link; + card->num_links = 1; + card->name = dd->pdata->card_name; + card->dev = dev; + + return 0; +} + +static void atmel_pdmic_get_sample_rate(struct atmel_pdmic *dd, + unsigned int *rate_min, unsigned int *rate_max) +{ + u32 mic_min_freq = dd->pdata->mic_min_freq; + u32 mic_max_freq = dd->pdata->mic_max_freq; + u32 clk_max_rate = (u32)(clk_get_rate(dd->pclk) >> 1); + u32 clk_min_rate = (u32)(clk_get_rate(dd->gclk) >> 8); + + if (mic_max_freq > clk_max_rate) + mic_max_freq = clk_max_rate; + + if (mic_min_freq < clk_min_rate) + mic_min_freq = clk_min_rate; + + *rate_min = DIV_ROUND_CLOSEST(mic_min_freq, 128); + *rate_max = mic_max_freq >> 6; +} + +/* PDMIC interrupt handler */ +static irqreturn_t atmel_pdmic_interrupt(int irq, void *dev_id) +{ + struct atmel_pdmic *dd = (struct atmel_pdmic *)dev_id; + u32 pdmic_isr; + irqreturn_t ret = IRQ_NONE; + + regmap_read(dd->regmap, PDMIC_ISR, &pdmic_isr); + + if (pdmic_isr & PDMIC_ISR_OVRE) { + regmap_update_bits(dd->regmap, PDMIC_CR, PDMIC_CR_ENPDM_MASK, + PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT); + + snd_pcm_stop_xrun(dd->substream); + + ret = IRQ_HANDLED; + } + + return ret; +} + +/* regmap configuration */ +#define ATMEL_PDMIC_REG_MAX 0x124 +static const struct regmap_config atmel_pdmic_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_PDMIC_REG_MAX, +}; + +static int atmel_pdmic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct atmel_pdmic *dd; + struct resource *res; + void __iomem *io_base; + const struct atmel_pdmic_pdata *pdata; + struct snd_soc_card *card; + unsigned int rate_min, rate_max; + int ret; + + pdata = atmel_pdmic_dt_init(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + dd->pdata = pdata; + + dd->irq = platform_get_irq(pdev, 0); + if (dd->irq < 0) { + ret = dd->irq; + dev_err(dev, "failed to could not get irq: %d\n", ret); + return ret; + } + + dd->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dd->pclk)) { + ret = PTR_ERR(dd->pclk); + dev_err(dev, "failed to get peripheral clock: %d\n", ret); + return ret; + } + + dd->gclk = devm_clk_get(dev, "gclk"); + if (IS_ERR(dd->gclk)) { + ret = PTR_ERR(dd->gclk); + dev_err(dev, "failed to get GCK: %d\n", ret); + return ret; + } + + /* The gclk clock frequency must always be tree times + * lower than the pclk clock frequency + */ + ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3); + if (ret) { + dev_err(dev, "failed to set GCK clock rate: %d\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no memory resource\n"); + return -ENXIO; + } + + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) { + ret = PTR_ERR(io_base); + dev_err(dev, "failed to remap register memory: %d\n", ret); + return ret; + } + + dd->phy_base = res->start; + + dd->regmap = devm_regmap_init_mmio(dev, io_base, + &atmel_pdmic_regmap_config); + if (IS_ERR(dd->regmap)) { + ret = PTR_ERR(dd->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, dd->irq, atmel_pdmic_interrupt, 0, + "PDMIC", (void *)dd); + if (ret < 0) { + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", + dd->irq, ret); + return ret; + } + + /* Get the minimal and maximal sample rate that micphone supports */ + atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max); + + /* register cpu dai */ + atmel_pdmic_cpu_dai.capture.rate_min = rate_min; + atmel_pdmic_cpu_dai.capture.rate_max = rate_max; + ret = devm_snd_soc_register_component(dev, + &atmel_pdmic_cpu_dai_component, + &atmel_pdmic_cpu_dai, 1); + if (ret) { + dev_err(dev, "could not register CPU DAI: %d\n", ret); + return ret; + } + + /* register platform */ + ret = devm_snd_dmaengine_pcm_register(dev, + &atmel_pdmic_dmaengine_pcm_config, + 0); + if (ret) { + dev_err(dev, "could not register platform: %d\n", ret); + return ret; + } + + /* register codec and codec dai */ + atmel_pdmic_codec_dai.capture.rate_min = rate_min; + atmel_pdmic_codec_dai.capture.rate_max = rate_max; + ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic, + &atmel_pdmic_codec_dai, 1); + if (ret) { + dev_err(dev, "could not register codec: %d\n", ret); + return ret; + } + + /* register sound card */ + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) { + ret = -ENOMEM; + goto unregister_codec; + } + + snd_soc_card_set_drvdata(card, dd); + platform_set_drvdata(pdev, card); + + ret = atmel_pdmic_asoc_card_init(dev, card); + if (ret) { + dev_err(dev, "failed to init sound card: %d\n", ret); + goto unregister_codec; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret) { + dev_err(dev, "failed to register sound card: %d\n", ret); + goto unregister_codec; + } + + return 0; + +unregister_codec: + snd_soc_unregister_codec(dev); + return ret; +} + +static int atmel_pdmic_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver atmel_pdmic_driver = { + .driver = { + .name = "atmel-pdmic", + .of_match_table = of_match_ptr(atmel_pdmic_of_match), + .pm = &snd_soc_pm_ops, + }, + .probe = atmel_pdmic_probe, + .remove = atmel_pdmic_remove, +}; +module_platform_driver(atmel_pdmic_driver); + +MODULE_DESCRIPTION("Atmel PDMIC driver under ALSA SoC architecture"); +MODULE_AUTHOR("Songjun Wu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/atmel/atmel-pdmic.h b/sound/soc/atmel/atmel-pdmic.h new file mode 100644 index 000000000000..4527ac741919 --- /dev/null +++ b/sound/soc/atmel/atmel-pdmic.h @@ -0,0 +1,80 @@ +#ifndef __ATMEL_PDMIC_H_ +#define __ATMEL_PDMIC_H_ + +#include + +#define PDMIC_CR 0x00000000 + +#define PDMIC_CR_SWRST 0x1 +#define PDMIC_CR_SWRST_MASK BIT(0) +#define PDMIC_CR_SWRST_SHIFT (0) + +#define PDMIC_CR_ENPDM_DIS 0x0 +#define PDMIC_CR_ENPDM_EN 0x1 +#define PDMIC_CR_ENPDM_MASK BIT(4) +#define PDMIC_CR_ENPDM_SHIFT (4) + +#define PDMIC_MR 0x00000004 + +#define PDMIC_MR_CLKS_PCK 0x0 +#define PDMIC_MR_CLKS_GCK 0x1 +#define PDMIC_MR_CLKS_MASK BIT(4) +#define PDMIC_MR_CLKS_SHIFT (4) + +#define PDMIC_MR_PRESCAL_MASK GENMASK(14, 8) +#define PDMIC_MR_PRESCAL_SHIFT (8) + +#define PDMIC_CDR 0x00000014 + +#define PDMIC_IER 0x00000018 +#define PDMIC_IER_OVRE BIT(25) + +#define PDMIC_IDR 0x0000001c +#define PDMIC_IDR_OVRE BIT(25) + +#define PDMIC_IMR 0x00000020 + +#define PDMIC_ISR 0x00000024 +#define PDMIC_ISR_OVRE BIT(25) + +#define PDMIC_DSPR0 0x00000058 + +#define PDMIC_DSPR0_HPFBYP_DIS 0x1 +#define PDMIC_DSPR0_HPFBYP_EN 0x0 +#define PDMIC_DSPR0_HPFBYP_MASK BIT(1) +#define PDMIC_DSPR0_HPFBYP_SHIFT (1) + +#define PDMIC_DSPR0_SINBYP_DIS 0x1 +#define PDMIC_DSPR0_SINBYP_EN 0x0 +#define PDMIC_DSPR0_SINBYP_MASK BIT(2) +#define PDMIC_DSPR0_SINBYP_SHIFT (2) + +#define PDMIC_DSPR0_SIZE_16_BITS 0x0 +#define PDMIC_DSPR0_SIZE_32_BITS 0x1 +#define PDMIC_DSPR0_SIZE_MASK BIT(3) +#define PDMIC_DSPR0_SIZE_SHIFT (3) + +#define PDMIC_DSPR0_OSR_128 0x0 +#define PDMIC_DSPR0_OSR_64 0x1 +#define PDMIC_DSPR0_OSR_MASK GENMASK(6, 4) +#define PDMIC_DSPR0_OSR_SHIFT (4) + +#define PDMIC_DSPR0_SCALE_MASK GENMASK(11, 8) +#define PDMIC_DSPR0_SCALE_SHIFT (8) + +#define PDMIC_DSPR0_SHIFT_MASK GENMASK(15, 12) +#define PDMIC_DSPR0_SHIFT_SHIFT (12) + +#define PDMIC_DSPR1 0x0000005c + +#define PDMIC_DSPR1_DGAIN_MASK GENMASK(14, 0) +#define PDMIC_DSPR1_DGAIN_SHIFT (0) + +#define PDMIC_DSPR1_OFFSET_MASK GENMASK(31, 16) +#define PDMIC_DSPR1_OFFSET_SHIFT (16) + +#define PDMIC_WPMR 0x000000e4 + +#define PDMIC_WPSR 0x000000e8 + +#endif -- cgit v1.2.3 From 5c27087e4b43e2a5be144afe7250fb2b20bd47c4 Mon Sep 17 00:00:00 2001 From: Rohit Ainapure Date: Fri, 11 Dec 2015 11:29:06 -0800 Subject: ASoC: max98357a: Add ACPI ID for Maxim Adding ACPI ID "MX98357A" for the MAXIM 98357A amp. Signed-off-by: Rohit Ainapure Signed-off-by: Fang, Yang A Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index f5e3dce2633a..5b1dfb1518fb 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -12,6 +12,7 @@ * max98357a.c -- MAX98357A ALSA SoC Codec driver */ +#include #include #include #include @@ -123,10 +124,19 @@ static const struct of_device_id max98357a_device_id[] = { MODULE_DEVICE_TABLE(of, max98357a_device_id); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id max98357a_acpi_match[] = { + { "MX98357A", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match); +#endif + static struct platform_driver max98357a_platform_driver = { .driver = { .name = "max98357a", .of_match_table = of_match_ptr(max98357a_device_id), + .acpi_match_table = ACPI_PTR(max98357a_acpi_match), }, .probe = max98357a_platform_probe, .remove = max98357a_platform_remove, -- cgit v1.2.3 From 2005bd881d273456e26a0b2027976f75fc47701f Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Wed, 16 Dec 2015 13:02:55 +0000 Subject: ASoC: wm8974: add devicetree support This adds devicetree support to the wm8974 codec driver. With a DT-based kernel, there is no board-specific setting to select the driver so allow it to be manually chosen. Signed-off-by: Mans Rullgard Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- sound/soc/codecs/wm8974.c | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..e36b14c5cb57 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -838,7 +838,8 @@ config SND_SOC_WM8971 tristate config SND_SOC_WM8974 - tristate + tristate "Wolfson Microelectronics WM8974 codec" + depends on I2C config SND_SOC_WM8978 tristate "Wolfson Microelectronics WM8978 codec" diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 0a60677397b3..45ba828b19de 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -631,9 +631,16 @@ static const struct i2c_device_id wm8974_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); +static const struct of_device_id wm8974_of_match[] = { + { .compatible = "wlf,wm8974", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8974_of_match); + static struct i2c_driver wm8974_i2c_driver = { .driver = { .name = "wm8974", + .of_match_table = wm8974_of_match, }, .probe = wm8974_i2c_probe, .remove = wm8974_i2c_remove, -- cgit v1.2.3 From 69b7f9c45856e49929bdde8492e5f46a07c8a2f3 Mon Sep 17 00:00:00 2001 From: Rohit Ainapure Date: Fri, 11 Dec 2015 11:29:07 -0800 Subject: ASoC: Intel: Add Nuvoton+Maxim machine driver entry Add the NAU88L25 + MAX98357A machine driver entry into the machine table Signed-off-by: Rohit Ainapure Signed-off-by: Fang, Yang A Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2c16325d1ce1..c38bf99ced10 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -600,6 +600,8 @@ static struct sst_acpi_mach sst_skl_devdata[] = { { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, + { "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin", + NULL, NULL, NULL }, {} }; -- cgit v1.2.3 From 8eaf2b31dd316ff5ffbdad14853d2bf8779bab13 Mon Sep 17 00:00:00 2001 From: Rohit Ainapure Date: Fri, 11 Dec 2015 11:29:08 -0800 Subject: ASoC: Intel: Skylake: Add Nuvoton Maxim machine driver This adds Skylake I2S machine driver which uses NAU88L25 as anlog codec and MAX98357A as speakers Signed-off-by: Rohit Ainapure Signed-off-by: Fang, Yang A Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 14 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/skl_nau88l25_max98357a.c | 485 ++++++++++++++++++++++++ 3 files changed, 501 insertions(+) create mode 100644 sound/soc/intel/boards/skl_nau88l25_max98357a.c (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2d3b12401db1..9b1c0aa8d2d9 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -169,3 +169,17 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH create an alsa sound card for NAU88L25 + SSM4567. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH + tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_NAU8825 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for NAU88L25 + MAX98357A. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index a59f76277cee..2485ea9434ad 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -7,6 +7,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o @@ -18,4 +19,5 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c new file mode 100644 index 000000000000..ab7da9c304b2 --- /dev/null +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -0,0 +1,485 @@ +/* + * Intel Skylake I2S Machine Driver with MAXIM98357A + * and NAU88L25 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" +#define SKL_MAXIM_CODEC_DAI "HiFi" + +static struct snd_soc_jack skylake_headset; +static struct snd_soc_card skylake_audio_card; + +static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI, + strlen(SKL_NUVOTON_CODEC_DAI))) + return rtd->codec_dai; + } + + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = skl_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } + + return ret; +} + +static const struct snd_kcontrol_new skylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget skylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route skylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Spk", NULL, "Speaker" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, + { "DMic", NULL, "SoC DMIC" }, + + {"WoV Sink", NULL, "hwd_in sink"}, + {"HDMI", NULL, "hif5 Output"}, + {"DP", NULL, "hif6 Output"}, + + /* CODEC BE connections */ + { "HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + { "hifi1", NULL, "iDisp Tx"}, + { "iDisp Tx", NULL, "iDisp_out"}, + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + nau8825_enable_jack_detect(codec, &skylake_headset); + + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); + + return ret; +} + +static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_nau8825_fe_ops = { + .startup = skl_fe_startup, +}; + +static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops skylake_nau8825_ops = { + .hw_params = skylake_nau8825_hw_params, +}; + +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static int skylake_refcap_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = skylake_refcap_startup, +}; + +/* skylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link skylake_dais[] = { + /* Front End DAI links */ + { + .name = "Skl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = skylake_nau8825_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, + }, + { + .name = "Skl HDMI Port", + .stream_name = "Hdmi", + .cpu_dai_name = "HDMI Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .be_id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "MX98357A:00", + .codec_dai_name = SKL_MAXIM_CODEC_DAI, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .be_id = 0, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10508825:00", + .codec_dai_name = SKL_NUVOTON_CODEC_DAI, + .init = skylake_nau8825_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .ops = &skylake_nau8825_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .be_id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = skylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp", + .be_id = 3, + .cpu_dai_name = "iDisp Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* skylake audio machine driver for SPT + NAU88L25 */ +static struct snd_soc_card skylake_audio_card = { + .name = "sklnau8825max", + .owner = THIS_MODULE, + .dai_link = skylake_dais, + .num_links = ARRAY_SIZE(skylake_dais), + .controls = skylake_controls, + .num_controls = ARRAY_SIZE(skylake_controls), + .dapm_widgets = skylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), + .dapm_routes = skylake_map, + .num_dapm_routes = ARRAY_SIZE(skylake_map), + .fully_routed = true, +}; + +static int skylake_audio_probe(struct platform_device *pdev) +{ + skylake_audio_card.dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); +} + +static struct platform_driver skylake_audio = { + .probe = skylake_audio_probe, + .driver = { + .name = "skl_nau88l25_max98357a_i2s", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); +MODULE_AUTHOR("Rohit Ainapure Date: Fri, 11 Dec 2015 11:29:09 -0800 Subject: ASoc: Intel: boards: fix dapm map of nau88l25_ssm4567 machine The DAPM map for DMIC and SSP was not properly done, so fix that up. Also mark machine as fully routed Signed-off-by: Vinod Koul Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 65c65d4c422c..9c9ebb8d0734 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -108,22 +108,22 @@ static const struct snd_soc_dapm_route skylake_map[] = { /* other jacks */ {"MIC", NULL, "Headset Mic"}, - {"DMIC AIF", NULL, "SoC DMIC"}, + {"DMic", NULL, "SoC DMIC"}, /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, - { "AIF1 Playback", NULL, "ssp1 Tx"}, + { "Playback", NULL, "ssp1 Tx"}, { "ssp1 Tx", NULL, "codec1_out"}, { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF1 Capture" }, + { "ssp1 Rx", NULL, "Capture" }, /* DMIC */ { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, }; @@ -336,6 +336,7 @@ static struct snd_soc_card skylake_audio_card = { .num_dapm_routes = ARRAY_SIZE(skylake_map), .codec_conf = ssm4567_codec_conf, .num_configs = ARRAY_SIZE(ssm4567_codec_conf), + .fully_routed = true, }; static int skylake_audio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 941eee74563652f6cc363d8d62b3a9f4bfffdbe2 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Fri, 11 Dec 2015 11:29:10 -0800 Subject: ASoc: Intel: boards: update ignore suspend for nau88l25_ssm4567 machine We don't support ignore suspend on few devices so remove that. Also since we support ignore susend on PDM DMIC, add that Signed-off-by: Vinod Koul Signed-off-by: Yong Zhi Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 9c9ebb8d0734..8aa821c6b106 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -187,6 +187,8 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) nau8825_enable_jack_detect(codec, &skylake_headset); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + return ret; } @@ -285,7 +287,6 @@ static struct snd_soc_dai_link skylake_dais[] = { SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS, .init = skylake_ssm4567_codec_init, - .ignore_suspend = 1, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .dpcm_playback = 1, @@ -302,7 +303,6 @@ static struct snd_soc_dai_link skylake_dais[] = { .init = skylake_nau8825_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .ignore_suspend = 1, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .ops = &skylake_nau8825_ops, -- cgit v1.2.3 From 2616e27efb21f82e666312cbbab53e6600225ef1 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Fri, 11 Dec 2015 11:29:11 -0800 Subject: ASoc: Intel: boards: update constraints for nau88l25_ssm4567 machine We have specific constraints for FE device (48KHz, stereo, 16 bits) and fixups for BE DMIC links (2 or 4 ch), so add those. Also add one more FE DAIlink for dmiccap Signed-off-by: Vinod Koul Signed-off-by: Fang, Yang A Signed-off-by: Jeeja KP Signed-off-by: Yong Zhi Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 136 ++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 8aa821c6b106..1b54613132c1 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -192,6 +192,65 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } +static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * on this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_nau8825_fe_ops = { + .startup = skl_fe_startup, +}; + static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -211,6 +270,19 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -231,6 +303,52 @@ static struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static int skylake_refcap_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = skylake_refcap_startup, +}; + /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_dais[] = { /* Front End DAI links */ @@ -243,9 +361,11 @@ static struct snd_soc_dai_link skylake_dais[] = { .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .nonatomic = 1, + .init = skylake_nau8825_fe_init, .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, + .ops = &skylake_nau8825_fe_ops, }, { .name = "Skl Audio Capture Port", @@ -259,6 +379,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_capture = 1, + .ops = &skylake_nau8825_fe_ops, }, { .name = "Skl Audio Reference cap", @@ -272,6 +393,20 @@ static struct snd_soc_dai_link skylake_dais[] = { .ignore_suspend = 1, .nonatomic = 1, .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, }, /* Back End DAI links */ { @@ -317,6 +452,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .codec_dai_name = "dmic-hifi", .platform_name = "0000:00:1f.3", .ignore_suspend = 1, + .be_hw_params_fixup = skylake_dmic_fixup, .dpcm_capture = 1, .no_pcm = 1, }, -- cgit v1.2.3 From 2154be362c9050b9ed5d3beac491f0103505bf16 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Fri, 11 Dec 2015 11:29:12 -0800 Subject: ASoc: Intel: boards: Add WOV as sink for nau88l25_ssm4567 machine We have WOV module which should act as DAPM sink, so add that and its links. Also rename the refcap to "Wake On Voice" as some user expect to find this name Signed-off-by: Vinod Koul Signed-off-by: Fang, Yang A Signed-off-by: Sathyanarayana Nujella Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 1b54613132c1..f6c252cccdb4 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -92,6 +92,7 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -110,6 +111,7 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"}, + {"WoV Sink", NULL, "hwd_in sink"}, /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, @@ -188,6 +190,7 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) nau8825_enable_jack_detect(codec, &skylake_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); return ret; } @@ -383,7 +386,7 @@ static struct snd_soc_dai_link skylake_dais[] = { }, { .name = "Skl Audio Reference cap", - .stream_name = "refcap", + .stream_name = "Wake on Voice", .cpu_dai_name = "Reference Pin", .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", -- cgit v1.2.3 From 743ad80e5c8565ab54e8832f6d74cb543a0adbba Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Fri, 11 Dec 2015 11:29:13 -0800 Subject: ASoc: Intel: boards: Add HDMI/DP links for nau88l25_ssm4567 machine This machine supports HDMI/DP ports so add these ports and its FE and BE DAIlinks Signed-off-by: Vinod Koul Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index f6c252cccdb4..c071812f31e5 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -93,6 +93,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SINK("WoV Sink"), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -112,6 +114,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"DMic", NULL, "SoC DMIC"}, {"WoV Sink", NULL, "hwd_in sink"}, + + {"HDMI", NULL, "hif5 Output"}, + {"DP", NULL, "hif6 Output"}, /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, @@ -126,6 +131,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { /* DMIC */ { "dmic01_hifi", NULL, "DMIC01 Rx" }, { "DMIC01 Rx", NULL, "DMIC AIF" }, + { "hifi1", NULL, "iDisp Tx"}, + { "iDisp Tx", NULL, "iDisp_out"}, { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, }; @@ -411,6 +418,19 @@ static struct snd_soc_dai_link skylake_dais[] = { .dynamic = 1, .ops = &skylake_dmic_ops, }, + { + .name = "Skl HDMI Port", + .stream_name = "Hdmi", + .cpu_dai_name = "HDMI Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + /* Back End DAI links */ { /* SSP0 - Codec */ @@ -459,6 +479,16 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .no_pcm = 1, }, + { + .name = "iDisp", + .be_id = 3, + .cpu_dai_name = "iDisp Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .no_pcm = 1, + }, }; /* skylake audio machine driver for SPT + NAU88L25 */ -- cgit v1.2.3 From cdf310ce119989353bb6848ca8327814ae1012e2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:55:25 +0000 Subject: ASoC: rsnd: fixup SSIU control timing SSIU should be controlled after SSI. This patch fix up it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ad854d6719ea..4b677e074c7a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -181,9 +181,9 @@ enum rsnd_mod_type { RSND_MOD_CTU, RSND_MOD_CMD, RSND_MOD_SRC, - RSND_MOD_SSIU, RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, + RSND_MOD_SSIU, RSND_MOD_MAX, }; -- cgit v1.2.3 From 5e7b9edd928d22ffd4936fc61c80532ed6df5077 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:55:51 +0000 Subject: ASoC: rsnd: tidyup return value of rsnd_get_adinr_bit() Renesas sound driver has rsnd_get_adinr_bit/chan() functions. It is assuming _bit() returns ADINR :: OTBL, and _chan() returns ADINR :: CHNUM. Current _bit() returns both OTBL and CHNUM. This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 849c1ad93df2..44f32c1db05d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -227,21 +227,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - u32 adinr = runtime->channels; switch (runtime->sample_bits) { case 16: - adinr |= (8 << 16); - break; + return 8 << 16; case 32: - adinr |= (0 << 16); - break; - default: - dev_warn(dev, "not supported sample bits\n"); - return 0; + return 0 << 16; } - return adinr; + dev_warn(dev, "not supported sample bits\n"); + + return 0; } u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -- cgit v1.2.3 From c90269c1fbfcb3082d379237f0912ea231e90a24 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:56:11 +0000 Subject: ASoC: rsnd: tidyup debug print position on rsnd_dma_attach() It can't output corrent dma name *before* rsnd_mod_init(). It goes to *after* rsnd_mod_init() by this patch Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 33eb37331498..418e6fdd06a3 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -680,16 +680,16 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, dma_mod = rsnd_mod_get(dma); - dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", - rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), - rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), - rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - ret = rsnd_mod_init(priv, dma_mod, ops, NULL, type, dma_id); if (ret < 0) return ERR_PTR(ret); + dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", + rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), + rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), + rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + ret = attach(io, dma, id, mod_from, mod_to); if (ret < 0) return ERR_PTR(ret); -- cgit v1.2.3 From 52dc68524327ed7bedfc2856bca4fa634f11141a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:56:31 +0000 Subject: ASoC: rsnd: rsnd_dai_connect() returns error if it connect to existing mod Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 44f32c1db05d..e59dc8a461bb 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -354,6 +354,9 @@ int rsnd_dai_connect(struct rsnd_mod *mod, if (!mod) return -EIO; + if (io->mod[type]) + return -EINVAL; + priv = rsnd_mod_to_priv(mod); dev = rsnd_priv_to_dev(priv); -- cgit v1.2.3 From 49ee73b441f5734c3da254c60e134f343b89911a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:56:50 +0000 Subject: ASoC: rsnd: SSI/SSIU use rsnd_get_slot_extend() to check TDM Current SSI/SSIU are using rsnd_get_slot_runtime() to check TDM, but using rsnd_get_slot_extend() is more sane. This patch fix it up Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 2 +- sound/soc/sh/rcar/ssiu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 79c3211a1e7f..7481bc3e0dff 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -267,7 +267,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, u32 wsr; int is_tdm; - is_tdm = (rsnd_get_slot_runtime(io) >= 6) ? 1 : 0; + is_tdm = (rsnd_get_slot_extend(io) >= 6) ? 1 : 0; /* * always use 32bit system word. diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 326550114299..c7f89beff44f 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -78,7 +78,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; - if (rsnd_get_slot_runtime(io) >= 6) { + if (rsnd_get_slot_extend(io) >= 6) { /* * TDM Extend Mode * see -- cgit v1.2.3 From 5858a7d17e266945b9860768d0549aeb6a52d31f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:57:07 +0000 Subject: ASoC: rsnd: remove rsnd_get_slot_runtime() Current Renesas sound driver is using rsnd_get_slot_runtime(), but it is same as runtime->channels. This patch removes rsnd_get_slot_runtime() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 19 ++++--------------- sound/soc/sh/rcar/rsnd.h | 1 - 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e59dc8a461bb..7f3a7edba096 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -196,21 +196,10 @@ int rsnd_get_slot_rdai(struct rsnd_dai *rdai) return rdai->slots; } -int rsnd_get_slot_runtime(struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int chan = rsnd_get_slot_rdai(rdai); - - if (runtime->channels < chan) - chan = runtime->channels; - - return chan; -} - int rsnd_get_slot_extend(struct rsnd_dai_stream *io) { - int chan = rsnd_get_slot_runtime(io); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int chan = runtime->channels; /* TDM Extend Mode needs 8ch */ if (chan == 6) @@ -243,9 +232,9 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - u32 chan = rsnd_get_slot_rdai(rdai); + u32 chan = runtime->channels; switch (chan) { case 1: diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4b677e074c7a..e9909a4ce754 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -294,7 +294,6 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); int rsnd_get_slot_rdai(struct rsnd_dai *rdai); -int rsnd_get_slot_runtime(struct rsnd_dai_stream *io); int rsnd_get_slot_extend(struct rsnd_dai_stream *io); /* -- cgit v1.2.3 From c140284b8085e0fa07c24f4285db9dc107ad2ed3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:57:27 +0000 Subject: ASoC: rsnd: tidyup rsnd_get_slot_xxx() naming rsnd_get_slot_rdai() returns total slots (it returns 6 if total 6 channels) , and rsnd_get_slot_extend() returns extended SSI width (it returns 8 if total 6 channels). This will be used on SSI multi channel support too (It will return 2 if total 6 channels with 3 SSI). But, it is using confusable naming. This patch changes rsnd_get_slot_rdai() -> rsnd_get_slot(), rsnd_get_slot_extend() -> rsnd_get_slot_width() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++++-- sound/soc/sh/rcar/dvc.c | 3 +-- sound/soc/sh/rcar/rsnd.h | 4 ++-- sound/soc/sh/rcar/ssi.c | 4 ++-- sound/soc/sh/rcar/ssiu.c | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7f3a7edba096..76af41633f9f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -191,12 +191,14 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return !!io->substream; } -int rsnd_get_slot_rdai(struct rsnd_dai *rdai) +int rsnd_get_slot(struct rsnd_dai_stream *io) { + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + return rdai->slots; } -int rsnd_get_slot_extend(struct rsnd_dai_stream *io) +int rsnd_get_slot_width(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); int chan = runtime->channels; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 42e6a230a3d1..d45ffe496397 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -242,10 +242,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); int is_play = rsnd_io_is_play(io); - int slots = rsnd_get_slot_rdai(rdai); + int slots = rsnd_get_slot(io); int ret; /* Volume */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e9909a4ce754..804f2f5622e0 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -293,8 +293,8 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); -int rsnd_get_slot_rdai(struct rsnd_dai *rdai); -int rsnd_get_slot_extend(struct rsnd_dai_stream *io); +int rsnd_get_slot(struct rsnd_dai_stream *io); +int rsnd_get_slot_width(struct rsnd_dai_stream *io); /* * R-Car sound DAI diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7481bc3e0dff..0b91692c5a66 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -180,7 +180,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - int slots = rsnd_get_slot_extend(io); + int slots = rsnd_get_slot_width(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -267,7 +267,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, u32 wsr; int is_tdm; - is_tdm = (rsnd_get_slot_extend(io) >= 6) ? 1 : 0; + is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0; /* * always use 32bit system word. diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index c7f89beff44f..7ae05a7621ae 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -78,7 +78,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; - if (rsnd_get_slot_extend(io) >= 6) { + if (rsnd_get_slot_width(io) >= 6) { /* * TDM Extend Mode * see -- cgit v1.2.3 From 750fd445ac53f1623cfcbf710d2bfc7aa1b7086d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:57:47 +0000 Subject: ASoC: rsnd: add rsnd_set_slot() / rsnd_get_slot_num() TDM will use 6 or 8 slots on 1 SSI, and Multi channel will use 6 or 8 slots on few SSI (each SSI uses 2 slots). Thus, this adds new slot control functions which can be prepare for Multi channel support. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 20 +++++++++++++++++--- sound/soc/sh/rcar/rsnd.h | 4 ++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 76af41633f9f..528041eff704 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -191,6 +191,13 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return !!io->substream; } +void rsnd_set_slot(struct rsnd_dai *rdai, + int slots, int num) +{ + rdai->slots = slots; + rdai->slots_num = num; +} + int rsnd_get_slot(struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); @@ -198,10 +205,17 @@ int rsnd_get_slot(struct rsnd_dai_stream *io) return rdai->slots; } +int rsnd_get_slot_num(struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + + return rdai->slots_num; +} + int rsnd_get_slot_width(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int chan = runtime->channels; + int chan = runtime->channels / rsnd_get_slot_num(io); /* TDM Extend Mode needs 8ch */ if (chan == 6) @@ -579,7 +593,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, switch (slots) { case 6: /* TDM Extend Mode */ - rdai->slots = slots; + rsnd_set_slot(rdai, slots, 1); break; default: dev_err(dev, "unsupported TDM slots (%d)\n", slots); @@ -660,7 +674,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) rdai->playback.rdai = rdai; rdai->capture.rdai = rdai; - rdai->slots = 2; /* default */ + rsnd_set_slot(rdai, 2, 1); /* default */ #define mod_parse(name) \ node = rsnd_##name##_of_node(priv); \ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 804f2f5622e0..c9aef234d002 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -293,8 +293,11 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); +void rsnd_set_slot(struct rsnd_dai *rdai, + int slots, int slots_total); int rsnd_get_slot(struct rsnd_dai_stream *io); int rsnd_get_slot_width(struct rsnd_dai_stream *io); +int rsnd_get_slot_num(struct rsnd_dai_stream *io); /* * R-Car sound DAI @@ -334,6 +337,7 @@ struct rsnd_dai { struct rsnd_priv *priv; int slots; + int slots_num; unsigned int clk_master:1; unsigned int bit_clk_inv:1; -- cgit v1.2.3 From 89b66174eca6609020cc3d1ef32df7956fd16b34 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 02:58:14 +0000 Subject: ASoC: rsnd: add rsnd_parse_connect_common() and remove complex macro Current rsnd driver is using complex macro to parse DAI connection. This patch adds new rsnd_parse_connect_common() and replace current macro to it. This is prepare for multi channel support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 57 +++++++++++++++++++++++++++++------------------- sound/soc/sh/rcar/rsnd.h | 25 +++++++++++++++++++++ 2 files changed, 59 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 528041eff704..7781cef634d4 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -609,17 +609,44 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, }; +void rsnd_parse_connect_common(struct rsnd_dai *rdai, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device_node *np; + struct rsnd_mod *mod; + int i; + + if (!node) + return; + + i = 0; + for_each_child_of_node(node, np) { + mod = mod_get(priv, i); + if (np == playback) + rsnd_dai_connect(mod, &rdai->playback, mod->type); + if (np == capture) + rsnd_dai_connect(mod, &rdai->capture, mod->type); + i++; + } + + of_node_put(node); +} + static int rsnd_dai_probe(struct rsnd_priv *priv) { struct device_node *dai_node; - struct device_node *dai_np, *np, *node; + struct device_node *dai_np; struct device_node *playback, *capture; struct rsnd_dai_stream *io_playback; struct rsnd_dai_stream *io_capture; struct snd_soc_dai_driver *rdrv, *drv; struct rsnd_dai *rdai; struct device *dev = rsnd_priv_to_dev(priv); - int nr, dai_i, io_i, np_i; + int nr, dai_i, io_i; int ret; dai_node = rsnd_dai_of_node(priv); @@ -676,22 +703,6 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) rdai->capture.rdai = rdai; rsnd_set_slot(rdai, 2, 1); /* default */ -#define mod_parse(name) \ -node = rsnd_##name##_of_node(priv); \ -if (node) { \ - struct rsnd_mod *mod; \ - np_i = 0; \ - for_each_child_of_node(node, np) { \ - mod = rsnd_##name##_mod_get(priv, np_i); \ - if (np == playback) \ - rsnd_dai_connect(mod, io_playback, mod->type); \ - if (np == capture) \ - rsnd_dai_connect(mod, io_capture, mod->type); \ - np_i++; \ - } \ - of_node_put(node); \ -} - for (io_i = 0;; io_i++) { playback = of_parse_phandle(dai_np, "playback", io_i); capture = of_parse_phandle(dai_np, "capture", io_i); @@ -699,11 +710,11 @@ if (node) { \ if (!playback && !capture) break; - mod_parse(ssi); - mod_parse(src); - mod_parse(ctu); - mod_parse(mix); - mod_parse(dvc); + rsnd_parse_connect_ssi(rdai, playback, capture); + rsnd_parse_connect_src(rdai, playback, capture); + rsnd_parse_connect_ctu(rdai, playback, capture); + rsnd_parse_connect_mix(rdai, playback, capture); + rsnd_parse_connect_dvc(rdai, playback, capture); of_node_put(playback); of_node_put(capture); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c9aef234d002..f803e140e733 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -292,6 +292,11 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); +void rsnd_parse_connect_common(struct rsnd_dai *rdai, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture); void rsnd_set_slot(struct rsnd_dai *rdai, int slots, int slots_total); @@ -544,6 +549,10 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); #define rsnd_ssi_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_parse_connect_ssi(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_ssi_mod_get, \ + rsnd_ssi_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car SSIU @@ -564,6 +573,10 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct snd_pcm_runtime *runtime); #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_parse_connect_src(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ + rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car CTU @@ -573,6 +586,10 @@ void rsnd_ctu_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); #define rsnd_ctu_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_parse_connect_ctu(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ + rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car MIX @@ -582,6 +599,10 @@ void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); #define rsnd_mix_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_parse_connect_mix(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ + rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car DVC @@ -591,6 +612,10 @@ void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_parse_connect_dvc(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ + rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car CMD -- cgit v1.2.3 From a4386450bf08cd968bf41ff30a92caf74262c9d6 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:11:57 +0530 Subject: ASoC: Intel: Skylake: Clear stream registers before stream setup This patch adds clean up routine to clear the stream registers and calls this routine before setting up stream registers. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 38 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 8c7e8576cba3..da2329d17f4d 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -60,6 +60,27 @@ static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable) dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable); } +static void skl_cldma_stream_clear(struct sst_dsp *ctx) +{ + /* make sure Run bit is cleared before setting stream register */ + skl_cldma_stream_run(ctx, 0); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + /* Code loader helper APIs */ static void skl_cldma_setup_bdle(struct sst_dsp *ctx, struct snd_dma_buffer *dmab_data, @@ -95,6 +116,7 @@ static void skl_cldma_setup_controller(struct sst_dsp *ctx, struct snd_dma_buffer *dmab_bdl, unsigned int max_size, u32 count) { + skl_cldma_stream_clear(ctx); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(dmab_bdl->addr)); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, @@ -137,21 +159,7 @@ static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) static void skl_cldma_cleanup(struct sst_dsp *ctx) { skl_cldma_cleanup_spb(ctx); - - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); + skl_cldma_stream_clear(ctx); ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); -- cgit v1.2.3 From d2c7db854ed07548ca7d01118eee67fd6a78a2be Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:11:58 +0530 Subject: ASoC: Intel: Skylake: Fix to set pipe state to invalid when deleting When pipeline is deleted, set the pipeline state to invalid state. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 46310d9ac008..de6dac496a0d 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -849,6 +849,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); if (ret < 0) dev_err(ctx->dev, "Failed to delete pipeline\n"); + + pipe->state = SKL_PIPE_INVALID; } return ret; -- cgit v1.2.3 From 3f27dedda463347e98d406fc97ff6767ac59ea05 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Thu, 17 Dec 2015 20:35:39 -0600 Subject: ASoC: Intel: bytcr_rt5640: set SSP to I2S mode 2ch Using the hw_fixup function in order to overwrite the default SSP setting for Audio DSP port connected to the codec. Instead of TDM 4ch use I2S 2ch 24 bits. Signed-off-by: Sebastien Guiriec Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 7a5c9a36c1db..66d37b0e64d1 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -107,6 +107,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; /* The DSP will covert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; @@ -114,6 +115,28 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP2 to 24-bit */ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + return 0; } -- cgit v1.2.3 From e2be1da0164c0fbc345874581738d2d72f5f1e24 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:40 -0600 Subject: ASoC: Intel: boards: align pin names between byt-rt5640 drivers initial cleanup to use same pins Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 66d37b0e64d1..694061c4c649 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -32,22 +32,21 @@ static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), }; static const struct snd_soc_dapm_route byt_audio_map[] = { - {"IN2P", NULL, "Headset Mic"}, - {"IN2N", NULL, "Headset Mic"}, {"Headset Mic", NULL, "MICBIAS1"}, - {"IN1P", NULL, "MICBIAS1"}, - {"LDO2", NULL, "Int Mic"}, + {"IN2P", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, - {"Ext Spk", NULL, "SPOLP"}, - {"Ext Spk", NULL, "SPOLN"}, - {"Ext Spk", NULL, "SPORP"}, - {"Ext Spk", NULL, "SPORN"}, + {"Speaker", NULL, "SPOLP"}, + {"Speaker", NULL, "SPOLN"}, + {"Speaker", NULL, "SPORP"}, + {"Speaker", NULL, "SPORN"}, + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, @@ -60,8 +59,8 @@ static const struct snd_soc_dapm_route byt_audio_map[] = { static const struct snd_kcontrol_new byt_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Int Mic"), - SOC_DAPM_PIN_SWITCH("Ext Spk"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), }; static int byt_aif1_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From a2d5563bc6655f25e23f3c2c700d601ef077499e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:41 -0600 Subject: ASoC: Intel: boards: start merging byt-rt5640 drivers first renaming and reducing delta with byt-rt5640 code before dmi-based quirks are enabled Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 128 ++++++++++++++++++++++++---------- 2 files changed, 93 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f3d109eb3800..f424460b917e 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -314,7 +314,7 @@ static int sst_acpi_remove(struct platform_device *pdev) } static struct sst_acpi_mach sst_acpi_bytcr[] = { - {"10EC5640", "bytt100_rt5640", "intel/fw_sst_0f28.bin", "T100", NULL, + {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, {}, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 694061c4c649..8dfb57d96985 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -20,23 +20,25 @@ #include #include #include +#include #include +#include #include -#include #include #include #include +#include #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" -static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { +static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), }; -static const struct snd_soc_dapm_route byt_audio_map[] = { +static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, @@ -56,14 +58,39 @@ static const struct snd_soc_dapm_route byt_audio_map[] = { {"ssp2 Rx", NULL, "AIF1 Capture"}, }; -static const struct snd_kcontrol_new byt_mc_controls[] = { +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_DMIC2_MAP, + BYT_RT5640_IN1_MAP, +}; + +#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5640_DMIC_EN BIT(16) + +static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN; + +static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), }; -static int byt_aif1_hw_params(struct snd_pcm_substream *substream, +static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -91,7 +118,34 @@ static int byt_aif1_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_pcm_stream byt_dai_params = { +static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5640_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_DMIC_EN), + }, + {} +}; + +static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { .formats = SNDRV_PCM_FMTBIT_S24_LE, .rate_min = 48000, .rate_max = 48000, @@ -99,7 +153,7 @@ static const struct snd_soc_pcm_stream byt_dai_params = { .channels_max = 2, }; -static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, +static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, @@ -139,21 +193,21 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static int byt_aif1_startup(struct snd_pcm_substream *substream) +static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream) { return snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_aif1_ops = { - .startup = byt_aif1_startup, +static struct snd_soc_ops byt_rt5640_aif1_ops = { + .startup = byt_rt5640_aif1_startup, }; -static struct snd_soc_ops byt_be_ssp2_ops = { - .hw_params = byt_aif1_hw_params, +static struct snd_soc_ops byt_rt5640_be_ssp2_ops = { + .hw_params = byt_rt5640_aif1_hw_params, }; -static struct snd_soc_dai_link byt_dailink[] = { +static struct snd_soc_dai_link byt_rt5640_dais[] = { [MERR_DPCM_AUDIO] = { .name = "Baytrail Audio Port", .stream_name = "Baytrail Audio", @@ -165,7 +219,7 @@ static struct snd_soc_dai_link byt_dailink[] = { .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .ops = &byt_aif1_ops, + .ops = &byt_rt5640_aif1_ops, }, [MERR_DPCM_COMPR] = { .name = "Baytrail Compressed Port", @@ -186,55 +240,57 @@ static struct snd_soc_dai_link byt_dailink[] = { .codec_name = "i2c-10EC5640:00", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .be_hw_params_fixup = byt_codec_fixup, + .be_hw_params_fixup = byt_rt5640_codec_fixup, .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .ops = &byt_be_ssp2_ops, + .ops = &byt_rt5640_be_ssp2_ops, }, }; /* SoC card */ -static struct snd_soc_card snd_soc_card_byt = { - .name = "baytrailcraudio", +static struct snd_soc_card snd_soc_card_byt_rt5640 = { + .name = "bytcr-rt5640", .owner = THIS_MODULE, - .dai_link = byt_dailink, - .num_links = ARRAY_SIZE(byt_dailink), - .dapm_widgets = byt_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets), - .dapm_routes = byt_audio_map, - .num_dapm_routes = ARRAY_SIZE(byt_audio_map), - .controls = byt_mc_controls, - .num_controls = ARRAY_SIZE(byt_mc_controls), + .dai_link = byt_rt5640_dais, + .num_links = ARRAY_SIZE(byt_rt5640_dais), + .dapm_widgets = byt_rt5640_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), + .dapm_routes = byt_rt5640_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), + .controls = byt_rt5640_controls, + .num_controls = ARRAY_SIZE(byt_rt5640_controls), }; -static int snd_byt_mc_probe(struct platform_device *pdev) +static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { int ret_val = 0; /* register the soc card */ - snd_soc_card_byt.dev = &pdev->dev; + snd_soc_card_byt_rt5640.dev = &pdev->dev; - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt); + ret_val = devm_snd_soc_register_card(&pdev->dev, + &snd_soc_card_byt_rt5640); if (ret_val) { - dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); + dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", + ret_val); return ret_val; } - platform_set_drvdata(pdev, &snd_soc_card_byt); + platform_set_drvdata(pdev, &snd_soc_card_byt_rt5640); return ret_val; } -static struct platform_driver snd_byt_mc_driver = { +static struct platform_driver snd_byt_rt5640_mc_driver = { .driver = { - .name = "bytt100_rt5640", + .name = "bytcr_rt5640", .pm = &snd_soc_pm_ops, }, - .probe = snd_byt_mc_probe, + .probe = snd_byt_rt5640_mc_probe, }; -module_platform_driver(snd_byt_mc_driver); +module_platform_driver(snd_byt_rt5640_mc_driver); MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); MODULE_AUTHOR("Subhransu S. Prusty "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bytt100_rt5640"); +MODULE_ALIAS("platform:bytcr_rt5640"); -- cgit v1.2.3 From 9fd57471017fcc2dc6ddda03c7bc196d31fe9ffe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:42 -0600 Subject: ASoC: Intel: boards: merge DMI-based quirks in bytcr-rt5640 driver Merge DMI quirks for various machines such as Asus T100 and clean-up code Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 78 ++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8dfb57d96985..944283f569c6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -39,6 +39,13 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { }; static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "AIF1 Capture"}, + {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, @@ -47,15 +54,6 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Speaker", NULL, "SPOLN"}, {"Speaker", NULL, "SPORP"}, {"Speaker", NULL, "SPORN"}, - {"Internal Mic", NULL, "MICBIAS1"}, - {"IN1P", NULL, "Internal Mic"}, - - {"AIF1 Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec_out0"}, - {"ssp2 Tx", NULL, "codec_out1"}, - {"codec_in0", NULL, "ssp2 Rx"}, - {"codec_in1", NULL, "ssp2 Rx"}, - {"ssp2 Rx", NULL, "AIF1 Capture"}, }; static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { @@ -145,6 +143,54 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { {} }; +static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; + + card->dapm.idle_bias_off = true; + + ret = snd_soc_add_card_controls(card, byt_rt5640_controls, + ARRAY_SIZE(byt_rt5640_controls)); + if (ret) { + dev_err(card->dev, "unable to add card controls\n"); + return ret; + } + + dmi_check_system(byt_rt5640_quirk_table); + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_IN1_MAP: + custom_map = byt_rt5640_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); + break; + case BYT_RT5640_DMIC2_MAP: + custom_map = byt_rt5640_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); + break; + default: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + } + + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { + ret = rt5640_dmic_enable(codec, 0, 0); + if (ret) + return ret; + } + + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + + return ret; +} + static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { .formats = SNDRV_PCM_FMTBIT_S24_LE, .rate_min = 48000, @@ -244,12 +290,13 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, + .init = byt_rt5640_init, .ops = &byt_rt5640_be_ssp2_ops, }, }; /* SoC card */ -static struct snd_soc_card snd_soc_card_byt_rt5640 = { +static struct snd_soc_card byt_rt5640_card = { .name = "bytcr-rt5640", .owner = THIS_MODULE, .dai_link = byt_rt5640_dais, @@ -258,8 +305,7 @@ static struct snd_soc_card snd_soc_card_byt_rt5640 = { .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), .dapm_routes = byt_rt5640_audio_map, .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), - .controls = byt_rt5640_controls, - .num_controls = ARRAY_SIZE(byt_rt5640_controls), + .fully_routed = true, }; static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) @@ -267,16 +313,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) int ret_val = 0; /* register the soc card */ - snd_soc_card_byt_rt5640.dev = &pdev->dev; + byt_rt5640_card.dev = &pdev->dev; + + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); - ret_val = devm_snd_soc_register_card(&pdev->dev, - &snd_soc_card_byt_rt5640); if (ret_val) { dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); return ret_val; } - platform_set_drvdata(pdev, &snd_soc_card_byt_rt5640); + platform_set_drvdata(pdev, &byt_rt5640_card); return ret_val; } -- cgit v1.2.3 From 595788e475d09fb081bedcf49b3720e62887f77f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:43 -0600 Subject: ASoC: Intel: tag byt-rt5640 machine driver as deprecated All the functionality was merged in DPCM-based driver, keep older driver to avoid breaking userspace but tag it as unsupported/deprecated Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 9b1c0aa8d2d9..337e178c1acb 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -57,13 +57,14 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE=y + depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n) select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help This adds audio driver for Intel Baytrail platform based boards - with the RT5640 audio codec. + with the RT5640 audio codec. This driver is deprecated, use + SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" @@ -91,14 +92,14 @@ config SND_SOC_INTEL_BROADWELL_MACH If unsure select "N". config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio DSP Support for MID BYT Platform" + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C select SND_SOC_RT5640 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI help - This adds support for ASoC machine driver for Intel(R) MID Baytrail platform - used as alsa device in audio substem in Intel(R) MID devices + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5640 audio codec. Say Y if you have such a device If unsure select "N". -- cgit v1.2.3 From 8788f83929ca1dbfa640ac17aec78b2e36cf493d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:44 -0600 Subject: ASoc: Intel: Atom: add deep buffer definitions for atom platforms Add definitions for MERR_DPCM_DEEP_BUFFER AND PIPE_MEDIA3_IN Add relevant cpu-dai and dai link names Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- arch/x86/include/asm/platform_sst_audio.h | 1 + sound/soc/intel/atom/sst-atom-controls.c | 1 + sound/soc/intel/atom/sst-atom-controls.h | 1 + sound/soc/intel/atom/sst-mfld-platform-pcm.c | 12 ++++++++++++ 4 files changed, 15 insertions(+) (limited to 'sound') diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h index 7249e6d0902d..5973a2f3db3d 100644 --- a/arch/x86/include/asm/platform_sst_audio.h +++ b/arch/x86/include/asm/platform_sst_audio.h @@ -55,6 +55,7 @@ enum sst_audio_device_id_mrfld { PIPE_MEDIA0_IN = 0x8F, PIPE_MEDIA1_IN = 0x90, PIPE_MEDIA2_IN = 0x91, + PIPE_MEDIA3_IN = 0x9C, PIPE_RSVD = 0xFF, }; diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index d55388e082e1..1727cc4c7f8a 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1109,6 +1109,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"media0_in", NULL, "Compress Playback"}, {"media1_in", NULL, "Headset Playback"}, {"media2_in", NULL, "pcm0_out"}, + {"media3_in", NULL, "Deepbuffer Playback"}, {"media0_out mix 0", "media0_in Switch", "media0_in"}, {"media0_out mix 0", "media1_in Switch", "media1_in"}, diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index 93de8045d4e1..e0113112f668 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -28,6 +28,7 @@ enum { MERR_DPCM_AUDIO = 0, + MERR_DPCM_DEEP_BUFFER, MERR_DPCM_COMPR, }; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 8e475e823205..60b73b7eed0f 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -98,6 +98,7 @@ static struct sst_dev_stream_map dpcm_strm_map[] = { {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0}, {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0}, {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, + {MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0}, }; static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) @@ -510,6 +511,17 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, +{ + .name = "deepbuffer-cpu-dai", + .ops = &sst_media_dai_ops, + .playback = { + .stream_name = "Deepbuffer Playback", + .channels_min = SST_STEREO, + .channels_max = SST_STEREO, + .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, { .name = "compress-cpu-dai", .compress_new = snd_soc_new_compress, -- cgit v1.2.3 From d35eb96a95dc82befe2d9d1533728506b0847f14 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:45 -0600 Subject: ASoC: Intel: boards: add DEEP_BUFFER support for BYT/CHT/BSW Add dai links to enable additional playback stream with deeper buffer for lower power consumption. The normal and DEEP_buffer streams are not mutually exclusive, content will be mixed by the DSP. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 13 +++++++++++++ sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ sound/soc/intel/boards/cht_bsw_rt5645.c | 12 ++++++++++++ sound/soc/intel/boards/cht_bsw_rt5672.c | 12 ++++++++++++ 4 files changed, 49 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 944283f569c6..a81389d10e17 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -267,6 +267,19 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .dpcm_capture = 1, .ops = &byt_rt5640_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_rt5640_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Baytrail Compressed Port", .stream_name = "Baytrail Compress", diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index e36dad302bed..90588d6e64fc 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -232,6 +232,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 1d2525a53bff..2d3afddb0a2e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -260,6 +260,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 77fb3c419ca4..2e5347f8f96c 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -248,6 +248,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", -- cgit v1.2.3 From 098c2cd2814098b6cf98ab8c068d69eefbc46716 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:46 -0600 Subject: ASoC: Intel: Atom: add 24-bit support for media playback and capture DSP firmware supports 24-bit data, expose functionality to userspace/apps. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 60b73b7eed0f..c1f618ed183b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -501,14 +501,14 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .channels_min = SST_STEREO, .channels_max = SST_STEREO, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, .capture = { .stream_name = "Headset Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, { @@ -519,7 +519,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .channels_min = SST_STEREO, .channels_max = SST_STEREO, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, { -- cgit v1.2.3 From 77095796ae9cbaf315f80611edb5aa569796e339 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:47 -0600 Subject: ASoC: Intel: Atom: clean-up compressed DAI definition the fields channels_min, channels_max, rate and formats are irrelevant for compressed playback, they will depend on the content. This was probably a copy-paste mistake to have them in the first place Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index c1f618ed183b..55c33dc76ce4 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -528,10 +528,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", - .channels_min = SST_STEREO, - .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, /* BE CPU Dais */ -- cgit v1.2.3 From 940a5a014d50e15269b5d197ab571d1ca9971c43 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Dec 2015 20:35:48 -0600 Subject: ASoC: Intel: Atom: flip logic for gain Switch The upstreamed code modified the control names from Mute to Switch without changing the logic. To get audio working the Switch needs to be off which isn't aligned with normal ALSA conventions. Inverting the logic now so that Switch Off means mute and Switch On means active audio using the specific volume setting. Signed-off-by: Sebastien Guiriec Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 1727cc4c7f8a..b97e6adcf1b2 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -443,7 +443,7 @@ static int sst_gain_get(struct snd_kcontrol *kcontrol, break; case SST_GAIN_MUTE: - ucontrol->value.integer.value[0] = gv->mute ? 1 : 0; + ucontrol->value.integer.value[0] = gv->mute ? 0 : 1; break; case SST_GAIN_RAMP_DURATION: @@ -479,7 +479,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, break; case SST_GAIN_MUTE: - gv->mute = !!ucontrol->value.integer.value[0]; + gv->mute = !ucontrol->value.integer.value[0]; dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute); break; -- cgit v1.2.3 From b1d15059957d33d111e0ed38724a6b2c5caac790 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 15 Dec 2015 14:57:41 +0800 Subject: ASoC: rt5616: add rt5616 codec driver This is the initial codec driver for rt5616. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt5616.c | 1372 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5616.h | 1819 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 3199 insertions(+) create mode 100644 sound/soc/codecs/rt5616.c create mode 100644 sound/soc/codecs/rt5616.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f22c66bde292..cdc0d09d52cb 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C + select SND_SOC_RT5616 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C @@ -524,12 +525,14 @@ config SND_SOC_PCM512x_SPI config SND_SOC_RL6231 tristate + default y if SND_SOC_RT5616=y default y if SND_SOC_RT5640=y default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y default y if SND_SOC_RT5659=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y + default m if SND_SOC_RT5616=m default m if SND_SOC_RT5640=m default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m @@ -552,6 +555,9 @@ config SND_SOC_RT298 tristate depends on I2C +config SND_SOC_RT5616 + tristate + config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 418e89eb25ca..0bcb2bdfb472 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o +snd-soc-rt5616-objs := rt5616.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o @@ -281,6 +282,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o +obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c new file mode 100644 index 000000000000..f4005cbaa99d --- /dev/null +++ b/sound/soc/codecs/rt5616.c @@ -0,0 +1,1372 @@ +/* + * rt5616.c -- RT5616 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6231.h" +#include "rt5616.h" + +#define RT5616_PR_RANGE_BASE (0xff + 1) +#define RT5616_PR_SPACING 0x100 + +#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING)) + +static const struct regmap_range_cfg rt5616_ranges[] = { + { + .name = "PR", + .range_min = RT5616_PR_BASE, + .range_max = RT5616_PR_BASE + 0xf8, + .selector_reg = RT5616_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5616_PRIV_DATA, + .window_len = 0x1, + }, +}; + +static const struct reg_sequence init_list[] = { + {RT5616_PR_BASE + 0x3d, 0x3e00}, + {RT5616_PR_BASE + 0x25, 0x6110}, + {RT5616_PR_BASE + 0x20, 0x611f}, + {RT5616_PR_BASE + 0x21, 0x4040}, + {RT5616_PR_BASE + 0x23, 0x0004}, +}; +#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5616_reg[] = { + { 0x00, 0x0021 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x05, 0x0000 }, + { 0x0d, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x19, 0xafaf }, + { 0x1c, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x27, 0x7860 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5252 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x006f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x006f }, + { 0x45, 0x6000 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x0279 }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x0279 }, + { 0x53, 0xf000 }, + { 0x61, 0x0000 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c0 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x70, 0x8000 }, + { 0x73, 0x1104 }, + { 0x74, 0x0c00 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x8b, 0x0600 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0000 }, + { 0x91, 0x0000 }, + { 0x92, 0x0000 }, + { 0x93, 0x2000 }, + { 0x94, 0x0200 }, + { 0x95, 0x0000 }, + { 0xb0, 0x2080 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb4, 0x2206 }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xb7, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0000 }, + { 0xc0, 0x0100 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xc8, 0x0000 }, + { 0xc9, 0x0000 }, + { 0xca, 0x0000 }, + { 0xcb, 0x0000 }, + { 0xcc, 0x0000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x0013 }, + { 0xd0, 0x0680 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0000 }, + { 0xd7, 0x0000 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xfa, 0x0010 }, + { 0xfb, 0x0000 }, + { 0xfc, 0x0000 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6281 }, +}; + +struct rt5616_priv { + struct snd_soc_codec *codec; + struct delayed_work patch_work; + struct regmap *regmap; + + int sysclk; + int sysclk_src; + int lrck[RT5616_AIFS]; + int bclk[RT5616_AIFS]; + int master[RT5616_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + +}; + +static bool rt5616_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { + if (reg >= rt5616_ranges[i].range_min && + reg <= rt5616_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5616_RESET: + case RT5616_PRIV_DATA: + case RT5616_EQ_CTRL1: + case RT5616_DRC_AGC_1: + case RT5616_IRQ_CTRL2: + case RT5616_INT_IRQ_ST: + case RT5616_PGM_REG_ARR1: + case RT5616_PGM_REG_ARR3: + case RT5616_VENDOR_ID: + case RT5616_DEVICE_ID: + return true; + default: + return false; + } +} + +static bool rt5616_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { + if (reg >= rt5616_ranges[i].range_min && + reg <= rt5616_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5616_RESET: + case RT5616_VERSION_ID: + case RT5616_VENDOR_ID: + case RT5616_DEVICE_ID: + case RT5616_HP_VOL: + case RT5616_LOUT_CTRL1: + case RT5616_LOUT_CTRL2: + case RT5616_IN1_IN2: + case RT5616_INL1_INR1_VOL: + case RT5616_DAC1_DIG_VOL: + case RT5616_ADC_DIG_VOL: + case RT5616_ADC_BST_VOL: + case RT5616_STO1_ADC_MIXER: + case RT5616_AD_DA_MIXER: + case RT5616_STO_DAC_MIXER: + case RT5616_REC_L1_MIXER: + case RT5616_REC_L2_MIXER: + case RT5616_REC_R1_MIXER: + case RT5616_REC_R2_MIXER: + case RT5616_HPO_MIXER: + case RT5616_OUT_L1_MIXER: + case RT5616_OUT_L2_MIXER: + case RT5616_OUT_L3_MIXER: + case RT5616_OUT_R1_MIXER: + case RT5616_OUT_R2_MIXER: + case RT5616_OUT_R3_MIXER: + case RT5616_LOUT_MIXER: + case RT5616_PWR_DIG1: + case RT5616_PWR_DIG2: + case RT5616_PWR_ANLG1: + case RT5616_PWR_ANLG2: + case RT5616_PWR_MIXER: + case RT5616_PWR_VOL: + case RT5616_PRIV_INDEX: + case RT5616_PRIV_DATA: + case RT5616_I2S1_SDP: + case RT5616_ADDA_CLK1: + case RT5616_ADDA_CLK2: + case RT5616_GLB_CLK: + case RT5616_PLL_CTRL1: + case RT5616_PLL_CTRL2: + case RT5616_HP_OVCD: + case RT5616_DEPOP_M1: + case RT5616_DEPOP_M2: + case RT5616_DEPOP_M3: + case RT5616_CHARGE_PUMP: + case RT5616_PV_DET_SPK_G: + case RT5616_MICBIAS: + case RT5616_A_JD_CTL1: + case RT5616_A_JD_CTL2: + case RT5616_EQ_CTRL1: + case RT5616_EQ_CTRL2: + case RT5616_WIND_FILTER: + case RT5616_DRC_AGC_1: + case RT5616_DRC_AGC_2: + case RT5616_DRC_AGC_3: + case RT5616_SVOL_ZC: + case RT5616_JD_CTRL1: + case RT5616_JD_CTRL2: + case RT5616_IRQ_CTRL1: + case RT5616_IRQ_CTRL2: + case RT5616_INT_IRQ_ST: + case RT5616_GPIO_CTRL1: + case RT5616_GPIO_CTRL2: + case RT5616_GPIO_CTRL3: + case RT5616_PGM_REG_ARR1: + case RT5616_PGM_REG_ARR2: + case RT5616_PGM_REG_ARR3: + case RT5616_PGM_REG_ARR4: + case RT5616_PGM_REG_ARR5: + case RT5616_SCB_FUNC: + case RT5616_SCB_CTRL: + case RT5616_BASE_BACK: + case RT5616_MP3_PLUS1: + case RT5616_MP3_PLUS2: + case RT5616_ADJ_HPF_CTRL1: + case RT5616_ADJ_HPF_CTRL2: + case RT5616_HP_CALIB_AMP_DET: + case RT5616_HP_CALIB2: + case RT5616_SV_ZCD1: + case RT5616_SV_ZCD2: + case RT5616_D_MISC: + case RT5616_DUMMY2: + case RT5616_DUMMY3: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static const struct snd_kcontrol_new rt5616_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + /* OUTPUT Control */ + SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1, + RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 175, 0, dac_vol_tlv), + /* IN1/IN2 Control */ + SOC_SINGLE_TLV("IN1 Boost", RT5616_IN1_IN2, + RT5616_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("IN2 Boost", RT5616_IN1_IN2, + RT5616_BST_SFT2, 8, 0, bst_tlv), + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL, + RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT, + 31, 1, in_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("ADC Boost Gain", RT5616_ADC_BST_VOL, + RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), +}; + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + + val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK); + val &= RT5616_SCLK_SRC_MASK; + if (val == RT5616_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER, + RT5616_M_STO1_ADC_L1_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER, + RT5616_M_STO1_ADC_R1_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER, + RT5616_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER, + RT5616_M_IF1_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER, + RT5616_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER, + RT5616_M_IF1_DAC_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_L1_MIXL_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_R1_MIXL_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_R1_MIXR_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_L1_MIXR_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5616_rec_l_mix[] = { + SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER, + RT5616_M_IN1_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER, + RT5616_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER, + RT5616_M_BST1_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_rec_r_mix[] = { + SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER, + RT5616_M_IN1_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER, + RT5616_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER, + RT5616_M_BST1_RM_R_SFT, 1, 1), +}; + +/* Analog Output Mixer */ + +static const struct snd_kcontrol_new rt5616_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_IN1_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER, + RT5616_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_IN1_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER, + RT5616_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_hpo_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER, + RT5616_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER, + RT5616_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_lout_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER, + RT5616_M_DAC_L1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER, + RT5616_M_DAC_R1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER, + RT5616_M_OV_L_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER, + RT5616_M_OV_R_LM_SFT, 1, 1), +}; + +static int rt5616_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* depop parameters */ + snd_soc_update_bits(codec, RT5616_DEPOP_M2, + RT5616_DEPOP_MASK, RT5616_DEPOP_MAN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_CP_MASK | RT5616_HP_SG_MASK | + RT5616_HP_CB_MASK, RT5616_HP_CP_PU | + RT5616_HP_SG_DIS | RT5616_HP_CB_PU); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_HP_DCC_INT1, 0x9f00); + /* headphone amp power on */ + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, 0); + snd_soc_update_bits(codec, RT5616_PWR_VOL, + RT5616_PWR_HV_L | RT5616_PWR_HV_R, + RT5616_PWR_HV_L | RT5616_PWR_HV_R); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, RT5616_PWR_HP_L | + RT5616_PWR_HP_R | RT5616_PWR_HA); + msleep(50); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + + snd_soc_update_bits(codec, RT5616_CHARGE_PUMP, + RT5616_PM_HP_MASK, RT5616_PM_HP_HV); + snd_soc_update_bits(codec, RT5616_PR_BASE + + RT5616_CHOP_DAC_ADC, 0x0200, 0x0200); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_CO_MASK | RT5616_HP_SG_MASK, + RT5616_HP_CO_EN | RT5616_HP_SG_EN); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PR_BASE + + RT5616_CHOP_DAC_ADC, 0x0200, 0x0); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + /* headphone amp power down */ + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK | + RT5616_HP_CO_MASK | RT5616_HP_CP_MASK | + RT5616_HP_SG_MASK | RT5616_HP_CB_MASK, + RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN | + RT5616_HP_CO_DIS | RT5616_HP_CP_PD | + RT5616_HP_SG_EN | RT5616_HP_CB_PD); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, 0); + break; + default: + return 0; + } + + return 0; +} + +static int rt5616_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* headphone unmute sequence */ + snd_soc_update_bits(codec, RT5616_DEPOP_M3, + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) | + (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | + (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT)); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTN_MASK, RT5616_RSTN_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + snd_soc_update_bits(codec, RT5616_HP_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + msleep(100); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + msleep(20); + snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, + RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* headphone mute sequence */ + snd_soc_update_bits(codec, RT5616_DEPOP_M3, + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) | + (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | + (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT)); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK, RT5616_HP_SG_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTP_MASK, RT5616_RSTP_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, + RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS); + msleep(90); + snd_soc_update_bits(codec, RT5616_HP_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + msleep(30); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_LM, RT5616_PWR_LM); + snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_LM, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_bst1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST1_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_bst2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST2_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2, + RT5616_PWR_PLL_BIT, 0, NULL, 0), + /* Input Side */ + /* micbias */ + SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1, + RT5616_PWR_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2, + RT5616_PWR_MB1_BIT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + /* Boost */ + SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2, + RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2, + RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + /* Input Volume */ + SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0, + rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0, + rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)), + /* ADCs */ + SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1, + RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1, + RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2, + RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1, + RT5616_PWR_I2S1_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Audio DSP */ + SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)), + + SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2, + RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0), + + /* DAC Mixer */ + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1, + RT5616_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1, + RT5616_PWR_DAC_R1_BIT, 0), + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT, + 0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT, + 0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)), + /* Output Volume */ + SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL, + RT5616_PWR_OV_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL, + RT5616_PWR_OV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL, + RT5616_PWR_HV_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL, + RT5616_PWR_HV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL, + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL, + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL, + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL, + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, + rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, + rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)), + + SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, + rt5616_hp_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, + rt5616_lout_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0, + rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_route rt5616_dapm_routes[] = { + {"IN1P", NULL, "LDO"}, + {"IN2P", NULL, "LDO"}, + + {"IN1P", NULL, "MIC1"}, + {"IN2P", NULL, "MIC2"}, + {"IN2N", NULL, "MIC2"}, + + {"BST1", NULL, "IN1P"}, + {"BST2", NULL, "IN2P"}, + {"BST2", NULL, "IN2N"}, + {"BST1", NULL, "micbias1"}, + {"BST2", NULL, "micbias1"}, + + {"INL1 VOL", NULL, "IN2P"}, + {"INR1 VOL", NULL, "IN2N"}, + + {"RECMIXL", "INL1 Switch", "INL1 VOL"}, + {"RECMIXL", "BST2 Switch", "BST2"}, + {"RECMIXL", "BST1 Switch", "BST1"}, + + {"RECMIXR", "INR1 Switch", "INR1 VOL"}, + {"RECMIXR", "BST2 Switch", "BST2"}, + {"RECMIXR", "BST1 Switch", "BST1"}, + + {"ADC L", NULL, "RECMIXL"}, + {"ADC R", NULL, "RECMIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"}, + {"Stereo1 ADC MIXL", NULL, "stereo1 filter"}, + {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"}, + {"Stereo1 ADC MIXR", NULL, "stereo1 filter"}, + {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll}, + + {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"}, + {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"}, + {"IF1 ADC1", NULL, "I2S1"}, + + {"AIF1TX", NULL, "IF1 ADC1"}, + + {"IF1 DAC", NULL, "AIF1RX"}, + {"IF1 DAC", NULL, "I2S1"}, + + {"IF1 DAC1 L", NULL, "IF1 DAC"}, + {"IF1 DAC1 R", NULL, "IF1 DAC"}, + + {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"}, + {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"}, + + {"Audio DSP", NULL, "DAC MIXL"}, + {"Audio DSP", NULL, "DAC MIXR"}, + + {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"}, + {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"}, + {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"}, + {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"}, + {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"}, + {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"}, + + {"DAC L1", NULL, "Stereo DAC MIXL"}, + {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC R1", NULL, "Stereo DAC MIXR"}, + {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll}, + + {"OUT MIXL", "BST1 Switch", "BST1"}, + {"OUT MIXL", "BST2 Switch", "BST2"}, + {"OUT MIXL", "INL1 Switch", "INL1 VOL"}, + {"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, + {"OUT MIXL", "DAC L1 Switch", "DAC L1"}, + + {"OUT MIXR", "BST2 Switch", "BST2"}, + {"OUT MIXR", "BST1 Switch", "BST1"}, + {"OUT MIXR", "INR1 Switch", "INR1 VOL"}, + {"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, + {"OUT MIXR", "DAC R1 Switch", "DAC R1"}, + + {"HPOVOL L", NULL, "OUT MIXL"}, + {"HPOVOL R", NULL, "OUT MIXR"}, + {"OUTVOL L", NULL, "OUT MIXL"}, + {"OUTVOL R", NULL, "OUT MIXR"}, + + {"DAC 1", NULL, "DAC L1"}, + {"DAC 1", NULL, "DAC R1"}, + {"HPOVOL", NULL, "HPOVOL L"}, + {"HPOVOL", NULL, "HPOVOL R"}, + {"HPO MIX", "DAC1 Switch", "DAC 1"}, + {"HPO MIX", "HPVOL Switch", "HPOVOL"}, + + {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, + {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, + {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, + + {"HP amp", NULL, "HPO MIX"}, + {"HP amp", NULL, "Charge Pump"}, + {"HPOL", NULL, "HP amp"}, + {"HPOR", NULL, "HP amp"}, + + {"LOUT amp", NULL, "LOUT MIX"}, + {"LOUT amp", NULL, "Charge Pump"}, + {"LOUTL", NULL, "LOUT amp"}, + {"LOUTR", NULL, "LOUT amp"}, + +}; + +static int rt5616_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5616->lrck[dai->id] = params_rate(params); + + pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]); + + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + bclk_ms = frame_size > 32 ? 1 : 0; + rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5616->bclk[dai->id], rt5616->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len |= RT5616_I2S_DL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len |= RT5616_I2S_DL_24; + break; + case SNDRV_PCM_FORMAT_S8: + val_len |= RT5616_I2S_DL_8; + break; + default: + return -EINVAL; + } + + mask_clk = RT5616_I2S_PD1_MASK; + val_clk = pre_div << RT5616_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5616_I2S1_SDP, + RT5616_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk); + + + return 0; +} + +static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5616->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5616_I2S_MS_S; + rt5616->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5616_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5616_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5616_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5616_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5616_I2S1_SDP, + RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK | + RT5616_I2S_DF_MASK, reg_val); + + + return 0; +} + +static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src) + return 0; + + switch (clk_id) { + case RT5616_SCLK_S_MCLK: + reg_val |= RT5616_SCLK_SRC_MCLK; + break; + case RT5616_SCLK_S_PLL1: + reg_val |= RT5616_SCLK_SRC_PLL1; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_SCLK_SRC_MASK, reg_val); + rt5616->sysclk = freq; + rt5616->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (source == rt5616->pll_src && freq_in == rt5616->pll_in && + freq_out == rt5616->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5616->pll_in = 0; + rt5616->pll_out = 0; + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5616_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK); + break; + case RT5616_PLL1_S_BCLK1: + case RT5616_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_BCLK1); + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5616_PLL_CTRL1, + pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5616_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT | + pll_code.m_bp << RT5616_PLL_M_BP_SFT); + + rt5616->pll_in = freq_in; + rt5616->pll_out = freq_out; + rt5616->pll_src = source; + + return 0; +} + +static int rt5616_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); + mdelay(10); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + snd_soc_update_bits(codec, RT5616_D_MISC, + RT5616_D_GATE_EN, RT5616_D_GATE_EN); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0); + snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000); + snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000); + snd_soc_write(codec, RT5616_PWR_VOL, 0x0000); + snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000); + snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000); + snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000); + break; + + default: + break; + } + + return 0; +} + +static int rt5616_probe(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + rt5616->codec = codec; + + return 0; +} + +#ifdef CONFIG_PM +static int rt5616_suspend(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5616->regmap, true); + regcache_mark_dirty(rt5616->regmap); + + return 0; +} + +static int rt5616_resume(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5616->regmap, false); + regcache_sync(rt5616->regmap); + return 0; +} +#else +#define rt5616_suspend NULL +#define rt5616_resume NULL +#endif + +#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + + +struct snd_soc_dai_ops rt5616_aif_dai_ops = { + .hw_params = rt5616_hw_params, + .set_fmt = rt5616_set_dai_fmt, + .set_sysclk = rt5616_set_dai_sysclk, + .set_pll = rt5616_set_dai_pll, +}; + +struct snd_soc_dai_driver rt5616_dai[] = { + { + .name = "rt5616-aif1", + .id = RT5616_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5616_STEREO_RATES, + .formats = RT5616_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5616_STEREO_RATES, + .formats = RT5616_FORMATS, + }, + .ops = &rt5616_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5616 = { + .probe = rt5616_probe, + .suspend = rt5616_suspend, + .resume = rt5616_resume, + .set_bias_level = rt5616_set_bias_level, + .idle_bias_off = true, + .controls = rt5616_snd_controls, + .num_controls = ARRAY_SIZE(rt5616_snd_controls), + .dapm_widgets = rt5616_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets), + .dapm_routes = rt5616_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), +}; + +static const struct regmap_config rt5616_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) * + RT5616_PR_SPACING), + .volatile_reg = rt5616_volatile_register, + .readable_reg = rt5616_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5616_reg, + .num_reg_defaults = ARRAY_SIZE(rt5616_reg), + .ranges = rt5616_ranges, + .num_ranges = ARRAY_SIZE(rt5616_ranges), +}; + +static const struct i2c_device_id rt5616_i2c_id[] = { + { "rt5616", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id); + +static int rt5616_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5616_priv *rt5616; + unsigned int val; + int ret; + + rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv), + GFP_KERNEL); + if (rt5616 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5616); + + rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap); + if (IS_ERR(rt5616->regmap)) { + ret = PTR_ERR(rt5616->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val); + if (val != 0x6281) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5616\n", + val); + ret = -ENODEV; + } + regmap_write(rt5616->regmap, RT5616_RESET, 0); + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); + mdelay(10); + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + + ret = regmap_register_patch(rt5616->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V); + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616, + rt5616_dai, ARRAY_SIZE(rt5616_dai)); + +} + +static int rt5616_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5616_i2c_shutdown(struct i2c_client *client) +{ + struct rt5616_priv *rt5616 = i2c_get_clientdata(client); + + regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8); + regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8); + +} + +static struct i2c_driver rt5616_i2c_driver = { + .driver = { + .name = "rt5616", + }, + .probe = rt5616_i2c_probe, + .remove = rt5616_i2c_remove, + .shutdown = rt5616_i2c_shutdown, + .id_table = rt5616_i2c_id, +}; +module_i2c_driver(rt5616_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5616 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h new file mode 100644 index 000000000000..f88cdddbc34a --- /dev/null +++ b/sound/soc/codecs/rt5616.h @@ -0,0 +1,1819 @@ +/* + * rt5616.h -- RT5616 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5616_H__ +#define __RT5616_H__ + +/* Info */ +#define RT5616_RESET 0x00 +#define RT5616_VERSION_ID 0xfd +#define RT5616_VENDOR_ID 0xfe +#define RT5616_DEVICE_ID 0xff +/* I/O - Output */ +#define RT5616_HP_VOL 0x02 +#define RT5616_LOUT_CTRL1 0x03 +#define RT5616_LOUT_CTRL2 0x05 +/* I/O - Input */ +#define RT5616_IN1_IN2 0x0d +#define RT5616_INL1_INR1_VOL 0x0f +/* I/O - ADC/DAC/DMIC */ +#define RT5616_DAC1_DIG_VOL 0x19 +#define RT5616_ADC_DIG_VOL 0x1c +#define RT5616_ADC_BST_VOL 0x1e +/* Mixer - D-D */ +#define RT5616_STO1_ADC_MIXER 0x27 +#define RT5616_AD_DA_MIXER 0x29 +#define RT5616_STO_DAC_MIXER 0x2a + +/* Mixer - ADC */ +#define RT5616_REC_L1_MIXER 0x3b +#define RT5616_REC_L2_MIXER 0x3c +#define RT5616_REC_R1_MIXER 0x3d +#define RT5616_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5616_HPO_MIXER 0x45 +#define RT5616_OUT_L1_MIXER 0x4d +#define RT5616_OUT_L2_MIXER 0x4e +#define RT5616_OUT_L3_MIXER 0x4f +#define RT5616_OUT_R1_MIXER 0x50 +#define RT5616_OUT_R2_MIXER 0x51 +#define RT5616_OUT_R3_MIXER 0x52 +#define RT5616_LOUT_MIXER 0x53 +/* Power */ +#define RT5616_PWR_DIG1 0x61 +#define RT5616_PWR_DIG2 0x62 +#define RT5616_PWR_ANLG1 0x63 +#define RT5616_PWR_ANLG2 0x64 +#define RT5616_PWR_MIXER 0x65 +#define RT5616_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5616_PRIV_INDEX 0x6a +#define RT5616_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5616_I2S1_SDP 0x70 +#define RT5616_ADDA_CLK1 0x73 +#define RT5616_ADDA_CLK2 0x74 + +/* Function - Analog */ +#define RT5616_GLB_CLK 0x80 +#define RT5616_PLL_CTRL1 0x81 +#define RT5616_PLL_CTRL2 0x82 +#define RT5616_HP_OVCD 0x8b +#define RT5616_DEPOP_M1 0x8e +#define RT5616_DEPOP_M2 0x8f +#define RT5616_DEPOP_M3 0x90 +#define RT5616_CHARGE_PUMP 0x91 +#define RT5616_PV_DET_SPK_G 0x92 +#define RT5616_MICBIAS 0x93 +#define RT5616_A_JD_CTL1 0x94 +#define RT5616_A_JD_CTL2 0x95 +/* Function - Digital */ +#define RT5616_EQ_CTRL1 0xb0 +#define RT5616_EQ_CTRL2 0xb1 +#define RT5616_WIND_FILTER 0xb2 +#define RT5616_DRC_AGC_1 0xb4 +#define RT5616_DRC_AGC_2 0xb5 +#define RT5616_DRC_AGC_3 0xb6 +#define RT5616_SVOL_ZC 0xb7 +#define RT5616_JD_CTRL1 0xbb +#define RT5616_JD_CTRL2 0xbc +#define RT5616_IRQ_CTRL1 0xbd +#define RT5616_IRQ_CTRL2 0xbe +#define RT5616_INT_IRQ_ST 0xbf +#define RT5616_GPIO_CTRL1 0xc0 +#define RT5616_GPIO_CTRL2 0xc1 +#define RT5616_GPIO_CTRL3 0xc2 +#define RT5616_PGM_REG_ARR1 0xc8 +#define RT5616_PGM_REG_ARR2 0xc9 +#define RT5616_PGM_REG_ARR3 0xca +#define RT5616_PGM_REG_ARR4 0xcb +#define RT5616_PGM_REG_ARR5 0xcc +#define RT5616_SCB_FUNC 0xcd +#define RT5616_SCB_CTRL 0xce +#define RT5616_BASE_BACK 0xcf +#define RT5616_MP3_PLUS1 0xd0 +#define RT5616_MP3_PLUS2 0xd1 +#define RT5616_ADJ_HPF_CTRL1 0xd3 +#define RT5616_ADJ_HPF_CTRL2 0xd4 +#define RT5616_HP_CALIB_AMP_DET 0xd6 +#define RT5616_HP_CALIB2 0xd7 +#define RT5616_SV_ZCD1 0xd9 +#define RT5616_SV_ZCD2 0xda +#define RT5616_D_MISC 0xfa +/* Dummy Register */ +#define RT5616_DUMMY2 0xfb +#define RT5616_DUMMY3 0xfc + + +/* Index of Codec Private Register definition */ +#define RT5616_BIAS_CUR1 0x12 +#define RT5616_BIAS_CUR3 0x14 +#define RT5616_CLSD_INT_REG1 0x1c +#define RT5616_MAMP_INT_REG2 0x37 +#define RT5616_CHOP_DAC_ADC 0x3d +#define RT5616_3D_SPK 0x63 +#define RT5616_WND_1 0x6c +#define RT5616_WND_2 0x6d +#define RT5616_WND_3 0x6e +#define RT5616_WND_4 0x6f +#define RT5616_WND_5 0x70 +#define RT5616_WND_8 0x73 +#define RT5616_DIP_SPK_INF 0x75 +#define RT5616_HP_DCC_INT1 0x77 +#define RT5616_EQ_BW_LOP 0xa0 +#define RT5616_EQ_GN_LOP 0xa1 +#define RT5616_EQ_FC_BP1 0xa2 +#define RT5616_EQ_BW_BP1 0xa3 +#define RT5616_EQ_GN_BP1 0xa4 +#define RT5616_EQ_FC_BP2 0xa5 +#define RT5616_EQ_BW_BP2 0xa6 +#define RT5616_EQ_GN_BP2 0xa7 +#define RT5616_EQ_FC_BP3 0xa8 +#define RT5616_EQ_BW_BP3 0xa9 +#define RT5616_EQ_GN_BP3 0xaa +#define RT5616_EQ_FC_BP4 0xab +#define RT5616_EQ_BW_BP4 0xac +#define RT5616_EQ_GN_BP4 0xad +#define RT5616_EQ_FC_HIP1 0xae +#define RT5616_EQ_GN_HIP1 0xaf +#define RT5616_EQ_FC_HIP2 0xb0 +#define RT5616_EQ_BW_HIP2 0xb1 +#define RT5616_EQ_GN_HIP2 0xb2 +#define RT5616_EQ_PRE_VOL 0xb3 +#define RT5616_EQ_PST_VOL 0xb4 + + +/* global definition */ +#define RT5616_L_MUTE (0x1 << 15) +#define RT5616_L_MUTE_SFT 15 +#define RT5616_VOL_L_MUTE (0x1 << 14) +#define RT5616_VOL_L_SFT 14 +#define RT5616_R_MUTE (0x1 << 7) +#define RT5616_R_MUTE_SFT 7 +#define RT5616_VOL_R_MUTE (0x1 << 6) +#define RT5616_VOL_R_SFT 6 +#define RT5616_L_VOL_MASK (0x3f << 8) +#define RT5616_L_VOL_SFT 8 +#define RT5616_R_VOL_MASK (0x3f) +#define RT5616_R_VOL_SFT 0 + +/* LOUT Control 2(0x05) */ +#define RT5616_EN_DFO (0x1 << 15) + +/* IN1 and IN2 Control (0x0d) */ +/* IN3 and IN4 Control (0x0e) */ +#define RT5616_BST_MASK1 (0xf<<12) +#define RT5616_BST_SFT1 12 +#define RT5616_BST_MASK2 (0xf<<8) +#define RT5616_BST_SFT2 8 +#define RT5616_IN_DF1 (0x1 << 7) +#define RT5616_IN_SFT1 7 +#define RT5616_IN_DF2 (0x1 << 6) +#define RT5616_IN_SFT2 6 + +/* INL1 and INR1 Volume Control (0x0f) */ +#define RT5616_INL_VOL_MASK (0x1f << 8) +#define RT5616_INL_VOL_SFT 8 +#define RT5616_INR_SEL_MASK (0x1 << 7) +#define RT5616_INR_SEL_SFT 7 +#define RT5616_INR_SEL_IN4N (0x0 << 7) +#define RT5616_INR_SEL_MONON (0x1 << 7) +#define RT5616_INR_VOL_MASK (0x1f) +#define RT5616_INR_VOL_SFT 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5616_DAC_L1_VOL_MASK (0xff << 8) +#define RT5616_DAC_L1_VOL_SFT 8 +#define RT5616_DAC_R1_VOL_MASK (0xff) +#define RT5616_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5616_DAC_L2_VOL_MASK (0xff << 8) +#define RT5616_DAC_L2_VOL_SFT 8 +#define RT5616_DAC_R2_VOL_MASK (0xff) +#define RT5616_DAC_R2_VOL_SFT 0 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5616_ADC_L_VOL_MASK (0x7f << 8) +#define RT5616_ADC_L_VOL_SFT 8 +#define RT5616_ADC_R_VOL_MASK (0x7f) +#define RT5616_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5616_M_MONO_ADC_L (0x1 << 15) +#define RT5616_M_MONO_ADC_L_SFT 15 +#define RT5616_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5616_MONO_ADC_L_VOL_SFT 8 +#define RT5616_M_MONO_ADC_R (0x1 << 7) +#define RT5616_M_MONO_ADC_R_SFT 7 +#define RT5616_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5616_MONO_ADC_R_VOL_SFT 0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5616_ADC_L_BST_MASK (0x3 << 14) +#define RT5616_ADC_L_BST_SFT 14 +#define RT5616_ADC_R_BST_MASK (0x3 << 12) +#define RT5616_ADC_R_BST_SFT 12 +#define RT5616_ADC_COMP_MASK (0x3 << 10) +#define RT5616_ADC_COMP_SFT 10 + +/* Stereo ADC1 Mixer Control (0x27) */ +#define RT5616_M_STO1_ADC_L1 (0x1 << 14) +#define RT5616_M_STO1_ADC_L1_SFT 14 +#define RT5616_M_STO1_ADC_R1 (0x1 << 6) +#define RT5616_M_STO1_ADC_R1_SFT 6 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5616_M_ADCMIX_L (0x1 << 15) +#define RT5616_M_ADCMIX_L_SFT 15 +#define RT5616_M_IF1_DAC_L (0x1 << 14) +#define RT5616_M_IF1_DAC_L_SFT 14 +#define RT5616_M_ADCMIX_R (0x1 << 7) +#define RT5616_M_ADCMIX_R_SFT 7 +#define RT5616_M_IF1_DAC_R (0x1 << 6) +#define RT5616_M_IF1_DAC_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5616_M_DAC_L1_MIXL (0x1 << 14) +#define RT5616_M_DAC_L1_MIXL_SFT 14 +#define RT5616_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5616_DAC_L1_STO_L_VOL_SFT 13 +#define RT5616_M_DAC_R1_MIXL (0x1 << 9) +#define RT5616_M_DAC_R1_MIXL_SFT 9 +#define RT5616_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5616_DAC_R1_STO_L_VOL_SFT 8 +#define RT5616_M_DAC_R1_MIXR (0x1 << 6) +#define RT5616_M_DAC_R1_MIXR_SFT 6 +#define RT5616_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5616_DAC_R1_STO_R_VOL_SFT 5 +#define RT5616_M_DAC_L1_MIXR (0x1 << 1) +#define RT5616_M_DAC_L1_MIXR_SFT 1 +#define RT5616_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5616_DAC_L1_STO_R_VOL_SFT 0 + +/* DD Mixer Control (0x2b) */ +#define RT5616_M_STO_DD_L1 (0x1 << 14) +#define RT5616_M_STO_DD_L1_SFT 14 +#define RT5616_STO_DD_L1_VOL_MASK (0x1 << 13) +#define RT5616_DAC_DD_L1_VOL_SFT 13 +#define RT5616_M_STO_DD_L2 (0x1 << 12) +#define RT5616_M_STO_DD_L2_SFT 12 +#define RT5616_STO_DD_L2_VOL_MASK (0x1 << 11) +#define RT5616_STO_DD_L2_VOL_SFT 11 +#define RT5616_M_STO_DD_R2_L (0x1 << 10) +#define RT5616_M_STO_DD_R2_L_SFT 10 +#define RT5616_STO_DD_R2_L_VOL_MASK (0x1 << 9) +#define RT5616_STO_DD_R2_L_VOL_SFT 9 +#define RT5616_M_STO_DD_R1 (0x1 << 6) +#define RT5616_M_STO_DD_R1_SFT 6 +#define RT5616_STO_DD_R1_VOL_MASK (0x1 << 5) +#define RT5616_STO_DD_R1_VOL_SFT 5 +#define RT5616_M_STO_DD_R2 (0x1 << 4) +#define RT5616_M_STO_DD_R2_SFT 4 +#define RT5616_STO_DD_R2_VOL_MASK (0x1 << 3) +#define RT5616_STO_DD_R2_VOL_SFT 3 +#define RT5616_M_STO_DD_L2_R (0x1 << 2) +#define RT5616_M_STO_DD_L2_R_SFT 2 +#define RT5616_STO_DD_L2_R_VOL_MASK (0x1 << 1) +#define RT5616_STO_DD_L2_R_VOL_SFT 1 + +/* Digital Mixer Control (0x2c) */ +#define RT5616_M_STO_L_DAC_L (0x1 << 15) +#define RT5616_M_STO_L_DAC_L_SFT 15 +#define RT5616_STO_L_DAC_L_VOL_MASK (0x1 << 14) +#define RT5616_STO_L_DAC_L_VOL_SFT 14 +#define RT5616_M_DAC_L2_DAC_L (0x1 << 13) +#define RT5616_M_DAC_L2_DAC_L_SFT 13 +#define RT5616_DAC_L2_DAC_L_VOL_MASK (0x1 << 12) +#define RT5616_DAC_L2_DAC_L_VOL_SFT 12 +#define RT5616_M_STO_R_DAC_R (0x1 << 11) +#define RT5616_M_STO_R_DAC_R_SFT 11 +#define RT5616_STO_R_DAC_R_VOL_MASK (0x1 << 10) +#define RT5616_STO_R_DAC_R_VOL_SFT 10 +#define RT5616_M_DAC_R2_DAC_R (0x1 << 9) +#define RT5616_M_DAC_R2_DAC_R_SFT 9 +#define RT5616_DAC_R2_DAC_R_VOL_MASK (0x1 << 8) +#define RT5616_DAC_R2_DAC_R_VOL_SFT 8 + +/* DSP Path Control 1 (0x2d) */ +#define RT5616_RXDP_SRC_MASK (0x1 << 15) +#define RT5616_RXDP_SRC_SFT 15 +#define RT5616_RXDP_SRC_NOR (0x0 << 15) +#define RT5616_RXDP_SRC_DIV3 (0x1 << 15) +#define RT5616_TXDP_SRC_MASK (0x1 << 14) +#define RT5616_TXDP_SRC_SFT 14 +#define RT5616_TXDP_SRC_NOR (0x0 << 14) +#define RT5616_TXDP_SRC_DIV3 (0x1 << 14) + +/* DSP Path Control 2 (0x2e) */ +#define RT5616_DAC_L2_SEL_MASK (0x3 << 14) +#define RT5616_DAC_L2_SEL_SFT 14 +#define RT5616_DAC_L2_SEL_IF2 (0x0 << 14) +#define RT5616_DAC_L2_SEL_IF3 (0x1 << 14) +#define RT5616_DAC_L2_SEL_TXDC (0x2 << 14) +#define RT5616_DAC_L2_SEL_BASS (0x3 << 14) +#define RT5616_DAC_R2_SEL_MASK (0x3 << 12) +#define RT5616_DAC_R2_SEL_SFT 12 +#define RT5616_DAC_R2_SEL_IF2 (0x0 << 12) +#define RT5616_DAC_R2_SEL_IF3 (0x1 << 12) +#define RT5616_DAC_R2_SEL_TXDC (0x2 << 12) +#define RT5616_IF2_ADC_L_SEL_MASK (0x1 << 11) +#define RT5616_IF2_ADC_L_SEL_SFT 11 +#define RT5616_IF2_ADC_L_SEL_TXDP (0x0 << 11) +#define RT5616_IF2_ADC_L_SEL_PASS (0x1 << 11) +#define RT5616_IF2_ADC_R_SEL_MASK (0x1 << 10) +#define RT5616_IF2_ADC_R_SEL_SFT 10 +#define RT5616_IF2_ADC_R_SEL_TXDP (0x0 << 10) +#define RT5616_IF2_ADC_R_SEL_PASS (0x1 << 10) +#define RT5616_RXDC_SEL_MASK (0x3 << 8) +#define RT5616_RXDC_SEL_SFT 8 +#define RT5616_RXDC_SEL_NOR (0x0 << 8) +#define RT5616_RXDC_SEL_L2R (0x1 << 8) +#define RT5616_RXDC_SEL_R2L (0x2 << 8) +#define RT5616_RXDC_SEL_SWAP (0x3 << 8) +#define RT5616_RXDP_SEL_MASK (0x3 << 6) +#define RT5616_RXDP_SEL_SFT 6 +#define RT5616_RXDP_SEL_NOR (0x0 << 6) +#define RT5616_RXDP_SEL_L2R (0x1 << 6) +#define RT5616_RXDP_SEL_R2L (0x2 << 6) +#define RT5616_RXDP_SEL_SWAP (0x3 << 6) +#define RT5616_TXDC_SEL_MASK (0x3 << 4) +#define RT5616_TXDC_SEL_SFT 4 +#define RT5616_TXDC_SEL_NOR (0x0 << 4) +#define RT5616_TXDC_SEL_L2R (0x1 << 4) +#define RT5616_TXDC_SEL_R2L (0x2 << 4) +#define RT5616_TXDC_SEL_SWAP (0x3 << 4) +#define RT5616_TXDP_SEL_MASK (0x3 << 2) +#define RT5616_TXDP_SEL_SFT 2 +#define RT5616_TXDP_SEL_NOR (0x0 << 2) +#define RT5616_TXDP_SEL_L2R (0x1 << 2) +#define RT5616_TXDP_SEL_R2L (0x2 << 2) +#define RT5616_TRXDP_SEL_SWAP (0x3 << 2) + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5616_G_LN_L2_RM_L_MASK (0x7 << 13) +#define RT5616_G_IN_L2_RM_L_SFT 13 +#define RT5616_G_LN_L1_RM_L_MASK (0x7 << 10) +#define RT5616_G_IN_L1_RM_L_SFT 10 +#define RT5616_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5616_G_BST3_RM_L_SFT 4 +#define RT5616_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5616_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5616_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5616_G_BST1_RM_L_SFT 13 +#define RT5616_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5616_G_OM_L_RM_L_SFT 10 +#define RT5616_M_IN2_L_RM_L (0x1 << 6) +#define RT5616_M_IN2_L_RM_L_SFT 6 +#define RT5616_M_IN1_L_RM_L (0x1 << 5) +#define RT5616_M_IN1_L_RM_L_SFT 5 +#define RT5616_M_BST3_RM_L (0x1 << 3) +#define RT5616_M_BST3_RM_L_SFT 3 +#define RT5616_M_BST2_RM_L (0x1 << 2) +#define RT5616_M_BST2_RM_L_SFT 2 +#define RT5616_M_BST1_RM_L (0x1 << 1) +#define RT5616_M_BST1_RM_L_SFT 1 +#define RT5616_M_OM_L_RM_L (0x1) +#define RT5616_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5616_G_IN2_R_RM_R_MASK (0x7 << 13) +#define RT5616_G_IN2_R_RM_R_SFT 13 +#define RT5616_G_IN1_R_RM_R_MASK (0x7 << 10) +#define RT5616_G_IN1_R_RM_R_SFT 10 +#define RT5616_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5616_G_BST3_RM_R_SFT 4 +#define RT5616_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5616_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5616_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5616_G_BST1_RM_R_SFT 13 +#define RT5616_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5616_G_OM_R_RM_R_SFT 10 +#define RT5616_M_IN2_R_RM_R (0x1 << 6) +#define RT5616_M_IN2_R_RM_R_SFT 6 +#define RT5616_M_IN1_R_RM_R (0x1 << 5) +#define RT5616_M_IN1_R_RM_R_SFT 5 +#define RT5616_M_BST3_RM_R (0x1 << 3) +#define RT5616_M_BST3_RM_R_SFT 3 +#define RT5616_M_BST2_RM_R (0x1 << 2) +#define RT5616_M_BST2_RM_R_SFT 2 +#define RT5616_M_BST1_RM_R (0x1 << 1) +#define RT5616_M_BST1_RM_R_SFT 1 +#define RT5616_M_OM_R_RM_R (0x1) +#define RT5616_M_OM_R_RM_R_SFT 0 + +/* HPMIX Control (0x45) */ +#define RT5616_M_DAC1_HM (0x1 << 14) +#define RT5616_M_DAC1_HM_SFT 14 +#define RT5616_M_HPVOL_HM (0x1 << 13) +#define RT5616_M_HPVOL_HM_SFT 13 +#define RT5616_G_HPOMIX_MASK (0x1 << 12) +#define RT5616_G_HPOMIX_SFT 12 + +/* SPK Left Mixer Control (0x46) */ +#define RT5616_G_RM_L_SM_L_MASK (0x3 << 14) +#define RT5616_G_RM_L_SM_L_SFT 14 +#define RT5616_G_IN_L_SM_L_MASK (0x3 << 12) +#define RT5616_G_IN_L_SM_L_SFT 12 +#define RT5616_G_DAC_L1_SM_L_MASK (0x3 << 10) +#define RT5616_G_DAC_L1_SM_L_SFT 10 +#define RT5616_G_DAC_L2_SM_L_MASK (0x3 << 8) +#define RT5616_G_DAC_L2_SM_L_SFT 8 +#define RT5616_G_OM_L_SM_L_MASK (0x3 << 6) +#define RT5616_G_OM_L_SM_L_SFT 6 +#define RT5616_M_RM_L_SM_L (0x1 << 5) +#define RT5616_M_RM_L_SM_L_SFT 5 +#define RT5616_M_IN_L_SM_L (0x1 << 4) +#define RT5616_M_IN_L_SM_L_SFT 4 +#define RT5616_M_DAC_L1_SM_L (0x1 << 3) +#define RT5616_M_DAC_L1_SM_L_SFT 3 +#define RT5616_M_DAC_L2_SM_L (0x1 << 2) +#define RT5616_M_DAC_L2_SM_L_SFT 2 +#define RT5616_M_OM_L_SM_L (0x1 << 1) +#define RT5616_M_OM_L_SM_L_SFT 1 + +/* SPK Right Mixer Control (0x47) */ +#define RT5616_G_RM_R_SM_R_MASK (0x3 << 14) +#define RT5616_G_RM_R_SM_R_SFT 14 +#define RT5616_G_IN_R_SM_R_MASK (0x3 << 12) +#define RT5616_G_IN_R_SM_R_SFT 12 +#define RT5616_G_DAC_R1_SM_R_MASK (0x3 << 10) +#define RT5616_G_DAC_R1_SM_R_SFT 10 +#define RT5616_G_DAC_R2_SM_R_MASK (0x3 << 8) +#define RT5616_G_DAC_R2_SM_R_SFT 8 +#define RT5616_G_OM_R_SM_R_MASK (0x3 << 6) +#define RT5616_G_OM_R_SM_R_SFT 6 +#define RT5616_M_RM_R_SM_R (0x1 << 5) +#define RT5616_M_RM_R_SM_R_SFT 5 +#define RT5616_M_IN_R_SM_R (0x1 << 4) +#define RT5616_M_IN_R_SM_R_SFT 4 +#define RT5616_M_DAC_R1_SM_R (0x1 << 3) +#define RT5616_M_DAC_R1_SM_R_SFT 3 +#define RT5616_M_DAC_R2_SM_R (0x1 << 2) +#define RT5616_M_DAC_R2_SM_R_SFT 2 +#define RT5616_M_OM_R_SM_R (0x1 << 1) +#define RT5616_M_OM_R_SM_R_SFT 1 + +/* SPOLMIX Control (0x48) */ +#define RT5616_M_DAC_R1_SPM_L (0x1 << 15) +#define RT5616_M_DAC_R1_SPM_L_SFT 15 +#define RT5616_M_DAC_L1_SPM_L (0x1 << 14) +#define RT5616_M_DAC_L1_SPM_L_SFT 14 +#define RT5616_M_SV_R_SPM_L (0x1 << 13) +#define RT5616_M_SV_R_SPM_L_SFT 13 +#define RT5616_M_SV_L_SPM_L (0x1 << 12) +#define RT5616_M_SV_L_SPM_L_SFT 12 +#define RT5616_M_BST1_SPM_L (0x1 << 11) +#define RT5616_M_BST1_SPM_L_SFT 11 + +/* SPORMIX Control (0x49) */ +#define RT5616_M_DAC_R1_SPM_R (0x1 << 13) +#define RT5616_M_DAC_R1_SPM_R_SFT 13 +#define RT5616_M_SV_R_SPM_R (0x1 << 12) +#define RT5616_M_SV_R_SPM_R_SFT 12 +#define RT5616_M_BST1_SPM_R (0x1 << 11) +#define RT5616_M_BST1_SPM_R_SFT 11 + +/* SPOLMIX / SPORMIX Ratio Control (0x4a) */ +#define RT5616_SPO_CLSD_RATIO_MASK (0x7) +#define RT5616_SPO_CLSD_RATIO_SFT 0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5616_M_DAC_R2_MM (0x1 << 15) +#define RT5616_M_DAC_R2_MM_SFT 15 +#define RT5616_M_DAC_L2_MM (0x1 << 14) +#define RT5616_M_DAC_L2_MM_SFT 14 +#define RT5616_M_OV_R_MM (0x1 << 13) +#define RT5616_M_OV_R_MM_SFT 13 +#define RT5616_M_OV_L_MM (0x1 << 12) +#define RT5616_M_OV_L_MM_SFT 12 +#define RT5616_M_BST1_MM (0x1 << 11) +#define RT5616_M_BST1_MM_SFT 11 +#define RT5616_G_MONOMIX_MASK (0x1 << 10) +#define RT5616_G_MONOMIX_SFT 10 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5616_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5616_G_BST2_OM_L_SFT 10 +#define RT5616_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5616_G_BST1_OM_L_SFT 7 +#define RT5616_G_IN1_L_OM_L_MASK (0x7 << 4) +#define RT5616_G_IN1_L_OM_L_SFT 4 +#define RT5616_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5616_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5616_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5616_G_DAC_L1_OM_L_SFT 7 +#define RT5616_G_IN2_L_OM_L_MASK (0x7 << 4) +#define RT5616_G_IN2_L_OM_L_SFT 4 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5616_M_IN2_L_OM_L (0x1 << 9) +#define RT5616_M_IN2_L_OM_L_SFT 9 +#define RT5616_M_BST2_OM_L (0x1 << 6) +#define RT5616_M_BST2_OM_L_SFT 6 +#define RT5616_M_BST1_OM_L (0x1 << 5) +#define RT5616_M_BST1_OM_L_SFT 5 +#define RT5616_M_IN1_L_OM_L (0x1 << 4) +#define RT5616_M_IN1_L_OM_L_SFT 4 +#define RT5616_M_RM_L_OM_L (0x1 << 3) +#define RT5616_M_RM_L_OM_L_SFT 3 +#define RT5616_M_DAC_L1_OM_L (0x1) +#define RT5616_M_DAC_L1_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5616_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5616_G_BST2_OM_R_SFT 10 +#define RT5616_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5616_G_BST1_OM_R_SFT 7 +#define RT5616_G_IN1_R_OM_R_MASK (0x7 << 4) +#define RT5616_G_IN1_R_OM_R_SFT 4 +#define RT5616_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5616_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5616_G_DAC_R1_OM_R_MASK (0x7 << 7) +#define RT5616_G_DAC_R1_OM_R_SFT 7 +#define RT5616_G_IN2_R_OM_R_MASK (0x7 << 4) +#define RT5616_G_IN2_R_OM_R_SFT 4 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5616_M_IN2_R_OM_R (0x1 << 9) +#define RT5616_M_IN2_R_OM_R_SFT 9 +#define RT5616_M_BST2_OM_R (0x1 << 6) +#define RT5616_M_BST2_OM_R_SFT 6 +#define RT5616_M_BST1_OM_R (0x1 << 5) +#define RT5616_M_BST1_OM_R_SFT 5 +#define RT5616_M_IN1_R_OM_R (0x1 << 4) +#define RT5616_M_IN1_R_OM_R_SFT 4 +#define RT5616_M_RM_R_OM_R (0x1 << 3) +#define RT5616_M_RM_R_OM_R_SFT 3 +#define RT5616_M_DAC_R1_OM_R (0x1) +#define RT5616_M_DAC_R1_OM_R_SFT 0 + +/* LOUT Mixer Control (0x53) */ +#define RT5616_M_DAC_L1_LM (0x1 << 15) +#define RT5616_M_DAC_L1_LM_SFT 15 +#define RT5616_M_DAC_R1_LM (0x1 << 14) +#define RT5616_M_DAC_R1_LM_SFT 14 +#define RT5616_M_OV_L_LM (0x1 << 13) +#define RT5616_M_OV_L_LM_SFT 13 +#define RT5616_M_OV_R_LM (0x1 << 12) +#define RT5616_M_OV_R_LM_SFT 12 +#define RT5616_G_LOUTMIX_MASK (0x1 << 11) +#define RT5616_G_LOUTMIX_SFT 11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5616_PWR_I2S1 (0x1 << 15) +#define RT5616_PWR_I2S1_BIT 15 +#define RT5616_PWR_I2S2 (0x1 << 14) +#define RT5616_PWR_I2S2_BIT 14 +#define RT5616_PWR_DAC_L1 (0x1 << 12) +#define RT5616_PWR_DAC_L1_BIT 12 +#define RT5616_PWR_DAC_R1 (0x1 << 11) +#define RT5616_PWR_DAC_R1_BIT 11 +#define RT5616_PWR_ADC_L (0x1 << 2) +#define RT5616_PWR_ADC_L_BIT 2 +#define RT5616_PWR_ADC_R (0x1 << 1) +#define RT5616_PWR_ADC_R_BIT 1 + +/* Power Management for Digital 2 (0x62) */ +#define RT5616_PWR_ADC_STO1_F (0x1 << 15) +#define RT5616_PWR_ADC_STO1_F_BIT 15 +#define RT5616_PWR_DAC_STO1_F (0x1 << 11) +#define RT5616_PWR_DAC_STO1_F_BIT 11 + +/* Power Management for Analog 1 (0x63) */ +#define RT5616_PWR_VREF1 (0x1 << 15) +#define RT5616_PWR_VREF1_BIT 15 +#define RT5616_PWR_FV1 (0x1 << 14) +#define RT5616_PWR_FV1_BIT 14 +#define RT5616_PWR_MB (0x1 << 13) +#define RT5616_PWR_MB_BIT 13 +#define RT5616_PWR_LM (0x1 << 12) +#define RT5616_PWR_LM_BIT 12 +#define RT5616_PWR_BG (0x1 << 11) +#define RT5616_PWR_BG_BIT 11 +#define RT5616_PWR_HP_L (0x1 << 7) +#define RT5616_PWR_HP_L_BIT 7 +#define RT5616_PWR_HP_R (0x1 << 6) +#define RT5616_PWR_HP_R_BIT 6 +#define RT5616_PWR_HA (0x1 << 5) +#define RT5616_PWR_HA_BIT 5 +#define RT5616_PWR_VREF2 (0x1 << 4) +#define RT5616_PWR_VREF2_BIT 4 +#define RT5616_PWR_FV2 (0x1 << 3) +#define RT5616_PWR_FV2_BIT 3 +#define RT5616_PWR_LDO (0x1 << 2) +#define RT5616_PWR_LDO_BIT 2 +#define RT5616_PWR_LDO_DVO_MASK (0x3) +#define RT5616_PWR_LDO_DVO_1_0V 0 +#define RT5616_PWR_LDO_DVO_1_1V 1 +#define RT5616_PWR_LDO_DVO_1_2V 2 +#define RT5616_PWR_LDO_DVO_1_3V 3 + +/* Power Management for Analog 2 (0x64) */ +#define RT5616_PWR_BST1 (0x1 << 15) +#define RT5616_PWR_BST1_BIT 15 +#define RT5616_PWR_BST2 (0x1 << 14) +#define RT5616_PWR_BST2_BIT 14 +#define RT5616_PWR_MB1 (0x1 << 11) +#define RT5616_PWR_MB1_BIT 11 +#define RT5616_PWR_PLL (0x1 << 9) +#define RT5616_PWR_PLL_BIT 9 +#define RT5616_PWR_BST1_OP2 (0x1 << 5) +#define RT5616_PWR_BST1_OP2_BIT 5 +#define RT5616_PWR_BST2_OP2 (0x1 << 4) +#define RT5616_PWR_BST2_OP2_BIT 4 +#define RT5616_PWR_BST3_OP2 (0x1 << 3) +#define RT5616_PWR_BST3_OP2_BIT 3 +#define RT5616_PWR_JD_M (0x1 << 2) +#define RT5616_PWM_JD_M_BIT 2 +#define RT5616_PWR_JD2 (0x1 << 1) +#define RT5616_PWM_JD2_BIT 1 +#define RT5616_PWR_JD3 (0x1) +#define RT5616_PWM_JD3_BIT 0 + +/* Power Management for Mixer (0x65) */ +#define RT5616_PWR_OM_L (0x1 << 15) +#define RT5616_PWR_OM_L_BIT 15 +#define RT5616_PWR_OM_R (0x1 << 14) +#define RT5616_PWR_OM_R_BIT 14 +#define RT5616_PWR_RM_L (0x1 << 11) +#define RT5616_PWR_RM_L_BIT 11 +#define RT5616_PWR_RM_R (0x1 << 10) +#define RT5616_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5616_PWR_OV_L (0x1 << 13) +#define RT5616_PWR_OV_L_BIT 13 +#define RT5616_PWR_OV_R (0x1 << 12) +#define RT5616_PWR_OV_R_BIT 12 +#define RT5616_PWR_HV_L (0x1 << 11) +#define RT5616_PWR_HV_L_BIT 11 +#define RT5616_PWR_HV_R (0x1 << 10) +#define RT5616_PWR_HV_R_BIT 10 +#define RT5616_PWR_IN1_L (0x1 << 9) +#define RT5616_PWR_IN1_L_BIT 9 +#define RT5616_PWR_IN1_R (0x1 << 8) +#define RT5616_PWR_IN1_R_BIT 8 +#define RT5616_PWR_IN2_L (0x1 << 7) +#define RT5616_PWR_IN2_L_BIT 7 +#define RT5616_PWR_IN2_R (0x1 << 6) +#define RT5616_PWR_IN2_R_BIT 6 + +/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5616_I2S_MS_MASK (0x1 << 15) +#define RT5616_I2S_MS_SFT 15 +#define RT5616_I2S_MS_M (0x0 << 15) +#define RT5616_I2S_MS_S (0x1 << 15) +#define RT5616_I2S_O_CP_MASK (0x3 << 10) +#define RT5616_I2S_O_CP_SFT 10 +#define RT5616_I2S_O_CP_OFF (0x0 << 10) +#define RT5616_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5616_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5616_I2S_I_CP_MASK (0x3 << 8) +#define RT5616_I2S_I_CP_SFT 8 +#define RT5616_I2S_I_CP_OFF (0x0 << 8) +#define RT5616_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5616_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5616_I2S_BP_MASK (0x1 << 7) +#define RT5616_I2S_BP_SFT 7 +#define RT5616_I2S_BP_NOR (0x0 << 7) +#define RT5616_I2S_BP_INV (0x1 << 7) +#define RT5616_I2S_DL_MASK (0x3 << 2) +#define RT5616_I2S_DL_SFT 2 +#define RT5616_I2S_DL_16 (0x0 << 2) +#define RT5616_I2S_DL_20 (0x1 << 2) +#define RT5616_I2S_DL_24 (0x2 << 2) +#define RT5616_I2S_DL_8 (0x3 << 2) +#define RT5616_I2S_DF_MASK (0x3) +#define RT5616_I2S_DF_SFT 0 +#define RT5616_I2S_DF_I2S (0x0) +#define RT5616_I2S_DF_LEFT (0x1) +#define RT5616_I2S_DF_PCM_A (0x2) +#define RT5616_I2S_DF_PCM_B (0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5616_I2S_PD1_MASK (0x7 << 12) +#define RT5616_I2S_PD1_SFT 12 +#define RT5616_I2S_PD1_1 (0x0 << 12) +#define RT5616_I2S_PD1_2 (0x1 << 12) +#define RT5616_I2S_PD1_3 (0x2 << 12) +#define RT5616_I2S_PD1_4 (0x3 << 12) +#define RT5616_I2S_PD1_6 (0x4 << 12) +#define RT5616_I2S_PD1_8 (0x5 << 12) +#define RT5616_I2S_PD1_12 (0x6 << 12) +#define RT5616_I2S_PD1_16 (0x7 << 12) +#define RT5616_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5616_DAC_OSR_MASK (0x3 << 2) +#define RT5616_DAC_OSR_SFT 2 +#define RT5616_DAC_OSR_128 (0x0 << 2) +#define RT5616_DAC_OSR_64 (0x1 << 2) +#define RT5616_DAC_OSR_32 (0x2 << 2) +#define RT5616_DAC_OSR_128_3 (0x3 << 2) +#define RT5616_ADC_OSR_MASK (0x3) +#define RT5616_ADC_OSR_SFT 0 +#define RT5616_ADC_OSR_128 (0x0) +#define RT5616_ADC_OSR_64 (0x1) +#define RT5616_ADC_OSR_32 (0x2) +#define RT5616_ADC_OSR_128_3 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5616_DAHPF_EN (0x1 << 11) +#define RT5616_DAHPF_EN_SFT 11 +#define RT5616_ADHPF_EN (0x1 << 10) +#define RT5616_ADHPF_EN_SFT 10 + +/* TDM Control 1 (0x77) */ +#define RT5616_TDM_INTEL_SEL_MASK (0x1 << 15) +#define RT5616_TDM_INTEL_SEL_SFT 15 +#define RT5616_TDM_INTEL_SEL_64 (0x0 << 15) +#define RT5616_TDM_INTEL_SEL_50 (0x1 << 15) +#define RT5616_TDM_MODE_SEL_MASK (0x1 << 14) +#define RT5616_TDM_MODE_SEL_SFT 14 +#define RT5616_TDM_MODE_SEL_NOR (0x0 << 14) +#define RT5616_TDM_MODE_SEL_TDM (0x1 << 14) +#define RT5616_TDM_CH_NUM_SEL_MASK (0x3 << 12) +#define RT5616_TDM_CH_NUM_SEL_SFT 12 +#define RT5616_TDM_CH_NUM_SEL_2 (0x0 << 12) +#define RT5616_TDM_CH_NUM_SEL_4 (0x1 << 12) +#define RT5616_TDM_CH_NUM_SEL_6 (0x2 << 12) +#define RT5616_TDM_CH_NUM_SEL_8 (0x3 << 12) +#define RT5616_TDM_CH_LEN_SEL_MASK (0x3 << 10) +#define RT5616_TDM_CH_LEN_SEL_SFT 10 +#define RT5616_TDM_CH_LEN_SEL_16 (0x0 << 10) +#define RT5616_TDM_CH_LEN_SEL_20 (0x1 << 10) +#define RT5616_TDM_CH_LEN_SEL_24 (0x2 << 10) +#define RT5616_TDM_CH_LEN_SEL_32 (0x3 << 10) +#define RT5616_TDM_ADC_SEL_MASK (0x1 << 9) +#define RT5616_TDM_ADC_SEL_SFT 9 +#define RT5616_TDM_ADC_SEL_NOR (0x0 << 9) +#define RT5616_TDM_ADC_SEL_SWAP (0x1 << 9) +#define RT5616_TDM_ADC_START_SEL_MASK (0x1 << 8) +#define RT5616_TDM_ADC_START_SEL_SFT 8 +#define RT5616_TDM_ADC_START_SEL_SL0 (0x0 << 8) +#define RT5616_TDM_ADC_START_SEL_SL4 (0x1 << 8) +#define RT5616_TDM_I2S_CH2_SEL_MASK (0x3 << 6) +#define RT5616_TDM_I2S_CH2_SEL_SFT 6 +#define RT5616_TDM_I2S_CH2_SEL_LR (0x0 << 6) +#define RT5616_TDM_I2S_CH2_SEL_RL (0x1 << 6) +#define RT5616_TDM_I2S_CH2_SEL_LL (0x2 << 6) +#define RT5616_TDM_I2S_CH2_SEL_RR (0x3 << 6) +#define RT5616_TDM_I2S_CH4_SEL_MASK (0x3 << 4) +#define RT5616_TDM_I2S_CH4_SEL_SFT 4 +#define RT5616_TDM_I2S_CH4_SEL_LR (0x0 << 4) +#define RT5616_TDM_I2S_CH4_SEL_RL (0x1 << 4) +#define RT5616_TDM_I2S_CH4_SEL_LL (0x2 << 4) +#define RT5616_TDM_I2S_CH4_SEL_RR (0x3 << 4) +#define RT5616_TDM_I2S_CH6_SEL_MASK (0x3 << 2) +#define RT5616_TDM_I2S_CH6_SEL_SFT 2 +#define RT5616_TDM_I2S_CH6_SEL_LR (0x0 << 2) +#define RT5616_TDM_I2S_CH6_SEL_RL (0x1 << 2) +#define RT5616_TDM_I2S_CH6_SEL_LL (0x2 << 2) +#define RT5616_TDM_I2S_CH6_SEL_RR (0x3 << 2) +#define RT5616_TDM_I2S_CH8_SEL_MASK (0x3) +#define RT5616_TDM_I2S_CH8_SEL_SFT 0 +#define RT5616_TDM_I2S_CH8_SEL_LR (0x0) +#define RT5616_TDM_I2S_CH8_SEL_RL (0x1) +#define RT5616_TDM_I2S_CH8_SEL_LL (0x2) +#define RT5616_TDM_I2S_CH8_SEL_RR (0x3) + +/* TDM Control 2 (0x78) */ +#define RT5616_TDM_LRCK_POL_SEL_MASK (0x1 << 15) +#define RT5616_TDM_LRCK_POL_SEL_SFT 15 +#define RT5616_TDM_LRCK_POL_SEL_NOR (0x0 << 15) +#define RT5616_TDM_LRCK_POL_SEL_INV (0x1 << 15) +#define RT5616_TDM_CH_VAL_SEL_MASK (0x1 << 14) +#define RT5616_TDM_CH_VAL_SEL_SFT 14 +#define RT5616_TDM_CH_VAL_SEL_CH01 (0x0 << 14) +#define RT5616_TDM_CH_VAL_SEL_CH0123 (0x1 << 14) +#define RT5616_TDM_CH_VAL_EN (0x1 << 13) +#define RT5616_TDM_CH_VAL_SFT 13 +#define RT5616_TDM_LPBK_EN (0x1 << 12) +#define RT5616_TDM_LPBK_SFT 12 +#define RT5616_TDM_LRCK_PULSE_SEL_MASK (0x1 << 11) +#define RT5616_TDM_LRCK_PULSE_SEL_SFT 11 +#define RT5616_TDM_LRCK_PULSE_SEL_BCLK (0x0 << 11) +#define RT5616_TDM_LRCK_PULSE_SEL_CH (0x1 << 11) +#define RT5616_TDM_END_EDGE_SEL_MASK (0x1 << 10) +#define RT5616_TDM_END_EDGE_SEL_SFT 10 +#define RT5616_TDM_END_EDGE_SEL_POS (0x0 << 10) +#define RT5616_TDM_END_EDGE_SEL_NEG (0x1 << 10) +#define RT5616_TDM_END_EDGE_EN (0x1 << 9) +#define RT5616_TDM_END_EDGE_EN_SFT 9 +#define RT5616_TDM_TRAN_EDGE_SEL_MASK (0x1 << 8) +#define RT5616_TDM_TRAN_EDGE_SEL_SFT 8 +#define RT5616_TDM_TRAN_EDGE_SEL_POS (0x0 << 8) +#define RT5616_TDM_TRAN_EDGE_SEL_NEG (0x1 << 8) +#define RT5616_M_TDM2_L (0x1 << 7) +#define RT5616_M_TDM2_L_SFT 7 +#define RT5616_M_TDM2_R (0x1 << 6) +#define RT5616_M_TDM2_R_SFT 6 +#define RT5616_M_TDM4_L (0x1 << 5) +#define RT5616_M_TDM4_L_SFT 5 +#define RT5616_M_TDM4_R (0x1 << 4) +#define RT5616_M_TDM4_R_SFT 4 + +/* Global Clock Control (0x80) */ +#define RT5616_SCLK_SRC_MASK (0x3 << 14) +#define RT5616_SCLK_SRC_SFT 14 +#define RT5616_SCLK_SRC_MCLK (0x0 << 14) +#define RT5616_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5616_PLL1_SRC_MASK (0x3 << 12) +#define RT5616_PLL1_SRC_SFT 12 +#define RT5616_PLL1_SRC_MCLK (0x0 << 12) +#define RT5616_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5616_PLL1_SRC_BCLK2 (0x2 << 12) +#define RT5616_PLL1_PD_MASK (0x1 << 3) +#define RT5616_PLL1_PD_SFT 3 +#define RT5616_PLL1_PD_1 (0x0 << 3) +#define RT5616_PLL1_PD_2 (0x1 << 3) + +#define RT5616_PLL_INP_MAX 40000000 +#define RT5616_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5616_PLL_N_MAX 0x1ff +#define RT5616_PLL_N_MASK (RT5616_PLL_N_MAX << 7) +#define RT5616_PLL_N_SFT 7 +#define RT5616_PLL_K_MAX 0x1f +#define RT5616_PLL_K_MASK (RT5616_PLL_K_MAX) +#define RT5616_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5616_PLL_M_MAX 0xf +#define RT5616_PLL_M_MASK (RT5616_PLL_M_MAX << 12) +#define RT5616_PLL_M_SFT 12 +#define RT5616_PLL_M_BP (0x1 << 11) +#define RT5616_PLL_M_BP_SFT 11 + +/* PLL tracking mode 1 (0x83) */ +#define RT5616_STO1_T_MASK (0x1 << 15) +#define RT5616_STO1_T_SFT 15 +#define RT5616_STO1_T_SCLK (0x0 << 15) +#define RT5616_STO1_T_LRCK1 (0x1 << 15) +#define RT5616_STO2_T_MASK (0x1 << 12) +#define RT5616_STO2_T_SFT 12 +#define RT5616_STO2_T_I2S2 (0x0 << 12) +#define RT5616_STO2_T_LRCK2 (0x1 << 12) +#define RT5616_ASRC2_REF_MASK (0x1 << 11) +#define RT5616_ASRC2_REF_SFT 11 +#define RT5616_ASRC2_REF_LRCK2 (0x0 << 11) +#define RT5616_ASRC2_REF_LRCK1 (0x1 << 11) +#define RT5616_DMIC_1_M_MASK (0x1 << 9) +#define RT5616_DMIC_1_M_SFT 9 +#define RT5616_DMIC_1_M_NOR (0x0 << 9) +#define RT5616_DMIC_1_M_ASYN (0x1 << 9) + +/* PLL tracking mode 2 (0x84) */ +#define RT5616_STO1_ASRC_EN (0x1 << 15) +#define RT5616_STO1_ASRC_EN_SFT 15 +#define RT5616_STO2_ASRC_EN (0x1 << 14) +#define RT5616_STO2_ASRC_EN_SFT 14 +#define RT5616_STO1_DAC_M_MASK (0x1 << 13) +#define RT5616_STO1_DAC_M_SFT 13 +#define RT5616_STO1_DAC_M_NOR (0x0 << 13) +#define RT5616_STO1_DAC_M_ASRC (0x1 << 13) +#define RT5616_STO2_DAC_M_MASK (0x1 << 12) +#define RT5616_STO2_DAC_M_SFT 12 +#define RT5616_STO2_DAC_M_NOR (0x0 << 12) +#define RT5616_STO2_DAC_M_ASRC (0x1 << 12) +#define RT5616_ADC_M_MASK (0x1 << 11) +#define RT5616_ADC_M_SFT 11 +#define RT5616_ADC_M_NOR (0x0 << 11) +#define RT5616_ADC_M_ASRC (0x1 << 11) +#define RT5616_I2S1_R_D_MASK (0x1 << 4) +#define RT5616_I2S1_R_D_SFT 4 +#define RT5616_I2S1_R_D_DIS (0x0 << 4) +#define RT5616_I2S1_R_D_EN (0x1 << 4) +#define RT5616_I2S2_R_D_MASK (0x1 << 3) +#define RT5616_I2S2_R_D_SFT 3 +#define RT5616_I2S2_R_D_DIS (0x0 << 3) +#define RT5616_I2S2_R_D_EN (0x1 << 3) +#define RT5616_PRE_SCLK_MASK (0x3) +#define RT5616_PRE_SCLK_SFT 0 +#define RT5616_PRE_SCLK_512 (0x0) +#define RT5616_PRE_SCLK_1024 (0x1) +#define RT5616_PRE_SCLK_2048 (0x2) + +/* PLL tracking mode 3 (0x85) */ +#define RT5616_I2S1_RATE_MASK (0xf << 12) +#define RT5616_I2S1_RATE_SFT 12 +#define RT5616_I2S2_RATE_MASK (0xf << 8) +#define RT5616_I2S2_RATE_SFT 8 +#define RT5616_G_ASRC_LP_MASK (0x1 << 3) +#define RT5616_G_ASRC_LP_SFT 3 +#define RT5616_ASRC_LP_F_M (0x1 << 2) +#define RT5616_ASRC_LP_F_SFT 2 +#define RT5616_ASRC_LP_F_NOR (0x0 << 2) +#define RT5616_ASRC_LP_F_SB (0x1 << 2) +#define RT5616_FTK_PH_DET_MASK (0x3) +#define RT5616_FTK_PH_DET_SFT 0 +#define RT5616_FTK_PH_DET_DIV1 (0x0) +#define RT5616_FTK_PH_DET_DIV2 (0x1) +#define RT5616_FTK_PH_DET_DIV4 (0x2) +#define RT5616_FTK_PH_DET_DIV8 (0x3) + +/*PLL tracking mode 6 (0x89) */ +#define RT5616_I2S1_PD_MASK (0x7 << 12) +#define RT5616_I2S1_PD_SFT 12 +#define RT5616_I2S2_PD_MASK (0x7 << 8) +#define RT5616_I2S2_PD_SFT 8 + +/*PLL tracking mode 7 (0x8a) */ +#define RT5616_FSI1_RATE_MASK (0xf << 12) +#define RT5616_FSI1_RATE_SFT 12 +#define RT5616_FSI2_RATE_MASK (0xf << 8) +#define RT5616_FSI2_RATE_SFT 8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5616_HP_OVCD_MASK (0x1 << 10) +#define RT5616_HP_OVCD_SFT 10 +#define RT5616_HP_OVCD_DIS (0x0 << 10) +#define RT5616_HP_OVCD_EN (0x1 << 10) +#define RT5616_HP_OC_TH_MASK (0x3 << 8) +#define RT5616_HP_OC_TH_SFT 8 +#define RT5616_HP_OC_TH_90 (0x0 << 8) +#define RT5616_HP_OC_TH_105 (0x1 << 8) +#define RT5616_HP_OC_TH_120 (0x2 << 8) +#define RT5616_HP_OC_TH_135 (0x3 << 8) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5616_SMT_TRIG_MASK (0x1 << 15) +#define RT5616_SMT_TRIG_SFT 15 +#define RT5616_SMT_TRIG_DIS (0x0 << 15) +#define RT5616_SMT_TRIG_EN (0x1 << 15) +#define RT5616_HP_L_SMT_MASK (0x1 << 9) +#define RT5616_HP_L_SMT_SFT 9 +#define RT5616_HP_L_SMT_DIS (0x0 << 9) +#define RT5616_HP_L_SMT_EN (0x1 << 9) +#define RT5616_HP_R_SMT_MASK (0x1 << 8) +#define RT5616_HP_R_SMT_SFT 8 +#define RT5616_HP_R_SMT_DIS (0x0 << 8) +#define RT5616_HP_R_SMT_EN (0x1 << 8) +#define RT5616_HP_CD_PD_MASK (0x1 << 7) +#define RT5616_HP_CD_PD_SFT 7 +#define RT5616_HP_CD_PD_DIS (0x0 << 7) +#define RT5616_HP_CD_PD_EN (0x1 << 7) +#define RT5616_RSTN_MASK (0x1 << 6) +#define RT5616_RSTN_SFT 6 +#define RT5616_RSTN_DIS (0x0 << 6) +#define RT5616_RSTN_EN (0x1 << 6) +#define RT5616_RSTP_MASK (0x1 << 5) +#define RT5616_RSTP_SFT 5 +#define RT5616_RSTP_DIS (0x0 << 5) +#define RT5616_RSTP_EN (0x1 << 5) +#define RT5616_HP_CO_MASK (0x1 << 4) +#define RT5616_HP_CO_SFT 4 +#define RT5616_HP_CO_DIS (0x0 << 4) +#define RT5616_HP_CO_EN (0x1 << 4) +#define RT5616_HP_CP_MASK (0x1 << 3) +#define RT5616_HP_CP_SFT 3 +#define RT5616_HP_CP_PD (0x0 << 3) +#define RT5616_HP_CP_PU (0x1 << 3) +#define RT5616_HP_SG_MASK (0x1 << 2) +#define RT5616_HP_SG_SFT 2 +#define RT5616_HP_SG_DIS (0x0 << 2) +#define RT5616_HP_SG_EN (0x1 << 2) +#define RT5616_HP_DP_MASK (0x1 << 1) +#define RT5616_HP_DP_SFT 1 +#define RT5616_HP_DP_PD (0x0 << 1) +#define RT5616_HP_DP_PU (0x1 << 1) +#define RT5616_HP_CB_MASK (0x1) +#define RT5616_HP_CB_SFT 0 +#define RT5616_HP_CB_PD (0x0) +#define RT5616_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5616_DEPOP_MASK (0x1 << 13) +#define RT5616_DEPOP_SFT 13 +#define RT5616_DEPOP_AUTO (0x0 << 13) +#define RT5616_DEPOP_MAN (0x1 << 13) +#define RT5616_RAMP_MASK (0x1 << 12) +#define RT5616_RAMP_SFT 12 +#define RT5616_RAMP_DIS (0x0 << 12) +#define RT5616_RAMP_EN (0x1 << 12) +#define RT5616_BPS_MASK (0x1 << 11) +#define RT5616_BPS_SFT 11 +#define RT5616_BPS_DIS (0x0 << 11) +#define RT5616_BPS_EN (0x1 << 11) +#define RT5616_FAST_UPDN_MASK (0x1 << 10) +#define RT5616_FAST_UPDN_SFT 10 +#define RT5616_FAST_UPDN_DIS (0x0 << 10) +#define RT5616_FAST_UPDN_EN (0x1 << 10) +#define RT5616_MRES_MASK (0x3 << 8) +#define RT5616_MRES_SFT 8 +#define RT5616_MRES_15MO (0x0 << 8) +#define RT5616_MRES_25MO (0x1 << 8) +#define RT5616_MRES_35MO (0x2 << 8) +#define RT5616_MRES_45MO (0x3 << 8) +#define RT5616_VLO_MASK (0x1 << 7) +#define RT5616_VLO_SFT 7 +#define RT5616_VLO_3V (0x0 << 7) +#define RT5616_VLO_32V (0x1 << 7) +#define RT5616_DIG_DP_MASK (0x1 << 6) +#define RT5616_DIG_DP_SFT 6 +#define RT5616_DIG_DP_DIS (0x0 << 6) +#define RT5616_DIG_DP_EN (0x1 << 6) +#define RT5616_DP_TH_MASK (0x3 << 4) +#define RT5616_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5616_CP_SYS_MASK (0x7 << 12) +#define RT5616_CP_SYS_SFT 12 +#define RT5616_CP_FQ1_MASK (0x7 << 8) +#define RT5616_CP_FQ1_SFT 8 +#define RT5616_CP_FQ2_MASK (0x7 << 4) +#define RT5616_CP_FQ2_SFT 4 +#define RT5616_CP_FQ3_MASK (0x7) +#define RT5616_CP_FQ3_SFT 0 +#define RT5616_CP_FQ_1_5_KHZ 0 +#define RT5616_CP_FQ_3_KHZ 1 +#define RT5616_CP_FQ_6_KHZ 2 +#define RT5616_CP_FQ_12_KHZ 3 +#define RT5616_CP_FQ_24_KHZ 4 +#define RT5616_CP_FQ_48_KHZ 5 +#define RT5616_CP_FQ_96_KHZ 6 +#define RT5616_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump (0x91) */ +#define RT5616_OSW_L_MASK (0x1 << 11) +#define RT5616_OSW_L_SFT 11 +#define RT5616_OSW_L_DIS (0x0 << 11) +#define RT5616_OSW_L_EN (0x1 << 11) +#define RT5616_OSW_R_MASK (0x1 << 10) +#define RT5616_OSW_R_SFT 10 +#define RT5616_OSW_R_DIS (0x0 << 10) +#define RT5616_OSW_R_EN (0x1 << 10) +#define RT5616_PM_HP_MASK (0x3 << 8) +#define RT5616_PM_HP_SFT 8 +#define RT5616_PM_HP_LV (0x0 << 8) +#define RT5616_PM_HP_MV (0x1 << 8) +#define RT5616_PM_HP_HV (0x2 << 8) +#define RT5616_IB_HP_MASK (0x3 << 6) +#define RT5616_IB_HP_SFT 6 +#define RT5616_IB_HP_125IL (0x0 << 6) +#define RT5616_IB_HP_25IL (0x1 << 6) +#define RT5616_IB_HP_5IL (0x2 << 6) +#define RT5616_IB_HP_1IL (0x3 << 6) + +/* Micbias Control (0x93) */ +#define RT5616_MIC1_BS_MASK (0x1 << 15) +#define RT5616_MIC1_BS_SFT 15 +#define RT5616_MIC1_BS_9AV (0x0 << 15) +#define RT5616_MIC1_BS_75AV (0x1 << 15) +#define RT5616_MIC1_CLK_MASK (0x1 << 13) +#define RT5616_MIC1_CLK_SFT 13 +#define RT5616_MIC1_CLK_DIS (0x0 << 13) +#define RT5616_MIC1_CLK_EN (0x1 << 13) +#define RT5616_MIC1_OVCD_MASK (0x1 << 11) +#define RT5616_MIC1_OVCD_SFT 11 +#define RT5616_MIC1_OVCD_DIS (0x0 << 11) +#define RT5616_MIC1_OVCD_EN (0x1 << 11) +#define RT5616_MIC1_OVTH_MASK (0x3 << 9) +#define RT5616_MIC1_OVTH_SFT 9 +#define RT5616_MIC1_OVTH_600UA (0x0 << 9) +#define RT5616_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5616_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5616_PWR_MB_MASK (0x1 << 5) +#define RT5616_PWR_MB_SFT 5 +#define RT5616_PWR_MB_PD (0x0 << 5) +#define RT5616_PWR_MB_PU (0x1 << 5) +#define RT5616_PWR_CLK12M_MASK (0x1 << 4) +#define RT5616_PWR_CLK12M_SFT 4 +#define RT5616_PWR_CLK12M_PD (0x0 << 4) +#define RT5616_PWR_CLK12M_PU (0x1 << 4) + +/* Analog JD Control 1 (0x94) */ +#define RT5616_JD2_CMP_MASK (0x7 << 12) +#define RT5616_JD2_CMP_SFT 12 +#define RT5616_JD_PU (0x1 << 11) +#define RT5616_JD_PU_SFT 11 +#define RT5616_JD_PD (0x1 << 10) +#define RT5616_JD_PD_SFT 10 +#define RT5616_JD_MODE_SEL_MASK (0x3 << 8) +#define RT5616_JD_MODE_SEL_SFT 8 +#define RT5616_JD_MODE_SEL_M0 (0x0 << 8) +#define RT5616_JD_MODE_SEL_M1 (0x1 << 8) +#define RT5616_JD_MODE_SEL_M2 (0x2 << 8) +#define RT5616_JD_M_CMP (0x7 << 4) +#define RT5616_JD_M_CMP_SFT 4 +#define RT5616_JD_M_PU (0x1 << 3) +#define RT5616_JD_M_PU_SFT 3 +#define RT5616_JD_M_PD (0x1 << 2) +#define RT5616_JD_M_PD_SFT 2 +#define RT5616_JD_M_MODE_SEL_MASK (0x3) +#define RT5616_JD_M_MODE_SEL_SFT 0 +#define RT5616_JD_M_MODE_SEL_M0 (0x0) +#define RT5616_JD_M_MODE_SEL_M1 (0x1) +#define RT5616_JD_M_MODE_SEL_M2 (0x2) + +/* Analog JD Control 2 (0x95) */ +#define RT5616_JD3_CMP_MASK (0x7 << 12) +#define RT5616_JD3_CMP_SFT 12 + +/* EQ Control 1 (0xb0) */ +#define RT5616_EQ_SRC_MASK (0x1 << 15) +#define RT5616_EQ_SRC_SFT 15 +#define RT5616_EQ_SRC_DAC (0x0 << 15) +#define RT5616_EQ_SRC_ADC (0x1 << 15) +#define RT5616_EQ_UPD (0x1 << 14) +#define RT5616_EQ_UPD_BIT 14 +#define RT5616_EQ_CD_MASK (0x1 << 13) +#define RT5616_EQ_CD_SFT 13 +#define RT5616_EQ_CD_DIS (0x0 << 13) +#define RT5616_EQ_CD_EN (0x1 << 13) +#define RT5616_EQ_DITH_MASK (0x3 << 8) +#define RT5616_EQ_DITH_SFT 8 +#define RT5616_EQ_DITH_NOR (0x0 << 8) +#define RT5616_EQ_DITH_LSB (0x1 << 8) +#define RT5616_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5616_EQ_DITH_LSB_2 (0x3 << 8) +#define RT5616_EQ_CD_F (0x1 << 7) +#define RT5616_EQ_CD_F_BIT 7 +#define RT5616_EQ_STA_HP2 (0x1 << 6) +#define RT5616_EQ_STA_HP2_BIT 6 +#define RT5616_EQ_STA_HP1 (0x1 << 5) +#define RT5616_EQ_STA_HP1_BIT 5 +#define RT5616_EQ_STA_BP4 (0x1 << 4) +#define RT5616_EQ_STA_BP4_BIT 4 +#define RT5616_EQ_STA_BP3 (0x1 << 3) +#define RT5616_EQ_STA_BP3_BIT 3 +#define RT5616_EQ_STA_BP2 (0x1 << 2) +#define RT5616_EQ_STA_BP2_BIT 2 +#define RT5616_EQ_STA_BP1 (0x1 << 1) +#define RT5616_EQ_STA_BP1_BIT 1 +#define RT5616_EQ_STA_LP (0x1) +#define RT5616_EQ_STA_LP_BIT 0 + +/* EQ Control 2 (0xb1) */ +#define RT5616_EQ_HPF1_M_MASK (0x1 << 8) +#define RT5616_EQ_HPF1_M_SFT 8 +#define RT5616_EQ_HPF1_M_HI (0x0 << 8) +#define RT5616_EQ_HPF1_M_1ST (0x1 << 8) +#define RT5616_EQ_LPF1_M_MASK (0x1 << 7) +#define RT5616_EQ_LPF1_M_SFT 7 +#define RT5616_EQ_LPF1_M_LO (0x0 << 7) +#define RT5616_EQ_LPF1_M_1ST (0x1 << 7) +#define RT5616_EQ_HPF2_MASK (0x1 << 6) +#define RT5616_EQ_HPF2_SFT 6 +#define RT5616_EQ_HPF2_DIS (0x0 << 6) +#define RT5616_EQ_HPF2_EN (0x1 << 6) +#define RT5616_EQ_HPF1_MASK (0x1 << 5) +#define RT5616_EQ_HPF1_SFT 5 +#define RT5616_EQ_HPF1_DIS (0x0 << 5) +#define RT5616_EQ_HPF1_EN (0x1 << 5) +#define RT5616_EQ_BPF4_MASK (0x1 << 4) +#define RT5616_EQ_BPF4_SFT 4 +#define RT5616_EQ_BPF4_DIS (0x0 << 4) +#define RT5616_EQ_BPF4_EN (0x1 << 4) +#define RT5616_EQ_BPF3_MASK (0x1 << 3) +#define RT5616_EQ_BPF3_SFT 3 +#define RT5616_EQ_BPF3_DIS (0x0 << 3) +#define RT5616_EQ_BPF3_EN (0x1 << 3) +#define RT5616_EQ_BPF2_MASK (0x1 << 2) +#define RT5616_EQ_BPF2_SFT 2 +#define RT5616_EQ_BPF2_DIS (0x0 << 2) +#define RT5616_EQ_BPF2_EN (0x1 << 2) +#define RT5616_EQ_BPF1_MASK (0x1 << 1) +#define RT5616_EQ_BPF1_SFT 1 +#define RT5616_EQ_BPF1_DIS (0x0 << 1) +#define RT5616_EQ_BPF1_EN (0x1 << 1) +#define RT5616_EQ_LPF_MASK (0x1) +#define RT5616_EQ_LPF_SFT 0 +#define RT5616_EQ_LPF_DIS (0x0) +#define RT5616_EQ_LPF_EN (0x1) +#define RT5616_EQ_CTRL_MASK (0x7f) + +/* Memory Test (0xb2) */ +#define RT5616_MT_MASK (0x1 << 15) +#define RT5616_MT_SFT 15 +#define RT5616_MT_DIS (0x0 << 15) +#define RT5616_MT_EN (0x1 << 15) + +/* DRC/AGC Control 1 (0xb4) */ +#define RT5616_DRC_AGC_P_MASK (0x1 << 15) +#define RT5616_DRC_AGC_P_SFT 15 +#define RT5616_DRC_AGC_P_DAC (0x0 << 15) +#define RT5616_DRC_AGC_P_ADC (0x1 << 15) +#define RT5616_DRC_AGC_MASK (0x1 << 14) +#define RT5616_DRC_AGC_SFT 14 +#define RT5616_DRC_AGC_DIS (0x0 << 14) +#define RT5616_DRC_AGC_EN (0x1 << 14) +#define RT5616_DRC_AGC_UPD (0x1 << 13) +#define RT5616_DRC_AGC_UPD_BIT 13 +#define RT5616_DRC_AGC_AR_MASK (0x1f << 8) +#define RT5616_DRC_AGC_AR_SFT 8 +#define RT5616_DRC_AGC_R_MASK (0x7 << 5) +#define RT5616_DRC_AGC_R_SFT 5 +#define RT5616_DRC_AGC_R_48K (0x1 << 5) +#define RT5616_DRC_AGC_R_96K (0x2 << 5) +#define RT5616_DRC_AGC_R_192K (0x3 << 5) +#define RT5616_DRC_AGC_R_441K (0x5 << 5) +#define RT5616_DRC_AGC_R_882K (0x6 << 5) +#define RT5616_DRC_AGC_R_1764K (0x7 << 5) +#define RT5616_DRC_AGC_RC_MASK (0x1f) +#define RT5616_DRC_AGC_RC_SFT 0 + +/* DRC/AGC Control 2 (0xb5) */ +#define RT5616_DRC_AGC_POB_MASK (0x3f << 8) +#define RT5616_DRC_AGC_POB_SFT 8 +#define RT5616_DRC_AGC_CP_MASK (0x1 << 7) +#define RT5616_DRC_AGC_CP_SFT 7 +#define RT5616_DRC_AGC_CP_DIS (0x0 << 7) +#define RT5616_DRC_AGC_CP_EN (0x1 << 7) +#define RT5616_DRC_AGC_CPR_MASK (0x3 << 5) +#define RT5616_DRC_AGC_CPR_SFT 5 +#define RT5616_DRC_AGC_CPR_1_1 (0x0 << 5) +#define RT5616_DRC_AGC_CPR_1_2 (0x1 << 5) +#define RT5616_DRC_AGC_CPR_1_3 (0x2 << 5) +#define RT5616_DRC_AGC_CPR_1_4 (0x3 << 5) +#define RT5616_DRC_AGC_PRB_MASK (0x1f) +#define RT5616_DRC_AGC_PRB_SFT 0 + +/* DRC/AGC Control 3 (0xb6) */ +#define RT5616_DRC_AGC_NGB_MASK (0xf << 12) +#define RT5616_DRC_AGC_NGB_SFT 12 +#define RT5616_DRC_AGC_TAR_MASK (0x1f << 7) +#define RT5616_DRC_AGC_TAR_SFT 7 +#define RT5616_DRC_AGC_NG_MASK (0x1 << 6) +#define RT5616_DRC_AGC_NG_SFT 6 +#define RT5616_DRC_AGC_NG_DIS (0x0 << 6) +#define RT5616_DRC_AGC_NG_EN (0x1 << 6) +#define RT5616_DRC_AGC_NGH_MASK (0x1 << 5) +#define RT5616_DRC_AGC_NGH_SFT 5 +#define RT5616_DRC_AGC_NGH_DIS (0x0 << 5) +#define RT5616_DRC_AGC_NGH_EN (0x1 << 5) +#define RT5616_DRC_AGC_NGT_MASK (0x1f) +#define RT5616_DRC_AGC_NGT_SFT 0 + +/* Jack Detect Control 1 (0xbb) */ +#define RT5616_JD_MASK (0x7 << 13) +#define RT5616_JD_SFT 13 +#define RT5616_JD_DIS (0x0 << 13) +#define RT5616_JD_GPIO1 (0x1 << 13) +#define RT5616_JD_GPIO2 (0x2 << 13) +#define RT5616_JD_GPIO3 (0x3 << 13) +#define RT5616_JD_GPIO4 (0x4 << 13) +#define RT5616_JD_GPIO5 (0x5 << 13) +#define RT5616_JD_GPIO6 (0x6 << 13) +#define RT5616_JD_HP_MASK (0x1 << 11) +#define RT5616_JD_HP_SFT 11 +#define RT5616_JD_HP_DIS (0x0 << 11) +#define RT5616_JD_HP_EN (0x1 << 11) +#define RT5616_JD_HP_TRG_MASK (0x1 << 10) +#define RT5616_JD_HP_TRG_SFT 10 +#define RT5616_JD_HP_TRG_LO (0x0 << 10) +#define RT5616_JD_HP_TRG_HI (0x1 << 10) +#define RT5616_JD_SPL_MASK (0x1 << 9) +#define RT5616_JD_SPL_SFT 9 +#define RT5616_JD_SPL_DIS (0x0 << 9) +#define RT5616_JD_SPL_EN (0x1 << 9) +#define RT5616_JD_SPL_TRG_MASK (0x1 << 8) +#define RT5616_JD_SPL_TRG_SFT 8 +#define RT5616_JD_SPL_TRG_LO (0x0 << 8) +#define RT5616_JD_SPL_TRG_HI (0x1 << 8) +#define RT5616_JD_SPR_MASK (0x1 << 7) +#define RT5616_JD_SPR_SFT 7 +#define RT5616_JD_SPR_DIS (0x0 << 7) +#define RT5616_JD_SPR_EN (0x1 << 7) +#define RT5616_JD_SPR_TRG_MASK (0x1 << 6) +#define RT5616_JD_SPR_TRG_SFT 6 +#define RT5616_JD_SPR_TRG_LO (0x0 << 6) +#define RT5616_JD_SPR_TRG_HI (0x1 << 6) +#define RT5616_JD_LO_MASK (0x1 << 3) +#define RT5616_JD_LO_SFT 3 +#define RT5616_JD_LO_DIS (0x0 << 3) +#define RT5616_JD_LO_EN (0x1 << 3) +#define RT5616_JD_LO_TRG_MASK (0x1 << 2) +#define RT5616_JD_LO_TRG_SFT 2 +#define RT5616_JD_LO_TRG_LO (0x0 << 2) +#define RT5616_JD_LO_TRG_HI (0x1 << 2) + +/* Jack Detect Control 2 (0xbc) */ +#define RT5616_JD_TRG_SEL_MASK (0x7 << 9) +#define RT5616_JD_TRG_SEL_SFT 9 +#define RT5616_JD_TRG_SEL_GPIO (0x0 << 9) +#define RT5616_JD_TRG_SEL_JD1_1 (0x1 << 9) +#define RT5616_JD_TRG_SEL_JD1_2 (0x2 << 9) +#define RT5616_JD_TRG_SEL_JD2 (0x3 << 9) +#define RT5616_JD_TRG_SEL_JD3 (0x4 << 9) +#define RT5616_JD3_IRQ_EN (0x1 << 8) +#define RT5616_JD3_IRQ_EN_SFT 8 +#define RT5616_JD3_EN_STKY (0x1 << 7) +#define RT5616_JD3_EN_STKY_SFT 7 +#define RT5616_JD3_INV (0x1 << 6) +#define RT5616_JD3_INV_SFT 6 + +/* IRQ Control 1 (0xbd) */ +#define RT5616_IRQ_JD_MASK (0x1 << 15) +#define RT5616_IRQ_JD_SFT 15 +#define RT5616_IRQ_JD_BP (0x0 << 15) +#define RT5616_IRQ_JD_NOR (0x1 << 15) +#define RT5616_JD_STKY_MASK (0x1 << 13) +#define RT5616_JD_STKY_SFT 13 +#define RT5616_JD_STKY_DIS (0x0 << 13) +#define RT5616_JD_STKY_EN (0x1 << 13) +#define RT5616_JD_P_MASK (0x1 << 11) +#define RT5616_JD_P_SFT 11 +#define RT5616_JD_P_NOR (0x0 << 11) +#define RT5616_JD_P_INV (0x1 << 11) +#define RT5616_JD1_1_IRQ_EN (0x1 << 9) +#define RT5616_JD1_1_IRQ_EN_SFT 9 +#define RT5616_JD1_1_EN_STKY (0x1 << 8) +#define RT5616_JD1_1_EN_STKY_SFT 8 +#define RT5616_JD1_1_INV (0x1 << 7) +#define RT5616_JD1_1_INV_SFT 7 +#define RT5616_JD1_2_IRQ_EN (0x1 << 6) +#define RT5616_JD1_2_IRQ_EN_SFT 6 +#define RT5616_JD1_2_EN_STKY (0x1 << 5) +#define RT5616_JD1_2_EN_STKY_SFT 5 +#define RT5616_JD1_2_INV (0x1 << 4) +#define RT5616_JD1_2_INV_SFT 4 +#define RT5616_JD2_IRQ_EN (0x1 << 3) +#define RT5616_JD2_IRQ_EN_SFT 3 +#define RT5616_JD2_EN_STKY (0x1 << 2) +#define RT5616_JD2_EN_STKY_SFT 2 +#define RT5616_JD2_INV (0x1 << 1) +#define RT5616_JD2_INV_SFT 1 + +/* IRQ Control 2 (0xbe) */ +#define RT5616_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5616_IRQ_MB1_OC_SFT 15 +#define RT5616_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5616_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5616_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5616_MB1_OC_STKY_SFT 11 +#define RT5616_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5616_MB1_OC_STKY_EN (0x1 << 11) +#define RT5616_MB1_OC_P_MASK (0x1 << 7) +#define RT5616_MB1_OC_P_SFT 7 +#define RT5616_MB1_OC_P_NOR (0x0 << 7) +#define RT5616_MB1_OC_P_INV (0x1 << 7) +#define RT5616_MB2_OC_P_MASK (0x1 << 6) +#define RT5616_MB1_OC_CLR (0x1 << 3) +#define RT5616_MB1_OC_CLR_SFT 3 +#define RT5616_STA_GPIO8 (0x1) +#define RT5616_STA_GPIO8_BIT 0 + +/* Internal Status and GPIO status (0xbf) */ +#define RT5616_STA_JD3 (0x1 << 15) +#define RT5616_STA_JD3_BIT 15 +#define RT5616_STA_JD2 (0x1 << 14) +#define RT5616_STA_JD2_BIT 14 +#define RT5616_STA_JD1_2 (0x1 << 13) +#define RT5616_STA_JD1_2_BIT 13 +#define RT5616_STA_JD1_1 (0x1 << 12) +#define RT5616_STA_JD1_1_BIT 12 +#define RT5616_STA_GP7 (0x1 << 11) +#define RT5616_STA_GP7_BIT 11 +#define RT5616_STA_GP6 (0x1 << 10) +#define RT5616_STA_GP6_BIT 10 +#define RT5616_STA_GP5 (0x1 << 9) +#define RT5616_STA_GP5_BIT 9 +#define RT5616_STA_GP1 (0x1 << 8) +#define RT5616_STA_GP1_BIT 8 +#define RT5616_STA_GP2 (0x1 << 7) +#define RT5616_STA_GP2_BIT 7 +#define RT5616_STA_GP3 (0x1 << 6) +#define RT5616_STA_GP3_BIT 6 +#define RT5616_STA_GP4 (0x1 << 5) +#define RT5616_STA_GP4_BIT 5 +#define RT5616_STA_GP_JD (0x1 << 4) +#define RT5616_STA_GP_JD_BIT 4 + +/* GPIO Control 1 (0xc0) */ +#define RT5616_GP1_PIN_MASK (0x1 << 15) +#define RT5616_GP1_PIN_SFT 15 +#define RT5616_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5616_GP1_PIN_IRQ (0x1 << 15) +#define RT5616_GP2_PIN_MASK (0x1 << 14) +#define RT5616_GP2_PIN_SFT 14 +#define RT5616_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5616_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5616_GPIO_M_MASK (0x1 << 9) +#define RT5616_GPIO_M_SFT 9 +#define RT5616_GPIO_M_FLT (0x0 << 9) +#define RT5616_GPIO_M_PH (0x1 << 9) +#define RT5616_I2S2_SEL_MASK (0x1 << 8) +#define RT5616_I2S2_SEL_SFT 8 +#define RT5616_I2S2_SEL_I2S (0x0 << 8) +#define RT5616_I2S2_SEL_GPIO (0x1 << 8) +#define RT5616_GP5_PIN_MASK (0x1 << 7) +#define RT5616_GP5_PIN_SFT 7 +#define RT5616_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5616_GP5_PIN_IRQ (0x1 << 7) +#define RT5616_GP6_PIN_MASK (0x1 << 6) +#define RT5616_GP6_PIN_SFT 6 +#define RT5616_GP6_PIN_GPIO6 (0x0 << 6) +#define RT5616_GP6_PIN_DMIC_SDA (0x1 << 6) +#define RT5616_GP7_PIN_MASK (0x1 << 5) +#define RT5616_GP7_PIN_SFT 5 +#define RT5616_GP7_PIN_GPIO7 (0x0 << 5) +#define RT5616_GP7_PIN_IRQ (0x1 << 5) +#define RT5616_GP8_PIN_MASK (0x1 << 4) +#define RT5616_GP8_PIN_SFT 4 +#define RT5616_GP8_PIN_GPIO8 (0x0 << 4) +#define RT5616_GP8_PIN_DMIC_SDA (0x1 << 4) +#define RT5616_GPIO_PDM_SEL_MASK (0x1 << 3) +#define RT5616_GPIO_PDM_SEL_SFT 3 +#define RT5616_GPIO_PDM_SEL_GPIO (0x0 << 3) +#define RT5616_GPIO_PDM_SEL_PDM (0x1 << 3) + +/* GPIO Control 2 (0xc1) */ +#define RT5616_GP5_DR_MASK (0x1 << 14) +#define RT5616_GP5_DR_SFT 14 +#define RT5616_GP5_DR_IN (0x0 << 14) +#define RT5616_GP5_DR_OUT (0x1 << 14) +#define RT5616_GP5_OUT_MASK (0x1 << 13) +#define RT5616_GP5_OUT_SFT 13 +#define RT5616_GP5_OUT_LO (0x0 << 13) +#define RT5616_GP5_OUT_HI (0x1 << 13) +#define RT5616_GP5_P_MASK (0x1 << 12) +#define RT5616_GP5_P_SFT 12 +#define RT5616_GP5_P_NOR (0x0 << 12) +#define RT5616_GP5_P_INV (0x1 << 12) +#define RT5616_GP4_DR_MASK (0x1 << 11) +#define RT5616_GP4_DR_SFT 11 +#define RT5616_GP4_DR_IN (0x0 << 11) +#define RT5616_GP4_DR_OUT (0x1 << 11) +#define RT5616_GP4_OUT_MASK (0x1 << 10) +#define RT5616_GP4_OUT_SFT 10 +#define RT5616_GP4_OUT_LO (0x0 << 10) +#define RT5616_GP4_OUT_HI (0x1 << 10) +#define RT5616_GP4_P_MASK (0x1 << 9) +#define RT5616_GP4_P_SFT 9 +#define RT5616_GP4_P_NOR (0x0 << 9) +#define RT5616_GP4_P_INV (0x1 << 9) +#define RT5616_GP3_DR_MASK (0x1 << 8) +#define RT5616_GP3_DR_SFT 8 +#define RT5616_GP3_DR_IN (0x0 << 8) +#define RT5616_GP3_DR_OUT (0x1 << 8) +#define RT5616_GP3_OUT_MASK (0x1 << 7) +#define RT5616_GP3_OUT_SFT 7 +#define RT5616_GP3_OUT_LO (0x0 << 7) +#define RT5616_GP3_OUT_HI (0x1 << 7) +#define RT5616_GP3_P_MASK (0x1 << 6) +#define RT5616_GP3_P_SFT 6 +#define RT5616_GP3_P_NOR (0x0 << 6) +#define RT5616_GP3_P_INV (0x1 << 6) +#define RT5616_GP2_DR_MASK (0x1 << 5) +#define RT5616_GP2_DR_SFT 5 +#define RT5616_GP2_DR_IN (0x0 << 5) +#define RT5616_GP2_DR_OUT (0x1 << 5) +#define RT5616_GP2_OUT_MASK (0x1 << 4) +#define RT5616_GP2_OUT_SFT 4 +#define RT5616_GP2_OUT_LO (0x0 << 4) +#define RT5616_GP2_OUT_HI (0x1 << 4) +#define RT5616_GP2_P_MASK (0x1 << 3) +#define RT5616_GP2_P_SFT 3 +#define RT5616_GP2_P_NOR (0x0 << 3) +#define RT5616_GP2_P_INV (0x1 << 3) +#define RT5616_GP1_DR_MASK (0x1 << 2) +#define RT5616_GP1_DR_SFT 2 +#define RT5616_GP1_DR_IN (0x0 << 2) +#define RT5616_GP1_DR_OUT (0x1 << 2) +#define RT5616_GP1_OUT_MASK (0x1 << 1) +#define RT5616_GP1_OUT_SFT 1 +#define RT5616_GP1_OUT_LO (0x0 << 1) +#define RT5616_GP1_OUT_HI (0x1 << 1) +#define RT5616_GP1_P_MASK (0x1) +#define RT5616_GP1_P_SFT 0 +#define RT5616_GP1_P_NOR (0x0) +#define RT5616_GP1_P_INV (0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5616_GP8_DR_MASK (0x1 << 8) +#define RT5616_GP8_DR_SFT 8 +#define RT5616_GP8_DR_IN (0x0 << 8) +#define RT5616_GP8_DR_OUT (0x1 << 8) +#define RT5616_GP8_OUT_MASK (0x1 << 7) +#define RT5616_GP8_OUT_SFT 7 +#define RT5616_GP8_OUT_LO (0x0 << 7) +#define RT5616_GP8_OUT_HI (0x1 << 7) +#define RT5616_GP8_P_MASK (0x1 << 6) +#define RT5616_GP8_P_SFT 6 +#define RT5616_GP8_P_NOR (0x0 << 6) +#define RT5616_GP8_P_INV (0x1 << 6) +#define RT5616_GP7_DR_MASK (0x1 << 5) +#define RT5616_GP7_DR_SFT 5 +#define RT5616_GP7_DR_IN (0x0 << 5) +#define RT5616_GP7_DR_OUT (0x1 << 5) +#define RT5616_GP7_OUT_MASK (0x1 << 4) +#define RT5616_GP7_OUT_SFT 4 +#define RT5616_GP7_OUT_LO (0x0 << 4) +#define RT5616_GP7_OUT_HI (0x1 << 4) +#define RT5616_GP7_P_MASK (0x1 << 3) +#define RT5616_GP7_P_SFT 3 +#define RT5616_GP7_P_NOR (0x0 << 3) +#define RT5616_GP7_P_INV (0x1 << 3) +#define RT5616_GP6_DR_MASK (0x1 << 2) +#define RT5616_GP6_DR_SFT 2 +#define RT5616_GP6_DR_IN (0x0 << 2) +#define RT5616_GP6_DR_OUT (0x1 << 2) +#define RT5616_GP6_OUT_MASK (0x1 << 1) +#define RT5616_GP6_OUT_SFT 1 +#define RT5616_GP6_OUT_LO (0x0 << 1) +#define RT5616_GP6_OUT_HI (0x1 << 1) +#define RT5616_GP6_P_MASK (0x1) +#define RT5616_GP6_P_SFT 0 +#define RT5616_GP6_P_NOR (0x0) +#define RT5616_GP6_P_INV (0x1) + +/* Scramble Control (0xce) */ +#define RT5616_SCB_SWAP_MASK (0x1 << 15) +#define RT5616_SCB_SWAP_SFT 15 +#define RT5616_SCB_SWAP_DIS (0x0 << 15) +#define RT5616_SCB_SWAP_EN (0x1 << 15) +#define RT5616_SCB_MASK (0x1 << 14) +#define RT5616_SCB_SFT 14 +#define RT5616_SCB_DIS (0x0 << 14) +#define RT5616_SCB_EN (0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5616_BB_MASK (0x1 << 15) +#define RT5616_BB_SFT 15 +#define RT5616_BB_DIS (0x0 << 15) +#define RT5616_BB_EN (0x1 << 15) +#define RT5616_BB_CT_MASK (0x7 << 12) +#define RT5616_BB_CT_SFT 12 +#define RT5616_BB_CT_A (0x0 << 12) +#define RT5616_BB_CT_B (0x1 << 12) +#define RT5616_BB_CT_C (0x2 << 12) +#define RT5616_BB_CT_D (0x3 << 12) +#define RT5616_M_BB_L_MASK (0x1 << 9) +#define RT5616_M_BB_L_SFT 9 +#define RT5616_M_BB_R_MASK (0x1 << 8) +#define RT5616_M_BB_R_SFT 8 +#define RT5616_M_BB_HPF_L_MASK (0x1 << 7) +#define RT5616_M_BB_HPF_L_SFT 7 +#define RT5616_M_BB_HPF_R_MASK (0x1 << 6) +#define RT5616_M_BB_HPF_R_SFT 6 +#define RT5616_G_BB_BST_MASK (0x3f) +#define RT5616_G_BB_BST_SFT 0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5616_M_MP3_L_MASK (0x1 << 15) +#define RT5616_M_MP3_L_SFT 15 +#define RT5616_M_MP3_R_MASK (0x1 << 14) +#define RT5616_M_MP3_R_SFT 14 +#define RT5616_M_MP3_MASK (0x1 << 13) +#define RT5616_M_MP3_SFT 13 +#define RT5616_M_MP3_DIS (0x0 << 13) +#define RT5616_M_MP3_EN (0x1 << 13) +#define RT5616_EG_MP3_MASK (0x1f << 8) +#define RT5616_EG_MP3_SFT 8 +#define RT5616_MP3_HLP_MASK (0x1 << 7) +#define RT5616_MP3_HLP_SFT 7 +#define RT5616_MP3_HLP_DIS (0x0 << 7) +#define RT5616_MP3_HLP_EN (0x1 << 7) +#define RT5616_M_MP3_ORG_L_MASK (0x1 << 6) +#define RT5616_M_MP3_ORG_L_SFT 6 +#define RT5616_M_MP3_ORG_R_MASK (0x1 << 5) +#define RT5616_M_MP3_ORG_R_SFT 5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5616_MP3_WT_MASK (0x1 << 13) +#define RT5616_MP3_WT_SFT 13 +#define RT5616_MP3_WT_1_4 (0x0 << 13) +#define RT5616_MP3_WT_1_2 (0x1 << 13) +#define RT5616_OG_MP3_MASK (0x1f << 8) +#define RT5616_OG_MP3_SFT 8 +#define RT5616_HG_MP3_MASK (0x3f) +#define RT5616_HG_MP3_SFT 0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5616_3D_CF_MASK (0x1 << 15) +#define RT5616_3D_CF_SFT 15 +#define RT5616_3D_CF_DIS (0x0 << 15) +#define RT5616_3D_CF_EN (0x1 << 15) +#define RT5616_3D_HP_MASK (0x1 << 14) +#define RT5616_3D_HP_SFT 14 +#define RT5616_3D_HP_DIS (0x0 << 14) +#define RT5616_3D_HP_EN (0x1 << 14) +#define RT5616_3D_BT_MASK (0x1 << 13) +#define RT5616_3D_BT_SFT 13 +#define RT5616_3D_BT_DIS (0x0 << 13) +#define RT5616_3D_BT_EN (0x1 << 13) +#define RT5616_3D_1F_MIX_MASK (0x3 << 11) +#define RT5616_3D_1F_MIX_SFT 11 +#define RT5616_3D_HP_M_MASK (0x1 << 10) +#define RT5616_3D_HP_M_SFT 10 +#define RT5616_3D_HP_M_SUR (0x0 << 10) +#define RT5616_3D_HP_M_FRO (0x1 << 10) +#define RT5616_M_3D_HRTF_MASK (0x1 << 9) +#define RT5616_M_3D_HRTF_SFT 9 +#define RT5616_M_3D_D2H_MASK (0x1 << 8) +#define RT5616_M_3D_D2H_SFT 8 +#define RT5616_M_3D_D2R_MASK (0x1 << 7) +#define RT5616_M_3D_D2R_SFT 7 +#define RT5616_M_3D_REVB_MASK (0x1 << 6) +#define RT5616_M_3D_REVB_SFT 6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5616_2ND_HPF_MASK (0x1 << 15) +#define RT5616_2ND_HPF_SFT 15 +#define RT5616_2ND_HPF_DIS (0x0 << 15) +#define RT5616_2ND_HPF_EN (0x1 << 15) +#define RT5616_HPF_CF_L_MASK (0x7 << 12) +#define RT5616_HPF_CF_L_SFT 12 +#define RT5616_HPF_CF_R_MASK (0x7 << 8) +#define RT5616_HPF_CF_R_SFT 8 +#define RT5616_ZD_T_MASK (0x3 << 6) +#define RT5616_ZD_T_SFT 6 +#define RT5616_ZD_F_MASK (0x3 << 4) +#define RT5616_ZD_F_SFT 4 +#define RT5616_ZD_F_IM (0x0 << 4) +#define RT5616_ZD_F_ZC_IM (0x1 << 4) +#define RT5616_ZD_F_ZC_IOD (0x2 << 4) +#define RT5616_ZD_F_UN (0x3 << 4) + +/* Adjustable high pass filter control 2 (0xd4) */ +#define RT5616_HPF_CF_L_NUM_MASK (0x3f << 8) +#define RT5616_HPF_CF_L_NUM_SFT 8 +#define RT5616_HPF_CF_R_NUM_MASK (0x3f) +#define RT5616_HPF_CF_R_NUM_SFT 0 + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5616_SI_DAC_MASK (0x1 << 11) +#define RT5616_SI_DAC_SFT 11 +#define RT5616_SI_DAC_AUTO (0x0 << 11) +#define RT5616_SI_DAC_TEST (0x1 << 11) +#define RT5616_DC_CAL_M_MASK (0x1 << 10) +#define RT5616_DC_CAL_M_SFT 10 +#define RT5616_DC_CAL_M_NOR (0x0 << 10) +#define RT5616_DC_CAL_M_CAL (0x1 << 10) +#define RT5616_DC_CAL_MASK (0x1 << 9) +#define RT5616_DC_CAL_SFT 9 +#define RT5616_DC_CAL_DIS (0x0 << 9) +#define RT5616_DC_CAL_EN (0x1 << 9) +#define RT5616_HPD_RCV_MASK (0x7 << 6) +#define RT5616_HPD_RCV_SFT 6 +#define RT5616_HPD_PS_MASK (0x1 << 5) +#define RT5616_HPD_PS_SFT 5 +#define RT5616_HPD_PS_DIS (0x0 << 5) +#define RT5616_HPD_PS_EN (0x1 << 5) +#define RT5616_CAL_M_MASK (0x1 << 4) +#define RT5616_CAL_M_SFT 4 +#define RT5616_CAL_M_DEP (0x0 << 4) +#define RT5616_CAL_M_CAL (0x1 << 4) +#define RT5616_CAL_MASK (0x1 << 3) +#define RT5616_CAL_SFT 3 +#define RT5616_CAL_DIS (0x0 << 3) +#define RT5616_CAL_EN (0x1 << 3) +#define RT5616_CAL_TEST_MASK (0x1 << 2) +#define RT5616_CAL_TEST_SFT 2 +#define RT5616_CAL_TEST_DIS (0x0 << 2) +#define RT5616_CAL_TEST_EN (0x1 << 2) +#define RT5616_CAL_P_MASK (0x3) +#define RT5616_CAL_P_SFT 0 +#define RT5616_CAL_P_NONE (0x0) +#define RT5616_CAL_P_CAL (0x1) +#define RT5616_CAL_P_DAC_CAL (0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5616_SV_MASK (0x1 << 15) +#define RT5616_SV_SFT 15 +#define RT5616_SV_DIS (0x0 << 15) +#define RT5616_SV_EN (0x1 << 15) +#define RT5616_OUT_SV_MASK (0x1 << 13) +#define RT5616_OUT_SV_SFT 13 +#define RT5616_OUT_SV_DIS (0x0 << 13) +#define RT5616_OUT_SV_EN (0x1 << 13) +#define RT5616_HP_SV_MASK (0x1 << 12) +#define RT5616_HP_SV_SFT 12 +#define RT5616_HP_SV_DIS (0x0 << 12) +#define RT5616_HP_SV_EN (0x1 << 12) +#define RT5616_ZCD_DIG_MASK (0x1 << 11) +#define RT5616_ZCD_DIG_SFT 11 +#define RT5616_ZCD_DIG_DIS (0x0 << 11) +#define RT5616_ZCD_DIG_EN (0x1 << 11) +#define RT5616_ZCD_MASK (0x1 << 10) +#define RT5616_ZCD_SFT 10 +#define RT5616_ZCD_PD (0x0 << 10) +#define RT5616_ZCD_PU (0x1 << 10) +#define RT5616_M_ZCD_MASK (0x3f << 4) +#define RT5616_M_ZCD_SFT 4 +#define RT5616_M_ZCD_OM_L (0x1 << 7) +#define RT5616_M_ZCD_OM_R (0x1 << 6) +#define RT5616_M_ZCD_RM_L (0x1 << 5) +#define RT5616_M_ZCD_RM_R (0x1 << 4) +#define RT5616_SV_DLY_MASK (0xf) +#define RT5616_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5616_ZCD_HP_MASK (0x1 << 15) +#define RT5616_ZCD_HP_SFT 15 +#define RT5616_ZCD_HP_DIS (0x0 << 15) +#define RT5616_ZCD_HP_EN (0x1 << 15) + +/* Digital Misc Control (0xfa) */ +#define RT5616_I2S2_MS_SP_MASK (0x1 << 8) +#define RT5616_I2S2_MS_SP_SEL 8 +#define RT5616_I2S2_MS_SP_64 (0x0 << 8) +#define RT5616_I2S2_MS_SP_50 (0x1 << 8) +#define RT5616_CLK_DET_EN (0x1 << 3) +#define RT5616_CLK_DET_EN_SFT 3 +#define RT5616_AMP_DET_EN (0x1 << 1) +#define RT5616_AMP_DET_EN_SFT 1 +#define RT5616_D_GATE_EN (0x1) +#define RT5616_D_GATE_EN_SFT 0 + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5616_3D_SPK_MASK (0x1 << 15) +#define RT5616_3D_SPK_SFT 15 +#define RT5616_3D_SPK_DIS (0x0 << 15) +#define RT5616_3D_SPK_EN (0x1 << 15) +#define RT5616_3D_SPK_M_MASK (0x3 << 13) +#define RT5616_3D_SPK_M_SFT 13 +#define RT5616_3D_SPK_CG_MASK (0x1f << 8) +#define RT5616_3D_SPK_CG_SFT 8 +#define RT5616_3D_SPK_SG_MASK (0x1f) +#define RT5616_3D_SPK_SG_SFT 0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5616_WND_MASK (0x1 << 15) +#define RT5616_WND_SFT 15 +#define RT5616_WND_DIS (0x0 << 15) +#define RT5616_WND_EN (0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5616_WND_FC_NW_MASK (0x3f << 10) +#define RT5616_WND_FC_NW_SFT 10 +#define RT5616_WND_FC_WK_MASK (0x3f << 4) +#define RT5616_WND_FC_WK_SFT 4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5616_HPF_FC_MASK (0x3f << 6) +#define RT5616_HPF_FC_SFT 6 +#define RT5616_WND_FC_ST_MASK (0x3f) +#define RT5616_WND_FC_ST_SFT 0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5616_WND_TH_LO_MASK (0x3ff) +#define RT5616_WND_TH_LO_SFT 0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5616_WND_TH_HI_MASK (0x3ff) +#define RT5616_WND_TH_HI_SFT 0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5616_WND_WIND_MASK (0x1 << 13) /* Read-Only */ +#define RT5616_WND_WIND_SFT 13 +#define RT5616_WND_STRONG_MASK (0x1 << 12) /* Read-Only */ +#define RT5616_WND_STRONG_SFT 12 +enum { + RT5616_NO_WIND, + RT5616_BREEZE, + RT5616_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5616_DP_ATT_MASK (0x3 << 14) +#define RT5616_DP_ATT_SFT 14 +#define RT5616_DP_SPK_MASK (0x1 << 10) +#define RT5616_DP_SPK_SFT 10 +#define RT5616_DP_SPK_DIS (0x0 << 10) +#define RT5616_DP_SPK_EN (0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5616_EQ_PRE_VOL_MASK (0xffff) +#define RT5616_EQ_PRE_VOL_SFT 0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5616_EQ_PST_VOL_MASK (0xffff) +#define RT5616_EQ_PST_VOL_SFT 0 + +/* System Clock Source */ +enum { + RT5616_SCLK_S_MCLK, + RT5616_SCLK_S_PLL1, +}; + +/* PLL1 Source */ +enum { + RT5616_PLL1_S_MCLK, + RT5616_PLL1_S_BCLK1, + RT5616_PLL1_S_BCLK2, +}; + +enum { + RT5616_AIF1, + RT5616_AIFS, +}; + +#endif /* __RT5616_H__ */ -- cgit v1.2.3 From 46325371b230cc66c743925c930a17e7d0b8211e Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 19 Dec 2015 15:23:13 +0100 Subject: ALSA: oss: consolidate kmalloc/memset 0 call to kzalloc This is an API consolidation only. The use of kmalloc + memset to 0 is equivalent to kzalloc. Signed-off-by: Nicholas Mc Guire Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e557dbe469f4..0e73d03b30e3 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -851,7 +851,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -EINTR; - sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); + sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); if (!sw_params || !params || !sparams) { @@ -989,7 +989,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) goto failure; } - memset(sw_params, 0, sizeof(*sw_params)); if (runtime->oss.trigger) { sw_params->start_threshold = 1; } else { -- cgit v1.2.3 From e97e98c63b43040732ad5d1f0b38ad4a8371c73a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Dec 2015 21:14:10 +0200 Subject: ALSA: fm801: explicitly free IRQ line Otherwise we will have a warning on ->remove() since device is a PCI one. WARNING: CPU: 4 PID: 1411 at /home/andy/prj/linux/fs/proc/generic.c:575 remove_proc_entry+0x137/0x160() remove_proc_entry: removing non-empty directory 'irq/21', leaking at least 'snd_fm801' Fixes: 5618955c4269 (ALSA: fm801: move to pcim_* and devm_* functions) Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 1fdd92b6f18f..f57847cc53c1 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1165,6 +1165,8 @@ static int snd_fm801_free(struct fm801 *chip) cmdw |= 0x00c3; fm801_writew(chip, IRQ_MASK, cmdw); + devm_free_irq(&chip->pci->dev, chip->irq, chip); + __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL if (!(chip->tea575x_tuner & TUNER_DISABLED)) { -- cgit v1.2.3 From 4b5c15f746db70efc710369f62c6e1d323e20fb9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Dec 2015 21:14:11 +0200 Subject: ALSA: fm801: convert rest outw() / inw() to use helpers The patch introduces two new helpers fm801_iowrite16() and fm801_ioread16() to write and read the registers by offset. Previously similar was done to access the hardware registers by their names. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index f57847cc53c1..c2afb41907bd 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -212,6 +212,20 @@ struct fm801 { #endif }; +/* + * IO accessors + */ + +static inline void fm801_iowrite16(struct fm801 *chip, unsigned short offset, u16 value) +{ + outw(value, chip->port + offset); +} + +static inline u16 fm801_ioread16(struct fm801 *chip, unsigned short offset) +{ + return inw(chip->port + offset); +} + static const struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ @@ -256,11 +270,11 @@ static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg, unsigned short old, new; spin_lock_irqsave(&chip->reg_lock, flags); - old = inw(chip->port + reg); + old = fm801_ioread16(chip, reg); new = (old & ~mask) | value; change = old != new; if (change) - outw(new, chip->port + reg); + fm801_iowrite16(chip, reg, new); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -851,10 +865,11 @@ static int snd_fm801_get_single(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; + long *value = ucontrol->value.integer.value; - ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift) & mask; + value[0] = (fm801_ioread16(chip, reg) >> shift) & mask; if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + value[0] = mask - value[0]; return 0; } @@ -907,14 +922,15 @@ static int snd_fm801_get_double(struct snd_kcontrol *kcontrol, int shift_right = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; + long *value = ucontrol->value.integer.value; spin_lock_irq(&chip->reg_lock); - ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift_left) & mask; - ucontrol->value.integer.value[1] = (inw(chip->port + reg) >> shift_right) & mask; + value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask; + value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask; spin_unlock_irq(&chip->reg_lock); if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; + value[0] = mask - value[0]; + value[1] = mask - value[1]; } return 0; } @@ -1372,7 +1388,7 @@ static int snd_fm801_suspend(struct device *dev) snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) - chip->saved_regs[i] = inw(chip->port + saved_regs[i]); + chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]); /* FIXME: tea575x suspend */ return 0; } @@ -1387,7 +1403,7 @@ static int snd_fm801_resume(struct device *dev) snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) - outw(chip->saved_regs[i], chip->port + saved_regs[i]); + fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; -- cgit v1.2.3 From 997c87dad2a322516db391c7df440bd89e18fc31 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Dec 2015 21:14:12 +0200 Subject: ALSA: fm801: put curly braces around empty if-body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compiler complains on unused condition as follows sound/pci/fm801.c: In function ‘snd_fm801_interrupt’: sound/pci/fm801.c:585:3: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] Put the curly braces around empty body as suggested. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c2afb41907bd..c24cb04895b8 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -592,8 +592,9 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) } if (chip->rmidi && (status & FM801_IRQ_MPU)) snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); - if (status & FM801_IRQ_VOLUME) - ;/* TODO */ + if (status & FM801_IRQ_VOLUME) { + /* TODO */ + } return IRQ_HANDLED; } -- cgit v1.2.3 From d3d33aabac51341065bcce0e9c2d9d27902a08c4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Dec 2015 21:14:13 +0200 Subject: ALSA: fm801: store struct device instead of pci_dev There is no need to store struct pci_dev in struct fm801. Generic struct device can be easily translated to struct pci_dev whenever it's needed, in particular for one user for now. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c24cb04895b8..e4e610c5d1ba 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -163,6 +163,7 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers"); * @cap_ctrl: capture control */ struct fm801 { + struct device *dev; int irq; unsigned long port; @@ -190,7 +191,6 @@ struct fm801 { struct snd_ac97 *ac97; struct snd_ac97 *ac97_sec; - struct pci_dev *pci; struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; @@ -715,6 +715,7 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { static int snd_fm801_pcm(struct fm801 *chip, int device) { + struct pci_dev *pdev = to_pci_dev(chip->dev); struct snd_pcm *pcm; int err; @@ -730,7 +731,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + snd_dma_pci_data(pdev), chip->multichannel ? 128*1024 : 64*1024, 128*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -1182,7 +1183,7 @@ static int snd_fm801_free(struct fm801 *chip) cmdw |= 0x00c3; fm801_writew(chip, IRQ_MASK, cmdw); - devm_free_irq(&chip->pci->dev, chip->irq, chip); + devm_free_irq(chip->dev, chip->irq, chip); __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL @@ -1220,7 +1221,7 @@ static int snd_fm801_create(struct snd_card *card, return -ENOMEM; spin_lock_init(&chip->reg_lock); chip->card = card; - chip->pci = pci; + chip->dev = &pci->dev; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; if ((err = pci_request_regions(pci, "FM801")) < 0) -- cgit v1.2.3 From dbec6719ac036f68568d8488805d41346c021eff Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:52 +0200 Subject: ALSA: fm801: propagate TUNER_ONLY bit when autodetected The commit d7ba858a7f7a (ALSA: fm801: implement TEA575x tuner autodetection) brings autodetection to the driver. However the autodetection algorithm misses the TUNER_ONLY bit if it is supplied by the user. Thus, user gets weird messages and no card registered. snd_fm801 0000:0d:01.0: detected TEA575x radio type SF64-PCR snd_fm801 0000:0d:01.0: AC'97 interface is busy (1) snd_fm801 0000:0d:01.0: AC'97 interface is busy (1) ... snd_fm801 0000:0d:01.0: AC'97 0 does not respond - RESET snd_fm801 0000:0d:01.0: AC'97 interface is busy (1) snd_fm801 0000:0d:01.0: AC'97 interface is busy (1) snd_fm801 0000:0d:01.0: AC'97 0 access is not valid [0x0], removing mixer. snd_fm801: probe of 0000:0d:01.0 failed with error -5 Do a copy of TUNER_ONLY bit to be applied after autodetection is done. Fixes: d7ba858a7f7a (ALSA: fm801: implement TEA575x tuner autodetection) Signed-off-by: Andy Shevchenko Cc: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index e4e610c5d1ba..63025b8925f5 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1269,6 +1269,8 @@ static int snd_fm801_create(struct snd_card *card, return -ENODEV; } } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { + unsigned int tuner_only = tea575x_tuner & TUNER_ONLY; + /* autodetect tuner connection */ for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { chip->tea575x_tuner = tea575x_tuner; @@ -1283,6 +1285,8 @@ static int snd_fm801_create(struct snd_card *card, dev_err(card->dev, "TEA575x radio not found\n"); chip->tea575x_tuner = TUNER_DISABLED; } + + chip->tea575x_tuner |= tuner_only; } if (!(chip->tea575x_tuner & TUNER_DISABLED)) { strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, -- cgit v1.2.3 From b56fa687e02b27f8bd9d282950a88c2ed23d766b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:53 +0200 Subject: ALSA: fm801: detect FM-only card earlier If user does not supply tea575x_tuner parameter the driver tries to detect the tuner type. The failed codec initialization is considered as FM-only card present, however the driver still registers an IRQ handler for it. Move codec detection earlier to set tea575x_tuner parameter before check. Here the following functions are introduced reset_coded() resets AC97 codec snd_fm801_chip_multichannel_init() initializes cards with multichannel support Fixes: 5618955c4269 (ALSA: fm801: move to pcim_* and devm_* functions) Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 69 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 63025b8925f5..294fc131aee0 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1098,26 +1098,20 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, return -EIO; } -static int snd_fm801_chip_init(struct fm801 *chip, int resume) +static int reset_codec(struct fm801 *chip) { - unsigned short cmdw; - - if (chip->tea575x_tuner & TUNER_ONLY) - goto __ac97_ok; - /* codec cold reset + AC'97 warm reset */ fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6)); fm801_readw(chip, CODEC_CTRL); /* flush posting data */ udelay(100); fm801_writew(chip, CODEC_CTRL, 0); - if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) - if (!resume) { - dev_info(chip->card->dev, - "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n"); - chip->tea575x_tuner = 3 | TUNER_ONLY; - goto __ac97_ok; - } + return wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)); +} + +static void snd_fm801_chip_multichannel_init(struct fm801 *chip) +{ + unsigned short cmdw; if (chip->multichannel) { if (chip->secondary_addr) { @@ -1144,8 +1138,11 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) /* cause timeout problems */ wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); } +} - __ac97_ok: +static void snd_fm801_chip_init(struct fm801 *chip) +{ + unsigned short cmdw; /* init volume */ fm801_writew(chip, PCM_VOL, 0x0808); @@ -1166,11 +1163,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) /* interrupt clear */ fm801_writew(chip, IRQ_STATUS, FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU); - - return 0; } - static int snd_fm801_free(struct fm801 *chip) { unsigned short cmdw; @@ -1227,7 +1221,23 @@ static int snd_fm801_create(struct snd_card *card, if ((err = pci_request_regions(pci, "FM801")) < 0) return err; chip->port = pci_resource_start(pci, 0); - if ((tea575x_tuner & TUNER_ONLY) == 0) { + + if (pci->revision >= 0xb1) /* FM801-AU */ + chip->multichannel = 1; + + if (!(chip->tea575x_tuner & TUNER_ONLY)) { + if (reset_codec(chip) < 0) { + dev_info(chip->card->dev, + "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n"); + chip->tea575x_tuner = 3 | TUNER_ONLY; + } else { + snd_fm801_chip_multichannel_init(chip); + } + } + + snd_fm801_chip_init(chip); + + if ((chip->tea575x_tuner & TUNER_ONLY) == 0) { if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); @@ -1238,13 +1248,6 @@ static int snd_fm801_create(struct snd_card *card, pci_set_master(pci); } - if (pci->revision >= 0xb1) /* FM801-AU */ - chip->multichannel = 1; - - snd_fm801_chip_init(chip, 0); - /* init might set tuner access method */ - tea575x_tuner = chip->tea575x_tuner; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); return err; @@ -1261,15 +1264,15 @@ static int snd_fm801_create(struct snd_card *card, chip->tea.private_data = chip; chip->tea.ops = &snd_fm801_tea_ops; sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); - if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && - (tea575x_tuner & TUNER_TYPE_MASK) < 4) { + if ((chip->tea575x_tuner & TUNER_TYPE_MASK) > 0 && + (chip->tea575x_tuner & TUNER_TYPE_MASK) < 4) { if (snd_tea575x_init(&chip->tea, THIS_MODULE)) { dev_err(card->dev, "TEA575x radio not found\n"); snd_fm801_free(chip); return -ENODEV; } - } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { - unsigned int tuner_only = tea575x_tuner & TUNER_ONLY; + } else if ((chip->tea575x_tuner & TUNER_TYPE_MASK) == 0) { + unsigned int tuner_only = chip->tea575x_tuner & TUNER_ONLY; /* autodetect tuner connection */ for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { @@ -1405,7 +1408,13 @@ static int snd_fm801_resume(struct device *dev) struct fm801 *chip = card->private_data; int i; - snd_fm801_chip_init(chip, 1); + if (chip->tea575x_tuner & TUNER_ONLY) { + snd_fm801_chip_init(chip); + } else { + reset_codec(chip); + snd_fm801_chip_multichannel_init(chip); + snd_fm801_chip_init(chip); + } snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) -- cgit v1.2.3 From 14da04b5ff8e1e70b53f9f927e915e32a56651e1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:54 +0200 Subject: ALSA: fm801: no need to suspend absent codec In case of tuner only card there is no need to take care of the codec which is anyway absent. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 294fc131aee0..9e870884c02c 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1393,12 +1393,17 @@ static int snd_fm801_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_ac97_suspend(chip->ac97); - snd_ac97_suspend(chip->ac97_sec); + + if (chip->tea575x_tuner & TUNER_ONLY) { + /* FIXME: tea575x suspend */ + } else { + snd_pcm_suspend_all(chip->pcm); + snd_ac97_suspend(chip->ac97); + snd_ac97_suspend(chip->ac97_sec); + } + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]); - /* FIXME: tea575x suspend */ return 0; } @@ -1414,9 +1419,10 @@ static int snd_fm801_resume(struct device *dev) reset_codec(chip); snd_fm801_chip_multichannel_init(chip); snd_fm801_chip_init(chip); + snd_ac97_resume(chip->ac97); + snd_ac97_resume(chip->ac97_sec); } - snd_ac97_resume(chip->ac97); - snd_ac97_resume(chip->ac97_sec); + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]); -- cgit v1.2.3 From 37ba8fca7e42b6e689689217b9739e3a9a3c35e6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:55 +0200 Subject: ALSA: fm801: save context before suspend devices In symmetry we save context first before suspend and restore it last after resume. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 9e870884c02c..0b1ae6c684c1 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1394,6 +1394,9 @@ static int snd_fm801_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) + chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]); + if (chip->tea575x_tuner & TUNER_ONLY) { /* FIXME: tea575x suspend */ } else { @@ -1402,8 +1405,6 @@ static int snd_fm801_suspend(struct device *dev) snd_ac97_suspend(chip->ac97_sec); } - for (i = 0; i < ARRAY_SIZE(saved_regs); i++) - chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]); return 0; } -- cgit v1.2.3 From cb41f271d01b7c985ab47ea26fdef531a6237561 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 19:09:56 +0200 Subject: ALSA: fm801: restore TEA575x state on resume The suspend / resume cycle resets the settings of the FM tuner. Restore frequency settings on resume. Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 0b1ae6c684c1..161925b6518e 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1427,6 +1427,11 @@ static int snd_fm801_resume(struct device *dev) for (i = 0; i < ARRAY_SIZE(saved_regs); i++) fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]); +#ifdef CONFIG_SND_FM801_TEA575X_BOOL + if (!(chip->tea575x_tuner & TUNER_DISABLED)) + snd_tea575x_set_freq(&chip->tea); +#endif + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } -- cgit v1.2.3 From f67d71ae8bb18137eb1909a588879b33e06cc4c4 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 21 Dec 2015 23:55:39 +0800 Subject: ALSA: usb-audio: use list_for_each_entry_continue_reverse For better readability, use list_for_each_entry_continue_reverse() in have_dup_chmap(). Signed-off-by: Geliang Tang Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 8ee14f2365e7..c4dc577ab1bd 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -125,11 +125,9 @@ static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol, static bool have_dup_chmap(struct snd_usb_substream *subs, struct audioformat *fp) { - struct list_head *p; + struct audioformat *prev = fp; - for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) { - struct audioformat *prev; - prev = list_entry(p, struct audioformat, list); + list_for_each_entry_continue_reverse(prev, &subs->fmt_list, list) { if (prev->chmap && !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap))) return true; -- cgit v1.2.3 From c582cc66b98af8130f4a26ccbd7e05d5aef2a96d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 16 Dec 2015 20:37:54 +0900 Subject: ALSA: oxfw: enable to keep memory block for model-specific structure ALSA oxfw driver should have backward compatibility to old firewire-speakers driver. Additionally, in future commit, scs1x driver will be merged. It's nice to add a pointer to have a memory block for model-specific structures. This commit adds a member to 'struct snd_oxfw' for this aim. Deallocation is done at freeing ALSA card structure. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw.c | 1 + sound/firewire/oxfw/oxfw.h | 1 + 2 files changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index d4fb3c10163a..7e50a4fcee50 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -132,6 +132,7 @@ static void oxfw_card_free(struct snd_card *card) kfree(oxfw->rx_stream_formats[i]); } + kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index f3e14fff4ba0..9625661bbe8a 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -74,6 +74,7 @@ struct snd_oxfw { wait_queue_head_t hwdep_wait; const struct ieee1394_device_id *entry; + void *spec; }; /* -- cgit v1.2.3 From 40540de503929ebac3844c65fad2cd32ca15d3ce Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 16 Dec 2015 20:37:55 +0900 Subject: ALSA: oxfw: move model-specific members from common structure Currently, 'struct snd_oxfw' has some members for models supported by old firewire-speakers driver, while these members are useless to the other models. This commit allocates new memory block and moves these members to model-specific structure. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-spkr.c | 48 +++++++++++++++++++++++++++++------------ sound/firewire/oxfw/oxfw.h | 5 ----- 2 files changed, 34 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index d733a15cdec7..fbdd432d8562 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -7,6 +7,13 @@ #include "oxfw.h" +struct fw_spkr { + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; +}; + enum control_action { CTL_READ, CTL_WRITE }; enum control_attribute { CTL_MIN = 0x02, @@ -135,8 +142,9 @@ static int spkr_mute_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; - value->value.integer.value[0] = !oxfw->mute; + value->value.integer.value[0] = !spkr->mute; return 0; } @@ -145,19 +153,20 @@ static int spkr_mute_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; bool mute; int err; mute = !value->value.integer.value[0]; - if (mute == oxfw->mute) + if (mute == spkr->mute) return 0; err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, &mute, CTL_WRITE); if (err < 0) return err; - oxfw->mute = mute; + spkr->mute = mute; return 1; } @@ -166,11 +175,12 @@ static int spkr_volume_info(struct snd_kcontrol *control, struct snd_ctl_elem_info *info) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; + info->value.integer.min = spkr->volume_min; + info->value.integer.max = spkr->volume_max; return 0; } @@ -181,10 +191,11 @@ static int spkr_volume_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + value->value.integer.value[channel_map[i]] = spkr->volume[i]; return 0; } @@ -193,14 +204,15 @@ static int spkr_volume_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i, changed_channels; bool equal_values = true; s16 volume; int err; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) + if (value->value.integer.value[i] < spkr->volume_min || + value->value.integer.value[i] > spkr->volume_max) return -EINVAL; if (value->value.integer.value[i] != value->value.integer.value[0]) @@ -210,7 +222,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, changed_channels = 0; for (i = 0; i < oxfw->device_info->mixer_channels; ++i) if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) + spkr->volume[i]) changed_channels |= 1 << (i + 1); if (equal_values && changed_channels != 0) @@ -227,7 +239,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, return err; } if (i > 0) - oxfw->volume[i - 1] = volume; + spkr->volume[i - 1] = volume; } return changed_channels != 0; @@ -251,22 +263,30 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) .put = spkr_volume_put, }, }; + struct fw_spkr *spkr; unsigned int i, first_ch; int err; + spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL); + if (spkr == NULL) + return -ENOMEM; + oxfw->spec = spkr; + err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume_min, 0, CTL_MIN, CTL_READ); + &spkr->volume_min, + 0, CTL_MIN, CTL_READ); if (err < 0) return err; err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume_max, 0, CTL_MAX, CTL_READ); + &spkr->volume_max, + 0, CTL_MAX, CTL_READ); if (err < 0) return err; err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &oxfw->mute, CTL_READ); + &spkr->mute, CTL_READ); if (err < 0) return err; @@ -274,7 +294,7 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { err = avc_audio_feature_volume(oxfw->unit, oxfw->device_info->volume_fb_id, - &oxfw->volume[i], + &spkr->volume[i], first_ch + i, CTL_CURRENT, CTL_READ); if (err < 0) return err; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 9625661bbe8a..046cd33cc41a 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -64,11 +64,6 @@ struct snd_oxfw { unsigned int midi_input_ports; unsigned int midi_output_ports; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; - int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; -- cgit v1.2.3 From 3e2f45708eb59179444f992ba1dc60ccf2cbdacd Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 16 Dec 2015 20:37:56 +0900 Subject: ALSA: oxfw: move model-specific parameters from common structure In previous commit, some members are moved from 'struct snd_oxfw' because they're model-specific. There are also the other model-specific parameters in 'struct device_info'. This commit moves these members to model-specific structure. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-spkr.c | 60 +++++++++++++++++++++++------------------ sound/firewire/oxfw/oxfw.c | 16 +++-------- sound/firewire/oxfw/oxfw.h | 5 +--- 3 files changed, 39 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index fbdd432d8562..cb905af0660d 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -12,6 +12,10 @@ struct fw_spkr { s16 volume[6]; s16 volume_min; s16 volume_max; + + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; }; enum control_action { CTL_READ, CTL_WRITE }; @@ -162,8 +166,8 @@ static int spkr_mute_put(struct snd_kcontrol *control, if (mute == spkr->mute) return 0; - err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &mute, CTL_WRITE); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute, + CTL_WRITE); if (err < 0) return err; spkr->mute = mute; @@ -178,7 +182,7 @@ static int spkr_volume_info(struct snd_kcontrol *control, struct fw_spkr *spkr = oxfw->spec; info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; + info->count = spkr->mixer_channels; info->value.integer.min = spkr->volume_min; info->value.integer.max = spkr->volume_max; @@ -194,7 +198,7 @@ static int spkr_volume_get(struct snd_kcontrol *control, struct fw_spkr *spkr = oxfw->spec; unsigned int i; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + for (i = 0; i < spkr->mixer_channels; ++i) value->value.integer.value[channel_map[i]] = spkr->volume[i]; return 0; @@ -210,7 +214,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, s16 volume; int err; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + for (i = 0; i < spkr->mixer_channels; ++i) { if (value->value.integer.value[i] < spkr->volume_min || value->value.integer.value[i] > spkr->volume_max) return -EINVAL; @@ -220,7 +224,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, } changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + for (i = 0; i < spkr->mixer_channels; ++i) if (value->value.integer.value[channel_map[i]] != spkr->volume[i]) changed_channels |= 1 << (i + 1); @@ -228,12 +232,11 @@ static int spkr_volume_put(struct snd_kcontrol *control, if (equal_values && changed_channels != 0) changed_channels = 1 << 0; - for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + for (i = 0; i <= spkr->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->mute_fb_id, - &volume, + spkr->volume_fb_id, &volume, i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; @@ -245,7 +248,7 @@ static int spkr_volume_put(struct snd_kcontrol *control, return changed_channels != 0; } -int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie) { static const struct snd_kcontrol_new controls[] = { { @@ -272,30 +275,35 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw) return -ENOMEM; oxfw->spec = spkr; - err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume_min, - 0, CTL_MIN, CTL_READ); + if (is_lacie) { + spkr->mixer_channels = 1; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x01; + } else { + spkr->mixer_channels = 6; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x02; + } + + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume_max, - 0, CTL_MAX, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err; - err = avc_audio_feature_mute(oxfw->unit, oxfw->device_info->mute_fb_id, - &spkr->mute, CTL_READ); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute, + CTL_READ); if (err < 0) return err; - first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = avc_audio_feature_volume(oxfw->unit, - oxfw->device_info->volume_fb_id, - &spkr->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); + first_ch = spkr->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < spkr->mixer_channels; ++i) { + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume[i], first_ch + i, + CTL_CURRENT, CTL_READ); if (err < 0) return err; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 7e50a4fcee50..16ee6ea033e4 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -147,12 +147,10 @@ static int detect_quirks(struct snd_oxfw *oxfw) * Add ALSA control elements for two models to keep compatibility to * old firewire-speaker module. */ - if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || - oxfw->entry->vendor_id == VENDOR_LACIE) { - oxfw->device_info = - (const struct device_info *)oxfw->entry->driver_data; - return snd_oxfw_add_spkr(oxfw); - } + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN) + return snd_oxfw_add_spkr(oxfw, false); + if (oxfw->entry->vendor_id == VENDOR_LACIE) + return snd_oxfw_add_spkr(oxfw, true); /* * TASCAM FireOne has physical control and requires a pair of additional @@ -285,18 +283,12 @@ static const struct device_info griffin_firewave = { .driver_name = "FireWave", .vendor_name = "Griffin", .model_name = "FireWave", - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, }; static const struct device_info lacie_speakers = { .driver_name = "FWSpeakers", .vendor_name = "LaCie", .model_name = "FireWire Speakers", - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, }; static const struct ieee1394_device_id oxfw_id_table[] = { diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 046cd33cc41a..603815017ae0 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -35,9 +35,6 @@ struct device_info { const char *driver_name; const char *vendor_name; const char *model_name; - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; }; /* This is an arbitrary number for convinience. */ @@ -142,4 +139,4 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw); int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); -int snd_oxfw_add_spkr(struct snd_oxfw *oxfw); +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); -- cgit v1.2.3 From d6ce6bbd7d83453ce958cfc03b7250dbee3a431e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 16 Dec 2015 20:37:57 +0900 Subject: ALSA: oxfw: rename a structure so that it means backward compatibility to old drivers In former commits, some model-specific members are split from the structure. The structure is just to keep names for compatibility to old drivers. This commit arranges name of the structure and localize it. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw.c | 14 ++++++++++---- sound/firewire/oxfw/oxfw.h | 6 ------ 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 16ee6ea033e4..96fbb784f086 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -30,6 +30,12 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); +struct compat_info { + const char *driver_name; + const char *vendor_name; + const char *model_name; +}; + static bool detect_loud_models(struct fw_unit *unit) { const char *const models[] = { @@ -59,7 +65,7 @@ static bool detect_loud_models(struct fw_unit *unit) static int name_card(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); - const struct device_info *info; + const struct compat_info *info; char vendor[24]; char model[32]; const char *d, *v, *m; @@ -87,7 +93,7 @@ static int name_card(struct snd_oxfw *oxfw) /* to apply card definitions */ if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || oxfw->entry->vendor_id == VENDOR_LACIE) { - info = (const struct device_info *)oxfw->entry->driver_data; + info = (const struct compat_info *)oxfw->entry->driver_data; d = info->driver_name; v = info->vendor_name; m = info->model_name; @@ -279,13 +285,13 @@ static void oxfw_remove(struct fw_unit *unit) snd_card_free_when_closed(oxfw->card); } -static const struct device_info griffin_firewave = { +static const struct compat_info griffin_firewave = { .driver_name = "FireWave", .vendor_name = "Griffin", .model_name = "FireWave", }; -static const struct device_info lacie_speakers = { +static const struct compat_info lacie_speakers = { .driver_name = "FWSpeakers", .vendor_name = "LaCie", .model_name = "FireWire Speakers", diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 603815017ae0..1c9844a4649d 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -31,12 +31,6 @@ #include "../amdtp-am824.h" #include "../cmp.h" -struct device_info { - const char *driver_name; - const char *vendor_name; - const char *model_name; -}; - /* This is an arbitrary number for convinience. */ #define SND_OXFW_STREAM_FORMAT_ENTRIES 10 struct snd_oxfw { -- cgit v1.2.3 From 3f47152a1c8f4d4c8ca18740bf3f1a7fff1b3fd9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:39 +0900 Subject: ALSA: oxfw: add scs1x layer Stanton Controllers and Systems 1 (SCS.1) series is supported by ALSA scs1x driver. This driver just supports MIDI functionality. On the other hand, models in this series are based on OXFW971 and ALSA OXFW driver can support them. SCS.1 series has MIDI functionality to control its surface state such as LED lighting. When operating physical knobs and faders, the models generate MIDI messages. These MIDI messages are transferred by asynchronous transactions. These transactions are really model-specific and ALSA OXFW driver requires the functionality so as scs1x module implements. This commit adds scs1x layer as a preparation to merge scs1x driver to oxfw driver. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/Makefile | 2 +- sound/firewire/oxfw/oxfw-scs1x.c | 26 ++++++++++++++++++++++++++ sound/firewire/oxfw/oxfw.c | 4 ++-- sound/firewire/oxfw/oxfw.h | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-scs1x.c (limited to 'sound') diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 4e54ba9f4394..b474da7c6a1f 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,3 +1,3 @@ snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \ - oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw.o + oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o obj-$(CONFIG_SND_OXFW) += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c new file mode 100644 index 000000000000..34db0d0957c5 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -0,0 +1,26 @@ +/* + * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2015 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) +{ + struct snd_rawmidi *rmidi; + int err; + + /* Use unique name for backward compatibility to scs1x module. */ + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); + if (err < 0) + return err; + + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", oxfw->card->shortname); + + return err; +} diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 96fbb784f086..b20e496e2201 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -216,11 +216,11 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = detect_quirks(oxfw); + err = name_card(oxfw); if (err < 0) goto error; - err = name_card(oxfw); + err = detect_quirks(oxfw); if (err < 0) goto error; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 1c9844a4649d..cbf00eee678c 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -134,3 +134,4 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw); int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw); -- cgit v1.2.3 From e3315b439c30c208582ac64e58f0c0d36b83181e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:40 +0900 Subject: ALSA: oxfw: allocate own address region for SCS.1 series When physical controls on SCS.1 models are operated, the models transfer MIDI messages in asynchronous transactions on IEEE 1394 bus. The models have a register to have an address for the transactions, and drivers can register own address for this purpose. This commit keeps a region of address, registers it and adds a handler for the transactions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 65 +++++++++++++++++++++++++++++++++++++++- sound/firewire/oxfw/oxfw.h | 1 + 2 files changed, 65 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 34db0d0957c5..32a7b673cbc8 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -9,18 +9,81 @@ #include "oxfw.h" +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct fw_scs1x { + struct fw_address_handler hss_handler; +}; + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int register_address(struct snd_oxfw *oxfw) +{ + struct fw_scs1x *scs = oxfw->spec; + __be64 data; + + data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | + scs->hss_handler.offset); + return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, &data, sizeof(data), 0); +} + +static void remove_scs1x(struct snd_rawmidi *rmidi) +{ + struct fw_scs1x *scs = rmidi->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); +} + +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw) +{ + register_address(oxfw); +} + int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) { struct snd_rawmidi *rmidi; + struct fw_scs1x *scs; int err; + scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); + if (scs == NULL) + return -ENOMEM; + oxfw->spec = scs; + + /* Allocate own handler for imcoming asynchronous transaction. */ + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + return err; + + err = register_address(oxfw); + if (err < 0) + goto err_allocated; + /* Use unique name for backward compatibility to scs1x module. */ err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); if (err < 0) - return err; + goto err_allocated; + rmidi->private_data = scs; + rmidi->private_free = remove_scs1x; snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname); + return 0; +err_allocated: + fw_core_remove_address_handler(&scs->hss_handler); return err; } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index cbf00eee678c..9beecc214767 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -135,3 +135,4 @@ int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw); +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw); -- cgit v1.2.3 From 13b8b78c7fd65abf8b100cc05166cca1d10a1e80 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:41 +0900 Subject: ALSA: oxfw: copy handlers of asynchronous transaction for MIDI capture This commit copies some functions of asynchronous transactions for MIDI capture, to merge scs1x module. The features of payload in asynchronous transaction are: * System exclusive messages for SCS.1 are encoded without ID data. In this encoding scheme, 4 bits in LSB are available. The bits are squashed in payload byte. Thus, one payload byte transfers two MIDI messages. * The first byte of payload byte means: * 0x00: depending on second payload byte * 0xf9: including escaped system exclusive messages for SCS.1, up to 3 byte (= 6 MIDI messages) * the others: including MIDI 1.0 messages * the others: including escaped system exclusive messages for SCS.1, up to 64 bytes Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 83 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 32a7b673cbc8..3e0349bced96 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -11,18 +11,99 @@ #define HSS1394_ADDRESS 0xc007dedadadaULL #define HSS1394_MAX_PACKET_SIZE 64 +#define HSS1394_TAG_USER_DATA 0x00 #define HSS1394_TAG_CHANGE_ADDRESS 0xf1 struct fw_scs1x { struct fw_address_handler hss_handler; + u8 input_escape_count; + struct snd_rawmidi_substream *input; }; +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void midi_input_byte(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, u8 byte) +{ + const u8 eox = 0xf7; + + if (scs->input_escape_count > 0) { + midi_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + midi_input_escaped_byte(stream, 0x00); + midi_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void midi_input_packet(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + const u8 eox = 0xf7; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 1; i < bytes; ++i) + midi_input_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + midi_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } +} + static void handle_hss(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, unsigned long long offset, void *data, size_t length, void *callback_data) { - fw_send_response(card, request, RCODE_COMPLETE); + struct fw_scs1x *scs = callback_data; + struct snd_rawmidi_substream *stream; + int rcode; + + if (offset != scs->hss_handler.offset) { + rcode = RCODE_ADDRESS_ERROR; + goto end; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + rcode = RCODE_TYPE_ERROR; + goto end; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + midi_input_packet(scs, stream, data, length); + } + + rcode = RCODE_COMPLETE; +end: + fw_send_response(card, request, rcode); } static int register_address(struct snd_oxfw *oxfw) -- cgit v1.2.3 From 8250427dc1a2f0a4f9de0ee5a3324fa6c75b44a1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:42 +0900 Subject: ALSA: oxfw: add MIDI capture port for SCS.1 models This commit adds MIDI capture so that scs1x driver has. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 3e0349bced96..6ab63f23b345 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -106,6 +106,34 @@ end: fw_send_response(card, request, rcode); } +static int midi_capture_open(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static int midi_capture_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + if (up) { + scs->input_escape_count = 0; + ACCESS_ONCE(scs->input) = stream; + } else { + ACCESS_ONCE(scs->input) = NULL; + } +} + +static struct snd_rawmidi_ops midi_capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, +}; + static int register_address(struct snd_oxfw *oxfw) { struct fw_scs1x *scs = oxfw->spec; @@ -154,7 +182,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) goto err_allocated; /* Use unique name for backward compatibility to scs1x module. */ - err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 0, &rmidi); + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 1, &rmidi); if (err < 0) goto err_allocated; rmidi->private_data = scs; @@ -163,6 +191,10 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &midi_capture_ops); + return 0; err_allocated: fw_core_remove_address_handler(&scs->hss_handler); -- cgit v1.2.3 From d7d20e77819f937a8e9bf0b12a21a12d33eb4b23 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:43 +0900 Subject: ALSA: oxfw: copy handlers of asynchronous transaction for MIDI playback This commit copies some functions of asynchronous transactions for MIDI playback, to merge scs1x module. The features of payload in asynchronous transaction are the same as captured MIDI messages. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 161 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 6ab63f23b345..84eacdb9f4c5 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -18,6 +18,20 @@ struct fw_scs1x { struct fw_address_handler hss_handler; u8 input_escape_count; struct snd_rawmidi_substream *input; + + /* For MIDI playback. */ + struct snd_rawmidi_substream *output; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 buffer[HSS1394_MAX_PACKET_SIZE]; + bool transaction_running; + struct fw_transaction transaction; + struct fw_device *fw_dev; }; static const u8 sysex_escape_prefix[] = { @@ -106,6 +120,148 @@ end: fw_send_response(card, request, rcode); } +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct fw_scs1x *scs = callback_data; + + if (rcode == RCODE_GENERATION) + ; /* TODO: retry this packet */ + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct fw_scs1x *scs = (struct fw_scs1x *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status( + scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != + HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + generation = scs->fw_dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(scs->fw_dev->card, &scs->transaction, + TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id, + generation, scs->fw_dev->max_speed, HSS1394_ADDRESS, + scs->buffer, i, scs_write_callback, scs); +} + static int midi_capture_open(struct snd_rawmidi_substream *stream) { return 0; @@ -166,6 +322,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); if (scs == NULL) return -ENOMEM; + scs->fw_dev = fw_parent_device(oxfw->unit); oxfw->spec = scs; /* Allocate own handler for imcoming asynchronous transaction. */ @@ -195,6 +352,10 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &midi_capture_ops); + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + return 0; err_allocated: fw_core_remove_address_handler(&scs->hss_handler); -- cgit v1.2.3 From 6f5dcb28df50eafb2d554c84f14c33677a5b95bd Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:44 +0900 Subject: ALSA: oxfw: add MIDI playback port for SCS.1 models This commit adds MIDI playback ports so that scs1x driver has. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 84eacdb9f4c5..bb53eb35721b 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -290,6 +290,45 @@ static struct snd_rawmidi_ops midi_capture_ops = { .trigger = midi_capture_trigger, }; +static int midi_playback_open(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static int midi_playback_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + if (up) { + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + scs->output_idle = false; + + ACCESS_ONCE(scs->output) = stream; + tasklet_schedule(&scs->tasklet); + } else { + ACCESS_ONCE(scs->output) = NULL; + } +} +static void midi_playback_drain(struct snd_rawmidi_substream *stream) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + .drain = midi_playback_drain, +}; static int register_address(struct snd_oxfw *oxfw) { struct fw_scs1x *scs = oxfw->spec; @@ -339,7 +378,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) goto err_allocated; /* Use unique name for backward compatibility to scs1x module. */ - err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 0, 1, &rmidi); + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi); if (err < 0) goto err_allocated; rmidi->private_data = scs; @@ -348,9 +387,13 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", oxfw->card->shortname); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT; + rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &midi_capture_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &midi_playback_ops); tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); init_waitqueue_head(&scs->idle_wait); -- cgit v1.2.3 From 9e2004f9cedf50469e62e3206bc3363913a972b4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:45 +0900 Subject: ALSA: oxfw: obsolete scs1x module Now ALSA oxfw driver gains functionalities which scs1x module has. This commit obsoletes the scs1x module, and adds a line of MODULE_ALIAS to load oxfw module instead of scs1x module. In scs1x module, the name of 'shortname' field is fixed as 'SCS1x'. This field is used to name MIDI ports for both of SCS.1m and SCS.1d. This is not good because typically some SCS.1m and SCS.1d are used in the same system. It's better to distinguish them according to name of the ports. This commit applies model name in config ROM to the 'shortname'. For the name of 'driver' and 'longname', this commit uses the same way applied to the other models. This change may not bring disadvantages to users because userspace applications use ALSA rawmidi or seq interface and these interfaces are not influenced by them directly. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 12 +- sound/firewire/Makefile | 2 - sound/firewire/oxfw/oxfw.c | 26 +++ sound/firewire/scs1x.c | 530 --------------------------------------------- 4 files changed, 27 insertions(+), 543 deletions(-) delete mode 100644 sound/firewire/scs1x.c (limited to 'sound') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index e92a6d949847..2a779c2f63ab 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -39,6 +39,7 @@ config SND_OXFW * Mackie(Loud) d.2 pro/d.4 pro * Mackie(Loud) U.420/U.420d * TASCAM FireOne + * Stanton Controllers & Systems 1 Deck/Mixer To compile this driver as a module, choose M here: the module will be called snd-oxfw. @@ -53,17 +54,6 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. -config SND_SCS1X - tristate "Stanton Control System 1 MIDI" - select SND_FIREWIRE_LIB - help - Say Y here to include support for the MIDI ports of the Stanton - SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled - by FFADO.) - - To compile this driver as a module, choose M here: the module - will be called snd-scs1x. - config SND_FIREWORKS tristate "Echo Fireworks board module support" select SND_FIREWIRE_LIB diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index f5fb62551c60..003c09029786 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,13 +1,11 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp-stream.o amdtp-am824.o snd-isight-objs := isight.o -snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_DICE) += dice/ obj-$(CONFIG_SND_OXFW) += oxfw/ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o -obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o obj-$(CONFIG_SND_FIREWORKS) += fireworks/ obj-$(CONFIG_SND_BEBOB) += bebob/ obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/ diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index b20e496e2201..e7f2698c4cb8 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -19,6 +19,7 @@ #define VENDOR_BEHRINGER 0x001564 #define VENDOR_LACIE 0x00d04b #define VENDOR_TASCAM 0x00022e +#define OUI_STANTON 0x001260 #define MODEL_SATELLITE 0x00200f @@ -29,6 +30,7 @@ MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); +MODULE_ALIAS("snd-scs1x"); struct compat_info { const char *driver_name; @@ -158,6 +160,13 @@ static int detect_quirks(struct snd_oxfw *oxfw) if (oxfw->entry->vendor_id == VENDOR_LACIE) return snd_oxfw_add_spkr(oxfw, true); + /* + * Stanton models supports asynchronous transactions for unique MIDI + * messages. + */ + if (oxfw->entry->vendor_id == OUI_STANTON) + return snd_oxfw_scs1x_add(oxfw); + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. @@ -275,6 +284,9 @@ static void oxfw_bus_reset(struct fw_unit *unit) snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); mutex_unlock(&oxfw->mutex); + + if (oxfw->entry->vendor_id == OUI_STANTON) + snd_oxfw_scs1x_update(oxfw); } static void oxfw_remove(struct fw_unit *unit) @@ -352,6 +364,20 @@ static const struct ieee1394_device_id oxfw_id_table[] = { .vendor_id = VENDOR_TASCAM, .model_id = 0x800007, }, + /* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x001000, + }, + /* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x002000, + }, { } }; MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c deleted file mode 100644 index 2dba848a781f..000000000000 --- a/sound/firewire/scs1x.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Stanton Control System 1 MIDI driver - * - * Copyright (c) Clemens Ladisch - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lib.h" - -#define OUI_STANTON 0x001260 -#define MODEL_SCS_1M 0x001000 -#define MODEL_SCS_1D 0x002000 - -#define HSS1394_ADDRESS 0xc007dedadadaULL -#define HSS1394_MAX_PACKET_SIZE 64 - -#define HSS1394_TAG_USER_DATA 0x00 -#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 - -struct scs { - struct snd_card *card; - struct fw_unit *unit; - struct fw_address_handler hss_handler; - struct fw_transaction transaction; - bool transaction_running; - bool output_idle; - u8 output_status; - u8 output_bytes; - bool output_escaped; - bool output_escape_high_nibble; - u8 input_escape_count; - struct snd_rawmidi_substream *output; - struct snd_rawmidi_substream *input; - struct tasklet_struct tasklet; - wait_queue_head_t idle_wait; - u8 *buffer; -}; - -static const u8 sysex_escape_prefix[] = { - 0xf0, /* SysEx begin */ - 0x00, 0x01, 0x60, /* Stanton DJ */ - 0x48, 0x53, 0x53, /* "HSS" */ -}; - -static int scs_output_open(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - scs->output_status = 0; - scs->output_bytes = 1; - scs->output_escaped = false; - - return 0; -} - -static int scs_output_close(struct snd_rawmidi_substream *stream) -{ - return 0; -} - -static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) -{ - struct scs *scs = stream->rmidi->private_data; - - ACCESS_ONCE(scs->output) = up ? stream : NULL; - if (up) { - scs->output_idle = false; - tasklet_schedule(&scs->tasklet); - } -} - -static void scs_write_callback(struct fw_card *card, int rcode, - void *data, size_t length, void *callback_data) -{ - struct scs *scs = callback_data; - - if (rcode == RCODE_GENERATION) { - /* TODO: retry this packet */ - } - - scs->transaction_running = false; - tasklet_schedule(&scs->tasklet); -} - -static bool is_valid_running_status(u8 status) -{ - return status >= 0x80 && status <= 0xef; -} - -static bool is_one_byte_cmd(u8 status) -{ - return status == 0xf6 || - status >= 0xf8; -} - -static bool is_two_bytes_cmd(u8 status) -{ - return (status >= 0xc0 && status <= 0xdf) || - status == 0xf1 || - status == 0xf3; -} - -static bool is_three_bytes_cmd(u8 status) -{ - return (status >= 0x80 && status <= 0xbf) || - (status >= 0xe0 && status <= 0xef) || - status == 0xf2; -} - -static bool is_invalid_cmd(u8 status) -{ - return status == 0xf4 || - status == 0xf5 || - status == 0xf9 || - status == 0xfd; -} - -static void scs_output_tasklet(unsigned long data) -{ - struct scs *scs = (void *)data; - struct snd_rawmidi_substream *stream; - unsigned int i; - u8 byte; - struct fw_device *dev; - int generation; - - if (scs->transaction_running) - return; - - stream = ACCESS_ONCE(scs->output); - if (!stream) { - scs->output_idle = true; - wake_up(&scs->idle_wait); - return; - } - - i = scs->output_bytes; - for (;;) { - if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { - scs->output_bytes = i; - scs->output_idle = true; - wake_up(&scs->idle_wait); - return; - } - /* - * Convert from real MIDI to what I think the device expects (no - * running status, one command per packet, unescaped SysExs). - */ - if (scs->output_escaped && byte < 0x80) { - if (scs->output_escape_high_nibble) { - if (i < HSS1394_MAX_PACKET_SIZE) { - scs->buffer[i] = byte << 4; - scs->output_escape_high_nibble = false; - } - } else { - scs->buffer[i++] |= byte & 0x0f; - scs->output_escape_high_nibble = true; - } - } else if (byte < 0x80) { - if (i == 1) { - if (!is_valid_running_status(scs->output_status)) - continue; - scs->buffer[0] = HSS1394_TAG_USER_DATA; - scs->buffer[i++] = scs->output_status; - } - scs->buffer[i++] = byte; - if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || - (i == 4 && is_three_bytes_cmd(scs->output_status))) - break; - if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && - !memcmp(scs->buffer + 1, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix))) { - scs->output_escaped = true; - scs->output_escape_high_nibble = true; - i = 0; - } - if (i >= HSS1394_MAX_PACKET_SIZE) - i = 1; - } else if (byte == 0xf7) { - if (scs->output_escaped) { - if (i >= 1 && scs->output_escape_high_nibble && - scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) - break; - } else { - if (i > 1 && scs->output_status == 0xf0) { - scs->buffer[i++] = 0xf7; - break; - } - } - i = 1; - scs->output_escaped = false; - } else if (!is_invalid_cmd(byte) && - byte < 0xf8) { - i = 1; - scs->buffer[0] = HSS1394_TAG_USER_DATA; - scs->buffer[i++] = byte; - scs->output_status = byte; - scs->output_escaped = false; - if (is_one_byte_cmd(byte)) - break; - } - } - scs->output_bytes = 1; - scs->output_escaped = false; - - scs->transaction_running = true; - dev = fw_parent_device(scs->unit); - generation = dev->generation; - smp_rmb(); /* node_id vs. generation */ - fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, - dev->node_id, generation, dev->max_speed, - HSS1394_ADDRESS, scs->buffer, i, - scs_write_callback, scs); -} - -static void scs_output_drain(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - wait_event(scs->idle_wait, scs->output_idle); -} - -static struct snd_rawmidi_ops output_ops = { - .open = scs_output_open, - .close = scs_output_close, - .trigger = scs_output_trigger, - .drain = scs_output_drain, -}; - -static int scs_input_open(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - scs->input_escape_count = 0; - - return 0; -} - -static int scs_input_close(struct snd_rawmidi_substream *stream) -{ - return 0; -} - -static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) -{ - struct scs *scs = stream->rmidi->private_data; - - ACCESS_ONCE(scs->input) = up ? stream : NULL; -} - -static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream, - u8 byte) -{ - u8 nibbles[2]; - - nibbles[0] = byte >> 4; - nibbles[1] = byte & 0x0f; - snd_rawmidi_receive(stream, nibbles, 2); -} - -static void scs_input_midi_byte(struct scs *scs, - struct snd_rawmidi_substream *stream, - u8 byte) -{ - if (scs->input_escape_count > 0) { - scs_input_escaped_byte(stream, byte); - scs->input_escape_count--; - if (scs->input_escape_count == 0) - snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); - } else if (byte == 0xf9) { - snd_rawmidi_receive(stream, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix)); - scs_input_escaped_byte(stream, 0x00); - scs_input_escaped_byte(stream, 0xf9); - scs->input_escape_count = 3; - } else { - snd_rawmidi_receive(stream, &byte, 1); - } -} - -static void scs_input_packet(struct scs *scs, - struct snd_rawmidi_substream *stream, - const u8 *data, unsigned int bytes) -{ - unsigned int i; - - if (data[0] == HSS1394_TAG_USER_DATA) { - for (i = 1; i < bytes; ++i) - scs_input_midi_byte(scs, stream, data[i]); - } else { - snd_rawmidi_receive(stream, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix)); - for (i = 0; i < bytes; ++i) - scs_input_escaped_byte(stream, data[i]); - snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); - } -} - -static struct snd_rawmidi_ops input_ops = { - .open = scs_input_open, - .close = scs_input_close, - .trigger = scs_input_trigger, -}; - -static int scs_create_midi(struct scs *scs) -{ - struct snd_rawmidi *rmidi; - int err; - - err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); - if (err < 0) - return err; - snprintf(rmidi->name, sizeof(rmidi->name), - "%s MIDI", scs->card->shortname); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - rmidi->private_data = scs; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); - - return 0; -} - -static void handle_hss(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, int generation, - unsigned long long offset, void *data, size_t length, - void *callback_data) -{ - struct scs *scs = callback_data; - struct snd_rawmidi_substream *stream; - - if (offset != scs->hss_handler.offset) { - fw_send_response(card, request, RCODE_ADDRESS_ERROR); - return; - } - if (tcode != TCODE_WRITE_QUADLET_REQUEST && - tcode != TCODE_WRITE_BLOCK_REQUEST) { - fw_send_response(card, request, RCODE_TYPE_ERROR); - return; - } - - if (length >= 1) { - stream = ACCESS_ONCE(scs->input); - if (stream) - scs_input_packet(scs, stream, data, length); - } - - fw_send_response(card, request, RCODE_COMPLETE); -} - -static int scs_init_hss_address(struct scs *scs) -{ - __be64 data; - int err; - - data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | - scs->hss_handler.offset); - err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, - HSS1394_ADDRESS, &data, 8, 0); - if (err < 0) - dev_err(&scs->unit->device, "HSS1394 communication failed\n"); - - return err; -} - -static void scs_card_free(struct snd_card *card) -{ - struct scs *scs = card->private_data; - - fw_core_remove_address_handler(&scs->hss_handler); - kfree(scs->buffer); -} - -static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) -{ - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct scs *scs; - int err; - - err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE, - sizeof(*scs), &card); - if (err < 0) - return err; - - scs = card->private_data; - scs->card = card; - scs->unit = unit; - tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); - init_waitqueue_head(&scs->idle_wait); - scs->output_idle = true; - - scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); - if (!scs->buffer) { - err = -ENOMEM; - goto err_card; - } - - scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; - scs->hss_handler.address_callback = handle_hss; - scs->hss_handler.callback_data = scs; - err = fw_core_add_address_handler(&scs->hss_handler, - &fw_high_memory_region); - if (err < 0) - goto err_buffer; - - card->private_free = scs_card_free; - - strcpy(card->driver, "SCS.1x"); - strcpy(card->shortname, "SCS.1x"); - fw_csr_string(unit->directory, CSR_MODEL, - card->shortname, sizeof(card->shortname)); - snprintf(card->longname, sizeof(card->longname), - "Stanton DJ %s (GUID %08x%08x) at %s, S%d", - card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, card->shortname); - - err = scs_init_hss_address(scs); - if (err < 0) - goto err_card; - - err = scs_create_midi(scs); - if (err < 0) - goto err_card; - - err = snd_card_register(card); - if (err < 0) - goto err_card; - - dev_set_drvdata(&unit->device, scs); - - return 0; - -err_buffer: - kfree(scs->buffer); -err_card: - snd_card_free(card); - return err; -} - -static void scs_update(struct fw_unit *unit) -{ - struct scs *scs = dev_get_drvdata(&unit->device); - int generation; - __be64 data; - - data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | - scs->hss_handler.offset); - generation = fw_parent_device(unit)->generation; - smp_rmb(); /* node_id vs. generation */ - snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, - HSS1394_ADDRESS, &data, 8, - FW_FIXED_GENERATION | generation); -} - -static void scs_remove(struct fw_unit *unit) -{ - struct scs *scs = dev_get_drvdata(&unit->device); - - snd_card_disconnect(scs->card); - - ACCESS_ONCE(scs->output) = NULL; - ACCESS_ONCE(scs->input) = NULL; - - wait_event(scs->idle_wait, scs->output_idle); - - tasklet_kill(&scs->tasklet); - - snd_card_free_when_closed(scs->card); -} - -static const struct ieee1394_device_id scs_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = MODEL_SCS_1M, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = MODEL_SCS_1D, - }, - {} -}; -MODULE_DEVICE_TABLE(ieee1394, scs_id_table); - -MODULE_DESCRIPTION("SCS.1x MIDI driver"); -MODULE_AUTHOR("Clemens Ladisch "); -MODULE_LICENSE("GPL v2"); - -static struct fw_driver scs_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - }, - .probe = scs_probe, - .update = scs_update, - .remove = scs_remove, - .id_table = scs_id_table, -}; - -static int __init alsa_scs1x_init(void) -{ - return driver_register(&scs_driver.driver); -} - -static void __exit alsa_scs1x_exit(void) -{ - driver_unregister(&scs_driver.driver); -} - -module_init(alsa_scs1x_init); -module_exit(alsa_scs1x_exit); -- cgit v1.2.3 From de5126cc3c0b0f291d08fa591dcdf237bc595a56 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Dec 2015 09:15:46 +0900 Subject: ALSA: oxfw: add stream format quirk for SCS.1 models As long as I investigate SCS.1m, this model reports to transfer/receive PCM data channels/MIDI conformant data channels in tx/rx AMDTP packet. There's a contradiction that this model actually has no analog/digital capture port for PCM frames and no physical MIDI ports. I guess that SCS.1d also has the contradiction. This model has no analog/digital ports for PCM frames and no physical MIDI ports, thus it requires no streaming functionality. This commit adds some modification codes to handle the contradiction, as much as possible. Unfortunately, this module adds one PCM playback substream for SCS.1d so as SCS.1m. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index e7f2698c4cb8..abedc2207261 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -164,8 +164,16 @@ static int detect_quirks(struct snd_oxfw *oxfw) * Stanton models supports asynchronous transactions for unique MIDI * messages. */ - if (oxfw->entry->vendor_id == OUI_STANTON) + if (oxfw->entry->vendor_id == OUI_STANTON) { + /* No physical MIDI ports. */ + oxfw->midi_input_ports = 0; + oxfw->midi_output_ports = 0; + + /* Output stream exists but no data channels are useful. */ + oxfw->has_output = false; + return snd_oxfw_scs1x_add(oxfw); + } /* * TASCAM FireOne has physical control and requires a pair of additional -- cgit v1.2.3 From 36ddd489b0669f8913c8eda192507f8267749917 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 22 Dec 2015 10:16:35 +0800 Subject: ASoC: rt5616: Return error if device ID mismatch Signed-off-by: Axel Lin Acked-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index f4005cbaa99d..0e9414abab65 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1314,7 +1314,7 @@ static int rt5616_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5616\n", val); - ret = -ENODEV; + return -ENODEV; } regmap_write(rt5616->regmap, RT5616_RESET, 0); regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, -- cgit v1.2.3 From c1f2a342846fbfd49ddc06ad7f0684d2c45b419d Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Tue, 22 Dec 2015 11:11:34 +0800 Subject: ASoC: mediatek: Turn AFE on/off in runtime resume/suspend AFE is actually allowed to be turn on before configuration of DAIs since each DAI has its own enabling control. Turn on/off AFE in runtime resume/suspend to avoid AFE being shut down when closing a DAI while other DAIs are still active. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-pcm.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 5399a0eead3e..08af9f5dc4ab 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -382,9 +382,6 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); - - /* disable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); } static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, @@ -433,9 +430,6 @@ static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream, mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], afe->clocks[MTK_CLK_I2S3_B]); - - /* disable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); } static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, @@ -679,17 +673,6 @@ static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream, return snd_pcm_lib_free_pages(substream); } -static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - - /* enable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); - return 0; -} - static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -757,7 +740,6 @@ static const struct snd_soc_dai_ops mtk_afe_dai_ops = { .shutdown = mtk_afe_dais_shutdown, .hw_params = mtk_afe_dais_hw_params, .hw_free = mtk_afe_dais_hw_free, - .prepare = mtk_afe_dais_prepare, .trigger = mtk_afe_dais_trigger, }; @@ -1118,6 +1100,9 @@ static int mtk_afe_runtime_suspend(struct device *dev) { struct mtk_afe *afe = dev_get_drvdata(dev); + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); + /* disable AFE clk */ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE); @@ -1164,6 +1149,9 @@ static int mtk_afe_runtime_resume(struct device *dev) /* unmask all IRQs */ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); return 0; err_bck0: -- cgit v1.2.3 From e17ff2de826f8c2153cf23c8bbd9097219a84fa9 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Tue, 22 Dec 2015 13:45:02 +0800 Subject: ASoC: rt5616: add an of_match table Add a device tree match table. This serves to make the driver's support of device tree more explicit. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 0e9414abab65..7bb56dddff8e 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1287,6 +1287,14 @@ static const struct i2c_device_id rt5616_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id rt5616_of_match[] = { + { .compatible = "realtek,rt5616", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5616_of_match); +#endif + static int rt5616_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1359,6 +1367,7 @@ static void rt5616_i2c_shutdown(struct i2c_client *client) static struct i2c_driver rt5616_i2c_driver = { .driver = { .name = "rt5616", + .of_match_table = of_match_ptr(rt5616_of_match), }, .probe = rt5616_i2c_probe, .remove = rt5616_i2c_remove, -- cgit v1.2.3 From 6b803c611c66debd6fc454c9ed049822994a5885 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 23:00:17 +0100 Subject: ASoC: sun4i-codec: Use proper output for external amp routes An external amp (if any) is connected to the external outputs of the SoC of course, rather then directly to the internal amp. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index e6cc6a14718a..44f170c73b06 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -728,7 +728,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = { }; static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = { - { "Speaker", NULL, "Power Amplifier" }, + { "Speaker", NULL, "HP Right" }, + { "Speaker", NULL, "HP Left" }, }; static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) -- cgit v1.2.3 From e05c25a1af29d65260ed1458f2cc4a959030ebd2 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 3 Dec 2015 17:10:07 +0000 Subject: ASoC: da7218: Enable mic level detection reporting to user-space This patch adds support to the codec driver to handle mic level detect related IRQs, and report these to user-space using a uevent variable. The uevent variable string "EVENT=MIC_LEVEL_DETECT" is sent to user-space, if the mic level detect feature is enabled, and the audio captured at the chosen mic(s) is above a certain threshold. User-space can then handle the event accordingly (e.g. process audio capture stream). This method was chosen over ALSA control notification for a couple of reasons: 1) There's no requirement here for a control to read state from. The event is the only thing that's required and of interest. 2) tinyalsa support for control notifications does not exist so on platforms using this over alsa-lib there is a need to add code to support this event handling. Another possible option would be to use the standard Jack reporting framework but this really does not fit for this kind of event. Finally, use of the input device framework is not being encouraged, due to difficulties in enabling apps to access input devices, so this has also been avoided. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index eacde128c4d6..72686517ff54 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -2202,6 +2202,16 @@ int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack) } EXPORT_SYMBOL_GPL(da7218_hpldet); +static void da7218_micldet_irq(struct snd_soc_codec *codec) +{ + char *envp[] = { + "EVENT=MIC_LEVEL_DETECT", + NULL, + }; + + kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp); +} + static void da7218_hpldet_irq(struct snd_soc_codec *codec) { struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); @@ -2232,6 +2242,10 @@ static irqreturn_t da7218_irq_thread(int irq, void *data) if (!status) return IRQ_NONE; + /* Mic level detect */ + if (status & DA7218_LVL_DET_EVENT_MASK) + da7218_micldet_irq(codec); + /* HP detect */ if (status & DA7218_HPLDET_JACK_EVENT_MASK) da7218_hpldet_irq(codec); @@ -2936,11 +2950,6 @@ static int da7218_probe(struct snd_soc_codec *codec) } if (da7218->irq) { - /* Mask off mic level events, currently not handled */ - snd_soc_update_bits(codec, DA7218_EVENT_MASK, - DA7218_LVL_DET_EVENT_MSK_MASK, - DA7218_LVL_DET_EVENT_MSK_MASK); - ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL, da7218_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, -- cgit v1.2.3 From b4c83b171557815a0b31a36805900cc9f21c9ee4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Dec 2015 03:00:10 +0000 Subject: ASoC: rsnd: add Multi channel support This patch adds Multi channel support on Renesas R-Car sound. This patch is tested on Salvator-X board, but it can't use Multi channel, because supported format is different between codec chip and R-Car. Thus, it was tested on board which doesn't mount codec chip, with oscilloscope. Signed-off-by: Kuninori Morimoto Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.txt | 18 ++++ sound/soc/sh/rcar/core.c | 6 +- sound/soc/sh/rcar/gen.c | 3 + sound/soc/sh/rcar/rsnd.h | 15 ++- sound/soc/sh/rcar/ssi.c | 114 ++++++++++++++++++++- sound/soc/sh/rcar/ssiu.c | 55 ++++++++-- 6 files changed, 194 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 162e94c8305c..8ee0fa91e4a0 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -308,3 +308,21 @@ Example: simple sound card for TDM sound-dai = <&xxx>; }; }; + +Example: simple sound card for Multi channel + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + status = "okay"; + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; + }; + }; +}; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7781cef634d4..ca05a0a95a4d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -215,7 +215,11 @@ int rsnd_get_slot_num(struct rsnd_dai_stream *io) int rsnd_get_slot_width(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int chan = runtime->channels / rsnd_get_slot_num(io); + int chan = runtime->channels; + + /* Multi channel Mode */ + if (rsnd_ssi_multi_slaves(io)) + chan /= rsnd_get_slot_num(io); /* TDM Extend Mode needs 8ch */ if (chan == 6) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 7c5485e46fd7..c7aee9e59e86 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -226,6 +226,9 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) const static struct rsnd_regmap_field_conf conf_ssiu[] = { RSND_GEN_S_REG(SSI_MODE0, 0x800), RSND_GEN_S_REG(SSI_MODE1, 0x804), + RSND_GEN_S_REG(SSI_MODE2, 0x808), + RSND_GEN_S_REG(SSI_CONTROL, 0x810), + /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f803e140e733..317dd793149a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -47,6 +47,8 @@ enum rsnd_reg { RSND_REG_SSI_MODE, /* Gen2 only */ RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, + RSND_REG_SSI_MODE2, + RSND_REG_SSI_CONTROL, RSND_REG_SSI_CTRL, /* Gen2 only */ RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ @@ -181,7 +183,10 @@ enum rsnd_mod_type { RSND_MOD_CTU, RSND_MOD_CMD, RSND_MOD_SRC, - RSND_MOD_SSIP, /* SSI parent */ + RSND_MOD_SSIM3, /* SSI multi 3 */ + RSND_MOD_SSIM2, /* SSI multi 2 */ + RSND_MOD_SSIM1, /* SSI multi 1 */ + RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, RSND_MOD_SSIU, RSND_MOD_MAX, @@ -542,6 +547,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); +u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io); #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) @@ -549,10 +555,9 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); #define rsnd_ssi_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") -#define rsnd_parse_connect_ssi(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, rsnd_ssi_mod_get, \ - rsnd_ssi_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture); /* * R-Car SSIU diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0b91692c5a66..7db05fdfb656 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -96,6 +96,7 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_mode_flags(p) ((p)->flags) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) +#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io)) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { @@ -171,6 +172,41 @@ static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) return 0; } +u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *mod; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + enum rsnd_mod_type types[] = { + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + int i, mask; + + switch (runtime->channels) { + case 2: /* Multi channel is not needed for Stereo */ + return 0; + case 6: + break; + default: + dev_err(dev, "unsupported channel\n"); + return 0; + } + + mask = 0; + for (i = 0; i < ARRAY_SIZE(types); i++) { + mod = rsnd_io_to_mod(io, types[i]); + if (!mod) + continue; + + mask |= 1 << rsnd_mod_id(mod); + } + + return mask; +} + static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_dai_stream *io) { @@ -194,6 +230,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) return 0; + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + if (ssi->usrcnt > 1) { if (ssi->rate != rate) { dev_err(dev, "SSI parent/child should use same rate\n"); @@ -437,8 +476,14 @@ static int __rsnd_ssi_start(struct rsnd_mod *mod, cr = ssi->cr_own | ssi->cr_clk | - ssi->cr_mode | - EN; + ssi->cr_mode; + + /* + * EN will be set via SSIU :: SSI_CONTROL + * if Multi channel mode + */ + if (!rsnd_ssi_multi_slaves(io)) + cr |= EN; rsnd_mod_write(mod, SSICR, cr); rsnd_mod_write(mod, SSIWSR, ssi->wsr); @@ -609,6 +654,13 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; + /* + * SSIP/SSIU/IRQ are not needed on + * SSI Multi slaves + */ + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + rsnd_ssi_parent_attach(mod, io, priv); ret = rsnd_ssiu_attach(io, mod); @@ -641,6 +693,13 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, int dma_id = 0; /* not needed */ int ret; + /* + * SSIP/SSIU/IRQ/DMA are not needed on + * SSI Multi slaves + */ + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + ret = rsnd_ssi_common_probe(mod, io, priv); if (ret) return ret; @@ -732,6 +791,57 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { /* * ssi mod function */ +static void rsnd_ssi_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + enum rsnd_mod_type types[] = { + RSND_MOD_SSI, + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + enum rsnd_mod_type type; + int i; + + /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ + for (i = 0; i < ARRAY_SIZE(types); i++) { + type = types[i]; + if (!rsnd_io_to_mod(io, type)) { + rsnd_dai_connect(mod, io, type); + rsnd_set_slot(rdai, 2 * (i + 1), (i + 1)); + return; + } + } +} + +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device_node *node; + struct device_node *np; + struct rsnd_mod *mod; + int i; + + node = rsnd_ssi_of_node(priv); + if (!node) + return; + + i = 0; + for_each_child_of_node(node, np) { + mod = rsnd_ssi_mod_get(priv, i); + if (np == playback) + rsnd_ssi_connect(mod, &rdai->playback); + if (np == capture) + rsnd_ssi_connect(mod, &rdai->capture); + i++; + } + + of_node_put(node); +} + struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) { if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 7ae05a7621ae..3fe9e08e81a3 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -27,8 +27,11 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io); int use_busif = rsnd_ssi_use_busif(io); int id = rsnd_mod_id(mod); + u32 mask1, val1; + u32 mask2, val2; /* * SSI_MODE0 @@ -38,6 +41,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, /* * SSI_MODE1 */ + mask1 = (1 << 4) | (1 << 20); /* mask sync bit */ + mask2 = (1 << 4); /* mask sync bit */ + val1 = val2 = 0; if (rsnd_ssi_is_pin_sharing(io)) { int shift = -1; @@ -51,15 +57,36 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, case 4: shift = 16; break; + default: + return -EINVAL; } - if (shift >= 0) - rsnd_mod_bset(mod, SSI_MODE1, - 0x3 << shift, - rsnd_rdai_is_clk_master(rdai) ? - 0x2 << shift : 0x1 << shift); + mask1 |= 0x3 << shift; + val1 = rsnd_rdai_is_clk_master(rdai) ? + 0x2 << shift : 0x1 << shift; + + } else if (multi_ssi_slaves) { + + mask2 |= 0x00000007; + mask1 |= 0x0000000f; + + switch (multi_ssi_slaves) { + case 0x0206: /* SSI0/1/2/9 */ + val2 = (1 << 4) | /* SSI0129 sync */ + rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1; + /* fall through */ + case 0x0006: /* SSI0/1/2 */ + val1 = rsnd_rdai_is_clk_master(rdai) ? + 0xa : 0x5; + + if (!val2) /* SSI012 sync */ + val1 |= (1 << 4); + } } + rsnd_mod_bset(mod, SSI_MODE1, mask1, val1); + rsnd_mod_bset(mod, SSI_MODE2, mask2, val2); + return 0; } @@ -104,8 +131,13 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - if (rsnd_ssi_use_busif(io)) - rsnd_mod_write(mod, SSI_CTRL, 0x1); + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_write(mod, SSI_CTRL, 0x1); + + if (rsnd_ssi_multi_slaves(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0x1); return 0; } @@ -114,8 +146,13 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - if (rsnd_ssi_use_busif(io)) - rsnd_mod_write(mod, SSI_CTRL, 0); + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_write(mod, SSI_CTRL, 0); + + if (rsnd_ssi_multi_slaves(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0); return 0; } -- cgit v1.2.3 From bfbcab7c2d8ab4cb52f0785d7381d20f39bb065b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 20 Dec 2015 10:34:25 +0100 Subject: ASoC: ssm2518: Use a signed return type for ssm2518_lookup_mcs() The return type "unsigned int" was used by the ssm2518_lookup_mcs() function even though it will eventually return a negative error code. Improve this implementation detail by deletion of the type modifier then. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2518.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 86b81a60ac52..e2e0bfa7ec20 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -309,7 +309,7 @@ static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = { .count = ARRAY_SIZE(ssm2518_rates_12288000), }; -static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, +static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, unsigned int rate) { const unsigned int *sysclks = NULL; -- cgit v1.2.3 From 10974ccf04b096fd79ad90fd50276b79c069f2cc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 20 Dec 2015 12:15:50 +0100 Subject: ASoC: imx-pcm-dma: add NULL test Add NULL test on call to devm_kzalloc. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; @@ * x = devm_kzalloc(...); ... when != x == NULL *x // Signed-off-by: Julia Lawall Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-dma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 1fc01ed3279d..f3d3d1ffa84e 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -62,6 +62,8 @@ int imx_pcm_dma_init(struct platform_device *pdev, size_t size) config = devm_kzalloc(&pdev->dev, sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); + if (!config) + return -ENOMEM; *config = imx_dmaengine_pcm_config; if (size) config->prealloc_buffer_size = size; -- cgit v1.2.3 From 18c94a043d6a466938f13761081a5cbee802dad1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 20 Dec 2015 12:15:51 +0100 Subject: ASoC: omap-hdmi-audio: add NULL test Add NULL test on call to devm_kzalloc. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; identifier fld; @@ * x = devm_kzalloc(...); ... when != x == NULL x->fld // Signed-off-by: Julia Lawall Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi-audio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 584b2372339e..f83cc2bc0fc4 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -368,6 +368,8 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dai_link = devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL); + if (!card->dai_link) + return -ENOMEM; card->dai_link->name = card->name; card->dai_link->stream_name = card->name; card->dai_link->cpu_dai_name = dev_name(ad->dssdev); -- cgit v1.2.3 From 3f317c9faabc546a503bc62e806fa2e8e93e76be Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 20 Dec 2015 12:15:53 +0100 Subject: ASoC: Intel: add NULL test Add NULL test on call to devm_kzalloc. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; identifier fld; @@ * x = devm_kzalloc(...); ... when != x == NULL x->fld // Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 79547bec558b..4765ad474544 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -377,6 +377,8 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform) priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; priv_data->byt = plat_data->dsp; snd_soc_platform_set_drvdata(platform, priv_data); -- cgit v1.2.3 From e2133b64820df302a8e3d00c7531018470cd63a9 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 21 Dec 2015 10:09:53 +0800 Subject: ASoC: rt5616: rename some alsa control names Rename some alsa control name as what they should be. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 7bb56dddff8e..1c10d8ed39d2 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -323,9 +323,9 @@ static const struct snd_kcontrol_new rt5616_snd_controls[] = { RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 175, 0, dac_vol_tlv), /* IN1/IN2 Control */ - SOC_SINGLE_TLV("IN1 Boost", RT5616_IN1_IN2, + SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2, RT5616_BST_SFT1, 8, 0, bst_tlv), - SOC_SINGLE_TLV("IN2 Boost", RT5616_IN1_IN2, + SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2, RT5616_BST_SFT2, 8, 0, bst_tlv), /* INL/INR Volume Control */ SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL, @@ -339,7 +339,7 @@ static const struct snd_kcontrol_new rt5616_snd_controls[] = { 127, 0, adc_vol_tlv), /* ADC Boost Volume Control */ - SOC_DOUBLE_TLV("ADC Boost Gain", RT5616_ADC_BST_VOL, + SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL, RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), }; -- cgit v1.2.3 From 50860e1d17d1bc2f1a2ebfc5042f2af786e53ad6 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 22 Dec 2015 14:06:42 +0800 Subject: ASoC: atmel_wm8904: add snd_soc_pm_ops Sometimes the audio play can not be resumed after it is suspended. Add snd_soc_pm_ops to execute power management operations, then this issue is fixed. Signed-off-by: Songjun Wu Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_wm8904.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 1933bcd46cca..fdd28ed3e0b9 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -183,6 +183,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = { .driver = { .name = "atmel-wm8904-audio", .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids), + .pm = &snd_soc_pm_ops, }, .probe = atmel_asoc_wm8904_probe, .remove = atmel_asoc_wm8904_remove, -- cgit v1.2.3 From fff6e03c7b659bfa2fa001b0ede71e4830a84b56 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Fri, 18 Dec 2015 17:00:09 +0800 Subject: ASoC: fsl_asrc: add support for 8-30kHz output sample rate Add 8kHz, 11.025kHz, 16kHz, 22.05kHz output sample rate support. According referance menual, "Limited support for the case when output sampling rates is between 8kHz and 30kHz. The limitation is the supported ratio (Fsin/Fsout) range as between 1/24 to 8." Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index cf382475670b..7b811485a8e5 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -31,21 +31,21 @@ dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) /* Sample rates are aligned with that defined in pcm.h file */ -static const u8 process_option[][8][2] = { - /* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ - {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ - {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ - {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ - {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ - {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ +static const u8 process_option[][12][2] = { + /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ + {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ + {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ + {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ + {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ + {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ + {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ }; /* Corresponding to process_option */ @@ -55,7 +55,7 @@ static int supported_input_rate[] = { }; static int supported_asrc_rate[] = { - 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; /** @@ -286,6 +286,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) return -EINVAL; } + if ((outrate > 8000 && outrate < 30000) && + (outrate/inrate > 24 || inrate/outrate > 8)) { + pair_err("exceed supported ratio range [1/24, 8] for \ + inrate/outrate: %d/%d\n", inrate, outrate); + return -EINVAL; + } + /* Validate input and output clock sources */ clk_index[IN] = clk_map[IN][config->inclk]; clk_index[OUT] = clk_map[OUT][config->outclk]; -- cgit v1.2.3 From 25e5ef974c33f1e4a07a68bf830e6493ee6dab11 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 20 Dec 2015 21:34:29 +0100 Subject: ASoC: fsl-asoc-card: use different route map for AC'97 mode fsl_ssi uses different stream names ("AC97 Playback" / "AC97 Capture") in AC'97 mode so in this case fsl-asoc-card route map should also be using them. Signed-off-by: Maciej S. Szmigiero Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 1b05d1c5d9fd..6fb3aed91b44 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -107,6 +107,13 @@ static const struct snd_soc_dapm_route audio_map[] = { {"CPU-Capture", NULL, "Capture"}, }; +static const struct snd_soc_dapm_route audio_map_ac97[] = { + {"AC97 Playback", NULL, "ASRC-Playback"}, + {"Playback", NULL, "AC97 Playback"}, + {"ASRC-Capture", NULL, "AC97 Capture"}, + {"AC97 Capture", NULL, "Capture"}, +}; + /* Add all possible widgets into here without being redundant */ static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { SND_SOC_DAPM_LINE("Line Out Jack", NULL), @@ -574,7 +581,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dev = &pdev->dev; priv->card.name = priv->name; priv->card.dai_link = priv->dai_link; - priv->card.dapm_routes = audio_map; + priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ? + audio_map_ac97 : audio_map; priv->card.late_probe = fsl_asoc_card_late_probe; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; -- cgit v1.2.3 From fdd50a8086422caa456b5f8abb631dda6c551744 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:52 +0000 Subject: ASoC: da7219: Fix Sidetone to work regardless of DAI capture Previously Sidetone would operate only when capture to DAI was in progress, due to DAPM path configuration. There is no reason why this should not operate without DAI capture, so this patch updates the DAPM path accordingly. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e36a7b79b494..319e794d27f6 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -968,10 +968,11 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = { {"Mixin PGA", NULL, "Mic PGA"}, {"ADC", NULL, "Mixin PGA"}, - {"Sidetone Filter", NULL, "ADC"}, {"Mixer In", NULL, "Mixer In Supply"}, {"Mixer In", "Mic Switch", "ADC"}, + {"Sidetone Filter", NULL, "Mixer In"}, + {"Tone Generator", NULL, "TONE"}, DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"), -- cgit v1.2.3 From 9069bf9bc839d97e07fe17c336eab095c1065cec Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:51 +0000 Subject: ASoC: da7219: Disable regulators on probe() failure If codec probe() function fails after supplies have been enabled it should really tidy up and disable them again. This patch updates the probe function to do just that. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 319e794d27f6..9136a8b6f593 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1663,10 +1663,12 @@ static int da7219_probe(struct snd_soc_codec *codec) /* Check if MCLK provided */ da7219->mclk = devm_clk_get(codec->dev, "mclk"); if (IS_ERR(da7219->mclk)) { - if (PTR_ERR(da7219->mclk) != -ENOENT) - return PTR_ERR(da7219->mclk); - else + if (PTR_ERR(da7219->mclk) != -ENOENT) { + ret = PTR_ERR(da7219->mclk); + goto err_disable_reg; + } else { da7219->mclk = NULL; + } } /* Default PC counter to free-running */ @@ -1694,7 +1696,16 @@ static int da7219_probe(struct snd_soc_codec *codec) snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); /* Initialise AAD block */ - return da7219_aad_init(codec); + ret = da7219_aad_init(codec); + if (ret) + goto err_disable_reg; + + return 0; + +err_disable_reg: + regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies); + + return ret; } static int da7219_remove(struct snd_soc_codec *codec) -- cgit v1.2.3 From 9ff099790412cb46536efba02039b36d81300976 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:53 +0000 Subject: ASoC: da7219: Update REFERENCES reg default, in-line with HW In current AB silicon, BIAS_EN field is enabled by default in the REFERENCES register, so the regmap default value should reflect this. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 9136a8b6f593..0a177ae8e0c3 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1788,7 +1788,7 @@ static struct reg_default da7219_reg_defaults[] = { { DA7219_DIG_ROUTING_DAC, 0x32 }, { DA7219_DAI_OFFSET_LOWER, 0x00 }, { DA7219_DAI_OFFSET_UPPER, 0x00 }, - { DA7219_REFERENCES, 0x00 }, + { DA7219_REFERENCES, 0x08 }, { DA7219_MIXIN_L_SELECT, 0x00 }, { DA7219_MIXIN_L_GAIN, 0x03 }, { DA7219_ADC_L_GAIN, 0x6F }, -- cgit v1.2.3 From d8ef140dccc1645aa37a140ed7585458294210b8 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:54 +0000 Subject: ASoC: da7219: Remove internal LDO features of codec In AB silicon, the internal LDO is not supported so remove DT and driver references to this (digital voltage direct from 'VDD' supply) Signed-off-by: Adam Thomson Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/da7219.txt | 6 ++- include/sound/da7219.h | 11 ----- sound/soc/codecs/da7219.c | 50 +--------------------- sound/soc/codecs/da7219.h | 7 --- 4 files changed, 6 insertions(+), 68 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt index 1b7030911a3b..062a2a08250e 100644 --- a/Documentation/devicetree/bindings/sound/da7219.txt +++ b/Documentation/devicetree/bindings/sound/da7219.txt @@ -28,13 +28,15 @@ Optional properties: - clocks : phandle and clock specifier for codec MCLK. - clock-names : Clock name string for 'clocks' attribute, should be "mclk". -- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine - [<1050>, <1100>, <1200>, <1400>] - dlg,micbias-lvl : Voltage (mV) for Mic Bias [<1800>, <2000>, <2200>, <2400>, <2600>] - dlg,mic-amp-in-sel : Mic input source type ["diff", "se_p", "se_n"] +Deprecated properties: +- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine + (LDO unavailable in production HW so property no longer required). + ====== Child node - 'da7219_aad': diff --git a/include/sound/da7219.h b/include/sound/da7219.h index 3f39e135312d..307198b469bc 100644 --- a/include/sound/da7219.h +++ b/include/sound/da7219.h @@ -14,14 +14,6 @@ #ifndef __DA7219_PDATA_H #define __DA7219_PDATA_H -/* LDO */ -enum da7219_ldo_lvl_sel { - DA7219_LDO_LVL_SEL_1_05V = 0, - DA7219_LDO_LVL_SEL_1_10V, - DA7219_LDO_LVL_SEL_1_20V, - DA7219_LDO_LVL_SEL_1_40V, -}; - /* Mic Bias */ enum da7219_micbias_voltage { DA7219_MICBIAS_1_8V = 1, @@ -41,9 +33,6 @@ enum da7219_mic_amp_in_sel { struct da7219_aad_pdata; struct da7219_pdata { - /* Internal LDO */ - enum da7219_ldo_lvl_sel ldo_lvl_sel; - /* Mic */ enum da7219_micbias_voltage micbias_lvl; enum da7219_mic_amp_in_sel mic_amp_in_sel; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 0a177ae8e0c3..2630c503e3df 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1406,24 +1406,6 @@ static const struct of_device_id da7219_of_match[] = { }; MODULE_DEVICE_TABLE(of, da7219_of_match); -static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec, - u32 val) -{ - switch (val) { - case 1050: - return DA7219_LDO_LVL_SEL_1_05V; - case 1100: - return DA7219_LDO_LVL_SEL_1_10V; - case 1200: - return DA7219_LDO_LVL_SEL_1_20V; - case 1400: - return DA7219_LDO_LVL_SEL_1_40V; - default: - dev_warn(codec->dev, "Invalid LDO level"); - return DA7219_LDO_LVL_SEL_1_05V; - } -} - static enum da7219_micbias_voltage da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) { @@ -1470,9 +1452,6 @@ static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec) if (!pdata) return NULL; - if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0) - pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32); - if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0) pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32); else @@ -1517,24 +1496,13 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, DA7219_BIAS_EN_MASK); - - /* Enable Internal Digital LDO */ - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_EN_MASK, - DA7219_LDO_EN_MASK); } break; case SND_SOC_BIAS_OFF: - /* Only disable if jack detection not active */ - if (!da7219->aad->jack) { - /* Bypass Internal Digital LDO */ - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_EN_MASK, 0); - - /* Master bias */ + /* Only disable master bias if jack detection not active */ + if (!da7219->aad->jack) snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, 0); - } /* MCLK */ if (da7219->mclk) @@ -1601,19 +1569,6 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) if (pdata) { u8 micbias_lvl = 0; - /* Internal LDO */ - switch (pdata->ldo_lvl_sel) { - case DA7219_LDO_LVL_SEL_1_05V: - case DA7219_LDO_LVL_SEL_1_10V: - case DA7219_LDO_LVL_SEL_1_20V: - case DA7219_LDO_LVL_SEL_1_40V: - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_LEVEL_SELECT_MASK, - (pdata->ldo_lvl_sel << - DA7219_LDO_LEVEL_SELECT_SHIFT)); - break; - } - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_8V: @@ -1823,7 +1778,6 @@ static struct reg_default da7219_reg_defaults[] = { { DA7219_CHIP_ID1, 0x23 }, { DA7219_CHIP_ID2, 0x93 }, { DA7219_CHIP_REVISION, 0x00 }, - { DA7219_LDO_CTRL, 0x00 }, { DA7219_IO_CTRL, 0x00 }, { DA7219_GAIN_RAMP_CTRL, 0x00 }, { DA7219_PC_COUNT, 0x02 }, diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index b514268c6c56..2b3f4471a17f 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -85,7 +85,6 @@ #define DA7219_CHIP_ID1 0x81 #define DA7219_CHIP_ID2 0x82 #define DA7219_CHIP_REVISION 0x83 -#define DA7219_LDO_CTRL 0x90 #define DA7219_IO_CTRL 0x91 #define DA7219_GAIN_RAMP_CTRL 0x92 #define DA7219_PC_COUNT 0x94 @@ -569,12 +568,6 @@ #define DA7219_CHIP_MAJOR_SHIFT 4 #define DA7219_CHIP_MAJOR_MASK (0xF << 4) -/* DA7219_LDO_CTRL = 0x90 */ -#define DA7219_LDO_LEVEL_SELECT_SHIFT 4 -#define DA7219_LDO_LEVEL_SELECT_MASK (0x3 << 4) -#define DA7219_LDO_EN_SHIFT 7 -#define DA7219_LDO_EN_MASK (0x1 << 7) - /* DA7219_IO_CTRL = 0x91 */ #define DA7219_IO_VOLTAGE_LEVEL_SHIFT 0 #define DA7219_IO_VOLTAGE_LEVEL_MASK (0x1 << 0) -- cgit v1.2.3 From 0aed64c1766d354c819a13a57d8673adaf2266eb Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:55 +0000 Subject: ASoC: da7219: Add support for 1.6V micbias level HW can provide 1.6V micbias level as well the existing levels already provided in the driver. This patch adds support for 1.6V to the DT binding. Signed-off-by: Adam Thomson Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/da7219.txt | 2 +- include/sound/da7219.h | 3 ++- sound/soc/codecs/da7219.c | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt index 062a2a08250e..cf61681826b6 100644 --- a/Documentation/devicetree/bindings/sound/da7219.txt +++ b/Documentation/devicetree/bindings/sound/da7219.txt @@ -29,7 +29,7 @@ Optional properties: - clock-names : Clock name string for 'clocks' attribute, should be "mclk". - dlg,micbias-lvl : Voltage (mV) for Mic Bias - [<1800>, <2000>, <2200>, <2400>, <2600>] + [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>] - dlg,mic-amp-in-sel : Mic input source type ["diff", "se_p", "se_n"] diff --git a/include/sound/da7219.h b/include/sound/da7219.h index 307198b469bc..02876acdc840 100644 --- a/include/sound/da7219.h +++ b/include/sound/da7219.h @@ -16,7 +16,8 @@ /* Mic Bias */ enum da7219_micbias_voltage { - DA7219_MICBIAS_1_8V = 1, + DA7219_MICBIAS_1_6V = 0, + DA7219_MICBIAS_1_8V, DA7219_MICBIAS_2_0V, DA7219_MICBIAS_2_2V, DA7219_MICBIAS_2_4V, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 2630c503e3df..371768092e17 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1410,6 +1410,8 @@ static enum da7219_micbias_voltage da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) { switch (val) { + case 1600: + return DA7219_MICBIAS_1_6V; case 1800: return DA7219_MICBIAS_1_8V; case 2000: @@ -1571,6 +1573,7 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) /* Mic Bias voltages */ switch (pdata->micbias_lvl) { + case DA7219_MICBIAS_1_6V: case DA7219_MICBIAS_1_8V: case DA7219_MICBIAS_2_0V: case DA7219_MICBIAS_2_2V: -- cgit v1.2.3 From 501f72e9c5205b9d70d5d61e9b186ae7ba873f73 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 22 Dec 2015 18:27:56 +0000 Subject: ASoC: da7219: Remove support for 32KHz PLL mode PLL mode based on 32KHz master clock not supported in AB silicon so remove support from the driver. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 10 ++-------- sound/soc/codecs/da7219.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 371768092e17..c6d3b32bb4ae 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1074,11 +1074,8 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ - if (da7219->mclk_rate == 32768) { - indiv_bits = DA7219_PLL_INDIV_2_5_MHZ; - indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL; - } else if (da7219->mclk_rate < 2000000) { + /* Verify 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7219->mclk_rate < 2000000) { dev_err(codec->dev, "PLL input clock %d below valid range\n", da7219->mclk_rate); return -EINVAL; @@ -1119,9 +1116,6 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, case DA7219_SYSCLK_PLL_SRM: pll_ctrl |= DA7219_PLL_MODE_SRM; break; - case DA7219_SYSCLK_PLL_32KHZ: - pll_ctrl |= DA7219_PLL_MODE_32KHZ; - break; default: dev_err(codec->dev, "Invalid PLL config\n"); return -EINVAL; diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 2b3f4471a17f..5a787e738084 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -206,7 +206,6 @@ #define DA7219_PLL_MODE_BYPASS (0x0 << 6) #define DA7219_PLL_MODE_NORMAL (0x1 << 6) #define DA7219_PLL_MODE_SRM (0x2 << 6) -#define DA7219_PLL_MODE_32KHZ (0x3 << 6) /* DA7219_PLL_FRAC_TOP = 0x22 */ #define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT 0 @@ -780,7 +779,6 @@ enum da7219_sys_clk { DA7219_SYSCLK_MCLK = 0, DA7219_SYSCLK_PLL, DA7219_SYSCLK_PLL_SRM, - DA7219_SYSCLK_PLL_32KHZ }; /* Regulators */ -- cgit v1.2.3 From 1d981e0a5af78339d55085041c6eb3b9a8626920 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Dec 2015 11:29:42 +0000 Subject: ASoC: wm5110: Provide basic hookup for voice control Register a platform driver for the CODEC and add DAIs that will be used to connect a compressed record path for the voice control functionality. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/arizona.h | 2 +- sound/soc/codecs/wm5110.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 55e14a3ed5e1..4f482f7b63fc 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -214,6 +214,7 @@ config SND_SOC_WM_HUBS config SND_SOC_WM_ADSP tristate + select SND_SOC_COMPRESS default y if SND_SOC_CS47L24=y default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index b4f1867ae9d6..8b6adb5419bb 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -57,7 +57,7 @@ #define ARIZONA_CLK_98MHZ 5 #define ARIZONA_CLK_147MHZ 6 -#define ARIZONA_MAX_DAI 6 +#define ARIZONA_MAX_DAI 8 #define ARIZONA_MAX_ADSP 4 #define ARIZONA_DVFS_SR1_RQ 0x001 diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index e93e5420943e..67d56511699a 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1810,6 +1810,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "Slim2 Capture", NULL, "SYSCLK" }, { "Slim3 Capture", NULL, "SYSCLK" }, + { "Voice Control DSP", NULL, "DSP3" }, + { "Voice Control DSP", NULL, "SYSCLK" }, + { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -2132,6 +2135,27 @@ static struct snd_soc_dai_driver wm5110_dai[] = { }, .ops = &arizona_simple_dai_ops, }, + { + .name = "wm5110-cpu-voicectrl", + .capture = { + .stream_name = "Voice Control CPU", + .channels_min = 1, + .channels_max = 1, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "wm5110-dsp-voicectrl", + .capture = { + .stream_name = "Voice Control DSP", + .channels_min = 1, + .channels_max = 1, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + }, }; static int wm5110_codec_probe(struct snd_soc_codec *codec) @@ -2224,6 +2248,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), }; +static struct snd_compr_ops wm5110_compr_ops = { +}; + +static struct snd_soc_platform_driver wm5110_compr_platform = { + .compr_ops = &wm5110_compr_ops, +}; + static int wm5110_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -2284,8 +2315,21 @@ static int wm5110_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, + ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); + goto error; + } + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, wm5110_dai, ARRAY_SIZE(wm5110_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + snd_soc_unregister_platform(&pdev->dev); + } + +error: + return ret; } static int wm5110_remove(struct platform_device *pdev) -- cgit v1.2.3 From 14197095e14a4ad2afb6c8c1ca8e41852382481d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Dec 2015 11:29:43 +0000 Subject: ASoC: wm_adsp: Factor out finding the location of an algorithm region Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d1e0826c7db2..27abad9c6e73 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1365,6 +1365,19 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, return alg; } +static struct wm_adsp_alg_region * + wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id) +{ + struct wm_adsp_alg_region *alg_region; + + list_for_each_entry(alg_region, &dsp->alg_regions, list) { + if (id == alg_region->alg && type == alg_region->type) + return alg_region; + } + + return NULL; +} + static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, int type, __be32 id, __be32 base) @@ -1737,22 +1750,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) break; } - reg = 0; - list_for_each_entry(alg_region, - &dsp->alg_regions, list) { - if (le32_to_cpu(blk->id) == alg_region->alg && - type == alg_region->type) { - reg = alg_region->base; - reg = wm_adsp_region_to_reg(mem, - reg); - reg += offset; - break; - } - } - - if (reg == 0) + alg_region = wm_adsp_find_alg_region(dsp, type, + le32_to_cpu(blk->id)); + if (alg_region) { + reg = alg_region->base; + reg = wm_adsp_region_to_reg(mem, reg); + reg += offset; + } else { adsp_err(dsp, "No %x for algorithm %x\n", type, le32_to_cpu(blk->id)); + } break; default: -- cgit v1.2.3 From 406abc95a0397e10eb6edcfe824b1a8bf6578a0b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Dec 2015 11:29:45 +0000 Subject: ASoC: wm_adsp: Add support for opening a compressed stream Allow user-space to open a compressed stream, although no data will be passed yet, as part of this adding the ability to define supported capabilities per firmware and check these match the stream being opened. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 23 ++++++ sound/soc/codecs/wm_adsp.c | 194 ++++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/wm_adsp.h | 13 +++ 3 files changed, 227 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 67d56511699a..8c0fd9106be0 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2158,6 +2158,25 @@ static struct snd_soc_dai_driver wm5110_dai[] = { }, }; +static int wm5110_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct arizona *arizona = priv->core.arizona; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) { + n_adsp = 2; + } else { + dev_err(arizona->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream); +} + static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); @@ -2249,6 +2268,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { }; static struct snd_compr_ops wm5110_compr_ops = { + .open = wm5110_open, + .free = wm_adsp_compr_free, + .set_params = wm_adsp_compr_set_params, + .get_caps = wm_adsp_compr_get_caps, }; static struct snd_soc_platform_driver wm5110_compr_platform = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 27abad9c6e73..d81ed218918e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -229,8 +229,42 @@ static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { [WM_ADSP_FW_MISC] = "Misc", }; -static struct { +struct wm_adsp_compr { + struct wm_adsp *dsp; + + struct snd_compr_stream *stream; + struct snd_compressed_buffer size; +}; + +#define WM_ADSP_DATA_WORD_SIZE 3 + +#define WM_ADSP_MIN_FRAGMENTS 1 +#define WM_ADSP_MAX_FRAGMENTS 256 +#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE) +#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE) + +struct wm_adsp_fw_caps { + u32 id; + struct snd_codec_desc desc; +}; + +static const struct wm_adsp_fw_caps ez2control_caps[] = { + { + .id = SND_AUDIOCODEC_BESPOKE, + .desc = { + .max_ch = 1, + .sample_rates = { 16000 }, + .num_sample_rates = 1, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + +static const struct { const char *file; + int compr_direction; + int num_caps; + const struct wm_adsp_fw_caps *caps; } wm_adsp_fw[WM_ADSP_NUM_FW] = { [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, [WM_ADSP_FW_HIFI] = { .file = "hifi" }, @@ -238,7 +272,12 @@ static struct { [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, [WM_ADSP_FW_RX] = { .file = "rx" }, [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, - [WM_ADSP_FW_CTRL] = { .file = "ctrl" }, + [WM_ADSP_FW_CTRL] = { + .file = "ctrl", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(ez2control_caps), + .caps = ez2control_caps, + }, [WM_ADSP_FW_ASR] = { .file = "asr" }, [WM_ADSP_FW_TRACE] = { .file = "trace" }, [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, @@ -461,7 +500,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, mutex_lock(&dsp[e->shift_l].pwr_lock); - if (dsp[e->shift_l].running) + if (dsp[e->shift_l].running || dsp[e->shift_l].compr) ret = -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; @@ -2178,4 +2217,153 @@ int wm_adsp2_init(struct wm_adsp *dsp) } EXPORT_SYMBOL_GPL(wm_adsp2_init); +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + if (wm_adsp_fw[dsp->fw].num_caps == 0) { + adsp_err(dsp, "Firmware does not support compressed API\n"); + ret = -ENXIO; + goto out; + } + + if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { + adsp_err(dsp, "Firmware does not support stream direction\n"); + ret = -EINVAL; + goto out; + } + + compr = kzalloc(sizeof(*compr), GFP_KERNEL); + if (!compr) { + ret = -ENOMEM; + goto out; + } + + compr->dsp = dsp; + compr->stream = stream; + + dsp->compr = compr; + + stream->runtime->private_data = compr; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_open); + +int wm_adsp_compr_free(struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + + mutex_lock(&dsp->pwr_lock); + + dsp->compr = NULL; + + kfree(compr); + + mutex_unlock(&dsp->pwr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_free); + +static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + const struct wm_adsp_fw_caps *caps; + const struct snd_codec_desc *desc; + int i, j; + + if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE || + params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE || + params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || + params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || + params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { + adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n", + params->buffer.fragment_size, + params->buffer.fragments); + + return -EINVAL; + } + + for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) { + caps = &wm_adsp_fw[dsp->fw].caps[i]; + desc = &caps->desc; + + if (caps->id != params->codec.id) + continue; + + if (stream->direction == SND_COMPRESS_PLAYBACK) { + if (desc->max_ch < params->codec.ch_out) + continue; + } else { + if (desc->max_ch < params->codec.ch_in) + continue; + } + + if (!(desc->formats & (1 << params->codec.format))) + continue; + + for (j = 0; j < desc->num_sample_rates; ++j) + if (desc->sample_rates[j] == params->codec.sample_rate) + return 0; + } + + adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", + params->codec.id, params->codec.ch_in, params->codec.ch_out, + params->codec.sample_rate, params->codec.format); + return -EINVAL; +} + +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + int ret; + + ret = wm_adsp_compr_check_params(stream, params); + if (ret) + return ret; + + compr->size = params->buffer; + + adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", + compr->size.fragment_size, compr->size.fragments); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); + +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + int fw = compr->dsp->fw; + int i; + + if (wm_adsp_fw[fw].caps) { + for (i = 0; i < wm_adsp_fw[fw].num_caps; i++) + caps->codecs[i] = wm_adsp_fw[fw].caps[i].id; + + caps->num_codecs = i; + caps->direction = wm_adsp_fw[fw].compr_direction; + + caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE; + caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE; + caps->min_fragments = WM_ADSP_MIN_FRAGMENTS; + caps->max_fragments = WM_ADSP_MAX_FRAGMENTS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index d2a8c78ed50b..33c9b5283d26 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -15,6 +15,7 @@ #include #include +#include #include "wmfw.h" @@ -30,6 +31,8 @@ struct wm_adsp_alg_region { unsigned int base; }; +struct wm_adsp_compr; + struct wm_adsp { const char *part; int num; @@ -59,6 +62,8 @@ struct wm_adsp { struct work_struct boot_work; + struct wm_adsp_compr *compr; + struct mutex pwr_lock; #ifdef CONFIG_DEBUG_FS @@ -97,4 +102,12 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int wm_adsp_compr_open(struct wm_adsp *dsp, + struct snd_compr_stream *stream); +extern int wm_adsp_compr_free(struct snd_compr_stream *stream); +extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params); +extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps); + #endif -- cgit v1.2.3 From 2cd19bdbf83c4c70b2ee36d022c5ded2738d2e19 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Dec 2015 11:29:46 +0000 Subject: ASoC: wm_adsp: Add code to locate and initialise compressed buffer Add code that locates and initialises the buffer of compressed data on the DSP if the firmware supported compressed data capture. The buffer struct (wm_adsp_compr_buf) is kept separate from the stream struct (wm_adsp_compr) this will allow much easier support of multiple streams of data from the one DSP in the future, although support for this will not be added in this patch chain. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 291 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 2 + 2 files changed, 293 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d81ed218918e..90994a5528a4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -229,6 +229,58 @@ static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { [WM_ADSP_FW_MISC] = "Misc", }; +struct wm_adsp_system_config_xm_hdr { + __be32 sys_enable; + __be32 fw_id; + __be32 fw_rev; + __be32 boot_status; + __be32 watchdog; + __be32 dma_buffer_size; + __be32 rdma[6]; + __be32 wdma[8]; + __be32 build_job_name[3]; + __be32 build_job_number; +}; + +struct wm_adsp_alg_xm_struct { + __be32 magic; + __be32 smoothing; + __be32 threshold; + __be32 host_buf_ptr; + __be32 start_seq; + __be32 high_water_mark; + __be32 low_water_mark; + __be64 smoothed_power; +}; + +struct wm_adsp_buffer { + __be32 X_buf_base; /* XM base addr of first X area */ + __be32 X_buf_size; /* Size of 1st X area in words */ + __be32 X_buf_base2; /* XM base addr of 2nd X area */ + __be32 X_buf_brk; /* Total X size in words */ + __be32 Y_buf_base; /* YM base addr of Y area */ + __be32 wrap; /* Total size X and Y in words */ + __be32 high_water_mark; /* Point at which IRQ is asserted */ + __be32 irq_count; /* bits 1-31 count IRQ assertions */ + __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */ + __be32 next_write_index; /* word index of next write */ + __be32 next_read_index; /* word index of next read */ + __be32 error; /* error if any */ + __be32 oldest_block_index; /* word index of oldest surviving */ + __be32 requested_rewind; /* how many blocks rewind was done */ + __be32 reserved_space; /* internal */ + __be32 min_free; /* min free space since stream start */ + __be32 blocks_written[2]; /* total blocks written (64 bit) */ + __be32 words_written[2]; /* total words written (64 bit) */ +}; + +struct wm_adsp_compr_buf { + struct wm_adsp *dsp; + + struct wm_adsp_buffer_region *regions; + u32 host_buf_ptr; +}; + struct wm_adsp_compr { struct wm_adsp *dsp; @@ -243,9 +295,53 @@ struct wm_adsp_compr { #define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE) #define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE) +#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7 + +#define HOST_BUFFER_FIELD(field) \ + (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32)) + +#define ALG_XM_FIELD(field) \ + (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32)) + +static int wm_adsp_buffer_init(struct wm_adsp *dsp); +static int wm_adsp_buffer_free(struct wm_adsp *dsp); + +struct wm_adsp_buffer_region { + unsigned int offset; + unsigned int cumulative_size; + unsigned int mem_type; + unsigned int base_addr; +}; + +struct wm_adsp_buffer_region_def { + unsigned int mem_type; + unsigned int base_offset; + unsigned int size_offset; +}; + +static struct wm_adsp_buffer_region_def ez2control_regions[] = { + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base), + .size_offset = HOST_BUFFER_FIELD(X_buf_size), + }, + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base2), + .size_offset = HOST_BUFFER_FIELD(X_buf_brk), + }, + { + .mem_type = WMFW_ADSP2_YM, + .base_offset = HOST_BUFFER_FIELD(Y_buf_base), + .size_offset = HOST_BUFFER_FIELD(wrap), + }, +}; + struct wm_adsp_fw_caps { u32 id; struct snd_codec_desc desc; + int num_regions; + struct wm_adsp_buffer_region_def *region_defs; }; static const struct wm_adsp_fw_caps ez2control_caps[] = { @@ -257,6 +353,8 @@ static const struct wm_adsp_fw_caps ez2control_caps[] = { .num_sample_rates = 1, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .num_regions = ARRAY_SIZE(ez2control_regions), + .region_defs = ez2control_regions, }, }; @@ -2123,6 +2221,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ADSP2_CORE_ENA | ADSP2_START); if (ret != 0) goto err; + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + ret = wm_adsp_buffer_init(dsp); + break; case SND_SOC_DAPM_PRE_PMD: @@ -2157,6 +2259,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, kfree(alg_region); } + if (wm_adsp_fw[dsp->fw].num_caps != 0) + wm_adsp_buffer_free(dsp); + mutex_unlock(&dsp->pwr_lock); adsp_dbg(dsp, "Shutdown complete\n"); @@ -2366,4 +2471,190 @@ int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, } EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); +static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, + unsigned int num_words, u32 *data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int i, reg; + int ret; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(mem, mem_addr); + + ret = regmap_raw_read(dsp->regmap, reg, data, + sizeof(*data) * num_words); + if (ret < 0) + return ret; + + for (i = 0; i < num_words; ++i) + data[i] = be32_to_cpu(data[i]) & 0x00ffffffu; + + return 0; +} + +static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 *data) +{ + return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data); +} + +static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int reg; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(mem, mem_addr); + + data = cpu_to_be32(data & 0x00ffffffu); + + return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data)); +} + +static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 *data) +{ + return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 data) +{ + return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) +{ + struct wm_adsp_alg_region *alg_region; + struct wm_adsp *dsp = buf->dsp; + u32 xmalg, addr, magic; + int i, ret; + + alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); + xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); + + addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); + if (ret < 0) + return ret; + + if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) + return -EINVAL; + + addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); + for (i = 0; i < 5; ++i) { + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, + &buf->host_buf_ptr); + if (ret < 0) + return ret; + + if (buf->host_buf_ptr) + break; + + usleep_range(1000, 2000); + } + + if (!buf->host_buf_ptr) + return -EIO; + + adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + + return 0; +} + +static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) +{ + const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; + struct wm_adsp_buffer_region *region; + u32 offset = 0; + int i, ret; + + for (i = 0; i < caps->num_regions; ++i) { + region = &buf->regions[i]; + + region->offset = offset; + region->mem_type = caps->region_defs[i].mem_type; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, + ®ion->base_addr); + if (ret < 0) + return ret; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, + &offset); + if (ret < 0) + return ret; + + region->cumulative_size = offset; + + adsp_dbg(buf->dsp, + "region=%d type=%d base=%04x off=%04x size=%04x\n", + i, region->mem_type, region->base_addr, + region->offset, region->cumulative_size); + } + + return 0; +} + +static int wm_adsp_buffer_init(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf->dsp = dsp; + + ret = wm_adsp_buffer_locate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret); + goto err_buffer; + } + + buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions, + sizeof(*buf->regions), GFP_KERNEL); + if (!buf->regions) { + ret = -ENOMEM; + goto err_buffer; + } + + ret = wm_adsp_buffer_populate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to populate host buffer: %d\n", ret); + goto err_regions; + } + + dsp->buffer = buf; + + return 0; + +err_regions: + kfree(buf->regions); +err_buffer: + kfree(buf); + return ret; +} + +static int wm_adsp_buffer_free(struct wm_adsp *dsp) +{ + if (dsp->buffer) { + kfree(dsp->buffer->regions); + kfree(dsp->buffer); + + dsp->buffer = NULL; + } + + return 0; +} + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 33c9b5283d26..0b2205a5c42f 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -32,6 +32,7 @@ struct wm_adsp_alg_region { }; struct wm_adsp_compr; +struct wm_adsp_compr_buf; struct wm_adsp { const char *part; @@ -63,6 +64,7 @@ struct wm_adsp { struct work_struct boot_work; struct wm_adsp_compr *compr; + struct wm_adsp_compr_buf *buffer; struct mutex pwr_lock; -- cgit v1.2.3 From 95fe9597d2494e8c4c9064fca1e12d1c03733ae7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 15 Dec 2015 11:29:47 +0000 Subject: ASoC: wm_adsp: Attach buffers and streams together The stream is created whilst the compressed stream is opened and a buffer is created when the DSP powers up. It is necessary at a point once both the DSP has powered up and the the stream has been opened to connect a stream to a buffer on the DSP. This is done in the trigger callback as this is after the DSP has been powered and obviously the stream must be open. Note that whilst the connect is currently trivial it is expected that this will get more complex when support for multiple buffers/streams per DSP is added. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 1 + sound/soc/codecs/wm_adsp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 1 + 3 files changed, 64 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 8c0fd9106be0..c36409601835 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2272,6 +2272,7 @@ static struct snd_compr_ops wm5110_compr_ops = { .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, .get_caps = wm_adsp_compr_get_caps, + .trigger = wm_adsp_compr_trigger, }; static struct snd_soc_platform_driver wm5110_compr_platform = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 90994a5528a4..ac879d16c6a6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -283,6 +283,7 @@ struct wm_adsp_compr_buf { struct wm_adsp_compr { struct wm_adsp *dsp; + struct wm_adsp_compr_buf *buf; struct snd_compr_stream *stream; struct snd_compressed_buffer size; @@ -2341,6 +2342,13 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) goto out; } + if (dsp->compr) { + /* It is expect this limitation will be removed in future */ + adsp_err(dsp, "Only a single stream supported per DSP\n"); + ret = -EBUSY; + goto out; + } + compr = kzalloc(sizeof(*compr), GFP_KERNEL); if (!compr) { ret = -ENOMEM; @@ -2657,4 +2665,58 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp) return 0; } +static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) +{ + return compr->buf != NULL; +} + +static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) +{ + /* + * Note this will be more complex once each DSP can support multiple + * streams + */ + if (!compr->dsp->buffer) + return -EINVAL; + + compr->buf = compr->dsp->buffer; + + return 0; +} + +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret = 0; + + adsp_dbg(dsp, "Trigger: %d\n", cmd); + + mutex_lock(&dsp->pwr_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (wm_adsp_compr_attached(compr)) + break; + + ret = wm_adsp_compr_attach(compr); + if (ret < 0) { + adsp_err(dsp, "Failed to link buffer and stream: %d\n", + ret); + break; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 0b2205a5c42f..43af093fafcf 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -111,5 +111,6 @@ extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, struct snd_compr_params *params); extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, struct snd_compr_caps *caps); +extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); #endif -- cgit v1.2.3 From b70381c35f65bbe1a2339e2833a574f0473162fa Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Dec 2015 15:50:49 +0100 Subject: ASoC: wm8903: Be sure to clamp return value As we want gpio_chip .get() calls to be able to return negative error codes and propagate to drivers, we need to go over all drivers and make sure their return values are clamped to [0,1]. We do this by using the ret = !!(val) design pattern. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index e4cc41e6c23e..2ed6419c181e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1804,7 +1804,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®); - return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; + return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT); } static int wm8903_gpio_direction_out(struct gpio_chip *chip, -- cgit v1.2.3 From 34015f5e56c71bbdcf7189430ffb63ea67656a35 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 22 Dec 2015 15:51:39 +0100 Subject: ASoC: ac97: Be sure to clamp return value As we want gpio_chip .get() calls to be able to return negative error codes and propagate to drivers, we need to go over all drivers and make sure their return values are clamped to [0,1]. We do this by using the ret = !!(val) design pattern. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/soc-ac97.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index ae563e379a72..733f5128eeff 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -92,7 +92,7 @@ static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) dev_dbg(codec->dev, "get gpio %d : %d\n", offset, ret < 0 ? ret : ret & (1 << offset)); - return ret < 0 ? ret : ret & (1 << offset); + return ret < 0 ? ret : !!(ret & (1 << offset)); } static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, -- cgit v1.2.3 From d0d1eedd5ad345f16234311b375bf94d6c90e14b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 18 Dec 2015 10:16:23 +0800 Subject: ASoC: rt5677: set PLL_CTRL2 non-volatile There is a status bit on RT5677_PLL1_CTRL2 and RT5677_PLL2_CTRL2. That's why those registers are set volatile. However, the status bit is currently not used by codec driver. So, it should be no problem if we set them non-volatile. The purpose of setting them non-volatile is to restore the setting after a syspend/resume cycle. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f73fd125e49c..13fef00e7b25 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -297,8 +297,6 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_HAP_GENE_CTRL2: case RT5677_PWR_DSP_ST: case RT5677_PRIV_DATA: - case RT5677_PLL1_CTRL2: - case RT5677_PLL2_CTRL2: case RT5677_ASRC_22: case RT5677_ASRC_23: case RT5677_VAD_CTRL5: -- cgit v1.2.3 From 3ae08dc0fc805bc15c5629f9794599c1171dc571 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 23 Dec 2015 18:24:09 +0800 Subject: ASoC: rt5651: add ACPI and OF support Add required tables and the binding document for ACPI and OF matching. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5651.txt | 41 ++++++++++++++++++++++ sound/soc/codecs/rt5651.c | 31 ++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt5651.txt (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt new file mode 100644 index 000000000000..3875233095f5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5651.txt @@ -0,0 +1,41 @@ +RT5651 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5651". + +- reg : The I2C address of the device. + +Optional properties: + +- realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +- realtek,dmic-en + Boolean. true if dmic is used. + +Pins on the device (for linking into audio routes) for RT5651: + + * DMIC L1 + * DMIC R1 + * IN1P + * IN2P + * IN2N + * IN3P + * HPOL + * HPOR + * LOUTL + * LOUTR + * PDML + * PDMR + +Example: + +codec: rt5651@1a { + compatible = "realtek,rt5651"; + reg = <0x1a>; + realtek,dmic-en = "true"; + realtek,in2-diff = "false"; +}; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 1d4031818966..7a6197042423 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1735,12 +1736,38 @@ static const struct regmap_config rt5651_regmap = { .num_ranges = ARRAY_SIZE(rt5651_ranges), }; +#if defined(CONFIG_OF) +static const struct of_device_id rt5651_of_match[] = { + { .compatible = "realtek,rt5651", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5651_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt5651_acpi_match[] = { + { "10EC5651", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); +#endif + static const struct i2c_device_id rt5651_i2c_id[] = { { "rt5651", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); +static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np) +{ + rt5651->pdata.in2_diff = of_property_read_bool(np, + "realtek,in2-differential"); + rt5651->pdata.dmic_en = of_property_read_bool(np, + "realtek,dmic-en"); + + return 0; +} + static int rt5651_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1757,6 +1784,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, if (pdata) rt5651->pdata = *pdata; + else if (i2c->dev.of_node) + rt5651_parse_dt(rt5651, i2c->dev.of_node); rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap); if (IS_ERR(rt5651->regmap)) { @@ -1806,6 +1835,8 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5651_i2c_driver = { .driver = { .name = "rt5651", + .acpi_match_table = ACPI_PTR(rt5651_acpi_match), + .of_match_table = of_match_ptr(rt5651_of_match), }, .probe = rt5651_i2c_probe, .remove = rt5651_i2c_remove, -- cgit v1.2.3 From abd7c894fc41a9a674354e10ed6c55413e1db077 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 23 Dec 2015 13:50:04 +0000 Subject: ASoC: da7219: Add regmap patch to support old silicon Initial silicon did not have master bias enabled by default, unlike later HW, so use regmap patch to align with newer defaults. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index c6d3b32bb4ae..9c7e8ec68b94 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1592,9 +1592,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) } } +static struct reg_sequence da7219_rev_aa_patch[] = { + { DA7219_REFERENCES, 0x08 }, +}; + static int da7219_probe(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + unsigned int rev; int ret; mutex_init(&da7219->lock); @@ -1604,6 +1609,26 @@ static int da7219_probe(struct snd_soc_codec *codec) if (ret) return ret; + ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev); + if (ret) { + dev_err(codec->dev, "Failed to read chip revision: %d\n", ret); + goto err_disable_reg; + } + + switch (rev & DA7219_CHIP_MINOR_MASK) { + case 0: + ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch, + ARRAY_SIZE(da7219_rev_aa_patch)); + if (ret) { + dev_err(codec->dev, "Failed to register AA patch: %d\n", + ret); + goto err_disable_reg; + } + break; + default: + break; + } + /* Handle DT/Platform data */ if (codec->dev->of_node) da7219->pdata = da7219_of_to_pdata(codec); @@ -1774,7 +1799,6 @@ static struct reg_default da7219_reg_defaults[] = { { DA7219_MIXOUT_R_CTRL, 0x10 }, { DA7219_CHIP_ID1, 0x23 }, { DA7219_CHIP_ID2, 0x93 }, - { DA7219_CHIP_REVISION, 0x00 }, { DA7219_IO_CTRL, 0x00 }, { DA7219_GAIN_RAMP_CTRL, 0x00 }, { DA7219_PC_COUNT, 0x02 }, -- cgit v1.2.3 From 4a5893cf67062be4f70196c3fe45cfda950ea308 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 24 Dec 2015 14:58:03 +0800 Subject: ASoC: wm8960: add kcontrol to select ADC data output add kcontrol to select ADC data output. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 056375339ea3..328bde09d5bf 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -147,6 +147,12 @@ static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"}; static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; +static const char *wm8960_adc_data_output_sel[] = { + "Left Data = Left ADC; Right Data = Right ADC", + "Left Data = Left ADC; Right Data = Left ADC", + "Left Data = Right ADC; Right Data = Right ADC", + "Left Data = Right ADC; Right Data = Left ADC", +}; static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), @@ -155,6 +161,7 @@ static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), + SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), }; static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; @@ -295,6 +302,8 @@ SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume", WM8960_BYPASS2, 4, 7, 1, bypass_tlv), SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), + +SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), }; static const struct snd_kcontrol_new wm8960_lin_boost[] = { -- cgit v1.2.3 From bb18f0976ef8db41f68b66623ce3b8a745adb0b8 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Dec 2015 21:03:39 +0800 Subject: ASoC: twl6040, fsl: use to_platform_device Use to_platform_device() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 3 +-- sound/soc/fsl/mpc8610_hpcd.c | 3 +-- sound/soc/fsl/p1022_ds.c | 3 +-- sound/soc/fsl/p1022_rdk.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4cad8929d262..bc3de2e844e6 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1097,8 +1097,7 @@ static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); - struct platform_device *pdev = container_of(codec->dev, - struct platform_device, dev); + struct platform_device *pdev = to_platform_device(codec->dev); int ret = 0; priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 6f236f170cf5..ddf49f30b23f 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -189,8 +189,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct mpc8610_hpcd_data *machine_data; diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 747aab0602bd..a1f780ecadf5 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -199,8 +199,7 @@ static int p1022_ds_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct machine_data *mdata; diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index 1dd49e5f9675..d4d88a8cb9c0 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -203,8 +203,7 @@ static int p1022_rdk_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct machine_data *mdata; -- cgit v1.2.3 From 7ff6319e7da5c09f0ce86d122d46040807262325 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 30 Dec 2015 15:33:20 +0800 Subject: ASoC: rt5645: use polling to support HS button The IRQ pin will keep high when the headset button is pressed. And keep low when the headset button is released. So, we need irq trigger at both edges. However, some platform can't support it. Therefore, we polling the register to report the button release event once a button presse event is received. To support the headset button detection function for those can't support both edges trigger platforms, we also need to invert the polarity of jack detection irq since we need to keep the IRQ pin low in normal case. Signed-off-by: John Lin Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3e8d66661b7e..57c8d9ecfde1 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -405,6 +405,7 @@ struct rt5645_priv { struct delayed_work jack_detect_work, rcclock_work; struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)]; struct rt5645_eq_param_s *eq_param; + struct timer_list btn_check_timer; int codec_type; int sysclk; @@ -3130,7 +3131,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } if (rt5645->pdata.jd_invert) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, - RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); + RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); } else { /* jack out */ rt5645->jack_type = 0; @@ -3151,7 +3152,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_sync(dapm); if (rt5645->pdata.jd_invert) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, - RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); } return rt5645->jack_type; @@ -3275,6 +3276,12 @@ static void rt5645_jack_detect_work(struct work_struct *work) } if (btn_type == 0)/* button release */ report = rt5645->jack_type; + else { + if (rt5645->pdata.jd_invert) { + mod_timer(&rt5645->btn_check_timer, + msecs_to_jiffies(100)); + } + } break; /* jack out */ @@ -3317,6 +3324,14 @@ static irqreturn_t rt5645_irq(int irq, void *data) return IRQ_HANDLED; } +static void rt5645_btn_check_callback(unsigned long data) +{ + struct rt5645_priv *rt5645 = (struct rt5645_priv *)data; + + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(5)); +} + static int rt5645_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); @@ -3783,6 +3798,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } } + if (rt5645->pdata.jd_invert) { + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); + setup_timer(&rt5645->btn_check_timer, + rt5645_btn_check_callback, (unsigned long)rt5645); + } + INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); -- cgit v1.2.3 From e116615b80bb89484ad4d55c752a00dd6379f95c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Dec 2015 16:25:14 +0000 Subject: ASoC: wm5110: Use helper function to lock the DAPM mutex A couple of call sites were missed when the snd_soc_dapm_mutex_lock function was added this patch fixes those up. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index e93e5420943e..605daffebc9c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -439,18 +439,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_get_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } @@ -460,18 +459,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_put_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } -- cgit v1.2.3 From e5d9cfc6f5fe56caa44cefbc7ef4531c480d901d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 24 Dec 2015 08:02:39 +0100 Subject: ASoC: rsnd: fix usrcnt decrementing bug Field usrcnt is unsigned so it cannot be lesser than zero. The patch fixes the check, moves it to the beginning of the function and changes return value to -EIO in case of usercnt error. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2038576 Signed-off-by: Andrzej Hajda Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7db05fdfb656..7ee89da4dd5f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -403,29 +403,30 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - if (rsnd_ssi_is_parent(mod, io)) - goto rsnd_ssi_quit_end; + if (!ssi->usrcnt) { + dev_err(dev, "%s[%d] usrcnt error\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + return -EIO; + } - if (ssi->err > 0) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); + if (!rsnd_ssi_is_parent(mod, io)) { + if (ssi->err > 0) + dev_warn(dev, "%s[%d] under/over flow err = %d\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + ssi->err); - ssi->cr_own = 0; - ssi->err = 0; + ssi->cr_own = 0; + ssi->err = 0; - rsnd_ssi_irq_disable(mod); + rsnd_ssi_irq_disable(mod); + } -rsnd_ssi_quit_end: rsnd_ssi_master_clk_stop(ssi, io); rsnd_mod_power_off(mod); ssi->usrcnt--; - if (ssi->usrcnt < 0) - dev_err(dev, "%s[%d] usrcnt error\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - return 0; } -- cgit v1.2.3 From 26eb5a9a6a8545ebb9d45de9e6d43e511b250839 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Dec 2015 09:49:19 +0000 Subject: ASoC: arizona: Exit startup early if no runtime commit 9b8ef9f6b3fc ("ASoC: dapm: Add startup & shutdown for dai_links") Added support for calling startup on CODEC to CODEC links, however this is called with a NULL runtime pointer. There isn't really a sensible way to pass a valid runtime pointer to a CODEC to CODEC link at the moment, so we need to make the startup function safe for NULL runtimes. This patch returns from the Arizona startup function early if there is no runtime, this is perfectly safe as all the startup function does is set the PCM constraints for user-space which arn't relevant to a CODEC to CODEC link anyway. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 38a73e3da508..88e2c74f1d17 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1494,6 +1494,9 @@ static int arizona_startup(struct snd_pcm_substream *substream, const struct snd_pcm_hw_constraint_list *constraint; unsigned int base_rate; + if (!substream->runtime) + return 0; + switch (dai_priv->clk) { case ARIZONA_CLK_SYSCLK: base_rate = priv->sysclk; -- cgit v1.2.3 From 064e186f8fe7f5e1c59f74bc455ac3aa18efa503 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 30 Dec 2015 11:21:57 +0100 Subject: ALSA: atiixp: constify atiixp_dma_ops structures The atiixp_dma_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/pci/atiixp.c | 6 +++--- sound/pci/atiixp_modem.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 1028fc8bdff5..2ce0022dbc46 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1219,7 +1219,7 @@ static struct ac97_pcm atiixp_pcm_defs[] = { }, }; -static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_OUT_DMA_LINKPTR, .dt_cur = ATI_REG_OUT_DMA_DT_CUR, @@ -1228,7 +1228,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .flush_dma = atiixp_out_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_IN_DMA_LINKPTR, .dt_cur = ATI_REG_IN_DMA_DT_CUR, @@ -1237,7 +1237,7 @@ static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .flush_dma = atiixp_in_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { .type = ATI_DMA_SPDIF, .llp_offset = ATI_REG_SPDF_DMA_LINKPTR, .dt_cur = ATI_REG_SPDF_DMA_DT_CUR, diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 27ed678a46df..c534552963e7 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -970,7 +970,7 @@ static struct snd_pcm_ops snd_atiixp_capture_ops = { .pointer = snd_atiixp_pcm_pointer, }; -static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR, .dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR, @@ -979,7 +979,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .flush_dma = atiixp_out_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR, .dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR, -- cgit v1.2.3 From 55a8aeef6dbdb90f5ee97801b86c73ffd93e8afd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 30 Dec 2015 11:44:53 +0100 Subject: ALSA: cs5535audio: constify cs5535audio_dma_ops structures The cs5535audio_dma_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 9c2dc911d8d7..27fa57da8dc4 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -402,7 +402,7 @@ static struct snd_pcm_ops snd_cs5535audio_capture_ops = { .pointer = snd_cs5535audio_pcm_pointer, }; -static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { +static const struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { .type = CS5535AUDIO_DMA_PLAYBACK, .enable_dma = cs5535audio_playback_enable_dma, .disable_dma = cs5535audio_playback_disable_dma, @@ -412,7 +412,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { .read_dma_pntr = cs5535audio_playback_read_dma_pntr, }; -static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { +static const struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { .type = CS5535AUDIO_DMA_CAPTURE, .enable_dma = cs5535audio_capture_enable_dma, .disable_dma = cs5535audio_capture_disable_dma, -- cgit v1.2.3 From d8c5ed752e5b9aabad9ea8b53272b6abb4fa5235 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 30 Dec 2015 12:28:49 +0100 Subject: ALSA: dummy: constify dummy_timer_ops structures The dummy_timer_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 016e451ed506..75b74850c005 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -351,7 +351,7 @@ static void dummy_systimer_free(struct snd_pcm_substream *substream) kfree(substream->runtime->private_data); } -static struct dummy_timer_ops dummy_systimer_ops = { +static const struct dummy_timer_ops dummy_systimer_ops = { .create = dummy_systimer_create, .free = dummy_systimer_free, .prepare = dummy_systimer_prepare, @@ -475,7 +475,7 @@ static void dummy_hrtimer_free(struct snd_pcm_substream *substream) kfree(dpcm); } -static struct dummy_timer_ops dummy_hrtimer_ops = { +static const struct dummy_timer_ops dummy_hrtimer_ops = { .create = dummy_hrtimer_create, .free = dummy_hrtimer_free, .prepare = dummy_hrtimer_prepare, -- cgit v1.2.3 From 51b2c4258f29d83120819a829a78345a3dac17c4 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 28 Dec 2015 22:47:13 +0800 Subject: ASoC: hdac_hdmi: use dev_to_hdac_dev and to_ehdac_device Use dev_to_hdac_dev() and to_ehdac_device() instead of open-coding. Signed-off-by: Geliang Tang Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1a2f33b4abfc..b999fb2a463b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -67,9 +67,9 @@ struct hdac_hdmi_priv { static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) { - struct hdac_device *hdac = container_of(dev, struct hdac_device, dev); + struct hdac_device *hdac = dev_to_hdac_dev(dev); - return container_of(hdac, struct hdac_ext_device, hdac); + return to_ehdac_device(hdac); } static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, -- cgit v1.2.3 From e2973769372a3de1c20249206db5ee93287a2230 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sat, 2 Jan 2016 23:23:56 +0100 Subject: ASoC: rt5645: Constify ACPI device ids Constify the ACPI device ID array, no need to have it writable at runtime. Also drop the unused RT5645_INIT_REG_LEN define. Signed-off-by: Mathias Krause Cc: Bard Liao Cc: Oder Chiou Cc: John Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 57c8d9ecfde1..bd23496a56ff 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -64,7 +64,6 @@ static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x21, 0x4040}, {RT5645_PR_BASE + 0x23, 0x0004}, }; -#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, @@ -3521,7 +3520,7 @@ static const struct i2c_device_id rt5645_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); #ifdef CONFIG_ACPI -static struct acpi_device_id rt5645_acpi_match[] = { +static const struct acpi_device_id rt5645_acpi_match[] = { { "10EC5645", 0 }, { "10EC5650", 0 }, {}, -- cgit v1.2.3 From 15b0f4d4b169dde8ecc4e162bcd6cd145cb09fed Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 5 Jan 2016 14:22:11 +0800 Subject: ASoC: rt5645: improve IRQ reaction time for HS button IRQ reaction time is not immediate when headset putton is pressed. This patch shortens the reaction time. Signed-off-by: John Lin Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index bd23496a56ff..4b079d189aac 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3062,6 +3062,7 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_dapm_force_enable_pin(dapm, "ADC R power"); snd_soc_dapm_sync(dapm); + snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); snd_soc_update_bits(codec, -- cgit v1.2.3 From bee3e020247eb2573a85a0f558c4a13aba2b81fe Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 4 Jan 2016 17:20:26 -0600 Subject: ASoC: rt5640: add ASRC support Signed-off-by: Jack Yu Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5640.h | 17 ++++++++ 2 files changed, 119 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index f2beb1aa5763..18f2d3bd3c80 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int is_using_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + + if (!rt5640->asrc_en) + return 0; + + return 1; +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER, @@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2, RT5640_PWR_PLL_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1, + 15, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1, + 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1, + 11, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1, + 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1, + 8, 0, NULL, 0), + + /* Input Side */ /* micbias */ SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1, @@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { + { "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc }, + { "I2S2", NULL, "I2S2 ASRC", is_using_asrc }, + { "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc }, + { "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc }, + { "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc }, + {"IN1P", NULL, "LDO2"}, {"IN2P", NULL, "LDO2"}, {"IN3P", NULL, "LDO2"}, @@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(rt5640_dmic_enable); +int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + + switch (clk_src) { + case RT5640_CLK_SEL_SYS: + case RT5640_CLK_SEL_ASRC: + break; + + default: + return -EINVAL; + } + + if (!filter_mask) + return -EINVAL; + + if (filter_mask & RT5640_DA_STEREO_FILTER) { + asrc2_mask |= RT5640_STO_DAC_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK) + | (clk_src << RT5640_STO_DAC_M_SFT); + } + + if (filter_mask & RT5640_DA_MONO_L_FILTER) { + asrc2_mask |= RT5640_MDA_L_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK) + | (clk_src << RT5640_MDA_L_M_SFT); + } + + if (filter_mask & RT5640_DA_MONO_R_FILTER) { + asrc2_mask |= RT5640_MDA_R_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK) + | (clk_src << RT5640_MDA_R_M_SFT); + } + + if (filter_mask & RT5640_AD_STEREO_FILTER) { + asrc2_mask |= RT5640_ADC_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK) + | (clk_src << RT5640_ADC_M_SFT); + } + + if (filter_mask & RT5640_AD_MONO_L_FILTER) { + asrc2_mask |= RT5640_MAD_L_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK) + | (clk_src << RT5640_MAD_L_M_SFT); + } + + if (filter_mask & RT5640_AD_MONO_R_FILTER) { + asrc2_mask |= RT5640_MAD_R_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK) + | (clk_src << RT5640_MAD_R_M_SFT); + } + + snd_soc_update_bits(codec, RT5640_ASRC_2, + asrc2_mask, asrc2_value); + + if (snd_soc_read(codec, RT5640_ASRC_2)) { + rt5640->asrc_en = true; + snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3); + } else { + rt5640->asrc_en = false; + snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src); + static int rt5640_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 3deb8babeabb..83a7150ddc24 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1033,6 +1033,10 @@ #define RT5640_DMIC_2_M_NOR (0x0 << 8) #define RT5640_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84) */ +#define RT5640_CLK_SEL_SYS (0x0) +#define RT5640_CLK_SEL_ASRC (0x1) + /* ASRC Control 2 (0x84) */ #define RT5640_MDA_L_M_MASK (0x1 << 15) #define RT5640_MDA_L_M_SFT 15 @@ -2079,6 +2083,16 @@ enum { RT5640_DMIC2, }; +/* filter mask */ +enum { + RT5640_DA_STEREO_FILTER = 0x1, + RT5640_DA_MONO_L_FILTER = (0x1 << 1), + RT5640_DA_MONO_R_FILTER = (0x1 << 2), + RT5640_AD_STEREO_FILTER = (0x1 << 3), + RT5640_AD_MONO_L_FILTER = (0x1 << 4), + RT5640_AD_MONO_R_FILTER = (0x1 << 5), +}; + struct rt5640_priv { struct snd_soc_codec *codec; struct rt5640_platform_data pdata; @@ -2095,9 +2109,12 @@ struct rt5640_priv { int pll_out; bool hp_mute; + bool asrc_en; }; int rt5640_dmic_enable(struct snd_soc_codec *codec, bool dmic1_data_pin, bool dmic2_data_pin); +int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); #endif -- cgit v1.2.3 From 0ec66e2d74aadaaee7e218861ca86effcd029435 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Jan 2016 17:20:27 -0600 Subject: ASoC: Intel: bytcr-rt5640: enable ASRC Sound is noisy when using BCLK as reference, enable ASRC in rt5640 codec Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a81389d10e17..0f2385f6f6ac 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -153,6 +153,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) card->dapm.idle_bias_off = true; + rt5640_sel_asrc_clk_src(codec, + RT5640_DA_STEREO_FILTER | + RT5640_AD_STEREO_FILTER, + RT5640_CLK_SEL_ASRC); + ret = snd_soc_add_card_controls(card, byt_rt5640_controls, ARRAY_SIZE(byt_rt5640_controls)); if (ret) { -- cgit v1.2.3 From dc901a3541717ca4963dd017eacf50a4c954609c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Jan 2016 17:20:23 -0600 Subject: ASoC: Intel: fix ACPI probe regression with Atom DPCM driver The commit 95f098014815b330838b1173d3d7bcea3b481242 "ASoC: Intel: Move apci find machine routines" introduced a regression in ACPI probe of the DPCM driver. Fix by conditionally compiling sst-acpi when the DPCM driver is not selected Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 3b9332e7a094..668fdeee195e 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,5 +1,10 @@ snd-soc-sst-dsp-objs := sst-dsp.o +ifneq ($(CONFIG_SND_SST_IPC_ACPI),) +snd-soc-sst-acpi-objs := sst-match-acpi.o +else snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o +endif + snd-soc-sst-ipc-objs := sst-ipc.o snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o -- cgit v1.2.3 From 2bd5bd15a51858866d792c678f0fe9280c4e8fa7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Jan 2016 17:20:24 -0600 Subject: ASoC: Intel: add bytct-rt5651 machine driver based on bytcr-rt5640 with changes only on codec side Quirk logic is kept as placeholder. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/atom/sst/sst_acpi.c | 3 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bytcr_rt5651.c | 332 ++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 sound/soc/intel/boards/bytcr_rt5651.c (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 337e178c1acb..803f95e40679 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -103,6 +103,18 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH Say Y if you have such a device If unsure select "N". +config SND_SOC_INTEL_BYTCR_RT5651_MACH + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" + depends on X86 && I2C + select SND_SOC_RT5651 + select SND_SST_MFLD_PLATFORM + select SND_SST_IPC_ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5651 audio codec. + Say Y if you have such a device + If unsure select "N". + config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f424460b917e..b6ea0a58f9d3 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -316,6 +316,9 @@ static int sst_acpi_remove(struct platform_device *pdev) static struct sst_acpi_mach sst_acpi_bytcr[] = { {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, + {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, + &byt_rvp_platform_data }, + {}, }; diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 2485ea9434ad..3310c0f9c356 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -3,6 +3,7 @@ snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o +snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o @@ -15,6 +16,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o +obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c new file mode 100644 index 000000000000..1c95ccc886c4 --- /dev/null +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -0,0 +1,332 @@ +/* + * bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform + * (derived from bytcr_rt5640.c) + * + * Copyright (C) 2015 Intel Corp + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt5651.h" +#include "../atom/sst-atom-controls.h" + +static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "AIF1 Capture"}, + + {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */ + {"IN2P", NULL, "Headset Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Speaker", NULL, "LOUTL"}, + {"Speaker", NULL, "LOUTR"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { + {"Internal Mic", NULL, "micbias1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5651_DMIC1_MAP, + BYT_RT5651_DMIC2_MAP, + BYT_RT5651_IN1_MAP, +}; + +#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5651_DMIC_EN BIT(16) + +static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP | + BYT_RT5651_DMIC_EN; + +static const struct snd_kcontrol_new byt_rt5651_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + snd_soc_dai_set_bclk_ratio(codec_dai, 50); + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1, + params_rate(params) * 50, + params_rate(params) * 512); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct dmi_system_id byt_rt5651_quirk_table[] = { + {} +}; + +static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; + + card->dapm.idle_bias_off = true; + + dmi_check_system(byt_rt5651_quirk_table); + switch (BYT_RT5651_MAP(byt_rt5651_quirk)) { + case BYT_RT5651_IN1_MAP: + custom_map = byt_rt5651_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map); + break; + case BYT_RT5651_DMIC2_MAP: + custom_map = byt_rt5651_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map); + break; + default: + custom_map = byt_rt5651_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map); + } + + ret = snd_soc_add_card_controls(card, byt_rt5651_controls, + ARRAY_SIZE(byt_rt5651_controls)); + if (ret) { + dev_err(card->dev, "unable to add card controls\n"); + return ret; + } + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + + return ret; +} + +static const struct snd_soc_pcm_stream byt_rt5651_dai_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; + + /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int rates_48000[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_48000); +} + +static struct snd_soc_ops byt_rt5651_aif1_ops = { + .startup = byt_rt5651_aif1_startup, +}; + +static struct snd_soc_ops byt_rt5651_be_ssp2_ops = { + .hw_params = byt_rt5651_aif1_hw_params, +}; + +static struct snd_soc_dai_link byt_rt5651_dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &byt_rt5651_aif1_ops, + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_rt5651_aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5651-aif1", + .codec_name = "i2c-10EC5651:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = byt_rt5651_codec_fixup, + .ignore_suspend = 1, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_rt5651_init, + .ops = &byt_rt5651_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card byt_rt5651_card = { + .name = "bytcr-rt5651", + .owner = THIS_MODULE, + .dai_link = byt_rt5651_dais, + .num_links = ARRAY_SIZE(byt_rt5651_dais), + .dapm_widgets = byt_rt5651_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets), + .dapm_routes = byt_rt5651_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map), + .fully_routed = true, +}; + +static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + + /* register the soc card */ + byt_rt5651_card.dev = &pdev->dev; + + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); + + if (ret_val) { + dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", + ret_val); + return ret_val; + } + platform_set_drvdata(pdev, &byt_rt5651_card); + return ret_val; +} + +static struct platform_driver snd_byt_rt5651_mc_driver = { + .driver = { + .name = "bytcr_rt5651", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_byt_rt5651_mc_probe, +}; + +module_platform_driver(snd_byt_rt5651_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651"); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcr_rt5651"); -- cgit v1.2.3 From caf94ed8629afb82d61a82ce76fb314145933a40 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Jan 2016 17:20:28 -0600 Subject: ASoC: Intel: bytcr_rt5640: fixup DAI codec_name with HID Codec name is hard-coded in machine driver, pass information from actual ACPI HID to help support BIOS variations Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 17 ++++++++++++----- sound/soc/intel/boards/bytcr_rt5640.c | 10 ++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index b6ea0a58f9d3..f61e53106339 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -247,16 +247,23 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "ACPI device id: %x\n", dev_id); - plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0); + plat_dev = platform_device_register_data(dev, pdata->platform, -1, + NULL, 0); if (IS_ERR(plat_dev)) { - dev_err(dev, "Failed to create machine device: %s\n", pdata->platform); + dev_err(dev, "Failed to create machine device: %s\n", + pdata->platform); return PTR_ERR(plat_dev); } - /* Create platform device for sst machine driver */ - mdev = platform_device_register_data(dev, mach->drv_name, -1, NULL, 0); + /* + * Create platform device for sst machine driver, + * pass machine info as pdata + */ + mdev = platform_device_register_data(dev, mach->drv_name, -1, + (const void *)mach, sizeof(*mach)); if (IS_ERR(mdev)) { - dev_err(dev, "Failed to create machine device: %s\n", mach->drv_name); + dev_err(dev, "Failed to create machine device: %s\n", + mach->drv_name); return PTR_ERR(mdev); } diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 0f2385f6f6ac..74bb7cc1f54a 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -30,6 +30,7 @@ #include #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -326,12 +327,21 @@ static struct snd_soc_card byt_rt5640_card = { .fully_routed = true, }; +static char byt_rt5640_codec_name[16]; /* i2c-:00 with HID being 8 chars */ + static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct sst_acpi_mach *mach; /* register the soc card */ byt_rt5640_card.dev = &pdev->dev; + mach = byt_rt5640_card.dev->platform_data; + + /* fixup codec name based on HID */ + snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), + "%s%s%s", "i2c-", mach->id, ":00"); + byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name; ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); -- cgit v1.2.3 From 7762ef42d804050ae0ad3b99a2e407f50e039a1c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Jan 2016 17:20:29 -0600 Subject: ASoC: Intel: Atom: add support for RT5642 The machine driver is not loaded when the BIOS uses the 10EC5642 _HID. Add it to the white list of known _HIDs, codec_name is already taken care of by previous commit Tested on Asus T100TAF. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 ++ sound/soc/intel/boards/bytcr_rt5640.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f61e53106339..510826f497c4 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -323,6 +323,8 @@ static int sst_acpi_remove(struct platform_device *pdev) static struct sst_acpi_mach sst_acpi_bytcr[] = { {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, + {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, &byt_rvp_platform_data }, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 74bb7cc1f54a..5b0cdad901b6 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -302,7 +302,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .platform_name = "sst-mfld-platform", .no_pcm = 1, .codec_dai_name = "rt5640-aif1", - .codec_name = "i2c-10EC5640:00", + .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_rt5640_codec_fixup, -- cgit v1.2.3 From 55fc205600ff3b529631cfe03b58645e3844bd92 Mon Sep 17 00:00:00 2001 From: Jorge Fernandez Monteagudo Date: Mon, 4 Jan 2016 17:20:30 -0600 Subject: ASoC: Intel: Atom: Add support for HP ElitePad 1000 G2 The BIOS for the HP ElitePad 1000 G2 uses an unexpected HID, (INTCCFFD), add it to the white list of knowns HIDs. Signed-off-by: Jorge Fernandez Monteagudo Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 1 + sound/soc/intel/atom/sst/sst_acpi.c | 3 ++- sound/soc/intel/boards/bytcr_rt5640.c | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 18f2d3bd3c80..11d032cdc658 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2277,6 +2277,7 @@ static const struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, { "10EC5640", 0 }, { "10EC5642", 0 }, + { "INTCCFFD", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 510826f497c4..4fce03fc1870 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -325,9 +325,10 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { &byt_rvp_platform_data }, {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, + {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, &byt_rvp_platform_data }, - {}, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 5b0cdad901b6..9a1752df45a9 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -141,6 +141,14 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | BYT_RT5640_DMIC_EN), }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, {} }; -- cgit v1.2.3 From d44c6114da8c9e83407397d06b5cd909a1cc9135 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 24 Dec 2015 11:42:11 +0800 Subject: ASoC: fsl_asrc: sound is wrong after suspend/resume The register ASRCFG is volatile, but some bits need to be recovered after suspend/resume. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 7 +++++++ sound/soc/fsl/fsl_asrc.h | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 7b811485a8e5..73fd2c683b78 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -996,6 +996,9 @@ static int fsl_asrc_suspend(struct device *dev) { struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + regmap_read(asrc_priv->regmap, REG_ASRCFG, + &asrc_priv->regcache_cfg); + regcache_cache_only(asrc_priv->regmap, true); regcache_mark_dirty(asrc_priv->regmap); @@ -1016,6 +1019,10 @@ static int fsl_asrc_resume(struct device *dev) regcache_cache_only(asrc_priv->regmap, false); regcache_sync(asrc_priv->regmap); + regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, + ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | + ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); + /* Restart enabled pairs */ regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, asrctr); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 68802cdc3f28..0f163abe4ba3 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -132,10 +132,13 @@ #define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i)) #define ASRCFG_NDPRi_SHIFT(i) (18 + i) #define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i)) +#define ASRCFG_NDPRi_ALL_SHIFT 18 +#define ASRCFG_NDPRi_ALL_MASK (7 << ASRCFG_NDPRi_ALL_SHIFT) #define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i)) #define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2)) #define ASRCFG_POSTMODi_WIDTH 2 #define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMODi_ALL_MASK (ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2)) #define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i)) #define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i)) #define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i)) @@ -143,6 +146,7 @@ #define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2)) #define ASRCFG_PREMODi_WIDTH 2 #define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_ALL_MASK (ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2)) #define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i)) #define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i)) #define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i)) @@ -434,6 +438,7 @@ struct fsl_asrc_pair { * @channel_avail: non-occupied channel numbers * @asrc_rate: default sample rate for ASoC Back-Ends * @asrc_width: default sample width for ASoC Back-Ends + * @regcache_cfg: store register value of REG_ASRCFG */ struct fsl_asrc { struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -453,6 +458,8 @@ struct fsl_asrc { int asrc_rate; int asrc_width; + + u32 regcache_cfg; }; extern struct snd_soc_platform_driver fsl_asrc_platform; -- cgit v1.2.3 From 4acfa36be618eb8ac3aa39f473e7550710216435 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 5 Jan 2016 15:05:36 +0000 Subject: ASoC: da7219: Correct BCLK inversion for DSP DAI format mode By default the device latches data on the falling edge of the BCLK in DSP mode, whereas the expectation for normal BCLK is to latch on the rising edge. This updates the driver to invert the BCLK configuration for DSP mode, to align with expected behaviour. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 48 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 9c7e8ec68b94..81c0708b85c1 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1156,18 +1156,44 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; - break; - case SND_SOC_DAIFMT_IB_NF: - dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | + DA7219_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } break; - case SND_SOC_DAIFMT_IB_IF: - dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | - DA7219_DAI_CLK_POL_INV; + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | + DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; -- cgit v1.2.3 From 3f80978397f447973d278198e8bbde82826cb9c1 Mon Sep 17 00:00:00 2001 From: Sanyog Kale Date: Tue, 5 Jan 2016 17:14:49 +0530 Subject: ASoC: pcm: allow delayed suspending request by users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a device would like to use delayed suspending then PM recommendation is to set ‘power.use_autosuspend’ flag. To allow users to do so we need to change runtime calls in core to use autosuspend counterparts. For user who do not wish to use delayed suspend not setting the device's ‘power.use_autosuspend’ flag will result in non-delayed suspend even with these APIs which incidentally is also the default behaviour, so only users will be impacted who opt in for this. Signed-off-by: Sanyog Kale Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96e8986..efad248efd4f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -599,10 +599,15 @@ platform_err: out: mutex_unlock(&rtd->pcm_mutex); - pm_runtime_put(platform->dev); - for (i = 0; i < rtd->num_codecs; i++) - pm_runtime_put(rtd->codec_dais[i]->dev); - pm_runtime_put(cpu_dai->dev); + pm_runtime_mark_last_busy(platform->dev); + pm_runtime_put_autosuspend(platform->dev); + for (i = 0; i < rtd->num_codecs; i++) { + pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev); + pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev); + } + + pm_runtime_mark_last_busy(cpu_dai->dev); + pm_runtime_put_autosuspend(cpu_dai->dev); for (i = 0; i < rtd->num_codecs; i++) { if (!rtd->codec_dais[i]->active) pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); @@ -706,10 +711,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) mutex_unlock(&rtd->pcm_mutex); - pm_runtime_put(platform->dev); - for (i = 0; i < rtd->num_codecs; i++) - pm_runtime_put(rtd->codec_dais[i]->dev); - pm_runtime_put(cpu_dai->dev); + pm_runtime_mark_last_busy(platform->dev); + pm_runtime_put_autosuspend(platform->dev); + + for (i = 0; i < rtd->num_codecs; i++) { + pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev); + pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev); + } + + pm_runtime_mark_last_busy(cpu_dai->dev); + pm_runtime_put_autosuspend(cpu_dai->dev); + for (i = 0; i < rtd->num_codecs; i++) { if (!rtd->codec_dais[i]->active) pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); -- cgit v1.2.3 From f644eb62fe88a2414e5e5c1bd80e20c881f5d86a Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 5 Jan 2016 18:15:33 +0000 Subject: ASoC: da7218: Correct BCLK inversion for DSP DAI format mode By default the device latches data on the falling edge of the BCLK in DSP mode, whereas the expectation for normal BCLK is to latch on the rising edge. This updates the driver to invert the BCLK configuration for DSP mode, to align with expected behaviour. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 72686517ff54..93575f251866 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1954,17 +1954,44 @@ static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; - break; - case SND_SOC_DAIFMT_IB_NF: - dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | + DA7218_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } break; - case SND_SOC_DAIFMT_IB_IF: - dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | DA7218_DAI_CLK_POL_INV; + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | + DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; -- cgit v1.2.3 From 541140d43046ccd4e7b511846d22b3d3ca7367f3 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 9 Dec 2015 21:46:08 +0530 Subject: ASoC: hdac_hdmi: Fix to check num nodes correctly commit 3c83ac23253c ("ASoC: hdac_hdmi: check error return") fixes the static checker warning reported by Dan Carpenter: sound/soc/codecs/hdac_hdmi.c:416 hdac_hdmi_parse_and_map_nid() warn: unsigned 'hdac->num_nodes' is never less than zero. But it doesn't fix the issue completely. It's also a failure if no sub nodes found for an afg node. So modify the return condition appropriately. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b999fb2a463b..e6dc4cd037d3 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -415,7 +415,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) int cvt_nid = 0, pin_nid = 0; num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); - if (!nid || num_nodes < 0) { + if (!nid || num_nodes <= 0) { dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } -- cgit v1.2.3 From 4a47a87defa0a67312932a3aaee3516dcf66659b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 31 Dec 2015 13:58:11 +0900 Subject: ALSA: dice: split subaddress check from category check Before allocating an instance of sound card, ALSA dice driver checks chip_ID_hi in Bus information block of Config ROM, then also checks subaddresses. The former operation reads cache of Config ROM in Linux FireWire subsystem, while the latter operation sends read transaction. The latter can be merged into initialization of transaction system. This commit splits these two operations to reduce needless transactions in probe processing. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-transaction.c | 90 ++++++++++++++++++++++++++-------- sound/firewire/dice/dice.c | 72 +++------------------------ 2 files changed, 78 insertions(+), 84 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index aee746187665..fdb7841c52e3 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -331,39 +331,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice) return register_notification_address(dice, false); } -int snd_dice_transaction_init(struct snd_dice *dice) +static int get_subaddrs(struct snd_dice *dice) { - struct fw_address_handler *handler = &dice->notification_handler; + static const int min_values[10] = { + 10, 0x64 / 4, + 10, 0x18 / 4, + 10, 0x18 / 4, + 0, 0, + 0, 0, + }; __be32 *pointers; + __be32 version; + u32 data; + unsigned int i; int err; - /* Use the same way which dice_interface_check() does. */ - pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL); + pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), + GFP_KERNEL); if (pointers == NULL) return -ENOMEM; - /* Get offsets for sub-addresses */ + /* + * Check that the sub address spaces exist and are located inside the + * private address space. The minimum values are chosen so that all + * minimally required registers are included. + */ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(__be32) * 10, 0); + DICE_PRIVATE_SPACE, pointers, + sizeof(__be32) * ARRAY_SIZE(min_values), 0); if (err < 0) goto end; - /* Allocation callback in address space over host controller */ - handler->length = 4; - handler->address_callback = dice_notification; - handler->callback_data = dice; - err = fw_core_add_address_handler(handler, &fw_high_memory_region); - if (err < 0) { - handler->callback_data = NULL; - goto end; + for (i = 0; i < ARRAY_SIZE(min_values); ++i) { + data = be32_to_cpu(pointers[i]); + if (data < min_values[i] || data >= 0x40000) { + err = -ENODEV; + goto end; + } } - /* Register the address space */ - err = register_notification_address(dice, true); - if (err < 0) { - fw_core_remove_address_handler(handler); - handler->callback_data = NULL; + /* + * Check that the implemented DICE driver specification major version + * number matches. + */ + err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, + DICE_PRIVATE_SPACE + + be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, + &version, sizeof(version), 0); + if (err < 0) + goto end; + + if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { + dev_err(&dice->unit->device, + "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); + err = -ENODEV; goto end; } @@ -380,3 +401,32 @@ end: kfree(pointers); return err; } + +int snd_dice_transaction_init(struct snd_dice *dice) +{ + struct fw_address_handler *handler = &dice->notification_handler; + int err; + + err = get_subaddrs(dice); + if (err < 0) + return err; + + /* Allocation callback in address space over host controller */ + handler->length = 4; + handler->address_callback = dice_notification; + handler->callback_data = dice; + err = fw_core_add_address_handler(handler, &fw_high_memory_region); + if (err < 0) { + handler->callback_data = NULL; + return err; + } + + /* Register the address space */ + err = register_notification_address(dice, true); + if (err < 0) { + fw_core_remove_address_handler(handler); + handler->callback_data = NULL; + } + + return err; +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 0cda05c72f50..26271cc9e9d0 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -18,27 +18,12 @@ MODULE_LICENSE("GPL v2"); #define WEISS_CATEGORY_ID 0x00 #define LOUD_CATEGORY_ID 0x10 -static int dice_interface_check(struct fw_unit *unit) +static int check_dice_category(struct fw_unit *unit) { - static const int min_values[10] = { - 10, 0x64 / 4, - 10, 0x18 / 4, - 10, 0x18 / 4, - 0, 0, - 0, 0, - }; struct fw_device *device = fw_parent_device(unit); struct fw_csr_iterator it; - int key, val, vendor = -1, model = -1, err; - unsigned int category, i; - __be32 *pointers; - u32 value; - __be32 version; - - pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), - GFP_KERNEL); - if (pointers == NULL) - return -ENOMEM; + int key, val, vendor = -1, model = -1; + unsigned int category; /* * Check that GUID and unit directory are constructed according to DICE @@ -64,51 +49,10 @@ static int dice_interface_check(struct fw_unit *unit) else category = DICE_CATEGORY_ID; if (device->config_rom[3] != ((vendor << 8) | category) || - device->config_rom[4] >> 22 != model) { - err = -ENODEV; - goto end; - } - - /* - * Check that the sub address spaces exist and are located inside the - * private address space. The minimum values are chosen so that all - * minimally required registers are included. - */ - err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, pointers, - sizeof(__be32) * ARRAY_SIZE(min_values), 0); - if (err < 0) { - err = -ENODEV; - goto end; - } - for (i = 0; i < ARRAY_SIZE(min_values); ++i) { - value = be32_to_cpu(pointers[i]); - if (value < min_values[i] || value >= 0x40000) { - err = -ENODEV; - goto end; - } - } + device->config_rom[4] >> 22 != model) + return -ENODEV; - /* - * Check that the implemented DICE driver specification major version - * number matches. - */ - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - DICE_PRIVATE_SPACE + - be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, - &version, 4, 0); - if (err < 0) { - err = -ENODEV; - goto end; - } - if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { - dev_err(&unit->device, - "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); - err = -ENODEV; - goto end; - } -end: - return err; + return 0; } static int highest_supported_mode_rate(struct snd_dice *dice, @@ -254,9 +198,9 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) struct snd_dice *dice; int err; - err = dice_interface_check(unit); + err = check_dice_category(unit); if (err < 0) - goto end; + return -ENODEV; err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dice), &card); -- cgit v1.2.3 From b59fb1900b4feedd2fa9256326e65b5632627465 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 31 Dec 2015 13:58:12 +0900 Subject: ALSA: dice: postpone card registration Some models based on ASIC for Dice II series (STD, CP) change their hardware configurations after appearing on IEEE 1394 bus. This is due to interactions of boot loader (RedBoot), firmwares (eCos) and vendor's configurations. This causes current ALSA dice driver to get wrong information about the hardware's capability because its probe function runs just after detecting unit of the model. As long as I investigated, it takes a bit time (less than 1 second) to load the firmware after bootstrap. Just after loaded, the driver can get information about the unit. Then the hardware is initialized according to vendor's configurations. After, the got information becomes wrong. Between bootstrap, firmware loading and post configuration, some bus resets are observed. This commit offloads most processing of probe function into workqueue and schedules the workqueue after successive bus resets. This has an effect to get correct hardware information and avoid involvement to bus reset storm. For code simplicity, this change effects all of Dice-based models, i.e. Dice II, Dice Jr., Dice Mini and Dice III. I use a loose strategy to manage a race condition between the work and the bus reset. This is due to a specification of dice transaction. When bus reset occurs, registered address for the transaction is cleared. Drivers must re-register their own address again. While, this operation is required for the work because the work includes to wait for the transaction. This commit uses no lock primitives for the race condition. Instead, checking 'registered' member of 'struct snd_dice' avoid executing the work again. If sound card is not registered, the work can be scheduled again by bus reset handler. When .remove callback is executed, the sound card is going to be released. The work should not be pending or executed in the releasing. This commit uses cancel_delayed_work_sync() in .remove callback and wait till the pending work finished. After .remove callback, .update callback is not executed, therefore no works are scheduled again. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice.c | 159 ++++++++++++++++++++++++++++++++------------- sound/firewire/dice/dice.h | 3 + 2 files changed, 117 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 26271cc9e9d0..b91b3739c810 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -18,6 +18,8 @@ MODULE_LICENSE("GPL v2"); #define WEISS_CATEGORY_ID 0x00 #define LOUD_CATEGORY_ID 0x10 +#define PROBE_DELAY_MS (2 * MSEC_PER_SEC) + static int check_dice_category(struct fw_unit *unit) { struct fw_device *device = fw_parent_device(unit); @@ -175,6 +177,16 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } +static void dice_free(struct snd_dice *dice) +{ + snd_dice_stream_destroy_duplex(dice); + snd_dice_transaction_destroy(dice); + fw_unit_put(dice->unit); + + mutex_destroy(&dice->mutex); + kfree(dice); +} + /* * This module releases the FireWire unit data after all ALSA character devices * are released by applications. This is for releasing stream data or finishing @@ -183,39 +195,21 @@ static void dice_card_strings(struct snd_dice *dice) */ static void dice_card_free(struct snd_card *card) { - struct snd_dice *dice = card->private_data; - - snd_dice_stream_destroy_duplex(dice); - snd_dice_transaction_destroy(dice); - fw_unit_put(dice->unit); - - mutex_destroy(&dice->mutex); + dice_free(card->private_data); } -static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) +static void do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_dice *dice; + struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work); int err; - err = check_dice_category(unit); - if (err < 0) - return -ENODEV; + if (dice->registered) + return; - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*dice), &card); + err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0, + &dice->card); if (err < 0) - goto end; - - dice = card->private_data; - dice->card = card; - dice->unit = fw_unit_get(unit); - card->private_free = dice_card_free; - - spin_lock_init(&dice->lock); - mutex_init(&dice->mutex); - init_completion(&dice->clock_accepted); - init_waitqueue_head(&dice->hwdep_wait); + return; err = snd_dice_transaction_init(dice); if (err < 0) @@ -227,56 +221,131 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_card_strings(dice); + snd_dice_create_proc(dice); + err = snd_dice_create_pcm(dice); if (err < 0) goto error; - err = snd_dice_create_hwdep(dice); + err = snd_dice_create_midi(dice); if (err < 0) goto error; - snd_dice_create_proc(dice); - - err = snd_dice_create_midi(dice); + err = snd_dice_create_hwdep(dice); if (err < 0) goto error; - err = snd_dice_stream_init_duplex(dice); + err = snd_card_register(dice->card); if (err < 0) goto error; - err = snd_card_register(card); + /* + * After registered, dice instance can be released corresponding to + * releasing the sound card instance. + */ + dice->card->private_free = dice_card_free; + dice->card->private_data = dice; + dice->registered = true; + + return; +error: + snd_dice_transaction_destroy(dice); + snd_card_free(dice->card); + dev_info(&dice->unit->device, + "Sound card registration failed: %d\n", err); +} + +static void schedule_registration(struct snd_dice *dice) +{ + struct fw_card *fw_card = fw_parent_device(dice->unit)->card; + u64 now, delay; + + now = get_jiffies_64(); + delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS); + + if (time_after64(delay, now)) + delay -= now; + else + delay = 0; + + mod_delayed_work(system_wq, &dice->dwork, delay); +} + +static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) +{ + struct snd_dice *dice; + int err; + + err = check_dice_category(unit); + if (err < 0) + return -ENODEV; + + /* Allocate this independent of sound card instance. */ + dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); + if (dice == NULL) + return -ENOMEM; + + dice->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, dice); + + spin_lock_init(&dice->lock); + mutex_init(&dice->mutex); + init_completion(&dice->clock_accepted); + init_waitqueue_head(&dice->hwdep_wait); + + err = snd_dice_stream_init_duplex(dice); if (err < 0) { - snd_dice_stream_destroy_duplex(dice); - goto error; + dice_free(dice); + return err; } - dev_set_drvdata(&unit->device, dice); -end: - return err; -error: - snd_card_free(card); - return err; + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&dice->dwork, do_registration); + schedule_registration(dice); + + return 0; } static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(dice->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&dice->dwork); + + if (dice->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(dice->card); + } else { + /* Don't forget this case. */ + dice_free(dice); + } } static void dice_bus_reset(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); + /* Postpone a workqueue for deferred registration. */ + if (!dice->registered) + schedule_registration(dice); + /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); - mutex_lock(&dice->mutex); - snd_dice_stream_update_duplex(dice); - mutex_unlock(&dice->mutex); + /* + * After registration, userspace can start packet streaming, then this + * code block works fine. + */ + if (dice->registered) { + mutex_lock(&dice->mutex); + snd_dice_stream_update_duplex(dice); + mutex_unlock(&dice->mutex); + } } #define DICE_INTERFACE 0x000001 diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 101550ac1a24..3d5ebebe61ea 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -45,6 +45,9 @@ struct snd_dice { spinlock_t lock; struct mutex mutex; + bool registered; + struct delayed_work dwork; + /* Offsets for sub-addresses */ unsigned int global_offset; unsigned int rx_offset; -- cgit v1.2.3 From a2875a92b8413b4d7eacf96802c9718aeeb0363f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 31 Dec 2015 13:58:13 +0900 Subject: ALSA: dice: purge transaction initialization at timeout of Dice notification In previous commit, card registration is processed under situation with few bus reset. There's no need to add a workaround of transaction re-initialization at timeout. This commit purges the re-initialization. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-transaction.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index fdb7841c52e3..55c1fbf31626 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -65,16 +65,15 @@ static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info) static int set_clock_info(struct snd_dice *dice, unsigned int rate, unsigned int source) { - unsigned int retries = 3; unsigned int i; __be32 info; u32 mask; u32 clock; int err; -retry: + err = get_clock_info(dice, &info); if (err < 0) - goto end; + return err; clock = be32_to_cpu(info); if (source != UINT_MAX) { @@ -87,10 +86,8 @@ retry: if (snd_dice_rates[i] == rate) break; } - if (i == ARRAY_SIZE(snd_dice_rates)) { - err = -EINVAL; - goto end; - } + if (i == ARRAY_SIZE(snd_dice_rates)) + return -EINVAL; mask = CLOCK_RATE_MASK; clock &= ~mask; @@ -104,25 +101,13 @@ retry: err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, &info, 4); if (err < 0) - goto end; + return err; - /* Timeout means it's invalid request, probably bus reset occurred. */ if (wait_for_completion_timeout(&dice->clock_accepted, - msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { - if (retries-- == 0) { - err = -ETIMEDOUT; - goto end; - } - - err = snd_dice_transaction_reinit(dice); - if (err < 0) - goto end; + msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) + return -ETIMEDOUT; - msleep(500); /* arbitrary */ - goto retry; - } -end: - return err; + return 0; } int snd_dice_transaction_get_clock_source(struct snd_dice *dice, -- cgit v1.2.3 From 2eb65d67afbf9364b525b657f1475d1a2cbc27de Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 31 Dec 2015 13:58:14 +0900 Subject: ALSA: dice: expand timeout to wait for Dice notification Some users have reported that their Dice based models generate ETIMEDOUT when starting PCM playback. It means that current timeout (=100msec) is not enough for their models to transfer notifications. This commit expands the timeout up to 2 sec. As a result, in a worst case, any operations to start AMDTP streams takes 2 sec or more. Then, in userspace, snd_pcm_hw_params(), snd_pcm_prepare(), snd_pcm_recover(), snd_rawmidi_open(), snd_seq_connect_from() and snd_seq_connect_to() may take the time. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index 55c1fbf31626..a4ff4e0bc0af 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -9,7 +9,7 @@ #include "dice.h" -#define NOTIFICATION_TIMEOUT_MS 100 +#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type, u64 offset) -- cgit v1.2.3 From 3643b46c381eda180df1ec68cd2ec5c79afd61f3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Jan 2016 17:50:47 +0100 Subject: ALSA: emux: constify nrpn_conv_table structures The nrpn_conv_table structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/synth/emux/emux_nrpn.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c index 00fc005ecf6e..9729a15b6ae6 100644 --- a/sound/synth/emux/emux_nrpn.c +++ b/sound/synth/emux/emux_nrpn.c @@ -48,7 +48,8 @@ struct nrpn_conv_table { * convert NRPN/control values */ -static int send_converted_effect(struct nrpn_conv_table *table, int num_tables, +static int send_converted_effect(const struct nrpn_conv_table *table, + int num_tables, struct snd_emux_port *port, struct snd_midi_channel *chan, int type, int val, int mode) @@ -179,7 +180,7 @@ static int fx_conv_Q(int val) } -static struct nrpn_conv_table awe_effects[] = +static const struct nrpn_conv_table awe_effects[] = { { 0, EMUX_FX_LFO1_DELAY, fx_lfo1_delay}, { 1, EMUX_FX_LFO1_FREQ, fx_lfo1_freq}, @@ -266,7 +267,7 @@ static int gs_vib_delay(int val) return -(val - 64) * gs_sense[FX_VIBDELAY] / 50; } -static struct nrpn_conv_table gs_effects[] = +static const struct nrpn_conv_table gs_effects[] = { {32, EMUX_FX_CUTOFF, gs_cutoff}, {33, EMUX_FX_FILTERQ, gs_filterQ}, @@ -350,7 +351,7 @@ static int xg_release(int val) return -(val - 64) * xg_sense[FX_RELEASE] / 64; } -static struct nrpn_conv_table xg_effects[] = +static const struct nrpn_conv_table xg_effects[] = { {71, EMUX_FX_CUTOFF, xg_cutoff}, {74, EMUX_FX_FILTERQ, xg_filterQ}, -- cgit v1.2.3 From 8012c983dd0cea8f5be5a02ca75fd8d437227a10 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Jan 2016 12:38:41 +0300 Subject: ASoC: rsnd: precedence error in rsnd_ssiu_init() The bitwise OR has higher precedence than ?: so the val2 was always set to 0x2. Fixes: b4c83b171557 ('ASoC: rsnd: add Multi channel support') Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssiu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 3fe9e08e81a3..06d72828e5bc 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -73,7 +73,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, switch (multi_ssi_slaves) { case 0x0206: /* SSI0/1/2/9 */ val2 = (1 << 4) | /* SSI0129 sync */ - rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1; + (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1); /* fall through */ case 0x0006: /* SSI0/1/2 */ val1 = rsnd_rdai_is_clk_master(rdai) ? -- cgit v1.2.3 From 24338722cfa23fdf4e08c6189a11f7e3a902d86a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Jan 2016 15:15:37 +0000 Subject: ASoC: wm5110: Fix PGA clear when disabling DRE We don't want to use a bypassed write in wm5110_clear_pga_volume, we might disable the DRE whilst the CODEC is powered down. A normal regmap_write will always go to the hardware (when not on cache_only) even if the written value matches the cache. As using a normal write will still achieve the desired behaviour of bring the cache and hardware in sync, this patch updates the function to use a normal write, which avoids issues when the CODEC is powered down. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/wm5110.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index c04c0bc6f58a..52b9ccf6d389 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, static int wm5110_clear_pga_volume(struct arizona *arizona, int output) { - struct reg_sequence clear_pga = { - ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 - }; + unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4; int ret; - ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1); + ret = regmap_write(arizona->regmap, reg, 0x80); if (ret) dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n", - clear_pga.reg, ret); + reg, ret); return ret; } -- cgit v1.2.3 From 565ace464105cb9623cbf4eb9549d4b0c24166c9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Jan 2016 12:33:18 +0000 Subject: ASoC: wm_adsp: Add a handler for the compressed IRQ Here support is added for responding to DSP IRQs that are used to indicate data being available on the DSP. The idea is that we check the amount of data available upon receipt of an IRQ and on subsequent calls to the pointer callback we recheck once less than one fragment is available (to avoid excessive SPI traffic), if there is truely less than one fragment available we ack the last IRQ and wait for a new one. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 27 +++++++ sound/soc/codecs/wm_adsp.c | 188 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 3 + 3 files changed, 218 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index c36409601835..dde94c4a0caa 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2177,10 +2177,23 @@ static int wm5110_open(struct snd_compr_stream *stream) return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream); } +static irqreturn_t wm5110_adsp2_irq(int irq, void *data) +{ + struct wm5110_priv *florida = data; + int ret; + + ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]); + if (ret == -ENODEV) + return IRQ_NONE; + + return IRQ_HANDLED; +} + static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i, ret; priv->core.arizona->dapm = dapm; @@ -2189,6 +2202,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_mono(codec); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5110_adsp2_irq, + priv); + if (ret != 0) { + dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) @@ -2209,12 +2230,15 @@ err_adsp2_codec_probe: for (--i; i >= 0; --i) wm_adsp2_codec_remove(&priv->core.adsp[i], codec); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i; for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2222,6 +2246,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return 0; } @@ -2273,6 +2299,7 @@ static struct snd_compr_ops wm5110_compr_ops = { .set_params = wm_adsp_compr_set_params, .get_caps = wm_adsp_compr_get_caps, .trigger = wm_adsp_compr_trigger, + .pointer = wm_adsp_compr_pointer, }; static struct snd_soc_platform_driver wm5110_compr_platform = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ac879d16c6a6..49ef0bbe9892 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -279,6 +279,11 @@ struct wm_adsp_compr_buf { struct wm_adsp_buffer_region *regions; u32 host_buf_ptr; + + u32 error; + u32 irq_count; + int read_index; + int avail; }; struct wm_adsp_compr { @@ -287,6 +292,8 @@ struct wm_adsp_compr { struct snd_compr_stream *stream; struct snd_compressed_buffer size; + + unsigned int copied_total; }; #define WM_ADSP_DATA_WORD_SIZE 3 @@ -2436,6 +2443,11 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, return -EINVAL; } +static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) +{ + return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; +} + int wm_adsp_compr_set_params(struct snd_compr_stream *stream, struct snd_compr_params *params) { @@ -2622,6 +2634,8 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp) return -ENOMEM; buf->dsp = dsp; + buf->read_index = -1; + buf->irq_count = 0xFFFFFFFF; ret = wm_adsp_buffer_locate(buf); if (ret < 0) { @@ -2705,6 +2719,16 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) ret); break; } + + /* Trigger the IRQ at one fragment of data */ + ret = wm_adsp_buffer_write(compr->buf, + HOST_BUFFER_FIELD(high_water_mark), + wm_adsp_compr_frag_words(compr)); + if (ret < 0) { + adsp_err(dsp, "Failed to set high water mark: %d\n", + ret); + break; + } break; case SNDRV_PCM_TRIGGER_STOP: break; @@ -2719,4 +2743,168 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) } EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); +static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf) +{ + int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1; + + return buf->regions[last_region].cumulative_size; +} + +static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) +{ + u32 next_read_index, next_write_index; + int write_index, read_index, avail; + int ret; + + /* Only sync read index if we haven't already read a valid index */ + if (buf->read_index < 0) { + ret = wm_adsp_buffer_read(buf, + HOST_BUFFER_FIELD(next_read_index), + &next_read_index); + if (ret < 0) + return ret; + + read_index = sign_extend32(next_read_index, 23); + + if (read_index < 0) { + adsp_dbg(buf->dsp, "Avail check on unstarted stream\n"); + return 0; + } + + buf->read_index = read_index; + } + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index), + &next_write_index); + if (ret < 0) + return ret; + + write_index = sign_extend32(next_write_index, 23); + + avail = write_index - buf->read_index; + if (avail < 0) + avail += wm_adsp_buffer_size(buf); + + adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", + buf->read_index, write_index, avail); + + buf->avail = avail; + + return 0; +} + +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf = dsp->buffer; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + if (!buf) { + adsp_err(dsp, "Spurious buffer IRQ\n"); + ret = -ENODEV; + goto out; + } + + adsp_dbg(dsp, "Handling buffer IRQ\n"); + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); + if (ret < 0) { + adsp_err(dsp, "Failed to check buffer error: %d\n", ret); + goto out; + } + if (buf->error != 0) { + adsp_err(dsp, "Buffer error occurred: %d\n", buf->error); + ret = -EIO; + goto out; + } + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), + &buf->irq_count); + if (ret < 0) { + adsp_err(dsp, "Failed to get irq_count: %d\n", ret); + goto out; + } + + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq); + +static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) +{ + if (buf->irq_count & 0x01) + return 0; + + adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n", + buf->irq_count); + + buf->irq_count |= 0x01; + + return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack), + buf->irq_count); +} + +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp_compr_buf *buf = compr->buf; + struct wm_adsp *dsp = compr->dsp; + int ret = 0; + + adsp_dbg(dsp, "Pointer request\n"); + + mutex_lock(&dsp->pwr_lock); + + if (!compr->buf) { + ret = -ENXIO; + goto out; + } + + if (compr->buf->error) { + ret = -EIO; + goto out; + } + + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + /* + * If we really have less than 1 fragment available tell the + * DSP to inform us once a whole fragment is available. + */ + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_reenable_irq(buf); + if (ret < 0) { + adsp_err(dsp, + "Failed to re-enable buffer IRQ: %d\n", + ret); + goto out; + } + } + } + + tstamp->copied_total = compr->copied_total; + tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 43af093fafcf..522fa1ada4e6 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -112,5 +112,8 @@ extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, struct snd_compr_caps *caps); extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); +extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp); #endif -- cgit v1.2.3 From 83a40ce993cda0757b102389e38446e79a2cc172 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Jan 2016 12:33:19 +0000 Subject: ASoC: wm_adsp: Pull data through compressed read Data is read in blocks of up to one fragment is size from the circular buffer on the DSP and is re-packed to remove the padding byte that exists in the DSP memory map. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 1 + sound/soc/codecs/wm_adsp.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 2 + 3 files changed, 141 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index dde94c4a0caa..61fa7cc91d15 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2300,6 +2300,7 @@ static struct snd_compr_ops wm5110_compr_ops = { .get_caps = wm_adsp_compr_get_caps, .trigger = wm_adsp_compr_trigger, .pointer = wm_adsp_compr_pointer, + .copy = wm_adsp_compr_copy, }; static struct snd_soc_platform_driver wm5110_compr_platform = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 49ef0bbe9892..33806d487b8a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -293,6 +293,7 @@ struct wm_adsp_compr { struct snd_compr_stream *stream; struct snd_compressed_buffer size; + u32 *raw_buf; unsigned int copied_total; }; @@ -2385,6 +2386,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream) dsp->compr = NULL; + kfree(compr->raw_buf); kfree(compr); mutex_unlock(&dsp->pwr_lock); @@ -2452,6 +2454,7 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream, struct snd_compr_params *params) { struct wm_adsp_compr *compr = stream->runtime->private_data; + unsigned int size; int ret; ret = wm_adsp_compr_check_params(stream, params); @@ -2463,6 +2466,11 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream, adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", compr->size.fragment_size, compr->size.fragments); + size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); + compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); + if (!compr->raw_buf) + return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); @@ -2796,6 +2804,7 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) { struct wm_adsp_compr_buf *buf = dsp->buffer; + struct wm_adsp_compr *compr = dsp->compr; int ret = 0; mutex_lock(&dsp->pwr_lock); @@ -2832,6 +2841,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) goto out; } + if (compr->stream) + snd_compr_fragment_elapsed(compr->stream); + out: mutex_unlock(&dsp->pwr_lock); @@ -2907,4 +2919,130 @@ out: } EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); +static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) +{ + struct wm_adsp_compr_buf *buf = compr->buf; + u8 *pack_in = (u8 *)compr->raw_buf; + u8 *pack_out = (u8 *)compr->raw_buf; + unsigned int adsp_addr; + int mem_type, nwords, max_read; + int i, j, ret; + + /* Calculate read parameters */ + for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) + if (buf->read_index < buf->regions[i].cumulative_size) + break; + + if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions) + return -EINVAL; + + mem_type = buf->regions[i].mem_type; + adsp_addr = buf->regions[i].base_addr + + (buf->read_index - buf->regions[i].offset); + + max_read = wm_adsp_compr_frag_words(compr); + nwords = buf->regions[i].cumulative_size - buf->read_index; + + if (nwords > target) + nwords = target; + if (nwords > buf->avail) + nwords = buf->avail; + if (nwords > max_read) + nwords = max_read; + if (!nwords) + return 0; + + /* Read data from DSP */ + ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr, + nwords, compr->raw_buf); + if (ret < 0) + return ret; + + /* Remove the padding bytes from the data read from the DSP */ + for (i = 0; i < nwords; i++) { + for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++) + *pack_out++ = *pack_in++; + + pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE; + } + + /* update read index to account for words read */ + buf->read_index += nwords; + if (buf->read_index == wm_adsp_buffer_size(buf)) + buf->read_index = 0; + + ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index), + buf->read_index); + if (ret < 0) + return ret; + + /* update avail to account for words read */ + buf->avail -= nwords; + + return nwords; +} + +static int wm_adsp_compr_read(struct wm_adsp_compr *compr, + char __user *buf, size_t count) +{ + struct wm_adsp *dsp = compr->dsp; + int ntotal = 0; + int nwords, nbytes; + + adsp_dbg(dsp, "Requested read of %zu bytes\n", count); + + if (!compr->buf) + return -ENXIO; + + if (compr->buf->error) + return -EIO; + + count /= WM_ADSP_DATA_WORD_SIZE; + + do { + nwords = wm_adsp_buffer_capture_block(compr, count); + if (nwords < 0) { + adsp_err(dsp, "Failed to capture block: %d\n", nwords); + return nwords; + } + + nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; + + adsp_dbg(dsp, "Read %d bytes\n", nbytes); + + if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { + adsp_err(dsp, "Failed to copy data to user: %d, %d\n", + ntotal, nbytes); + return -EFAULT; + } + + count -= nwords; + ntotal += nbytes; + } while (nwords > 0 && count > 0); + + compr->copied_total += ntotal; + + return ntotal; +} + +int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, + size_t count) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret; + + mutex_lock(&dsp->pwr_lock); + + if (stream->direction == SND_COMPRESS_CAPTURE) + ret = wm_adsp_compr_read(compr, buf, count); + else + ret = -ENOTSUPP; + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 522fa1ada4e6..1a928ec54741 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -115,5 +115,7 @@ extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp); +extern int wm_adsp_compr_copy(struct snd_compr_stream *stream, + char __user *buf, size_t count); #endif -- cgit v1.2.3 From 5307246015bceb2758f1eee078c6bdc8545ac91f Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 9 Dec 2015 21:46:09 +0530 Subject: ASoC: hdac_hdmi: Fix to warn instead of err for no connected nids It is possible that some pin widget may return with no converter connected. So don't throw error if none are found to be connected. Instead print a warning and continue. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e6dc4cd037d3..41117e130ce0 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -316,10 +316,12 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, pin->mux_nids, HDA_MAX_CONNECTIONS); - if (pin->num_mux_nids == 0) { - dev_err(&hdac->hdac.dev, "No connections found\n"); - return -ENODEV; - } + if (pin->num_mux_nids == 0) + dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", + pin->nid); + + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", + pin->num_mux_nids, pin->nid); return pin->num_mux_nids; } -- cgit v1.2.3 From defbf708baf2a4cc4421699d02b57d7c3bb728b0 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Fri, 8 Jan 2016 16:57:01 +0800 Subject: ASoC: wm8960: add DAC mono mix kcontrol In normal operation, the left and right channel digital audio data is converted to analogue in two separate DACs. There is a mono-mix mode where the two audio channels are mixed together digitally and then converted to analogue using only one DAC, while the other DAC is switched off. The mono-mix signal can be selected to appear on both analogue output channels. The mono mix is automatically attenuated by 6dB to prevent clipping. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 328bde09d5bf..9e90b8e2b86e 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -153,6 +153,7 @@ static const char *wm8960_adc_data_output_sel[] = { "Left Data = Right ADC; Right Data = Right ADC", "Left Data = Right ADC; Right Data = Left ADC", }; +static const char *wm8960_dmonomix[] = {"Stereo", "Mono"}; static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), @@ -162,6 +163,7 @@ static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), + SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), }; static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; @@ -304,6 +306,7 @@ SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), +SOC_ENUM("DAC Mono Mix", wm8960_enum[7]), }; static const struct snd_kcontrol_new wm8960_lin_boost[] = { -- cgit v1.2.3 From 2d4a32602bc5d4d8f9a80c6b66a4e28d5f2d4798 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Fri, 8 Jan 2016 16:57:02 +0800 Subject: ASoC: wm8960: boost switch should be closed when using L/RINPUT1 L/RINPUT1 can line to Left/Right Boost Mixer through boost switch. If boost switch is open, there will be no voice when using L/RINPUT1. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 9e90b8e2b86e..28bfe39b5f34 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -413,8 +413,8 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" }, { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" }, - { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", }, - { "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */ + { "Left Input Mixer", "Boost Switch", "Left Boost Mixer" }, + { "Left Input Mixer", "Boost Switch", "LINPUT1" }, /* Really Boost Switch */ { "Left Input Mixer", NULL, "LINPUT2" }, { "Left Input Mixer", NULL, "LINPUT3" }, @@ -422,8 +422,8 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" }, { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" }, - { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, - { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ + { "Right Input Mixer", "Boost Switch", "Right Boost Mixer" }, + { "Right Input Mixer", "Boost Switch", "RINPUT1" }, /* Really Boost Switch */ { "Right Input Mixer", NULL, "RINPUT2" }, { "Right Input Mixer", NULL, "RINPUT3" }, @@ -431,11 +431,11 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Right ADC", NULL, "Right Input Mixer" }, { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" }, - { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} , + { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" }, { "Left Output Mixer", "PCM Playback Switch", "Left DAC" }, { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" }, - { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } , + { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" }, { "Right Output Mixer", "PCM Playback Switch", "Right DAC" }, { "LOUT1 PGA", NULL, "Left Output Mixer" }, -- cgit v1.2.3 From 15b914476bf24185534a59fb8e149d465ff79c59 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 9 Dec 2015 21:46:10 +0530 Subject: ASoC: hdac_hdmi: Use list to add pins and converters Future platforms may have a different set of pins/converters. So use lists to add pins and converters based on enumeration. Also it may be required to connect any converter to any pin dynamically as per different use cases (for example DP is connected to pin 6 on skylake board). So this will help in dynamically select and route. Fix the dai map as well to use the pin/cvt from list. Not enabling all dai maps for now. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 154 +++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 48 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 41117e130ce0..f5df7232405b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -43,11 +43,13 @@ struct hdac_hdmi_cvt_params { }; struct hdac_hdmi_cvt { + struct list_head head; hda_nid_t nid; struct hdac_hdmi_cvt_params params; }; struct hdac_hdmi_pin { + struct list_head head; hda_nid_t nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; @@ -55,14 +57,16 @@ struct hdac_hdmi_pin { struct hdac_hdmi_dai_pin_map { int dai_id; - struct hdac_hdmi_pin pin; - struct hdac_hdmi_cvt cvt; + struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt; }; struct hdac_hdmi_priv { - hda_nid_t pin_nid[3]; - hda_nid_t cvt_nid[3]; struct hdac_hdmi_dai_pin_map dai_map[3]; + struct list_head pin_list; + struct list_head cvt_list; + int num_pin; + int num_cvt; }; static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) @@ -149,13 +153,15 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) { /* Power up pin widget */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0, + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); /* Power up converter */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); } @@ -179,13 +185,13 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dd->stream_tag, dd->format); - ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid, - dai_map->pin.nid); + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, + dai_map->pin->nid); if (ret < 0) return ret; - return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, - dd->stream_tag, dd->format); + return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, + dai_map->pin->nid, dd->stream_tag, dd->format); } static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, @@ -221,9 +227,9 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; - snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); @@ -249,7 +255,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; - val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0, + val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_GET_PIN_SENSE, 0); dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); @@ -260,7 +266,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); - snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, + snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); snd_pcm_hw_constraint_step(substream->runtime, 0, @@ -280,7 +286,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); - snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, + snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); } @@ -368,40 +374,79 @@ static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); } -static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map, - hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id) +static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { - int ret; + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; + struct hdac_hdmi_cvt *cvt; + struct hdac_hdmi_pin *pin; - dai_map->dai_id = dai_id; - dai_map->pin.nid = pin_nid; + if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) + return -EINVAL; - ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); - if (ret < 0) { - dev_err(&edev->hdac.dev, - "Error querying connection list: %d\n", ret); - return ret; - } + /* + * Currently on board only 1 pin and 1 converter is enabled for + * simplification, more will be added eventually + * So using fixed map for dai_id:pin:cvt + */ + cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); + pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); + + dai_map->dai_id = 0; + dai_map->pin = pin; - dai_map->cvt.nid = cvt_nid; + dai_map->cvt = cvt; /* Enable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 1); /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0); - snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_CONNECT_SEL, 0); - return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt); + return 0; +} + +static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_cvt *cvt; + + cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + if (!cvt) + return -ENOMEM; + + cvt->nid = nid; + + list_add_tail(&cvt->head, &hdmi->cvt_list); + hdmi->num_cvt++; + + return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); +} + +static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + + pin = kzalloc(sizeof(*pin), GFP_KERNEL); + if (!pin) + return -ENOMEM; + + pin->nid = nid; + + list_add_tail(&pin->head, &hdmi->pin_list); + hdmi->num_pin++; + + return 0; } /* @@ -414,7 +459,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) int i, num_nodes; struct hdac_device *hdac = &edev->hdac; struct hdac_hdmi_priv *hdmi = edev->private_data; - int cvt_nid = 0, pin_nid = 0; + int ret; num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); if (!nid || num_nodes <= 0) { @@ -438,29 +483,25 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) switch (type) { case AC_WID_AUD_OUT: - hdmi->cvt_nid[cvt_nid] = nid; - cvt_nid++; + ret = hdac_hdmi_add_cvt(edev, nid); + if (ret < 0) + return ret; break; case AC_WID_PIN: - hdmi->pin_nid[pin_nid] = nid; - pin_nid++; + ret = hdac_hdmi_add_pin(edev, nid); + if (ret < 0) + return ret; break; } } hdac->end_nid = nid; - if (!pin_nid || !cvt_nid) + if (!hdmi->num_pin || !hdmi->num_cvt) return -EIO; - /* - * Currently on board only 1 pin and 1 converter is enabled for - * simplification, more will be added eventually - * So using fixed map for dai_id:pin:cvt - */ - return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], - hdmi->cvt_nid[0], 0); + return hdac_hdmi_init_dai_map(edev); } static int hdmi_codec_probe(struct snd_soc_codec *codec) @@ -544,6 +585,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) dev_set_drvdata(&codec->dev, edev); + INIT_LIST_HEAD(&hdmi_priv->pin_list); + INIT_LIST_HEAD(&hdmi_priv->cvt_list); + ret = hdac_hdmi_parse_and_map_nid(edev); if (ret < 0) return ret; @@ -555,8 +599,22 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) { + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin, *pin_next; + struct hdac_hdmi_cvt *cvt, *cvt_next; + snd_soc_unregister_codec(&edev->hdac.dev); + list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { + list_del(&cvt->head); + kfree(cvt); + } + + list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { + list_del(&pin->head); + kfree(pin); + } + return 0; } -- cgit v1.2.3 From a1068045883ed4a18363a4ebad0c3d55e473b716 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 7 Jan 2016 21:48:14 +0530 Subject: ASoC: compress: Fix compress device direction check The detection of direction for compress was only taking into account codec capabilities and not CPU ones. Fix this by checking the CPU side capabilities as well Cc: Tested-by: Ashish Panwar Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 12a9820feac1..bb82bb966000 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -630,6 +630,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) struct snd_pcm *be_pcm; char new_name[64]; int ret = 0, direction = 0; + int playback = 0, capture = 0; if (rtd->num_codecs > 1) { dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n"); @@ -641,11 +642,27 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) rtd->dai_link->stream_name, codec_dai->name, num); if (codec_dai->driver->playback.channels_min) + playback = 1; + if (codec_dai->driver->capture.channels_min) + capture = 1; + + capture = capture && cpu_dai->driver->capture.channels_min; + playback = playback && cpu_dai->driver->playback.channels_min; + + /* + * Compress devices are unidirectional so only one of the directions + * should be set, check for that (xor) + */ + if (playback + capture != 1) { + dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n", + playback, capture); + return -EINVAL; + } + + if(playback) direction = SND_COMPRESS_PLAYBACK; - else if (codec_dai->driver->capture.channels_min) - direction = SND_COMPRESS_CAPTURE; else - return -EINVAL; + direction = SND_COMPRESS_CAPTURE; compr = kzalloc(sizeof(*compr), GFP_KERNEL); if (compr == NULL) { -- cgit v1.2.3 From 4ab936d1aca69978dc738592a00e34f836bda1c3 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Sat, 9 Jan 2016 23:47:58 +0100 Subject: ASoC: rockchip: i2s: Add SNDRV_PCM_FMTBIT_S32_LE support Signed-off-by: Michael Trimarchi Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 8b0a588ed622..6561c4cc2edd 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -242,6 +242,9 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S24_LE: val |= I2S_TXCR_VDW(24); break; + case SNDRV_PCM_FORMAT_S32_LE: + val |= I2S_TXCR_VDW(32); + break; default: return -EINVAL; } @@ -360,7 +363,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), }, .capture = { .stream_name = "Capture", @@ -370,7 +374,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &rockchip_i2s_dai_ops, .symmetric_rates = 1, -- cgit v1.2.3 From 823733b91619aef5a2be21d0918ef6dd996de72a Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Sun, 10 Jan 2016 00:38:03 +0100 Subject: ASoC: pcm1792a: Rename internal data and function to pcm179x Signed-off-by: Michael Trimarchi Signed-off-by: Mark Brown --- sound/soc/codecs/pcm1792a.c | 158 ++++++++++++++++++++++---------------------- sound/soc/codecs/pcm1792a.h | 6 +- 2 files changed, 82 insertions(+), 82 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 08bb4863e96f..a56c7b767d90 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -1,5 +1,5 @@ /* - * PCM1792A ASoC codec driver + * PCM179X ASoC codec driver * * Copyright (c) Amarula Solutions B.V. 2013 * @@ -31,21 +31,21 @@ #include #include -#include "pcm1792a.h" +#include "pcm179x.h" -#define PCM1792A_DAC_VOL_LEFT 0x10 -#define PCM1792A_DAC_VOL_RIGHT 0x11 -#define PCM1792A_FMT_CONTROL 0x12 -#define PCM1792A_MODE_CONTROL 0x13 -#define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL +#define PCM179X_DAC_VOL_LEFT 0x10 +#define PCM179X_DAC_VOL_RIGHT 0x11 +#define PCM179X_FMT_CONTROL 0x12 +#define PCM179X_MODE_CONTROL 0x13 +#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL -#define PCM1792A_FMT_MASK 0x70 -#define PCM1792A_FMT_SHIFT 4 -#define PCM1792A_MUTE_MASK 0x01 -#define PCM1792A_MUTE_SHIFT 0 -#define PCM1792A_ATLD_ENABLE (1 << 7) +#define PCM179X_FMT_MASK 0x70 +#define PCM179X_FMT_SHIFT 4 +#define PCM179X_MUTE_MASK 0x01 +#define PCM179X_MUTE_SHIFT 0 +#define PCM179X_ATLD_ENABLE (1 << 7) -static const struct reg_default pcm1792a_reg_defaults[] = { +static const struct reg_default pcm179x_reg_defaults[] = { { 0x10, 0xff }, { 0x11, 0xff }, { 0x12, 0x50 }, @@ -56,57 +56,57 @@ static const struct reg_default pcm1792a_reg_defaults[] = { { 0x17, 0x00 }, }; -static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg) +static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg) { return reg >= 0x10 && reg <= 0x17; } -static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg) +static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg) { bool accessible; - accessible = pcm1792a_accessible_reg(dev, reg); + accessible = pcm179x_accessible_reg(dev, reg); return accessible && reg != 0x16 && reg != 0x17; } -struct pcm1792a_private { +struct pcm179x_private { struct regmap *regmap; unsigned int format; unsigned int rate; }; -static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); priv->format = format; return 0; } -static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute) +static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); int ret; - ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE, - PCM1792A_MUTE_MASK, !!mute); + ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE, + PCM179X_MUTE_MASK, !!mute); if (ret < 0) return ret; return 0; } -static int pcm1792a_hw_params(struct snd_pcm_substream *substream, +static int pcm179x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); int val = 0, ret; priv->rate = params_rate(params); @@ -143,129 +143,129 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE; + val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE; - ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL, - PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val); + ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL, + PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val); if (ret < 0) return ret; return 0; } -static const struct snd_soc_dai_ops pcm1792a_dai_ops = { - .set_fmt = pcm1792a_set_dai_fmt, - .hw_params = pcm1792a_hw_params, - .digital_mute = pcm1792a_digital_mute, +static const struct snd_soc_dai_ops pcm179x_dai_ops = { + .set_fmt = pcm179x_set_dai_fmt, + .hw_params = pcm179x_hw_params, + .digital_mute = pcm179x_digital_mute, }; -static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1); +static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1); -static const struct snd_kcontrol_new pcm1792a_controls[] = { - SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, - PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, - pcm1792a_dac_tlv), - SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0), - SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0), +static const struct snd_kcontrol_new pcm179x_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT, + PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, + pcm179x_dac_tlv), + SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0), + SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0), }; -static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { +static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("IOUTL+"), SND_SOC_DAPM_OUTPUT("IOUTL-"), SND_SOC_DAPM_OUTPUT("IOUTR+"), SND_SOC_DAPM_OUTPUT("IOUTR-"), }; -static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = { +static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = { { "IOUTL+", NULL, "Playback" }, { "IOUTL-", NULL, "Playback" }, { "IOUTR+", NULL, "Playback" }, { "IOUTR-", NULL, "Playback" }, }; -static struct snd_soc_dai_driver pcm1792a_dai = { - .name = "pcm1792a-hifi", +static struct snd_soc_dai_driver pcm179x_dai = { + .name = "pcm179x-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = PCM1792A_RATES, .formats = PCM1792A_FORMATS, }, - .ops = &pcm1792a_dai_ops, + .ops = &pcm179x_dai_ops, }; -static const struct of_device_id pcm1792a_of_match[] = { +static const struct of_device_id pcm179x_of_match[] = { { .compatible = "ti,pcm1792a", }, { } }; -MODULE_DEVICE_TABLE(of, pcm1792a_of_match); +MODULE_DEVICE_TABLE(of, pcm179x_of_match); -static const struct regmap_config pcm1792a_regmap = { +static const struct regmap_config pcm179x_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = 23, - .reg_defaults = pcm1792a_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults), - .writeable_reg = pcm1792a_writeable_reg, - .readable_reg = pcm1792a_accessible_reg, + .reg_defaults = pcm179x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults), + .writeable_reg = pcm179x_writeable_reg, + .readable_reg = pcm179x_accessible_reg, }; -static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = { - .controls = pcm1792a_controls, - .num_controls = ARRAY_SIZE(pcm1792a_controls), - .dapm_widgets = pcm1792a_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm1792a_dapm_widgets), - .dapm_routes = pcm1792a_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm1792a_dapm_routes), +static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { + .controls = pcm179x_controls, + .num_controls = ARRAY_SIZE(pcm179x_controls), + .dapm_widgets = pcm179x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), + .dapm_routes = pcm179x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), }; -static int pcm1792a_spi_probe(struct spi_device *spi) +static int pcm179x_spi_probe(struct spi_device *spi) { - struct pcm1792a_private *pcm1792a; + struct pcm179x_private *pcm179x; int ret; - pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private), + pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private), GFP_KERNEL); - if (!pcm1792a) + if (!pcm179x) return -ENOMEM; - spi_set_drvdata(spi, pcm1792a); + spi_set_drvdata(spi, pcm179x); - pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap); - if (IS_ERR(pcm1792a->regmap)) { - ret = PTR_ERR(pcm1792a->regmap); + pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap); + if (IS_ERR(pcm179x->regmap)) { + ret = PTR_ERR(pcm179x->regmap); dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); return ret; } return snd_soc_register_codec(&spi->dev, - &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1); + &soc_codec_dev_pcm179x, &pcm179x_dai, 1); } -static int pcm1792a_spi_remove(struct spi_device *spi) +static int pcm179x_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); return 0; } -static const struct spi_device_id pcm1792a_spi_ids[] = { - { "pcm1792a", 0 }, +static const struct spi_device_id pcm179x_spi_ids[] = { + { "pcm179x", 0 }, { }, }; -MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids); +MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); -static struct spi_driver pcm1792a_codec_driver = { +static struct spi_driver pcm179x_codec_driver = { .driver = { - .name = "pcm1792a", - .of_match_table = of_match_ptr(pcm1792a_of_match), + .name = "pcm179x", + .of_match_table = of_match_ptr(pcm179x_of_match), }, - .id_table = pcm1792a_spi_ids, - .probe = pcm1792a_spi_probe, - .remove = pcm1792a_spi_remove, + .id_table = pcm179x_spi_ids, + .probe = pcm179x_spi_probe, + .remove = pcm179x_spi_remove, }; -module_spi_driver(pcm1792a_codec_driver); +module_spi_driver(pcm179x_codec_driver); -MODULE_DESCRIPTION("ASoC PCM1792A driver"); +MODULE_DESCRIPTION("ASoC PCM179X driver"); MODULE_AUTHOR("Michael Trimarchi "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h index 51d5470fee16..c6fdc062a497 100644 --- a/sound/soc/codecs/pcm1792a.h +++ b/sound/soc/codecs/pcm1792a.h @@ -1,5 +1,5 @@ /* - * definitions for PCM1792A + * definitions for PCM179X * * Copyright 2013 Amarula Solutions * @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ -#ifndef __PCM1792A_H__ -#define __PCM1792A_H__ +#ifndef __PCM179X_H__ +#define __PCM179X_H__ #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ -- cgit v1.2.3 From 0471cd938e244e22f3ead77d2b82230f83e35f69 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Sun, 10 Jan 2016 00:38:04 +0100 Subject: ASoC: pcm1792a: Rename pcm1792a to pcm179x pcm1792a is compatible with pcm1795 and pcm1796 so it's better to have them under the common name pcm179x Signed-off-by: Michael Trimarchi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/pcm1792a.txt | 18 -- .../devicetree/bindings/sound/pcm179x.txt | 18 ++ sound/soc/codecs/Kconfig | 6 +- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/pcm1792a.c | 271 --------------------- sound/soc/codecs/pcm1792a.h | 27 -- sound/soc/codecs/pcm179x.c | 271 +++++++++++++++++++++ sound/soc/codecs/pcm179x.h | 27 ++ 8 files changed, 321 insertions(+), 321 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/pcm1792a.txt create mode 100644 Documentation/devicetree/bindings/sound/pcm179x.txt delete mode 100644 sound/soc/codecs/pcm1792a.c delete mode 100644 sound/soc/codecs/pcm1792a.h create mode 100644 sound/soc/codecs/pcm179x.c create mode 100644 sound/soc/codecs/pcm179x.h (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm1792a.txt deleted file mode 100644 index 970ba1ed576f..000000000000 --- a/Documentation/devicetree/bindings/sound/pcm1792a.txt +++ /dev/null @@ -1,18 +0,0 @@ -Texas Instruments pcm1792a DT bindings - -This driver supports the SPI bus. - -Required properties: - - - compatible: "ti,pcm1792a" - -For required properties on SPI, please consult -Documentation/devicetree/bindings/spi/spi-bus.txt - -Examples: - - codec_spi: 1792a@0 { - compatible = "ti,pcm1792a"; - spi-max-frequency = <600000>; - }; - diff --git a/Documentation/devicetree/bindings/sound/pcm179x.txt b/Documentation/devicetree/bindings/sound/pcm179x.txt new file mode 100644 index 000000000000..4ae70d3462d6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm179x.txt @@ -0,0 +1,18 @@ +Texas Instruments pcm179x DT bindings + +This driver supports the SPI bus. + +Required properties: + + - compatible: "ti,pcm1792a" + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Examples: + + codec_spi: 1792a@0 { + compatible = "ti,pcm1792a"; + spi-max-frequency = <600000>; + }; + diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4c11ea..b28060e55006 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -83,7 +83,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ML26124 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM1792A if SPI_MASTER + select SND_SOC_PCM179X if SPI_MASTER select SND_SOC_PCM3008 select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER @@ -499,8 +499,8 @@ config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" depends on I2C -config SND_SOC_PCM1792A - tristate "Texas Instruments PCM1792A CODEC" +config SND_SOC_PCM179X + tristate "Texas Instruments PCM179X CODEC" depends on SPI_MASTER config SND_SOC_PCM3008 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc42f59f..e4256039ff80 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -76,7 +76,7 @@ snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o snd-soc-nau8825-objs := nau8825.o snd-soc-pcm1681-objs := pcm1681.o -snd-soc-pcm1792a-codec-objs := pcm1792a.o +snd-soc-pcm179x-codec-objs := pcm179x.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o @@ -271,7 +271,7 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o -obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o +obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c deleted file mode 100644 index a56c7b767d90..000000000000 --- a/sound/soc/codecs/pcm1792a.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * PCM179X ASoC codec driver - * - * Copyright (c) Amarula Solutions B.V. 2013 - * - * Michael Trimarchi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcm179x.h" - -#define PCM179X_DAC_VOL_LEFT 0x10 -#define PCM179X_DAC_VOL_RIGHT 0x11 -#define PCM179X_FMT_CONTROL 0x12 -#define PCM179X_MODE_CONTROL 0x13 -#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL - -#define PCM179X_FMT_MASK 0x70 -#define PCM179X_FMT_SHIFT 4 -#define PCM179X_MUTE_MASK 0x01 -#define PCM179X_MUTE_SHIFT 0 -#define PCM179X_ATLD_ENABLE (1 << 7) - -static const struct reg_default pcm179x_reg_defaults[] = { - { 0x10, 0xff }, - { 0x11, 0xff }, - { 0x12, 0x50 }, - { 0x13, 0x00 }, - { 0x14, 0x00 }, - { 0x15, 0x01 }, - { 0x16, 0x00 }, - { 0x17, 0x00 }, -}; - -static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg) -{ - return reg >= 0x10 && reg <= 0x17; -} - -static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg) -{ - bool accessible; - - accessible = pcm179x_accessible_reg(dev, reg); - - return accessible && reg != 0x16 && reg != 0x17; -} - -struct pcm179x_private { - struct regmap *regmap; - unsigned int format; - unsigned int rate; -}; - -static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int format) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); - - priv->format = format; - - return 0; -} - -static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE, - PCM179X_MUTE_MASK, !!mute); - if (ret < 0) - return ret; - - return 0; -} - -static int pcm179x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); - int val = 0, ret; - - priv->rate = params_rate(params); - - switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_width(params)) { - case 24: - case 32: - val = 2; - break; - case 16: - val = 0; - break; - default: - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_I2S: - switch (params_width(params)) { - case 24: - case 32: - val = 5; - break; - case 16: - val = 4; - break; - default: - return -EINVAL; - } - break; - default: - dev_err(codec->dev, "Invalid DAI format\n"); - return -EINVAL; - } - - val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE; - - ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL, - PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val); - if (ret < 0) - return ret; - - return 0; -} - -static const struct snd_soc_dai_ops pcm179x_dai_ops = { - .set_fmt = pcm179x_set_dai_fmt, - .hw_params = pcm179x_hw_params, - .digital_mute = pcm179x_digital_mute, -}; - -static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1); - -static const struct snd_kcontrol_new pcm179x_controls[] = { - SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT, - PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, - pcm179x_dac_tlv), - SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0), - SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0), -}; - -static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = { -SND_SOC_DAPM_OUTPUT("IOUTL+"), -SND_SOC_DAPM_OUTPUT("IOUTL-"), -SND_SOC_DAPM_OUTPUT("IOUTR+"), -SND_SOC_DAPM_OUTPUT("IOUTR-"), -}; - -static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = { - { "IOUTL+", NULL, "Playback" }, - { "IOUTL-", NULL, "Playback" }, - { "IOUTR+", NULL, "Playback" }, - { "IOUTR-", NULL, "Playback" }, -}; - -static struct snd_soc_dai_driver pcm179x_dai = { - .name = "pcm179x-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = PCM1792A_RATES, - .formats = PCM1792A_FORMATS, }, - .ops = &pcm179x_dai_ops, -}; - -static const struct of_device_id pcm179x_of_match[] = { - { .compatible = "ti,pcm1792a", }, - { } -}; -MODULE_DEVICE_TABLE(of, pcm179x_of_match); - -static const struct regmap_config pcm179x_regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 23, - .reg_defaults = pcm179x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults), - .writeable_reg = pcm179x_writeable_reg, - .readable_reg = pcm179x_accessible_reg, -}; - -static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { - .controls = pcm179x_controls, - .num_controls = ARRAY_SIZE(pcm179x_controls), - .dapm_widgets = pcm179x_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), - .dapm_routes = pcm179x_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), -}; - -static int pcm179x_spi_probe(struct spi_device *spi) -{ - struct pcm179x_private *pcm179x; - int ret; - - pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private), - GFP_KERNEL); - if (!pcm179x) - return -ENOMEM; - - spi_set_drvdata(spi, pcm179x); - - pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap); - if (IS_ERR(pcm179x->regmap)) { - ret = PTR_ERR(pcm179x->regmap); - dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); - return ret; - } - - return snd_soc_register_codec(&spi->dev, - &soc_codec_dev_pcm179x, &pcm179x_dai, 1); -} - -static int pcm179x_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} - -static const struct spi_device_id pcm179x_spi_ids[] = { - { "pcm179x", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); - -static struct spi_driver pcm179x_codec_driver = { - .driver = { - .name = "pcm179x", - .of_match_table = of_match_ptr(pcm179x_of_match), - }, - .id_table = pcm179x_spi_ids, - .probe = pcm179x_spi_probe, - .remove = pcm179x_spi_remove, -}; - -module_spi_driver(pcm179x_codec_driver); - -MODULE_DESCRIPTION("ASoC PCM179X driver"); -MODULE_AUTHOR("Michael Trimarchi "); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h deleted file mode 100644 index c6fdc062a497..000000000000 --- a/sound/soc/codecs/pcm1792a.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * definitions for PCM179X - * - * Copyright 2013 Amarula Solutions - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __PCM179X_H__ -#define __PCM179X_H__ - -#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_192000) - -#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S16_LE) - -#endif diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c new file mode 100644 index 000000000000..a56c7b767d90 --- /dev/null +++ b/sound/soc/codecs/pcm179x.c @@ -0,0 +1,271 @@ +/* + * PCM179X ASoC codec driver + * + * Copyright (c) Amarula Solutions B.V. 2013 + * + * Michael Trimarchi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcm179x.h" + +#define PCM179X_DAC_VOL_LEFT 0x10 +#define PCM179X_DAC_VOL_RIGHT 0x11 +#define PCM179X_FMT_CONTROL 0x12 +#define PCM179X_MODE_CONTROL 0x13 +#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL + +#define PCM179X_FMT_MASK 0x70 +#define PCM179X_FMT_SHIFT 4 +#define PCM179X_MUTE_MASK 0x01 +#define PCM179X_MUTE_SHIFT 0 +#define PCM179X_ATLD_ENABLE (1 << 7) + +static const struct reg_default pcm179x_reg_defaults[] = { + { 0x10, 0xff }, + { 0x11, 0xff }, + { 0x12, 0x50 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x15, 0x01 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, +}; + +static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg) +{ + return reg >= 0x10 && reg <= 0x17; +} + +static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg) +{ + bool accessible; + + accessible = pcm179x_accessible_reg(dev, reg); + + return accessible && reg != 0x16 && reg != 0x17; +} + +struct pcm179x_private { + struct regmap *regmap; + unsigned int format; + unsigned int rate; +}; + +static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + + priv->format = format; + + return 0; +} + +static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE, + PCM179X_MUTE_MASK, !!mute); + if (ret < 0) + return ret; + + return 0; +} + +static int pcm179x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + int val = 0, ret; + + priv->rate = params_rate(params); + + switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 24: + case 32: + val = 2; + break; + case 16: + val = 0; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + switch (params_width(params)) { + case 24: + case 32: + val = 5; + break; + case 16: + val = 4; + break; + default: + return -EINVAL; + } + break; + default: + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE; + + ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL, + PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_soc_dai_ops pcm179x_dai_ops = { + .set_fmt = pcm179x_set_dai_fmt, + .hw_params = pcm179x_hw_params, + .digital_mute = pcm179x_digital_mute, +}; + +static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1); + +static const struct snd_kcontrol_new pcm179x_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT, + PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, + pcm179x_dac_tlv), + SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0), + SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = { +SND_SOC_DAPM_OUTPUT("IOUTL+"), +SND_SOC_DAPM_OUTPUT("IOUTL-"), +SND_SOC_DAPM_OUTPUT("IOUTR+"), +SND_SOC_DAPM_OUTPUT("IOUTR-"), +}; + +static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = { + { "IOUTL+", NULL, "Playback" }, + { "IOUTL-", NULL, "Playback" }, + { "IOUTR+", NULL, "Playback" }, + { "IOUTR-", NULL, "Playback" }, +}; + +static struct snd_soc_dai_driver pcm179x_dai = { + .name = "pcm179x-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PCM1792A_RATES, + .formats = PCM1792A_FORMATS, }, + .ops = &pcm179x_dai_ops, +}; + +static const struct of_device_id pcm179x_of_match[] = { + { .compatible = "ti,pcm1792a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm179x_of_match); + +static const struct regmap_config pcm179x_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 23, + .reg_defaults = pcm179x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults), + .writeable_reg = pcm179x_writeable_reg, + .readable_reg = pcm179x_accessible_reg, +}; + +static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { + .controls = pcm179x_controls, + .num_controls = ARRAY_SIZE(pcm179x_controls), + .dapm_widgets = pcm179x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), + .dapm_routes = pcm179x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), +}; + +static int pcm179x_spi_probe(struct spi_device *spi) +{ + struct pcm179x_private *pcm179x; + int ret; + + pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private), + GFP_KERNEL); + if (!pcm179x) + return -ENOMEM; + + spi_set_drvdata(spi, pcm179x); + + pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap); + if (IS_ERR(pcm179x->regmap)) { + ret = PTR_ERR(pcm179x->regmap); + dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); + return ret; + } + + return snd_soc_register_codec(&spi->dev, + &soc_codec_dev_pcm179x, &pcm179x_dai, 1); +} + +static int pcm179x_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static const struct spi_device_id pcm179x_spi_ids[] = { + { "pcm179x", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); + +static struct spi_driver pcm179x_codec_driver = { + .driver = { + .name = "pcm179x", + .of_match_table = of_match_ptr(pcm179x_of_match), + }, + .id_table = pcm179x_spi_ids, + .probe = pcm179x_spi_probe, + .remove = pcm179x_spi_remove, +}; + +module_spi_driver(pcm179x_codec_driver); + +MODULE_DESCRIPTION("ASoC PCM179X driver"); +MODULE_AUTHOR("Michael Trimarchi "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h new file mode 100644 index 000000000000..c6fdc062a497 --- /dev/null +++ b/sound/soc/codecs/pcm179x.h @@ -0,0 +1,27 @@ +/* + * definitions for PCM179X + * + * Copyright 2013 Amarula Solutions + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __PCM179X_H__ +#define __PCM179X_H__ + +#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000) + +#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S16_LE) + +#endif -- cgit v1.2.3 From a9c48f7f5906d02d4ec4aa50b1c20fccbce53eec Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:11:59 +0530 Subject: ALSA: hdac: Add support for hda DMA Resume capability Skylake sports new capability of DMA resume, DRSM where we can resume the DMA. This capability is defined by presence of AZX_DRSM_CAP_ID. If this capability is present, we use this capability. So we add: snd_hdac_ext_stream_drsm_enable() - DMA resume caps snd_hdac_ext_stream_set_dpibr() - set the DMA position snd_hdac_ext_stream_set_lpib() - set the lpib Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/hda_register.h | 9 +++++ include/sound/hdaudio_ext.h | 14 ++++++++ sound/hda/ext/hdac_ext_controller.c | 6 ++++ sound/hda/ext/hdac_ext_stream.c | 71 +++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) (limited to 'sound') diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 2ae8812d7b1a..28ac1f9a18ac 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -230,6 +230,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_MLCTL_SPA (1<<16) #define AZX_MLCTL_CPA 23 + +/* registers for DMA Resume Capability Structure */ +#define AZX_DRSM_CAP_ID 0x5 +#define AZX_REG_DRSM_CTL 0x4 +/* Base used to calculate the iterating register offset */ +#define AZX_DRSM_BASE 0x08 +/* Interval used to calculate the iterating register offset */ +#define AZX_DRSM_INTERVAL 0x08 + /* * helpers to read the stream position */ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 425af0674557..f3454950ee0b 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -12,6 +12,7 @@ * @spbcap: SPIB capabilities pointer * @mlcap: MultiLink capabilities pointer * @gtscap: gts capabilities pointer + * @drsmcap: dma resume capabilities pointer * @hlink_list: link list of HDA links */ struct hdac_ext_bus { @@ -23,6 +24,7 @@ struct hdac_ext_bus { void __iomem *spbcap; void __iomem *mlcap; void __iomem *gtscap; + void __iomem *drsmcap; struct list_head hlink_list; }; @@ -72,6 +74,9 @@ enum hdac_ext_stream_type { * @pplc_addr: processing pipe link stream pointer * @spib_addr: software position in buffers stream pointer * @fifo_addr: software position Max fifos stream pointer + * @dpibr_addr: DMA position in buffer resume pointer + * @dpib: DMA position in buffer + * @lpib: Linear position in buffer * @decoupled: stream host and link is decoupled * @link_locked: link is locked * @link_prepared: link is prepared @@ -86,6 +91,10 @@ struct hdac_ext_stream { void __iomem *spib_addr; void __iomem *fifo_addr; + void __iomem *dpibr_addr; + + u32 dpib; + u32 lpib; bool decoupled:1; bool link_locked:1; bool link_prepared; @@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream, u32 value); int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream); +void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, + bool enable, int index); +int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *stream, u32 value); +int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value); void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream); diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 63215b17247c..556267e75591 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus) ebus->spbcap = bus->remap_addr + offset; break; + case AZX_DRSM_CAP_ID: + /* DMA resume capability found, handler function */ + dev_dbg(bus->dev, "Found DRSM capability\n"); + ebus->drsmcap = bus->remap_addr + offset; + break; + default: dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); break; diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index cb89ec7c8147..8f30e8836818 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus, AZX_SPB_MAXFIFO; } + if (ebus->drsmcap) + stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE + + AZX_DRSM_INTERVAL * idx; + stream->decoupled = false; snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag); } @@ -497,3 +501,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus) } } EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams); + +/** + * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream + * @ebus: HD-audio ext core bus + * @enable: flag to enable/disable DRSM + * @index: stream index for which DRSM need to be enabled + */ +void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, + bool enable, int index) +{ + u32 mask = 0; + u32 register_mask = 0; + struct hdac_bus *bus = &ebus->bus; + + if (!ebus->drsmcap) { + dev_err(bus->dev, "Address of DRSM capability is NULL"); + return; + } + + mask |= (1 << index); + + register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL); + + mask |= register_mask; + + if (enable) + snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); + else + snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); + +/** + * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream + * @ebus: HD-audio ext core bus + * @stream: hdac_ext_stream + * @value: dpib value to set + */ +int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *stream, u32 value) +{ + struct hdac_bus *bus = &ebus->bus; + + if (!ebus->drsmcap) { + dev_err(bus->dev, "Address of DRSM capability is NULL"); + return -EINVAL; + } + + writel(value, stream->dpibr_addr); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr); + +/** + * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream + * @ebus: HD-audio ext core bus + * @stream: hdac_ext_stream + * @value: lpib value to set + */ +int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value) +{ + snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib); -- cgit v1.2.3 From 88888155c555487037b894a97a2a4c6a8155cda0 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:12:00 +0530 Subject: ALSA: hdac: couple the hda DMA stream in cleanup A stream is by default in coupled mode, in DSP operation we move it to decoupled mode. On cleanup HW expects that we leave it back to default state so couple the DMA on cleanup. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/hda/ext/hdac_ext_stream.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 8f30e8836818..023cc4cad5c1 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -111,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus) while (!list_empty(&bus->stream_list)) { s = list_first_entry(&bus->stream_list, struct hdac_stream, list); stream = stream_to_hdac_ext_stream(s); + snd_hdac_ext_stream_decouple(ebus, stream, false); list_del(&s->list); kfree(stream); } -- cgit v1.2.3 From cf8fe58b1066cea668e030d0ab61e4b8eef8b219 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Fri, 18 Dec 2015 15:12:01 +0530 Subject: ALSA: hdac: Increase timeout value for link power check HW recommends 180us for worst case values for link power up delay, so change the current delay value from 50 (150us) to 150 (450us) Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/hda/ext/hdac_ext_controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 556267e75591..1a55a781270d 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -246,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) int mask = (1 << AZX_MLCTL_CPA); udelay(3); - timeout = 50; + timeout = 150; do { val = readl(link->ml_addr + AZX_REG_ML_LCTL); -- cgit v1.2.3 From 6706a19747eb693ff35ce140f5cbee66dcfec0c4 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 18 Dec 2015 15:12:02 +0530 Subject: ALSA: hdac: add snd_hdac_ext_bus_link_power_up_all We have an API for powering down all links, we need a similar one for powering up links, so add for power up as well Signed-off-by: Jayachandran B Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/hdaudio_ext.h | 1 + sound/hda/ext/hdac_ext_controller.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'sound') diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index f3454950ee0b..07fa59237feb 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -147,6 +147,7 @@ struct hdac_ext_link { int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); +int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus); int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus); void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, int stream); diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 1a55a781270d..548cc1e4114b 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -287,6 +287,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); +/** + * snd_hdac_ext_bus_link_power_up_all -power up all hda link + * @ebus: HD-audio extended bus + */ +int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus) +{ + struct hdac_ext_link *hlink = NULL; + int ret; + + list_for_each_entry(hlink, &ebus->hlink_list, list) { + snd_hdac_updatel(hlink->ml_addr, + AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + ret = check_hdac_link_power_active(hlink, true); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all); + /** * snd_hdac_ext_bus_link_power_down_all -power down all hda link * @ebus: HD-audio extended bus -- cgit v1.2.3 From 5e4fb372117f476e0c7f85418ed3e39506fbb75c Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 31 Dec 2015 16:40:20 +0800 Subject: ASoC: Define soc_add_dai() to add a DAI to a component Define soc_add_dai() as a wrapper to add a single DAI to a component. It can be reused to register a DAI dynamically by topology. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 88 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6b1982dcedf1..1bd0b37b907f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2744,6 +2744,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) } } +/* Create a DAI and add it to the component's DAI list */ +static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) +{ + struct device *dev = component->dev; + struct snd_soc_dai *dai; + + dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); + + dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + if (dai == NULL) + return NULL; + + /* + * Back in the old days when we still had component-less DAIs, + * instead of having a static name, component-less DAIs would + * inherit the name of the parent device so it is possible to + * register multiple instances of the DAI. We still need to keep + * the same naming style even though those DAIs are not + * component-less anymore. + */ + if (legacy_dai_naming && + (dai_drv->id == 0 || dai_drv->name == NULL)) { + dai->name = fmt_single_name(dev, &dai->id); + } else { + dai->name = fmt_multiple_name(dev, dai_drv); + if (dai_drv->id) + dai->id = dai_drv->id; + else + dai->id = component->num_dai; + } + if (dai->name == NULL) { + kfree(dai); + return NULL; + } + + dai->component = component; + dai->dev = dev; + dai->driver = dai_drv; + if (!dai->driver->ops) + dai->driver->ops = &null_dai_ops; + + list_add(&dai->list, &component->dai_list); + component->num_dai++; + + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); + return dai; +} + /** * snd_soc_register_dais - Register a DAI with the ASoC core * @@ -2765,49 +2815,15 @@ static int snd_soc_register_dais(struct snd_soc_component *component, dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); component->dai_drv = dai_drv; - component->num_dai = count; for (i = 0; i < count; i++) { - dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + dai = soc_add_dai(component, dai_drv + i, + count == 1 && legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; } - - /* - * Back in the old days when we still had component-less DAIs, - * instead of having a static name, component-less DAIs would - * inherit the name of the parent device so it is possible to - * register multiple instances of the DAI. We still need to keep - * the same naming style even though those DAIs are not - * component-less anymore. - */ - if (count == 1 && legacy_dai_naming && - (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) { - dai->name = fmt_single_name(dev, &dai->id); - } else { - dai->name = fmt_multiple_name(dev, &dai_drv[i]); - if (dai_drv[i].id) - dai->id = dai_drv[i].id; - else - dai->id = i; - } - if (dai->name == NULL) { - kfree(dai); - ret = -ENOMEM; - goto err; - } - - dai->component = component; - dai->dev = dev; - dai->driver = &dai_drv[i]; - if (!dai->driver->ops) - dai->driver->ops = &null_dai_ops; - - list_add(&dai->list, &component->dai_list); - - dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); } return 0; -- cgit v1.2.3 From 68003e6cf2bbd239a322bd8a28dacfaf8174fdee Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 31 Dec 2015 16:40:43 +0800 Subject: ASoC: Support registering a DAI dynamically Define API snd_soc_register_dai() to add a DAI dynamically and create the DAI widgets. Topology can use this API to register DAIs when probing a component with topology info. These DAIs's playback & capture widgets will be freed when the sound card is unregistered and the DAIs will be freed when cleaning up the component. And a dobj is embedded into the struct snd_soc_dai_driver. Topology can use the dobj to find the DAI drivers created by it and free them when the topology component is removed. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 212eaaf172ed..964b7de1a1cc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -222,6 +222,7 @@ struct snd_soc_dai_driver { const char *name; unsigned int id; unsigned int base; + struct snd_soc_dobj dobj; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); diff --git a/include/sound/soc.h b/include/sound/soc.h index af347bcdc2f6..9d1383e8d039 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1663,6 +1663,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv); + #include #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1bd0b37b907f..c572673a5a24 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2834,6 +2834,48 @@ err: return ret; } +/** + * snd_soc_register_dai - Register a DAI dynamically & create its widgets + * + * @component: The component the DAIs are registered for + * @dai_drv: DAI driver to use for the DAI + * + * Topology can use this API to register DAIs when probing a component. + * These DAIs's widgets will be freed in the card cleanup and the DAIs + * will be freed in the component cleanup. + */ +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_dai *dai; + int ret; + + if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { + dev_err(component->dev, "Invalid dai type %d\n", + dai_drv->dobj.type); + return -EINVAL; + } + + lockdep_assert_held(&client_mutex); + dai = soc_add_dai(component, dai_drv, false); + if (!dai) + return -ENOMEM; + + /* Create the DAI widgets here. After adding DAIs, topology may + * also add routes that need these widgets as source or sink. + */ + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dai); + static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, enum snd_soc_dapm_type type, int subseq) { -- cgit v1.2.3 From a242cac1d3aa098fbe51097d2b1dcae8b662b761 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 8 Jan 2016 18:22:05 -0500 Subject: ASoC: dwc: add quirk to override COMP_PARAM_1 register DWC for capture in ACP 2.x IP reports playback and capture capabilities though it supports only capture. Added a quirk to override default value to represent capture capability only. Signed-off-by: Maruthi Bayyavarapu Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- include/sound/designware_i2s.h | 1 + sound/soc/dwc/designware_i2s.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'sound') diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index e0bb45807f29..5681855396c4 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -46,6 +46,7 @@ struct i2s_platform_data { u32 snd_rates; #define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0) + #define DW_I2S_QUIRK_COMP_PARAM1 (1 << 1) unsigned int quirks; unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp2; diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 825a1f480aab..ce664c239be3 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -500,6 +500,10 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); u32 idx; + if (dev->capability & DWC_I2S_RECORD && + dev->quirks & DW_I2S_QUIRK_COMP_PARAM1) + comp1 = comp1 & ~BIT(5); + if (COMP1_TX_ENABLED(comp1)) { dev_dbg(dev->dev, " designware: play supported\n"); idx = COMP1_TX_WORDSIZE_0(comp1); -- cgit v1.2.3 From 0c8ba9d28518822d612de23fc9020b2a66a0228c Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Fri, 18 Dec 2015 15:12:03 +0530 Subject: ASoC: Intel: Skylake: fix reset controller sequencing MISCBDCGE is a new register for Misc Backbone clock gate control which is useful to control while resetting the link and ensuring controller is in required state so add API to control it HW recommends that we reset with CGCTL.MISCBDCGE disabled, so add that while doing init chip and reset sequence. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.h | 5 ++++ sound/soc/intel/skylake/skl.c | 55 +++++++++++++++++++++++++++++++++-- sound/soc/intel/skylake/skl.h | 3 ++ 3 files changed, 60 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 1bbcdb471cf2..d59d1ba62a43 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -55,6 +55,11 @@ struct skl_sst { /* IPC messaging */ struct sst_generic_ipc ipc; + + /* callback for miscbdge */ + void (*enable_miscbdcge)(struct device *dev, bool enable); + /*Is CGCTL.MISCBDCGE disabled*/ + bool miscbdcg_disabled; }; struct skl_ipc_init_instance_msg { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index b69649aa7809..dd38f5feb7c0 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -29,6 +29,8 @@ #include #include "../common/sst-acpi.h" #include "skl.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" /* * initialize the PCI registers @@ -59,6 +61,49 @@ static void skl_init_pci(struct skl *skl) skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); } +static void update_pci_dword(struct pci_dev *pci, + unsigned int reg, u32 mask, u32 val) +{ + u32 data = 0; + + pci_read_config_dword(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_dword(pci, reg, data); +} + +/* + * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits + * + * @dev: device pointer + * @enable: enable/disable flag + */ +static void skl_enable_miscbdcge(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + u32 val; + + val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; + + update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); +} + +/* + * While performing reset, controller may not come back properly causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +static int skl_init_chip(struct hdac_bus *bus, bool full_reset) +{ + int ret; + + skl_enable_miscbdcge(bus->dev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + skl_enable_miscbdcge(bus->dev, true); + + return ret; +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { @@ -145,7 +190,9 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) return ret; snd_hdac_bus_stop_chip(bus); + skl_enable_miscbdcge(bus->dev, false); snd_hdac_bus_enter_link_reset(bus); + skl_enable_miscbdcge(bus->dev, true); return 0; } @@ -156,7 +203,7 @@ static int _skl_resume(struct hdac_ext_bus *ebus) struct hdac_bus *bus = ebus_to_hbus(ebus); skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); return skl_resume_dsp(skl); } @@ -380,7 +427,7 @@ static int skl_codec_create(struct hdac_ext_bus *ebus) * back to the sanity state. */ snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); } } } @@ -490,7 +537,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* initialize chip */ skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); /* codec detection */ if (!bus->codec_mask) { @@ -539,6 +586,8 @@ static int skl_probe(struct pci_dev *pci, dev_dbg(bus->dev, "error failed to register dsp\n"); goto out_mach_free; } + skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; + } if (ebus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 36a1b8c5f6d0..8a08bb727991 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -48,6 +48,9 @@ #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 +#define AZX_PCIREG_CGCTL 0x48 +#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) + struct skl_dsp_resource { u32 max_mcps; u32 max_mem; -- cgit v1.2.3 From 721c3e36f774150f453216efcf5e1895577ac68c Mon Sep 17 00:00:00 2001 From: "Dharageswari.R" Date: Fri, 18 Dec 2015 15:12:04 +0530 Subject: ASoC: Intel: Skylake: Use CGCTL.MISCBDCGE for Phrase detection notification Per HW recommendation, SW shall clear the CGCTL.MISCBDCGE and set it back once data is transferred. So clear this when we get the IPC and track using a driver flag, and set back on closure Signed-off-by: Dharageswari.R Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 13 +++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.c | 15 +++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b89ae6f7c096..8039a0479053 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -25,6 +25,8 @@ #include #include "skl.h" #include "skl-topology.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" #define HDA_MONO 1 #define HDA_STEREO 2 @@ -272,6 +274,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; + struct skl *skl = ebus_to_skl(ebus); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -285,6 +288,16 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); skl_set_suspend_active(substream, dai, false); + /* + * check if close is for "Reference Pin" and set back the + * CGCTL.MISCBDCGE if disabled by driver + */ + if (!strncmp(dai->name, "Reference Pin", 13) && + skl->skl_sst->miscbdcg_disabled) { + skl->skl_sst->enable_miscbdcge(dai->dev, true); + skl->skl_sst->miscbdcg_disabled = false; + } + kfree(dma_params); } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 62e665a3b8f7..543460293b00 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -16,8 +16,10 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "sound/hdaudio_ext.h" #define IPC_IXC_STATUS_BITS 24 @@ -322,6 +324,19 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, wake_up(&skl->boot_wait); break; + case IPC_GLB_NOTIFY_PHRASE_DETECTED: + dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); + + /* + * Per HW recomendation, After phrase detection, + * clear the CGCTL.MISCBDCGE. + * + * This will be set back on stream closure + */ + skl->enable_miscbdcge(ipc->dev, false); + skl->miscbdcg_disabled = true; + break; + default: dev_err(ipc->dev, "ipc: Unhandled error msg=%x", header.primary); -- cgit v1.2.3 From c2e20cd8187cb576362e7c8ecb0b1c51eedb2686 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 18 Dec 2015 15:12:05 +0530 Subject: ASoC: Intel: Skylake: manage link power in active suspend When device enters active suspend, we should turn off the links as they are not in use. Similarly we need to bring back links when we exit active suspend. Signed-off-by: Jayachandran B Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index dd38f5feb7c0..80a5f6456aca 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -224,6 +224,7 @@ static int skl_suspend(struct device *dev) * running, we need to save the state for these and continue */ if (skl->supend_active) { + snd_hdac_ext_bus_link_power_down_all(ebus); pci_save_state(pci); pci_disable_device(pci); return 0; @@ -246,6 +247,7 @@ static int skl_resume(struct device *dev) if (skl->supend_active) { pci_restore_state(pci); ret = pci_enable_device(pci); + snd_hdac_ext_bus_link_power_up_all(ebus); } else { ret = _skl_resume(ebus); } -- cgit v1.2.3 From 1f4956fd96c98e3fbe9a2818014cf36854398db0 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:12:06 +0530 Subject: ASoC: Intel: Skylake: enable interrupt as wake source in active suspend In active suspend, any HDA interrupt should wake the system. When device enters active suspend, we need to enable HDA controller interrupt as wake source. Similarly disable HDA controller interrupt as wake source when exiting active suspend. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 80a5f6456aca..443a15de94b5 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -218,6 +218,7 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); /* * Do not suspend if streams which are marked ignore suspend are @@ -225,6 +226,7 @@ static int skl_suspend(struct device *dev) */ if (skl->supend_active) { snd_hdac_ext_bus_link_power_down_all(ebus); + enable_irq_wake(bus->irq); pci_save_state(pci); pci_disable_device(pci); return 0; @@ -238,6 +240,7 @@ static int skl_resume(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); int ret; /* @@ -248,6 +251,7 @@ static int skl_resume(struct device *dev) pci_restore_state(pci); ret = pci_enable_device(pci); snd_hdac_ext_bus_link_power_up_all(ebus); + disable_irq_wake(bus->irq); } else { ret = _skl_resume(ebus); } -- cgit v1.2.3 From 748a1d5a3fb75e1102320214a8bde347d7b228c3 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:12:07 +0530 Subject: ASoC: Intel: Skylake: Add DMA resume position in Trigger resume/suspend Use the DMA resume capability to resume the DMA position when stream is suspended/resumed. In suspend we save the position and when stream is resumed the stream needs to be started from the position when the stream was suspended using the new DMA resume capabilities Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 8039a0479053..5a532224cb47 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -393,6 +393,15 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: skl_pcm_prepare(substream, dai); + /* + * enable DMA Resume enable bit for the stream, set the dpib + * & lpib position to resune before starting the DMA + */ + snd_hdac_ext_stream_drsm_enable(ebus, true, + hdac_stream(stream)->index); + snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); + snd_hdac_ext_stream_set_lpib(stream, stream->lpib); + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* @@ -421,8 +430,17 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, return ret; ret = skl_decoupled_trigger(substream, cmd); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) { + /* save the dpib and lpib positions */ + stream->dpib = readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(stream)->index)); + + stream->lpib = snd_hdac_stream_get_pos_lpib( + hdac_stream(stream)); snd_hdac_ext_stream_decouple(ebus, stream, false); + } break; default: -- cgit v1.2.3 From 920982c93c26a9a94d1e90221953a2ce16e91c0b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:12:08 +0530 Subject: ASoC: Intel: Skylake: Reconfigure Link stream on suspend/resume On suspend the link register are lost so we need to reconfigure them in resume. This patch adds the reconfiguration of the link register in trigger resume. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 5a532224cb47..17a64362b283 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -496,11 +496,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct hdac_ext_link *link; - if (link_dev->link_prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } - dma_params = (struct skl_dma_params *) snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -508,14 +503,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - snd_hdac_ext_link_stream_reset(link_dev); - - snd_hdac_ext_link_stream_setup(link_dev, format_val); - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); if (!link) return -EINVAL; + snd_hdac_ext_bus_link_power_up(link); + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); link_dev->link_prepared = 1; @@ -527,12 +523,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; @@ -540,6 +540,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(ebus, stream, false); break; default: -- cgit v1.2.3 From 3637976b8975afb0a55a1fc88a2c320a2839a9da Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 18 Dec 2015 15:12:09 +0530 Subject: ASoC: Intel: Skylake: Add Resume capability in PCM info. This patch adds pcm capability to support Resume. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 17a64362b283..f3553258091a 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -38,6 +38,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ SNDRV_PCM_INFO_HAS_LINK_ATIME | -- cgit v1.2.3 From 3f1c241f0f5f90046258e6b8d4aeb6463ffdc08e Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 20 Dec 2015 21:30:25 +0100 Subject: ASoC: fsl_ssi: mark SACNT register volatile SACNT register should be marked volatile since its WR and RD bits are cleared by SSI after completing the relevant operation. This unbreaks AC'97 register access. Fixes: 05cf237972fe ("ASoC: fsl_ssi: Add driver suspend and resume to support MEGA Fast") Signed-off-by: Maciej S. Szmigiero Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e3abad5f980a..cc22354d7758 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -146,6 +146,7 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) case CCSR_SSI_SRX1: case CCSR_SSI_SISR: case CCSR_SSI_SFCSR: + case CCSR_SSI_SACNT: case CCSR_SSI_SACADD: case CCSR_SSI_SACDAT: case CCSR_SSI_SATAG: @@ -239,8 +240,9 @@ struct fsl_ssi_private { unsigned int baudclk_streams; unsigned int bitclk_freq; - /*regcache for SFCSR*/ + /* regcache for volatile regs */ u32 regcache_sfcsr; + u32 regcache_sacnt; /* DMA params */ struct snd_dmaengine_dai_dma_data dma_params_tx; @@ -1587,6 +1589,8 @@ static int fsl_ssi_suspend(struct device *dev) regmap_read(regs, CCSR_SSI_SFCSR, &ssi_private->regcache_sfcsr); + regmap_read(regs, CCSR_SSI_SACNT, + &ssi_private->regcache_sacnt); regcache_cache_only(regs, true); regcache_mark_dirty(regs); @@ -1605,6 +1609,8 @@ static int fsl_ssi_resume(struct device *dev) CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK | CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK, ssi_private->regcache_sfcsr); + regmap_write(regs, CCSR_SSI_SACNT, + ssi_private->regcache_sacnt); return regcache_sync(regs); } -- cgit v1.2.3 From f51e3d5372b4bf80006cdc1694a7656aba7c9b58 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 20 Dec 2015 21:31:48 +0100 Subject: ASoC: fsl_ssi: mark some registers precious Mark some registers precious since their reads have side effects (like clearing flags). Signed-off-by: Maciej S. Szmigiero Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index cc22354d7758..40dfd8a36484 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -157,6 +157,21 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) } } +static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CCSR_SSI_SRX0: + case CCSR_SSI_SRX1: + case CCSR_SSI_SISR: + case CCSR_SSI_SACADD: + case CCSR_SSI_SACDAT: + case CCSR_SSI_SATAG: + return true; + default: + return false; + } +} + static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -179,6 +194,7 @@ static const struct regmap_config fsl_ssi_regconfig = { .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults), .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, + .precious_reg = fsl_ssi_precious_reg, .writeable_reg = fsl_ssi_writeable_reg, .cache_type = REGCACHE_RBTREE, }; -- cgit v1.2.3 From 2fa86e94a383cd6dd6e34a10950ddc93c0bb173b Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 8 Jan 2016 18:22:08 -0500 Subject: ASoC: AMD : add ACP 2.2 register headers These are register headers for the ACP (Audio CoProcessor) v2.2 Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/amd/include/acp_2_2_d.h | 609 ++++++++ sound/soc/amd/include/acp_2_2_enum.h | 1068 ++++++++++++++ sound/soc/amd/include/acp_2_2_sh_mask.h | 2292 +++++++++++++++++++++++++++++++ 3 files changed, 3969 insertions(+) create mode 100644 sound/soc/amd/include/acp_2_2_d.h create mode 100644 sound/soc/amd/include/acp_2_2_enum.h create mode 100644 sound/soc/amd/include/acp_2_2_sh_mask.h (limited to 'sound') diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h new file mode 100644 index 000000000000..0118fe9e6a87 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_d.h @@ -0,0 +1,609 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ACP_2_2_D_H +#define ACP_2_2_D_H + +#define mmACP_DMA_CNTL_0 0x5000 +#define mmACP_DMA_CNTL_1 0x5001 +#define mmACP_DMA_CNTL_2 0x5002 +#define mmACP_DMA_CNTL_3 0x5003 +#define mmACP_DMA_CNTL_4 0x5004 +#define mmACP_DMA_CNTL_5 0x5005 +#define mmACP_DMA_CNTL_6 0x5006 +#define mmACP_DMA_CNTL_7 0x5007 +#define mmACP_DMA_CNTL_8 0x5008 +#define mmACP_DMA_CNTL_9 0x5009 +#define mmACP_DMA_CNTL_10 0x500a +#define mmACP_DMA_CNTL_11 0x500b +#define mmACP_DMA_CNTL_12 0x500c +#define mmACP_DMA_CNTL_13 0x500d +#define mmACP_DMA_CNTL_14 0x500e +#define mmACP_DMA_CNTL_15 0x500f +#define mmACP_DMA_DSCR_STRT_IDX_0 0x5010 +#define mmACP_DMA_DSCR_STRT_IDX_1 0x5011 +#define mmACP_DMA_DSCR_STRT_IDX_2 0x5012 +#define mmACP_DMA_DSCR_STRT_IDX_3 0x5013 +#define mmACP_DMA_DSCR_STRT_IDX_4 0x5014 +#define mmACP_DMA_DSCR_STRT_IDX_5 0x5015 +#define mmACP_DMA_DSCR_STRT_IDX_6 0x5016 +#define mmACP_DMA_DSCR_STRT_IDX_7 0x5017 +#define mmACP_DMA_DSCR_STRT_IDX_8 0x5018 +#define mmACP_DMA_DSCR_STRT_IDX_9 0x5019 +#define mmACP_DMA_DSCR_STRT_IDX_10 0x501a +#define mmACP_DMA_DSCR_STRT_IDX_11 0x501b +#define mmACP_DMA_DSCR_STRT_IDX_12 0x501c +#define mmACP_DMA_DSCR_STRT_IDX_13 0x501d +#define mmACP_DMA_DSCR_STRT_IDX_14 0x501e +#define mmACP_DMA_DSCR_STRT_IDX_15 0x501f +#define mmACP_DMA_DSCR_CNT_0 0x5020 +#define mmACP_DMA_DSCR_CNT_1 0x5021 +#define mmACP_DMA_DSCR_CNT_2 0x5022 +#define mmACP_DMA_DSCR_CNT_3 0x5023 +#define mmACP_DMA_DSCR_CNT_4 0x5024 +#define mmACP_DMA_DSCR_CNT_5 0x5025 +#define mmACP_DMA_DSCR_CNT_6 0x5026 +#define mmACP_DMA_DSCR_CNT_7 0x5027 +#define mmACP_DMA_DSCR_CNT_8 0x5028 +#define mmACP_DMA_DSCR_CNT_9 0x5029 +#define mmACP_DMA_DSCR_CNT_10 0x502a +#define mmACP_DMA_DSCR_CNT_11 0x502b +#define mmACP_DMA_DSCR_CNT_12 0x502c +#define mmACP_DMA_DSCR_CNT_13 0x502d +#define mmACP_DMA_DSCR_CNT_14 0x502e +#define mmACP_DMA_DSCR_CNT_15 0x502f +#define mmACP_DMA_PRIO_0 0x5030 +#define mmACP_DMA_PRIO_1 0x5031 +#define mmACP_DMA_PRIO_2 0x5032 +#define mmACP_DMA_PRIO_3 0x5033 +#define mmACP_DMA_PRIO_4 0x5034 +#define mmACP_DMA_PRIO_5 0x5035 +#define mmACP_DMA_PRIO_6 0x5036 +#define mmACP_DMA_PRIO_7 0x5037 +#define mmACP_DMA_PRIO_8 0x5038 +#define mmACP_DMA_PRIO_9 0x5039 +#define mmACP_DMA_PRIO_10 0x503a +#define mmACP_DMA_PRIO_11 0x503b +#define mmACP_DMA_PRIO_12 0x503c +#define mmACP_DMA_PRIO_13 0x503d +#define mmACP_DMA_PRIO_14 0x503e +#define mmACP_DMA_PRIO_15 0x503f +#define mmACP_DMA_CUR_DSCR_0 0x5040 +#define mmACP_DMA_CUR_DSCR_1 0x5041 +#define mmACP_DMA_CUR_DSCR_2 0x5042 +#define mmACP_DMA_CUR_DSCR_3 0x5043 +#define mmACP_DMA_CUR_DSCR_4 0x5044 +#define mmACP_DMA_CUR_DSCR_5 0x5045 +#define mmACP_DMA_CUR_DSCR_6 0x5046 +#define mmACP_DMA_CUR_DSCR_7 0x5047 +#define mmACP_DMA_CUR_DSCR_8 0x5048 +#define mmACP_DMA_CUR_DSCR_9 0x5049 +#define mmACP_DMA_CUR_DSCR_10 0x504a +#define mmACP_DMA_CUR_DSCR_11 0x504b +#define mmACP_DMA_CUR_DSCR_12 0x504c +#define mmACP_DMA_CUR_DSCR_13 0x504d +#define mmACP_DMA_CUR_DSCR_14 0x504e +#define mmACP_DMA_CUR_DSCR_15 0x504f +#define mmACP_DMA_CUR_TRANS_CNT_0 0x5050 +#define mmACP_DMA_CUR_TRANS_CNT_1 0x5051 +#define mmACP_DMA_CUR_TRANS_CNT_2 0x5052 +#define mmACP_DMA_CUR_TRANS_CNT_3 0x5053 +#define mmACP_DMA_CUR_TRANS_CNT_4 0x5054 +#define mmACP_DMA_CUR_TRANS_CNT_5 0x5055 +#define mmACP_DMA_CUR_TRANS_CNT_6 0x5056 +#define mmACP_DMA_CUR_TRANS_CNT_7 0x5057 +#define mmACP_DMA_CUR_TRANS_CNT_8 0x5058 +#define mmACP_DMA_CUR_TRANS_CNT_9 0x5059 +#define mmACP_DMA_CUR_TRANS_CNT_10 0x505a +#define mmACP_DMA_CUR_TRANS_CNT_11 0x505b +#define mmACP_DMA_CUR_TRANS_CNT_12 0x505c +#define mmACP_DMA_CUR_TRANS_CNT_13 0x505d +#define mmACP_DMA_CUR_TRANS_CNT_14 0x505e +#define mmACP_DMA_CUR_TRANS_CNT_15 0x505f +#define mmACP_DMA_ERR_STS_0 0x5060 +#define mmACP_DMA_ERR_STS_1 0x5061 +#define mmACP_DMA_ERR_STS_2 0x5062 +#define mmACP_DMA_ERR_STS_3 0x5063 +#define mmACP_DMA_ERR_STS_4 0x5064 +#define mmACP_DMA_ERR_STS_5 0x5065 +#define mmACP_DMA_ERR_STS_6 0x5066 +#define mmACP_DMA_ERR_STS_7 0x5067 +#define mmACP_DMA_ERR_STS_8 0x5068 +#define mmACP_DMA_ERR_STS_9 0x5069 +#define mmACP_DMA_ERR_STS_10 0x506a +#define mmACP_DMA_ERR_STS_11 0x506b +#define mmACP_DMA_ERR_STS_12 0x506c +#define mmACP_DMA_ERR_STS_13 0x506d +#define mmACP_DMA_ERR_STS_14 0x506e +#define mmACP_DMA_ERR_STS_15 0x506f +#define mmACP_DMA_DESC_BASE_ADDR 0x5070 +#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x5071 +#define mmACP_DMA_CH_STS 0x5072 +#define mmACP_DMA_CH_GROUP 0x5073 +#define mmACP_DSP0_CACHE_OFFSET0 0x5078 +#define mmACP_DSP0_CACHE_SIZE0 0x5079 +#define mmACP_DSP0_CACHE_OFFSET1 0x507a +#define mmACP_DSP0_CACHE_SIZE1 0x507b +#define mmACP_DSP0_CACHE_OFFSET2 0x507c +#define mmACP_DSP0_CACHE_SIZE2 0x507d +#define mmACP_DSP0_CACHE_OFFSET3 0x507e +#define mmACP_DSP0_CACHE_SIZE3 0x507f +#define mmACP_DSP0_CACHE_OFFSET4 0x5080 +#define mmACP_DSP0_CACHE_SIZE4 0x5081 +#define mmACP_DSP0_CACHE_OFFSET5 0x5082 +#define mmACP_DSP0_CACHE_SIZE5 0x5083 +#define mmACP_DSP0_CACHE_OFFSET6 0x5084 +#define mmACP_DSP0_CACHE_SIZE6 0x5085 +#define mmACP_DSP0_CACHE_OFFSET7 0x5086 +#define mmACP_DSP0_CACHE_SIZE7 0x5087 +#define mmACP_DSP0_CACHE_OFFSET8 0x5088 +#define mmACP_DSP0_CACHE_SIZE8 0x5089 +#define mmACP_DSP0_NONCACHE_OFFSET0 0x508a +#define mmACP_DSP0_NONCACHE_SIZE0 0x508b +#define mmACP_DSP0_NONCACHE_OFFSET1 0x508c +#define mmACP_DSP0_NONCACHE_SIZE1 0x508d +#define mmACP_DSP0_DEBUG_PC 0x508e +#define mmACP_DSP0_NMI_SEL 0x508f +#define mmACP_DSP0_CLKRST_CNTL 0x5090 +#define mmACP_DSP0_RUNSTALL 0x5091 +#define mmACP_DSP0_OCD_HALT_ON_RST 0x5092 +#define mmACP_DSP0_WAIT_MODE 0x5093 +#define mmACP_DSP0_VECT_SEL 0x5094 +#define mmACP_DSP0_DEBUG_REG1 0x5095 +#define mmACP_DSP0_DEBUG_REG2 0x5096 +#define mmACP_DSP0_DEBUG_REG3 0x5097 +#define mmACP_DSP1_CACHE_OFFSET0 0x509d +#define mmACP_DSP1_CACHE_SIZE0 0x509e +#define mmACP_DSP1_CACHE_OFFSET1 0x509f +#define mmACP_DSP1_CACHE_SIZE1 0x50a0 +#define mmACP_DSP1_CACHE_OFFSET2 0x50a1 +#define mmACP_DSP1_CACHE_SIZE2 0x50a2 +#define mmACP_DSP1_CACHE_OFFSET3 0x50a3 +#define mmACP_DSP1_CACHE_SIZE3 0x50a4 +#define mmACP_DSP1_CACHE_OFFSET4 0x50a5 +#define mmACP_DSP1_CACHE_SIZE4 0x50a6 +#define mmACP_DSP1_CACHE_OFFSET5 0x50a7 +#define mmACP_DSP1_CACHE_SIZE5 0x50a8 +#define mmACP_DSP1_CACHE_OFFSET6 0x50a9 +#define mmACP_DSP1_CACHE_SIZE6 0x50aa +#define mmACP_DSP1_CACHE_OFFSET7 0x50ab +#define mmACP_DSP1_CACHE_SIZE7 0x50ac +#define mmACP_DSP1_CACHE_OFFSET8 0x50ad +#define mmACP_DSP1_CACHE_SIZE8 0x50ae +#define mmACP_DSP1_NONCACHE_OFFSET0 0x50af +#define mmACP_DSP1_NONCACHE_SIZE0 0x50b0 +#define mmACP_DSP1_NONCACHE_OFFSET1 0x50b1 +#define mmACP_DSP1_NONCACHE_SIZE1 0x50b2 +#define mmACP_DSP1_DEBUG_PC 0x50b3 +#define mmACP_DSP1_NMI_SEL 0x50b4 +#define mmACP_DSP1_CLKRST_CNTL 0x50b5 +#define mmACP_DSP1_RUNSTALL 0x50b6 +#define mmACP_DSP1_OCD_HALT_ON_RST 0x50b7 +#define mmACP_DSP1_WAIT_MODE 0x50b8 +#define mmACP_DSP1_VECT_SEL 0x50b9 +#define mmACP_DSP1_DEBUG_REG1 0x50ba +#define mmACP_DSP1_DEBUG_REG2 0x50bb +#define mmACP_DSP1_DEBUG_REG3 0x50bc +#define mmACP_DSP2_CACHE_OFFSET0 0x50c2 +#define mmACP_DSP2_CACHE_SIZE0 0x50c3 +#define mmACP_DSP2_CACHE_OFFSET1 0x50c4 +#define mmACP_DSP2_CACHE_SIZE1 0x50c5 +#define mmACP_DSP2_CACHE_OFFSET2 0x50c6 +#define mmACP_DSP2_CACHE_SIZE2 0x50c7 +#define mmACP_DSP2_CACHE_OFFSET3 0x50c8 +#define mmACP_DSP2_CACHE_SIZE3 0x50c9 +#define mmACP_DSP2_CACHE_OFFSET4 0x50ca +#define mmACP_DSP2_CACHE_SIZE4 0x50cb +#define mmACP_DSP2_CACHE_OFFSET5 0x50cc +#define mmACP_DSP2_CACHE_SIZE5 0x50cd +#define mmACP_DSP2_CACHE_OFFSET6 0x50ce +#define mmACP_DSP2_CACHE_SIZE6 0x50cf +#define mmACP_DSP2_CACHE_OFFSET7 0x50d0 +#define mmACP_DSP2_CACHE_SIZE7 0x50d1 +#define mmACP_DSP2_CACHE_OFFSET8 0x50d2 +#define mmACP_DSP2_CACHE_SIZE8 0x50d3 +#define mmACP_DSP2_NONCACHE_OFFSET0 0x50d4 +#define mmACP_DSP2_NONCACHE_SIZE0 0x50d5 +#define mmACP_DSP2_NONCACHE_OFFSET1 0x50d6 +#define mmACP_DSP2_NONCACHE_SIZE1 0x50d7 +#define mmACP_DSP2_DEBUG_PC 0x50d8 +#define mmACP_DSP2_NMI_SEL 0x50d9 +#define mmACP_DSP2_CLKRST_CNTL 0x50da +#define mmACP_DSP2_RUNSTALL 0x50db +#define mmACP_DSP2_OCD_HALT_ON_RST 0x50dc +#define mmACP_DSP2_WAIT_MODE 0x50dd +#define mmACP_DSP2_VECT_SEL 0x50de +#define mmACP_DSP2_DEBUG_REG1 0x50df +#define mmACP_DSP2_DEBUG_REG2 0x50e0 +#define mmACP_DSP2_DEBUG_REG3 0x50e1 +#define mmACP_AXI2DAGB_ONION_CNTL 0x50e7 +#define mmACP_AXI2DAGB_ONION_ERR_STATUS_WR 0x50e8 +#define mmACP_AXI2DAGB_ONION_ERR_STATUS_RD 0x50e9 +#define mmACP_DAGB_Onion_TransPerf_Counter_Control 0x50ea +#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Current 0x50eb +#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Peak 0x50ec +#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Current 0x50ed +#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Peak 0x50ee +#define mmACP_AXI2DAGB_GARLIC_CNTL 0x50f3 +#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_WR 0x50f4 +#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_RD 0x50f5 +#define mmACP_DAGB_Garlic_TransPerf_Counter_Control 0x50f6 +#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Current 0x50f7 +#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak 0x50f8 +#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Current 0x50f9 +#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak 0x50fa +#define mmACP_DAGB_PAGE_SIZE_GRP_1 0x50ff +#define mmACP_DAGB_BASE_ADDR_GRP_1 0x5100 +#define mmACP_DAGB_PAGE_SIZE_GRP_2 0x5101 +#define mmACP_DAGB_BASE_ADDR_GRP_2 0x5102 +#define mmACP_DAGB_PAGE_SIZE_GRP_3 0x5103 +#define mmACP_DAGB_BASE_ADDR_GRP_3 0x5104 +#define mmACP_DAGB_PAGE_SIZE_GRP_4 0x5105 +#define mmACP_DAGB_BASE_ADDR_GRP_4 0x5106 +#define mmACP_DAGB_PAGE_SIZE_GRP_5 0x5107 +#define mmACP_DAGB_BASE_ADDR_GRP_5 0x5108 +#define mmACP_DAGB_PAGE_SIZE_GRP_6 0x5109 +#define mmACP_DAGB_BASE_ADDR_GRP_6 0x510a +#define mmACP_DAGB_PAGE_SIZE_GRP_7 0x510b +#define mmACP_DAGB_BASE_ADDR_GRP_7 0x510c +#define mmACP_DAGB_PAGE_SIZE_GRP_8 0x510d +#define mmACP_DAGB_BASE_ADDR_GRP_8 0x510e +#define mmACP_DAGB_ATU_CTRL 0x510f +#define mmACP_CONTROL 0x5131 +#define mmACP_STATUS 0x5133 +#define mmACP_SOFT_RESET 0x5134 +#define mmACP_PwrMgmt_CNTL 0x5135 +#define mmACP_CAC_INDICATOR_CONTROL 0x5136 +#define mmACP_SMU_MAILBOX 0x5137 +#define mmACP_FUTURE_REG_SCLK_0 0x5138 +#define mmACP_FUTURE_REG_SCLK_1 0x5139 +#define mmACP_FUTURE_REG_SCLK_2 0x513a +#define mmACP_FUTURE_REG_SCLK_3 0x513b +#define mmACP_FUTURE_REG_SCLK_4 0x513c +#define mmACP_DAGB_DEBUG_CNT_ENABLE 0x513d +#define mmACP_DAGBG_WR_ASK_CNT 0x513e +#define mmACP_DAGBG_WR_GO_CNT 0x513f +#define mmACP_DAGBG_WR_EXP_RESP_CNT 0x5140 +#define mmACP_DAGBG_WR_ACTUAL_RESP_CNT 0x5141 +#define mmACP_DAGBG_RD_ASK_CNT 0x5142 +#define mmACP_DAGBG_RD_GO_CNT 0x5143 +#define mmACP_DAGBG_RD_EXP_RESP_CNT 0x5144 +#define mmACP_DAGBG_RD_ACTUAL_RESP_CNT 0x5145 +#define mmACP_DAGBO_WR_ASK_CNT 0x5146 +#define mmACP_DAGBO_WR_GO_CNT 0x5147 +#define mmACP_DAGBO_WR_EXP_RESP_CNT 0x5148 +#define mmACP_DAGBO_WR_ACTUAL_RESP_CNT 0x5149 +#define mmACP_DAGBO_RD_ASK_CNT 0x514a +#define mmACP_DAGBO_RD_GO_CNT 0x514b +#define mmACP_DAGBO_RD_EXP_RESP_CNT 0x514c +#define mmACP_DAGBO_RD_ACTUAL_RESP_CNT 0x514d +#define mmACP_BRB_CONTROL 0x5156 +#define mmACP_EXTERNAL_INTR_ENB 0x5157 +#define mmACP_EXTERNAL_INTR_CNTL 0x5158 +#define mmACP_ERROR_SOURCE_STS 0x5159 +#define mmACP_DSP_SW_INTR_TRIG 0x515a +#define mmACP_DSP_SW_INTR_CNTL 0x515b +#define mmACP_DAGBG_TIMEOUT_CNTL 0x515c +#define mmACP_DAGBO_TIMEOUT_CNTL 0x515d +#define mmACP_EXTERNAL_INTR_STAT 0x515e +#define mmACP_DSP_SW_INTR_STAT 0x515f +#define mmACP_DSP0_INTR_CNTL 0x5160 +#define mmACP_DSP0_INTR_STAT 0x5161 +#define mmACP_DSP0_TIMEOUT_CNTL 0x5162 +#define mmACP_DSP1_INTR_CNTL 0x5163 +#define mmACP_DSP1_INTR_STAT 0x5164 +#define mmACP_DSP1_TIMEOUT_CNTL 0x5165 +#define mmACP_DSP2_INTR_CNTL 0x5166 +#define mmACP_DSP2_INTR_STAT 0x5167 +#define mmACP_DSP2_TIMEOUT_CNTL 0x5168 +#define mmACP_DSP0_EXT_TIMER_CNTL 0x5169 +#define mmACP_DSP1_EXT_TIMER_CNTL 0x516a +#define mmACP_DSP2_EXT_TIMER_CNTL 0x516b +#define mmACP_AXI2DAGB_SEM_0 0x516c +#define mmACP_AXI2DAGB_SEM_1 0x516d +#define mmACP_AXI2DAGB_SEM_2 0x516e +#define mmACP_AXI2DAGB_SEM_3 0x516f +#define mmACP_AXI2DAGB_SEM_4 0x5170 +#define mmACP_AXI2DAGB_SEM_5 0x5171 +#define mmACP_AXI2DAGB_SEM_6 0x5172 +#define mmACP_AXI2DAGB_SEM_7 0x5173 +#define mmACP_AXI2DAGB_SEM_8 0x5174 +#define mmACP_AXI2DAGB_SEM_9 0x5175 +#define mmACP_AXI2DAGB_SEM_10 0x5176 +#define mmACP_AXI2DAGB_SEM_11 0x5177 +#define mmACP_AXI2DAGB_SEM_12 0x5178 +#define mmACP_AXI2DAGB_SEM_13 0x5179 +#define mmACP_AXI2DAGB_SEM_14 0x517a +#define mmACP_AXI2DAGB_SEM_15 0x517b +#define mmACP_AXI2DAGB_SEM_16 0x517c +#define mmACP_AXI2DAGB_SEM_17 0x517d +#define mmACP_AXI2DAGB_SEM_18 0x517e +#define mmACP_AXI2DAGB_SEM_19 0x517f +#define mmACP_AXI2DAGB_SEM_20 0x5180 +#define mmACP_AXI2DAGB_SEM_21 0x5181 +#define mmACP_AXI2DAGB_SEM_22 0x5182 +#define mmACP_AXI2DAGB_SEM_23 0x5183 +#define mmACP_AXI2DAGB_SEM_24 0x5184 +#define mmACP_AXI2DAGB_SEM_25 0x5185 +#define mmACP_AXI2DAGB_SEM_26 0x5186 +#define mmACP_AXI2DAGB_SEM_27 0x5187 +#define mmACP_AXI2DAGB_SEM_28 0x5188 +#define mmACP_AXI2DAGB_SEM_29 0x5189 +#define mmACP_AXI2DAGB_SEM_30 0x518a +#define mmACP_AXI2DAGB_SEM_31 0x518b +#define mmACP_AXI2DAGB_SEM_32 0x518c +#define mmACP_AXI2DAGB_SEM_33 0x518d +#define mmACP_AXI2DAGB_SEM_34 0x518e +#define mmACP_AXI2DAGB_SEM_35 0x518f +#define mmACP_AXI2DAGB_SEM_36 0x5190 +#define mmACP_AXI2DAGB_SEM_37 0x5191 +#define mmACP_AXI2DAGB_SEM_38 0x5192 +#define mmACP_AXI2DAGB_SEM_39 0x5193 +#define mmACP_AXI2DAGB_SEM_40 0x5194 +#define mmACP_AXI2DAGB_SEM_41 0x5195 +#define mmACP_AXI2DAGB_SEM_42 0x5196 +#define mmACP_AXI2DAGB_SEM_43 0x5197 +#define mmACP_AXI2DAGB_SEM_44 0x5198 +#define mmACP_AXI2DAGB_SEM_45 0x5199 +#define mmACP_AXI2DAGB_SEM_46 0x519a +#define mmACP_AXI2DAGB_SEM_47 0x519b +#define mmACP_SRBM_Client_Base_Addr 0x519c +#define mmACP_SRBM_Client_RDDATA 0x519d +#define mmACP_SRBM_Cycle_Sts 0x519e +#define mmACP_SRBM_Targ_Idx_Addr 0x519f +#define mmACP_SRBM_Targ_Idx_Data 0x51a0 +#define mmACP_SEMA_ADDR_LOW 0x51a1 +#define mmACP_SEMA_ADDR_HIGH 0x51a2 +#define mmACP_SEMA_CMD 0x51a3 +#define mmACP_SEMA_STS 0x51a4 +#define mmACP_SEMA_REQ 0x51a5 +#define mmACP_FW_STATUS 0x51a6 +#define mmACP_FUTURE_REG_ACLK_0 0x51a7 +#define mmACP_FUTURE_REG_ACLK_1 0x51a8 +#define mmACP_FUTURE_REG_ACLK_2 0x51a9 +#define mmACP_FUTURE_REG_ACLK_3 0x51aa +#define mmACP_FUTURE_REG_ACLK_4 0x51ab +#define mmACP_TIMER 0x51ac +#define mmACP_TIMER_CNTL 0x51ad +#define mmACP_DSP0_TIMER 0x51ae +#define mmACP_DSP1_TIMER 0x51af +#define mmACP_DSP2_TIMER 0x51b0 +#define mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH 0x51b1 +#define mmACP_I2S_TRANSMIT_BYTE_CNT_LOW 0x51b2 +#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH 0x51b3 +#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW 0x51b4 +#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH 0x51b5 +#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW 0x51b6 +#define mmACP_DSP0_CS_STATE 0x51b7 +#define mmACP_DSP1_CS_STATE 0x51b8 +#define mmACP_DSP2_CS_STATE 0x51b9 +#define mmACP_SCRATCH_REG_BASE_ADDR 0x51ba +#define mmCC_ACP_EFUSE 0x51c8 +#define mmACP_PGFSM_RETAIN_REG 0x51c9 +#define mmACP_PGFSM_CONFIG_REG 0x51ca +#define mmACP_PGFSM_WRITE_REG 0x51cb +#define mmACP_PGFSM_READ_REG_0 0x51cc +#define mmACP_PGFSM_READ_REG_1 0x51cd +#define mmACP_PGFSM_READ_REG_2 0x51ce +#define mmACP_PGFSM_READ_REG_3 0x51cf +#define mmACP_PGFSM_READ_REG_4 0x51d0 +#define mmACP_PGFSM_READ_REG_5 0x51d1 +#define mmACP_IP_PGFSM_ENABLE 0x51d2 +#define mmACP_I2S_PIN_CONFIG 0x51d3 +#define mmACP_AZALIA_I2S_SELECT 0x51d4 +#define mmACP_CHIP_PKG_FOR_PAD_ISOLATION 0x51d5 +#define mmACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL 0x51d6 +#define mmACP_BT_UART_PAD_SEL 0x51d7 +#define mmACP_SCRATCH_REG_0 0x52c0 +#define mmACP_SCRATCH_REG_1 0x52c1 +#define mmACP_SCRATCH_REG_2 0x52c2 +#define mmACP_SCRATCH_REG_3 0x52c3 +#define mmACP_SCRATCH_REG_4 0x52c4 +#define mmACP_SCRATCH_REG_5 0x52c5 +#define mmACP_SCRATCH_REG_6 0x52c6 +#define mmACP_SCRATCH_REG_7 0x52c7 +#define mmACP_SCRATCH_REG_8 0x52c8 +#define mmACP_SCRATCH_REG_9 0x52c9 +#define mmACP_SCRATCH_REG_10 0x52ca +#define mmACP_SCRATCH_REG_11 0x52cb +#define mmACP_SCRATCH_REG_12 0x52cc +#define mmACP_SCRATCH_REG_13 0x52cd +#define mmACP_SCRATCH_REG_14 0x52ce +#define mmACP_SCRATCH_REG_15 0x52cf +#define mmACP_SCRATCH_REG_16 0x52d0 +#define mmACP_SCRATCH_REG_17 0x52d1 +#define mmACP_SCRATCH_REG_18 0x52d2 +#define mmACP_SCRATCH_REG_19 0x52d3 +#define mmACP_SCRATCH_REG_20 0x52d4 +#define mmACP_SCRATCH_REG_21 0x52d5 +#define mmACP_SCRATCH_REG_22 0x52d6 +#define mmACP_SCRATCH_REG_23 0x52d7 +#define mmACP_SCRATCH_REG_24 0x52d8 +#define mmACP_SCRATCH_REG_25 0x52d9 +#define mmACP_SCRATCH_REG_26 0x52da +#define mmACP_SCRATCH_REG_27 0x52db +#define mmACP_SCRATCH_REG_28 0x52dc +#define mmACP_SCRATCH_REG_29 0x52dd +#define mmACP_SCRATCH_REG_30 0x52de +#define mmACP_SCRATCH_REG_31 0x52df +#define mmACP_SCRATCH_REG_32 0x52e0 +#define mmACP_SCRATCH_REG_33 0x52e1 +#define mmACP_SCRATCH_REG_34 0x52e2 +#define mmACP_SCRATCH_REG_35 0x52e3 +#define mmACP_SCRATCH_REG_36 0x52e4 +#define mmACP_SCRATCH_REG_37 0x52e5 +#define mmACP_SCRATCH_REG_38 0x52e6 +#define mmACP_SCRATCH_REG_39 0x52e7 +#define mmACP_SCRATCH_REG_40 0x52e8 +#define mmACP_SCRATCH_REG_41 0x52e9 +#define mmACP_SCRATCH_REG_42 0x52ea +#define mmACP_SCRATCH_REG_43 0x52eb +#define mmACP_SCRATCH_REG_44 0x52ec +#define mmACP_SCRATCH_REG_45 0x52ed +#define mmACP_SCRATCH_REG_46 0x52ee +#define mmACP_SCRATCH_REG_47 0x52ef +#define mmACP_VOICE_WAKEUP_ENABLE 0x51e8 +#define mmACP_VOICE_WAKEUP_STATUS 0x51e9 +#define mmI2S_VOICE_WAKEUP_LOWER_THRESHOLD 0x51ea +#define mmI2S_VOICE_WAKEUP_HIGHER_THRESHOLD 0x51eb +#define mmI2S_VOICE_WAKEUP_NO_OF_SAMPLES 0x51ec +#define mmI2S_VOICE_WAKEUP_NO_OF_PEAKS 0x51ed +#define mmI2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS 0x51ee +#define mmI2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION 0x51ef +#define mmI2S_VOICE_WAKEUP_DATA_PATH_SWITCH 0x51f0 +#define mmI2S_VOICE_WAKEUP_DATA_POINTER 0x51f1 +#define mmI2S_VOICE_WAKEUP_AUTH_MATCH 0x51f2 +#define mmI2S_VOICE_WAKEUP_8KB_WRAP 0x51f3 +#define mmACP_I2S_RECEIVED_BYTE_CNT_HIGH 0x51f4 +#define mmACP_I2S_RECEIVED_BYTE_CNT_LOW 0x51f5 +#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH 0x51f6 +#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW 0x51f7 +#define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8 +#define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9 +#define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa +#define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb +#define mmACP_MEM_DEEP_SLEEP_REQ_LO 0x51fc +#define mmACP_MEM_DEEP_SLEEP_REQ_HI 0x51fd +#define mmACP_MEM_DEEP_SLEEP_STS_LO 0x51fe +#define mmACP_MEM_DEEP_SLEEP_STS_HI 0x51ff +#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO 0x5200 +#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI 0x5201 +#define mmACP_MEM_WAKEUP_FROM_SLEEP_LO 0x5202 +#define mmACP_MEM_WAKEUP_FROM_SLEEP_HI 0x5203 +#define mmACP_I2SSP_IER 0x5210 +#define mmACP_I2SSP_IRER 0x5211 +#define mmACP_I2SSP_ITER 0x5212 +#define mmACP_I2SSP_CER 0x5213 +#define mmACP_I2SSP_CCR 0x5214 +#define mmACP_I2SSP_RXFFR 0x5215 +#define mmACP_I2SSP_TXFFR 0x5216 +#define mmACP_I2SSP_LRBR0 0x5218 +#define mmACP_I2SSP_RRBR0 0x5219 +#define mmACP_I2SSP_RER0 0x521a +#define mmACP_I2SSP_TER0 0x521b +#define mmACP_I2SSP_RCR0 0x521c +#define mmACP_I2SSP_TCR0 0x521d +#define mmACP_I2SSP_ISR0 0x521e +#define mmACP_I2SSP_IMR0 0x521f +#define mmACP_I2SSP_ROR0 0x5220 +#define mmACP_I2SSP_TOR0 0x5221 +#define mmACP_I2SSP_RFCR0 0x5222 +#define mmACP_I2SSP_TFCR0 0x5223 +#define mmACP_I2SSP_RFF0 0x5224 +#define mmACP_I2SSP_TFF0 0x5225 +#define mmACP_I2SSP_RXDMA 0x5226 +#define mmACP_I2SSP_RRXDMA 0x5227 +#define mmACP_I2SSP_TXDMA 0x5228 +#define mmACP_I2SSP_RTXDMA 0x5229 +#define mmACP_I2SSP_COMP_PARAM_2 0x522a +#define mmACP_I2SSP_COMP_PARAM_1 0x522b +#define mmACP_I2SSP_COMP_VERSION 0x522c +#define mmACP_I2SSP_COMP_TYPE 0x522d +#define mmACP_I2SMICSP_IER 0x522e +#define mmACP_I2SMICSP_IRER 0x522f +#define mmACP_I2SMICSP_ITER 0x5230 +#define mmACP_I2SMICSP_CER 0x5231 +#define mmACP_I2SMICSP_CCR 0x5232 +#define mmACP_I2SMICSP_RXFFR 0x5233 +#define mmACP_I2SMICSP_TXFFR 0x5234 +#define mmACP_I2SMICSP_LRBR0 0x5236 +#define mmACP_I2SMICSP_RRBR0 0x5237 +#define mmACP_I2SMICSP_RER0 0x5238 +#define mmACP_I2SMICSP_TER0 0x5239 +#define mmACP_I2SMICSP_RCR0 0x523a +#define mmACP_I2SMICSP_TCR0 0x523b +#define mmACP_I2SMICSP_ISR0 0x523c +#define mmACP_I2SMICSP_IMR0 0x523d +#define mmACP_I2SMICSP_ROR0 0x523e +#define mmACP_I2SMICSP_TOR0 0x523f +#define mmACP_I2SMICSP_RFCR0 0x5240 +#define mmACP_I2SMICSP_TFCR0 0x5241 +#define mmACP_I2SMICSP_RFF0 0x5242 +#define mmACP_I2SMICSP_TFF0 0x5243 +#define mmACP_I2SMICSP_LRBR1 0x5246 +#define mmACP_I2SMICSP_RRBR1 0x5247 +#define mmACP_I2SMICSP_RER1 0x5248 +#define mmACP_I2SMICSP_TER1 0x5249 +#define mmACP_I2SMICSP_RCR1 0x524a +#define mmACP_I2SMICSP_TCR1 0x524b +#define mmACP_I2SMICSP_ISR1 0x524c +#define mmACP_I2SMICSP_IMR1 0x524d +#define mmACP_I2SMICSP_ROR1 0x524e +#define mmACP_I2SMICSP_TOR1 0x524f +#define mmACP_I2SMICSP_RFCR1 0x5250 +#define mmACP_I2SMICSP_TFCR1 0x5251 +#define mmACP_I2SMICSP_RFF1 0x5252 +#define mmACP_I2SMICSP_TFF1 0x5253 +#define mmACP_I2SMICSP_RXDMA 0x5254 +#define mmACP_I2SMICSP_RRXDMA 0x5255 +#define mmACP_I2SMICSP_TXDMA 0x5256 +#define mmACP_I2SMICSP_RTXDMA 0x5257 +#define mmACP_I2SMICSP_COMP_PARAM_2 0x5258 +#define mmACP_I2SMICSP_COMP_PARAM_1 0x5259 +#define mmACP_I2SMICSP_COMP_VERSION 0x525a +#define mmACP_I2SMICSP_COMP_TYPE 0x525b +#define mmACP_I2SBT_IER 0x525c +#define mmACP_I2SBT_IRER 0x525d +#define mmACP_I2SBT_ITER 0x525e +#define mmACP_I2SBT_CER 0x525f +#define mmACP_I2SBT_CCR 0x5260 +#define mmACP_I2SBT_RXFFR 0x5261 +#define mmACP_I2SBT_TXFFR 0x5262 +#define mmACP_I2SBT_LRBR0 0x5264 +#define mmACP_I2SBT_RRBR0 0x5265 +#define mmACP_I2SBT_RER0 0x5266 +#define mmACP_I2SBT_TER0 0x5267 +#define mmACP_I2SBT_RCR0 0x5268 +#define mmACP_I2SBT_TCR0 0x5269 +#define mmACP_I2SBT_ISR0 0x526a +#define mmACP_I2SBT_IMR0 0x526b +#define mmACP_I2SBT_ROR0 0x526c +#define mmACP_I2SBT_TOR0 0x526d +#define mmACP_I2SBT_RFCR0 0x526e +#define mmACP_I2SBT_TFCR0 0x526f +#define mmACP_I2SBT_RFF0 0x5270 +#define mmACP_I2SBT_TFF0 0x5271 +#define mmACP_I2SBT_LRBR1 0x5274 +#define mmACP_I2SBT_RRBR1 0x5275 +#define mmACP_I2SBT_RER1 0x5276 +#define mmACP_I2SBT_TER1 0x5277 +#define mmACP_I2SBT_RCR1 0x5278 +#define mmACP_I2SBT_TCR1 0x5279 +#define mmACP_I2SBT_ISR1 0x527a +#define mmACP_I2SBT_IMR1 0x527b +#define mmACP_I2SBT_ROR1 0x527c +#define mmACP_I2SBT_TOR1 0x527d +#define mmACP_I2SBT_RFCR1 0x527e +#define mmACP_I2SBT_TFCR1 0x527f +#define mmACP_I2SBT_RFF1 0x5280 +#define mmACP_I2SBT_TFF1 0x5281 +#define mmACP_I2SBT_RXDMA 0x5282 +#define mmACP_I2SBT_RRXDMA 0x5283 +#define mmACP_I2SBT_TXDMA 0x5284 +#define mmACP_I2SBT_RTXDMA 0x5285 +#define mmACP_I2SBT_COMP_PARAM_2 0x5286 +#define mmACP_I2SBT_COMP_PARAM_1 0x5287 +#define mmACP_I2SBT_COMP_VERSION 0x5288 +#define mmACP_I2SBT_COMP_TYPE 0x5289 + +#endif /* ACP_2_2_D_H */ diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h new file mode 100644 index 000000000000..f3577c851086 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_enum.h @@ -0,0 +1,1068 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ACP_2_2_ENUM_H +#define ACP_2_2_ENUM_H + +typedef enum DebugBlockId { + DBG_BLOCK_ID_RESERVED = 0x0, + DBG_BLOCK_ID_DBG = 0x1, + DBG_BLOCK_ID_VMC = 0x2, + DBG_BLOCK_ID_PDMA = 0x3, + DBG_BLOCK_ID_CG = 0x4, + DBG_BLOCK_ID_SRBM = 0x5, + DBG_BLOCK_ID_GRBM = 0x6, + DBG_BLOCK_ID_RLC = 0x7, + DBG_BLOCK_ID_CSC = 0x8, + DBG_BLOCK_ID_SEM = 0x9, + DBG_BLOCK_ID_IH = 0xa, + DBG_BLOCK_ID_SC = 0xb, + DBG_BLOCK_ID_SQ = 0xc, + DBG_BLOCK_ID_UVDU = 0xd, + DBG_BLOCK_ID_SQA = 0xe, + DBG_BLOCK_ID_SDMA0 = 0xf, + DBG_BLOCK_ID_SDMA1 = 0x10, + DBG_BLOCK_ID_SPIM = 0x11, + DBG_BLOCK_ID_GDS = 0x12, + DBG_BLOCK_ID_VC0 = 0x13, + DBG_BLOCK_ID_VC1 = 0x14, + DBG_BLOCK_ID_PA0 = 0x15, + DBG_BLOCK_ID_PA1 = 0x16, + DBG_BLOCK_ID_CP0 = 0x17, + DBG_BLOCK_ID_CP1 = 0x18, + DBG_BLOCK_ID_CP2 = 0x19, + DBG_BLOCK_ID_XBR = 0x1a, + DBG_BLOCK_ID_UVDM = 0x1b, + DBG_BLOCK_ID_VGT0 = 0x1c, + DBG_BLOCK_ID_VGT1 = 0x1d, + DBG_BLOCK_ID_IA = 0x1e, + DBG_BLOCK_ID_SXM0 = 0x1f, + DBG_BLOCK_ID_SXM1 = 0x20, + DBG_BLOCK_ID_SCT0 = 0x21, + DBG_BLOCK_ID_SCT1 = 0x22, + DBG_BLOCK_ID_SPM0 = 0x23, + DBG_BLOCK_ID_SPM1 = 0x24, + DBG_BLOCK_ID_UNUSED0 = 0x25, + DBG_BLOCK_ID_UNUSED1 = 0x26, + DBG_BLOCK_ID_TCAA = 0x27, + DBG_BLOCK_ID_TCAB = 0x28, + DBG_BLOCK_ID_TCCA = 0x29, + DBG_BLOCK_ID_TCCB = 0x2a, + DBG_BLOCK_ID_MCC0 = 0x2b, + DBG_BLOCK_ID_MCC1 = 0x2c, + DBG_BLOCK_ID_MCC2 = 0x2d, + DBG_BLOCK_ID_MCC3 = 0x2e, + DBG_BLOCK_ID_SXS0 = 0x2f, + DBG_BLOCK_ID_SXS1 = 0x30, + DBG_BLOCK_ID_SXS2 = 0x31, + DBG_BLOCK_ID_SXS3 = 0x32, + DBG_BLOCK_ID_SXS4 = 0x33, + DBG_BLOCK_ID_SXS5 = 0x34, + DBG_BLOCK_ID_SXS6 = 0x35, + DBG_BLOCK_ID_SXS7 = 0x36, + DBG_BLOCK_ID_SXS8 = 0x37, + DBG_BLOCK_ID_SXS9 = 0x38, + DBG_BLOCK_ID_BCI0 = 0x39, + DBG_BLOCK_ID_BCI1 = 0x3a, + DBG_BLOCK_ID_BCI2 = 0x3b, + DBG_BLOCK_ID_BCI3 = 0x3c, + DBG_BLOCK_ID_MCB = 0x3d, + DBG_BLOCK_ID_UNUSED6 = 0x3e, + DBG_BLOCK_ID_SQA00 = 0x3f, + DBG_BLOCK_ID_SQA01 = 0x40, + DBG_BLOCK_ID_SQA02 = 0x41, + DBG_BLOCK_ID_SQA10 = 0x42, + DBG_BLOCK_ID_SQA11 = 0x43, + DBG_BLOCK_ID_SQA12 = 0x44, + DBG_BLOCK_ID_UNUSED7 = 0x45, + DBG_BLOCK_ID_UNUSED8 = 0x46, + DBG_BLOCK_ID_SQB00 = 0x47, + DBG_BLOCK_ID_SQB01 = 0x48, + DBG_BLOCK_ID_SQB10 = 0x49, + DBG_BLOCK_ID_SQB11 = 0x4a, + DBG_BLOCK_ID_SQ00 = 0x4b, + DBG_BLOCK_ID_SQ01 = 0x4c, + DBG_BLOCK_ID_SQ10 = 0x4d, + DBG_BLOCK_ID_SQ11 = 0x4e, + DBG_BLOCK_ID_CB00 = 0x4f, + DBG_BLOCK_ID_CB01 = 0x50, + DBG_BLOCK_ID_CB02 = 0x51, + DBG_BLOCK_ID_CB03 = 0x52, + DBG_BLOCK_ID_CB04 = 0x53, + DBG_BLOCK_ID_UNUSED9 = 0x54, + DBG_BLOCK_ID_UNUSED10 = 0x55, + DBG_BLOCK_ID_UNUSED11 = 0x56, + DBG_BLOCK_ID_CB10 = 0x57, + DBG_BLOCK_ID_CB11 = 0x58, + DBG_BLOCK_ID_CB12 = 0x59, + DBG_BLOCK_ID_CB13 = 0x5a, + DBG_BLOCK_ID_CB14 = 0x5b, + DBG_BLOCK_ID_UNUSED12 = 0x5c, + DBG_BLOCK_ID_UNUSED13 = 0x5d, + DBG_BLOCK_ID_UNUSED14 = 0x5e, + DBG_BLOCK_ID_TCP0 = 0x5f, + DBG_BLOCK_ID_TCP1 = 0x60, + DBG_BLOCK_ID_TCP2 = 0x61, + DBG_BLOCK_ID_TCP3 = 0x62, + DBG_BLOCK_ID_TCP4 = 0x63, + DBG_BLOCK_ID_TCP5 = 0x64, + DBG_BLOCK_ID_TCP6 = 0x65, + DBG_BLOCK_ID_TCP7 = 0x66, + DBG_BLOCK_ID_TCP8 = 0x67, + DBG_BLOCK_ID_TCP9 = 0x68, + DBG_BLOCK_ID_TCP10 = 0x69, + DBG_BLOCK_ID_TCP11 = 0x6a, + DBG_BLOCK_ID_TCP12 = 0x6b, + DBG_BLOCK_ID_TCP13 = 0x6c, + DBG_BLOCK_ID_TCP14 = 0x6d, + DBG_BLOCK_ID_TCP15 = 0x6e, + DBG_BLOCK_ID_TCP16 = 0x6f, + DBG_BLOCK_ID_TCP17 = 0x70, + DBG_BLOCK_ID_TCP18 = 0x71, + DBG_BLOCK_ID_TCP19 = 0x72, + DBG_BLOCK_ID_TCP20 = 0x73, + DBG_BLOCK_ID_TCP21 = 0x74, + DBG_BLOCK_ID_TCP22 = 0x75, + DBG_BLOCK_ID_TCP23 = 0x76, + DBG_BLOCK_ID_TCP_RESERVED0 = 0x77, + DBG_BLOCK_ID_TCP_RESERVED1 = 0x78, + DBG_BLOCK_ID_TCP_RESERVED2 = 0x79, + DBG_BLOCK_ID_TCP_RESERVED3 = 0x7a, + DBG_BLOCK_ID_TCP_RESERVED4 = 0x7b, + DBG_BLOCK_ID_TCP_RESERVED5 = 0x7c, + DBG_BLOCK_ID_TCP_RESERVED6 = 0x7d, + DBG_BLOCK_ID_TCP_RESERVED7 = 0x7e, + DBG_BLOCK_ID_DB00 = 0x7f, + DBG_BLOCK_ID_DB01 = 0x80, + DBG_BLOCK_ID_DB02 = 0x81, + DBG_BLOCK_ID_DB03 = 0x82, + DBG_BLOCK_ID_DB04 = 0x83, + DBG_BLOCK_ID_UNUSED15 = 0x84, + DBG_BLOCK_ID_UNUSED16 = 0x85, + DBG_BLOCK_ID_UNUSED17 = 0x86, + DBG_BLOCK_ID_DB10 = 0x87, + DBG_BLOCK_ID_DB11 = 0x88, + DBG_BLOCK_ID_DB12 = 0x89, + DBG_BLOCK_ID_DB13 = 0x8a, + DBG_BLOCK_ID_DB14 = 0x8b, + DBG_BLOCK_ID_UNUSED18 = 0x8c, + DBG_BLOCK_ID_UNUSED19 = 0x8d, + DBG_BLOCK_ID_UNUSED20 = 0x8e, + DBG_BLOCK_ID_TCC0 = 0x8f, + DBG_BLOCK_ID_TCC1 = 0x90, + DBG_BLOCK_ID_TCC2 = 0x91, + DBG_BLOCK_ID_TCC3 = 0x92, + DBG_BLOCK_ID_TCC4 = 0x93, + DBG_BLOCK_ID_TCC5 = 0x94, + DBG_BLOCK_ID_TCC6 = 0x95, + DBG_BLOCK_ID_TCC7 = 0x96, + DBG_BLOCK_ID_SPS00 = 0x97, + DBG_BLOCK_ID_SPS01 = 0x98, + DBG_BLOCK_ID_SPS02 = 0x99, + DBG_BLOCK_ID_SPS10 = 0x9a, + DBG_BLOCK_ID_SPS11 = 0x9b, + DBG_BLOCK_ID_SPS12 = 0x9c, + DBG_BLOCK_ID_UNUSED21 = 0x9d, + DBG_BLOCK_ID_UNUSED22 = 0x9e, + DBG_BLOCK_ID_TA00 = 0x9f, + DBG_BLOCK_ID_TA01 = 0xa0, + DBG_BLOCK_ID_TA02 = 0xa1, + DBG_BLOCK_ID_TA03 = 0xa2, + DBG_BLOCK_ID_TA04 = 0xa3, + DBG_BLOCK_ID_TA05 = 0xa4, + DBG_BLOCK_ID_TA06 = 0xa5, + DBG_BLOCK_ID_TA07 = 0xa6, + DBG_BLOCK_ID_TA08 = 0xa7, + DBG_BLOCK_ID_TA09 = 0xa8, + DBG_BLOCK_ID_TA0A = 0xa9, + DBG_BLOCK_ID_TA0B = 0xaa, + DBG_BLOCK_ID_UNUSED23 = 0xab, + DBG_BLOCK_ID_UNUSED24 = 0xac, + DBG_BLOCK_ID_UNUSED25 = 0xad, + DBG_BLOCK_ID_UNUSED26 = 0xae, + DBG_BLOCK_ID_TA10 = 0xaf, + DBG_BLOCK_ID_TA11 = 0xb0, + DBG_BLOCK_ID_TA12 = 0xb1, + DBG_BLOCK_ID_TA13 = 0xb2, + DBG_BLOCK_ID_TA14 = 0xb3, + DBG_BLOCK_ID_TA15 = 0xb4, + DBG_BLOCK_ID_TA16 = 0xb5, + DBG_BLOCK_ID_TA17 = 0xb6, + DBG_BLOCK_ID_TA18 = 0xb7, + DBG_BLOCK_ID_TA19 = 0xb8, + DBG_BLOCK_ID_TA1A = 0xb9, + DBG_BLOCK_ID_TA1B = 0xba, + DBG_BLOCK_ID_UNUSED27 = 0xbb, + DBG_BLOCK_ID_UNUSED28 = 0xbc, + DBG_BLOCK_ID_UNUSED29 = 0xbd, + DBG_BLOCK_ID_UNUSED30 = 0xbe, + DBG_BLOCK_ID_TD00 = 0xbf, + DBG_BLOCK_ID_TD01 = 0xc0, + DBG_BLOCK_ID_TD02 = 0xc1, + DBG_BLOCK_ID_TD03 = 0xc2, + DBG_BLOCK_ID_TD04 = 0xc3, + DBG_BLOCK_ID_TD05 = 0xc4, + DBG_BLOCK_ID_TD06 = 0xc5, + DBG_BLOCK_ID_TD07 = 0xc6, + DBG_BLOCK_ID_TD08 = 0xc7, + DBG_BLOCK_ID_TD09 = 0xc8, + DBG_BLOCK_ID_TD0A = 0xc9, + DBG_BLOCK_ID_TD0B = 0xca, + DBG_BLOCK_ID_UNUSED31 = 0xcb, + DBG_BLOCK_ID_UNUSED32 = 0xcc, + DBG_BLOCK_ID_UNUSED33 = 0xcd, + DBG_BLOCK_ID_UNUSED34 = 0xce, + DBG_BLOCK_ID_TD10 = 0xcf, + DBG_BLOCK_ID_TD11 = 0xd0, + DBG_BLOCK_ID_TD12 = 0xd1, + DBG_BLOCK_ID_TD13 = 0xd2, + DBG_BLOCK_ID_TD14 = 0xd3, + DBG_BLOCK_ID_TD15 = 0xd4, + DBG_BLOCK_ID_TD16 = 0xd5, + DBG_BLOCK_ID_TD17 = 0xd6, + DBG_BLOCK_ID_TD18 = 0xd7, + DBG_BLOCK_ID_TD19 = 0xd8, + DBG_BLOCK_ID_TD1A = 0xd9, + DBG_BLOCK_ID_TD1B = 0xda, + DBG_BLOCK_ID_UNUSED35 = 0xdb, + DBG_BLOCK_ID_UNUSED36 = 0xdc, + DBG_BLOCK_ID_UNUSED37 = 0xdd, + DBG_BLOCK_ID_UNUSED38 = 0xde, + DBG_BLOCK_ID_LDS00 = 0xdf, + DBG_BLOCK_ID_LDS01 = 0xe0, + DBG_BLOCK_ID_LDS02 = 0xe1, + DBG_BLOCK_ID_LDS03 = 0xe2, + DBG_BLOCK_ID_LDS04 = 0xe3, + DBG_BLOCK_ID_LDS05 = 0xe4, + DBG_BLOCK_ID_LDS06 = 0xe5, + DBG_BLOCK_ID_LDS07 = 0xe6, + DBG_BLOCK_ID_LDS08 = 0xe7, + DBG_BLOCK_ID_LDS09 = 0xe8, + DBG_BLOCK_ID_LDS0A = 0xe9, + DBG_BLOCK_ID_LDS0B = 0xea, + DBG_BLOCK_ID_UNUSED39 = 0xeb, + DBG_BLOCK_ID_UNUSED40 = 0xec, + DBG_BLOCK_ID_UNUSED41 = 0xed, + DBG_BLOCK_ID_UNUSED42 = 0xee, + DBG_BLOCK_ID_LDS10 = 0xef, + DBG_BLOCK_ID_LDS11 = 0xf0, + DBG_BLOCK_ID_LDS12 = 0xf1, + DBG_BLOCK_ID_LDS13 = 0xf2, + DBG_BLOCK_ID_LDS14 = 0xf3, + DBG_BLOCK_ID_LDS15 = 0xf4, + DBG_BLOCK_ID_LDS16 = 0xf5, + DBG_BLOCK_ID_LDS17 = 0xf6, + DBG_BLOCK_ID_LDS18 = 0xf7, + DBG_BLOCK_ID_LDS19 = 0xf8, + DBG_BLOCK_ID_LDS1A = 0xf9, + DBG_BLOCK_ID_LDS1B = 0xfa, + DBG_BLOCK_ID_UNUSED43 = 0xfb, + DBG_BLOCK_ID_UNUSED44 = 0xfc, + DBG_BLOCK_ID_UNUSED45 = 0xfd, + DBG_BLOCK_ID_UNUSED46 = 0xfe, +} DebugBlockId; +typedef enum DebugBlockId_BY2 { + DBG_BLOCK_ID_RESERVED_BY2 = 0x0, + DBG_BLOCK_ID_VMC_BY2 = 0x1, + DBG_BLOCK_ID_UNUSED0_BY2 = 0x2, + DBG_BLOCK_ID_GRBM_BY2 = 0x3, + DBG_BLOCK_ID_CSC_BY2 = 0x4, + DBG_BLOCK_ID_IH_BY2 = 0x5, + DBG_BLOCK_ID_SQ_BY2 = 0x6, + DBG_BLOCK_ID_UVD_BY2 = 0x7, + DBG_BLOCK_ID_SDMA0_BY2 = 0x8, + DBG_BLOCK_ID_SPIM_BY2 = 0x9, + DBG_BLOCK_ID_VC0_BY2 = 0xa, + DBG_BLOCK_ID_PA_BY2 = 0xb, + DBG_BLOCK_ID_CP0_BY2 = 0xc, + DBG_BLOCK_ID_CP2_BY2 = 0xd, + DBG_BLOCK_ID_PC0_BY2 = 0xe, + DBG_BLOCK_ID_BCI0_BY2 = 0xf, + DBG_BLOCK_ID_SXM0_BY2 = 0x10, + DBG_BLOCK_ID_SCT0_BY2 = 0x11, + DBG_BLOCK_ID_SPM0_BY2 = 0x12, + DBG_BLOCK_ID_BCI2_BY2 = 0x13, + DBG_BLOCK_ID_TCA_BY2 = 0x14, + DBG_BLOCK_ID_TCCA_BY2 = 0x15, + DBG_BLOCK_ID_MCC_BY2 = 0x16, + DBG_BLOCK_ID_MCC2_BY2 = 0x17, + DBG_BLOCK_ID_MCD_BY2 = 0x18, + DBG_BLOCK_ID_MCD2_BY2 = 0x19, + DBG_BLOCK_ID_MCD4_BY2 = 0x1a, + DBG_BLOCK_ID_MCB_BY2 = 0x1b, + DBG_BLOCK_ID_SQA_BY2 = 0x1c, + DBG_BLOCK_ID_SQA02_BY2 = 0x1d, + DBG_BLOCK_ID_SQA11_BY2 = 0x1e, + DBG_BLOCK_ID_UNUSED8_BY2 = 0x1f, + DBG_BLOCK_ID_SQB_BY2 = 0x20, + DBG_BLOCK_ID_SQB10_BY2 = 0x21, + DBG_BLOCK_ID_UNUSED10_BY2 = 0x22, + DBG_BLOCK_ID_UNUSED12_BY2 = 0x23, + DBG_BLOCK_ID_CB_BY2 = 0x24, + DBG_BLOCK_ID_CB02_BY2 = 0x25, + DBG_BLOCK_ID_CB10_BY2 = 0x26, + DBG_BLOCK_ID_CB12_BY2 = 0x27, + DBG_BLOCK_ID_SXS_BY2 = 0x28, + DBG_BLOCK_ID_SXS2_BY2 = 0x29, + DBG_BLOCK_ID_SXS4_BY2 = 0x2a, + DBG_BLOCK_ID_SXS6_BY2 = 0x2b, + DBG_BLOCK_ID_DB_BY2 = 0x2c, + DBG_BLOCK_ID_DB02_BY2 = 0x2d, + DBG_BLOCK_ID_DB10_BY2 = 0x2e, + DBG_BLOCK_ID_DB12_BY2 = 0x2f, + DBG_BLOCK_ID_TCP_BY2 = 0x30, + DBG_BLOCK_ID_TCP2_BY2 = 0x31, + DBG_BLOCK_ID_TCP4_BY2 = 0x32, + DBG_BLOCK_ID_TCP6_BY2 = 0x33, + DBG_BLOCK_ID_TCP8_BY2 = 0x34, + DBG_BLOCK_ID_TCP10_BY2 = 0x35, + DBG_BLOCK_ID_TCP12_BY2 = 0x36, + DBG_BLOCK_ID_TCP14_BY2 = 0x37, + DBG_BLOCK_ID_TCP16_BY2 = 0x38, + DBG_BLOCK_ID_TCP18_BY2 = 0x39, + DBG_BLOCK_ID_TCP20_BY2 = 0x3a, + DBG_BLOCK_ID_TCP22_BY2 = 0x3b, + DBG_BLOCK_ID_TCP_RESERVED0_BY2 = 0x3c, + DBG_BLOCK_ID_TCP_RESERVED2_BY2 = 0x3d, + DBG_BLOCK_ID_TCP_RESERVED4_BY2 = 0x3e, + DBG_BLOCK_ID_TCP_RESERVED6_BY2 = 0x3f, + DBG_BLOCK_ID_TCC_BY2 = 0x40, + DBG_BLOCK_ID_TCC2_BY2 = 0x41, + DBG_BLOCK_ID_TCC4_BY2 = 0x42, + DBG_BLOCK_ID_TCC6_BY2 = 0x43, + DBG_BLOCK_ID_SPS_BY2 = 0x44, + DBG_BLOCK_ID_SPS02_BY2 = 0x45, + DBG_BLOCK_ID_SPS11_BY2 = 0x46, + DBG_BLOCK_ID_UNUSED14_BY2 = 0x47, + DBG_BLOCK_ID_TA_BY2 = 0x48, + DBG_BLOCK_ID_TA02_BY2 = 0x49, + DBG_BLOCK_ID_TA04_BY2 = 0x4a, + DBG_BLOCK_ID_TA06_BY2 = 0x4b, + DBG_BLOCK_ID_TA08_BY2 = 0x4c, + DBG_BLOCK_ID_TA0A_BY2 = 0x4d, + DBG_BLOCK_ID_UNUSED20_BY2 = 0x4e, + DBG_BLOCK_ID_UNUSED22_BY2 = 0x4f, + DBG_BLOCK_ID_TA10_BY2 = 0x50, + DBG_BLOCK_ID_TA12_BY2 = 0x51, + DBG_BLOCK_ID_TA14_BY2 = 0x52, + DBG_BLOCK_ID_TA16_BY2 = 0x53, + DBG_BLOCK_ID_TA18_BY2 = 0x54, + DBG_BLOCK_ID_TA1A_BY2 = 0x55, + DBG_BLOCK_ID_UNUSED24_BY2 = 0x56, + DBG_BLOCK_ID_UNUSED26_BY2 = 0x57, + DBG_BLOCK_ID_TD_BY2 = 0x58, + DBG_BLOCK_ID_TD02_BY2 = 0x59, + DBG_BLOCK_ID_TD04_BY2 = 0x5a, + DBG_BLOCK_ID_TD06_BY2 = 0x5b, + DBG_BLOCK_ID_TD08_BY2 = 0x5c, + DBG_BLOCK_ID_TD0A_BY2 = 0x5d, + DBG_BLOCK_ID_UNUSED28_BY2 = 0x5e, + DBG_BLOCK_ID_UNUSED30_BY2 = 0x5f, + DBG_BLOCK_ID_TD10_BY2 = 0x60, + DBG_BLOCK_ID_TD12_BY2 = 0x61, + DBG_BLOCK_ID_TD14_BY2 = 0x62, + DBG_BLOCK_ID_TD16_BY2 = 0x63, + DBG_BLOCK_ID_TD18_BY2 = 0x64, + DBG_BLOCK_ID_TD1A_BY2 = 0x65, + DBG_BLOCK_ID_UNUSED32_BY2 = 0x66, + DBG_BLOCK_ID_UNUSED34_BY2 = 0x67, + DBG_BLOCK_ID_LDS_BY2 = 0x68, + DBG_BLOCK_ID_LDS02_BY2 = 0x69, + DBG_BLOCK_ID_LDS04_BY2 = 0x6a, + DBG_BLOCK_ID_LDS06_BY2 = 0x6b, + DBG_BLOCK_ID_LDS08_BY2 = 0x6c, + DBG_BLOCK_ID_LDS0A_BY2 = 0x6d, + DBG_BLOCK_ID_UNUSED36_BY2 = 0x6e, + DBG_BLOCK_ID_UNUSED38_BY2 = 0x6f, + DBG_BLOCK_ID_LDS10_BY2 = 0x70, + DBG_BLOCK_ID_LDS12_BY2 = 0x71, + DBG_BLOCK_ID_LDS14_BY2 = 0x72, + DBG_BLOCK_ID_LDS16_BY2 = 0x73, + DBG_BLOCK_ID_LDS18_BY2 = 0x74, + DBG_BLOCK_ID_LDS1A_BY2 = 0x75, + DBG_BLOCK_ID_UNUSED40_BY2 = 0x76, + DBG_BLOCK_ID_UNUSED42_BY2 = 0x77, +} DebugBlockId_BY2; +typedef enum DebugBlockId_BY4 { + DBG_BLOCK_ID_RESERVED_BY4 = 0x0, + DBG_BLOCK_ID_UNUSED0_BY4 = 0x1, + DBG_BLOCK_ID_CSC_BY4 = 0x2, + DBG_BLOCK_ID_SQ_BY4 = 0x3, + DBG_BLOCK_ID_SDMA0_BY4 = 0x4, + DBG_BLOCK_ID_VC0_BY4 = 0x5, + DBG_BLOCK_ID_CP0_BY4 = 0x6, + DBG_BLOCK_ID_UNUSED1_BY4 = 0x7, + DBG_BLOCK_ID_SXM0_BY4 = 0x8, + DBG_BLOCK_ID_SPM0_BY4 = 0x9, + DBG_BLOCK_ID_TCAA_BY4 = 0xa, + DBG_BLOCK_ID_MCC_BY4 = 0xb, + DBG_BLOCK_ID_MCD_BY4 = 0xc, + DBG_BLOCK_ID_MCD4_BY4 = 0xd, + DBG_BLOCK_ID_SQA_BY4 = 0xe, + DBG_BLOCK_ID_SQA11_BY4 = 0xf, + DBG_BLOCK_ID_SQB_BY4 = 0x10, + DBG_BLOCK_ID_UNUSED10_BY4 = 0x11, + DBG_BLOCK_ID_CB_BY4 = 0x12, + DBG_BLOCK_ID_CB10_BY4 = 0x13, + DBG_BLOCK_ID_SXS_BY4 = 0x14, + DBG_BLOCK_ID_SXS4_BY4 = 0x15, + DBG_BLOCK_ID_DB_BY4 = 0x16, + DBG_BLOCK_ID_DB10_BY4 = 0x17, + DBG_BLOCK_ID_TCP_BY4 = 0x18, + DBG_BLOCK_ID_TCP4_BY4 = 0x19, + DBG_BLOCK_ID_TCP8_BY4 = 0x1a, + DBG_BLOCK_ID_TCP12_BY4 = 0x1b, + DBG_BLOCK_ID_TCP16_BY4 = 0x1c, + DBG_BLOCK_ID_TCP20_BY4 = 0x1d, + DBG_BLOCK_ID_TCP_RESERVED0_BY4 = 0x1e, + DBG_BLOCK_ID_TCP_RESERVED4_BY4 = 0x1f, + DBG_BLOCK_ID_TCC_BY4 = 0x20, + DBG_BLOCK_ID_TCC4_BY4 = 0x21, + DBG_BLOCK_ID_SPS_BY4 = 0x22, + DBG_BLOCK_ID_SPS11_BY4 = 0x23, + DBG_BLOCK_ID_TA_BY4 = 0x24, + DBG_BLOCK_ID_TA04_BY4 = 0x25, + DBG_BLOCK_ID_TA08_BY4 = 0x26, + DBG_BLOCK_ID_UNUSED20_BY4 = 0x27, + DBG_BLOCK_ID_TA10_BY4 = 0x28, + DBG_BLOCK_ID_TA14_BY4 = 0x29, + DBG_BLOCK_ID_TA18_BY4 = 0x2a, + DBG_BLOCK_ID_UNUSED24_BY4 = 0x2b, + DBG_BLOCK_ID_TD_BY4 = 0x2c, + DBG_BLOCK_ID_TD04_BY4 = 0x2d, + DBG_BLOCK_ID_TD08_BY4 = 0x2e, + DBG_BLOCK_ID_UNUSED28_BY4 = 0x2f, + DBG_BLOCK_ID_TD10_BY4 = 0x30, + DBG_BLOCK_ID_TD14_BY4 = 0x31, + DBG_BLOCK_ID_TD18_BY4 = 0x32, + DBG_BLOCK_ID_UNUSED32_BY4 = 0x33, + DBG_BLOCK_ID_LDS_BY4 = 0x34, + DBG_BLOCK_ID_LDS04_BY4 = 0x35, + DBG_BLOCK_ID_LDS08_BY4 = 0x36, + DBG_BLOCK_ID_UNUSED36_BY4 = 0x37, + DBG_BLOCK_ID_LDS10_BY4 = 0x38, + DBG_BLOCK_ID_LDS14_BY4 = 0x39, + DBG_BLOCK_ID_LDS18_BY4 = 0x3a, + DBG_BLOCK_ID_UNUSED40_BY4 = 0x3b, +} DebugBlockId_BY4; +typedef enum DebugBlockId_BY8 { + DBG_BLOCK_ID_RESERVED_BY8 = 0x0, + DBG_BLOCK_ID_CSC_BY8 = 0x1, + DBG_BLOCK_ID_SDMA0_BY8 = 0x2, + DBG_BLOCK_ID_CP0_BY8 = 0x3, + DBG_BLOCK_ID_SXM0_BY8 = 0x4, + DBG_BLOCK_ID_TCA_BY8 = 0x5, + DBG_BLOCK_ID_MCD_BY8 = 0x6, + DBG_BLOCK_ID_SQA_BY8 = 0x7, + DBG_BLOCK_ID_SQB_BY8 = 0x8, + DBG_BLOCK_ID_CB_BY8 = 0x9, + DBG_BLOCK_ID_SXS_BY8 = 0xa, + DBG_BLOCK_ID_DB_BY8 = 0xb, + DBG_BLOCK_ID_TCP_BY8 = 0xc, + DBG_BLOCK_ID_TCP8_BY8 = 0xd, + DBG_BLOCK_ID_TCP16_BY8 = 0xe, + DBG_BLOCK_ID_TCP_RESERVED0_BY8 = 0xf, + DBG_BLOCK_ID_TCC_BY8 = 0x10, + DBG_BLOCK_ID_SPS_BY8 = 0x11, + DBG_BLOCK_ID_TA_BY8 = 0x12, + DBG_BLOCK_ID_TA08_BY8 = 0x13, + DBG_BLOCK_ID_TA10_BY8 = 0x14, + DBG_BLOCK_ID_TA18_BY8 = 0x15, + DBG_BLOCK_ID_TD_BY8 = 0x16, + DBG_BLOCK_ID_TD08_BY8 = 0x17, + DBG_BLOCK_ID_TD10_BY8 = 0x18, + DBG_BLOCK_ID_TD18_BY8 = 0x19, + DBG_BLOCK_ID_LDS_BY8 = 0x1a, + DBG_BLOCK_ID_LDS08_BY8 = 0x1b, + DBG_BLOCK_ID_LDS10_BY8 = 0x1c, + DBG_BLOCK_ID_LDS18_BY8 = 0x1d, +} DebugBlockId_BY8; +typedef enum DebugBlockId_BY16 { + DBG_BLOCK_ID_RESERVED_BY16 = 0x0, + DBG_BLOCK_ID_SDMA0_BY16 = 0x1, + DBG_BLOCK_ID_SXM_BY16 = 0x2, + DBG_BLOCK_ID_MCD_BY16 = 0x3, + DBG_BLOCK_ID_SQB_BY16 = 0x4, + DBG_BLOCK_ID_SXS_BY16 = 0x5, + DBG_BLOCK_ID_TCP_BY16 = 0x6, + DBG_BLOCK_ID_TCP16_BY16 = 0x7, + DBG_BLOCK_ID_TCC_BY16 = 0x8, + DBG_BLOCK_ID_TA_BY16 = 0x9, + DBG_BLOCK_ID_TA10_BY16 = 0xa, + DBG_BLOCK_ID_TD_BY16 = 0xb, + DBG_BLOCK_ID_TD10_BY16 = 0xc, + DBG_BLOCK_ID_LDS_BY16 = 0xd, + DBG_BLOCK_ID_LDS10_BY16 = 0xe, +} DebugBlockId_BY16; +typedef enum SurfaceEndian { + ENDIAN_NONE = 0x0, + ENDIAN_8IN16 = 0x1, + ENDIAN_8IN32 = 0x2, + ENDIAN_8IN64 = 0x3, +} SurfaceEndian; +typedef enum ArrayMode { + ARRAY_LINEAR_GENERAL = 0x0, + ARRAY_LINEAR_ALIGNED = 0x1, + ARRAY_1D_TILED_THIN1 = 0x2, + ARRAY_1D_TILED_THICK = 0x3, + ARRAY_2D_TILED_THIN1 = 0x4, + ARRAY_PRT_TILED_THIN1 = 0x5, + ARRAY_PRT_2D_TILED_THIN1 = 0x6, + ARRAY_2D_TILED_THICK = 0x7, + ARRAY_2D_TILED_XTHICK = 0x8, + ARRAY_PRT_TILED_THICK = 0x9, + ARRAY_PRT_2D_TILED_THICK = 0xa, + ARRAY_PRT_3D_TILED_THIN1 = 0xb, + ARRAY_3D_TILED_THIN1 = 0xc, + ARRAY_3D_TILED_THICK = 0xd, + ARRAY_3D_TILED_XTHICK = 0xe, + ARRAY_PRT_3D_TILED_THICK = 0xf, +} ArrayMode; +typedef enum PipeTiling { + CONFIG_1_PIPE = 0x0, + CONFIG_2_PIPE = 0x1, + CONFIG_4_PIPE = 0x2, + CONFIG_8_PIPE = 0x3, +} PipeTiling; +typedef enum BankTiling { + CONFIG_4_BANK = 0x0, + CONFIG_8_BANK = 0x1, +} BankTiling; +typedef enum GroupInterleave { + CONFIG_256B_GROUP = 0x0, + CONFIG_512B_GROUP = 0x1, +} GroupInterleave; +typedef enum RowTiling { + CONFIG_1KB_ROW = 0x0, + CONFIG_2KB_ROW = 0x1, + CONFIG_4KB_ROW = 0x2, + CONFIG_8KB_ROW = 0x3, + CONFIG_1KB_ROW_OPT = 0x4, + CONFIG_2KB_ROW_OPT = 0x5, + CONFIG_4KB_ROW_OPT = 0x6, + CONFIG_8KB_ROW_OPT = 0x7, +} RowTiling; +typedef enum BankSwapBytes { + CONFIG_128B_SWAPS = 0x0, + CONFIG_256B_SWAPS = 0x1, + CONFIG_512B_SWAPS = 0x2, + CONFIG_1KB_SWAPS = 0x3, +} BankSwapBytes; +typedef enum SampleSplitBytes { + CONFIG_1KB_SPLIT = 0x0, + CONFIG_2KB_SPLIT = 0x1, + CONFIG_4KB_SPLIT = 0x2, + CONFIG_8KB_SPLIT = 0x3, +} SampleSplitBytes; +typedef enum NumPipes { + ADDR_CONFIG_1_PIPE = 0x0, + ADDR_CONFIG_2_PIPE = 0x1, + ADDR_CONFIG_4_PIPE = 0x2, + ADDR_CONFIG_8_PIPE = 0x3, +} NumPipes; +typedef enum PipeInterleaveSize { + ADDR_CONFIG_PIPE_INTERLEAVE_256B = 0x0, + ADDR_CONFIG_PIPE_INTERLEAVE_512B = 0x1, +} PipeInterleaveSize; +typedef enum BankInterleaveSize { + ADDR_CONFIG_BANK_INTERLEAVE_1 = 0x0, + ADDR_CONFIG_BANK_INTERLEAVE_2 = 0x1, + ADDR_CONFIG_BANK_INTERLEAVE_4 = 0x2, + ADDR_CONFIG_BANK_INTERLEAVE_8 = 0x3, +} BankInterleaveSize; +typedef enum NumShaderEngines { + ADDR_CONFIG_1_SHADER_ENGINE = 0x0, + ADDR_CONFIG_2_SHADER_ENGINE = 0x1, +} NumShaderEngines; +typedef enum ShaderEngineTileSize { + ADDR_CONFIG_SE_TILE_16 = 0x0, + ADDR_CONFIG_SE_TILE_32 = 0x1, +} ShaderEngineTileSize; +typedef enum NumGPUs { + ADDR_CONFIG_1_GPU = 0x0, + ADDR_CONFIG_2_GPU = 0x1, + ADDR_CONFIG_4_GPU = 0x2, +} NumGPUs; +typedef enum MultiGPUTileSize { + ADDR_CONFIG_GPU_TILE_16 = 0x0, + ADDR_CONFIG_GPU_TILE_32 = 0x1, + ADDR_CONFIG_GPU_TILE_64 = 0x2, + ADDR_CONFIG_GPU_TILE_128 = 0x3, +} MultiGPUTileSize; +typedef enum RowSize { + ADDR_CONFIG_1KB_ROW = 0x0, + ADDR_CONFIG_2KB_ROW = 0x1, + ADDR_CONFIG_4KB_ROW = 0x2, +} RowSize; +typedef enum NumLowerPipes { + ADDR_CONFIG_1_LOWER_PIPES = 0x0, + ADDR_CONFIG_2_LOWER_PIPES = 0x1, +} NumLowerPipes; +typedef enum ColorTransform { + DCC_CT_AUTO = 0x0, + DCC_CT_NONE = 0x1, + ABGR_TO_A_BG_G_RB = 0x2, + BGRA_TO_BG_G_RB_A = 0x3, +} ColorTransform; +typedef enum CompareRef { + REF_NEVER = 0x0, + REF_LESS = 0x1, + REF_EQUAL = 0x2, + REF_LEQUAL = 0x3, + REF_GREATER = 0x4, + REF_NOTEQUAL = 0x5, + REF_GEQUAL = 0x6, + REF_ALWAYS = 0x7, +} CompareRef; +typedef enum ReadSize { + READ_256_BITS = 0x0, + READ_512_BITS = 0x1, +} ReadSize; +typedef enum DepthFormat { + DEPTH_INVALID = 0x0, + DEPTH_16 = 0x1, + DEPTH_X8_24 = 0x2, + DEPTH_8_24 = 0x3, + DEPTH_X8_24_FLOAT = 0x4, + DEPTH_8_24_FLOAT = 0x5, + DEPTH_32_FLOAT = 0x6, + DEPTH_X24_8_32_FLOAT = 0x7, +} DepthFormat; +typedef enum ZFormat { + Z_INVALID = 0x0, + Z_16 = 0x1, + Z_24 = 0x2, + Z_32_FLOAT = 0x3, +} ZFormat; +typedef enum StencilFormat { + STENCIL_INVALID = 0x0, + STENCIL_8 = 0x1, +} StencilFormat; +typedef enum CmaskMode { + CMASK_CLEAR_NONE = 0x0, + CMASK_CLEAR_ONE = 0x1, + CMASK_CLEAR_ALL = 0x2, + CMASK_ANY_EXPANDED = 0x3, + CMASK_ALPHA0_FRAG1 = 0x4, + CMASK_ALPHA0_FRAG2 = 0x5, + CMASK_ALPHA0_FRAG4 = 0x6, + CMASK_ALPHA0_FRAGS = 0x7, + CMASK_ALPHA1_FRAG1 = 0x8, + CMASK_ALPHA1_FRAG2 = 0x9, + CMASK_ALPHA1_FRAG4 = 0xa, + CMASK_ALPHA1_FRAGS = 0xb, + CMASK_ALPHAX_FRAG1 = 0xc, + CMASK_ALPHAX_FRAG2 = 0xd, + CMASK_ALPHAX_FRAG4 = 0xe, + CMASK_ALPHAX_FRAGS = 0xf, +} CmaskMode; +typedef enum QuadExportFormat { + EXPORT_UNUSED = 0x0, + EXPORT_32_R = 0x1, + EXPORT_32_GR = 0x2, + EXPORT_32_AR = 0x3, + EXPORT_FP16_ABGR = 0x4, + EXPORT_UNSIGNED16_ABGR = 0x5, + EXPORT_SIGNED16_ABGR = 0x6, + EXPORT_32_ABGR = 0x7, +} QuadExportFormat; +typedef enum QuadExportFormatOld { + EXPORT_4P_32BPC_ABGR = 0x0, + EXPORT_4P_16BPC_ABGR = 0x1, + EXPORT_4P_32BPC_GR = 0x2, + EXPORT_4P_32BPC_AR = 0x3, + EXPORT_2P_32BPC_ABGR = 0x4, + EXPORT_8P_32BPC_R = 0x5, +} QuadExportFormatOld; +typedef enum ColorFormat { + COLOR_INVALID = 0x0, + COLOR_8 = 0x1, + COLOR_16 = 0x2, + COLOR_8_8 = 0x3, + COLOR_32 = 0x4, + COLOR_16_16 = 0x5, + COLOR_10_11_11 = 0x6, + COLOR_11_11_10 = 0x7, + COLOR_10_10_10_2 = 0x8, + COLOR_2_10_10_10 = 0x9, + COLOR_8_8_8_8 = 0xa, + COLOR_32_32 = 0xb, + COLOR_16_16_16_16 = 0xc, + COLOR_RESERVED_13 = 0xd, + COLOR_32_32_32_32 = 0xe, + COLOR_RESERVED_15 = 0xf, + COLOR_5_6_5 = 0x10, + COLOR_1_5_5_5 = 0x11, + COLOR_5_5_5_1 = 0x12, + COLOR_4_4_4_4 = 0x13, + COLOR_8_24 = 0x14, + COLOR_24_8 = 0x15, + COLOR_X24_8_32_FLOAT = 0x16, + COLOR_RESERVED_23 = 0x17, +} ColorFormat; +typedef enum SurfaceFormat { + FMT_INVALID = 0x0, + FMT_8 = 0x1, + FMT_16 = 0x2, + FMT_8_8 = 0x3, + FMT_32 = 0x4, + FMT_16_16 = 0x5, + FMT_10_11_11 = 0x6, + FMT_11_11_10 = 0x7, + FMT_10_10_10_2 = 0x8, + FMT_2_10_10_10 = 0x9, + FMT_8_8_8_8 = 0xa, + FMT_32_32 = 0xb, + FMT_16_16_16_16 = 0xc, + FMT_32_32_32 = 0xd, + FMT_32_32_32_32 = 0xe, + FMT_RESERVED_4 = 0xf, + FMT_5_6_5 = 0x10, + FMT_1_5_5_5 = 0x11, + FMT_5_5_5_1 = 0x12, + FMT_4_4_4_4 = 0x13, + FMT_8_24 = 0x14, + FMT_24_8 = 0x15, + FMT_X24_8_32_FLOAT = 0x16, + FMT_RESERVED_33 = 0x17, + FMT_11_11_10_FLOAT = 0x18, + FMT_16_FLOAT = 0x19, + FMT_32_FLOAT = 0x1a, + FMT_16_16_FLOAT = 0x1b, + FMT_8_24_FLOAT = 0x1c, + FMT_24_8_FLOAT = 0x1d, + FMT_32_32_FLOAT = 0x1e, + FMT_10_11_11_FLOAT = 0x1f, + FMT_16_16_16_16_FLOAT = 0x20, + FMT_3_3_2 = 0x21, + FMT_6_5_5 = 0x22, + FMT_32_32_32_32_FLOAT = 0x23, + FMT_RESERVED_36 = 0x24, + FMT_1 = 0x25, + FMT_1_REVERSED = 0x26, + FMT_GB_GR = 0x27, + FMT_BG_RG = 0x28, + FMT_32_AS_8 = 0x29, + FMT_32_AS_8_8 = 0x2a, + FMT_5_9_9_9_SHAREDEXP = 0x2b, + FMT_8_8_8 = 0x2c, + FMT_16_16_16 = 0x2d, + FMT_16_16_16_FLOAT = 0x2e, + FMT_4_4 = 0x2f, + FMT_32_32_32_FLOAT = 0x30, + FMT_BC1 = 0x31, + FMT_BC2 = 0x32, + FMT_BC3 = 0x33, + FMT_BC4 = 0x34, + FMT_BC5 = 0x35, + FMT_BC6 = 0x36, + FMT_BC7 = 0x37, + FMT_32_AS_32_32_32_32 = 0x38, + FMT_APC3 = 0x39, + FMT_APC4 = 0x3a, + FMT_APC5 = 0x3b, + FMT_APC6 = 0x3c, + FMT_APC7 = 0x3d, + FMT_CTX1 = 0x3e, + FMT_RESERVED_63 = 0x3f, +} SurfaceFormat; +typedef enum BUF_DATA_FORMAT { + BUF_DATA_FORMAT_INVALID = 0x0, + BUF_DATA_FORMAT_8 = 0x1, + BUF_DATA_FORMAT_16 = 0x2, + BUF_DATA_FORMAT_8_8 = 0x3, + BUF_DATA_FORMAT_32 = 0x4, + BUF_DATA_FORMAT_16_16 = 0x5, + BUF_DATA_FORMAT_10_11_11 = 0x6, + BUF_DATA_FORMAT_11_11_10 = 0x7, + BUF_DATA_FORMAT_10_10_10_2 = 0x8, + BUF_DATA_FORMAT_2_10_10_10 = 0x9, + BUF_DATA_FORMAT_8_8_8_8 = 0xa, + BUF_DATA_FORMAT_32_32 = 0xb, + BUF_DATA_FORMAT_16_16_16_16 = 0xc, + BUF_DATA_FORMAT_32_32_32 = 0xd, + BUF_DATA_FORMAT_32_32_32_32 = 0xe, + BUF_DATA_FORMAT_RESERVED_15 = 0xf, +} BUF_DATA_FORMAT; +typedef enum IMG_DATA_FORMAT { + IMG_DATA_FORMAT_INVALID = 0x0, + IMG_DATA_FORMAT_8 = 0x1, + IMG_DATA_FORMAT_16 = 0x2, + IMG_DATA_FORMAT_8_8 = 0x3, + IMG_DATA_FORMAT_32 = 0x4, + IMG_DATA_FORMAT_16_16 = 0x5, + IMG_DATA_FORMAT_10_11_11 = 0x6, + IMG_DATA_FORMAT_11_11_10 = 0x7, + IMG_DATA_FORMAT_10_10_10_2 = 0x8, + IMG_DATA_FORMAT_2_10_10_10 = 0x9, + IMG_DATA_FORMAT_8_8_8_8 = 0xa, + IMG_DATA_FORMAT_32_32 = 0xb, + IMG_DATA_FORMAT_16_16_16_16 = 0xc, + IMG_DATA_FORMAT_32_32_32 = 0xd, + IMG_DATA_FORMAT_32_32_32_32 = 0xe, + IMG_DATA_FORMAT_RESERVED_15 = 0xf, + IMG_DATA_FORMAT_5_6_5 = 0x10, + IMG_DATA_FORMAT_1_5_5_5 = 0x11, + IMG_DATA_FORMAT_5_5_5_1 = 0x12, + IMG_DATA_FORMAT_4_4_4_4 = 0x13, + IMG_DATA_FORMAT_8_24 = 0x14, + IMG_DATA_FORMAT_24_8 = 0x15, + IMG_DATA_FORMAT_X24_8_32 = 0x16, + IMG_DATA_FORMAT_RESERVED_23 = 0x17, + IMG_DATA_FORMAT_RESERVED_24 = 0x18, + IMG_DATA_FORMAT_RESERVED_25 = 0x19, + IMG_DATA_FORMAT_RESERVED_26 = 0x1a, + IMG_DATA_FORMAT_RESERVED_27 = 0x1b, + IMG_DATA_FORMAT_RESERVED_28 = 0x1c, + IMG_DATA_FORMAT_RESERVED_29 = 0x1d, + IMG_DATA_FORMAT_RESERVED_30 = 0x1e, + IMG_DATA_FORMAT_RESERVED_31 = 0x1f, + IMG_DATA_FORMAT_GB_GR = 0x20, + IMG_DATA_FORMAT_BG_RG = 0x21, + IMG_DATA_FORMAT_5_9_9_9 = 0x22, + IMG_DATA_FORMAT_BC1 = 0x23, + IMG_DATA_FORMAT_BC2 = 0x24, + IMG_DATA_FORMAT_BC3 = 0x25, + IMG_DATA_FORMAT_BC4 = 0x26, + IMG_DATA_FORMAT_BC5 = 0x27, + IMG_DATA_FORMAT_BC6 = 0x28, + IMG_DATA_FORMAT_BC7 = 0x29, + IMG_DATA_FORMAT_RESERVED_42 = 0x2a, + IMG_DATA_FORMAT_RESERVED_43 = 0x2b, + IMG_DATA_FORMAT_FMASK8_S2_F1 = 0x2c, + IMG_DATA_FORMAT_FMASK8_S4_F1 = 0x2d, + IMG_DATA_FORMAT_FMASK8_S8_F1 = 0x2e, + IMG_DATA_FORMAT_FMASK8_S2_F2 = 0x2f, + IMG_DATA_FORMAT_FMASK8_S4_F2 = 0x30, + IMG_DATA_FORMAT_FMASK8_S4_F4 = 0x31, + IMG_DATA_FORMAT_FMASK16_S16_F1 = 0x32, + IMG_DATA_FORMAT_FMASK16_S8_F2 = 0x33, + IMG_DATA_FORMAT_FMASK32_S16_F2 = 0x34, + IMG_DATA_FORMAT_FMASK32_S8_F4 = 0x35, + IMG_DATA_FORMAT_FMASK32_S8_F8 = 0x36, + IMG_DATA_FORMAT_FMASK64_S16_F4 = 0x37, + IMG_DATA_FORMAT_FMASK64_S16_F8 = 0x38, + IMG_DATA_FORMAT_4_4 = 0x39, + IMG_DATA_FORMAT_6_5_5 = 0x3a, + IMG_DATA_FORMAT_1 = 0x3b, + IMG_DATA_FORMAT_1_REVERSED = 0x3c, + IMG_DATA_FORMAT_32_AS_8 = 0x3d, + IMG_DATA_FORMAT_32_AS_8_8 = 0x3e, + IMG_DATA_FORMAT_32_AS_32_32_32_32 = 0x3f, +} IMG_DATA_FORMAT; +typedef enum BUF_NUM_FORMAT { + BUF_NUM_FORMAT_UNORM = 0x0, + BUF_NUM_FORMAT_SNORM = 0x1, + BUF_NUM_FORMAT_USCALED = 0x2, + BUF_NUM_FORMAT_SSCALED = 0x3, + BUF_NUM_FORMAT_UINT = 0x4, + BUF_NUM_FORMAT_SINT = 0x5, + BUF_NUM_FORMAT_RESERVED_6 = 0x6, + BUF_NUM_FORMAT_FLOAT = 0x7, +} BUF_NUM_FORMAT; +typedef enum IMG_NUM_FORMAT { + IMG_NUM_FORMAT_UNORM = 0x0, + IMG_NUM_FORMAT_SNORM = 0x1, + IMG_NUM_FORMAT_USCALED = 0x2, + IMG_NUM_FORMAT_SSCALED = 0x3, + IMG_NUM_FORMAT_UINT = 0x4, + IMG_NUM_FORMAT_SINT = 0x5, + IMG_NUM_FORMAT_RESERVED_6 = 0x6, + IMG_NUM_FORMAT_FLOAT = 0x7, + IMG_NUM_FORMAT_RESERVED_8 = 0x8, + IMG_NUM_FORMAT_SRGB = 0x9, + IMG_NUM_FORMAT_RESERVED_10 = 0xa, + IMG_NUM_FORMAT_RESERVED_11 = 0xb, + IMG_NUM_FORMAT_RESERVED_12 = 0xc, + IMG_NUM_FORMAT_RESERVED_13 = 0xd, + IMG_NUM_FORMAT_RESERVED_14 = 0xe, + IMG_NUM_FORMAT_RESERVED_15 = 0xf, +} IMG_NUM_FORMAT; +typedef enum TileType { + ARRAY_COLOR_TILE = 0x0, + ARRAY_DEPTH_TILE = 0x1, +} TileType; +typedef enum NonDispTilingOrder { + ADDR_SURF_MICRO_TILING_DISPLAY = 0x0, + ADDR_SURF_MICRO_TILING_NON_DISPLAY = 0x1, +} NonDispTilingOrder; +typedef enum MicroTileMode { + ADDR_SURF_DISPLAY_MICRO_TILING = 0x0, + ADDR_SURF_THIN_MICRO_TILING = 0x1, + ADDR_SURF_DEPTH_MICRO_TILING = 0x2, + ADDR_SURF_ROTATED_MICRO_TILING = 0x3, + ADDR_SURF_THICK_MICRO_TILING = 0x4, +} MicroTileMode; +typedef enum TileSplit { + ADDR_SURF_TILE_SPLIT_64B = 0x0, + ADDR_SURF_TILE_SPLIT_128B = 0x1, + ADDR_SURF_TILE_SPLIT_256B = 0x2, + ADDR_SURF_TILE_SPLIT_512B = 0x3, + ADDR_SURF_TILE_SPLIT_1KB = 0x4, + ADDR_SURF_TILE_SPLIT_2KB = 0x5, + ADDR_SURF_TILE_SPLIT_4KB = 0x6, +} TileSplit; +typedef enum SampleSplit { + ADDR_SURF_SAMPLE_SPLIT_1 = 0x0, + ADDR_SURF_SAMPLE_SPLIT_2 = 0x1, + ADDR_SURF_SAMPLE_SPLIT_4 = 0x2, + ADDR_SURF_SAMPLE_SPLIT_8 = 0x3, +} SampleSplit; +typedef enum PipeConfig { + ADDR_SURF_P2 = 0x0, + ADDR_SURF_P2_RESERVED0 = 0x1, + ADDR_SURF_P2_RESERVED1 = 0x2, + ADDR_SURF_P2_RESERVED2 = 0x3, + ADDR_SURF_P4_8x16 = 0x4, + ADDR_SURF_P4_16x16 = 0x5, + ADDR_SURF_P4_16x32 = 0x6, + ADDR_SURF_P4_32x32 = 0x7, + ADDR_SURF_P8_16x16_8x16 = 0x8, + ADDR_SURF_P8_16x32_8x16 = 0x9, + ADDR_SURF_P8_32x32_8x16 = 0xa, + ADDR_SURF_P8_16x32_16x16 = 0xb, + ADDR_SURF_P8_32x32_16x16 = 0xc, + ADDR_SURF_P8_32x32_16x32 = 0xd, + ADDR_SURF_P8_32x64_32x32 = 0xe, + ADDR_SURF_P8_RESERVED0 = 0xf, + ADDR_SURF_P16_32x32_8x16 = 0x10, + ADDR_SURF_P16_32x32_16x16 = 0x11, +} PipeConfig; +typedef enum NumBanks { + ADDR_SURF_2_BANK = 0x0, + ADDR_SURF_4_BANK = 0x1, + ADDR_SURF_8_BANK = 0x2, + ADDR_SURF_16_BANK = 0x3, +} NumBanks; +typedef enum BankWidth { + ADDR_SURF_BANK_WIDTH_1 = 0x0, + ADDR_SURF_BANK_WIDTH_2 = 0x1, + ADDR_SURF_BANK_WIDTH_4 = 0x2, + ADDR_SURF_BANK_WIDTH_8 = 0x3, +} BankWidth; +typedef enum BankHeight { + ADDR_SURF_BANK_HEIGHT_1 = 0x0, + ADDR_SURF_BANK_HEIGHT_2 = 0x1, + ADDR_SURF_BANK_HEIGHT_4 = 0x2, + ADDR_SURF_BANK_HEIGHT_8 = 0x3, +} BankHeight; +typedef enum BankWidthHeight { + ADDR_SURF_BANK_WH_1 = 0x0, + ADDR_SURF_BANK_WH_2 = 0x1, + ADDR_SURF_BANK_WH_4 = 0x2, + ADDR_SURF_BANK_WH_8 = 0x3, +} BankWidthHeight; +typedef enum MacroTileAspect { + ADDR_SURF_MACRO_ASPECT_1 = 0x0, + ADDR_SURF_MACRO_ASPECT_2 = 0x1, + ADDR_SURF_MACRO_ASPECT_4 = 0x2, + ADDR_SURF_MACRO_ASPECT_8 = 0x3, +} MacroTileAspect; +typedef enum GATCL1RequestType { + GATCL1_TYPE_NORMAL = 0x0, + GATCL1_TYPE_SHOOTDOWN = 0x1, + GATCL1_TYPE_BYPASS = 0x2, +} GATCL1RequestType; +typedef enum TCC_CACHE_POLICIES { + TCC_CACHE_POLICY_LRU = 0x0, + TCC_CACHE_POLICY_STREAM = 0x1, +} TCC_CACHE_POLICIES; +typedef enum MTYPE { + MTYPE_NC_NV = 0x0, + MTYPE_NC = 0x1, + MTYPE_CC = 0x2, + MTYPE_UC = 0x3, +} MTYPE; +typedef enum PERFMON_COUNTER_MODE { + PERFMON_COUNTER_MODE_ACCUM = 0x0, + PERFMON_COUNTER_MODE_ACTIVE_CYCLES = 0x1, + PERFMON_COUNTER_MODE_MAX = 0x2, + PERFMON_COUNTER_MODE_DIRTY = 0x3, + PERFMON_COUNTER_MODE_SAMPLE = 0x4, + PERFMON_COUNTER_MODE_CYCLES_SINCE_FIRST_EVENT = 0x5, + PERFMON_COUNTER_MODE_CYCLES_SINCE_LAST_EVENT = 0x6, + PERFMON_COUNTER_MODE_CYCLES_GE_HI = 0x7, + PERFMON_COUNTER_MODE_CYCLES_EQ_HI = 0x8, + PERFMON_COUNTER_MODE_INACTIVE_CYCLES = 0x9, + PERFMON_COUNTER_MODE_RESERVED = 0xf, +} PERFMON_COUNTER_MODE; +typedef enum PERFMON_SPM_MODE { + PERFMON_SPM_MODE_OFF = 0x0, + PERFMON_SPM_MODE_16BIT_CLAMP = 0x1, + PERFMON_SPM_MODE_16BIT_NO_CLAMP = 0x2, + PERFMON_SPM_MODE_32BIT_CLAMP = 0x3, + PERFMON_SPM_MODE_32BIT_NO_CLAMP = 0x4, + PERFMON_SPM_MODE_RESERVED_5 = 0x5, + PERFMON_SPM_MODE_RESERVED_6 = 0x6, + PERFMON_SPM_MODE_RESERVED_7 = 0x7, + PERFMON_SPM_MODE_TEST_MODE_0 = 0x8, + PERFMON_SPM_MODE_TEST_MODE_1 = 0x9, + PERFMON_SPM_MODE_TEST_MODE_2 = 0xa, +} PERFMON_SPM_MODE; +typedef enum SurfaceTiling { + ARRAY_LINEAR = 0x0, + ARRAY_TILED = 0x1, +} SurfaceTiling; +typedef enum SurfaceArray { + ARRAY_1D = 0x0, + ARRAY_2D = 0x1, + ARRAY_3D = 0x2, + ARRAY_3D_SLICE = 0x3, +} SurfaceArray; +typedef enum ColorArray { + ARRAY_2D_ALT_COLOR = 0x0, + ARRAY_2D_COLOR = 0x1, + ARRAY_3D_SLICE_COLOR = 0x3, +} ColorArray; +typedef enum DepthArray { + ARRAY_2D_ALT_DEPTH = 0x0, + ARRAY_2D_DEPTH = 0x1, +} DepthArray; +typedef enum ENUM_NUM_SIMD_PER_CU { + NUM_SIMD_PER_CU = 0x4, +} ENUM_NUM_SIMD_PER_CU; +typedef enum MEM_PWR_FORCE_CTRL { + NO_FORCE_REQUEST = 0x0, + FORCE_LIGHT_SLEEP_REQUEST = 0x1, + FORCE_DEEP_SLEEP_REQUEST = 0x2, + FORCE_SHUT_DOWN_REQUEST = 0x3, +} MEM_PWR_FORCE_CTRL; +typedef enum MEM_PWR_FORCE_CTRL2 { + NO_FORCE_REQ = 0x0, + FORCE_LIGHT_SLEEP_REQ = 0x1, +} MEM_PWR_FORCE_CTRL2; +typedef enum MEM_PWR_DIS_CTRL { + ENABLE_MEM_PWR_CTRL = 0x0, + DISABLE_MEM_PWR_CTRL = 0x1, +} MEM_PWR_DIS_CTRL; +typedef enum MEM_PWR_SEL_CTRL { + DYNAMIC_SHUT_DOWN_ENABLE = 0x0, + DYNAMIC_DEEP_SLEEP_ENABLE = 0x1, + DYNAMIC_LIGHT_SLEEP_ENABLE = 0x2, +} MEM_PWR_SEL_CTRL; +typedef enum MEM_PWR_SEL_CTRL2 { + DYNAMIC_DEEP_SLEEP_EN = 0x0, + DYNAMIC_LIGHT_SLEEP_EN = 0x1, +} MEM_PWR_SEL_CTRL2; + +#endif /* ACP_2_2_ENUM_H */ diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h new file mode 100644 index 000000000000..32d2d4104309 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_sh_mask.h @@ -0,0 +1,2292 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ACP_2_2_SH_MASK_H +#define ACP_2_2_SH_MASK_H + +#define ACP_DMA_CNTL_0__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_0__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_0__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_0__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_0__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_0__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_0__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_0__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_0__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_0__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_1__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_1__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_1__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_1__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_1__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_1__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_1__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_1__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_1__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_1__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_2__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_2__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_2__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_2__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_2__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_2__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_2__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_2__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_2__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_2__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_3__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_3__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_3__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_3__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_3__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_3__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_3__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_3__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_3__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_3__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_4__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_4__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_4__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_4__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_4__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_4__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_4__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_4__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_4__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_4__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_5__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_5__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_5__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_5__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_5__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_5__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_5__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_5__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_5__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_5__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_6__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_6__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_6__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_6__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_6__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_6__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_6__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_6__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_6__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_6__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_7__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_7__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_7__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_7__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_7__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_7__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_7__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_7__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_7__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_7__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_8__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_8__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_8__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_8__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_8__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_8__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_8__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_8__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_8__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_8__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_9__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_9__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_9__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_9__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_9__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_9__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_9__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_9__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_9__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_9__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_10__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_10__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_10__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_10__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_10__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_10__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_10__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_10__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_10__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_10__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_11__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_11__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_11__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_11__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_11__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_11__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_11__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_11__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_11__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_11__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_12__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_12__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_12__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_12__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_12__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_12__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_12__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_12__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_12__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_12__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_13__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_13__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_13__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_13__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_13__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_13__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_13__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_13__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_13__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_13__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_14__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_14__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_14__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_14__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_14__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_14__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_14__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_14__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_14__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_14__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_15__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_15__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_15__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_15__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_15__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_15__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_15__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_15__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_15__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_15__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_PRIO_0__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_0__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_1__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_1__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_2__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_2__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_3__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_3__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_4__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_4__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_5__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_5__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_6__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_6__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_7__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_7__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_8__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_8__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_9__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_9__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_10__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_10__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_11__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_11__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_12__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_12__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_13__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_13__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_14__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_14__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_15__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_15__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_ERR_STS_0__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_0__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_0__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_0__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_1__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_1__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_1__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_1__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_2__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_2__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_2__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_2__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_3__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_3__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_3__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_3__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_4__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_4__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_4__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_4__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_5__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_5__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_5__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_5__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_6__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_6__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_6__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_6__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_7__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_7__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_7__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_7__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_8__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_8__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_8__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_8__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_9__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_9__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_9__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_9__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_10__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_10__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_10__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_10__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_11__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_11__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_11__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_11__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_12__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_12__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_12__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_12__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_13__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_13__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_13__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_13__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_14__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_14__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_14__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_14__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_15__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_15__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_15__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_15__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr_MASK 0xffffffff +#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr__SHIFT 0x0 +#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr_MASK 0xf +#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr__SHIFT 0x0 +#define ACP_DMA_CH_STS__DMAChSts_MASK 0xffff +#define ACP_DMA_CH_STS__DMAChSts__SHIFT 0x0 +#define ACP_DMA_CH_GROUP__DMAChanelGrouping_MASK 0x1 +#define ACP_DMA_CH_GROUP__DMAChanelGrouping__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP0_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP0_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP0_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP0_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP0_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP0_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP0_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP0_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP0_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP0_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP0_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP0_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP0_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP0_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP0_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP0_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP1_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP1_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP1_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP1_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP1_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP1_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP1_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP1_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP1_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP1_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP1_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP1_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP1_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP1_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP1_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP1_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP2_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP2_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP2_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP2_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP2_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP2_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP2_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP2_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP2_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP2_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP2_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP2_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP2_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP2_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP2_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP2_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap_MASK 0x3 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap__SHIFT 0x0 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb_MASK 0x80 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb__SHIFT 0x7 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb_MASK 0x100 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb_MASK 0x400 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode_MASK 0x2000 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode__SHIFT 0xd +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1 +#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap_MASK 0x3 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap__SHIFT 0x0 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb_MASK 0x80 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb__SHIFT 0x7 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb_MASK 0x100 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb_MASK 0x400 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode_MASK 0x2000 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode__SHIFT 0xd +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1 +#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate_MASK 0x1 +#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate__SHIFT 0x0 +#define ACP_CONTROL__ClkEn_MASK 0x1 +#define ACP_CONTROL__ClkEn__SHIFT 0x0 +#define ACP_CONTROL__JtagEn_MASK 0x400 +#define ACP_CONTROL__JtagEn__SHIFT 0xa +#define ACP_STATUS__ClkOn_MASK 0x1 +#define ACP_STATUS__ClkOn__SHIFT 0x0 +#define ACP_STATUS__ACPRefClkSpd_MASK 0x2 +#define ACP_STATUS__ACPRefClkSpd__SHIFT 0x1 +#define ACP_STATUS__SMUStutterLastEdge_MASK 0x4 +#define ACP_STATUS__SMUStutterLastEdge__SHIFT 0x2 +#define ACP_STATUS__MCStutterLastEdge_MASK 0x8 +#define ACP_STATUS__MCStutterLastEdge__SHIFT 0x3 +#define ACP_SOFT_RESET__SoftResetAud_MASK 0x100 +#define ACP_SOFT_RESET__SoftResetAud__SHIFT 0x8 +#define ACP_SOFT_RESET__SoftResetDMA_MASK 0x200 +#define ACP_SOFT_RESET__SoftResetDMA__SHIFT 0x9 +#define ACP_SOFT_RESET__InternalSoftResetMode_MASK 0x4000 +#define ACP_SOFT_RESET__InternalSoftResetMode__SHIFT 0xe +#define ACP_SOFT_RESET__ExternalSoftResetMode_MASK 0x8000 +#define ACP_SOFT_RESET__ExternalSoftResetMode__SHIFT 0xf +#define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000 +#define ACP_SOFT_RESET__SoftResetAudDone__SHIFT 0x18 +#define ACP_SOFT_RESET__SoftResetDMADone_MASK 0x2000000 +#define ACP_SOFT_RESET__SoftResetDMADone__SHIFT 0x19 +#define ACP_PwrMgmt_CNTL__SCLKSleepCntl_MASK 0x3 +#define ACP_PwrMgmt_CNTL__SCLKSleepCntl__SHIFT 0x0 +#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter_MASK 0xffff +#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter__SHIFT 0x0 +#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox_MASK 0xffffffff +#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg__SHIFT 0x0 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable_MASK 0x1 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable__SHIFT 0x0 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable_MASK 0x2 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable__SHIFT 0x1 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable_MASK 0x4 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable__SHIFT 0x2 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable_MASK 0x8 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable__SHIFT 0x3 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable_MASK 0x10 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable__SHIFT 0x4 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable_MASK 0x20 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable__SHIFT 0x5 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable_MASK 0x40 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable__SHIFT 0x6 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable_MASK 0x80 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable__SHIFT 0x7 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable_MASK 0x100 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable__SHIFT 0x8 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable_MASK 0x200 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable__SHIFT 0x9 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable_MASK 0x400 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable__SHIFT 0xa +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable_MASK 0x800 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable__SHIFT 0xb +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable_MASK 0x1000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable__SHIFT 0xc +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable_MASK 0x2000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable__SHIFT 0xd +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable_MASK 0x4000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable__SHIFT 0xe +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable_MASK 0x8000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable__SHIFT 0xf +#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt_MASK 0xffff +#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt_MASK 0xffff +#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt_MASK 0xffff +#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt_MASK 0xffff +#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt_MASK 0xffff +#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt_MASK 0xffff +#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt_MASK 0xffff +#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt_MASK 0xffff +#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt__SHIFT 0x0 +#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl_MASK 0xf +#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb_MASK 0x1 +#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask_MASK 0x100 +#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask_MASK 0x200 +#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask_MASK 0x400 +#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask__SHIFT 0xa +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x800 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xb +#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr_MASK 0x1 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr__SHIFT 0x0 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource_MASK 0xe +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource__SHIFT 0x1 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver_MASK 0x10 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver__SHIFT 0x4 +#define ACP_ERROR_SOURCE_STS__BRBAddrErr_MASK 0x20 +#define ACP_ERROR_SOURCE_STS__BRBAddrErr__SHIFT 0x5 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource_MASK 0x3c0 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource__SHIFT 0x6 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver_MASK 0x400 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver__SHIFT 0xa +#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr_MASK 0x800 +#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr__SHIFT 0xb +#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr_MASK 0x1000 +#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr__SHIFT 0xc +#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr_MASK 0x2000 +#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr__SHIFT 0xd +#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr_MASK 0x4000 +#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr__SHIFT 0xe +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr_MASK 0x8000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr__SHIFT 0xf +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource_MASK 0x70000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource__SHIFT 0x10 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver_MASK 0x80000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver__SHIFT 0x13 +#define ACP_ERROR_SOURCE_STS__DAGBErr_MASK 0x100000 +#define ACP_ERROR_SOURCE_STS__DAGBErr__SHIFT 0x14 +#define ACP_ERROR_SOURCE_STS__DAGBErrSource_MASK 0x1e00000 +#define ACP_ERROR_SOURCE_STS__DAGBErrSource__SHIFT 0x15 +#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver_MASK 0x2000000 +#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver__SHIFT 0x19 +#define ACP_ERROR_SOURCE_STS__DMATermOnErr_MASK 0x4000000 +#define ACP_ERROR_SOURCE_STS__DMATermOnErr__SHIFT 0x1a +#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr_MASK 0x10000000 +#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr__SHIFT 0x1c +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0_MASK 0x1 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0__SHIFT 0x0 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1_MASK 0x2 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1__SHIFT 0x1 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2_MASK 0x4 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2__SHIFT 0x2 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0_MASK 0x100 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0__SHIFT 0x8 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1_MASK 0x200 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1__SHIFT 0x9 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2_MASK 0x400 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2__SHIFT 0xa +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host_MASK 0x10000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host__SHIFT 0x10 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host_MASK 0x20000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host__SHIFT 0x11 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host_MASK 0x40000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host__SHIFT 0x12 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0_MASK 0x1 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0__SHIFT 0x0 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1_MASK 0x2 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1__SHIFT 0x1 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2_MASK 0x4 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2__SHIFT 0x2 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0_MASK 0x100 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0__SHIFT 0x8 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1_MASK 0x200 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1__SHIFT 0x9 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2_MASK 0x400 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2__SHIFT 0xa +#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask_MASK 0x10000 +#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask__SHIFT 0x10 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask_MASK 0x20000 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask__SHIFT 0x11 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask_MASK 0x40000 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask__SHIFT 0x12 +#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue_MASK 0x3ffff +#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue__SHIFT 0x0 +#define ACP_DAGBG_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DAGBG_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue_MASK 0x3ffff +#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue__SHIFT 0x0 +#define ACP_DAGBO_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DAGBO_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_EXTERNAL_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_EXTERNAL_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_EXTERNAL_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat_MASK 0x100 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck_MASK 0x100 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat_MASK 0x200 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck_MASK 0x200 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat_MASK 0x400 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat__SHIFT 0xa +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck_MASK 0x400 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck__SHIFT 0xa +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat_MASK 0x800 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xb +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck_MASK 0x800 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xb +#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat_MASK 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat__SHIFT 0x0 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack_MASK 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack__SHIFT 0x0 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat_MASK 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat__SHIFT 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack_MASK 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack__SHIFT 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat_MASK 0x4 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat__SHIFT 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack_MASK 0x4 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack__SHIFT 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat_MASK 0x100 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat__SHIFT 0x8 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack_MASK 0x100 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack__SHIFT 0x8 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat_MASK 0x200 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat__SHIFT 0x9 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack_MASK 0x200 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack__SHIFT 0x9 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat_MASK 0x400 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat__SHIFT 0xa +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack_MASK 0x400 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack__SHIFT 0xa +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat_MASK 0x10000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack_MASK 0x10000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat_MASK 0x20000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat__SHIFT 0x11 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack_MASK 0x20000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack__SHIFT 0x11 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat_MASK 0x40000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat__SHIFT 0x12 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack_MASK 0x40000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack__SHIFT 0x12 +#define ACP_DSP0_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP0_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP0_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP0_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP0_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP0_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP0_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP0_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP0_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP0_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP0_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP0_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP0_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP0_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP0_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP0_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP0_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP0_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP0_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP0_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP0_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP0_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP0_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP0_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP0_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP0_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP0_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP0_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP0_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP0_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue_MASK 0x3ffff +#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue__SHIFT 0x0 +#define ACP_DSP0_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP0_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP1_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP1_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP1_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP1_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP1_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP1_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP1_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP1_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP1_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP1_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP1_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP1_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP1_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP1_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP1_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP1_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP1_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP1_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP1_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP1_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP1_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP1_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP1_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP1_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP1_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP1_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP1_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP1_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP1_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP1_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue_MASK 0x3ffff +#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue__SHIFT 0x0 +#define ACP_DSP1_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP1_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP2_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP2_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP2_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP2_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP2_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP2_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP2_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP2_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP2_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP2_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP2_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP2_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP2_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP2_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP2_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP2_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP2_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP2_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP2_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP2_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP2_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP2_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP2_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP2_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP2_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP2_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP2_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP2_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP2_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP2_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue_MASK 0x3ffff +#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue__SHIFT 0x0 +#define ACP_DSP2_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP2_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr_MASK 0xff +#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr__SHIFT 0x0 +#define ACP_SRBM_Client_RDDATA__ReadData_MASK 0xffffffff +#define ACP_SRBM_Client_RDDATA__ReadData__SHIFT 0x0 +#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts_MASK 0x1 +#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts__SHIFT 0x0 +#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr_MASK 0x7ffffff +#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr__SHIFT 0x0 +#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data_MASK 0xffffffff +#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data__SHIFT 0x0 +#define ACP_SEMA_ADDR_LOW__ADDR_9_3_MASK 0x7f +#define ACP_SEMA_ADDR_LOW__ADDR_9_3__SHIFT 0x0 +#define ACP_SEMA_ADDR_HIGH__ADDR_39_10_MASK 0x3fffffff +#define ACP_SEMA_ADDR_HIGH__ADDR_39_10__SHIFT 0x0 +#define ACP_SEMA_CMD__REQ_CMD_MASK 0xf +#define ACP_SEMA_CMD__REQ_CMD__SHIFT 0x0 +#define ACP_SEMA_CMD__WR_PHASE_MASK 0x30 +#define ACP_SEMA_CMD__WR_PHASE__SHIFT 0x4 +#define ACP_SEMA_CMD__VMID_EN_MASK 0x80 +#define ACP_SEMA_CMD__VMID_EN__SHIFT 0x7 +#define ACP_SEMA_CMD__VMID_MASK 0xf00 +#define ACP_SEMA_CMD__VMID__SHIFT 0x8 +#define ACP_SEMA_CMD__ATC_MASK 0x1000 +#define ACP_SEMA_CMD__ATC__SHIFT 0xc +#define ACP_SEMA_STS__REQ_STS_MASK 0x3 +#define ACP_SEMA_STS__REQ_STS__SHIFT 0x0 +#define ACP_SEMA_STS__REQ_RESP_AVAIL_MASK 0x100 +#define ACP_SEMA_STS__REQ_RESP_AVAIL__SHIFT 0x8 +#define ACP_SEMA_REQ__ISSUE_POLL_REQ_MASK 0x1 +#define ACP_SEMA_REQ__ISSUE_POLL_REQ__SHIFT 0x0 +#define ACP_FW_STATUS__RUN_MASK 0x1 +#define ACP_FW_STATUS__RUN__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg__SHIFT 0x0 +#define ACP_TIMER__ACP_Timer_count_MASK 0xffffffff +#define ACP_TIMER__ACP_Timer_count__SHIFT 0x0 +#define ACP_TIMER_CNTL__ACP_Timer_control_MASK 0x1 +#define ACP_TIMER_CNTL__ACP_Timer_control__SHIFT 0x0 +#define ACP_DSP0_TIMER__ACP_DSP0_timer_MASK 0xffffff +#define ACP_DSP0_TIMER__ACP_DSP0_timer__SHIFT 0x0 +#define ACP_DSP1_TIMER__ACP_DSP1_timer_MASK 0xffffff +#define ACP_DSP1_TIMER__ACP_DSP1_timer__SHIFT 0x0 +#define ACP_DSP2_TIMER__ACP_DSP2_timer_MASK 0xffffff +#define ACP_DSP2_TIMER__ACP_DSP2_timer__SHIFT 0x0 +#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low__SHIFT 0x0 +#define ACP_DSP0_CS_STATE__DSP0_CS_state_MASK 0x1 +#define ACP_DSP0_CS_STATE__DSP0_CS_state__SHIFT 0x0 +#define ACP_DSP1_CS_STATE__DSP1_CS_state_MASK 0x1 +#define ACP_DSP1_CS_STATE__DSP1_CS_state__SHIFT 0x0 +#define ACP_DSP2_CS_STATE__DSP2_CS_state_MASK 0x1 +#define ACP_DSP2_CS_STATE__DSP2_CS_state__SHIFT 0x0 +#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR_MASK 0x7ffff +#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR__SHIFT 0x0 +#define CC_ACP_EFUSE__DSP0_DISABLE_MASK 0x2 +#define CC_ACP_EFUSE__DSP0_DISABLE__SHIFT 0x1 +#define CC_ACP_EFUSE__DSP1_DISABLE_MASK 0x4 +#define CC_ACP_EFUSE__DSP1_DISABLE__SHIFT 0x2 +#define CC_ACP_EFUSE__DSP2_DISABLE_MASK 0x8 +#define CC_ACP_EFUSE__DSP2_DISABLE__SHIFT 0x3 +#define CC_ACP_EFUSE__ACP_DISABLE_MASK 0x10 +#define CC_ACP_EFUSE__ACP_DISABLE__SHIFT 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF_MASK 0x1 +#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF__SHIFT 0x0 +#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF_MASK 0x2 +#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF__SHIFT 0x1 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF_MASK 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF__SHIFT 0x2 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF_MASK 0x8 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF__SHIFT 0x3 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF_MASK 0x10 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF__SHIFT 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF_MASK 0x20 +#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF__SHIFT 0x5 +#define ACP_PGFSM_CONFIG_REG__FSM_ADDR_MASK 0xff +#define ACP_PGFSM_CONFIG_REG__FSM_ADDR__SHIFT 0x0 +#define ACP_PGFSM_CONFIG_REG__Power_Down_MASK 0x100 +#define ACP_PGFSM_CONFIG_REG__Power_Down__SHIFT 0x8 +#define ACP_PGFSM_CONFIG_REG__Power_Up_MASK 0x200 +#define ACP_PGFSM_CONFIG_REG__Power_Up__SHIFT 0x9 +#define ACP_PGFSM_CONFIG_REG__P1_Select_MASK 0x400 +#define ACP_PGFSM_CONFIG_REG__P1_Select__SHIFT 0xa +#define ACP_PGFSM_CONFIG_REG__P2_Select_MASK 0x800 +#define ACP_PGFSM_CONFIG_REG__P2_Select__SHIFT 0xb +#define ACP_PGFSM_CONFIG_REG__Wr_MASK 0x1000 +#define ACP_PGFSM_CONFIG_REG__Wr__SHIFT 0xc +#define ACP_PGFSM_CONFIG_REG__Rd_MASK 0x2000 +#define ACP_PGFSM_CONFIG_REG__Rd__SHIFT 0xd +#define ACP_PGFSM_CONFIG_REG__RdData_Reset_MASK 0x4000 +#define ACP_PGFSM_CONFIG_REG__RdData_Reset__SHIFT 0xe +#define ACP_PGFSM_CONFIG_REG__Short_Format_MASK 0x8000 +#define ACP_PGFSM_CONFIG_REG__Short_Format__SHIFT 0xf +#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG_MASK 0x3ff0000 +#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG__SHIFT 0x10 +#define ACP_PGFSM_CONFIG_REG__SRBM_override_MASK 0x4000000 +#define ACP_PGFSM_CONFIG_REG__SRBM_override__SHIFT 0x1a +#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr_MASK 0x8000000 +#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr__SHIFT 0x1b +#define ACP_PGFSM_CONFIG_REG__REG_ADDR_MASK 0xf0000000 +#define ACP_PGFSM_CONFIG_REG__REG_ADDR__SHIFT 0x1c +#define ACP_PGFSM_WRITE_REG__Write_value_MASK 0xffffffff +#define ACP_PGFSM_WRITE_REG__Write_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_0__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_0__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_1__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_1__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_2__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_2__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_3__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_3__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_4__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_4__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_5__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_5__Read_value__SHIFT 0x0 +#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS_MASK 0x1 +#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS__SHIFT 0x0 +#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG_MASK 0x3 +#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG__SHIFT 0x0 +#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT_MASK 0x1 +#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT__SHIFT 0x0 +#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package_MASK 0x1 +#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package__SHIFT 0x0 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable_MASK 0x7ff +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable__SHIFT 0x0 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable_MASK 0x7ff0000 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable__SHIFT 0x10 +#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL_MASK 0x1 +#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL__SHIFT 0x0 +#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable_MASK 0x1 +#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable__SHIFT 0x0 +#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status_MASK 0x1 +#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples_MASK 0xffff +#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks_MASK 0xffff +#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en_MASK 0x1 +#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req_MASK 0x1 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack_MASK 0x2 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack__SHIFT 0x1 +#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid_MASK 0x1 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match_MASK 0x2 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match__SHIFT 0x1 +#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap_MASK 0x1 +#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap__SHIFT 0x0 +#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML_MASK 0xffffffff +#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH_MASK 0xffff +#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML_MASK 0xffffffff +#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH_MASK 0xffff +#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML_MASK 0xffffffff +#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH_MASK 0xffff +#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML_MASK 0xffffffff +#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH_MASK 0xffff +#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo_MASK 0xffffffff +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi_MASK 0xffff +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo_MASK 0xffffffff +#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi_MASK 0xffff +#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi__SHIFT 0x0 +#define ACP_I2SSP_IER__I2SSP_IEN_MASK 0x1 +#define ACP_I2SSP_IER__I2SSP_IEN__SHIFT 0x0 +#define ACP_I2SSP_IRER__I2SSP_RXEN_MASK 0x1 +#define ACP_I2SSP_IRER__I2SSP_RXEN__SHIFT 0x0 +#define ACP_I2SSP_ITER__I2SSP_TXEN_MASK 0x1 +#define ACP_I2SSP_ITER__I2SSP_TXEN__SHIFT 0x0 +#define ACP_I2SSP_CER__I2SSP_CLKEN_MASK 0x1 +#define ACP_I2SSP_CER__I2SSP_CLKEN__SHIFT 0x0 +#define ACP_I2SSP_CCR__I2SSP_SCLKG_MASK 0x7 +#define ACP_I2SSP_CCR__I2SSP_SCLKG__SHIFT 0x0 +#define ACP_I2SSP_CCR__I2SSP_WSS_MASK 0x18 +#define ACP_I2SSP_CCR__I2SSP_WSS__SHIFT 0x3 +#define ACP_I2SSP_RXFFR__I2SSP_RXFFR_MASK 0x1 +#define ACP_I2SSP_RXFFR__I2SSP_RXFFR__SHIFT 0x0 +#define ACP_I2SSP_TXFFR__I2SSP_TXFFR_MASK 0x1 +#define ACP_I2SSP_TXFFR__I2SSP_TXFFR__SHIFT 0x0 +#define ACP_I2SSP_LRBR0__I2SSP_LRBR0_MASK 0xffffffff +#define ACP_I2SSP_LRBR0__I2SSP_LRBR0__SHIFT 0x0 +#define ACP_I2SSP_RRBR0__I2SSP_RRBR0_MASK 0xffffffff +#define ACP_I2SSP_RRBR0__I2SSP_RRBR0__SHIFT 0x0 +#define ACP_I2SSP_RER0__I2SSP_RXCHEN0_MASK 0x1 +#define ACP_I2SSP_RER0__I2SSP_RXCHEN0__SHIFT 0x0 +#define ACP_I2SSP_TER0__I2SSP_TXCHEN0_MASK 0x1 +#define ACP_I2SSP_TER0__I2SSP_TXCHEN0__SHIFT 0x0 +#define ACP_I2SSP_RCR0__I2SSP_WLEN_MASK 0x7 +#define ACP_I2SSP_RCR0__I2SSP_WLEN__SHIFT 0x0 +#define ACP_I2SSP_TCR0__I2SSP_WLEN_MASK 0x7 +#define ACP_I2SSP_TCR0__I2SSP_WLEN__SHIFT 0x0 +#define ACP_I2SSP_ISR0__I2SSP_RXDA_MASK 0x1 +#define ACP_I2SSP_ISR0__I2SSP_RXDA__SHIFT 0x0 +#define ACP_I2SSP_ISR0__I2SSP_RXFO_MASK 0x2 +#define ACP_I2SSP_ISR0__I2SSP_RXFO__SHIFT 0x1 +#define ACP_I2SSP_ISR0__I2SSP_TXFE_MASK 0x10 +#define ACP_I2SSP_ISR0__I2SSP_TXFE__SHIFT 0x4 +#define ACP_I2SSP_ISR0__I2SSP_TXFO_MASK 0x20 +#define ACP_I2SSP_ISR0__I2SSP_TXFO__SHIFT 0x5 +#define ACP_I2SSP_IMR0__I2SSP_RXDAM_MASK 0x1 +#define ACP_I2SSP_IMR0__I2SSP_RXDAM__SHIFT 0x0 +#define ACP_I2SSP_IMR0__I2SSP_RXFOM_MASK 0x2 +#define ACP_I2SSP_IMR0__I2SSP_RXFOM__SHIFT 0x1 +#define ACP_I2SSP_IMR0__I2SSP_TXFEM_MASK 0x10 +#define ACP_I2SSP_IMR0__I2SSP_TXFEM__SHIFT 0x4 +#define ACP_I2SSP_IMR0__I2SSP_TXFOM_MASK 0x20 +#define ACP_I2SSP_IMR0__I2SSP_TXFOM__SHIFT 0x5 +#define ACP_I2SSP_ROR0__I2SSP_RXCHO_MASK 0x1 +#define ACP_I2SSP_ROR0__I2SSP_RXCHO__SHIFT 0x0 +#define ACP_I2SSP_TOR0__I2SSP_TXCHO_MASK 0x1 +#define ACP_I2SSP_TOR0__I2SSP_TXCHO__SHIFT 0x0 +#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT_MASK 0xf +#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SSP_TFCR0__I2SSP_TXCHET_MASK 0xf +#define ACP_I2SSP_TFCR0__I2SSP_TXCHET__SHIFT 0x0 +#define ACP_I2SSP_RFF0__I2SSP_RXCHFR_MASK 0x1 +#define ACP_I2SSP_RFF0__I2SSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SSP_TFF0__I2SSP_TXCHFR_MASK 0x1 +#define ACP_I2SSP_TFF0__I2SSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SSP_RXDMA__I2SSP_RXDMA_MASK 0xffffffff +#define ACP_I2SSP_RXDMA__I2SSP_RXDMA__SHIFT 0x0 +#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA_MASK 0x1 +#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA__SHIFT 0x0 +#define ACP_I2SSP_TXDMA__I2SSP_TXDMA_MASK 0xffffffff +#define ACP_I2SSP_TXDMA__I2SSP_TXDMA__SHIFT 0x0 +#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA_MASK 0x1 +#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN_MASK 0x10 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN__SHIFT 0x4 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES_MASK 0x180 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES_MASK 0x600 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE__SHIFT 0x0 +#define ACP_I2SMICSP_IER__I2SMICSP_IEN_MASK 0x1 +#define ACP_I2SMICSP_IER__I2SMICSP_IEN__SHIFT 0x0 +#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN_MASK 0x1 +#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN__SHIFT 0x0 +#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN_MASK 0x1 +#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN__SHIFT 0x0 +#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN_MASK 0x1 +#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN__SHIFT 0x0 +#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG_MASK 0x7 +#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG__SHIFT 0x0 +#define ACP_I2SMICSP_CCR__I2SMICSP_WSS_MASK 0x18 +#define ACP_I2SMICSP_CCR__I2SMICSP_WSS__SHIFT 0x3 +#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR_MASK 0x1 +#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR__SHIFT 0x0 +#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR_MASK 0x1 +#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR__SHIFT 0x0 +#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0_MASK 0xffffffff +#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0__SHIFT 0x0 +#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0_MASK 0xffffffff +#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0__SHIFT 0x0 +#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0_MASK 0x1 +#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0__SHIFT 0x0 +#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0_MASK 0x1 +#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0__SHIFT 0x0 +#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA_MASK 0x1 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA__SHIFT 0x0 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO_MASK 0x2 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO__SHIFT 0x1 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE_MASK 0x10 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE__SHIFT 0x4 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO_MASK 0x20 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO__SHIFT 0x5 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM_MASK 0x1 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM__SHIFT 0x0 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM_MASK 0x2 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM__SHIFT 0x1 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM_MASK 0x10 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM__SHIFT 0x4 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM_MASK 0x20 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM__SHIFT 0x5 +#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO_MASK 0x1 +#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO_MASK 0x1 +#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT_MASK 0xf +#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET_MASK 0xf +#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET__SHIFT 0x0 +#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR_MASK 0x1 +#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR_MASK 0x1 +#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1_MASK 0xffffffff +#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1__SHIFT 0x0 +#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1_MASK 0xffffffff +#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1__SHIFT 0x0 +#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1_MASK 0x1 +#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1__SHIFT 0x0 +#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1_MASK 0x1 +#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1__SHIFT 0x0 +#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA_MASK 0x1 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA__SHIFT 0x0 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO_MASK 0x2 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO__SHIFT 0x1 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE_MASK 0x10 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE__SHIFT 0x4 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO_MASK 0x20 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO__SHIFT 0x5 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK 0x1 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM__SHIFT 0x0 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK 0x2 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM__SHIFT 0x1 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM_MASK 0x10 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM__SHIFT 0x4 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM_MASK 0x20 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM__SHIFT 0x5 +#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO_MASK 0x1 +#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO_MASK 0x1 +#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT_MASK 0xf +#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET_MASK 0xf +#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET__SHIFT 0x0 +#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR_MASK 0x1 +#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR_MASK 0x1 +#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA_MASK 0xffffffff +#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA_MASK 0x1 +#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA_MASK 0xffffffff +#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA_MASK 0x1 +#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN_MASK 0x10 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN__SHIFT 0x4 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES_MASK 0x180 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES_MASK 0x600 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE__SHIFT 0x0 +#define ACP_I2SBT_IER__I2SBT_IEN_MASK 0x1 +#define ACP_I2SBT_IER__I2SBT_IEN__SHIFT 0x0 +#define ACP_I2SBT_IRER__I2SBT_RXEN_MASK 0x1 +#define ACP_I2SBT_IRER__I2SBT_RXEN__SHIFT 0x0 +#define ACP_I2SBT_ITER__I2SBT_TXEN_MASK 0x1 +#define ACP_I2SBT_ITER__I2SBT_TXEN__SHIFT 0x0 +#define ACP_I2SBT_CER__I2SBT_CLKEN_MASK 0x1 +#define ACP_I2SBT_CER__I2SBT_CLKEN__SHIFT 0x0 +#define ACP_I2SBT_CCR__I2SBT_SCLKG_MASK 0x7 +#define ACP_I2SBT_CCR__I2SBT_SCLKG__SHIFT 0x0 +#define ACP_I2SBT_CCR__I2SBT_WSS_MASK 0x18 +#define ACP_I2SBT_CCR__I2SBT_WSS__SHIFT 0x3 +#define ACP_I2SBT_RXFFR__I2SBT_RXFFR_MASK 0x1 +#define ACP_I2SBT_RXFFR__I2SBT_RXFFR__SHIFT 0x0 +#define ACP_I2SBT_TXFFR__I2SBT_TXFFR_MASK 0x1 +#define ACP_I2SBT_TXFFR__I2SBT_TXFFR__SHIFT 0x0 +#define ACP_I2SBT_LRBR0__I2SBT_LRBR0_MASK 0xffffffff +#define ACP_I2SBT_LRBR0__I2SBT_LRBR0__SHIFT 0x0 +#define ACP_I2SBT_RRBR0__I2SBT_RRBR0_MASK 0xffffffff +#define ACP_I2SBT_RRBR0__I2SBT_RRBR0__SHIFT 0x0 +#define ACP_I2SBT_RER0__I2SBT_RXCHEN0_MASK 0x1 +#define ACP_I2SBT_RER0__I2SBT_RXCHEN0__SHIFT 0x0 +#define ACP_I2SBT_TER0__I2SBT_TXCHEN0_MASK 0x1 +#define ACP_I2SBT_TER0__I2SBT_TXCHEN0__SHIFT 0x0 +#define ACP_I2SBT_RCR0__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_RCR0__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_TCR0__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_TCR0__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_ISR0__I2SBT_RXDA_MASK 0x1 +#define ACP_I2SBT_ISR0__I2SBT_RXDA__SHIFT 0x0 +#define ACP_I2SBT_ISR0__I2SBT_RXFO_MASK 0x2 +#define ACP_I2SBT_ISR0__I2SBT_RXFO__SHIFT 0x1 +#define ACP_I2SBT_ISR0__I2SBT_TXFE_MASK 0x10 +#define ACP_I2SBT_ISR0__I2SBT_TXFE__SHIFT 0x4 +#define ACP_I2SBT_ISR0__I2SBT_TXFO_MASK 0x20 +#define ACP_I2SBT_ISR0__I2SBT_TXFO__SHIFT 0x5 +#define ACP_I2SBT_IMR0__I2SBT_RXDAM_MASK 0x1 +#define ACP_I2SBT_IMR0__I2SBT_RXDAM__SHIFT 0x0 +#define ACP_I2SBT_IMR0__I2SBT_RXFOM_MASK 0x2 +#define ACP_I2SBT_IMR0__I2SBT_RXFOM__SHIFT 0x1 +#define ACP_I2SBT_IMR0__I2SBT_TXFEM_MASK 0x10 +#define ACP_I2SBT_IMR0__I2SBT_TXFEM__SHIFT 0x4 +#define ACP_I2SBT_IMR0__I2SBT_TXFOM_MASK 0x20 +#define ACP_I2SBT_IMR0__I2SBT_TXFOM__SHIFT 0x5 +#define ACP_I2SBT_ROR0__I2SBT_RXCHO_MASK 0x1 +#define ACP_I2SBT_ROR0__I2SBT_RXCHO__SHIFT 0x0 +#define ACP_I2SBT_TOR0__I2SBT_TXCHO_MASK 0x1 +#define ACP_I2SBT_TOR0__I2SBT_TXCHO__SHIFT 0x0 +#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT_MASK 0xf +#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT__SHIFT 0x0 +#define ACP_I2SBT_TFCR0__I2SBT_TXCHET_MASK 0xf +#define ACP_I2SBT_TFCR0__I2SBT_TXCHET__SHIFT 0x0 +#define ACP_I2SBT_RFF0__I2SBT_RXCHFR_MASK 0x1 +#define ACP_I2SBT_RFF0__I2SBT_RXCHFR__SHIFT 0x0 +#define ACP_I2SBT_TFF0__I2SBT_TXCHFR_MASK 0x1 +#define ACP_I2SBT_TFF0__I2SBT_TXCHFR__SHIFT 0x0 +#define ACP_I2SBT_LRBR1__I2SBT_LRBR1_MASK 0xffffffff +#define ACP_I2SBT_LRBR1__I2SBT_LRBR1__SHIFT 0x0 +#define ACP_I2SBT_RRBR1__I2SBT_RRBR1_MASK 0xffffffff +#define ACP_I2SBT_RRBR1__I2SBT_RRBR1__SHIFT 0x0 +#define ACP_I2SBT_RER1__I2SBT_RXCHEN1_MASK 0x1 +#define ACP_I2SBT_RER1__I2SBT_RXCHEN1__SHIFT 0x0 +#define ACP_I2SBT_TER1__I2SBT_TXCHEN1_MASK 0x1 +#define ACP_I2SBT_TER1__I2SBT_TXCHEN1__SHIFT 0x0 +#define ACP_I2SBT_RCR1__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_RCR1__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_TCR1__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_TCR1__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_ISR1__I2SBT_RXDA_MASK 0x1 +#define ACP_I2SBT_ISR1__I2SBT_RXDA__SHIFT 0x0 +#define ACP_I2SBT_ISR1__I2SBT_RXFO_MASK 0x2 +#define ACP_I2SBT_ISR1__I2SBT_RXFO__SHIFT 0x1 +#define ACP_I2SBT_ISR1__I2SBT_TXFE_MASK 0x10 +#define ACP_I2SBT_ISR1__I2SBT_TXFE__SHIFT 0x4 +#define ACP_I2SBT_ISR1__I2SBT_TXFO_MASK 0x20 +#define ACP_I2SBT_ISR1__I2SBT_TXFO__SHIFT 0x5 +#define ACP_I2SBT_IMR1__I2SBT_RXDAM_MASK 0x1 +#define ACP_I2SBT_IMR1__I2SBT_RXDAM__SHIFT 0x0 +#define ACP_I2SBT_IMR1__I2SBT_RXFOM_MASK 0x2 +#define ACP_I2SBT_IMR1__I2SBT_RXFOM__SHIFT 0x1 +#define ACP_I2SBT_IMR1__I2SBT_TXFEM_MASK 0x10 +#define ACP_I2SBT_IMR1__I2SBT_TXFEM__SHIFT 0x4 +#define ACP_I2SBT_IMR1__I2SBT_TXFOM_MASK 0x20 +#define ACP_I2SBT_IMR1__I2SBT_TXFOM__SHIFT 0x5 +#define ACP_I2SBT_ROR1__I2SBT_RXCHO_MASK 0x1 +#define ACP_I2SBT_ROR1__I2SBT_RXCHO__SHIFT 0x0 +#define ACP_I2SBT_TOR1__I2SBT_TXCHO_MASK 0x1 +#define ACP_I2SBT_TOR1__I2SBT_TXCHO__SHIFT 0x0 +#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT_MASK 0xf +#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT__SHIFT 0x0 +#define ACP_I2SBT_TFCR1__I2SBT_TXCHET_MASK 0xf +#define ACP_I2SBT_TFCR1__I2SBT_TXCHET__SHIFT 0x0 +#define ACP_I2SBT_RFF1__I2SBT_RXCHFR_MASK 0x1 +#define ACP_I2SBT_RFF1__I2SBT_RXCHFR__SHIFT 0x0 +#define ACP_I2SBT_TFF1__I2SBT_TXCHFR_MASK 0x1 +#define ACP_I2SBT_TFF1__I2SBT_TXCHFR__SHIFT 0x0 +#define ACP_I2SBT_RXDMA__I2SBT_RXDMA_MASK 0xffffffff +#define ACP_I2SBT_RXDMA__I2SBT_RXDMA__SHIFT 0x0 +#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA_MASK 0x1 +#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA__SHIFT 0x0 +#define ACP_I2SBT_TXDMA__I2SBT_TXDMA_MASK 0xffffffff +#define ACP_I2SBT_TXDMA__I2SBT_TXDMA__SHIFT 0x0 +#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA_MASK 0x1 +#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN_MASK 0x10 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN__SHIFT 0x4 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES_MASK 0x180 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES_MASK 0x600 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE__SHIFT 0x0 + +#endif /* ACP_2_2_SH_MASK_H */ -- cgit v1.2.3 From 7c31335a03b6afff1c474c693c3187f13b8587cc Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 8 Jan 2016 18:22:09 -0500 Subject: ASoC: AMD: add AMD ASoC ACP 2.x DMA driver ACP IP has internal DMA controller with multiple channels which can be programmed in cyclic/non cyclic manner. ACP can generate interrupt upon completion of DMA transfer, if required. The PCM driver provides the platform DMA component to ALSA core. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Reviewed-by: Murali Krishna Vemuri Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/amd/Kconfig | 4 + sound/soc/amd/Makefile | 3 + sound/soc/amd/acp-pcm-dma.c | 914 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/amd/acp.h | 118 ++++++ 6 files changed, 1041 insertions(+) create mode 100644 sound/soc/amd/Kconfig create mode 100644 sound/soc/amd/Makefile create mode 100644 sound/soc/amd/acp-pcm-dma.c create mode 100644 sound/soc/amd/acp.h (limited to 'sound') diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 7ff7d88e46dd..a34e9e9fb28c 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -38,6 +38,7 @@ config SND_SOC_TOPOLOGY # All the supported SoCs source "sound/soc/adi/Kconfig" +source "sound/soc/amd/Kconfig" source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/bcm/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 8eb06db32fa0..a79a4c735679 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ obj-$(CONFIG_SND_SOC) += adi/ +obj-$(CONFIG_SND_SOC) += amd/ obj-$(CONFIG_SND_SOC) += atmel/ obj-$(CONFIG_SND_SOC) += au1x/ obj-$(CONFIG_SND_SOC) += bcm/ diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig new file mode 100644 index 000000000000..78187eb24f56 --- /dev/null +++ b/sound/soc/amd/Kconfig @@ -0,0 +1,4 @@ +config SND_SOC_AMD_ACP + tristate "AMD Audio Coprocessor support" + help + This option enables ACP DMA support on AMD platform. diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile new file mode 100644 index 000000000000..1a66ec0366b2 --- /dev/null +++ b/sound/soc/amd/Makefile @@ -0,0 +1,3 @@ +snd-soc-acp-pcm-objs := acp-pcm-dma.o + +obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c new file mode 100644 index 000000000000..0724d7847c07 --- /dev/null +++ b/sound/soc/amd/acp-pcm-dma.c @@ -0,0 +1,914 @@ +/* + * AMD ALSA SoC PCM Driver for ACP 2.x + * + * Copyright 2014-2015 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include + +#include + +#include "acp.h" + +#define PLAYBACK_MIN_NUM_PERIODS 2 +#define PLAYBACK_MAX_NUM_PERIODS 2 +#define PLAYBACK_MAX_PERIOD_SIZE 16384 +#define PLAYBACK_MIN_PERIOD_SIZE 1024 +#define CAPTURE_MIN_NUM_PERIODS 2 +#define CAPTURE_MAX_NUM_PERIODS 2 +#define CAPTURE_MAX_PERIOD_SIZE 16384 +#define CAPTURE_MIN_PERIOD_SIZE 1024 + +#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) +#define MIN_BUFFER MAX_BUFFER + +static const struct snd_pcm_hardware acp_pcm_hardware_playback = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .rate_min = 8000, + .rate_max = 96000, + .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, + .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, + .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, + .periods_min = PLAYBACK_MIN_NUM_PERIODS, + .periods_max = PLAYBACK_MAX_NUM_PERIODS, +}; + +static const struct snd_pcm_hardware acp_pcm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, + .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, + .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, + .periods_min = CAPTURE_MIN_NUM_PERIODS, + .periods_max = CAPTURE_MAX_NUM_PERIODS, +}; + +struct audio_drv_data { + struct snd_pcm_substream *play_stream; + struct snd_pcm_substream *capture_stream; + void __iomem *acp_mmio; +}; + +static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg) +{ + return readl(acp_mmio + (reg * 4)); +} + +static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg) +{ + writel(val, acp_mmio + (reg * 4)); +} + +/* Configure a given dma channel parameters - enable/disble, + * number of descriptors, priority + */ +static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num, + u16 dscr_strt_idx, u16 num_dscrs, + enum acp_dma_priority_level priority_level) +{ + u32 dma_ctrl; + + /* disable the channel run field */ + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* program a DMA channel with first descriptor to be processed. */ + acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK + & dscr_strt_idx), + acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num); + + /* program a DMA channel with the number of descriptors to be + * processed in the transfer + */ + acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs, + acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num); + + /* set DMA channel priority */ + acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num); +} + +/* Initialize a dma descriptor in SRAM based on descritor information passed */ +static void config_dma_descriptor_in_sram(void __iomem *acp_mmio, + u16 descr_idx, + acp_dma_dscr_transfer_t *descr_info) +{ + u32 sram_offset; + + sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t)); + + /* program the source base address. */ + acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->src, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + /* program the destination base address. */ + acp_reg_write(sram_offset + 4, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* program the number of bytes to be transferred for this descriptor. */ + acp_reg_write(sram_offset + 8, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data); +} + +/* Initialize the DMA descriptor information for transfer between + * system memory <-> ACP SRAM + */ +static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio, + u32 size, int direction, + u32 pte_offset) +{ + u16 i; + u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; + acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; + + for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { + dmadscr[i].xfer_val = 0; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i; + dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS + + (size / 2) - (i * (size/2)); + dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS + + (pte_offset * SZ_4K) + (i * (size/2)); + dmadscr[i].xfer_val |= + (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) | + (size / 2); + } else { + dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i; + dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS + + (i * (size/2)); + dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS + + (pte_offset * SZ_4K) + + (i * (size/2)); + dmadscr[i].xfer_val |= + BIT(22) | + (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) | + (size / 2); + } + config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, + &dmadscr[i]); + } + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); + else + config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, + CAPTURE_START_DMA_DESCR_CH14, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); +} + +/* Initialize the DMA descriptor information for transfer between + * ACP SRAM <-> I2S + */ +static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, + u32 size, int direction) +{ + + u16 i; + u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13; + acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; + + for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { + dmadscr[i].xfer_val = 0; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i; + dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS + + (i * (size/2)); + /* dmadscr[i].dest is unused by hardware. */ + dmadscr[i].dest = 0; + dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) | + (size / 2); + } else { + dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i; + /* dmadscr[i].src is unused by hardware. */ + dmadscr[i].src = 0; + dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS + + (i * (size / 2)); + dmadscr[i].xfer_val |= BIT(22) | + (FROM_ACP_I2S_1 << 16) | (size / 2); + } + config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, + &dmadscr[i]); + } + /* Configure the DMA channel with the above descriptore */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH13, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); + else + config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM, + CAPTURE_START_DMA_DESCR_CH15, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); +} + +/* Create page table entries in ACP SRAM for the allocated memory */ +static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, + u16 num_of_pages, u32 pte_offset) +{ + u16 page_idx; + u64 addr; + u32 low; + u32 high; + u32 offset; + + offset = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8); + for (page_idx = 0; page_idx < (num_of_pages); page_idx++) { + /* Load the low address of page int ACP SRAM through SRBM */ + acp_reg_write((offset + (page_idx * 8)), + acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + addr = page_to_phys(pg); + + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* Load the High address of page int ACP SRAM through SRBM */ + acp_reg_write((offset + (page_idx * 8) + 4), + acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + + /* page enable in ACP */ + high |= BIT(31); + acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* Move to next physically contiguos page */ + pg++; + } +} + +static void config_acp_dma(void __iomem *acp_mmio, + struct audio_substream_data *audio_config) +{ + u32 pte_offset; + + if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) + pte_offset = ACP_PLAYBACK_PTE_OFFSET; + else + pte_offset = ACP_CAPTURE_PTE_OFFSET; + + acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages, + pte_offset); + + /* Configure System memory <-> ACP SRAM DMA descriptors */ + set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size, + audio_config->direction, pte_offset); + + /* Configure ACP SRAM <-> I2S DMA descriptors */ + set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size, + audio_config->direction); +} + +/* Start a given DMA channel transfer */ +static void acp_dma_start(void __iomem *acp_mmio, + u16 ch_num, bool is_circular) +{ + u32 dma_ctrl; + + /* read the dma control register and disable the channel run field */ + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* Invalidating the DAGB cache */ + acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL); + + /* configure the DMA channel and start the DMA transfer + * set dmachrun bit to start the transfer and enable the + * interrupt on completion of the dma transfer + */ + dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK; + + switch (ch_num) { + case ACP_TO_I2S_DMA_CH_NUM: + case ACP_TO_SYSRAM_CH_NUM: + case I2S_TO_ACP_DMA_CH_NUM: + dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + break; + default: + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + break; + } + + /* enable for ACP SRAM to/from I2S DMA channel */ + if (is_circular == true) + dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK; + else + dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); +} + +/* Stop a given DMA channel transfer */ +static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num) +{ + u32 dma_ctrl; + u32 dma_ch_sts; + u32 count = ACP_DMA_RESET_TIME; + + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* clear the dma control register fields before writing zero + * in reset bit + */ + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); + + if (dma_ch_sts & BIT(ch_num)) { + /* set the reset bit for this channel to stop the dma + * transfer + */ + dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK; + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + } + + /* check the channel status bit for some time and return the status */ + while (true) { + dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); + if (!(dma_ch_sts & BIT(ch_num))) { + /* clear the reset flag after successfully stopping + * the dma transfer and break from the loop + */ + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + + ch_num); + break; + } + if (--count == 0) { + pr_err("Failed to stop ACP DMA channel : %d\n", ch_num); + return -ETIMEDOUT; + } + udelay(100); + } + return 0; +} + +/* Initialize and bring ACP hardware to default state. */ +static int acp_init(void __iomem *acp_mmio) +{ + u32 val, count, sram_pte_offset; + + /* Assert Soft reset of ACP */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + + val |= ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; + while (true) { + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + if (ACP_SOFT_RESET__SoftResetAudDone_MASK == + (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + + /* Enable clock to ACP and wait until the clock is enabled */ + val = acp_reg_read(acp_mmio, mmACP_CONTROL); + val = val | ACP_CONTROL__ClkEn_MASK; + acp_reg_write(val, acp_mmio, mmACP_CONTROL); + + count = ACP_CLOCK_EN_TIME_OUT_VALUE; + + while (true) { + val = acp_reg_read(acp_mmio, mmACP_STATUS); + if (val & (u32) 0x1) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + + /* Deassert the SOFT RESET flags */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + val &= ~ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + /* initiailize Onion control DAGB register */ + acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio, + mmACP_AXI2DAGB_ONION_CNTL); + + /* initiailize Garlic control DAGB registers */ + acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio, + mmACP_AXI2DAGB_GARLIC_CNTL); + + sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK; + acp_reg_write(sram_pte_offset, acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1); + acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio, + mmACP_DAGB_PAGE_SIZE_GRP_1); + + acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio, + mmACP_DMA_DESC_BASE_ADDR); + + /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */ + acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR); + acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK, + acp_mmio, mmACP_EXTERNAL_INTR_CNTL); + + return 0; +} + +/* Deintialize ACP */ +static int acp_deinit(void __iomem *acp_mmio) +{ + u32 val; + u32 count; + + /* Assert Soft reset of ACP */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + + val |= ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; + while (true) { + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + if (ACP_SOFT_RESET__SoftResetAudDone_MASK == + (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + /** Disable ACP clock */ + val = acp_reg_read(acp_mmio, mmACP_CONTROL); + val &= ~ACP_CONTROL__ClkEn_MASK; + acp_reg_write(val, acp_mmio, mmACP_CONTROL); + + count = ACP_CLOCK_EN_TIME_OUT_VALUE; + + while (true) { + val = acp_reg_read(acp_mmio, mmACP_STATUS); + if (!(val & (u32) 0x1)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + return 0; +} + +/* ACP DMA irq handler routine for playback, capture usecases */ +static irqreturn_t dma_irq_handler(int irq, void *arg) +{ + u16 dscr_idx; + u32 intr_flag, ext_intr_status; + struct audio_drv_data *irq_data; + void __iomem *acp_mmio; + struct device *dev = arg; + bool valid_irq = false; + + irq_data = dev_get_drvdata(dev); + acp_mmio = irq_data->acp_mmio; + + ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT); + intr_flag = (((ext_intr_status & + ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >> + ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT)); + + if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) { + valid_irq = true; + if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) == + PLAYBACK_START_DMA_DESCR_CH13) + dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; + else + dscr_idx = PLAYBACK_END_DMA_DESCR_CH12; + config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx, + 1, 0); + acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); + + snd_pcm_period_elapsed(irq_data->play_stream); + + acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) { + valid_irq = true; + if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) == + CAPTURE_START_DMA_DESCR_CH15) + dscr_idx = CAPTURE_END_DMA_DESCR_CH14; + else + dscr_idx = CAPTURE_START_DMA_DESCR_CH14; + config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx, + 1, 0); + acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false); + + acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) { + valid_irq = true; + snd_pcm_period_elapsed(irq_data->capture_stream); + acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if (valid_irq) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + +static int acp_dma_open(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev); + + struct audio_substream_data *adata = + kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); + if (adata == NULL) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = acp_pcm_hardware_playback; + else + runtime->hw = acp_pcm_hardware_capture; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(prtd->platform->dev, "set integer constraint failed\n"); + return ret; + } + + adata->acp_mmio = intr_data->acp_mmio; + runtime->private_data = adata; + + /* Enable ACP irq, when neither playback or capture streams are + * active by the time when a new stream is being opened. + * This enablement is not required for another stream, if current + * stream is not closed + */ + if (!intr_data->play_stream && !intr_data->capture_stream) + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + intr_data->play_stream = substream; + else + intr_data->capture_stream = substream; + + return 0; +} + +static int acp_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int status; + uint64_t size; + struct snd_dma_buffer *dma_buffer; + struct page *pg; + struct snd_pcm_runtime *runtime; + struct audio_substream_data *rtd; + + dma_buffer = &substream->dma_buffer; + + runtime = substream->runtime; + rtd = runtime->private_data; + + if (WARN_ON(!rtd)) + return -EINVAL; + + size = params_buffer_bytes(params); + status = snd_pcm_lib_malloc_pages(substream, size); + if (status < 0) + return status; + + memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); + pg = virt_to_page(substream->dma_buffer.area); + + if (pg != NULL) { + /* Save for runtime private data */ + rtd->pg = pg; + rtd->order = get_order(size); + + /* Fill the page table entries in ACP SRAM */ + rtd->pg = pg; + rtd->size = size; + rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + rtd->direction = substream->stream; + + config_acp_dma(rtd->acp_mmio, rtd); + status = 0; + } else { + status = -ENOMEM; + } + return status; +} + +static int acp_dma_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) +{ + u16 dscr; + u32 mul, dma_config, period_bytes; + u32 pos = 0; + + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + + period_bytes = frames_to_bytes(runtime, runtime->period_size); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13); + + if (dscr == PLAYBACK_START_DMA_DESCR_CH13) + mul = 0; + else + mul = 1; + pos = (mul * period_bytes); + } else { + dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14); + if (dma_config != 0) { + dscr = acp_reg_read(rtd->acp_mmio, + mmACP_DMA_CUR_DSCR_14); + if (dscr == CAPTURE_START_DMA_DESCR_CH14) + mul = 1; + else + mul = 2; + pos = (mul * period_bytes); + } + + if (pos >= (2 * period_bytes)) + pos = 0; + + } + return bytes_to_frames(runtime, pos); +} + +static int acp_dma_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return snd_pcm_lib_default_mmap(substream, vma); +} + +static int acp_dma_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + NUM_DSCRS_PER_CHANNEL, 0); + config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH13, + NUM_DSCRS_PER_CHANNEL, 0); + /* Fill ACP SRAM (2 periods) with zeros from System RAM + * which is zero-ed in hw_params + */ + acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); + + /* ACP SRAM (2 periods of buffer size) is intially filled with + * zeros. Before rendering starts, 2nd half of SRAM will be + * filled with valid audio data DMA'ed from first half of system + * RAM and 1st half of SRAM will be filled with Zeros. This is + * the initial scenario when redering starts from SRAM. Later + * on, 2nd half of system memory will be DMA'ed to 1st half of + * SRAM, 1st half of system memory will be DMA'ed to 2nd half of + * SRAM in ping-pong way till rendering stops. + */ + config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + 1, 0); + } else { + config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM, + CAPTURE_START_DMA_DESCR_CH14, + NUM_DSCRS_PER_CHANNEL, 0); + config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM, + CAPTURE_START_DMA_DESCR_CH15, + NUM_DSCRS_PER_CHANNEL, 0); + } + return 0; +} + +static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret; + u32 loops = 1000; + + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_substream_data *rtd = runtime->private_data; + + if (!rtd) + return -EINVAL; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + acp_dma_start(rtd->acp_mmio, + SYSRAM_TO_ACP_CH_NUM, false); + while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) & + BIT(SYSRAM_TO_ACP_CH_NUM)) { + if (!loops--) { + dev_err(prtd->platform->dev, + "acp dma start timeout\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + acp_dma_start(rtd->acp_mmio, + ACP_TO_I2S_DMA_CH_NUM, true); + + } else { + acp_dma_start(rtd->acp_mmio, + I2S_TO_ACP_DMA_CH_NUM, true); + } + ret = 0; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* Need to stop only circular DMA channels : + * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular + * channels will stopped automatically after its transfer + * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = acp_dma_stop(rtd->acp_mmio, + ACP_TO_I2S_DMA_CH_NUM); + else + ret = acp_dma_stop(rtd->acp_mmio, + I2S_TO_ACP_DMA_CH_NUM); + break; + default: + ret = -EINVAL; + + } + return ret; +} + +static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) +{ + return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, + NULL, MIN_BUFFER, + MAX_BUFFER); +} + +static int acp_dma_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev); + + kfree(rtd); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + adata->play_stream = NULL; + else + adata->capture_stream = NULL; + + /* Disable ACP irq, when the current stream is being closed and + * another stream is also not active. + */ + if (!adata->play_stream && !adata->capture_stream) + acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + + return 0; +} + +static struct snd_pcm_ops acp_dma_ops = { + .open = acp_dma_open, + .close = acp_dma_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = acp_dma_hw_params, + .hw_free = acp_dma_hw_free, + .trigger = acp_dma_trigger, + .pointer = acp_dma_pointer, + .mmap = acp_dma_mmap, + .prepare = acp_dma_prepare, +}; + +static struct snd_soc_platform_driver acp_asoc_platform = { + .ops = &acp_dma_ops, + .pcm_new = acp_dma_new, +}; + +static int acp_audio_probe(struct platform_device *pdev) +{ + int status; + struct audio_drv_data *audio_drv_data; + struct resource *res; + + audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data), + GFP_KERNEL); + if (audio_drv_data == NULL) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); + + /* The following members gets populated in device 'open' + * function. Till then interrupts are disabled in 'acp_init' + * and device doesn't generate any interrupts. + */ + + audio_drv_data->play_stream = NULL; + audio_drv_data->capture_stream = NULL; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); + return -ENODEV; + } + + status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler, + 0, "ACP_IRQ", &pdev->dev); + if (status) { + dev_err(&pdev->dev, "ACP IRQ request failed\n"); + return status; + } + + dev_set_drvdata(&pdev->dev, audio_drv_data); + + /* Initialize the ACP */ + acp_init(audio_drv_data->acp_mmio); + + status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform); + if (status != 0) { + dev_err(&pdev->dev, "Fail to register ALSA platform device\n"); + return status; + } + + return status; +} + +static int acp_audio_remove(struct platform_device *pdev) +{ + struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev); + + acp_deinit(adata->acp_mmio); + snd_soc_unregister_platform(&pdev->dev); + + return 0; +} + +static struct platform_driver acp_dma_driver = { + .probe = acp_audio_probe, + .remove = acp_audio_remove, + .driver = { + .name = "acp_audio_dma", + }, +}; + +module_platform_driver(acp_dma_driver); + +MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); +MODULE_DESCRIPTION("AMD ACP PCM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:acp-dma-audio"); diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h new file mode 100644 index 000000000000..330832ef4e5e --- /dev/null +++ b/sound/soc/amd/acp.h @@ -0,0 +1,118 @@ +#ifndef __ACP_HW_H +#define __ACP_HW_H + +#include "include/acp_2_2_d.h" +#include "include/acp_2_2_sh_mask.h" + +#define ACP_PAGE_SIZE_4K_ENABLE 0x02 + +#define ACP_PLAYBACK_PTE_OFFSET 10 +#define ACP_CAPTURE_PTE_OFFSET 0 + +#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4 +#define ACP_ONION_CNTL_DEFAULT 0x00000FB4 + +#define ACP_PHYSICAL_BASE 0x14000 + +/* Playback SRAM address (as a destination in dma descriptor) */ +#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000 + +/* Capture SRAM address (as a source in dma descriptor) */ +#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000 + +#define ACP_DMA_RESET_TIME 10000 +#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF +#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF +#define ACP_DMA_COMPLETE_TIME_OUT_VALUE 0x000000FF + +#define ACP_SRAM_BASE_ADDRESS 0x4000000 +#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS 0x4001000 +#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET 0x1000 +#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000 +#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000 + +#define TO_ACP_I2S_1 0x2 +#define TO_ACP_I2S_2 0x4 +#define FROM_ACP_I2S_1 0xa +#define FROM_ACP_I2S_2 0xb + +#define ACP_TILE_ON_MASK 0x03 +#define ACP_TILE_OFF_MASK 0x02 +#define ACP_TILE_ON_RETAIN_REG_MASK 0x1f +#define ACP_TILE_OFF_RETAIN_REG_MASK 0x20 + +#define ACP_TILE_P1_MASK 0x3e +#define ACP_TILE_P2_MASK 0x3d +#define ACP_TILE_DSP0_MASK 0x3b +#define ACP_TILE_DSP1_MASK 0x37 + +#define ACP_TILE_DSP2_MASK 0x2f +/* Playback DMA channels */ +#define SYSRAM_TO_ACP_CH_NUM 12 +#define ACP_TO_I2S_DMA_CH_NUM 13 + +/* Capture DMA channels */ +#define ACP_TO_SYSRAM_CH_NUM 14 +#define I2S_TO_ACP_DMA_CH_NUM 15 + +#define NUM_DSCRS_PER_CHANNEL 2 + +#define PLAYBACK_START_DMA_DESCR_CH12 0 +#define PLAYBACK_END_DMA_DESCR_CH12 1 +#define PLAYBACK_START_DMA_DESCR_CH13 2 +#define PLAYBACK_END_DMA_DESCR_CH13 3 + +#define CAPTURE_START_DMA_DESCR_CH14 4 +#define CAPTURE_END_DMA_DESCR_CH14 5 +#define CAPTURE_START_DMA_DESCR_CH15 6 +#define CAPTURE_END_DMA_DESCR_CH15 7 + +enum acp_dma_priority_level { + /* 0x0 Specifies the DMA channel is given normal priority */ + ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0, + /* 0x1 Specifies the DMA channel is given high priority */ + ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1, + ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF +}; + +struct audio_substream_data { + struct page *pg; + unsigned int order; + u16 num_of_pages; + u16 direction; + uint64_t size; + void __iomem *acp_mmio; +}; + +enum { + ACP_TILE_P1 = 0, + ACP_TILE_P2, + ACP_TILE_DSP0, + ACP_TILE_DSP1, + ACP_TILE_DSP2, +}; + +enum { + ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0, + ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1, + ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8, + ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9, + ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF +}; + +typedef struct acp_dma_dscr_transfer { + /* Specifies the source memory location for the DMA data transfer. */ + u32 src; + /* Specifies the destination memory location to where the data will + * be transferred. + */ + u32 dest; + /* Specifies the number of bytes need to be transferred + * from source to destination memory.Transfer direction & IOC enable + */ + u32 xfer_val; + /* Reserved for future use */ + u32 reserved; +} acp_dma_dscr_transfer_t; + +#endif /*__ACP_HW_H */ -- cgit v1.2.3 From 1927da9355670d04889ce57716bbc671fdca4135 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 8 Jan 2016 18:22:10 -0500 Subject: ASoC: AMD: add pm ops genpd will power off/on ACP to manage runtime ACP PM. ACP runtime PM hooks are added to get it deinitialized and initialized respectively, after it is powered off/on. When system goes to suspend when audio usecase is active, ACP will be powered off through genpd. When it resumes, ACP needs to be initialized and reconfigured. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'sound') diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 0724d7847c07..c0819b5f8ba5 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -885,6 +886,10 @@ static int acp_audio_probe(struct platform_device *pdev) return status; } + pm_runtime_set_autosuspend_delay(&pdev->dev, 10000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return status; } @@ -894,15 +899,58 @@ static int acp_audio_remove(struct platform_device *pdev) acp_deinit(adata->acp_mmio); snd_soc_unregister_platform(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } +static int acp_pcm_resume(struct device *dev) +{ + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_init(adata->acp_mmio); + + if (adata->play_stream && adata->play_stream->runtime) + config_acp_dma(adata->acp_mmio, + adata->play_stream->runtime->private_data); + if (adata->capture_stream && adata->capture_stream->runtime) + config_acp_dma(adata->acp_mmio, + adata->capture_stream->runtime->private_data); + + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static int acp_pcm_runtime_suspend(struct device *dev) +{ + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_deinit(adata->acp_mmio); + acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static int acp_pcm_runtime_resume(struct device *dev) +{ + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_init(adata->acp_mmio); + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static const struct dev_pm_ops acp_pm_ops = { + .resume = acp_pcm_resume, + .runtime_suspend = acp_pcm_runtime_suspend, + .runtime_resume = acp_pcm_runtime_resume, +}; + static struct platform_driver acp_dma_driver = { .probe = acp_audio_probe, .remove = acp_audio_remove, .driver = { .name = "acp_audio_dma", + .pm = &acp_pm_ops, }, }; -- cgit v1.2.3 From c36d9b3f6de7c6aefed5fdf6ad752773bdafa60c Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 8 Jan 2016 18:22:11 -0500 Subject: ASoC: AMD: Manage ACP 2.x SRAM banks power ACP SRAM banks gets turned on when ACP is powered on. Not all banks are used for playback/capture. So, power on required banks during audio device open and power off during audio device close. Signed-off-by: Maruthi Bayyavarapu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 94 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index c0819b5f8ba5..cc8b841b69b6 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -376,9 +376,57 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num) return 0; } +static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank, + bool power_on) +{ + u32 val, req_reg, sts_reg, sts_reg_mask; + u32 loops = 1000; + + if (bank < 32) { + req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO; + sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO; + sts_reg_mask = 0xFFFFFFFF; + + } else { + bank -= 32; + req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI; + sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI; + sts_reg_mask = 0x0000FFFF; + } + + val = acp_reg_read(acp_mmio, req_reg); + if (val & (1 << bank)) { + /* bank is in off state */ + if (power_on == true) + /* request to on */ + val &= ~(1 << bank); + else + /* request to off */ + return; + } else { + /* bank is in on state */ + if (power_on == false) + /* request to off */ + val |= 1 << bank; + else + /* request to on */ + return; + } + acp_reg_write(val, acp_mmio, req_reg); + + while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) { + if (!loops--) { + pr_err("ACP SRAM bank %d state change failed\n", bank); + break; + } + cpu_relax(); + } +} + /* Initialize and bring ACP hardware to default state. */ static int acp_init(void __iomem *acp_mmio) { + u16 bank; u32 val, count, sram_pte_offset; /* Assert Soft reset of ACP */ @@ -447,6 +495,13 @@ static int acp_init(void __iomem *acp_mmio) acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK, acp_mmio, mmACP_EXTERNAL_INTR_CNTL); + /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on. + * Now, turn off all of them. This can't be done in 'poweron' of + * ACP pm domain, as this requires ACP to be initialized. + */ + for (bank = 1; bank < 48; bank++) + acp_set_sram_bank_state(acp_mmio, bank, false); + return 0; } @@ -559,6 +614,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg) static int acp_dma_open(struct snd_pcm_substream *substream) { + u16 bank; int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *prtd = substream->private_data; @@ -592,10 +648,17 @@ static int acp_dma_open(struct snd_pcm_substream *substream) if (!intr_data->play_stream && !intr_data->capture_stream) acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { intr_data->play_stream = substream; - else + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(intr_data->acp_mmio, bank, + true); + } else { intr_data->capture_stream = substream; + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(intr_data->acp_mmio, bank, + true); + } return 0; } @@ -627,6 +690,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, pg = virt_to_page(substream->dma_buffer.area); if (pg != NULL) { + acp_set_sram_bank_state(rtd->acp_mmio, 0, true); /* Save for runtime private data */ rtd->pg = pg; rtd->order = get_order(size); @@ -802,6 +866,7 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) static int acp_dma_close(struct snd_pcm_substream *substream) { + u16 bank; struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; struct snd_soc_pcm_runtime *prtd = substream->private_data; @@ -809,10 +874,17 @@ static int acp_dma_close(struct snd_pcm_substream *substream) kfree(rtd); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { adata->play_stream = NULL; - else + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + false); + } else { adata->capture_stream = NULL; + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + false); + } /* Disable ACP irq, when the current stream is being closed and * another stream is also not active. @@ -906,17 +978,25 @@ static int acp_audio_remove(struct platform_device *pdev) static int acp_pcm_resume(struct device *dev) { + u16 bank; struct audio_drv_data *adata = dev_get_drvdata(dev); acp_init(adata->acp_mmio); - if (adata->play_stream && adata->play_stream->runtime) + if (adata->play_stream && adata->play_stream->runtime) { + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + true); config_acp_dma(adata->acp_mmio, adata->play_stream->runtime->private_data); - if (adata->capture_stream && adata->capture_stream->runtime) + } + if (adata->capture_stream && adata->capture_stream->runtime) { + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + true); config_acp_dma(adata->acp_mmio, adata->capture_stream->runtime->private_data); - + } acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); return 0; } -- cgit v1.2.3 From 7905f08247131ac5d5c0e2f057e0cf19da40e5da Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Sat, 9 Jan 2016 09:25:53 +0000 Subject: ASoC: bcm2835: cleanup includes by ordering them alphabetically Cleanup of includes so that they are ordered alphabetically. Signed-off-by: Martin Sperl Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 8c435beb263d..3303d5f58082 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -31,20 +31,20 @@ * General Public License for more details. */ +#include +#include +#include #include +#include #include -#include #include -#include -#include -#include #include +#include +#include #include #include -#include #include -#include /* Clock registers */ #define BCM2835_CLK_PCMCTL_REG 0x00 -- cgit v1.2.3 From f2ed6b07645ed29c1e090ead2e41066385cba3ea Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 6 Jan 2016 13:29:31 +0800 Subject: ASoC: Make aux_dev more like a generic component aux_dev is mainly used by the machine driver to specify analog devices, which are registered as codecs. Making it more like a generic component can help the machine driver to use it to specify any component with topology info by name. Details: - Remove the stub 'rtd_aux' array from the soc card. - Add a list 'aux_comp_list' to store the components of aux_devs. And add a list head 'list_aux' to struct snd_soc_component, for adding such components to the above list. - Add a 'init' ops to a component for machine specific init. soc_bind_aux_dev() will set it to be aux_dev's init. And it will be called when probing the component. - soc_bind_aux_dev() will also search components by name of an aux_dev, since it may not be a codec. - Move probing of aux_devs before checking new DAI links brought by topology. - Move removal of aux_devs later than removal of links. Because topology of aux components may register DAIs and the DAI drivers will go with removal of the aux components, we want soc_remove_link_dais() to remove the DAIs at first. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 8 ++- sound/soc/soc-core.c | 146 +++++++++++++++++++++++++++------------------------ 2 files changed, 83 insertions(+), 71 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 9d1383e8d039..5bc5def6af02 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -787,6 +787,7 @@ struct snd_soc_component { unsigned int registered_as_component:1; struct list_head list; + struct list_head list_aux; /* for auxiliary component of the card */ struct snd_soc_dai_driver *dai_drv; int num_dai; @@ -830,6 +831,9 @@ struct snd_soc_component { int (*probe)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *); + /* machine specific init */ + int (*init)(struct snd_soc_component *component); + #ifdef CONFIG_DEBUG_FS void (*init_debugfs)(struct snd_soc_component *component); const char *debugfs_prefix; @@ -1130,8 +1134,7 @@ struct snd_soc_card { */ struct snd_soc_aux_dev *aux_dev; int num_aux_devs; - struct snd_soc_pcm_runtime *rtd_aux; - int num_aux_rtd; + struct list_head aux_comp_list; const struct snd_kcontrol_new *controls; int num_controls; @@ -1537,6 +1540,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->dapm_list); + INIT_LIST_HEAD(&card->aux_comp_list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c572673a5a24..c10bd668659c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1413,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card, component->name); } + /* machine specific init */ + if (component->init) { + ret = component->init(component); + if (ret < 0) { + dev_err(component->dev, + "Failed to do machine specific init %d\n", ret); + goto err_probe; + } + } + if (component->controls) snd_soc_add_component_controls(component, component->controls, component->num_controls); @@ -1657,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *name = aux_dev->codec_name; - - rtd->component = soc_find_component(aux_dev->codec_of_node, name); - if (!rtd->component) { - if (aux_dev->codec_of_node) - name = of_node_full_name(aux_dev->codec_of_node); - - dev_err(card->dev, "ASoC: %s not registered\n", name); - return -EPROBE_DEFER; + struct snd_soc_component *component; + const char *name; + struct device_node *codec_of_node; + + if (aux_dev->codec_of_node || aux_dev->codec_name) { + /* codecs, usually analog devices */ + name = aux_dev->codec_name; + codec_of_node = aux_dev->codec_of_node; + component = soc_find_component(codec_of_node, name); + if (!component) { + if (codec_of_node) + name = of_node_full_name(codec_of_node); + goto err_defer; + } + } else if (aux_dev->name) { + /* generic components */ + name = aux_dev->name; + component = soc_find_component(NULL, name); + if (!component) + goto err_defer; + } else { + dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); + return -EINVAL; } - /* - * Some places still reference rtd->codec, so we have to keep that - * initialized if the component is a CODEC. Once all those references - * have been removed, this code can be removed as well. - */ - rtd->codec = rtd->component->codec; - + component->init = aux_dev->init; + list_add(&component->list_aux, &card->aux_comp_list); return 0; + +err_defer: + dev_err(card->dev, "ASoC: %s not registered\n", name); + return -EPROBE_DEFER; } -static int soc_probe_aux_dev(struct snd_soc_card *card, int num) +static int soc_probe_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; + struct snd_soc_component *comp; + int order; int ret; - ret = soc_probe_component(card, rtd->component); - if (ret < 0) - return ret; - - /* do machine specific initialization */ - if (aux_dev->init) { - ret = aux_dev->init(rtd->component); - if (ret < 0) { - dev_err(card->dev, "ASoC: failed to init %s: %d\n", - aux_dev->name, ret); - return ret; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry(comp, &card->aux_comp_list, list_aux) { + if (comp->driver->probe_order == order) { + ret = soc_probe_component(card, comp); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to probe aux component %s %d\n", + comp->name, ret); + return ret; + } + } } } - return soc_post_component_init(rtd, aux_dev->name); + return 0; } -static void soc_remove_aux_dev(struct snd_soc_card *card, int num) +static void soc_remove_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_component *component = rtd->component; + struct snd_soc_component *comp, *_comp; + int order; - /* unregister the rtd device */ - if (rtd->dev_registered) { - device_unregister(rtd->dev); - rtd->dev_registered = 0; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry_safe(comp, _comp, + &card->aux_comp_list, list_aux) { + if (comp->driver->remove_order == order) { + soc_remove_component(comp); + /* remove it from the card's aux_comp_list */ + list_del(&comp->list_aux); + } + } } - - if (component) - soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -1894,6 +1920,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + /* probe auxiliary components */ + ret = soc_probe_aux_devices(card); + if (ret < 0) + goto probe_dai_err; + /* Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ @@ -1923,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } - for (i = 0; i < card->num_aux_devs; i++) { - ret = soc_probe_aux_dev(card, i); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to add auxiliary devices %d\n", - ret); - goto probe_aux_dev_err; - } - } - snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); @@ -1992,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) return 0; probe_aux_dev_err: - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); + soc_remove_aux_devices(card); probe_dai_err: soc_remove_dai_links(card); @@ -2039,20 +2059,18 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; - int i; /* make sure any delayed work runs */ list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - /* remove auxiliary devices */ - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); - /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + soc_cleanup_card_debugfs(card); /* remove the card */ @@ -2608,16 +2626,6 @@ int snd_soc_register_card(struct snd_soc_card *card) INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; - card->rtd_aux = devm_kzalloc(card->dev, - sizeof(struct snd_soc_pcm_runtime) * - card->num_aux_devs, - GFP_KERNEL); - if (card->rtd_aux == NULL) - return -ENOMEM; - - for (i = 0; i < card->num_aux_devs; i++) - card->rtd_aux[i].card = card; - INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); card->instantiated = 0; -- cgit v1.2.3 From a4eae3a506ea4a7d4474cd74e20b423fa8053d91 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Mon, 11 Jan 2016 08:16:58 +0100 Subject: ALSA: usb: Add native DSD support for Oppo HA-1 This patch adds native DSD support for the Oppo HA-1. It uses a XMOS chipset but they use their own vendor ID. Signed-off-by: Jurgen Kramer Cc: Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b6c0c8e3b450..23ea6d800c4c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1269,6 +1269,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ + case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/ if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; -- cgit v1.2.3 From 56f27013482c0803d978b667fe85de04ce9357cd Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 11 Jan 2016 09:33:14 +0100 Subject: ALSA: hda - Fixup inverted internal mic for Lenovo E50-80 Inform userspace that one channel of the internal mic has reversed polarity, so it does not attempt to add both channels together and end up with silence. Cc: stable@vger.kernel.org Reported-by: Andrzej Mendel Alsa-info: http://www.alsa-project.org/db/?f=3088f82a0cf977855f92af9db8ad406c04f71efa BugLink: https://bugs.launchpad.net/bugs/1529624 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3a89d82f8057..2fdda51d07c4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4666,6 +4666,7 @@ enum { ALC290_FIXUP_SUBWOOFER, ALC290_FIXUP_SUBWOOFER_HSJACK, ALC269_FIXUP_THINKPAD_ACPI, + ALC269_FIXUP_DMIC_THINKPAD_ACPI, ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, @@ -5103,6 +5104,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, }, + [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -5457,6 +5464,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -- cgit v1.2.3 From 7cb1dc810935fbf82ad06007dc7fb08d93c1e59f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 11 Jan 2016 02:41:05 -0800 Subject: ASoC: AMD: Add missing include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm:allmodconfig, s390:allmodconfig, sparc64:allmodconfig, and probably other builds fail with sound/soc/amd/acp-pcm-dma.c:83:2: error: implicit declaration of function ‘readl’ sound/soc/amd/acp-pcm-dma.c:88:2: error: implicit declaration of function ‘writel’ Include linux/io.h explicitly to fix the problem. Fixes: 7c31335a03b6a ("ASoC: AMD: add AMD ASoC ACP 2.x DMA driver") Cc: Maruthi Srinivas Bayyavarapu Signed-off-by: Guenter Roeck Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index cc8b841b69b6..3191e0a7d273 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -15,6 +15,7 @@ #include #include +#include #include #include -- cgit v1.2.3 From fe09dd8eb2310ec658f49a5431df2259f11cbe9e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 11 Jan 2016 13:09:55 +0100 Subject: ASoC: hdac_hdmi: remove unused hdac_hdmi_query_pin_connlist A recent rework removed the only user of the hdac_hdmi_query_pin_connlist function, so we now get a warning when building the hdac_hdmi driver: hdac_hdmi.c:313:12: warning: 'hdac_hdmi_query_pin_connlist' defined but not used [-Wunused-function] This removes the function, which makes the file build cleanly again. Signed-off-by: Arnd Bergmann Fixes: 15b914476bf2 ("ASoC: hdac_hdmi: Use list to add pins and converters") Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f5df7232405b..5a1ec0f7a1a6 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -310,28 +310,6 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) return err; } -static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, - struct hdac_hdmi_pin *pin) -{ - if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { - dev_warn(&hdac->hdac.dev, - "HDMI: pin %d wcaps %#x does not support connection list\n", - pin->nid, get_wcaps(&hdac->hdac, pin->nid)); - return -EINVAL; - } - - pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, - pin->mux_nids, HDA_MAX_CONNECTIONS); - if (pin->num_mux_nids == 0) - dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", - pin->nid); - - dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", - pin->num_mux_nids, pin->nid); - - return pin->num_mux_nids; -} - static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id, const char *wname, const char *stream) -- cgit v1.2.3 From 5c06d68bc2a174a6b82dce9f100f55173b9a5189 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Jan 2016 14:03:33 +0100 Subject: ALSA: usb-audio: Avoid calling usb_autopm_put_interface() at disconnect ALSA PCM may still have a leftover instance after disconnection and it delays its release. The problem is that the PCM close code path of USB-audio driver has a call of snd_usb_autosuspend(). This involves with the call of usb_autopm_put_interface() and it may lead to a kernel Oops due to the NULL object like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000190 IP: [] usb_autopm_put_interface+0xf/0x30 PGD 0 Call Trace: [] snd_usb_autosuspend+0x14/0x20 [] snd_usb_pcm_close.isra.14+0x5c/0x90 [] snd_usb_playback_close+0xf/0x20 [] snd_pcm_release_substream.part.36+0x3a/0x90 [] snd_pcm_release+0xa3/0xb0 [] snd_disconnect_release+0xd0/0xe0 [] __fput+0x97/0x1d0 [] ____fput+0x9/0x10 [] task_work_run+0x72/0x90 [] do_exit+0x280/0xa80 [] do_group_exit+0x3a/0xa0 [] get_signal+0x1df/0x540 [] do_signal+0x23/0x620 [] ? do_readv_writev+0x128/0x200 [] prepare_exit_to_usermode+0x91/0xd0 [] syscall_return_slowpath+0x9a/0x120 [] ? __sys_recvmsg+0x5d/0x70 [] ? ktime_get_ts64+0x45/0xe0 [] ? SyS_poll+0x60/0xf0 [] int_ret_from_sys_call+0x25/0x8f We have already a check of disconnection in snd_usb_autoresume(), but the check is missing its counterpart. The fix is just to put the same check in snd_usb_autosuspend(), too. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=109431 Cc: Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 18f56646ce86..1f09d9591276 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -675,6 +675,8 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip) { + if (atomic_read(&chip->shutdown)) + return; if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); } -- cgit v1.2.3 From 030e2c78d3a91dd0d27fef37e91950dde333eba1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Jan 2016 12:38:02 +0100 Subject: ALSA: seq: Fix missing NULL check at remove_events ioctl snd_seq_ioctl_remove_events() calls snd_seq_fifo_clear() unconditionally even if there is no FIFO assigned, and this leads to an Oops due to NULL dereference. The fix is just to add a proper NULL check. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index b64f20deba90..13cfa815732d 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1962,7 +1962,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, * No restrictions so for a user client we can clear * the whole fifo */ - if (client->type == USER_CLIENT) + if (client->type == USER_CLIENT && client->data.user.fifo) snd_seq_fifo_clear(client->data.user.fifo); } -- cgit v1.2.3 From 3567eb6af614dac436c4b16a8d426f9faed639b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Jan 2016 15:36:27 +0100 Subject: ALSA: seq: Fix race at timer setup and close ALSA sequencer code has an open race between the timer setup ioctl and the close of the client. This was triggered by syzkaller fuzzer, and a use-after-free was caught there as a result. This patch papers over it by adding a proper queue->timer_mutex lock around the timer-related calls in the relevant code path. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/seq_queue.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 7dfd0f429410..0bec02e89d51 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -142,8 +142,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked) static void queue_delete(struct snd_seq_queue *q) { /* stop and release the timer */ + mutex_lock(&q->timer_mutex); snd_seq_timer_stop(q->timer); snd_seq_timer_close(q); + mutex_unlock(&q->timer_mutex); /* wait until access free */ snd_use_lock_sync(&q->use_lock); /* release resources... */ -- cgit v1.2.3 From de65360be0239a63268de589c4189f8ee52dad6c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 22 Dec 2015 19:09:05 +0100 Subject: ALSA: hda_intel: add card number to irq description Currently the info in /proc/interrupts doesn't allow to figure out which interrupt belongs to which card (HDMI, PCH, ..). Therefore add card details to the interrupt description. With the patch the info in /proc/interrupts looks like this: PCI-MSI 442368-edge snd_hda_intel:card1 PCI-MSI 49152-edge snd_hda_intel:card0 NOTE: this patch adds the new irq_descr field snd_card struct that is filled automatically at a card object creation. This can be used generically for other drivers as well. The changes for others will follow later -- tiwai Signed-off-by: Heiner Kallweit Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 + sound/core/init.c | 3 +++ sound/pci/hda/hda_intel.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/core.h b/include/sound/core.h index cdfecafff0f4..31079ea5e484 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -99,6 +99,7 @@ struct snd_card { char driver[16]; /* driver name */ char shortname[32]; /* short name of this soundcard */ char longname[80]; /* name of this soundcard */ + char irq_descr[32]; /* Interrupt description */ char mixername[80]; /* mixer name */ char components[128]; /* card components delimited with space */ diff --git a/sound/core/init.c b/sound/core/init.c index 20f37fb3800e..6bda8436d765 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -268,6 +268,9 @@ int snd_card_new(struct device *parent, int idx, const char *xid, if (err < 0) goto __error; + snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s", + dev_driver_string(card->dev), dev_name(&card->card_dev)); + /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ err = snd_ctl_create(card); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 83800ac6ebd7..c0bef11afa7e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -725,7 +725,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, - KBUILD_MODNAME, chip)) { + chip->card->irq_descr, chip)) { dev_err(chip->card->dev, "unable to grab IRQ %d, disabling device\n", chip->pci->irq); -- cgit v1.2.3 From 98070576c4f77509459c83cd2358617ef0769a38 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Jan 2016 21:06:39 +0100 Subject: ALSA: hda - Fix white noise on Dell Latitude E5550 Dell Latitude E5550 (1028:062c) has a white noise problem like other Latitude E models, and it gets fixed by the very same quirk as well. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=110591 Cc: # v4.1+ Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2fdda51d07c4..f0ed41e1a884 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5339,6 +5339,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), -- cgit v1.2.3 From 0a1f90a982e85f4921bed606a6b41a24f4de2ae1 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 13 Jan 2016 11:51:38 +0800 Subject: ALSA: hda - fix the headset mic detection problem for a Dell laptop The machine uses codec alc255, and the pin configuration value for pin 0x14 on this machine is 0x90171130 which is not in the pin quirk table yet. Cc: stable@vger.kernel.org BugLink: https://bugs.launchpad.net/bugs/1533461 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f0ed41e1a884..61d8502e6b08 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5624,6 +5624,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60170}, {0x14, 0x90170130}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60170}, + {0x14, 0x90171130}, + {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60170}, {0x14, 0x90170140}, -- cgit v1.2.3 From c4a359a0049f2e17b012b31e801e96566f6391e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Jan 2016 07:20:13 +0100 Subject: ALSA: usb-audio: Fix mixer ctl regression of Native Instrument devices The commit [da6d276957ea: ALSA: usb-audio: Add resume support for Native Instruments controls] brought a regression where the Native Instrument audio devices don't get the correct value at update due to the missing shift at writing. This patch addresses it. Fixes: da6d276957ea ('ALSA: usb-audio: Add resume support for Native Instruments controls') Reported-and-tested-by: Owen Williams Cc: Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 0ce888dceed0..279025650568 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -793,7 +793,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, return 0; kcontrol->private_value &= ~(0xff << 24); - kcontrol->private_value |= newval; + kcontrol->private_value |= (unsigned int)newval << 24; err = snd_ni_update_cur_val(list); return err < 0 ? err : 1; } -- cgit v1.2.3 From ee8413b01045c74340aa13ad5bdf905de32be736 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Jan 2016 21:35:06 +0100 Subject: ALSA: timer: Fix double unlink of active_list ALSA timer instance object has a couple of linked lists and they are unlinked unconditionally at snd_timer_stop(). Meanwhile snd_timer_interrupt() unlinks it, but it calls list_del() which leaves the element list itself unchanged. This ends up with unlinking twice, and it was caught by syzkaller fuzzer. The fix is to use list_del_init() variant properly there, too. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai --- sound/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 31f40f03e5b7..9241784dfe7d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -694,7 +694,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(&ti->active_list); + list_del_init(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) -- cgit v1.2.3 From 91815d8aa7e2f45d30e51caa297061ad893628d9 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 14 Jan 2016 14:09:00 +0800 Subject: ALSA: hda - add codec support for Kabylake display audio codec This patch adds codec ID (0x8086280b) for Kabylake display codec and apply the hsw fix-ups to Kabylake. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cd9b0ffc91dc..426a29a1c19b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -51,8 +51,10 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808) #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809) #define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a) +#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b) #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ - || is_skylake(codec) || is_broxton(codec)) + || is_skylake(codec) || is_broxton(codec) \ + || is_kabylake(codec)) #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) @@ -3667,6 +3669,7 @@ HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi), -- cgit v1.2.3 From af368027a49a751d6ff4ee9e3f9961f35bb4fede Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Jan 2016 17:48:01 +0100 Subject: ALSA: timer: Fix race among timer ioctls ALSA timer ioctls have an open race and this may lead to a use-after-free of timer instance object. A simplistic fix is to make each ioctl exclusive. We have already tread_sem for controlling the tread, and extend this as a global mutex to be applied to each ioctl. The downside is, of course, the worse concurrency. But these ioctls aren't to be parallel accessible, in anyway, so it should be fine to serialize there. Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai --- sound/core/timer.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 9241784dfe7d..3810ee8f1205 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -73,7 +73,7 @@ struct snd_timer_user { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; - struct mutex tread_sem; + struct mutex ioctl_lock; }; /* list of timers */ @@ -1253,7 +1253,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); - mutex_init(&tu->tread_sem); + mutex_init(&tu->ioctl_lock); tu->ticks = 1; tu->queue_size = 128; tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), @@ -1273,8 +1273,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) if (file->private_data) { tu = file->private_data; file->private_data = NULL; + mutex_lock(&tu->ioctl_lock); if (tu->timeri) snd_timer_close(tu->timeri); + mutex_unlock(&tu->ioctl_lock); kfree(tu->queue); kfree(tu->tqueue); kfree(tu); @@ -1512,7 +1514,6 @@ static int snd_timer_user_tselect(struct file *file, int err = 0; tu = file->private_data; - mutex_lock(&tu->tread_sem); if (tu->timeri) { snd_timer_close(tu->timeri); tu->timeri = NULL; @@ -1556,7 +1557,6 @@ static int snd_timer_user_tselect(struct file *file, } __err: - mutex_unlock(&tu->tread_sem); return err; } @@ -1769,7 +1769,7 @@ enum { SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), }; -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, +static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_timer_user *tu; @@ -1786,17 +1786,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, { int xarg; - mutex_lock(&tu->tread_sem); - if (tu->timeri) { /* too late */ - mutex_unlock(&tu->tread_sem); + if (tu->timeri) /* too late */ return -EBUSY; - } - if (get_user(xarg, p)) { - mutex_unlock(&tu->tread_sem); + if (get_user(xarg, p)) return -EFAULT; - } tu->tread = xarg ? 1 : 0; - mutex_unlock(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -1829,6 +1823,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, return -ENOTTY; } +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct snd_timer_user *tu = file->private_data; + long ret; + + mutex_lock(&tu->ioctl_lock); + ret = __snd_timer_user_ioctl(file, cmd, arg); + mutex_unlock(&tu->ioctl_lock); + return ret; +} + static int snd_timer_user_fasync(int fd, struct file * file, int on) { struct snd_timer_user *tu; -- cgit v1.2.3 From cf52103a218744f3fd18111325c28e95aa9cd226 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 15 Jan 2016 12:59:25 +0100 Subject: ALSA: hda - Add fixup for Dell Latitidue E6540 Another Dell model, another fixup entry: Latitude E6540 needs the same fixup as other Latitude E series as workaround for noise problems. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104341 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 61d8502e6b08..8143c0e24a27 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5331,6 +5331,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), + SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), -- cgit v1.2.3 From b5a663aa426f4884c71cd8580adae73f33570f0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2016 16:30:58 +0100 Subject: ALSA: timer: Harden slave timer list handling A slave timer instance might be still accessible in a racy way while operating the master instance as it lacks of locking. Since the master operation is mostly protected with timer->lock, we should cope with it while changing the slave instance, too. Also, some linked lists (active_list and ack_list) of slave instances aren't unlinked immediately at stopping or closing, and this may lead to unexpected accesses. This patch tries to address these issues. It adds spin lock of timer->lock (either from master or slave, which is equivalent) in a few places. For avoiding a deadlock, we ensure that the global slave_active_lock is always locked at first before each timer lock. Also, ack and active_list of slave instances are properly unlinked at snd_timer_stop() and snd_timer_close(). Last but not least, remove the superfluous call of _snd_timer_stop() at removing slave links. This is a noop, and calling it may confuse readers wrt locking. Further cleanup will follow in a later patch. Actually we've got reports of use-after-free by syzkaller fuzzer, and this hopefully fixes these issues. Reported-by: Dmitry Vyukov Cc: Signed-off-by: Takashi Iwai --- sound/core/timer.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 3810ee8f1205..4e8d7bfffff6 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) slave->slave_id == master->slave_id) { list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) list_add_tail(&slave->active_list, &master->slave_active_head); + spin_unlock(&master->timer->lock); spin_unlock_irq(&slave_active_lock); } } @@ -346,15 +348,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer->hw.close) timer->hw.close(timer); /* remove slave links */ + spin_lock_irq(&slave_active_lock); + spin_lock(&timer->lock); list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { - spin_lock_irq(&slave_active_lock); - _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; - spin_unlock_irq(&slave_active_lock); + list_del_init(&slave->ack_list); + list_del_init(&slave->active_list); } + spin_unlock(&timer->lock); + spin_unlock_irq(&slave_active_lock); mutex_unlock(®ister_mutex); } out: @@ -441,9 +446,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) spin_lock_irqsave(&slave_active_lock, flags); timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - if (timeri->master) + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + spin_unlock(&timeri->timer->lock); + } spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } @@ -489,6 +497,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, if (!keep_flag) { spin_lock_irqsave(&slave_active_lock, flags); timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); spin_unlock_irqrestore(&slave_active_lock, flags); } goto __end; -- cgit v1.2.3 From c3b1681375dc6e71d89a3ae00cc3ce9e775a8917 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2016 17:01:46 +0100 Subject: ALSA: timer: Code cleanup This is a minor code cleanup without any functional changes: - Kill keep_flag argument from _snd_timer_stop(), as all callers pass only it false. - Remove redundant NULL check in _snd_timer_stop(). Signed-off-by: Takashi Iwai --- sound/core/timer.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 4e8d7bfffff6..cb25aded5349 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -301,8 +301,7 @@ int snd_timer_open(struct snd_timer_instance **ti, return 0; } -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); /* * close a timer instance @@ -344,7 +343,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_unlock_irq(&timer->lock); mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && + if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); /* remove slave links */ @@ -484,8 +483,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) return result; } -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) { struct snd_timer *timer; unsigned long flags; @@ -494,13 +492,11 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, return -ENXIO; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - list_del_init(&timeri->ack_list); - list_del_init(&timeri->active_list); - spin_unlock_irqrestore(&slave_active_lock, flags); - } + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + spin_unlock_irqrestore(&slave_active_lock, flags); goto __end; } timer = timeri->timer; @@ -521,9 +517,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, } } } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -542,7 +536,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) unsigned long flags; int err; - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); + err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); if (err < 0) return err; timer = timeri->timer; @@ -586,7 +580,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) */ int snd_timer_pause(struct snd_timer_instance * timeri) { - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); + return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); } /* -- cgit v1.2.3