diff options
Diffstat (limited to 'sound')
60 files changed, 2002 insertions, 3282 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 42ded997b223..c6ff94ab1ad6 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -216,6 +216,8 @@ static char *snd_pcm_format_names[] = { | |||
216 | FORMAT(DSD_U8), | 216 | FORMAT(DSD_U8), |
217 | FORMAT(DSD_U16_LE), | 217 | FORMAT(DSD_U16_LE), |
218 | FORMAT(DSD_U32_LE), | 218 | FORMAT(DSD_U32_LE), |
219 | FORMAT(DSD_U16_BE), | ||
220 | FORMAT(DSD_U32_BE), | ||
219 | }; | 221 | }; |
220 | 222 | ||
221 | const char *snd_pcm_format_name(snd_pcm_format_t format) | 223 | const char *snd_pcm_format_name(snd_pcm_format_t format) |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 102e8fd1d450..2d957ba63557 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -210,6 +210,8 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, | |||
210 | if (err < 0) | 210 | if (err < 0) |
211 | return err; | 211 | return err; |
212 | 212 | ||
213 | if (clear_user(src, sizeof(*src))) | ||
214 | return -EFAULT; | ||
213 | if (put_user(status.state, &src->state) || | 215 | if (put_user(status.state, &src->state) || |
214 | compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || | 216 | compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || |
215 | compat_put_timespec(&status.tstamp, &src->tstamp) || | 217 | compat_put_timespec(&status.tstamp, &src->tstamp) || |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index ae7a0feb3b76..ebe8444de6c6 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -152,6 +152,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { | |||
152 | .width = 32, .phys = 32, .le = 1, .signd = 0, | 152 | .width = 32, .phys = 32, .le = 1, .signd = 0, |
153 | .silence = { 0x69, 0x69, 0x69, 0x69 }, | 153 | .silence = { 0x69, 0x69, 0x69, 0x69 }, |
154 | }, | 154 | }, |
155 | [SNDRV_PCM_FORMAT_DSD_U16_BE] = { | ||
156 | .width = 16, .phys = 16, .le = 0, .signd = 0, | ||
157 | .silence = { 0x69, 0x69 }, | ||
158 | }, | ||
159 | [SNDRV_PCM_FORMAT_DSD_U32_BE] = { | ||
160 | .width = 32, .phys = 32, .le = 0, .signd = 0, | ||
161 | .silence = { 0x69, 0x69, 0x69, 0x69 }, | ||
162 | }, | ||
155 | /* FIXME: the following three formats are not defined properly yet */ | 163 | /* FIXME: the following three formats are not defined properly yet */ |
156 | [SNDRV_PCM_FORMAT_MPEG] = { | 164 | [SNDRV_PCM_FORMAT_MPEG] = { |
157 | .le = -1, .signd = -1, | 165 | .le = -1, .signd = -1, |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bfe1cf6b492f..166d59cdc86b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -781,16 +781,15 @@ static int snd_pcm_action_group(struct action_ops *ops, | |||
781 | { | 781 | { |
782 | struct snd_pcm_substream *s = NULL; | 782 | struct snd_pcm_substream *s = NULL; |
783 | struct snd_pcm_substream *s1; | 783 | struct snd_pcm_substream *s1; |
784 | int res = 0; | 784 | int res = 0, depth = 1; |
785 | 785 | ||
786 | snd_pcm_group_for_each_entry(s, substream) { | 786 | snd_pcm_group_for_each_entry(s, substream) { |
787 | if (do_lock && s != substream) { | 787 | if (do_lock && s != substream) { |
788 | if (s->pcm->nonatomic) | 788 | if (s->pcm->nonatomic) |
789 | mutex_lock_nested(&s->self_group.mutex, | 789 | mutex_lock_nested(&s->self_group.mutex, depth); |
790 | SINGLE_DEPTH_NESTING); | ||
791 | else | 790 | else |
792 | spin_lock_nested(&s->self_group.lock, | 791 | spin_lock_nested(&s->self_group.lock, depth); |
793 | SINGLE_DEPTH_NESTING); | 792 | depth++; |
794 | } | 793 | } |
795 | res = ops->pre_action(s, state); | 794 | res = ops->pre_action(s, state); |
796 | if (res < 0) | 795 | if (res < 0) |
@@ -906,8 +905,7 @@ static int snd_pcm_action_lock_mutex(struct action_ops *ops, | |||
906 | down_read(&snd_pcm_link_rwsem); | 905 | down_read(&snd_pcm_link_rwsem); |
907 | if (snd_pcm_stream_linked(substream)) { | 906 | if (snd_pcm_stream_linked(substream)) { |
908 | mutex_lock(&substream->group->mutex); | 907 | mutex_lock(&substream->group->mutex); |
909 | mutex_lock_nested(&substream->self_group.mutex, | 908 | mutex_lock(&substream->self_group.mutex); |
910 | SINGLE_DEPTH_NESTING); | ||
911 | res = snd_pcm_action_group(ops, substream, state, 1); | 909 | res = snd_pcm_action_group(ops, substream, state, 1); |
912 | mutex_unlock(&substream->self_group.mutex); | 910 | mutex_unlock(&substream->self_group.mutex); |
913 | mutex_unlock(&substream->group->mutex); | 911 | mutex_unlock(&substream->group->mutex); |
@@ -3311,7 +3309,7 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { | |||
3311 | 3309 | ||
3312 | #ifndef ARCH_HAS_DMA_MMAP_COHERENT | 3310 | #ifndef ARCH_HAS_DMA_MMAP_COHERENT |
3313 | /* This should be defined / handled globally! */ | 3311 | /* This should be defined / handled globally! */ |
3314 | #ifdef CONFIG_ARM | 3312 | #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) |
3315 | #define ARCH_HAS_DMA_MMAP_COHERENT | 3313 | #define ARCH_HAS_DMA_MMAP_COHERENT |
3316 | #endif | 3314 | #endif |
3317 | #endif | 3315 | #endif |
diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c index 45a0eed6d5b1..3b052ed0fbf5 100644 --- a/sound/firewire/bebob/bebob_focusrite.c +++ b/sound/firewire/bebob/bebob_focusrite.c | |||
@@ -27,12 +27,14 @@ | |||
27 | #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 | 27 | #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 |
28 | #define SAFFIRE_CLOCK_SOURCE_SPDIF 1 | 28 | #define SAFFIRE_CLOCK_SOURCE_SPDIF 1 |
29 | 29 | ||
30 | /* '1' is absent, why... */ | 30 | /* clock sources as returned from register of Saffire Pro 10 and 26 */ |
31 | #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 | 31 | #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 |
32 | #define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ | ||
32 | #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 | 33 | #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 |
33 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 | 34 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */ |
34 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 | 35 | #define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */ |
35 | #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 | 36 | #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 |
37 | #define SAFFIREPRO_CLOCK_SOURCE_COUNT 6 | ||
36 | 38 | ||
37 | /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ | 39 | /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ |
38 | #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 | 40 | #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 |
@@ -101,13 +103,34 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) | |||
101 | &data, sizeof(__be32), 0); | 103 | &data, sizeof(__be32), 0); |
102 | } | 104 | } |
103 | 105 | ||
106 | static char *const saffirepro_10_clk_src_labels[] = { | ||
107 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" | ||
108 | }; | ||
104 | static char *const saffirepro_26_clk_src_labels[] = { | 109 | static char *const saffirepro_26_clk_src_labels[] = { |
105 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" | 110 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" |
106 | }; | 111 | }; |
107 | 112 | /* Value maps between registers and labels for SaffirePro 10/26. */ | |
108 | static char *const saffirepro_10_clk_src_labels[] = { | 113 | static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = { |
109 | SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" | 114 | /* SaffirePro 10 */ |
115 | [0] = { | ||
116 | [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, | ||
117 | [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ | ||
118 | [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, | ||
119 | [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */ | ||
120 | [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */ | ||
121 | [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2, | ||
122 | }, | ||
123 | /* SaffirePro 26 */ | ||
124 | [1] = { | ||
125 | [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, | ||
126 | [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ | ||
127 | [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, | ||
128 | [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2, | ||
129 | [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3, | ||
130 | [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4, | ||
131 | } | ||
110 | }; | 132 | }; |
133 | |||
111 | static int | 134 | static int |
112 | saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) | 135 | saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) |
113 | { | 136 | { |
@@ -138,24 +161,35 @@ saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) | |||
138 | 161 | ||
139 | return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); | 162 | return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); |
140 | } | 163 | } |
164 | |||
165 | /* | ||
166 | * query hardware for current clock source, return our internally | ||
167 | * used clock index in *id, depending on hardware. | ||
168 | */ | ||
141 | static int | 169 | static int |
142 | saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | 170 | saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) |
143 | { | 171 | { |
144 | int err; | 172 | int err; |
145 | u32 value; | 173 | u32 value; /* clock source read from hw register */ |
174 | const signed char *map; | ||
146 | 175 | ||
147 | err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); | 176 | err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); |
148 | if (err < 0) | 177 | if (err < 0) |
149 | goto end; | 178 | goto end; |
150 | 179 | ||
151 | if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { | 180 | /* depending on hardware, use a different mapping */ |
152 | if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) | 181 | if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) |
153 | *id = 2; | 182 | map = saffirepro_clk_maps[0]; |
154 | else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) | 183 | else |
155 | *id = 1; | 184 | map = saffirepro_clk_maps[1]; |
156 | } else if (value > 1) { | 185 | |
157 | *id = value - 1; | 186 | /* In a case that this driver cannot handle the value of register. */ |
187 | if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { | ||
188 | err = -EIO; | ||
189 | goto end; | ||
158 | } | 190 | } |
191 | |||
192 | *id = (unsigned int)map[value]; | ||
159 | end: | 193 | end: |
160 | return err; | 194 | return err; |
161 | } | 195 | } |
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index ef4d0c9f6578..1aab0a32870c 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c | |||
@@ -129,12 +129,24 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal) | |||
129 | /* 1.The device has its own operation to switch source of clock */ | 129 | /* 1.The device has its own operation to switch source of clock */ |
130 | if (clk_spec) { | 130 | if (clk_spec) { |
131 | err = clk_spec->get(bebob, &id); | 131 | err = clk_spec->get(bebob, &id); |
132 | if (err < 0) | 132 | if (err < 0) { |
133 | dev_err(&bebob->unit->device, | 133 | dev_err(&bebob->unit->device, |
134 | "fail to get clock source: %d\n", err); | 134 | "fail to get clock source: %d\n", err); |
135 | else if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, | 135 | goto end; |
136 | strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) | 136 | } |
137 | |||
138 | if (id >= clk_spec->num) { | ||
139 | dev_err(&bebob->unit->device, | ||
140 | "clock source %d out of range 0..%d\n", | ||
141 | id, clk_spec->num - 1); | ||
142 | err = -EIO; | ||
143 | goto end; | ||
144 | } | ||
145 | |||
146 | if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, | ||
147 | strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) | ||
137 | *internal = true; | 148 | *internal = true; |
149 | |||
138 | goto end; | 150 | goto end; |
139 | } | 151 | } |
140 | 152 | ||
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c index 0e4c0bfc463b..9940611f2e1b 100644 --- a/sound/firewire/bebob/bebob_terratec.c +++ b/sound/firewire/bebob/bebob_terratec.c | |||
@@ -24,7 +24,12 @@ phase88_rack_clk_src_get(struct snd_bebob *bebob, unsigned int *id) | |||
24 | if (err < 0) | 24 | if (err < 0) |
25 | goto end; | 25 | goto end; |
26 | 26 | ||
27 | *id = (enable_ext & 0x01) | ((enable_word & 0x01) << 1); | 27 | if (enable_ext == 0) |
28 | *id = 0; | ||
29 | else if (enable_word == 0) | ||
30 | *id = 1; | ||
31 | else | ||
32 | *id = 2; | ||
28 | end: | 33 | end: |
29 | return err; | 34 | return err; |
30 | } | 35 | } |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 7bfdf9c51416..1610c38337af 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
@@ -681,7 +681,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe | |||
681 | 681 | ||
682 | /* WARQ is at offset 12 */ | 682 | /* WARQ is at offset 12 */ |
683 | tmp = (reg & AD_DS_WSMC_WARQ) ? | 683 | tmp = (reg & AD_DS_WSMC_WARQ) ? |
684 | (((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4; | 684 | ((((reg & AD_DS_WSMC_WARQ) >> 12) & 0x01) ? 12 : 18) : 4; |
685 | tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; | 685 | tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; |
686 | 686 | ||
687 | snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp, | 687 | snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp, |
@@ -693,7 +693,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe | |||
693 | 693 | ||
694 | /* SYRQ is at offset 4 */ | 694 | /* SYRQ is at offset 4 */ |
695 | tmp = (reg & AD_DS_WSMC_SYRQ) ? | 695 | tmp = (reg & AD_DS_WSMC_SYRQ) ? |
696 | (((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4; | 696 | ((((reg & AD_DS_WSMC_SYRQ) >> 4) & 0x01) ? 12 : 18) : 4; |
697 | tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; | 697 | tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; |
698 | 698 | ||
699 | snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp, | 699 | snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp, |
@@ -709,7 +709,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe | |||
709 | 709 | ||
710 | /* ACRQ is at offset 4 */ | 710 | /* ACRQ is at offset 4 */ |
711 | tmp = (reg & AD_DS_RAMC_ACRQ) ? | 711 | tmp = (reg & AD_DS_RAMC_ACRQ) ? |
712 | (((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4; | 712 | ((((reg & AD_DS_RAMC_ACRQ) >> 4) & 0x01) ? 12 : 18) : 4; |
713 | tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; | 713 | tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; |
714 | 714 | ||
715 | snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp, | 715 | snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp, |
@@ -720,7 +720,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe | |||
720 | 720 | ||
721 | /* RERQ is at offset 12 */ | 721 | /* RERQ is at offset 12 */ |
722 | tmp = (reg & AD_DS_RAMC_RERQ) ? | 722 | tmp = (reg & AD_DS_RAMC_RERQ) ? |
723 | (((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4; | 723 | ((((reg & AD_DS_RAMC_RERQ) >> 12) & 0x01) ? 12 : 18) : 4; |
724 | tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; | 724 | tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; |
725 | 725 | ||
726 | snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp, | 726 | snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp, |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cfcca4c30d4d..48b6c5a3884f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -219,6 +219,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
219 | "{Intel, LPT_LP}," | 219 | "{Intel, LPT_LP}," |
220 | "{Intel, WPT_LP}," | 220 | "{Intel, WPT_LP}," |
221 | "{Intel, SPT}," | 221 | "{Intel, SPT}," |
222 | "{Intel, SPT_LP}," | ||
222 | "{Intel, HPT}," | 223 | "{Intel, HPT}," |
223 | "{Intel, PBG}," | 224 | "{Intel, PBG}," |
224 | "{Intel, SCH}," | 225 | "{Intel, SCH}," |
@@ -297,7 +298,8 @@ enum { | |||
297 | 298 | ||
298 | /* quirks for ATI/AMD HDMI */ | 299 | /* quirks for ATI/AMD HDMI */ |
299 | #define AZX_DCAPS_PRESET_ATI_HDMI \ | 300 | #define AZX_DCAPS_PRESET_ATI_HDMI \ |
300 | (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) | 301 | (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\ |
302 | AZX_DCAPS_NO_MSI64) | ||
301 | 303 | ||
302 | /* quirks for Nvidia */ | 304 | /* quirks for Nvidia */ |
303 | #define AZX_DCAPS_PRESET_NVIDIA \ | 305 | #define AZX_DCAPS_PRESET_NVIDIA \ |
@@ -374,6 +376,8 @@ static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool | |||
374 | #ifdef CONFIG_SND_DMA_SGBUF | 376 | #ifdef CONFIG_SND_DMA_SGBUF |
375 | if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { | 377 | if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { |
376 | struct snd_sg_buf *sgbuf = dmab->private_data; | 378 | struct snd_sg_buf *sgbuf = dmab->private_data; |
379 | if (chip->driver_type == AZX_DRIVER_CMEDIA) | ||
380 | return; /* deal with only CORB/RIRB buffers */ | ||
377 | if (on) | 381 | if (on) |
378 | set_pages_array_wc(sgbuf->page_table, sgbuf->pages); | 382 | set_pages_array_wc(sgbuf->page_table, sgbuf->pages); |
379 | else | 383 | else |
@@ -1483,6 +1487,7 @@ static int azx_first_init(struct azx *chip) | |||
1483 | struct snd_card *card = chip->card; | 1487 | struct snd_card *card = chip->card; |
1484 | int err; | 1488 | int err; |
1485 | unsigned short gcap; | 1489 | unsigned short gcap; |
1490 | unsigned int dma_bits = 64; | ||
1486 | 1491 | ||
1487 | #if BITS_PER_LONG != 64 | 1492 | #if BITS_PER_LONG != 64 |
1488 | /* Fix up base address on ULI M5461 */ | 1493 | /* Fix up base address on ULI M5461 */ |
@@ -1506,9 +1511,14 @@ static int azx_first_init(struct azx *chip) | |||
1506 | return -ENXIO; | 1511 | return -ENXIO; |
1507 | } | 1512 | } |
1508 | 1513 | ||
1509 | if (chip->msi) | 1514 | if (chip->msi) { |
1515 | if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { | ||
1516 | dev_dbg(card->dev, "Disabling 64bit MSI\n"); | ||
1517 | pci->no_64bit_msi = true; | ||
1518 | } | ||
1510 | if (pci_enable_msi(pci) < 0) | 1519 | if (pci_enable_msi(pci) < 0) |
1511 | chip->msi = 0; | 1520 | chip->msi = 0; |
1521 | } | ||
1512 | 1522 | ||
1513 | if (azx_acquire_irq(chip, 0) < 0) | 1523 | if (azx_acquire_irq(chip, 0) < 0) |
1514 | return -EBUSY; | 1524 | return -EBUSY; |
@@ -1519,9 +1529,14 @@ static int azx_first_init(struct azx *chip) | |||
1519 | gcap = azx_readw(chip, GCAP); | 1529 | gcap = azx_readw(chip, GCAP); |
1520 | dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); | 1530 | dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); |
1521 | 1531 | ||
1532 | /* AMD devices support 40 or 48bit DMA, take the safe one */ | ||
1533 | if (chip->pci->vendor == PCI_VENDOR_ID_AMD) | ||
1534 | dma_bits = 40; | ||
1535 | |||
1522 | /* disable SB600 64bit support for safety */ | 1536 | /* disable SB600 64bit support for safety */ |
1523 | if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { | 1537 | if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { |
1524 | struct pci_dev *p_smbus; | 1538 | struct pci_dev *p_smbus; |
1539 | dma_bits = 40; | ||
1525 | p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, | 1540 | p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, |
1526 | PCI_DEVICE_ID_ATI_SBX00_SMBUS, | 1541 | PCI_DEVICE_ID_ATI_SBX00_SMBUS, |
1527 | NULL); | 1542 | NULL); |
@@ -1551,9 +1566,11 @@ static int azx_first_init(struct azx *chip) | |||
1551 | } | 1566 | } |
1552 | 1567 | ||
1553 | /* allow 64bit DMA address if supported by H/W */ | 1568 | /* allow 64bit DMA address if supported by H/W */ |
1554 | if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) | 1569 | if (!(gcap & AZX_GCAP_64OK)) |
1555 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); | 1570 | dma_bits = 32; |
1556 | else { | 1571 | if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) { |
1572 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits)); | ||
1573 | } else { | ||
1557 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); | 1574 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); |
1558 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); | 1575 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); |
1559 | } | 1576 | } |
@@ -1769,7 +1786,7 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, | |||
1769 | #ifdef CONFIG_X86 | 1786 | #ifdef CONFIG_X86 |
1770 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | 1787 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); |
1771 | struct azx *chip = apcm->chip; | 1788 | struct azx *chip = apcm->chip; |
1772 | if (!azx_snoop(chip)) | 1789 | if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA) |
1773 | area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); | 1790 | area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); |
1774 | #endif | 1791 | #endif |
1775 | } | 1792 | } |
@@ -2002,6 +2019,9 @@ static const struct pci_device_id azx_ids[] = { | |||
2002 | /* Sunrise Point */ | 2019 | /* Sunrise Point */ |
2003 | { PCI_DEVICE(0x8086, 0xa170), | 2020 | { PCI_DEVICE(0x8086, 0xa170), |
2004 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | 2021 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, |
2022 | /* Sunrise Point-LP */ | ||
2023 | { PCI_DEVICE(0x8086, 0x9d70), | ||
2024 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | ||
2005 | /* Haswell */ | 2025 | /* Haswell */ |
2006 | { PCI_DEVICE(0x8086, 0x0a0c), | 2026 | { PCI_DEVICE(0x8086, 0x0a0c), |
2007 | .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, | 2027 | .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7eb44e78e141..62658f2f8c9f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -419,7 +419,7 @@ struct snd_hda_pin_quirk { | |||
419 | .subvendor = _subvendor,\ | 419 | .subvendor = _subvendor,\ |
420 | .name = _name,\ | 420 | .name = _name,\ |
421 | .value = _value,\ | 421 | .value = _value,\ |
422 | .pins = (const struct hda_pintbl[]) { _pins } \ | 422 | .pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \ |
423 | } | 423 | } |
424 | #else | 424 | #else |
425 | 425 | ||
@@ -427,7 +427,7 @@ struct snd_hda_pin_quirk { | |||
427 | { .codec = _codec,\ | 427 | { .codec = _codec,\ |
428 | .subvendor = _subvendor,\ | 428 | .subvendor = _subvendor,\ |
429 | .value = _value,\ | 429 | .value = _value,\ |
430 | .pins = (const struct hda_pintbl[]) { _pins } \ | 430 | .pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \ |
431 | } | 431 | } |
432 | 432 | ||
433 | #endif | 433 | #endif |
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 949cd437eeb2..5016014e57f2 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h | |||
@@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
171 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ | 171 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ |
172 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ | 172 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ |
173 | #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ | 173 | #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ |
174 | #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ | ||
174 | 175 | ||
175 | /* HD Audio class code */ | 176 | /* HD Audio class code */ |
176 | #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 | 177 | #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 71e4bad06345..e9ebc7bd752c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -43,6 +43,7 @@ struct conexant_spec { | |||
43 | unsigned int num_eapds; | 43 | unsigned int num_eapds; |
44 | hda_nid_t eapds[4]; | 44 | hda_nid_t eapds[4]; |
45 | bool dynamic_eapd; | 45 | bool dynamic_eapd; |
46 | hda_nid_t mute_led_eapd; | ||
46 | 47 | ||
47 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ | 48 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ |
48 | 49 | ||
@@ -163,6 +164,17 @@ static void cx_auto_vmaster_hook(void *private_data, int enabled) | |||
163 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); | 164 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); |
164 | } | 165 | } |
165 | 166 | ||
167 | /* turn on/off EAPD according to Master switch (inversely!) for mute LED */ | ||
168 | static void cx_auto_vmaster_hook_mute_led(void *private_data, int enabled) | ||
169 | { | ||
170 | struct hda_codec *codec = private_data; | ||
171 | struct conexant_spec *spec = codec->spec; | ||
172 | |||
173 | snd_hda_codec_write(codec, spec->mute_led_eapd, 0, | ||
174 | AC_VERB_SET_EAPD_BTLENABLE, | ||
175 | enabled ? 0x00 : 0x02); | ||
176 | } | ||
177 | |||
166 | static int cx_auto_build_controls(struct hda_codec *codec) | 178 | static int cx_auto_build_controls(struct hda_codec *codec) |
167 | { | 179 | { |
168 | int err; | 180 | int err; |
@@ -223,6 +235,7 @@ enum { | |||
223 | CXT_FIXUP_TOSHIBA_P105, | 235 | CXT_FIXUP_TOSHIBA_P105, |
224 | CXT_FIXUP_HP_530, | 236 | CXT_FIXUP_HP_530, |
225 | CXT_FIXUP_CAP_MIX_AMP_5047, | 237 | CXT_FIXUP_CAP_MIX_AMP_5047, |
238 | CXT_FIXUP_MUTE_LED_EAPD, | ||
226 | }; | 239 | }; |
227 | 240 | ||
228 | /* for hda_fixup_thinkpad_acpi() */ | 241 | /* for hda_fixup_thinkpad_acpi() */ |
@@ -557,6 +570,18 @@ static void cxt_fixup_olpc_xo(struct hda_codec *codec, | |||
557 | } | 570 | } |
558 | } | 571 | } |
559 | 572 | ||
573 | static void cxt_fixup_mute_led_eapd(struct hda_codec *codec, | ||
574 | const struct hda_fixup *fix, int action) | ||
575 | { | ||
576 | struct conexant_spec *spec = codec->spec; | ||
577 | |||
578 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
579 | spec->mute_led_eapd = 0x1b; | ||
580 | spec->dynamic_eapd = 1; | ||
581 | spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook_mute_led; | ||
582 | } | ||
583 | } | ||
584 | |||
560 | /* | 585 | /* |
561 | * Fix max input level on mixer widget to 0dB | 586 | * Fix max input level on mixer widget to 0dB |
562 | * (originally it has 0x2b steps with 0dB offset 0x14) | 587 | * (originally it has 0x2b steps with 0dB offset 0x14) |
@@ -705,6 +730,10 @@ static const struct hda_fixup cxt_fixups[] = { | |||
705 | .type = HDA_FIXUP_FUNC, | 730 | .type = HDA_FIXUP_FUNC, |
706 | .v.func = cxt_fixup_cap_mix_amp_5047, | 731 | .v.func = cxt_fixup_cap_mix_amp_5047, |
707 | }, | 732 | }, |
733 | [CXT_FIXUP_MUTE_LED_EAPD] = { | ||
734 | .type = HDA_FIXUP_FUNC, | ||
735 | .v.func = cxt_fixup_mute_led_eapd, | ||
736 | }, | ||
708 | }; | 737 | }; |
709 | 738 | ||
710 | static const struct snd_pci_quirk cxt5045_fixups[] = { | 739 | static const struct snd_pci_quirk cxt5045_fixups[] = { |
@@ -762,6 +791,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { | |||
762 | SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), | 791 | SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), |
763 | SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), | 792 | SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), |
764 | SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), | 793 | SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), |
794 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD), | ||
765 | SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), | 795 | SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), |
766 | SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), | 796 | SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), |
767 | SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), | 797 | SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), |
@@ -780,6 +810,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { | |||
780 | { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, | 810 | { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, |
781 | { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, | 811 | { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, |
782 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, | 812 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, |
813 | { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, | ||
783 | {} | 814 | {} |
784 | }; | 815 | }; |
785 | 816 | ||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 39862e98551c..9dc9cf8c90e9 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -1583,19 +1583,22 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1583 | } | 1583 | } |
1584 | } | 1584 | } |
1585 | 1585 | ||
1586 | if (pin_eld->eld_valid && !eld->eld_valid) { | 1586 | if (pin_eld->eld_valid != eld->eld_valid) |
1587 | update_eld = true; | ||
1588 | eld_changed = true; | 1587 | eld_changed = true; |
1589 | } | 1588 | |
1589 | if (pin_eld->eld_valid && !eld->eld_valid) | ||
1590 | update_eld = true; | ||
1591 | |||
1590 | if (update_eld) { | 1592 | if (update_eld) { |
1591 | bool old_eld_valid = pin_eld->eld_valid; | 1593 | bool old_eld_valid = pin_eld->eld_valid; |
1592 | pin_eld->eld_valid = eld->eld_valid; | 1594 | pin_eld->eld_valid = eld->eld_valid; |
1593 | eld_changed = pin_eld->eld_size != eld->eld_size || | 1595 | if (pin_eld->eld_size != eld->eld_size || |
1594 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, | 1596 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, |
1595 | eld->eld_size) != 0; | 1597 | eld->eld_size) != 0) { |
1596 | if (eld_changed) | ||
1597 | memcpy(pin_eld->eld_buffer, eld->eld_buffer, | 1598 | memcpy(pin_eld->eld_buffer, eld->eld_buffer, |
1598 | eld->eld_size); | 1599 | eld->eld_size); |
1600 | eld_changed = true; | ||
1601 | } | ||
1599 | pin_eld->eld_size = eld->eld_size; | 1602 | pin_eld->eld_size = eld->eld_size; |
1600 | pin_eld->info = eld->info; | 1603 | pin_eld->info = eld->info; |
1601 | 1604 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bc86c36b4bfa..b118a5be18df 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -288,21 +288,91 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) | |||
288 | snd_hda_jack_unsol_event(codec, res >> 2); | 288 | snd_hda_jack_unsol_event(codec, res >> 2); |
289 | } | 289 | } |
290 | 290 | ||
291 | /* additional initialization for ALC888 variants */ | 291 | /* Change EAPD to verb control */ |
292 | static void alc888_coef_init(struct hda_codec *codec) | 292 | static void alc_fill_eapd_coef(struct hda_codec *codec) |
293 | { | 293 | { |
294 | if (alc_get_coef0(codec) == 0x20) | 294 | int coef; |
295 | /* alc888S-VC */ | 295 | |
296 | alc_write_coef_idx(codec, 7, 0x830); | 296 | coef = alc_get_coef0(codec); |
297 | else | 297 | |
298 | /* alc888-VB */ | 298 | switch (codec->vendor_id) { |
299 | alc_write_coef_idx(codec, 7, 0x3030); | 299 | case 0x10ec0262: |
300 | alc_update_coef_idx(codec, 0x7, 0, 1<<5); | ||
301 | break; | ||
302 | case 0x10ec0267: | ||
303 | case 0x10ec0268: | ||
304 | alc_update_coef_idx(codec, 0x7, 0, 1<<13); | ||
305 | break; | ||
306 | case 0x10ec0269: | ||
307 | if ((coef & 0x00f0) == 0x0010) | ||
308 | alc_update_coef_idx(codec, 0xd, 0, 1<<14); | ||
309 | if ((coef & 0x00f0) == 0x0020) | ||
310 | alc_update_coef_idx(codec, 0x4, 1<<15, 0); | ||
311 | if ((coef & 0x00f0) == 0x0030) | ||
312 | alc_update_coef_idx(codec, 0x10, 1<<9, 0); | ||
313 | break; | ||
314 | case 0x10ec0280: | ||
315 | case 0x10ec0284: | ||
316 | case 0x10ec0290: | ||
317 | case 0x10ec0292: | ||
318 | alc_update_coef_idx(codec, 0x4, 1<<15, 0); | ||
319 | break; | ||
320 | case 0x10ec0233: | ||
321 | case 0x10ec0255: | ||
322 | case 0x10ec0282: | ||
323 | case 0x10ec0283: | ||
324 | case 0x10ec0286: | ||
325 | case 0x10ec0288: | ||
326 | alc_update_coef_idx(codec, 0x10, 1<<9, 0); | ||
327 | break; | ||
328 | case 0x10ec0285: | ||
329 | case 0x10ec0293: | ||
330 | alc_update_coef_idx(codec, 0xa, 1<<13, 0); | ||
331 | break; | ||
332 | case 0x10ec0662: | ||
333 | if ((coef & 0x00f0) == 0x0030) | ||
334 | alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ | ||
335 | break; | ||
336 | case 0x10ec0272: | ||
337 | case 0x10ec0273: | ||
338 | case 0x10ec0663: | ||
339 | case 0x10ec0665: | ||
340 | case 0x10ec0670: | ||
341 | case 0x10ec0671: | ||
342 | case 0x10ec0672: | ||
343 | alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ | ||
344 | break; | ||
345 | case 0x10ec0668: | ||
346 | alc_update_coef_idx(codec, 0x7, 3<<13, 0); | ||
347 | break; | ||
348 | case 0x10ec0867: | ||
349 | alc_update_coef_idx(codec, 0x4, 1<<10, 0); | ||
350 | break; | ||
351 | case 0x10ec0888: | ||
352 | if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030) | ||
353 | alc_update_coef_idx(codec, 0x7, 1<<5, 0); | ||
354 | break; | ||
355 | case 0x10ec0892: | ||
356 | alc_update_coef_idx(codec, 0x7, 1<<5, 0); | ||
357 | break; | ||
358 | case 0x10ec0899: | ||
359 | case 0x10ec0900: | ||
360 | alc_update_coef_idx(codec, 0x7, 1<<1, 0); | ||
361 | break; | ||
362 | } | ||
300 | } | 363 | } |
301 | 364 | ||
302 | /* additional initialization for ALC889 variants */ | 365 | /* additional initialization for ALC888 variants */ |
303 | static void alc889_coef_init(struct hda_codec *codec) | 366 | static void alc888_coef_init(struct hda_codec *codec) |
304 | { | 367 | { |
305 | alc_update_coef_idx(codec, 7, 0, 0x2010); | 368 | switch (alc_get_coef0(codec) & 0x00f0) { |
369 | /* alc888-VA */ | ||
370 | case 0x00: | ||
371 | /* alc888-VB */ | ||
372 | case 0x10: | ||
373 | alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */ | ||
374 | break; | ||
375 | } | ||
306 | } | 376 | } |
307 | 377 | ||
308 | /* turn on/off EAPD control (only if available) */ | 378 | /* turn on/off EAPD control (only if available) */ |
@@ -343,6 +413,7 @@ static void alc_eapd_shutup(struct hda_codec *codec) | |||
343 | /* generic EAPD initialization */ | 413 | /* generic EAPD initialization */ |
344 | static void alc_auto_init_amp(struct hda_codec *codec, int type) | 414 | static void alc_auto_init_amp(struct hda_codec *codec, int type) |
345 | { | 415 | { |
416 | alc_fill_eapd_coef(codec); | ||
346 | alc_auto_setup_eapd(codec, true); | 417 | alc_auto_setup_eapd(codec, true); |
347 | switch (type) { | 418 | switch (type) { |
348 | case ALC_INIT_GPIO1: | 419 | case ALC_INIT_GPIO1: |
@@ -359,25 +430,15 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) | |||
359 | case 0x10ec0260: | 430 | case 0x10ec0260: |
360 | alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); | 431 | alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); |
361 | break; | 432 | break; |
362 | case 0x10ec0262: | ||
363 | case 0x10ec0880: | 433 | case 0x10ec0880: |
364 | case 0x10ec0882: | 434 | case 0x10ec0882: |
365 | case 0x10ec0883: | 435 | case 0x10ec0883: |
366 | case 0x10ec0885: | 436 | case 0x10ec0885: |
367 | case 0x10ec0887: | 437 | alc_update_coef_idx(codec, 7, 0, 0x2030); |
368 | /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ | ||
369 | case 0x10ec0900: | ||
370 | alc889_coef_init(codec); | ||
371 | break; | 438 | break; |
372 | case 0x10ec0888: | 439 | case 0x10ec0888: |
373 | alc888_coef_init(codec); | 440 | alc888_coef_init(codec); |
374 | break; | 441 | break; |
375 | #if 0 /* XXX: This may cause the silent output on speaker on some machines */ | ||
376 | case 0x10ec0267: | ||
377 | case 0x10ec0268: | ||
378 | alc_update_coef_idx(codec, 7, 0, 0x3000); | ||
379 | break; | ||
380 | #endif /* XXX */ | ||
381 | } | 442 | } |
382 | break; | 443 | break; |
383 | } | 444 | } |
@@ -1710,7 +1771,7 @@ static void alc889_fixup_coef(struct hda_codec *codec, | |||
1710 | { | 1771 | { |
1711 | if (action != HDA_FIXUP_ACT_INIT) | 1772 | if (action != HDA_FIXUP_ACT_INIT) |
1712 | return; | 1773 | return; |
1713 | alc889_coef_init(codec); | 1774 | alc_update_coef_idx(codec, 7, 0, 0x2030); |
1714 | } | 1775 | } |
1715 | 1776 | ||
1716 | /* toggle speaker-output according to the hp-jack state */ | 1777 | /* toggle speaker-output according to the hp-jack state */ |
@@ -2675,7 +2736,7 @@ static void alc269_shutup(struct hda_codec *codec) | |||
2675 | 2736 | ||
2676 | static struct coef_fw alc282_coefs[] = { | 2737 | static struct coef_fw alc282_coefs[] = { |
2677 | WRITE_COEF(0x03, 0x0002), /* Power Down Control */ | 2738 | WRITE_COEF(0x03, 0x0002), /* Power Down Control */ |
2678 | WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ | 2739 | UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */ |
2679 | WRITE_COEF(0x07, 0x0200), /* DMIC control */ | 2740 | WRITE_COEF(0x07, 0x0200), /* DMIC control */ |
2680 | UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ | 2741 | UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ |
2681 | UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ | 2742 | UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ |
@@ -2786,7 +2847,7 @@ static void alc282_shutup(struct hda_codec *codec) | |||
2786 | 2847 | ||
2787 | static struct coef_fw alc283_coefs[] = { | 2848 | static struct coef_fw alc283_coefs[] = { |
2788 | WRITE_COEF(0x03, 0x0002), /* Power Down Control */ | 2849 | WRITE_COEF(0x03, 0x0002), /* Power Down Control */ |
2789 | WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ | 2850 | UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */ |
2790 | WRITE_COEF(0x07, 0x0200), /* DMIC control */ | 2851 | WRITE_COEF(0x07, 0x0200), /* DMIC control */ |
2791 | UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ | 2852 | UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ |
2792 | UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ | 2853 | UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ |
@@ -2817,6 +2878,7 @@ static struct coef_fw alc283_coefs[] = { | |||
2817 | UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ | 2878 | UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ |
2818 | UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ | 2879 | UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ |
2819 | WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ | 2880 | WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ |
2881 | UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */ | ||
2820 | {} | 2882 | {} |
2821 | }; | 2883 | }; |
2822 | 2884 | ||
@@ -2884,6 +2946,9 @@ static void alc283_shutup(struct hda_codec *codec) | |||
2884 | 2946 | ||
2885 | alc_write_coef_idx(codec, 0x43, 0x9004); | 2947 | alc_write_coef_idx(codec, 0x43, 0x9004); |
2886 | 2948 | ||
2949 | /*depop hp during suspend*/ | ||
2950 | alc_write_coef_idx(codec, 0x06, 0x2100); | ||
2951 | |||
2887 | snd_hda_codec_write(codec, hp_pin, 0, | 2952 | snd_hda_codec_write(codec, hp_pin, 0, |
2888 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | 2953 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); |
2889 | 2954 | ||
@@ -3346,6 +3411,27 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, | |||
3346 | } | 3411 | } |
3347 | } | 3412 | } |
3348 | 3413 | ||
3414 | static void alc280_fixup_hp_gpio4(struct hda_codec *codec, | ||
3415 | const struct hda_fixup *fix, int action) | ||
3416 | { | ||
3417 | /* Like hp_gpio_mic1_led, but also needs GPIO4 low to enable headphone amp */ | ||
3418 | struct alc_spec *spec = codec->spec; | ||
3419 | static const struct hda_verb gpio_init[] = { | ||
3420 | { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, | ||
3421 | { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, | ||
3422 | {} | ||
3423 | }; | ||
3424 | |||
3425 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
3426 | spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; | ||
3427 | spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; | ||
3428 | spec->gpio_led = 0; | ||
3429 | spec->cap_mute_led_nid = 0x18; | ||
3430 | snd_hda_add_verbs(codec, gpio_init); | ||
3431 | codec->power_filter = led_power_filter; | ||
3432 | } | ||
3433 | } | ||
3434 | |||
3349 | static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, | 3435 | static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, |
3350 | const struct hda_fixup *fix, int action) | 3436 | const struct hda_fixup *fix, int action) |
3351 | { | 3437 | { |
@@ -4213,6 +4299,7 @@ enum { | |||
4213 | ALC283_FIXUP_BXBT2807_MIC, | 4299 | ALC283_FIXUP_BXBT2807_MIC, |
4214 | ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, | 4300 | ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, |
4215 | ALC282_FIXUP_ASPIRE_V5_PINS, | 4301 | ALC282_FIXUP_ASPIRE_V5_PINS, |
4302 | ALC280_FIXUP_HP_GPIO4, | ||
4216 | }; | 4303 | }; |
4217 | 4304 | ||
4218 | static const struct hda_fixup alc269_fixups[] = { | 4305 | static const struct hda_fixup alc269_fixups[] = { |
@@ -4433,6 +4520,8 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4433 | [ALC269_FIXUP_HEADSET_MODE] = { | 4520 | [ALC269_FIXUP_HEADSET_MODE] = { |
4434 | .type = HDA_FIXUP_FUNC, | 4521 | .type = HDA_FIXUP_FUNC, |
4435 | .v.func = alc_fixup_headset_mode, | 4522 | .v.func = alc_fixup_headset_mode, |
4523 | .chained = true, | ||
4524 | .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED | ||
4436 | }, | 4525 | }, |
4437 | [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = { | 4526 | [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = { |
4438 | .type = HDA_FIXUP_FUNC, | 4527 | .type = HDA_FIXUP_FUNC, |
@@ -4622,6 +4711,8 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4622 | [ALC255_FIXUP_HEADSET_MODE] = { | 4711 | [ALC255_FIXUP_HEADSET_MODE] = { |
4623 | .type = HDA_FIXUP_FUNC, | 4712 | .type = HDA_FIXUP_FUNC, |
4624 | .v.func = alc_fixup_headset_mode_alc255, | 4713 | .v.func = alc_fixup_headset_mode_alc255, |
4714 | .chained = true, | ||
4715 | .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED | ||
4625 | }, | 4716 | }, |
4626 | [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = { | 4717 | [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = { |
4627 | .type = HDA_FIXUP_FUNC, | 4718 | .type = HDA_FIXUP_FUNC, |
@@ -4657,8 +4748,6 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4657 | [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = { | 4748 | [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = { |
4658 | .type = HDA_FIXUP_FUNC, | 4749 | .type = HDA_FIXUP_FUNC, |
4659 | .v.func = alc_fixup_dell_wmi, | 4750 | .v.func = alc_fixup_dell_wmi, |
4660 | .chained_before = true, | ||
4661 | .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE | ||
4662 | }, | 4751 | }, |
4663 | [ALC282_FIXUP_ASPIRE_V5_PINS] = { | 4752 | [ALC282_FIXUP_ASPIRE_V5_PINS] = { |
4664 | .type = HDA_FIXUP_PINS, | 4753 | .type = HDA_FIXUP_PINS, |
@@ -4676,7 +4765,10 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4676 | { }, | 4765 | { }, |
4677 | }, | 4766 | }, |
4678 | }, | 4767 | }, |
4679 | 4768 | [ALC280_FIXUP_HP_GPIO4] = { | |
4769 | .type = HDA_FIXUP_FUNC, | ||
4770 | .v.func = alc280_fixup_hp_gpio4, | ||
4771 | }, | ||
4680 | }; | 4772 | }; |
4681 | 4773 | ||
4682 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 4774 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
@@ -4693,13 +4785,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4693 | SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 4785 | SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
4694 | SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 4786 | SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
4695 | SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 4787 | SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
4696 | SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), | ||
4697 | SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), | 4788 | SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), |
4698 | SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), | 4789 | SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), |
4699 | SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), | ||
4700 | SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), | 4790 | SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), |
4701 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4791 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4702 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4792 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4793 | SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4794 | SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4703 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4795 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4704 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4796 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4705 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), | 4797 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), |
@@ -4724,21 +4816,15 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4724 | SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4816 | SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
4725 | SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4817 | SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4726 | SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4818 | SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4727 | SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4728 | /* ALC290 */ | 4819 | /* ALC290 */ |
4729 | SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4820 | SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4730 | SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4821 | SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4731 | SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4822 | SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4732 | SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4733 | SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4734 | SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4735 | SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4736 | SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4823 | SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4737 | SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4824 | SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4738 | SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4825 | SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4739 | SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4826 | SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4740 | SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4827 | SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4741 | SND_PCI_QUIRK(0x103c, 0x2258, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4742 | SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4828 | SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4743 | SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4829 | SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4744 | SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4830 | SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
@@ -4747,7 +4833,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4747 | SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4833 | SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
4748 | SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4834 | SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4749 | SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4835 | SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4750 | SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4751 | SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4836 | SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4752 | SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4837 | SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
4753 | SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4838 | SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
@@ -4800,7 +4885,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4800 | SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), | 4885 | SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), |
4801 | SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), | 4886 | SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), |
4802 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK), | 4887 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK), |
4803 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4888 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK), |
4804 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4889 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
4805 | SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), | 4890 | SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), |
4806 | SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4891 | SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -4980,6 +5065,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | |||
4980 | {0x17, 0x40000000}, | 5065 | {0x17, 0x40000000}, |
4981 | {0x1d, 0x40700001}, | 5066 | {0x1d, 0x40700001}, |
4982 | {0x21, 0x02211040}), | 5067 | {0x21, 0x02211040}), |
5068 | SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, | ||
5069 | {0x12, 0x90a60130}, | ||
5070 | {0x13, 0x40000000}, | ||
5071 | {0x14, 0x90170110}, | ||
5072 | {0x15, 0x0421101f}, | ||
5073 | {0x16, 0x411111f0}, | ||
5074 | {0x17, 0x411111f0}, | ||
5075 | {0x18, 0x411111f0}, | ||
5076 | {0x19, 0x411111f0}, | ||
5077 | {0x1a, 0x04a11020}, | ||
5078 | {0x1b, 0x411111f0}, | ||
5079 | {0x1d, 0x40748605}, | ||
5080 | {0x1e, 0x411111f0}), | ||
4983 | SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED, | 5081 | SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED, |
4984 | {0x12, 0x90a60140}, | 5082 | {0x12, 0x90a60140}, |
4985 | {0x13, 0x40000000}, | 5083 | {0x13, 0x40000000}, |
@@ -5190,9 +5288,6 @@ static void alc269_fill_coef(struct hda_codec *codec) | |||
5190 | } | 5288 | } |
5191 | } | 5289 | } |
5192 | 5290 | ||
5193 | /* Class D */ | ||
5194 | alc_update_coef_idx(codec, 0xd, 0, 1<<14); | ||
5195 | |||
5196 | /* HP */ | 5291 | /* HP */ |
5197 | alc_update_coef_idx(codec, 0x4, 0, 1<<11); | 5292 | alc_update_coef_idx(codec, 0x4, 0, 1<<11); |
5198 | } | 5293 | } |
@@ -5610,9 +5705,9 @@ static void alc662_led_gpio1_mute_hook(void *private_data, int enabled) | |||
5610 | unsigned int oldval = spec->gpio_led; | 5705 | unsigned int oldval = spec->gpio_led; |
5611 | 5706 | ||
5612 | if (enabled) | 5707 | if (enabled) |
5613 | spec->gpio_led &= ~0x01; | ||
5614 | else | ||
5615 | spec->gpio_led |= 0x01; | 5708 | spec->gpio_led |= 0x01; |
5709 | else | ||
5710 | spec->gpio_led &= ~0x01; | ||
5616 | if (spec->gpio_led != oldval) | 5711 | if (spec->gpio_led != oldval) |
5617 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | 5712 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, |
5618 | spec->gpio_led); | 5713 | spec->gpio_led); |
@@ -5647,6 +5742,35 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec, | |||
5647 | } | 5742 | } |
5648 | } | 5743 | } |
5649 | 5744 | ||
5745 | static struct coef_fw alc668_coefs[] = { | ||
5746 | WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0), | ||
5747 | WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80), | ||
5748 | WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0), | ||
5749 | WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f), | ||
5750 | WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001), | ||
5751 | WRITE_COEF(0x13, 0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940), | ||
5752 | WRITE_COEF(0x19, 0x0), WRITE_COEF(0x1a, 0x0), WRITE_COEF(0x1b, 0x0), | ||
5753 | WRITE_COEF(0x1c, 0x0), WRITE_COEF(0x1d, 0x0), WRITE_COEF(0x1e, 0x7418), | ||
5754 | WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468), | ||
5755 | WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418), | ||
5756 | WRITE_COEF(0x27, 0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00), | ||
5757 | WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000), | ||
5758 | WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac, 0x0), | ||
5759 | WRITE_COEF(0xad, 0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480), | ||
5760 | WRITE_COEF(0xb0, 0x0), WRITE_COEF(0xb1, 0x0), WRITE_COEF(0xb2, 0x0), | ||
5761 | WRITE_COEF(0xb3, 0x0), WRITE_COEF(0xb4, 0x0), WRITE_COEF(0xb5, 0x1040), | ||
5762 | WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697), | ||
5763 | WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab), | ||
5764 | WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02), | ||
5765 | WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6), | ||
5766 | {} | ||
5767 | }; | ||
5768 | |||
5769 | static void alc668_restore_default_value(struct hda_codec *codec) | ||
5770 | { | ||
5771 | alc_process_coef_fw(codec, alc668_coefs); | ||
5772 | } | ||
5773 | |||
5650 | enum { | 5774 | enum { |
5651 | ALC662_FIXUP_ASPIRE, | 5775 | ALC662_FIXUP_ASPIRE, |
5652 | ALC662_FIXUP_LED_GPIO1, | 5776 | ALC662_FIXUP_LED_GPIO1, |
@@ -5919,6 +6043,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { | |||
5919 | SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 6043 | SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5920 | SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 6044 | SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5921 | SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 6045 | SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
6046 | SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | ||
5922 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), | 6047 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), |
5923 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), | 6048 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), |
5924 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), | 6049 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), |
@@ -6072,29 +6197,6 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { | |||
6072 | {} | 6197 | {} |
6073 | }; | 6198 | }; |
6074 | 6199 | ||
6075 | static void alc662_fill_coef(struct hda_codec *codec) | ||
6076 | { | ||
6077 | int coef; | ||
6078 | |||
6079 | coef = alc_get_coef0(codec); | ||
6080 | |||
6081 | switch (codec->vendor_id) { | ||
6082 | case 0x10ec0662: | ||
6083 | if ((coef & 0x00f0) == 0x0030) | ||
6084 | alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ | ||
6085 | break; | ||
6086 | case 0x10ec0272: | ||
6087 | case 0x10ec0273: | ||
6088 | case 0x10ec0663: | ||
6089 | case 0x10ec0665: | ||
6090 | case 0x10ec0670: | ||
6091 | case 0x10ec0671: | ||
6092 | case 0x10ec0672: | ||
6093 | alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ | ||
6094 | break; | ||
6095 | } | ||
6096 | } | ||
6097 | |||
6098 | /* | 6200 | /* |
6099 | */ | 6201 | */ |
6100 | static int patch_alc662(struct hda_codec *codec) | 6202 | static int patch_alc662(struct hda_codec *codec) |
@@ -6113,8 +6215,11 @@ static int patch_alc662(struct hda_codec *codec) | |||
6113 | 6215 | ||
6114 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | 6216 | alc_fix_pll_init(codec, 0x20, 0x04, 15); |
6115 | 6217 | ||
6116 | spec->init_hook = alc662_fill_coef; | 6218 | switch (codec->vendor_id) { |
6117 | alc662_fill_coef(codec); | 6219 | case 0x10ec0668: |
6220 | spec->init_hook = alc668_restore_default_value; | ||
6221 | break; | ||
6222 | } | ||
6118 | 6223 | ||
6119 | snd_hda_pick_fixup(codec, alc662_fixup_models, | 6224 | snd_hda_pick_fixup(codec, alc662_fixup_models, |
6120 | alc662_fixup_tbl, alc662_fixups); | 6225 | alc662_fixup_tbl, alc662_fixups); |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 0e9623368ab0..7d5d6444a837 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -49,7 +49,6 @@ source "sound/soc/mxs/Kconfig" | |||
49 | source "sound/soc/pxa/Kconfig" | 49 | source "sound/soc/pxa/Kconfig" |
50 | source "sound/soc/rockchip/Kconfig" | 50 | source "sound/soc/rockchip/Kconfig" |
51 | source "sound/soc/samsung/Kconfig" | 51 | source "sound/soc/samsung/Kconfig" |
52 | source "sound/soc/s6000/Kconfig" | ||
53 | source "sound/soc/sh/Kconfig" | 52 | source "sound/soc/sh/Kconfig" |
54 | source "sound/soc/sirf/Kconfig" | 53 | source "sound/soc/sirf/Kconfig" |
55 | source "sound/soc/spear/Kconfig" | 54 | source "sound/soc/spear/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 0fded1bb613f..865e090c8061 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o |
3 | 3 | ||
4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) | 4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) |
5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o | 5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o |
@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += kirkwood/ | |||
30 | obj-$(CONFIG_SND_SOC) += pxa/ | 30 | obj-$(CONFIG_SND_SOC) += pxa/ |
31 | obj-$(CONFIG_SND_SOC) += rockchip/ | 31 | obj-$(CONFIG_SND_SOC) += rockchip/ |
32 | obj-$(CONFIG_SND_SOC) += samsung/ | 32 | obj-$(CONFIG_SND_SOC) += samsung/ |
33 | obj-$(CONFIG_SND_SOC) += s6000/ | ||
34 | obj-$(CONFIG_SND_SOC) += sh/ | 33 | obj-$(CONFIG_SND_SOC) += sh/ |
35 | obj-$(CONFIG_SND_SOC) += sirf/ | 34 | obj-$(CONFIG_SND_SOC) += sirf/ |
36 | obj-$(CONFIG_SND_SOC) += spear/ | 35 | obj-$(CONFIG_SND_SOC) += spear/ |
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 6844d0b2af68..387530b0b0fd 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = { | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | 74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { |
75 | SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), | 75 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), |
76 | SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0), | ||
76 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), | 77 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), |
77 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), | 78 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), |
78 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), | 79 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), |
79 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), | 80 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), |
81 | SND_SOC_DAPM_VMID("VMID"), | ||
80 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | 82 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), |
81 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | 83 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), |
82 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), | 84 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), |
@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | |||
87 | 89 | ||
88 | static const struct snd_soc_dapm_route audio_paths[] = { | 90 | static const struct snd_soc_dapm_route audio_paths[] = { |
89 | { "DAC", NULL, "SYSCLK" }, | 91 | { "DAC", NULL, "SYSCLK" }, |
92 | { "DAC Output", NULL, "DAC" }, | ||
93 | { "DAC Output", NULL, "VMID" }, | ||
90 | { "ADC", NULL, "SYSCLK" }, | 94 | { "ADC", NULL, "SYSCLK" }, |
91 | { "DAC", NULL, "ADC_PWR" }, | 95 | { "DAC", NULL, "ADC_PWR" }, |
92 | { "ADC", NULL, "ADC_PWR" }, | 96 | { "ADC", NULL, "ADC_PWR" }, |
93 | { "DAC1OUT", NULL, "DAC" }, | 97 | { "DAC1OUT", NULL, "DAC Output" }, |
94 | { "DAC2OUT", NULL, "DAC" }, | 98 | { "DAC2OUT", NULL, "DAC Output" }, |
95 | { "DAC3OUT", NULL, "DAC" }, | 99 | { "DAC3OUT", NULL, "DAC Output" }, |
96 | { "DAC4OUT", NULL, "DAC" }, | 100 | { "DAC4OUT", NULL, "DAC Output" }, |
97 | { "ADC", NULL, "ADC1IN" }, | 101 | { "ADC", NULL, "ADC1IN" }, |
98 | { "ADC", NULL, "ADC2IN" }, | 102 | { "ADC", NULL, "ADC2IN" }, |
99 | { "SYSCLK", NULL, "PLL_PWR" }, | 103 | { "SYSCLK", NULL, "PLL_PWR" }, |
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 7c784ad3e8b2..783dcb57043a 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = { | |||
551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, | 551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, |
552 | struct snd_kcontrol *kcontrol, int event) | 552 | struct snd_kcontrol *kcontrol, int event) |
553 | { | 553 | { |
554 | struct snd_soc_codec *codec = w->codec; | 554 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
556 | unsigned int pll_id = w->name[3] - '1'; | 556 | unsigned int pll_id = w->name[3] - '1'; |
557 | unsigned int val; | 557 | unsigned int val; |
@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { | |||
823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | 823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, |
824 | struct snd_soc_dapm_widget *sink) | 824 | struct snd_soc_dapm_widget *sink) |
825 | { | 825 | { |
826 | struct snd_soc_codec *codec = source->codec; | 826 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
828 | unsigned int dai; | 828 | unsigned int dai; |
829 | const char *clk; | 829 | const char *clk; |
@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | |||
844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, | 844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, |
845 | struct snd_soc_dapm_widget *sink) | 845 | struct snd_soc_dapm_widget *sink) |
846 | { | 846 | { |
847 | struct snd_soc_codec *codec = source->codec; | 847 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
849 | unsigned int dai; | 849 | unsigned int dai; |
850 | 850 | ||
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 5518ebd6947c..16093dc89441 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c | |||
@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control = | |||
255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, | 255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, |
256 | struct snd_kcontrol *kcontrol, int event) | 256 | struct snd_kcontrol *kcontrol, int event) |
257 | { | 257 | { |
258 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 258 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
259 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
259 | 260 | ||
260 | /* After any power changes have been made the dejitter circuit | 261 | /* After any power changes have been made the dejitter circuit |
261 | * has to be reinitialized. */ | 262 | * has to be reinitialized. */ |
@@ -405,6 +406,7 @@ static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = { | |||
405 | 2, 0, NULL, 0), | 406 | 2, 0, NULL, 0), |
406 | 407 | ||
407 | SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0), | 408 | SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0), |
409 | SND_SOC_DAPM_SUPPLY("ALC Clock", ADAU1761_CLK_ENABLE0, 5, 0, NULL, 0), | ||
408 | 410 | ||
409 | SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1, | 411 | SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1, |
410 | 0, 0, NULL, 0), | 412 | 0, 0, NULL, 0), |
@@ -436,6 +438,9 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = { | |||
436 | { "Right Playback Mixer", NULL, "Slew Clock" }, | 438 | { "Right Playback Mixer", NULL, "Slew Clock" }, |
437 | { "Left Playback Mixer", NULL, "Slew Clock" }, | 439 | { "Left Playback Mixer", NULL, "Slew Clock" }, |
438 | 440 | ||
441 | { "Left Input Mixer", NULL, "ALC Clock" }, | ||
442 | { "Right Input Mixer", NULL, "ALC Clock" }, | ||
443 | |||
439 | { "Digital Clock 0", NULL, "SYSCLK" }, | 444 | { "Digital Clock 0", NULL, "SYSCLK" }, |
440 | { "Digital Clock 1", NULL, "SYSCLK" }, | 445 | { "Digital Clock 1", NULL, "SYSCLK" }, |
441 | }; | 446 | }; |
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index e9fc00fb13dd..aa6a37cc44b7 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c | |||
@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = { | |||
174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, | 174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, |
175 | struct snd_kcontrol *kcontrol, int event) | 175 | struct snd_kcontrol *kcontrol, int event) |
176 | { | 176 | { |
177 | struct snd_soc_codec *codec = w->codec; | 177 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
179 | 179 | ||
180 | /* After any power changes have been made the dejitter circuit | 180 | /* After any power changes have been made the dejitter circuit |
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 3e16c1c64115..427ad77bfe56 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { | |||
61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, | 61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, |
62 | struct snd_kcontrol *kcontrol, int event) | 62 | struct snd_kcontrol *kcontrol, int event) |
63 | { | 63 | { |
64 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 64 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
65 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
65 | int ret; | 66 | int ret; |
66 | 67 | ||
67 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 68 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index cee51ae177c1..c40428f25ba5 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c | |||
@@ -46,6 +46,7 @@ static struct i2c_driver cs42l51_i2c_driver = { | |||
46 | .driver = { | 46 | .driver = { |
47 | .name = "cs42l51", | 47 | .name = "cs42l51", |
48 | .owner = THIS_MODULE, | 48 | .owner = THIS_MODULE, |
49 | .of_match_table = cs42l51_of_match, | ||
49 | }, | 50 | }, |
50 | .probe = cs42l51_i2c_probe, | 51 | .probe = cs42l51_i2c_probe, |
51 | .remove = cs42l51_i2c_remove, | 52 | .remove = cs42l51_i2c_remove, |
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 09488d97de60..669c38fc3034 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -558,11 +558,13 @@ error: | |||
558 | } | 558 | } |
559 | EXPORT_SYMBOL_GPL(cs42l51_probe); | 559 | EXPORT_SYMBOL_GPL(cs42l51_probe); |
560 | 560 | ||
561 | static const struct of_device_id cs42l51_of_match[] = { | 561 | const struct of_device_id cs42l51_of_match[] = { |
562 | { .compatible = "cirrus,cs42l51", }, | 562 | { .compatible = "cirrus,cs42l51", }, |
563 | { } | 563 | { } |
564 | }; | 564 | }; |
565 | MODULE_DEVICE_TABLE(of, cs42l51_of_match); | 565 | MODULE_DEVICE_TABLE(of, cs42l51_of_match); |
566 | EXPORT_SYMBOL_GPL(cs42l51_of_match); | ||
567 | |||
566 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | 568 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); |
567 | MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); | 569 | MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); |
568 | MODULE_LICENSE("GPL"); | 570 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h index 8c55bf384bc6..0ca805492ac4 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h | |||
@@ -22,6 +22,7 @@ struct device; | |||
22 | 22 | ||
23 | extern const struct regmap_config cs42l51_regmap; | 23 | extern const struct regmap_config cs42l51_regmap; |
24 | int cs42l51_probe(struct device *dev, struct regmap *regmap); | 24 | int cs42l51_probe(struct device *dev, struct regmap *regmap); |
25 | extern const struct of_device_id cs42l51_of_match[]; | ||
25 | 26 | ||
26 | #define CS42L51_CHIP_ID 0x1B | 27 | #define CS42L51_CHIP_ID 0x1B |
27 | #define CS42L51_CHIP_REV_A 0x00 | 28 | #define CS42L51_CHIP_REV_A 0x00 |
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c index aae410d122ee..2d05b5d3a6ce 100644 --- a/sound/soc/codecs/es8328-i2c.c +++ b/sound/soc/codecs/es8328-i2c.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "es8328.h" | 19 | #include "es8328.h" |
20 | 20 | ||
21 | static const struct i2c_device_id es8328_id[] = { | 21 | static const struct i2c_device_id es8328_id[] = { |
22 | { "everest,es8328", 0 }, | 22 | { "es8328", 0 }, |
23 | { } | 23 | { } |
24 | }; | 24 | }; |
25 | MODULE_DEVICE_TABLE(i2c, es8328_id); | 25 | MODULE_DEVICE_TABLE(i2c, es8328_id); |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index d519294f57c7..34ed9a91f392 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1311 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
1312 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
1313 | 1313 | ||
1314 | {"DMICL", NULL, "DMICL_ENA"}, | ||
1315 | {"DMICL", NULL, "DMICR_ENA"}, | ||
1316 | {"DMICR", NULL, "DMICL_ENA"}, | ||
1317 | {"DMICR", NULL, "DMICR_ENA"}, | ||
1314 | {"DMICL", NULL, "AHPF"}, | 1318 | {"DMICL", NULL, "AHPF"}, |
1315 | {"DMICR", NULL, "AHPF"}, | 1319 | {"DMICR", NULL, "AHPF"}, |
1316 | 1320 | ||
@@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1368 | {"DMIC Mux", "ADC", "ADCR"}, | 1372 | {"DMIC Mux", "ADC", "ADCR"}, |
1369 | {"DMIC Mux", "DMIC", "DMICL"}, | 1373 | {"DMIC Mux", "DMIC", "DMICL"}, |
1370 | {"DMIC Mux", "DMIC", "DMICR"}, | 1374 | {"DMIC Mux", "DMIC", "DMICR"}, |
1371 | {"DMIC Mux", "DMIC", "DMICL_ENA"}, | ||
1372 | {"DMIC Mux", "DMIC", "DMICR_ENA"}, | ||
1373 | 1375 | ||
1374 | {"LBENL Mux", "Normal", "DMIC Mux"}, | 1376 | {"LBENL Mux", "Normal", "DMIC Mux"}, |
1375 | {"LBENL Mux", "Loopback", "LTENL Mux"}, | 1377 | {"LBENL Mux", "Loopback", "LTENL Mux"}, |
@@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1395 | {"STENL Mux", "Sidetone Left", "DMICL"}, | 1397 | {"STENL Mux", "Sidetone Left", "DMICL"}, |
1396 | {"STENR Mux", "Sidetone Right", "ADCR"}, | 1398 | {"STENR Mux", "Sidetone Right", "ADCR"}, |
1397 | {"STENR Mux", "Sidetone Right", "DMICR"}, | 1399 | {"STENR Mux", "Sidetone Right", "DMICR"}, |
1398 | {"DACL", "NULL", "STENL Mux"}, | 1400 | {"DACL", NULL, "STENL Mux"}, |
1399 | {"DACR", "NULL", "STENL Mux"}, | 1401 | {"DACR", NULL, "STENR Mux"}, |
1400 | 1402 | ||
1401 | {"AIFINL", NULL, "SHDN"}, | 1403 | {"AIFINL", NULL, "SHDN"}, |
1402 | {"AIFINR", NULL, "SHDN"}, | 1404 | {"AIFINR", NULL, "SHDN"}, |
@@ -1941,13 +1943,13 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1941 | * 0x02 (when master clk is 20MHz to 40MHz).. | 1943 | * 0x02 (when master clk is 20MHz to 40MHz).. |
1942 | * 0x03 (when master clk is 40MHz to 60MHz).. | 1944 | * 0x03 (when master clk is 40MHz to 60MHz).. |
1943 | */ | 1945 | */ |
1944 | if ((freq >= 10000000) && (freq < 20000000)) { | 1946 | if ((freq >= 10000000) && (freq <= 20000000)) { |
1945 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 1947 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1946 | M98090_PSCLK_DIV1); | 1948 | M98090_PSCLK_DIV1); |
1947 | } else if ((freq >= 20000000) && (freq < 40000000)) { | 1949 | } else if ((freq > 20000000) && (freq <= 40000000)) { |
1948 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 1950 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1949 | M98090_PSCLK_DIV2); | 1951 | M98090_PSCLK_DIV2); |
1950 | } else if ((freq >= 40000000) && (freq < 60000000)) { | 1952 | } else if ((freq > 40000000) && (freq <= 60000000)) { |
1951 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 1953 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1952 | M98090_PSCLK_DIV4); | 1954 | M98090_PSCLK_DIV4); |
1953 | } else { | 1955 | } else { |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3fb83bf09768..d16331e0b64d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -139,6 +139,7 @@ static const struct reg_default rt5645_reg[] = { | |||
139 | { 0x76, 0x000a }, | 139 | { 0x76, 0x000a }, |
140 | { 0x77, 0x0c00 }, | 140 | { 0x77, 0x0c00 }, |
141 | { 0x78, 0x0000 }, | 141 | { 0x78, 0x0000 }, |
142 | { 0x79, 0x0123 }, | ||
142 | { 0x80, 0x0000 }, | 143 | { 0x80, 0x0000 }, |
143 | { 0x81, 0x0000 }, | 144 | { 0x81, 0x0000 }, |
144 | { 0x82, 0x0000 }, | 145 | { 0x82, 0x0000 }, |
@@ -334,6 +335,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) | |||
334 | case RT5645_DMIC_CTRL2: | 335 | case RT5645_DMIC_CTRL2: |
335 | case RT5645_TDM_CTRL_1: | 336 | case RT5645_TDM_CTRL_1: |
336 | case RT5645_TDM_CTRL_2: | 337 | case RT5645_TDM_CTRL_2: |
338 | case RT5645_TDM_CTRL_3: | ||
337 | case RT5645_GLB_CLK: | 339 | case RT5645_GLB_CLK: |
338 | case RT5645_PLL_CTRL1: | 340 | case RT5645_PLL_CTRL1: |
339 | case RT5645_PLL_CTRL2: | 341 | case RT5645_PLL_CTRL2: |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index ba9d9b4d4857..9bd8b4f63303 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -100,18 +100,18 @@ static const struct reg_default rt5670_reg[] = { | |||
100 | { 0x4c, 0x5380 }, | 100 | { 0x4c, 0x5380 }, |
101 | { 0x4f, 0x0073 }, | 101 | { 0x4f, 0x0073 }, |
102 | { 0x52, 0x00d3 }, | 102 | { 0x52, 0x00d3 }, |
103 | { 0x53, 0xf0f0 }, | 103 | { 0x53, 0xf000 }, |
104 | { 0x61, 0x0000 }, | 104 | { 0x61, 0x0000 }, |
105 | { 0x62, 0x0001 }, | 105 | { 0x62, 0x0001 }, |
106 | { 0x63, 0x00c3 }, | 106 | { 0x63, 0x00c3 }, |
107 | { 0x64, 0x0000 }, | 107 | { 0x64, 0x0000 }, |
108 | { 0x65, 0x0000 }, | 108 | { 0x65, 0x0001 }, |
109 | { 0x66, 0x0000 }, | 109 | { 0x66, 0x0000 }, |
110 | { 0x6f, 0x8000 }, | 110 | { 0x6f, 0x8000 }, |
111 | { 0x70, 0x8000 }, | 111 | { 0x70, 0x8000 }, |
112 | { 0x71, 0x8000 }, | 112 | { 0x71, 0x8000 }, |
113 | { 0x72, 0x8000 }, | 113 | { 0x72, 0x8000 }, |
114 | { 0x73, 0x1110 }, | 114 | { 0x73, 0x7770 }, |
115 | { 0x74, 0x0e00 }, | 115 | { 0x74, 0x0e00 }, |
116 | { 0x75, 0x1505 }, | 116 | { 0x75, 0x1505 }, |
117 | { 0x76, 0x0015 }, | 117 | { 0x76, 0x0015 }, |
@@ -125,21 +125,21 @@ static const struct reg_default rt5670_reg[] = { | |||
125 | { 0x83, 0x0000 }, | 125 | { 0x83, 0x0000 }, |
126 | { 0x84, 0x0000 }, | 126 | { 0x84, 0x0000 }, |
127 | { 0x85, 0x0000 }, | 127 | { 0x85, 0x0000 }, |
128 | { 0x86, 0x0008 }, | 128 | { 0x86, 0x0004 }, |
129 | { 0x87, 0x0000 }, | 129 | { 0x87, 0x0000 }, |
130 | { 0x88, 0x0000 }, | 130 | { 0x88, 0x0000 }, |
131 | { 0x89, 0x0000 }, | 131 | { 0x89, 0x0000 }, |
132 | { 0x8a, 0x0000 }, | 132 | { 0x8a, 0x0000 }, |
133 | { 0x8b, 0x0000 }, | 133 | { 0x8b, 0x0000 }, |
134 | { 0x8c, 0x0007 }, | 134 | { 0x8c, 0x0003 }, |
135 | { 0x8d, 0x0000 }, | 135 | { 0x8d, 0x0000 }, |
136 | { 0x8e, 0x0004 }, | 136 | { 0x8e, 0x0004 }, |
137 | { 0x8f, 0x1100 }, | 137 | { 0x8f, 0x1100 }, |
138 | { 0x90, 0x0646 }, | 138 | { 0x90, 0x0646 }, |
139 | { 0x91, 0x0c06 }, | 139 | { 0x91, 0x0c06 }, |
140 | { 0x93, 0x0000 }, | 140 | { 0x93, 0x0000 }, |
141 | { 0x94, 0x0000 }, | 141 | { 0x94, 0x1270 }, |
142 | { 0x95, 0x0000 }, | 142 | { 0x95, 0x1000 }, |
143 | { 0x97, 0x0000 }, | 143 | { 0x97, 0x0000 }, |
144 | { 0x98, 0x0000 }, | 144 | { 0x98, 0x0000 }, |
145 | { 0x99, 0x0000 }, | 145 | { 0x99, 0x0000 }, |
@@ -150,11 +150,11 @@ static const struct reg_default rt5670_reg[] = { | |||
150 | { 0x9e, 0x0400 }, | 150 | { 0x9e, 0x0400 }, |
151 | { 0xae, 0x7000 }, | 151 | { 0xae, 0x7000 }, |
152 | { 0xaf, 0x0000 }, | 152 | { 0xaf, 0x0000 }, |
153 | { 0xb0, 0x6000 }, | 153 | { 0xb0, 0x7000 }, |
154 | { 0xb1, 0x0000 }, | 154 | { 0xb1, 0x0000 }, |
155 | { 0xb2, 0x0000 }, | 155 | { 0xb2, 0x0000 }, |
156 | { 0xb3, 0x001f }, | 156 | { 0xb3, 0x001f }, |
157 | { 0xb4, 0x2206 }, | 157 | { 0xb4, 0x220c }, |
158 | { 0xb5, 0x1f00 }, | 158 | { 0xb5, 0x1f00 }, |
159 | { 0xb6, 0x0000 }, | 159 | { 0xb6, 0x0000 }, |
160 | { 0xb7, 0x0000 }, | 160 | { 0xb7, 0x0000 }, |
@@ -171,25 +171,25 @@ static const struct reg_default rt5670_reg[] = { | |||
171 | { 0xcf, 0x1813 }, | 171 | { 0xcf, 0x1813 }, |
172 | { 0xd0, 0x0690 }, | 172 | { 0xd0, 0x0690 }, |
173 | { 0xd1, 0x1c17 }, | 173 | { 0xd1, 0x1c17 }, |
174 | { 0xd3, 0xb320 }, | 174 | { 0xd3, 0xa220 }, |
175 | { 0xd4, 0x0000 }, | 175 | { 0xd4, 0x0000 }, |
176 | { 0xd6, 0x0400 }, | 176 | { 0xd6, 0x0400 }, |
177 | { 0xd9, 0x0809 }, | 177 | { 0xd9, 0x0809 }, |
178 | { 0xda, 0x0000 }, | 178 | { 0xda, 0x0000 }, |
179 | { 0xdb, 0x0001 }, | 179 | { 0xdb, 0x0001 }, |
180 | { 0xdc, 0x0049 }, | 180 | { 0xdc, 0x0049 }, |
181 | { 0xdd, 0x0009 }, | 181 | { 0xdd, 0x0024 }, |
182 | { 0xe6, 0x8000 }, | 182 | { 0xe6, 0x8000 }, |
183 | { 0xe7, 0x0000 }, | 183 | { 0xe7, 0x0000 }, |
184 | { 0xec, 0xb300 }, | 184 | { 0xec, 0xa200 }, |
185 | { 0xed, 0x0000 }, | 185 | { 0xed, 0x0000 }, |
186 | { 0xee, 0xb300 }, | 186 | { 0xee, 0xa200 }, |
187 | { 0xef, 0x0000 }, | 187 | { 0xef, 0x0000 }, |
188 | { 0xf8, 0x0000 }, | 188 | { 0xf8, 0x0000 }, |
189 | { 0xf9, 0x0000 }, | 189 | { 0xf9, 0x0000 }, |
190 | { 0xfa, 0x8010 }, | 190 | { 0xfa, 0x8010 }, |
191 | { 0xfb, 0x0033 }, | 191 | { 0xfb, 0x0033 }, |
192 | { 0xfc, 0x0080 }, | 192 | { 0xfc, 0x0100 }, |
193 | }; | 193 | }; |
194 | 194 | ||
195 | static bool rt5670_volatile_register(struct device *dev, unsigned int reg) | 195 | static bool rt5670_volatile_register(struct device *dev, unsigned int reg) |
@@ -1877,6 +1877,10 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1877 | { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, | 1877 | { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, |
1878 | { "DAC1 MIXR", NULL, "DAC Stereo1 Filter" }, | 1878 | { "DAC1 MIXR", NULL, "DAC Stereo1 Filter" }, |
1879 | 1879 | ||
1880 | { "DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1881 | { "DAC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1882 | { "DAC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1883 | |||
1880 | { "DAC MIX", NULL, "DAC1 MIXL" }, | 1884 | { "DAC MIX", NULL, "DAC1 MIXL" }, |
1881 | { "DAC MIX", NULL, "DAC1 MIXR" }, | 1885 | { "DAC MIX", NULL, "DAC1 MIXR" }, |
1882 | 1886 | ||
@@ -1926,14 +1930,10 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1926 | 1930 | ||
1927 | { "DAC L1", NULL, "DAC L1 Power" }, | 1931 | { "DAC L1", NULL, "DAC L1 Power" }, |
1928 | { "DAC L1", NULL, "Stereo DAC MIXL" }, | 1932 | { "DAC L1", NULL, "Stereo DAC MIXL" }, |
1929 | { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1930 | { "DAC R1", NULL, "DAC R1 Power" }, | 1933 | { "DAC R1", NULL, "DAC R1 Power" }, |
1931 | { "DAC R1", NULL, "Stereo DAC MIXR" }, | 1934 | { "DAC R1", NULL, "Stereo DAC MIXR" }, |
1932 | { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1933 | { "DAC L2", NULL, "Mono DAC MIXL" }, | 1935 | { "DAC L2", NULL, "Mono DAC MIXL" }, |
1934 | { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1935 | { "DAC R2", NULL, "Mono DAC MIXR" }, | 1936 | { "DAC R2", NULL, "Mono DAC MIXR" }, |
1936 | { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, | ||
1937 | 1937 | ||
1938 | { "OUT MIXL", "BST1 Switch", "BST1" }, | 1938 | { "OUT MIXL", "BST1 Switch", "BST1" }, |
1939 | { "OUT MIXL", "INL Switch", "INL VOL" }, | 1939 | { "OUT MIXL", "INL Switch", "INL VOL" }, |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 6bb77d76561b..dab9b15304af 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -1299,8 +1299,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1299 | 1299 | ||
1300 | /* enable small pop, introduce 400ms delay in turning off */ | 1300 | /* enable small pop, introduce 400ms delay in turning off */ |
1301 | snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, | 1301 | snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, |
1302 | SGTL5000_SMALL_POP, | 1302 | SGTL5000_SMALL_POP, 1); |
1303 | SGTL5000_SMALL_POP); | ||
1304 | 1303 | ||
1305 | /* disable short cut detector */ | 1304 | /* disable short cut detector */ |
1306 | snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0); | 1305 | snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0); |
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 2f8c88931f69..bd7a344bf8c5 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h | |||
@@ -275,7 +275,7 @@ | |||
275 | #define SGTL5000_BIAS_CTRL_MASK 0x000e | 275 | #define SGTL5000_BIAS_CTRL_MASK 0x000e |
276 | #define SGTL5000_BIAS_CTRL_SHIFT 1 | 276 | #define SGTL5000_BIAS_CTRL_SHIFT 1 |
277 | #define SGTL5000_BIAS_CTRL_WIDTH 3 | 277 | #define SGTL5000_BIAS_CTRL_WIDTH 3 |
278 | #define SGTL5000_SMALL_POP 0x0001 | 278 | #define SGTL5000_SMALL_POP 0 |
279 | 279 | ||
280 | /* | 280 | /* |
281 | * SGTL5000_CHIP_MIC_CTRL | 281 | * SGTL5000_CHIP_MIC_CTRL |
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index f2de7e049bc6..81a38dd9af1f 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c | |||
@@ -159,6 +159,13 @@ int _process_sigma_firmware(struct device *dev, | |||
159 | goto done; | 159 | goto done; |
160 | } | 160 | } |
161 | 161 | ||
162 | if (ssfw_head->version != 1) { | ||
163 | dev_err(dev, | ||
164 | "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", | ||
165 | ssfw_head->version); | ||
166 | goto done; | ||
167 | } | ||
168 | |||
162 | crc = crc32(0, fw->data + sizeof(*ssfw_head), | 169 | crc = crc32(0, fw->data + sizeof(*ssfw_head), |
163 | fw->size - sizeof(*ssfw_head)); | 170 | fw->size - sizeof(*ssfw_head)); |
164 | pr_debug("%s: crc=%x\n", __func__, crc); | 171 | pr_debug("%s: crc=%x\n", __func__, crc); |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 145fe5b253d4..93de5dd0a7b9 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -911,12 +911,13 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
911 | } | 911 | } |
912 | aic31xx->p_div = i; | 912 | aic31xx->p_div = i; |
913 | 913 | ||
914 | for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { | 914 | for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && |
915 | if (i == ARRAY_SIZE(aic31xx_divs)) { | 915 | aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) |
916 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", | 916 | ; |
917 | __func__, freq); | 917 | if (i == ARRAY_SIZE(aic31xx_divs)) { |
918 | return -EINVAL; | 918 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", |
919 | } | 919 | __func__, freq); |
920 | return -EINVAL; | ||
920 | } | 921 | } |
921 | 922 | ||
922 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ | 923 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f412a9911a75..cce9020933c6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -1355,6 +1355,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
1355 | file, blocks, pos - firmware->size); | 1355 | file, blocks, pos - firmware->size); |
1356 | 1356 | ||
1357 | out_fw: | 1357 | out_fw: |
1358 | regmap_async_complete(regmap); | ||
1358 | release_firmware(firmware); | 1359 | release_firmware(firmware); |
1359 | wm_adsp_buf_free(&buf_list); | 1360 | wm_adsp_buf_free(&buf_list); |
1360 | out: | 1361 | out: |
@@ -1594,13 +1595,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) | |||
1594 | if (ret != 0) | 1595 | if (ret != 0) |
1595 | goto err; | 1596 | goto err; |
1596 | 1597 | ||
1597 | ret = regmap_update_bits_async(dsp->regmap, | ||
1598 | dsp->base + ADSP2_CONTROL, | ||
1599 | ADSP2_CORE_ENA, | ||
1600 | ADSP2_CORE_ENA); | ||
1601 | if (ret != 0) | ||
1602 | goto err; | ||
1603 | |||
1604 | dsp->running = true; | 1598 | dsp->running = true; |
1605 | 1599 | ||
1606 | return; | 1600 | return; |
@@ -1650,8 +1644,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1650 | 1644 | ||
1651 | ret = regmap_update_bits(dsp->regmap, | 1645 | ret = regmap_update_bits(dsp->regmap, |
1652 | dsp->base + ADSP2_CONTROL, | 1646 | dsp->base + ADSP2_CONTROL, |
1653 | ADSP2_START, | 1647 | ADSP2_CORE_ENA | ADSP2_START, |
1654 | ADSP2_START); | 1648 | ADSP2_CORE_ENA | ADSP2_START); |
1655 | if (ret != 0) | 1649 | if (ret != 0) |
1656 | goto err; | 1650 | goto err; |
1657 | break; | 1651 | break; |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0eed9b1b24e1..ea3ad747d092 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -154,9 +154,9 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) | |||
154 | 154 | ||
155 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 155 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) |
156 | { | 156 | { |
157 | /* Start clocks */ | ||
157 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); | 158 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); |
158 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); | 159 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); |
159 | |||
160 | /* | 160 | /* |
161 | * When ASYNC == 0 the transmit and receive sections operate | 161 | * When ASYNC == 0 the transmit and receive sections operate |
162 | * synchronously from the transmit clock and frame sync. We need to make | 162 | * synchronously from the transmit clock and frame sync. We need to make |
@@ -167,47 +167,36 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) | |||
167 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 167 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
168 | } | 168 | } |
169 | 169 | ||
170 | /* Activate serializer(s) */ | ||
170 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); | 171 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); |
171 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | 172 | /* Release RX state machine */ |
172 | |||
173 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | ||
174 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | ||
175 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | ||
176 | |||
177 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 173 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); |
174 | /* Release Frame Sync generator */ | ||
178 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 175 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); |
179 | |||
180 | if (mcasp_is_synchronous(mcasp)) | 176 | if (mcasp_is_synchronous(mcasp)) |
181 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 177 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); |
182 | } | 178 | } |
183 | 179 | ||
184 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 180 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) |
185 | { | 181 | { |
186 | u8 offset = 0, i; | ||
187 | u32 cnt; | 182 | u32 cnt; |
188 | 183 | ||
184 | /* Start clocks */ | ||
189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 185 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); |
190 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 186 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
187 | /* Activate serializer(s) */ | ||
191 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); | 188 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); |
192 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
193 | 189 | ||
194 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 190 | /* wait for XDATA to be cleared */ |
195 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
196 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
197 | for (i = 0; i < mcasp->num_serializer; i++) { | ||
198 | if (mcasp->serial_dir[i] == TX_MODE) { | ||
199 | offset = i; | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* wait for TX ready */ | ||
205 | cnt = 0; | 191 | cnt = 0; |
206 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) & | 192 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & |
207 | TXSTATE) && (cnt < 100000)) | 193 | ~XRDATA) && (cnt < 100000)) |
208 | cnt++; | 194 | cnt++; |
209 | 195 | ||
210 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 196 | /* Release TX state machine */ |
197 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | ||
198 | /* Release Frame Sync generator */ | ||
199 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
211 | } | 200 | } |
212 | 201 | ||
213 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | 202 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) |
@@ -244,6 +233,12 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | |||
244 | 233 | ||
245 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); | 234 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); |
246 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 235 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); |
236 | |||
237 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
238 | u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
239 | |||
240 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
241 | } | ||
247 | } | 242 | } |
248 | 243 | ||
249 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | 244 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) |
@@ -259,27 +254,22 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
259 | 254 | ||
260 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); | 255 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); |
261 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 256 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); |
257 | |||
258 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
259 | u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
260 | |||
261 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
262 | } | ||
262 | } | 263 | } |
263 | 264 | ||
264 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | 265 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) |
265 | { | 266 | { |
266 | u32 reg; | ||
267 | |||
268 | mcasp->streams--; | 267 | mcasp->streams--; |
269 | 268 | ||
270 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 269 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
271 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
272 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
273 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
274 | } | ||
275 | mcasp_stop_tx(mcasp); | 270 | mcasp_stop_tx(mcasp); |
276 | } else { | 271 | else |
277 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
278 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
279 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
280 | } | ||
281 | mcasp_stop_rx(mcasp); | 272 | mcasp_stop_rx(mcasp); |
282 | } | ||
283 | } | 273 | } |
284 | 274 | ||
285 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 275 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
@@ -500,8 +490,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
500 | * both left and right channels), so it has to be divided by number of | 490 | * both left and right channels), so it has to be divided by number of |
501 | * tdm-slots (for I2S - divided by 2). | 491 | * tdm-slots (for I2S - divided by 2). |
502 | */ | 492 | */ |
503 | if (mcasp->bclk_lrclk_ratio) | 493 | if (mcasp->bclk_lrclk_ratio) { |
504 | word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; | 494 | u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; |
495 | |||
496 | /* | ||
497 | * When we have more bclk then it is needed for the data, we | ||
498 | * need to use the rotation to move the received samples to have | ||
499 | * correct alignment. | ||
500 | */ | ||
501 | rx_rotate = (slot_length - word_length) / 4; | ||
502 | word_length = slot_length; | ||
503 | } | ||
505 | 504 | ||
506 | /* mapping of the XSSZ bit-field as described in the datasheet */ | 505 | /* mapping of the XSSZ bit-field as described in the datasheet */ |
507 | fmt = (word_length >> 1) - 1; | 506 | fmt = (word_length >> 1) - 1; |
@@ -971,6 +970,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | |||
971 | }, | 970 | }, |
972 | .ops = &davinci_mcasp_dai_ops, | 971 | .ops = &davinci_mcasp_dai_ops, |
973 | 972 | ||
973 | .symmetric_samplebits = 1, | ||
974 | }, | 974 | }, |
975 | { | 975 | { |
976 | .name = "davinci-mcasp.1", | 976 | .name = "davinci-mcasp.1", |
@@ -1235,6 +1235,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1235 | ret = pm_runtime_get_sync(&pdev->dev); | 1235 | ret = pm_runtime_get_sync(&pdev->dev); |
1236 | if (IS_ERR_VALUE(ret)) { | 1236 | if (IS_ERR_VALUE(ret)) { |
1237 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); | 1237 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); |
1238 | pm_runtime_disable(&pdev->dev); | ||
1238 | return ret; | 1239 | return ret; |
1239 | } | 1240 | } |
1240 | 1241 | ||
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 98fbc451892a..9737108f0305 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -253,6 +253,12 @@ | |||
253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ | 253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ |
254 | 254 | ||
255 | /* | 255 | /* |
256 | * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits | ||
257 | * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits | ||
258 | */ | ||
259 | #define XRDATA BIT(5) /* Transmit/Receive data ready */ | ||
260 | |||
261 | /* | ||
256 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits | 262 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits |
257 | */ | 263 | */ |
258 | #define MUTENA(val) (val) | 264 | #define MUTENA(val) (val) |
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 3b145313f93e..9deabdd2b1a2 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c | |||
@@ -684,12 +684,38 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) | |||
684 | } | 684 | } |
685 | } | 685 | } |
686 | 686 | ||
687 | static struct reg_default fsl_asrc_reg[] = { | ||
688 | { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, | ||
689 | { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, | ||
690 | { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, | ||
691 | { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, | ||
692 | { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, | ||
693 | { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, | ||
694 | { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, | ||
695 | { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, | ||
696 | { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, | ||
697 | { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, | ||
698 | { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, | ||
699 | { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, | ||
700 | { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, | ||
701 | { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, | ||
702 | { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, | ||
703 | { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, | ||
704 | { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, | ||
705 | { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, | ||
706 | { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, | ||
707 | { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, | ||
708 | { REG_ASRMCR1C, 0x0000 }, | ||
709 | }; | ||
710 | |||
687 | static const struct regmap_config fsl_asrc_regmap_config = { | 711 | static const struct regmap_config fsl_asrc_regmap_config = { |
688 | .reg_bits = 32, | 712 | .reg_bits = 32, |
689 | .reg_stride = 4, | 713 | .reg_stride = 4, |
690 | .val_bits = 32, | 714 | .val_bits = 32, |
691 | 715 | ||
692 | .max_register = REG_ASRMCR1C, | 716 | .max_register = REG_ASRMCR1C, |
717 | .reg_defaults = fsl_asrc_reg, | ||
718 | .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), | ||
693 | .readable_reg = fsl_asrc_readable_reg, | 719 | .readable_reg = fsl_asrc_readable_reg, |
694 | .volatile_reg = fsl_asrc_volatile_reg, | 720 | .volatile_reg = fsl_asrc_volatile_reg, |
695 | .writeable_reg = fsl_asrc_writeable_reg, | 721 | .writeable_reg = fsl_asrc_writeable_reg, |
@@ -792,7 +818,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) | |||
792 | return -ENOMEM; | 818 | return -ENOMEM; |
793 | 819 | ||
794 | asrc_priv->pdev = pdev; | 820 | asrc_priv->pdev = pdev; |
795 | strcpy(asrc_priv->name, np->name); | 821 | strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1); |
796 | 822 | ||
797 | /* Get the addresses and IRQ */ | 823 | /* Get the addresses and IRQ */ |
798 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 824 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 8bcdfda09d7a..ca319d59f843 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -513,10 +513,15 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
513 | u32 width = snd_pcm_format_width(params_format(params)); | 513 | u32 width = snd_pcm_format_width(params_format(params)); |
514 | u32 channels = params_channels(params); | 514 | u32 channels = params_channels(params); |
515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); | 515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); |
516 | u32 slot_width = width; | ||
516 | u32 bclk, mask, val; | 517 | u32 bclk, mask, val; |
517 | int ret; | 518 | int ret; |
518 | 519 | ||
519 | bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; | 520 | /* Override slot_width if being specifially set */ |
521 | if (esai_priv->slot_width) | ||
522 | slot_width = esai_priv->slot_width; | ||
523 | |||
524 | bclk = params_rate(params) * slot_width * esai_priv->slots; | ||
520 | 525 | ||
521 | ret = fsl_esai_set_bclk(dai, tx, bclk); | 526 | ret = fsl_esai_set_bclk(dai, tx, bclk); |
522 | if (ret) | 527 | if (ret) |
@@ -538,7 +543,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
538 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); | 543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); |
539 | 544 | ||
540 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); | 545 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); |
541 | val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0); | 546 | val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0); |
542 | 547 | ||
543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); | 548 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); |
544 | 549 | ||
@@ -734,7 +739,7 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
734 | return -ENOMEM; | 739 | return -ENOMEM; |
735 | 740 | ||
736 | esai_priv->pdev = pdev; | 741 | esai_priv->pdev = pdev; |
737 | strcpy(esai_priv->name, np->name); | 742 | strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1); |
738 | 743 | ||
739 | /* Get the addresses and IRQ */ | 744 | /* Get the addresses and IRQ */ |
740 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 745 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -780,9 +785,6 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
780 | return ret; | 785 | return ret; |
781 | } | 786 | } |
782 | 787 | ||
783 | /* Set a default slot size */ | ||
784 | esai_priv->slot_width = 32; | ||
785 | |||
786 | /* Set a default slot number */ | 788 | /* Set a default slot number */ |
787 | esai_priv->slots = 2; | 789 | esai_priv->slots = 2; |
788 | 790 | ||
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 33fc5c3abf55..4df867cbb92a 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -691,9 +691,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
691 | } | 691 | } |
692 | 692 | ||
693 | #define HSW_FORMATS \ | 693 | #define HSW_FORMATS \ |
694 | (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ | 694 | (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
695 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ | ||
696 | SNDRV_PCM_FMTBIT_S8) | ||
697 | 695 | ||
698 | static struct snd_soc_dai_driver hsw_dais[] = { | 696 | static struct snd_soc_dai_driver hsw_dais[] = { |
699 | { | 697 | { |
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index f373e37f8305..c74ba37f862c 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
@@ -154,8 +154,10 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) | |||
154 | while (val) { | 154 | while (val) { |
155 | regmap_read(i2s->regmap, I2S_CLR, &val); | 155 | regmap_read(i2s->regmap, I2S_CLR, &val); |
156 | retry--; | 156 | retry--; |
157 | if (!retry) | 157 | if (!retry) { |
158 | dev_warn(i2s->dev, "fail to clear\n"); | 158 | dev_warn(i2s->dev, "fail to clear\n"); |
159 | break; | ||
160 | } | ||
159 | } | 161 | } |
160 | } | 162 | } |
161 | } | 163 | } |
diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig deleted file mode 100644 index f244a2566f20..000000000000 --- a/sound/soc/s6000/Kconfig +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | config SND_S6000_SOC | ||
2 | tristate "SoC Audio for the Stretch s6000 family" | ||
3 | depends on XTENSA_VARIANT_S6000 || COMPILE_TEST | ||
4 | depends on HAS_IOMEM | ||
5 | select SND_S6000_SOC_PCM if XTENSA_VARIANT_S6000 | ||
6 | help | ||
7 | Say Y or M if you want to add support for codecs attached to | ||
8 | s6000 family chips. You will also need to select the platform | ||
9 | to support below. | ||
10 | |||
11 | config SND_S6000_SOC_PCM | ||
12 | tristate | ||
13 | |||
14 | config SND_S6000_SOC_I2S | ||
15 | tristate | ||
16 | |||
17 | config SND_S6000_SOC_S6IPCAM | ||
18 | bool "SoC Audio support for Stretch 6105 IP Camera" | ||
19 | depends on SND_S6000_SOC=y | ||
20 | depends on I2C=y | ||
21 | depends on XTENSA_PLATFORM_S6105 || COMPILE_TEST | ||
22 | select SND_S6000_SOC_I2S | ||
23 | select SND_SOC_TLV320AIC3X | ||
24 | help | ||
25 | Say Y if you want to add support for SoC audio on the | ||
26 | Stretch s6105 IP Camera Reference Design. | ||
diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile deleted file mode 100644 index 0f0ae2a012aa..000000000000 --- a/sound/soc/s6000/Makefile +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | # s6000 Platform Support | ||
2 | snd-soc-s6000-objs := s6000-pcm.o | ||
3 | snd-soc-s6000-i2s-objs := s6000-i2s.o | ||
4 | |||
5 | obj-$(CONFIG_SND_S6000_SOC_PCM) += snd-soc-s6000.o | ||
6 | obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o | ||
7 | |||
8 | # s6105 Machine Support | ||
9 | snd-soc-s6ipcam-objs := s6105-ipcam.o | ||
10 | |||
11 | obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o | ||
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c deleted file mode 100644 index 1c8d01166e5b..000000000000 --- a/sound/soc/s6000/s6000-i2s.c +++ /dev/null | |||
@@ -1,617 +0,0 @@ | |||
1 | /* | ||
2 | * ALSA SoC I2S Audio Layer for the Stretch S6000 family | ||
3 | * | ||
4 | * Author: Daniel Gloeckner, <dg@emlix.com> | ||
5 | * Copyright: (C) 2009 emlix GmbH <info@emlix.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "s6000-i2s.h" | ||
28 | #include "s6000-pcm.h" | ||
29 | |||
30 | struct s6000_i2s_dev { | ||
31 | dma_addr_t sifbase; | ||
32 | u8 __iomem *scbbase; | ||
33 | unsigned int wide; | ||
34 | unsigned int channel_in; | ||
35 | unsigned int channel_out; | ||
36 | unsigned int lines_in; | ||
37 | unsigned int lines_out; | ||
38 | struct s6000_pcm_dma_params dma_params; | ||
39 | }; | ||
40 | |||
41 | #define S6_I2S_INTERRUPT_STATUS 0x00 | ||
42 | #define S6_I2S_INT_OVERRUN 1 | ||
43 | #define S6_I2S_INT_UNDERRUN 2 | ||
44 | #define S6_I2S_INT_ALIGNMENT 4 | ||
45 | #define S6_I2S_INTERRUPT_ENABLE 0x04 | ||
46 | #define S6_I2S_INTERRUPT_RAW 0x08 | ||
47 | #define S6_I2S_INTERRUPT_CLEAR 0x0C | ||
48 | #define S6_I2S_INTERRUPT_SET 0x10 | ||
49 | #define S6_I2S_MODE 0x20 | ||
50 | #define S6_I2S_DUAL 0 | ||
51 | #define S6_I2S_WIDE 1 | ||
52 | #define S6_I2S_TX_DEFAULT 0x24 | ||
53 | #define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c)) | ||
54 | #define S6_I2S_IN 0 | ||
55 | #define S6_I2S_OUT 1 | ||
56 | #define S6_I2S_UNUSED 2 | ||
57 | #define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c)) | ||
58 | #define S6_I2S_DIV_MASK 0x001fff | ||
59 | #define S6_I2S_16BIT 0x000000 | ||
60 | #define S6_I2S_20BIT 0x002000 | ||
61 | #define S6_I2S_24BIT 0x004000 | ||
62 | #define S6_I2S_32BIT 0x006000 | ||
63 | #define S6_I2S_BITS_MASK 0x006000 | ||
64 | #define S6_I2S_MEM_16BIT 0x000000 | ||
65 | #define S6_I2S_MEM_32BIT 0x008000 | ||
66 | #define S6_I2S_MEM_MASK 0x008000 | ||
67 | #define S6_I2S_CHANNELS_SHIFT 16 | ||
68 | #define S6_I2S_CHANNELS_MASK 0x030000 | ||
69 | #define S6_I2S_SCK_IN 0x000000 | ||
70 | #define S6_I2S_SCK_OUT 0x040000 | ||
71 | #define S6_I2S_SCK_DIR 0x040000 | ||
72 | #define S6_I2S_WS_IN 0x000000 | ||
73 | #define S6_I2S_WS_OUT 0x080000 | ||
74 | #define S6_I2S_WS_DIR 0x080000 | ||
75 | #define S6_I2S_LEFT_FIRST 0x000000 | ||
76 | #define S6_I2S_RIGHT_FIRST 0x100000 | ||
77 | #define S6_I2S_FIRST 0x100000 | ||
78 | #define S6_I2S_CUR_SCK 0x200000 | ||
79 | #define S6_I2S_CUR_WS 0x400000 | ||
80 | #define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c)) | ||
81 | #define S6_I2S_DISABLE_IF 0x02 | ||
82 | #define S6_I2S_ENABLE_IF 0x03 | ||
83 | #define S6_I2S_IS_BUSY 0x04 | ||
84 | #define S6_I2S_DMA_ACTIVE 0x08 | ||
85 | #define S6_I2S_IS_ENABLED 0x10 | ||
86 | |||
87 | #define S6_I2S_NUM_LINES 4 | ||
88 | |||
89 | #define S6_I2S_SIF_PORT0 0x0000000 | ||
90 | #define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */ | ||
91 | |||
92 | static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val) | ||
93 | { | ||
94 | writel(val, dev->scbbase + reg); | ||
95 | } | ||
96 | |||
97 | static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg) | ||
98 | { | ||
99 | return readl(dev->scbbase + reg); | ||
100 | } | ||
101 | |||
102 | static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg, | ||
103 | u32 mask, u32 val) | ||
104 | { | ||
105 | val ^= s6_i2s_read_reg(dev, reg) & ~mask; | ||
106 | s6_i2s_write_reg(dev, reg, val); | ||
107 | } | ||
108 | |||
109 | static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel) | ||
110 | { | ||
111 | int i, j, cur, prev; | ||
112 | |||
113 | /* | ||
114 | * Wait for WCLK to toggle 5 times before enabling the channel | ||
115 | * s6000 Family Datasheet 3.6.4: | ||
116 | * "At least two cycles of WS must occur between commands | ||
117 | * to disable or enable the interface" | ||
118 | */ | ||
119 | j = 0; | ||
120 | prev = ~S6_I2S_CUR_WS; | ||
121 | for (i = 1000000; --i && j < 6; ) { | ||
122 | cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel)) | ||
123 | & S6_I2S_CUR_WS; | ||
124 | if (prev != cur) { | ||
125 | prev = cur; | ||
126 | j++; | ||
127 | } | ||
128 | } | ||
129 | if (j < 6) | ||
130 | printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n"); | ||
131 | |||
132 | s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF); | ||
133 | } | ||
134 | |||
135 | static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel) | ||
136 | { | ||
137 | s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF); | ||
138 | } | ||
139 | |||
140 | static void s6000_i2s_start(struct snd_pcm_substream *substream) | ||
141 | { | ||
142 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
143 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
144 | int channel; | ||
145 | |||
146 | channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
147 | dev->channel_out : dev->channel_in; | ||
148 | |||
149 | s6000_i2s_start_channel(dev, channel); | ||
150 | } | ||
151 | |||
152 | static void s6000_i2s_stop(struct snd_pcm_substream *substream) | ||
153 | { | ||
154 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
155 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
156 | int channel; | ||
157 | |||
158 | channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
159 | dev->channel_out : dev->channel_in; | ||
160 | |||
161 | s6000_i2s_stop_channel(dev, channel); | ||
162 | } | ||
163 | |||
164 | static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
165 | int after) | ||
166 | { | ||
167 | switch (cmd) { | ||
168 | case SNDRV_PCM_TRIGGER_START: | ||
169 | case SNDRV_PCM_TRIGGER_RESUME: | ||
170 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
171 | if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after) | ||
172 | s6000_i2s_start(substream); | ||
173 | break; | ||
174 | case SNDRV_PCM_TRIGGER_STOP: | ||
175 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
176 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
177 | if (!after) | ||
178 | s6000_i2s_stop(substream); | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev) | ||
184 | { | ||
185 | unsigned int pending; | ||
186 | pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW); | ||
187 | pending &= S6_I2S_INT_ALIGNMENT | | ||
188 | S6_I2S_INT_UNDERRUN | | ||
189 | S6_I2S_INT_OVERRUN; | ||
190 | s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending); | ||
191 | |||
192 | return pending; | ||
193 | } | ||
194 | |||
195 | static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai) | ||
196 | { | ||
197 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); | ||
198 | unsigned int errors; | ||
199 | unsigned int ret; | ||
200 | |||
201 | errors = s6000_i2s_int_sources(dev); | ||
202 | if (likely(!errors)) | ||
203 | return 0; | ||
204 | |||
205 | ret = 0; | ||
206 | if (errors & S6_I2S_INT_ALIGNMENT) | ||
207 | printk(KERN_ERR "s6000-i2s: WCLK misaligned\n"); | ||
208 | if (errors & S6_I2S_INT_UNDERRUN) | ||
209 | ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK; | ||
210 | if (errors & S6_I2S_INT_OVERRUN) | ||
211 | ret |= 1 << SNDRV_PCM_STREAM_CAPTURE; | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev) | ||
216 | { | ||
217 | int channel; | ||
218 | int n = 50; | ||
219 | for (channel = 0; channel < 2; channel++) { | ||
220 | while (--n >= 0) { | ||
221 | int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel)); | ||
222 | if ((v & S6_I2S_IS_ENABLED) | ||
223 | || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY))) | ||
224 | break; | ||
225 | udelay(20); | ||
226 | } | ||
227 | } | ||
228 | if (n < 0) | ||
229 | printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces"); | ||
230 | } | ||
231 | |||
232 | static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
233 | unsigned int fmt) | ||
234 | { | ||
235 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); | ||
236 | u32 w; | ||
237 | |||
238 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
239 | case SND_SOC_DAIFMT_CBM_CFM: | ||
240 | w = S6_I2S_SCK_IN | S6_I2S_WS_IN; | ||
241 | break; | ||
242 | case SND_SOC_DAIFMT_CBS_CFM: | ||
243 | w = S6_I2S_SCK_OUT | S6_I2S_WS_IN; | ||
244 | break; | ||
245 | case SND_SOC_DAIFMT_CBM_CFS: | ||
246 | w = S6_I2S_SCK_IN | S6_I2S_WS_OUT; | ||
247 | break; | ||
248 | case SND_SOC_DAIFMT_CBS_CFS: | ||
249 | w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT; | ||
250 | break; | ||
251 | default: | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
256 | case SND_SOC_DAIFMT_NB_NF: | ||
257 | w |= S6_I2S_LEFT_FIRST; | ||
258 | break; | ||
259 | case SND_SOC_DAIFMT_NB_IF: | ||
260 | w |= S6_I2S_RIGHT_FIRST; | ||
261 | break; | ||
262 | default: | ||
263 | return -EINVAL; | ||
264 | } | ||
265 | |||
266 | s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0), | ||
267 | S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); | ||
268 | s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1), | ||
269 | S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) | ||
275 | { | ||
276 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
277 | |||
278 | if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2) | ||
279 | return -EINVAL; | ||
280 | |||
281 | s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id), | ||
282 | S6_I2S_DIV_MASK, div / 2 - 1); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int s6000_i2s_hw_params(struct snd_pcm_substream *substream, | ||
287 | struct snd_pcm_hw_params *params, | ||
288 | struct snd_soc_dai *dai) | ||
289 | { | ||
290 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
291 | int interf; | ||
292 | u32 w = 0; | ||
293 | |||
294 | if (dev->wide) | ||
295 | interf = 0; | ||
296 | else { | ||
297 | w |= (((params_channels(params) - 2) / 2) | ||
298 | << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK; | ||
299 | interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
300 | ? dev->channel_out : dev->channel_in; | ||
301 | } | ||
302 | |||
303 | switch (params_format(params)) { | ||
304 | case SNDRV_PCM_FORMAT_S16_LE: | ||
305 | w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT; | ||
306 | break; | ||
307 | case SNDRV_PCM_FORMAT_S32_LE: | ||
308 | w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT; | ||
309 | break; | ||
310 | default: | ||
311 | printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n", | ||
312 | params_format(params)); | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf)) | ||
317 | & S6_I2S_IS_ENABLED) { | ||
318 | printk(KERN_ERR "s6000-i2s: interface already enabled\n"); | ||
319 | return -EBUSY; | ||
320 | } | ||
321 | |||
322 | s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf), | ||
323 | S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK, | ||
324 | w); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int s6000_i2s_dai_probe(struct snd_soc_dai *dai) | ||
330 | { | ||
331 | struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
332 | struct s6000_snd_platform_data *pdata = dai->dev->platform_data; | ||
333 | |||
334 | if (!pdata) | ||
335 | return -EINVAL; | ||
336 | |||
337 | dai->capture_dma_data = &dev->dma_params; | ||
338 | dai->playback_dma_data = &dev->dma_params; | ||
339 | |||
340 | dev->wide = pdata->wide; | ||
341 | dev->channel_in = pdata->channel_in; | ||
342 | dev->channel_out = pdata->channel_out; | ||
343 | dev->lines_in = pdata->lines_in; | ||
344 | dev->lines_out = pdata->lines_out; | ||
345 | |||
346 | s6_i2s_write_reg(dev, S6_I2S_MODE, | ||
347 | dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL); | ||
348 | |||
349 | if (dev->wide) { | ||
350 | int i; | ||
351 | |||
352 | if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES) | ||
353 | return -EINVAL; | ||
354 | |||
355 | dev->channel_in = 0; | ||
356 | dev->channel_out = 1; | ||
357 | dai->driver->capture.channels_min = 2 * dev->lines_in; | ||
358 | dai->driver->capture.channels_max = dai->driver->capture.channels_min; | ||
359 | dai->driver->playback.channels_min = 2 * dev->lines_out; | ||
360 | dai->driver->playback.channels_max = dai->driver->playback.channels_min; | ||
361 | |||
362 | for (i = 0; i < dev->lines_out; i++) | ||
363 | s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT); | ||
364 | |||
365 | for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++) | ||
366 | s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), | ||
367 | S6_I2S_UNUSED); | ||
368 | |||
369 | for (; i < S6_I2S_NUM_LINES; i++) | ||
370 | s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN); | ||
371 | } else { | ||
372 | unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED}; | ||
373 | |||
374 | if (dev->lines_in > 1 || dev->lines_out > 1) | ||
375 | return -EINVAL; | ||
376 | |||
377 | dai->driver->capture.channels_min = 2 * dev->lines_in; | ||
378 | dai->driver->capture.channels_max = 8 * dev->lines_in; | ||
379 | dai->driver->playback.channels_min = 2 * dev->lines_out; | ||
380 | dai->driver->playback.channels_max = 8 * dev->lines_out; | ||
381 | |||
382 | if (dev->lines_in) | ||
383 | cfg[dev->channel_in] = S6_I2S_IN; | ||
384 | if (dev->lines_out) | ||
385 | cfg[dev->channel_out] = S6_I2S_OUT; | ||
386 | |||
387 | s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]); | ||
388 | s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]); | ||
389 | } | ||
390 | |||
391 | if (dev->lines_out) { | ||
392 | if (dev->lines_in) { | ||
393 | if (!dev->dma_params.dma_out) | ||
394 | return -ENODEV; | ||
395 | } else { | ||
396 | dev->dma_params.dma_out = dev->dma_params.dma_in; | ||
397 | dev->dma_params.dma_in = 0; | ||
398 | } | ||
399 | } | ||
400 | dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ? | ||
401 | S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); | ||
402 | dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ? | ||
403 | S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); | ||
404 | dev->dma_params.same_rate = pdata->same_rate | pdata->wide; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | #define S6000_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS | ||
409 | #define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
410 | |||
411 | static const struct snd_soc_dai_ops s6000_i2s_dai_ops = { | ||
412 | .set_fmt = s6000_i2s_set_dai_fmt, | ||
413 | .set_clkdiv = s6000_i2s_set_clkdiv, | ||
414 | .hw_params = s6000_i2s_hw_params, | ||
415 | }; | ||
416 | |||
417 | static struct snd_soc_dai_driver s6000_i2s_dai = { | ||
418 | .probe = s6000_i2s_dai_probe, | ||
419 | .playback = { | ||
420 | .channels_min = 2, | ||
421 | .channels_max = 8, | ||
422 | .formats = S6000_I2S_FORMATS, | ||
423 | .rates = S6000_I2S_RATES, | ||
424 | .rate_min = 0, | ||
425 | .rate_max = 1562500, | ||
426 | }, | ||
427 | .capture = { | ||
428 | .channels_min = 2, | ||
429 | .channels_max = 8, | ||
430 | .formats = S6000_I2S_FORMATS, | ||
431 | .rates = S6000_I2S_RATES, | ||
432 | .rate_min = 0, | ||
433 | .rate_max = 1562500, | ||
434 | }, | ||
435 | .ops = &s6000_i2s_dai_ops, | ||
436 | }; | ||
437 | |||
438 | static const struct snd_soc_component_driver s6000_i2s_component = { | ||
439 | .name = "s6000-i2s", | ||
440 | }; | ||
441 | |||
442 | static int s6000_i2s_probe(struct platform_device *pdev) | ||
443 | { | ||
444 | struct s6000_i2s_dev *dev; | ||
445 | struct resource *scbmem, *sifmem, *region, *dma1, *dma2; | ||
446 | u8 __iomem *mmio; | ||
447 | int ret; | ||
448 | |||
449 | scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
450 | if (!scbmem) { | ||
451 | dev_err(&pdev->dev, "no mem resource?\n"); | ||
452 | ret = -ENODEV; | ||
453 | goto err_release_none; | ||
454 | } | ||
455 | |||
456 | region = request_mem_region(scbmem->start, resource_size(scbmem), | ||
457 | pdev->name); | ||
458 | if (!region) { | ||
459 | dev_err(&pdev->dev, "I2S SCB region already claimed\n"); | ||
460 | ret = -EBUSY; | ||
461 | goto err_release_none; | ||
462 | } | ||
463 | |||
464 | mmio = ioremap(scbmem->start, resource_size(scbmem)); | ||
465 | if (!mmio) { | ||
466 | dev_err(&pdev->dev, "can't ioremap SCB region\n"); | ||
467 | ret = -ENOMEM; | ||
468 | goto err_release_scb; | ||
469 | } | ||
470 | |||
471 | sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
472 | if (!sifmem) { | ||
473 | dev_err(&pdev->dev, "no second mem resource?\n"); | ||
474 | ret = -ENODEV; | ||
475 | goto err_release_map; | ||
476 | } | ||
477 | |||
478 | region = request_mem_region(sifmem->start, resource_size(sifmem), | ||
479 | pdev->name); | ||
480 | if (!region) { | ||
481 | dev_err(&pdev->dev, "I2S SIF region already claimed\n"); | ||
482 | ret = -EBUSY; | ||
483 | goto err_release_map; | ||
484 | } | ||
485 | |||
486 | dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
487 | if (!dma1) { | ||
488 | dev_err(&pdev->dev, "no dma resource?\n"); | ||
489 | ret = -ENODEV; | ||
490 | goto err_release_sif; | ||
491 | } | ||
492 | |||
493 | region = request_mem_region(dma1->start, resource_size(dma1), | ||
494 | pdev->name); | ||
495 | if (!region) { | ||
496 | dev_err(&pdev->dev, "I2S DMA region already claimed\n"); | ||
497 | ret = -EBUSY; | ||
498 | goto err_release_sif; | ||
499 | } | ||
500 | |||
501 | dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
502 | if (dma2) { | ||
503 | region = request_mem_region(dma2->start, resource_size(dma2), | ||
504 | pdev->name); | ||
505 | if (!region) { | ||
506 | dev_err(&pdev->dev, | ||
507 | "I2S DMA region already claimed\n"); | ||
508 | ret = -EBUSY; | ||
509 | goto err_release_dma1; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL); | ||
514 | if (!dev) { | ||
515 | ret = -ENOMEM; | ||
516 | goto err_release_dma2; | ||
517 | } | ||
518 | dev_set_drvdata(&pdev->dev, dev); | ||
519 | |||
520 | dev->sifbase = sifmem->start; | ||
521 | dev->scbbase = mmio; | ||
522 | |||
523 | s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); | ||
524 | s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, | ||
525 | S6_I2S_INT_ALIGNMENT | | ||
526 | S6_I2S_INT_UNDERRUN | | ||
527 | S6_I2S_INT_OVERRUN); | ||
528 | |||
529 | s6000_i2s_stop_channel(dev, 0); | ||
530 | s6000_i2s_stop_channel(dev, 1); | ||
531 | s6000_i2s_wait_disabled(dev); | ||
532 | |||
533 | dev->dma_params.check_xrun = s6000_i2s_check_xrun; | ||
534 | dev->dma_params.trigger = s6000_i2s_trigger; | ||
535 | dev->dma_params.dma_in = dma1->start; | ||
536 | dev->dma_params.dma_out = dma2 ? dma2->start : 0; | ||
537 | dev->dma_params.irq = platform_get_irq(pdev, 0); | ||
538 | if (dev->dma_params.irq < 0) { | ||
539 | dev_err(&pdev->dev, "no irq resource?\n"); | ||
540 | ret = -ENODEV; | ||
541 | goto err_release_dev; | ||
542 | } | ||
543 | |||
544 | s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, | ||
545 | S6_I2S_INT_ALIGNMENT | | ||
546 | S6_I2S_INT_UNDERRUN | | ||
547 | S6_I2S_INT_OVERRUN); | ||
548 | |||
549 | ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component, | ||
550 | &s6000_i2s_dai, 1); | ||
551 | if (ret) | ||
552 | goto err_release_dev; | ||
553 | |||
554 | return 0; | ||
555 | |||
556 | err_release_dev: | ||
557 | kfree(dev); | ||
558 | err_release_dma2: | ||
559 | if (dma2) | ||
560 | release_mem_region(dma2->start, resource_size(dma2)); | ||
561 | err_release_dma1: | ||
562 | release_mem_region(dma1->start, resource_size(dma1)); | ||
563 | err_release_sif: | ||
564 | release_mem_region(sifmem->start, resource_size(sifmem)); | ||
565 | err_release_map: | ||
566 | iounmap(mmio); | ||
567 | err_release_scb: | ||
568 | release_mem_region(scbmem->start, resource_size(scbmem)); | ||
569 | err_release_none: | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | static int s6000_i2s_remove(struct platform_device *pdev) | ||
574 | { | ||
575 | struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev); | ||
576 | struct resource *region; | ||
577 | void __iomem *mmio = dev->scbbase; | ||
578 | |||
579 | snd_soc_unregister_component(&pdev->dev); | ||
580 | |||
581 | s6000_i2s_stop_channel(dev, 0); | ||
582 | s6000_i2s_stop_channel(dev, 1); | ||
583 | |||
584 | s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); | ||
585 | kfree(dev); | ||
586 | |||
587 | region = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
588 | release_mem_region(region->start, resource_size(region)); | ||
589 | |||
590 | region = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
591 | if (region) | ||
592 | release_mem_region(region->start, resource_size(region)); | ||
593 | |||
594 | region = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
595 | release_mem_region(region->start, resource_size(region)); | ||
596 | |||
597 | iounmap(mmio); | ||
598 | region = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
599 | release_mem_region(region->start, resource_size(region)); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static struct platform_driver s6000_i2s_driver = { | ||
605 | .probe = s6000_i2s_probe, | ||
606 | .remove = s6000_i2s_remove, | ||
607 | .driver = { | ||
608 | .name = "s6000-i2s", | ||
609 | .owner = THIS_MODULE, | ||
610 | }, | ||
611 | }; | ||
612 | |||
613 | module_platform_driver(s6000_i2s_driver); | ||
614 | |||
615 | MODULE_AUTHOR("Daniel Gloeckner"); | ||
616 | MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface"); | ||
617 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h deleted file mode 100644 index 86aa1921c89e..000000000000 --- a/sound/soc/s6000/s6000-i2s.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * ALSA SoC I2S Audio Layer for the Stretch s6000 family | ||
3 | * | ||
4 | * Author: Daniel Gloeckner, <dg@emlix.com> | ||
5 | * Copyright: (C) 2009 emlix GmbH <info@emlix.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _S6000_I2S_H | ||
13 | #define _S6000_I2S_H | ||
14 | |||
15 | struct s6000_snd_platform_data { | ||
16 | int lines_in; | ||
17 | int lines_out; | ||
18 | int channel_in; | ||
19 | int channel_out; | ||
20 | int wide; | ||
21 | int same_rate; | ||
22 | }; | ||
23 | #endif | ||
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c deleted file mode 100644 index fb8461e1b1f6..000000000000 --- a/sound/soc/s6000/s6000-pcm.c +++ /dev/null | |||
@@ -1,521 +0,0 @@ | |||
1 | /* | ||
2 | * ALSA PCM interface for the Stetch s6000 family | ||
3 | * | ||
4 | * Author: Daniel Gloeckner, <dg@emlix.com> | ||
5 | * Copyright: (C) 2009 emlix GmbH <info@emlix.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | ||
23 | |||
24 | #include <asm/dma.h> | ||
25 | #include <variant/dmac.h> | ||
26 | |||
27 | #include "s6000-pcm.h" | ||
28 | |||
29 | #define S6_PCM_PREALLOCATE_SIZE (96 * 1024) | ||
30 | #define S6_PCM_PREALLOCATE_MAX (2048 * 1024) | ||
31 | |||
32 | static struct snd_pcm_hardware s6000_pcm_hardware = { | ||
33 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
34 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
35 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX), | ||
36 | .buffer_bytes_max = 0x7ffffff0, | ||
37 | .period_bytes_min = 16, | ||
38 | .period_bytes_max = 0xfffff0, | ||
39 | .periods_min = 2, | ||
40 | .periods_max = 1024, /* no limit */ | ||
41 | .fifo_size = 0, | ||
42 | }; | ||
43 | |||
44 | struct s6000_runtime_data { | ||
45 | spinlock_t lock; | ||
46 | int period; /* current DMA period */ | ||
47 | }; | ||
48 | |||
49 | static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
52 | struct s6000_runtime_data *prtd = runtime->private_data; | ||
53 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
54 | struct s6000_pcm_dma_params *par; | ||
55 | int channel; | ||
56 | unsigned int period_size; | ||
57 | unsigned int dma_offset; | ||
58 | dma_addr_t dma_pos; | ||
59 | dma_addr_t src, dst; | ||
60 | |||
61 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
62 | |||
63 | period_size = snd_pcm_lib_period_bytes(substream); | ||
64 | dma_offset = prtd->period * period_size; | ||
65 | dma_pos = runtime->dma_addr + dma_offset; | ||
66 | |||
67 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
68 | src = dma_pos; | ||
69 | dst = par->sif_out; | ||
70 | channel = par->dma_out; | ||
71 | } else { | ||
72 | src = par->sif_in; | ||
73 | dst = dma_pos; | ||
74 | channel = par->dma_in; | ||
75 | } | ||
76 | |||
77 | if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel), | ||
78 | DMA_INDEX_CHNL(channel))) | ||
79 | return; | ||
80 | |||
81 | if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) { | ||
82 | printk(KERN_ERR "s6000-pcm: fifo full\n"); | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | if (WARN_ON(period_size & 15)) | ||
87 | return; | ||
88 | s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel), | ||
89 | src, dst, period_size); | ||
90 | |||
91 | prtd->period++; | ||
92 | if (unlikely(prtd->period >= runtime->periods)) | ||
93 | prtd->period = 0; | ||
94 | } | ||
95 | |||
96 | static irqreturn_t s6000_pcm_irq(int irq, void *data) | ||
97 | { | ||
98 | struct snd_pcm *pcm = data; | ||
99 | struct snd_soc_pcm_runtime *runtime = pcm->private_data; | ||
100 | struct s6000_runtime_data *prtd; | ||
101 | unsigned int has_xrun; | ||
102 | int i, ret = IRQ_NONE; | ||
103 | |||
104 | for (i = 0; i < 2; ++i) { | ||
105 | struct snd_pcm_substream *substream = pcm->streams[i].substream; | ||
106 | struct s6000_pcm_dma_params *params = | ||
107 | snd_soc_dai_get_dma_data(runtime->cpu_dai, substream); | ||
108 | u32 channel; | ||
109 | unsigned int pending; | ||
110 | |||
111 | if (substream == SNDRV_PCM_STREAM_PLAYBACK) | ||
112 | channel = params->dma_out; | ||
113 | else | ||
114 | channel = params->dma_in; | ||
115 | |||
116 | has_xrun = params->check_xrun(runtime->cpu_dai); | ||
117 | |||
118 | if (!channel) | ||
119 | continue; | ||
120 | |||
121 | if (unlikely(has_xrun & (1 << i)) && | ||
122 | substream->runtime && | ||
123 | snd_pcm_running(substream)) { | ||
124 | dev_dbg(pcm->dev, "xrun\n"); | ||
125 | snd_pcm_stream_lock(substream); | ||
126 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
127 | snd_pcm_stream_unlock(substream); | ||
128 | ret = IRQ_HANDLED; | ||
129 | } | ||
130 | |||
131 | pending = s6dmac_int_sources(DMA_MASK_DMAC(channel), | ||
132 | DMA_INDEX_CHNL(channel)); | ||
133 | |||
134 | if (pending & 1) { | ||
135 | ret = IRQ_HANDLED; | ||
136 | if (likely(substream->runtime && | ||
137 | snd_pcm_running(substream))) { | ||
138 | snd_pcm_period_elapsed(substream); | ||
139 | dev_dbg(pcm->dev, "period elapsed %x %x\n", | ||
140 | s6dmac_cur_src(DMA_MASK_DMAC(channel), | ||
141 | DMA_INDEX_CHNL(channel)), | ||
142 | s6dmac_cur_dst(DMA_MASK_DMAC(channel), | ||
143 | DMA_INDEX_CHNL(channel))); | ||
144 | prtd = substream->runtime->private_data; | ||
145 | spin_lock(&prtd->lock); | ||
146 | s6000_pcm_enqueue_dma(substream); | ||
147 | spin_unlock(&prtd->lock); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (unlikely(pending & ~7)) { | ||
152 | if (pending & (1 << 3)) | ||
153 | printk(KERN_WARNING | ||
154 | "s6000-pcm: DMA %x Underflow\n", | ||
155 | channel); | ||
156 | if (pending & (1 << 4)) | ||
157 | printk(KERN_WARNING | ||
158 | "s6000-pcm: DMA %x Overflow\n", | ||
159 | channel); | ||
160 | if (pending & 0x1e0) | ||
161 | printk(KERN_WARNING | ||
162 | "s6000-pcm: DMA %x Master Error " | ||
163 | "(mask %x)\n", | ||
164 | channel, pending >> 5); | ||
165 | |||
166 | } | ||
167 | } | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int s6000_pcm_start(struct snd_pcm_substream *substream) | ||
173 | { | ||
174 | struct s6000_runtime_data *prtd = substream->runtime->private_data; | ||
175 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
176 | struct s6000_pcm_dma_params *par; | ||
177 | unsigned long flags; | ||
178 | int srcinc; | ||
179 | u32 dma; | ||
180 | |||
181 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
182 | |||
183 | spin_lock_irqsave(&prtd->lock, flags); | ||
184 | |||
185 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
186 | srcinc = 1; | ||
187 | dma = par->dma_out; | ||
188 | } else { | ||
189 | srcinc = 0; | ||
190 | dma = par->dma_in; | ||
191 | } | ||
192 | s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma), | ||
193 | 1 /* priority 1 (0 is max) */, | ||
194 | 0 /* peripheral requests w/o xfer length mode */, | ||
195 | srcinc /* source address increment */, | ||
196 | srcinc^1 /* destination address increment */, | ||
197 | 0 /* chunksize 0 (skip impossible on this dma) */, | ||
198 | 0 /* source skip after chunk (impossible) */, | ||
199 | 0 /* destination skip after chunk (impossible) */, | ||
200 | 4 /* 16 byte burst size */, | ||
201 | -1 /* don't conserve bandwidth */, | ||
202 | 0 /* low watermark irq descriptor threshold */, | ||
203 | 0 /* disable hardware timestamps */, | ||
204 | 1 /* enable channel */); | ||
205 | |||
206 | s6000_pcm_enqueue_dma(substream); | ||
207 | s6000_pcm_enqueue_dma(substream); | ||
208 | |||
209 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int s6000_pcm_stop(struct snd_pcm_substream *substream) | ||
215 | { | ||
216 | struct s6000_runtime_data *prtd = substream->runtime->private_data; | ||
217 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
218 | struct s6000_pcm_dma_params *par; | ||
219 | unsigned long flags; | ||
220 | u32 channel; | ||
221 | |||
222 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
223 | |||
224 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
225 | channel = par->dma_out; | ||
226 | else | ||
227 | channel = par->dma_in; | ||
228 | |||
229 | s6dmac_set_terminal_count(DMA_MASK_DMAC(channel), | ||
230 | DMA_INDEX_CHNL(channel), 0); | ||
231 | |||
232 | spin_lock_irqsave(&prtd->lock, flags); | ||
233 | |||
234 | s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel)); | ||
235 | |||
236 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
242 | { | ||
243 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
244 | struct s6000_pcm_dma_params *par; | ||
245 | int ret; | ||
246 | |||
247 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
248 | |||
249 | ret = par->trigger(substream, cmd, 0); | ||
250 | if (ret < 0) | ||
251 | return ret; | ||
252 | |||
253 | switch (cmd) { | ||
254 | case SNDRV_PCM_TRIGGER_START: | ||
255 | case SNDRV_PCM_TRIGGER_RESUME: | ||
256 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
257 | ret = s6000_pcm_start(substream); | ||
258 | break; | ||
259 | case SNDRV_PCM_TRIGGER_STOP: | ||
260 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
261 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
262 | ret = s6000_pcm_stop(substream); | ||
263 | break; | ||
264 | default: | ||
265 | ret = -EINVAL; | ||
266 | } | ||
267 | if (ret < 0) | ||
268 | return ret; | ||
269 | |||
270 | return par->trigger(substream, cmd, 1); | ||
271 | } | ||
272 | |||
273 | static int s6000_pcm_prepare(struct snd_pcm_substream *substream) | ||
274 | { | ||
275 | struct s6000_runtime_data *prtd = substream->runtime->private_data; | ||
276 | |||
277 | prtd->period = 0; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream) | ||
283 | { | ||
284 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
285 | struct s6000_pcm_dma_params *par; | ||
286 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
287 | struct s6000_runtime_data *prtd = runtime->private_data; | ||
288 | unsigned long flags; | ||
289 | unsigned int offset; | ||
290 | dma_addr_t count; | ||
291 | |||
292 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
293 | |||
294 | spin_lock_irqsave(&prtd->lock, flags); | ||
295 | |||
296 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
297 | count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out), | ||
298 | DMA_INDEX_CHNL(par->dma_out)); | ||
299 | else | ||
300 | count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in), | ||
301 | DMA_INDEX_CHNL(par->dma_in)); | ||
302 | |||
303 | count -= runtime->dma_addr; | ||
304 | |||
305 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
306 | |||
307 | offset = bytes_to_frames(runtime, count); | ||
308 | if (unlikely(offset >= runtime->buffer_size)) | ||
309 | offset = 0; | ||
310 | |||
311 | return offset; | ||
312 | } | ||
313 | |||
314 | static int s6000_pcm_open(struct snd_pcm_substream *substream) | ||
315 | { | ||
316 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
317 | struct s6000_pcm_dma_params *par; | ||
318 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
319 | struct s6000_runtime_data *prtd; | ||
320 | int ret; | ||
321 | |||
322 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
323 | snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware); | ||
324 | |||
325 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
326 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); | ||
327 | if (ret < 0) | ||
328 | return ret; | ||
329 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
330 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); | ||
331 | if (ret < 0) | ||
332 | return ret; | ||
333 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
334 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | if (par->same_rate) { | ||
339 | int rate; | ||
340 | spin_lock(&par->lock); /* needed? */ | ||
341 | rate = par->rate; | ||
342 | spin_unlock(&par->lock); | ||
343 | if (rate != -1) { | ||
344 | ret = snd_pcm_hw_constraint_minmax(runtime, | ||
345 | SNDRV_PCM_HW_PARAM_RATE, | ||
346 | rate, rate); | ||
347 | if (ret < 0) | ||
348 | return ret; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL); | ||
353 | if (prtd == NULL) | ||
354 | return -ENOMEM; | ||
355 | |||
356 | spin_lock_init(&prtd->lock); | ||
357 | |||
358 | runtime->private_data = prtd; | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int s6000_pcm_close(struct snd_pcm_substream *substream) | ||
364 | { | ||
365 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
366 | struct s6000_runtime_data *prtd = runtime->private_data; | ||
367 | |||
368 | kfree(prtd); | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, | ||
374 | struct snd_pcm_hw_params *hw_params) | ||
375 | { | ||
376 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
377 | struct s6000_pcm_dma_params *par; | ||
378 | int ret; | ||
379 | ret = snd_pcm_lib_malloc_pages(substream, | ||
380 | params_buffer_bytes(hw_params)); | ||
381 | if (ret < 0) { | ||
382 | printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n"); | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
387 | |||
388 | if (par->same_rate) { | ||
389 | spin_lock(&par->lock); | ||
390 | if (par->rate == -1 || | ||
391 | !(par->in_use & ~(1 << substream->stream))) { | ||
392 | par->rate = params_rate(hw_params); | ||
393 | par->in_use |= 1 << substream->stream; | ||
394 | } else if (params_rate(hw_params) != par->rate) { | ||
395 | snd_pcm_lib_free_pages(substream); | ||
396 | par->in_use &= ~(1 << substream->stream); | ||
397 | ret = -EBUSY; | ||
398 | } | ||
399 | spin_unlock(&par->lock); | ||
400 | } | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int s6000_pcm_hw_free(struct snd_pcm_substream *substream) | ||
405 | { | ||
406 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
407 | struct s6000_pcm_dma_params *par = | ||
408 | snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
409 | |||
410 | spin_lock(&par->lock); | ||
411 | par->in_use &= ~(1 << substream->stream); | ||
412 | if (!par->in_use) | ||
413 | par->rate = -1; | ||
414 | spin_unlock(&par->lock); | ||
415 | |||
416 | return snd_pcm_lib_free_pages(substream); | ||
417 | } | ||
418 | |||
419 | static struct snd_pcm_ops s6000_pcm_ops = { | ||
420 | .open = s6000_pcm_open, | ||
421 | .close = s6000_pcm_close, | ||
422 | .ioctl = snd_pcm_lib_ioctl, | ||
423 | .hw_params = s6000_pcm_hw_params, | ||
424 | .hw_free = s6000_pcm_hw_free, | ||
425 | .trigger = s6000_pcm_trigger, | ||
426 | .prepare = s6000_pcm_prepare, | ||
427 | .pointer = s6000_pcm_pointer, | ||
428 | }; | ||
429 | |||
430 | static void s6000_pcm_free(struct snd_pcm *pcm) | ||
431 | { | ||
432 | struct snd_soc_pcm_runtime *runtime = pcm->private_data; | ||
433 | struct s6000_pcm_dma_params *params = | ||
434 | snd_soc_dai_get_dma_data(runtime->cpu_dai, | ||
435 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); | ||
436 | |||
437 | free_irq(params->irq, pcm); | ||
438 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
439 | } | ||
440 | |||
441 | static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime) | ||
442 | { | ||
443 | struct snd_card *card = runtime->card->snd_card; | ||
444 | struct snd_pcm *pcm = runtime->pcm; | ||
445 | struct s6000_pcm_dma_params *params; | ||
446 | int res; | ||
447 | |||
448 | params = snd_soc_dai_get_dma_data(runtime->cpu_dai, | ||
449 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); | ||
450 | |||
451 | res = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); | ||
452 | if (res) | ||
453 | return res; | ||
454 | |||
455 | if (params->dma_in) { | ||
456 | s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in), | ||
457 | DMA_INDEX_CHNL(params->dma_in)); | ||
458 | s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in), | ||
459 | DMA_INDEX_CHNL(params->dma_in)); | ||
460 | } | ||
461 | |||
462 | if (params->dma_out) { | ||
463 | s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out), | ||
464 | DMA_INDEX_CHNL(params->dma_out)); | ||
465 | s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out), | ||
466 | DMA_INDEX_CHNL(params->dma_out)); | ||
467 | } | ||
468 | |||
469 | res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED, | ||
470 | "s6000-audio", pcm); | ||
471 | if (res) { | ||
472 | printk(KERN_ERR "s6000-pcm couldn't get IRQ\n"); | ||
473 | return res; | ||
474 | } | ||
475 | |||
476 | res = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
477 | SNDRV_DMA_TYPE_DEV, | ||
478 | card->dev, | ||
479 | S6_PCM_PREALLOCATE_SIZE, | ||
480 | S6_PCM_PREALLOCATE_MAX); | ||
481 | if (res) | ||
482 | printk(KERN_WARNING "s6000-pcm: preallocation failed\n"); | ||
483 | |||
484 | spin_lock_init(¶ms->lock); | ||
485 | params->in_use = 0; | ||
486 | params->rate = -1; | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static struct snd_soc_platform_driver s6000_soc_platform = { | ||
491 | .ops = &s6000_pcm_ops, | ||
492 | .pcm_new = s6000_pcm_new, | ||
493 | .pcm_free = s6000_pcm_free, | ||
494 | }; | ||
495 | |||
496 | static int s6000_soc_platform_probe(struct platform_device *pdev) | ||
497 | { | ||
498 | return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform); | ||
499 | } | ||
500 | |||
501 | static int s6000_soc_platform_remove(struct platform_device *pdev) | ||
502 | { | ||
503 | snd_soc_unregister_platform(&pdev->dev); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static struct platform_driver s6000_pcm_driver = { | ||
508 | .driver = { | ||
509 | .name = "s6000-pcm-audio", | ||
510 | .owner = THIS_MODULE, | ||
511 | }, | ||
512 | |||
513 | .probe = s6000_soc_platform_probe, | ||
514 | .remove = s6000_soc_platform_remove, | ||
515 | }; | ||
516 | |||
517 | module_platform_driver(s6000_pcm_driver); | ||
518 | |||
519 | MODULE_AUTHOR("Daniel Gloeckner"); | ||
520 | MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module"); | ||
521 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h deleted file mode 100644 index 09d9b883e58b..000000000000 --- a/sound/soc/s6000/s6000-pcm.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* | ||
2 | * ALSA PCM interface for the Stretch s6000 family | ||
3 | * | ||
4 | * Author: Daniel Gloeckner, <dg@emlix.com> | ||
5 | * Copyright: (C) 2009 emlix GmbH <info@emlix.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _S6000_PCM_H | ||
13 | #define _S6000_PCM_H | ||
14 | |||
15 | struct snd_soc_dai; | ||
16 | struct snd_pcm_substream; | ||
17 | |||
18 | struct s6000_pcm_dma_params { | ||
19 | unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai); | ||
20 | int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after); | ||
21 | dma_addr_t sif_in; | ||
22 | dma_addr_t sif_out; | ||
23 | u32 dma_in; | ||
24 | u32 dma_out; | ||
25 | int irq; | ||
26 | int same_rate; | ||
27 | |||
28 | spinlock_t lock; | ||
29 | int in_use; | ||
30 | int rate; | ||
31 | }; | ||
32 | |||
33 | #endif | ||
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c deleted file mode 100644 index 3510c01f8a6a..000000000000 --- a/sound/soc/s6000/s6105-ipcam.c +++ /dev/null | |||
@@ -1,221 +0,0 @@ | |||
1 | /* | ||
2 | * ASoC driver for Stretch s6105 IP camera platform | ||
3 | * | ||
4 | * Author: Daniel Gloeckner, <dg@emlix.com> | ||
5 | * Copyright: (C) 2009 emlix GmbH <info@emlix.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/timer.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/soc.h> | ||
21 | |||
22 | #include "s6000-pcm.h" | ||
23 | #include "s6000-i2s.h" | ||
24 | |||
25 | #define S6105_CAM_CODEC_CLOCK 12288000 | ||
26 | |||
27 | static int s6105_hw_params(struct snd_pcm_substream *substream, | ||
28 | struct snd_pcm_hw_params *params) | ||
29 | { | ||
30 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
31 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
32 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
33 | int ret = 0; | ||
34 | |||
35 | /* set codec DAI configuration */ | ||
36 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
37 | SND_SOC_DAIFMT_CBM_CFM); | ||
38 | if (ret < 0) | ||
39 | return ret; | ||
40 | |||
41 | /* set cpu DAI configuration */ | ||
42 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | | ||
43 | SND_SOC_DAIFMT_NB_NF); | ||
44 | if (ret < 0) | ||
45 | return ret; | ||
46 | |||
47 | /* set the codec system clock */ | ||
48 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK, | ||
49 | SND_SOC_CLOCK_OUT); | ||
50 | if (ret < 0) | ||
51 | return ret; | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static struct snd_soc_ops s6105_ops = { | ||
57 | .hw_params = s6105_hw_params, | ||
58 | }; | ||
59 | |||
60 | /* s6105 machine dapm widgets */ | ||
61 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | ||
62 | SND_SOC_DAPM_LINE("Audio Out Differential", NULL), | ||
63 | SND_SOC_DAPM_LINE("Audio Out Stereo", NULL), | ||
64 | SND_SOC_DAPM_LINE("Audio In", NULL), | ||
65 | }; | ||
66 | |||
67 | /* s6105 machine audio_mapnections to the codec pins */ | ||
68 | static const struct snd_soc_dapm_route audio_map[] = { | ||
69 | /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */ | ||
70 | {"Audio Out Differential", NULL, "HPLOUT"}, | ||
71 | {"Audio Out Differential", NULL, "HPLCOM"}, | ||
72 | {"Audio Out Stereo", NULL, "HPLOUT"}, | ||
73 | {"Audio Out Stereo", NULL, "HPROUT"}, | ||
74 | |||
75 | /* Audio In connected to LINE1L, LINE1R */ | ||
76 | {"LINE1L", NULL, "Audio In"}, | ||
77 | {"LINE1R", NULL, "Audio In"}, | ||
78 | }; | ||
79 | |||
80 | static int output_type_info(struct snd_kcontrol *kcontrol, | ||
81 | struct snd_ctl_elem_info *uinfo) | ||
82 | { | ||
83 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
84 | uinfo->count = 1; | ||
85 | uinfo->value.enumerated.items = 2; | ||
86 | if (uinfo->value.enumerated.item) { | ||
87 | uinfo->value.enumerated.item = 1; | ||
88 | strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT"); | ||
89 | } else { | ||
90 | strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM"); | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int output_type_get(struct snd_kcontrol *kcontrol, | ||
96 | struct snd_ctl_elem_value *ucontrol) | ||
97 | { | ||
98 | ucontrol->value.enumerated.item[0] = kcontrol->private_value; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int output_type_put(struct snd_kcontrol *kcontrol, | ||
103 | struct snd_ctl_elem_value *ucontrol) | ||
104 | { | ||
105 | struct snd_soc_card *card = kcontrol->private_data; | ||
106 | struct snd_soc_dapm_context *dapm = &card->dapm; | ||
107 | unsigned int val = (ucontrol->value.enumerated.item[0] != 0); | ||
108 | char *differential = "Audio Out Differential"; | ||
109 | char *stereo = "Audio Out Stereo"; | ||
110 | |||
111 | if (kcontrol->private_value == val) | ||
112 | return 0; | ||
113 | kcontrol->private_value = val; | ||
114 | snd_soc_dapm_disable_pin(dapm, val ? differential : stereo); | ||
115 | snd_soc_dapm_sync(dapm); | ||
116 | snd_soc_dapm_enable_pin(dapm, val ? stereo : differential); | ||
117 | snd_soc_dapm_sync(dapm); | ||
118 | |||
119 | return 1; | ||
120 | } | ||
121 | |||
122 | static const struct snd_kcontrol_new audio_out_mux = { | ||
123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
124 | .name = "Master Output Mux", | ||
125 | .index = 0, | ||
126 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
127 | .info = output_type_info, | ||
128 | .get = output_type_get, | ||
129 | .put = output_type_put, | ||
130 | .private_value = 1 /* default to stereo */ | ||
131 | }; | ||
132 | |||
133 | /* Logic for a aic3x as connected on the s6105 ip camera ref design */ | ||
134 | static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd) | ||
135 | { | ||
136 | struct snd_soc_card *card = rtd->card; | ||
137 | |||
138 | /* must correspond to audio_out_mux.private_value initializer */ | ||
139 | snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential"); | ||
140 | |||
141 | snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card)); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* s6105 digital audio interface glue - connects codec <--> CPU */ | ||
147 | static struct snd_soc_dai_link s6105_dai = { | ||
148 | .name = "TLV320AIC31", | ||
149 | .stream_name = "AIC31", | ||
150 | .cpu_dai_name = "s6000-i2s", | ||
151 | .codec_dai_name = "tlv320aic3x-hifi", | ||
152 | .platform_name = "s6000-pcm-audio", | ||
153 | .codec_name = "tlv320aic3x-codec.0-001a", | ||
154 | .init = s6105_aic3x_init, | ||
155 | .ops = &s6105_ops, | ||
156 | }; | ||
157 | |||
158 | /* s6105 audio machine driver */ | ||
159 | static struct snd_soc_card snd_soc_card_s6105 = { | ||
160 | .name = "Stretch IP Camera", | ||
161 | .owner = THIS_MODULE, | ||
162 | .dai_link = &s6105_dai, | ||
163 | .num_links = 1, | ||
164 | |||
165 | .dapm_widgets = aic3x_dapm_widgets, | ||
166 | .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets), | ||
167 | .dapm_routes = audio_map, | ||
168 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
169 | .fully_routed = true, | ||
170 | }; | ||
171 | |||
172 | static struct s6000_snd_platform_data s6105_snd_data __initdata = { | ||
173 | .wide = 0, | ||
174 | .channel_in = 0, | ||
175 | .channel_out = 1, | ||
176 | .lines_in = 1, | ||
177 | .lines_out = 1, | ||
178 | .same_rate = 1, | ||
179 | }; | ||
180 | |||
181 | static struct platform_device *s6105_snd_device; | ||
182 | |||
183 | /* temporary i2c device creation until this can be moved into the machine | ||
184 | * support file. | ||
185 | */ | ||
186 | static struct i2c_board_info i2c_device[] = { | ||
187 | { I2C_BOARD_INFO("tlv320aic33", 0x18), } | ||
188 | }; | ||
189 | |||
190 | static int __init s6105_init(void) | ||
191 | { | ||
192 | int ret; | ||
193 | |||
194 | i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device)); | ||
195 | |||
196 | s6105_snd_device = platform_device_alloc("soc-audio", -1); | ||
197 | if (!s6105_snd_device) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105); | ||
201 | platform_device_add_data(s6105_snd_device, &s6105_snd_data, | ||
202 | sizeof(s6105_snd_data)); | ||
203 | |||
204 | ret = platform_device_add(s6105_snd_device); | ||
205 | if (ret) | ||
206 | platform_device_put(s6105_snd_device); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | static void __exit s6105_exit(void) | ||
212 | { | ||
213 | platform_device_unregister(s6105_snd_device); | ||
214 | } | ||
215 | |||
216 | module_init(s6105_init); | ||
217 | module_exit(s6105_exit); | ||
218 | |||
219 | MODULE_AUTHOR("Daniel Gloeckner"); | ||
220 | MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver"); | ||
221 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 0acf5d0eed53..72118a77dd5b 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c | |||
@@ -110,6 +110,7 @@ static const struct of_device_id snow_of_match[] = { | |||
110 | { .compatible = "google,snow-audio-max98095", }, | 110 | { .compatible = "google,snow-audio-max98095", }, |
111 | {}, | 111 | {}, |
112 | }; | 112 | }; |
113 | MODULE_DEVICE_TABLE(of, snow_of_match); | ||
113 | 114 | ||
114 | static struct platform_driver snow_driver = { | 115 | static struct platform_driver snow_driver = { |
115 | .driver = { | 116 | .driver = { |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 66fddec9543d..88e5df474ccf 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -1711,8 +1711,7 @@ static const struct snd_soc_dai_ops fsi_dai_ops = { | |||
1711 | static struct snd_pcm_hardware fsi_pcm_hardware = { | 1711 | static struct snd_pcm_hardware fsi_pcm_hardware = { |
1712 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 1712 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
1713 | SNDRV_PCM_INFO_MMAP | | 1713 | SNDRV_PCM_INFO_MMAP | |
1714 | SNDRV_PCM_INFO_MMAP_VALID | | 1714 | SNDRV_PCM_INFO_MMAP_VALID, |
1715 | SNDRV_PCM_INFO_PAUSE, | ||
1716 | .buffer_bytes_max = 64 * 1024, | 1715 | .buffer_bytes_max = 64 * 1024, |
1717 | .period_bytes_min = 32, | 1716 | .period_bytes_min = 32, |
1718 | .period_bytes_max = 8192, | 1717 | .period_bytes_max = 8192, |
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1922ec57d10a..70042197f9e2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -886,8 +886,7 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
886 | static struct snd_pcm_hardware rsnd_pcm_hardware = { | 886 | static struct snd_pcm_hardware rsnd_pcm_hardware = { |
887 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 887 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
888 | SNDRV_PCM_INFO_MMAP | | 888 | SNDRV_PCM_INFO_MMAP | |
889 | SNDRV_PCM_INFO_MMAP_VALID | | 889 | SNDRV_PCM_INFO_MMAP_VALID, |
890 | SNDRV_PCM_INFO_PAUSE, | ||
891 | .buffer_bytes_max = 64 * 1024, | 890 | .buffer_bytes_max = 64 * 1024, |
892 | .period_bytes_min = 32, | 891 | .period_bytes_min = 32, |
893 | .period_bytes_max = 8192, | 892 | .period_bytes_max = 8192, |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index a9f82b5aba9d..07f43356f963 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -15,56 +15,6 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | #include <trace/events/asoc.h> | ||
19 | |||
20 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
21 | unsigned int val, unsigned int word_size) | ||
22 | { | ||
23 | switch (word_size) { | ||
24 | case 1: { | ||
25 | u8 *cache = base; | ||
26 | if (cache[idx] == val) | ||
27 | return true; | ||
28 | cache[idx] = val; | ||
29 | break; | ||
30 | } | ||
31 | case 2: { | ||
32 | u16 *cache = base; | ||
33 | if (cache[idx] == val) | ||
34 | return true; | ||
35 | cache[idx] = val; | ||
36 | break; | ||
37 | } | ||
38 | default: | ||
39 | WARN(1, "Invalid word_size %d\n", word_size); | ||
40 | break; | ||
41 | } | ||
42 | return false; | ||
43 | } | ||
44 | |||
45 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
46 | unsigned int word_size) | ||
47 | { | ||
48 | if (!base) | ||
49 | return -1; | ||
50 | |||
51 | switch (word_size) { | ||
52 | case 1: { | ||
53 | const u8 *cache = base; | ||
54 | return cache[idx]; | ||
55 | } | ||
56 | case 2: { | ||
57 | const u16 *cache = base; | ||
58 | return cache[idx]; | ||
59 | } | ||
60 | default: | ||
61 | WARN(1, "Invalid word_size %d\n", word_size); | ||
62 | break; | ||
63 | } | ||
64 | /* unreachable */ | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | int snd_soc_cache_init(struct snd_soc_codec *codec) | 18 | int snd_soc_cache_init(struct snd_soc_codec *codec) |
69 | { | 19 | { |
70 | const struct snd_soc_codec_driver *codec_drv = codec->driver; | 20 | const struct snd_soc_codec_driver *codec_drv = codec->driver; |
@@ -75,8 +25,6 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) | |||
75 | if (!reg_size) | 25 | if (!reg_size) |
76 | return 0; | 26 | return 0; |
77 | 27 | ||
78 | mutex_init(&codec->cache_rw_mutex); | ||
79 | |||
80 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", | 28 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", |
81 | codec->component.name); | 29 | codec->component.name); |
82 | 30 | ||
@@ -103,100 +51,3 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
103 | codec->reg_cache = NULL; | 51 | codec->reg_cache = NULL; |
104 | return 0; | 52 | return 0; |
105 | } | 53 | } |
106 | |||
107 | /** | ||
108 | * snd_soc_cache_read: Fetch the value of a given register from the cache. | ||
109 | * | ||
110 | * @codec: CODEC to configure. | ||
111 | * @reg: The register index. | ||
112 | * @value: The value to be returned. | ||
113 | */ | ||
114 | int snd_soc_cache_read(struct snd_soc_codec *codec, | ||
115 | unsigned int reg, unsigned int *value) | ||
116 | { | ||
117 | if (!value) | ||
118 | return -EINVAL; | ||
119 | |||
120 | mutex_lock(&codec->cache_rw_mutex); | ||
121 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
122 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | ||
123 | codec->driver->reg_word_size); | ||
124 | mutex_unlock(&codec->cache_rw_mutex); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL_GPL(snd_soc_cache_read); | ||
129 | |||
130 | /** | ||
131 | * snd_soc_cache_write: Set the value of a given register in the cache. | ||
132 | * | ||
133 | * @codec: CODEC to configure. | ||
134 | * @reg: The register index. | ||
135 | * @value: The new register value. | ||
136 | */ | ||
137 | int snd_soc_cache_write(struct snd_soc_codec *codec, | ||
138 | unsigned int reg, unsigned int value) | ||
139 | { | ||
140 | mutex_lock(&codec->cache_rw_mutex); | ||
141 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
142 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | ||
143 | codec->driver->reg_word_size); | ||
144 | mutex_unlock(&codec->cache_rw_mutex); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | EXPORT_SYMBOL_GPL(snd_soc_cache_write); | ||
149 | |||
150 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | ||
151 | { | ||
152 | int i; | ||
153 | int ret; | ||
154 | const struct snd_soc_codec_driver *codec_drv; | ||
155 | unsigned int val; | ||
156 | |||
157 | codec_drv = codec->driver; | ||
158 | for (i = 0; i < codec_drv->reg_cache_size; ++i) { | ||
159 | ret = snd_soc_cache_read(codec, i, &val); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | if (codec_drv->reg_cache_default) | ||
163 | if (snd_soc_get_cache_val(codec_drv->reg_cache_default, | ||
164 | i, codec_drv->reg_word_size) == val) | ||
165 | continue; | ||
166 | |||
167 | ret = snd_soc_write(codec, i, val); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", | ||
171 | i, val); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_cache_sync: Sync the register cache with the hardware. | ||
178 | * | ||
179 | * @codec: CODEC to configure. | ||
180 | * | ||
181 | * Any registers that should not be synced should be marked as | ||
182 | * volatile. In general drivers can choose not to use the provided | ||
183 | * syncing functionality if they so require. | ||
184 | */ | ||
185 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | ||
186 | { | ||
187 | const char *name = "flat"; | ||
188 | int ret; | ||
189 | |||
190 | if (!codec->cache_sync) | ||
191 | return 0; | ||
192 | |||
193 | dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", | ||
194 | codec->component.name); | ||
195 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
196 | ret = snd_soc_flat_cache_sync(codec); | ||
197 | if (!ret) | ||
198 | codec->cache_sync = 0; | ||
199 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
200 | return ret; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1edc519d6286..e0d3b6f109c4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -296,9 +296,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) | |||
296 | { | 296 | { |
297 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | 297 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); |
298 | 298 | ||
299 | debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, | ||
300 | &codec->cache_sync); | ||
301 | |||
302 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 299 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
303 | codec->component.debugfs_root, | 300 | codec->component.debugfs_root, |
304 | codec, &codec_reg_fops); | 301 | codec, &codec_reg_fops); |
@@ -545,17 +542,12 @@ int snd_soc_suspend(struct device *dev) | |||
545 | 542 | ||
546 | for (i = 0; i < card->num_rtd; i++) { | 543 | for (i = 0; i < card->num_rtd; i++) { |
547 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 544 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
548 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
549 | 545 | ||
550 | if (card->rtd[i].dai_link->ignore_suspend) | 546 | if (card->rtd[i].dai_link->ignore_suspend) |
551 | continue; | 547 | continue; |
552 | 548 | ||
553 | if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) | 549 | if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) |
554 | cpu_dai->driver->suspend(cpu_dai); | 550 | cpu_dai->driver->suspend(cpu_dai); |
555 | if (platform->driver->suspend && !platform->suspended) { | ||
556 | platform->driver->suspend(cpu_dai); | ||
557 | platform->suspended = 1; | ||
558 | } | ||
559 | } | 551 | } |
560 | 552 | ||
561 | /* close any waiting streams and save state */ | 553 | /* close any waiting streams and save state */ |
@@ -582,8 +574,8 @@ int snd_soc_suspend(struct device *dev) | |||
582 | SND_SOC_DAPM_STREAM_SUSPEND); | 574 | SND_SOC_DAPM_STREAM_SUSPEND); |
583 | } | 575 | } |
584 | 576 | ||
585 | /* Recheck all analogue paths too */ | 577 | /* Recheck all endpoints too, their state is affected by suspend */ |
586 | dapm_mark_io_dirty(&card->dapm); | 578 | dapm_mark_endpoints_dirty(card); |
587 | snd_soc_dapm_sync(&card->dapm); | 579 | snd_soc_dapm_sync(&card->dapm); |
588 | 580 | ||
589 | /* suspend all CODECs */ | 581 | /* suspend all CODECs */ |
@@ -609,7 +601,6 @@ int snd_soc_suspend(struct device *dev) | |||
609 | if (codec->driver->suspend) | 601 | if (codec->driver->suspend) |
610 | codec->driver->suspend(codec); | 602 | codec->driver->suspend(codec); |
611 | codec->suspended = 1; | 603 | codec->suspended = 1; |
612 | codec->cache_sync = 1; | ||
613 | if (codec->component.regmap) | 604 | if (codec->component.regmap) |
614 | regcache_mark_dirty(codec->component.regmap); | 605 | regcache_mark_dirty(codec->component.regmap); |
615 | /* deactivate pins to sleep state */ | 606 | /* deactivate pins to sleep state */ |
@@ -728,17 +719,12 @@ static void soc_resume_deferred(struct work_struct *work) | |||
728 | 719 | ||
729 | for (i = 0; i < card->num_rtd; i++) { | 720 | for (i = 0; i < card->num_rtd; i++) { |
730 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 721 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
731 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
732 | 722 | ||
733 | if (card->rtd[i].dai_link->ignore_suspend) | 723 | if (card->rtd[i].dai_link->ignore_suspend) |
734 | continue; | 724 | continue; |
735 | 725 | ||
736 | if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) | 726 | if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) |
737 | cpu_dai->driver->resume(cpu_dai); | 727 | cpu_dai->driver->resume(cpu_dai); |
738 | if (platform->driver->resume && platform->suspended) { | ||
739 | platform->driver->resume(cpu_dai); | ||
740 | platform->suspended = 0; | ||
741 | } | ||
742 | } | 728 | } |
743 | 729 | ||
744 | if (card->resume_post) | 730 | if (card->resume_post) |
@@ -749,8 +735,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
749 | /* userspace can access us now we are back as we were before */ | 735 | /* userspace can access us now we are back as we were before */ |
750 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); | 736 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); |
751 | 737 | ||
752 | /* Recheck all analogue paths too */ | 738 | /* Recheck all endpoints too, their state is affected by suspend */ |
753 | dapm_mark_io_dirty(&card->dapm); | 739 | dapm_mark_endpoints_dirty(card); |
754 | snd_soc_dapm_sync(&card->dapm); | 740 | snd_soc_dapm_sync(&card->dapm); |
755 | } | 741 | } |
756 | 742 | ||
@@ -839,7 +825,7 @@ static struct snd_soc_dai *snd_soc_find_dai( | |||
839 | list_for_each_entry(component, &component_list, list) { | 825 | list_for_each_entry(component, &component_list, list) { |
840 | if (dlc->of_node && component->dev->of_node != dlc->of_node) | 826 | if (dlc->of_node && component->dev->of_node != dlc->of_node) |
841 | continue; | 827 | continue; |
842 | if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) | 828 | if (dlc->name && strcmp(component->name, dlc->name)) |
843 | continue; | 829 | continue; |
844 | list_for_each_entry(dai, &component->dai_list, list) { | 830 | list_for_each_entry(dai, &component->dai_list, list) { |
845 | if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) | 831 | if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) |
@@ -1206,25 +1192,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1206 | return 0; | 1192 | return 0; |
1207 | } | 1193 | } |
1208 | 1194 | ||
1209 | static int soc_probe_codec_dai(struct snd_soc_card *card, | 1195 | static int soc_probe_dai(struct snd_soc_dai *dai, int order) |
1210 | struct snd_soc_dai *codec_dai, | ||
1211 | int order) | ||
1212 | { | 1196 | { |
1213 | int ret; | 1197 | int ret; |
1214 | 1198 | ||
1215 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { | 1199 | if (!dai->probed && dai->driver->probe_order == order) { |
1216 | if (codec_dai->driver->probe) { | 1200 | if (dai->driver->probe) { |
1217 | ret = codec_dai->driver->probe(codec_dai); | 1201 | ret = dai->driver->probe(dai); |
1218 | if (ret < 0) { | 1202 | if (ret < 0) { |
1219 | dev_err(codec_dai->dev, | 1203 | dev_err(dai->dev, |
1220 | "ASoC: failed to probe CODEC DAI %s: %d\n", | 1204 | "ASoC: failed to probe DAI %s: %d\n", |
1221 | codec_dai->name, ret); | 1205 | dai->name, ret); |
1222 | return ret; | 1206 | return ret; |
1223 | } | 1207 | } |
1224 | } | 1208 | } |
1225 | 1209 | ||
1226 | /* mark codec_dai as probed and add to card dai list */ | 1210 | dai->probed = 1; |
1227 | codec_dai->probed = 1; | ||
1228 | } | 1211 | } |
1229 | 1212 | ||
1230 | return 0; | 1213 | return 0; |
@@ -1274,40 +1257,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1274 | { | 1257 | { |
1275 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1258 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1276 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1259 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1277 | struct snd_soc_platform *platform = rtd->platform; | ||
1278 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1260 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1279 | int i, ret; | 1261 | int i, ret; |
1280 | 1262 | ||
1281 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", | 1263 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", |
1282 | card->name, num, order); | 1264 | card->name, num, order); |
1283 | 1265 | ||
1284 | /* config components */ | ||
1285 | cpu_dai->platform = platform; | ||
1286 | cpu_dai->card = card; | ||
1287 | for (i = 0; i < rtd->num_codecs; i++) | ||
1288 | rtd->codec_dais[i]->card = card; | ||
1289 | |||
1290 | /* set default power off timeout */ | 1266 | /* set default power off timeout */ |
1291 | rtd->pmdown_time = pmdown_time; | 1267 | rtd->pmdown_time = pmdown_time; |
1292 | 1268 | ||
1293 | /* probe the cpu_dai */ | 1269 | ret = soc_probe_dai(cpu_dai, order); |
1294 | if (!cpu_dai->probed && | 1270 | if (ret) |
1295 | cpu_dai->driver->probe_order == order) { | 1271 | return ret; |
1296 | if (cpu_dai->driver->probe) { | ||
1297 | ret = cpu_dai->driver->probe(cpu_dai); | ||
1298 | if (ret < 0) { | ||
1299 | dev_err(cpu_dai->dev, | ||
1300 | "ASoC: failed to probe CPU DAI %s: %d\n", | ||
1301 | cpu_dai->name, ret); | ||
1302 | return ret; | ||
1303 | } | ||
1304 | } | ||
1305 | cpu_dai->probed = 1; | ||
1306 | } | ||
1307 | 1272 | ||
1308 | /* probe the CODEC DAI */ | 1273 | /* probe the CODEC DAI */ |
1309 | for (i = 0; i < rtd->num_codecs; i++) { | 1274 | for (i = 0; i < rtd->num_codecs; i++) { |
1310 | ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order); | 1275 | ret = soc_probe_dai(rtd->codec_dais[i], order); |
1311 | if (ret) | 1276 | if (ret) |
1312 | return ret; | 1277 | return ret; |
1313 | } | 1278 | } |
@@ -1982,7 +1947,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); | |||
1982 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | 1947 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, |
1983 | const struct snd_kcontrol_new *controls, int num_controls) | 1948 | const struct snd_kcontrol_new *controls, int num_controls) |
1984 | { | 1949 | { |
1985 | struct snd_card *card = dai->card->snd_card; | 1950 | struct snd_card *card = dai->component->card->snd_card; |
1986 | 1951 | ||
1987 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, | 1952 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, |
1988 | NULL, dai); | 1953 | NULL, dai); |
@@ -1990,1020 +1955,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | |||
1990 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); | 1955 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); |
1991 | 1956 | ||
1992 | /** | 1957 | /** |
1993 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
1994 | * @kcontrol: mixer control | ||
1995 | * @uinfo: control element information | ||
1996 | * | ||
1997 | * Callback to provide information about a double enumerated | ||
1998 | * mixer control. | ||
1999 | * | ||
2000 | * Returns 0 for success. | ||
2001 | */ | ||
2002 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
2003 | struct snd_ctl_elem_info *uinfo) | ||
2004 | { | ||
2005 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2006 | |||
2007 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2008 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
2009 | uinfo->value.enumerated.items = e->items; | ||
2010 | |||
2011 | if (uinfo->value.enumerated.item >= e->items) | ||
2012 | uinfo->value.enumerated.item = e->items - 1; | ||
2013 | strlcpy(uinfo->value.enumerated.name, | ||
2014 | e->texts[uinfo->value.enumerated.item], | ||
2015 | sizeof(uinfo->value.enumerated.name)); | ||
2016 | return 0; | ||
2017 | } | ||
2018 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
2019 | |||
2020 | /** | ||
2021 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
2022 | * @kcontrol: mixer control | ||
2023 | * @ucontrol: control element information | ||
2024 | * | ||
2025 | * Callback to get the value of a double enumerated mixer. | ||
2026 | * | ||
2027 | * Returns 0 for success. | ||
2028 | */ | ||
2029 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
2030 | struct snd_ctl_elem_value *ucontrol) | ||
2031 | { | ||
2032 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2033 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2034 | unsigned int val, item; | ||
2035 | unsigned int reg_val; | ||
2036 | int ret; | ||
2037 | |||
2038 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
2039 | if (ret) | ||
2040 | return ret; | ||
2041 | val = (reg_val >> e->shift_l) & e->mask; | ||
2042 | item = snd_soc_enum_val_to_item(e, val); | ||
2043 | ucontrol->value.enumerated.item[0] = item; | ||
2044 | if (e->shift_l != e->shift_r) { | ||
2045 | val = (reg_val >> e->shift_l) & e->mask; | ||
2046 | item = snd_soc_enum_val_to_item(e, val); | ||
2047 | ucontrol->value.enumerated.item[1] = item; | ||
2048 | } | ||
2049 | |||
2050 | return 0; | ||
2051 | } | ||
2052 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
2053 | |||
2054 | /** | ||
2055 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
2056 | * @kcontrol: mixer control | ||
2057 | * @ucontrol: control element information | ||
2058 | * | ||
2059 | * Callback to set the value of a double enumerated mixer. | ||
2060 | * | ||
2061 | * Returns 0 for success. | ||
2062 | */ | ||
2063 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
2064 | struct snd_ctl_elem_value *ucontrol) | ||
2065 | { | ||
2066 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2067 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2068 | unsigned int *item = ucontrol->value.enumerated.item; | ||
2069 | unsigned int val; | ||
2070 | unsigned int mask; | ||
2071 | |||
2072 | if (item[0] >= e->items) | ||
2073 | return -EINVAL; | ||
2074 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
2075 | mask = e->mask << e->shift_l; | ||
2076 | if (e->shift_l != e->shift_r) { | ||
2077 | if (item[1] >= e->items) | ||
2078 | return -EINVAL; | ||
2079 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
2080 | mask |= e->mask << e->shift_r; | ||
2081 | } | ||
2082 | |||
2083 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
2084 | } | ||
2085 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
2086 | |||
2087 | /** | ||
2088 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
2089 | * @component: component | ||
2090 | * @reg: Register to read | ||
2091 | * @mask: Mask to use after shifting the register value | ||
2092 | * @shift: Right shift of register value | ||
2093 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2094 | * @signed_val: Pointer to where the read value should be stored | ||
2095 | * | ||
2096 | * This functions reads a codec register. The register value is shifted right | ||
2097 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
2098 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2099 | * | ||
2100 | * Returns 0 on sucess, otherwise an error value | ||
2101 | */ | ||
2102 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
2103 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
2104 | unsigned int sign_bit, int *signed_val) | ||
2105 | { | ||
2106 | int ret; | ||
2107 | unsigned int val; | ||
2108 | |||
2109 | ret = snd_soc_component_read(component, reg, &val); | ||
2110 | if (ret < 0) | ||
2111 | return ret; | ||
2112 | |||
2113 | val = (val >> shift) & mask; | ||
2114 | |||
2115 | if (!sign_bit) { | ||
2116 | *signed_val = val; | ||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | /* non-negative number */ | ||
2121 | if (!(val & BIT(sign_bit))) { | ||
2122 | *signed_val = val; | ||
2123 | return 0; | ||
2124 | } | ||
2125 | |||
2126 | ret = val; | ||
2127 | |||
2128 | /* | ||
2129 | * The register most probably does not contain a full-sized int. | ||
2130 | * Instead we have an arbitrary number of bits in a signed | ||
2131 | * representation which has to be translated into a full-sized int. | ||
2132 | * This is done by filling up all bits above the sign-bit. | ||
2133 | */ | ||
2134 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2135 | |||
2136 | *signed_val = ret; | ||
2137 | |||
2138 | return 0; | ||
2139 | } | ||
2140 | |||
2141 | /** | ||
2142 | * snd_soc_info_volsw - single mixer info callback | ||
2143 | * @kcontrol: mixer control | ||
2144 | * @uinfo: control element information | ||
2145 | * | ||
2146 | * Callback to provide information about a single mixer control, or a double | ||
2147 | * mixer control that spans 2 registers. | ||
2148 | * | ||
2149 | * Returns 0 for success. | ||
2150 | */ | ||
2151 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
2152 | struct snd_ctl_elem_info *uinfo) | ||
2153 | { | ||
2154 | struct soc_mixer_control *mc = | ||
2155 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2156 | int platform_max; | ||
2157 | |||
2158 | if (!mc->platform_max) | ||
2159 | mc->platform_max = mc->max; | ||
2160 | platform_max = mc->platform_max; | ||
2161 | |||
2162 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2163 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2164 | else | ||
2165 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2166 | |||
2167 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2168 | uinfo->value.integer.min = 0; | ||
2169 | uinfo->value.integer.max = platform_max - mc->min; | ||
2170 | return 0; | ||
2171 | } | ||
2172 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
2173 | |||
2174 | /** | ||
2175 | * snd_soc_get_volsw - single mixer get callback | ||
2176 | * @kcontrol: mixer control | ||
2177 | * @ucontrol: control element information | ||
2178 | * | ||
2179 | * Callback to get the value of a single mixer control, or a double mixer | ||
2180 | * control that spans 2 registers. | ||
2181 | * | ||
2182 | * Returns 0 for success. | ||
2183 | */ | ||
2184 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
2185 | struct snd_ctl_elem_value *ucontrol) | ||
2186 | { | ||
2187 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2188 | struct soc_mixer_control *mc = | ||
2189 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2190 | unsigned int reg = mc->reg; | ||
2191 | unsigned int reg2 = mc->rreg; | ||
2192 | unsigned int shift = mc->shift; | ||
2193 | unsigned int rshift = mc->rshift; | ||
2194 | int max = mc->max; | ||
2195 | int min = mc->min; | ||
2196 | int sign_bit = mc->sign_bit; | ||
2197 | unsigned int mask = (1 << fls(max)) - 1; | ||
2198 | unsigned int invert = mc->invert; | ||
2199 | int val; | ||
2200 | int ret; | ||
2201 | |||
2202 | if (sign_bit) | ||
2203 | mask = BIT(sign_bit + 1) - 1; | ||
2204 | |||
2205 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
2206 | if (ret) | ||
2207 | return ret; | ||
2208 | |||
2209 | ucontrol->value.integer.value[0] = val - min; | ||
2210 | if (invert) | ||
2211 | ucontrol->value.integer.value[0] = | ||
2212 | max - ucontrol->value.integer.value[0]; | ||
2213 | |||
2214 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2215 | if (reg == reg2) | ||
2216 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
2217 | sign_bit, &val); | ||
2218 | else | ||
2219 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
2220 | sign_bit, &val); | ||
2221 | if (ret) | ||
2222 | return ret; | ||
2223 | |||
2224 | ucontrol->value.integer.value[1] = val - min; | ||
2225 | if (invert) | ||
2226 | ucontrol->value.integer.value[1] = | ||
2227 | max - ucontrol->value.integer.value[1]; | ||
2228 | } | ||
2229 | |||
2230 | return 0; | ||
2231 | } | ||
2232 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
2233 | |||
2234 | /** | ||
2235 | * snd_soc_put_volsw - single mixer put callback | ||
2236 | * @kcontrol: mixer control | ||
2237 | * @ucontrol: control element information | ||
2238 | * | ||
2239 | * Callback to set the value of a single mixer control, or a double mixer | ||
2240 | * control that spans 2 registers. | ||
2241 | * | ||
2242 | * Returns 0 for success. | ||
2243 | */ | ||
2244 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
2245 | struct snd_ctl_elem_value *ucontrol) | ||
2246 | { | ||
2247 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2248 | struct soc_mixer_control *mc = | ||
2249 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2250 | unsigned int reg = mc->reg; | ||
2251 | unsigned int reg2 = mc->rreg; | ||
2252 | unsigned int shift = mc->shift; | ||
2253 | unsigned int rshift = mc->rshift; | ||
2254 | int max = mc->max; | ||
2255 | int min = mc->min; | ||
2256 | unsigned int sign_bit = mc->sign_bit; | ||
2257 | unsigned int mask = (1 << fls(max)) - 1; | ||
2258 | unsigned int invert = mc->invert; | ||
2259 | int err; | ||
2260 | bool type_2r = false; | ||
2261 | unsigned int val2 = 0; | ||
2262 | unsigned int val, val_mask; | ||
2263 | |||
2264 | if (sign_bit) | ||
2265 | mask = BIT(sign_bit + 1) - 1; | ||
2266 | |||
2267 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2268 | if (invert) | ||
2269 | val = max - val; | ||
2270 | val_mask = mask << shift; | ||
2271 | val = val << shift; | ||
2272 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2273 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2274 | if (invert) | ||
2275 | val2 = max - val2; | ||
2276 | if (reg == reg2) { | ||
2277 | val_mask |= mask << rshift; | ||
2278 | val |= val2 << rshift; | ||
2279 | } else { | ||
2280 | val2 = val2 << shift; | ||
2281 | type_2r = true; | ||
2282 | } | ||
2283 | } | ||
2284 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2285 | if (err < 0) | ||
2286 | return err; | ||
2287 | |||
2288 | if (type_2r) | ||
2289 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2290 | val2); | ||
2291 | |||
2292 | return err; | ||
2293 | } | ||
2294 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
2295 | |||
2296 | /** | ||
2297 | * snd_soc_get_volsw_sx - single mixer get callback | ||
2298 | * @kcontrol: mixer control | ||
2299 | * @ucontrol: control element information | ||
2300 | * | ||
2301 | * Callback to get the value of a single mixer control, or a double mixer | ||
2302 | * control that spans 2 registers. | ||
2303 | * | ||
2304 | * Returns 0 for success. | ||
2305 | */ | ||
2306 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2307 | struct snd_ctl_elem_value *ucontrol) | ||
2308 | { | ||
2309 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2310 | struct soc_mixer_control *mc = | ||
2311 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2312 | unsigned int reg = mc->reg; | ||
2313 | unsigned int reg2 = mc->rreg; | ||
2314 | unsigned int shift = mc->shift; | ||
2315 | unsigned int rshift = mc->rshift; | ||
2316 | int max = mc->max; | ||
2317 | int min = mc->min; | ||
2318 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2319 | unsigned int val; | ||
2320 | int ret; | ||
2321 | |||
2322 | ret = snd_soc_component_read(component, reg, &val); | ||
2323 | if (ret < 0) | ||
2324 | return ret; | ||
2325 | |||
2326 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
2327 | |||
2328 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2329 | ret = snd_soc_component_read(component, reg2, &val); | ||
2330 | if (ret < 0) | ||
2331 | return ret; | ||
2332 | |||
2333 | val = ((val >> rshift) - min) & mask; | ||
2334 | ucontrol->value.integer.value[1] = val; | ||
2335 | } | ||
2336 | |||
2337 | return 0; | ||
2338 | } | ||
2339 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
2340 | |||
2341 | /** | ||
2342 | * snd_soc_put_volsw_sx - double mixer set callback | ||
2343 | * @kcontrol: mixer control | ||
2344 | * @uinfo: control element information | ||
2345 | * | ||
2346 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
2347 | * | ||
2348 | * Returns 0 for success. | ||
2349 | */ | ||
2350 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2351 | struct snd_ctl_elem_value *ucontrol) | ||
2352 | { | ||
2353 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2354 | struct soc_mixer_control *mc = | ||
2355 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2356 | |||
2357 | unsigned int reg = mc->reg; | ||
2358 | unsigned int reg2 = mc->rreg; | ||
2359 | unsigned int shift = mc->shift; | ||
2360 | unsigned int rshift = mc->rshift; | ||
2361 | int max = mc->max; | ||
2362 | int min = mc->min; | ||
2363 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2364 | int err = 0; | ||
2365 | unsigned int val, val_mask, val2 = 0; | ||
2366 | |||
2367 | val_mask = mask << shift; | ||
2368 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
2369 | val = val << shift; | ||
2370 | |||
2371 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2372 | if (err < 0) | ||
2373 | return err; | ||
2374 | |||
2375 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2376 | val_mask = mask << rshift; | ||
2377 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
2378 | val2 = val2 << rshift; | ||
2379 | |||
2380 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2381 | val2); | ||
2382 | } | ||
2383 | return err; | ||
2384 | } | ||
2385 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
2386 | |||
2387 | /** | ||
2388 | * snd_soc_info_volsw_s8 - signed mixer info callback | ||
2389 | * @kcontrol: mixer control | ||
2390 | * @uinfo: control element information | ||
2391 | * | ||
2392 | * Callback to provide information about a signed mixer control. | ||
2393 | * | ||
2394 | * Returns 0 for success. | ||
2395 | */ | ||
2396 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2397 | struct snd_ctl_elem_info *uinfo) | ||
2398 | { | ||
2399 | struct soc_mixer_control *mc = | ||
2400 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2401 | int platform_max; | ||
2402 | int min = mc->min; | ||
2403 | |||
2404 | if (!mc->platform_max) | ||
2405 | mc->platform_max = mc->max; | ||
2406 | platform_max = mc->platform_max; | ||
2407 | |||
2408 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2409 | uinfo->count = 2; | ||
2410 | uinfo->value.integer.min = 0; | ||
2411 | uinfo->value.integer.max = platform_max - min; | ||
2412 | return 0; | ||
2413 | } | ||
2414 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | ||
2415 | |||
2416 | /** | ||
2417 | * snd_soc_get_volsw_s8 - signed mixer get callback | ||
2418 | * @kcontrol: mixer control | ||
2419 | * @ucontrol: control element information | ||
2420 | * | ||
2421 | * Callback to get the value of a signed mixer control. | ||
2422 | * | ||
2423 | * Returns 0 for success. | ||
2424 | */ | ||
2425 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2426 | struct snd_ctl_elem_value *ucontrol) | ||
2427 | { | ||
2428 | struct soc_mixer_control *mc = | ||
2429 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2430 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2431 | unsigned int reg = mc->reg; | ||
2432 | unsigned int val; | ||
2433 | int min = mc->min; | ||
2434 | int ret; | ||
2435 | |||
2436 | ret = snd_soc_component_read(component, reg, &val); | ||
2437 | if (ret) | ||
2438 | return ret; | ||
2439 | |||
2440 | ucontrol->value.integer.value[0] = | ||
2441 | ((signed char)(val & 0xff))-min; | ||
2442 | ucontrol->value.integer.value[1] = | ||
2443 | ((signed char)((val >> 8) & 0xff))-min; | ||
2444 | return 0; | ||
2445 | } | ||
2446 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | ||
2447 | |||
2448 | /** | ||
2449 | * snd_soc_put_volsw_sgn - signed mixer put callback | ||
2450 | * @kcontrol: mixer control | ||
2451 | * @ucontrol: control element information | ||
2452 | * | ||
2453 | * Callback to set the value of a signed mixer control. | ||
2454 | * | ||
2455 | * Returns 0 for success. | ||
2456 | */ | ||
2457 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2458 | struct snd_ctl_elem_value *ucontrol) | ||
2459 | { | ||
2460 | struct soc_mixer_control *mc = | ||
2461 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2462 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2463 | unsigned int reg = mc->reg; | ||
2464 | int min = mc->min; | ||
2465 | unsigned int val; | ||
2466 | |||
2467 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | ||
2468 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | ||
2469 | |||
2470 | return snd_soc_component_update_bits(component, reg, 0xffff, val); | ||
2471 | } | ||
2472 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | ||
2473 | |||
2474 | /** | ||
2475 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
2476 | * @kcontrol: mixer control | ||
2477 | * @uinfo: control element information | ||
2478 | * | ||
2479 | * Callback to provide information, within a range, about a single | ||
2480 | * mixer control. | ||
2481 | * | ||
2482 | * returns 0 for success. | ||
2483 | */ | ||
2484 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
2485 | struct snd_ctl_elem_info *uinfo) | ||
2486 | { | ||
2487 | struct soc_mixer_control *mc = | ||
2488 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2489 | int platform_max; | ||
2490 | int min = mc->min; | ||
2491 | |||
2492 | if (!mc->platform_max) | ||
2493 | mc->platform_max = mc->max; | ||
2494 | platform_max = mc->platform_max; | ||
2495 | |||
2496 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2497 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2498 | uinfo->value.integer.min = 0; | ||
2499 | uinfo->value.integer.max = platform_max - min; | ||
2500 | |||
2501 | return 0; | ||
2502 | } | ||
2503 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
2504 | |||
2505 | /** | ||
2506 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
2507 | * @kcontrol: mixer control | ||
2508 | * @ucontrol: control element information | ||
2509 | * | ||
2510 | * Callback to set the value, within a range, for a single mixer control. | ||
2511 | * | ||
2512 | * Returns 0 for success. | ||
2513 | */ | ||
2514 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
2515 | struct snd_ctl_elem_value *ucontrol) | ||
2516 | { | ||
2517 | struct soc_mixer_control *mc = | ||
2518 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2519 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2520 | unsigned int reg = mc->reg; | ||
2521 | unsigned int rreg = mc->rreg; | ||
2522 | unsigned int shift = mc->shift; | ||
2523 | int min = mc->min; | ||
2524 | int max = mc->max; | ||
2525 | unsigned int mask = (1 << fls(max)) - 1; | ||
2526 | unsigned int invert = mc->invert; | ||
2527 | unsigned int val, val_mask; | ||
2528 | int ret; | ||
2529 | |||
2530 | if (invert) | ||
2531 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
2532 | else | ||
2533 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2534 | val_mask = mask << shift; | ||
2535 | val = val << shift; | ||
2536 | |||
2537 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2538 | if (ret < 0) | ||
2539 | return ret; | ||
2540 | |||
2541 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2542 | if (invert) | ||
2543 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
2544 | else | ||
2545 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2546 | val_mask = mask << shift; | ||
2547 | val = val << shift; | ||
2548 | |||
2549 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
2550 | val); | ||
2551 | } | ||
2552 | |||
2553 | return ret; | ||
2554 | } | ||
2555 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
2556 | |||
2557 | /** | ||
2558 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
2559 | * @kcontrol: mixer control | ||
2560 | * @ucontrol: control element information | ||
2561 | * | ||
2562 | * Callback to get the value, within a range, of a single mixer control. | ||
2563 | * | ||
2564 | * Returns 0 for success. | ||
2565 | */ | ||
2566 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
2567 | struct snd_ctl_elem_value *ucontrol) | ||
2568 | { | ||
2569 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2570 | struct soc_mixer_control *mc = | ||
2571 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2572 | unsigned int reg = mc->reg; | ||
2573 | unsigned int rreg = mc->rreg; | ||
2574 | unsigned int shift = mc->shift; | ||
2575 | int min = mc->min; | ||
2576 | int max = mc->max; | ||
2577 | unsigned int mask = (1 << fls(max)) - 1; | ||
2578 | unsigned int invert = mc->invert; | ||
2579 | unsigned int val; | ||
2580 | int ret; | ||
2581 | |||
2582 | ret = snd_soc_component_read(component, reg, &val); | ||
2583 | if (ret) | ||
2584 | return ret; | ||
2585 | |||
2586 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
2587 | if (invert) | ||
2588 | ucontrol->value.integer.value[0] = | ||
2589 | max - ucontrol->value.integer.value[0]; | ||
2590 | else | ||
2591 | ucontrol->value.integer.value[0] = | ||
2592 | ucontrol->value.integer.value[0] - min; | ||
2593 | |||
2594 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2595 | ret = snd_soc_component_read(component, rreg, &val); | ||
2596 | if (ret) | ||
2597 | return ret; | ||
2598 | |||
2599 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
2600 | if (invert) | ||
2601 | ucontrol->value.integer.value[1] = | ||
2602 | max - ucontrol->value.integer.value[1]; | ||
2603 | else | ||
2604 | ucontrol->value.integer.value[1] = | ||
2605 | ucontrol->value.integer.value[1] - min; | ||
2606 | } | ||
2607 | |||
2608 | return 0; | ||
2609 | } | ||
2610 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
2611 | |||
2612 | /** | ||
2613 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
2614 | * | ||
2615 | * @codec: where to look for the control | ||
2616 | * @name: Name of the control | ||
2617 | * @max: new maximum limit | ||
2618 | * | ||
2619 | * Return 0 for success, else error. | ||
2620 | */ | ||
2621 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
2622 | const char *name, int max) | ||
2623 | { | ||
2624 | struct snd_card *card = codec->component.card->snd_card; | ||
2625 | struct snd_kcontrol *kctl; | ||
2626 | struct soc_mixer_control *mc; | ||
2627 | int found = 0; | ||
2628 | int ret = -EINVAL; | ||
2629 | |||
2630 | /* Sanity check for name and max */ | ||
2631 | if (unlikely(!name || max <= 0)) | ||
2632 | return -EINVAL; | ||
2633 | |||
2634 | list_for_each_entry(kctl, &card->controls, list) { | ||
2635 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
2636 | found = 1; | ||
2637 | break; | ||
2638 | } | ||
2639 | } | ||
2640 | if (found) { | ||
2641 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
2642 | if (max <= mc->max) { | ||
2643 | mc->platform_max = max; | ||
2644 | ret = 0; | ||
2645 | } | ||
2646 | } | ||
2647 | return ret; | ||
2648 | } | ||
2649 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
2650 | |||
2651 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
2652 | struct snd_ctl_elem_info *uinfo) | ||
2653 | { | ||
2654 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2655 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
2656 | |||
2657 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
2658 | uinfo->count = params->num_regs * component->val_bytes; | ||
2659 | |||
2660 | return 0; | ||
2661 | } | ||
2662 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
2663 | |||
2664 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
2665 | struct snd_ctl_elem_value *ucontrol) | ||
2666 | { | ||
2667 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2668 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
2669 | int ret; | ||
2670 | |||
2671 | if (component->regmap) | ||
2672 | ret = regmap_raw_read(component->regmap, params->base, | ||
2673 | ucontrol->value.bytes.data, | ||
2674 | params->num_regs * component->val_bytes); | ||
2675 | else | ||
2676 | ret = -EINVAL; | ||
2677 | |||
2678 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
2679 | if (ret == 0 && params->mask) { | ||
2680 | switch (component->val_bytes) { | ||
2681 | case 1: | ||
2682 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
2683 | break; | ||
2684 | case 2: | ||
2685 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
2686 | &= cpu_to_be16(~params->mask); | ||
2687 | break; | ||
2688 | case 4: | ||
2689 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
2690 | &= cpu_to_be32(~params->mask); | ||
2691 | break; | ||
2692 | default: | ||
2693 | return -EINVAL; | ||
2694 | } | ||
2695 | } | ||
2696 | |||
2697 | return ret; | ||
2698 | } | ||
2699 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
2700 | |||
2701 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
2702 | struct snd_ctl_elem_value *ucontrol) | ||
2703 | { | ||
2704 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2705 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
2706 | int ret, len; | ||
2707 | unsigned int val, mask; | ||
2708 | void *data; | ||
2709 | |||
2710 | if (!component->regmap || !params->num_regs) | ||
2711 | return -EINVAL; | ||
2712 | |||
2713 | len = params->num_regs * component->val_bytes; | ||
2714 | |||
2715 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
2716 | if (!data) | ||
2717 | return -ENOMEM; | ||
2718 | |||
2719 | /* | ||
2720 | * If we've got a mask then we need to preserve the register | ||
2721 | * bits. We shouldn't modify the incoming data so take a | ||
2722 | * copy. | ||
2723 | */ | ||
2724 | if (params->mask) { | ||
2725 | ret = regmap_read(component->regmap, params->base, &val); | ||
2726 | if (ret != 0) | ||
2727 | goto out; | ||
2728 | |||
2729 | val &= params->mask; | ||
2730 | |||
2731 | switch (component->val_bytes) { | ||
2732 | case 1: | ||
2733 | ((u8 *)data)[0] &= ~params->mask; | ||
2734 | ((u8 *)data)[0] |= val; | ||
2735 | break; | ||
2736 | case 2: | ||
2737 | mask = ~params->mask; | ||
2738 | ret = regmap_parse_val(component->regmap, | ||
2739 | &mask, &mask); | ||
2740 | if (ret != 0) | ||
2741 | goto out; | ||
2742 | |||
2743 | ((u16 *)data)[0] &= mask; | ||
2744 | |||
2745 | ret = regmap_parse_val(component->regmap, | ||
2746 | &val, &val); | ||
2747 | if (ret != 0) | ||
2748 | goto out; | ||
2749 | |||
2750 | ((u16 *)data)[0] |= val; | ||
2751 | break; | ||
2752 | case 4: | ||
2753 | mask = ~params->mask; | ||
2754 | ret = regmap_parse_val(component->regmap, | ||
2755 | &mask, &mask); | ||
2756 | if (ret != 0) | ||
2757 | goto out; | ||
2758 | |||
2759 | ((u32 *)data)[0] &= mask; | ||
2760 | |||
2761 | ret = regmap_parse_val(component->regmap, | ||
2762 | &val, &val); | ||
2763 | if (ret != 0) | ||
2764 | goto out; | ||
2765 | |||
2766 | ((u32 *)data)[0] |= val; | ||
2767 | break; | ||
2768 | default: | ||
2769 | ret = -EINVAL; | ||
2770 | goto out; | ||
2771 | } | ||
2772 | } | ||
2773 | |||
2774 | ret = regmap_raw_write(component->regmap, params->base, | ||
2775 | data, len); | ||
2776 | |||
2777 | out: | ||
2778 | kfree(data); | ||
2779 | |||
2780 | return ret; | ||
2781 | } | ||
2782 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
2783 | |||
2784 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
2785 | struct snd_ctl_elem_info *ucontrol) | ||
2786 | { | ||
2787 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
2788 | |||
2789 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
2790 | ucontrol->count = params->max; | ||
2791 | |||
2792 | return 0; | ||
2793 | } | ||
2794 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
2795 | |||
2796 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
2797 | unsigned int size, unsigned int __user *tlv) | ||
2798 | { | ||
2799 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
2800 | unsigned int count = size < params->max ? size : params->max; | ||
2801 | int ret = -ENXIO; | ||
2802 | |||
2803 | switch (op_flag) { | ||
2804 | case SNDRV_CTL_TLV_OP_READ: | ||
2805 | if (params->get) | ||
2806 | ret = params->get(tlv, count); | ||
2807 | break; | ||
2808 | case SNDRV_CTL_TLV_OP_WRITE: | ||
2809 | if (params->put) | ||
2810 | ret = params->put(tlv, count); | ||
2811 | break; | ||
2812 | } | ||
2813 | return ret; | ||
2814 | } | ||
2815 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
2816 | |||
2817 | /** | ||
2818 | * snd_soc_info_xr_sx - signed multi register info callback | ||
2819 | * @kcontrol: mreg control | ||
2820 | * @uinfo: control element information | ||
2821 | * | ||
2822 | * Callback to provide information of a control that can | ||
2823 | * span multiple codec registers which together | ||
2824 | * forms a single signed value in a MSB/LSB manner. | ||
2825 | * | ||
2826 | * Returns 0 for success. | ||
2827 | */ | ||
2828 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
2829 | struct snd_ctl_elem_info *uinfo) | ||
2830 | { | ||
2831 | struct soc_mreg_control *mc = | ||
2832 | (struct soc_mreg_control *)kcontrol->private_value; | ||
2833 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2834 | uinfo->count = 1; | ||
2835 | uinfo->value.integer.min = mc->min; | ||
2836 | uinfo->value.integer.max = mc->max; | ||
2837 | |||
2838 | return 0; | ||
2839 | } | ||
2840 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
2841 | |||
2842 | /** | ||
2843 | * snd_soc_get_xr_sx - signed multi register get callback | ||
2844 | * @kcontrol: mreg control | ||
2845 | * @ucontrol: control element information | ||
2846 | * | ||
2847 | * Callback to get the value of a control that can span | ||
2848 | * multiple codec registers which together forms a single | ||
2849 | * signed value in a MSB/LSB manner. The control supports | ||
2850 | * specifying total no of bits used to allow for bitfields | ||
2851 | * across the multiple codec registers. | ||
2852 | * | ||
2853 | * Returns 0 for success. | ||
2854 | */ | ||
2855 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
2856 | struct snd_ctl_elem_value *ucontrol) | ||
2857 | { | ||
2858 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2859 | struct soc_mreg_control *mc = | ||
2860 | (struct soc_mreg_control *)kcontrol->private_value; | ||
2861 | unsigned int regbase = mc->regbase; | ||
2862 | unsigned int regcount = mc->regcount; | ||
2863 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
2864 | unsigned int regwmask = (1<<regwshift)-1; | ||
2865 | unsigned int invert = mc->invert; | ||
2866 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
2867 | long min = mc->min; | ||
2868 | long max = mc->max; | ||
2869 | long val = 0; | ||
2870 | unsigned int regval; | ||
2871 | unsigned int i; | ||
2872 | int ret; | ||
2873 | |||
2874 | for (i = 0; i < regcount; i++) { | ||
2875 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
2876 | if (ret) | ||
2877 | return ret; | ||
2878 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
2879 | } | ||
2880 | val &= mask; | ||
2881 | if (min < 0 && val > max) | ||
2882 | val |= ~mask; | ||
2883 | if (invert) | ||
2884 | val = max - val; | ||
2885 | ucontrol->value.integer.value[0] = val; | ||
2886 | |||
2887 | return 0; | ||
2888 | } | ||
2889 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
2890 | |||
2891 | /** | ||
2892 | * snd_soc_put_xr_sx - signed multi register get callback | ||
2893 | * @kcontrol: mreg control | ||
2894 | * @ucontrol: control element information | ||
2895 | * | ||
2896 | * Callback to set the value of a control that can span | ||
2897 | * multiple codec registers which together forms a single | ||
2898 | * signed value in a MSB/LSB manner. The control supports | ||
2899 | * specifying total no of bits used to allow for bitfields | ||
2900 | * across the multiple codec registers. | ||
2901 | * | ||
2902 | * Returns 0 for success. | ||
2903 | */ | ||
2904 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
2905 | struct snd_ctl_elem_value *ucontrol) | ||
2906 | { | ||
2907 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2908 | struct soc_mreg_control *mc = | ||
2909 | (struct soc_mreg_control *)kcontrol->private_value; | ||
2910 | unsigned int regbase = mc->regbase; | ||
2911 | unsigned int regcount = mc->regcount; | ||
2912 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
2913 | unsigned int regwmask = (1<<regwshift)-1; | ||
2914 | unsigned int invert = mc->invert; | ||
2915 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
2916 | long max = mc->max; | ||
2917 | long val = ucontrol->value.integer.value[0]; | ||
2918 | unsigned int i, regval, regmask; | ||
2919 | int err; | ||
2920 | |||
2921 | if (invert) | ||
2922 | val = max - val; | ||
2923 | val &= mask; | ||
2924 | for (i = 0; i < regcount; i++) { | ||
2925 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
2926 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
2927 | err = snd_soc_component_update_bits(component, regbase+i, | ||
2928 | regmask, regval); | ||
2929 | if (err < 0) | ||
2930 | return err; | ||
2931 | } | ||
2932 | |||
2933 | return 0; | ||
2934 | } | ||
2935 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
2936 | |||
2937 | /** | ||
2938 | * snd_soc_get_strobe - strobe get callback | ||
2939 | * @kcontrol: mixer control | ||
2940 | * @ucontrol: control element information | ||
2941 | * | ||
2942 | * Callback get the value of a strobe mixer control. | ||
2943 | * | ||
2944 | * Returns 0 for success. | ||
2945 | */ | ||
2946 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
2947 | struct snd_ctl_elem_value *ucontrol) | ||
2948 | { | ||
2949 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2950 | struct soc_mixer_control *mc = | ||
2951 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2952 | unsigned int reg = mc->reg; | ||
2953 | unsigned int shift = mc->shift; | ||
2954 | unsigned int mask = 1 << shift; | ||
2955 | unsigned int invert = mc->invert != 0; | ||
2956 | unsigned int val; | ||
2957 | int ret; | ||
2958 | |||
2959 | ret = snd_soc_component_read(component, reg, &val); | ||
2960 | if (ret) | ||
2961 | return ret; | ||
2962 | |||
2963 | val &= mask; | ||
2964 | |||
2965 | if (shift != 0 && val != 0) | ||
2966 | val = val >> shift; | ||
2967 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
2968 | |||
2969 | return 0; | ||
2970 | } | ||
2971 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
2972 | |||
2973 | /** | ||
2974 | * snd_soc_put_strobe - strobe put callback | ||
2975 | * @kcontrol: mixer control | ||
2976 | * @ucontrol: control element information | ||
2977 | * | ||
2978 | * Callback strobe a register bit to high then low (or the inverse) | ||
2979 | * in one pass of a single mixer enum control. | ||
2980 | * | ||
2981 | * Returns 1 for success. | ||
2982 | */ | ||
2983 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
2984 | struct snd_ctl_elem_value *ucontrol) | ||
2985 | { | ||
2986 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2987 | struct soc_mixer_control *mc = | ||
2988 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2989 | unsigned int reg = mc->reg; | ||
2990 | unsigned int shift = mc->shift; | ||
2991 | unsigned int mask = 1 << shift; | ||
2992 | unsigned int invert = mc->invert != 0; | ||
2993 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
2994 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
2995 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
2996 | int err; | ||
2997 | |||
2998 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
2999 | if (err < 0) | ||
3000 | return err; | ||
3001 | |||
3002 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
3003 | } | ||
3004 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
3005 | |||
3006 | /** | ||
3007 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 1958 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
3008 | * @dai: DAI | 1959 | * @dai: DAI |
3009 | * @clk_id: DAI specific clock ID | 1960 | * @clk_id: DAI specific clock ID |
@@ -4281,7 +3232,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4281 | const char *propname) | 3232 | const char *propname) |
4282 | { | 3233 | { |
4283 | struct device_node *np = card->dev->of_node; | 3234 | struct device_node *np = card->dev->of_node; |
4284 | int num_routes; | 3235 | int num_routes, old_routes; |
4285 | struct snd_soc_dapm_route *routes; | 3236 | struct snd_soc_dapm_route *routes; |
4286 | int i, ret; | 3237 | int i, ret; |
4287 | 3238 | ||
@@ -4299,7 +3250,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4299 | return -EINVAL; | 3250 | return -EINVAL; |
4300 | } | 3251 | } |
4301 | 3252 | ||
4302 | routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes), | 3253 | old_routes = card->num_dapm_routes; |
3254 | routes = devm_kzalloc(card->dev, | ||
3255 | (old_routes + num_routes) * sizeof(*routes), | ||
4303 | GFP_KERNEL); | 3256 | GFP_KERNEL); |
4304 | if (!routes) { | 3257 | if (!routes) { |
4305 | dev_err(card->dev, | 3258 | dev_err(card->dev, |
@@ -4307,9 +3260,11 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4307 | return -EINVAL; | 3260 | return -EINVAL; |
4308 | } | 3261 | } |
4309 | 3262 | ||
3263 | memcpy(routes, card->dapm_routes, old_routes * sizeof(*routes)); | ||
3264 | |||
4310 | for (i = 0; i < num_routes; i++) { | 3265 | for (i = 0; i < num_routes; i++) { |
4311 | ret = of_property_read_string_index(np, propname, | 3266 | ret = of_property_read_string_index(np, propname, |
4312 | 2 * i, &routes[i].sink); | 3267 | 2 * i, &routes[old_routes + i].sink); |
4313 | if (ret) { | 3268 | if (ret) { |
4314 | dev_err(card->dev, | 3269 | dev_err(card->dev, |
4315 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3270 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4317,7 +3272,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4317 | return -EINVAL; | 3272 | return -EINVAL; |
4318 | } | 3273 | } |
4319 | ret = of_property_read_string_index(np, propname, | 3274 | ret = of_property_read_string_index(np, propname, |
4320 | (2 * i) + 1, &routes[i].source); | 3275 | (2 * i) + 1, &routes[old_routes + i].source); |
4321 | if (ret) { | 3276 | if (ret) { |
4322 | dev_err(card->dev, | 3277 | dev_err(card->dev, |
4323 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3278 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4326,7 +3281,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4326 | } | 3281 | } |
4327 | } | 3282 | } |
4328 | 3283 | ||
4329 | card->num_dapm_routes = num_routes; | 3284 | card->num_dapm_routes += num_routes; |
4330 | card->dapm_routes = routes; | 3285 | card->dapm_routes = routes; |
4331 | 3286 | ||
4332 | return 0; | 3287 | return 0; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c61cb9cedbcd..c5136bb1f982 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | |||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | /* |
163 | * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input | ||
164 | * paths | ||
165 | * @w: The widget for which to invalidate the cached number of input paths | ||
166 | * | ||
167 | * The function resets the cached number of inputs for the specified widget and | ||
168 | * all widgets that can be reached via outgoing paths from the widget. | ||
169 | * | ||
170 | * This function must be called if the number of input paths for a widget might | ||
171 | * have changed. E.g. if the source state of a widget changes or a path is added | ||
172 | * or activated with the widget as the sink. | ||
173 | */ | ||
174 | static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) | ||
175 | { | ||
176 | struct snd_soc_dapm_widget *sink; | ||
177 | struct snd_soc_dapm_path *p; | ||
178 | LIST_HEAD(list); | ||
179 | |||
180 | dapm_assert_locked(w->dapm); | ||
181 | |||
182 | if (w->inputs == -1) | ||
183 | return; | ||
184 | |||
185 | w->inputs = -1; | ||
186 | list_add_tail(&w->work_list, &list); | ||
187 | |||
188 | list_for_each_entry(w, &list, work_list) { | ||
189 | list_for_each_entry(p, &w->sinks, list_source) { | ||
190 | if (p->is_supply || p->weak || !p->connect) | ||
191 | continue; | ||
192 | sink = p->sink; | ||
193 | if (sink->inputs != -1) { | ||
194 | sink->inputs = -1; | ||
195 | list_add_tail(&sink->work_list, &list); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * dapm_widget_invalidate_output_paths() - Invalidate the cached number of | ||
203 | * output paths | ||
204 | * @w: The widget for which to invalidate the cached number of output paths | ||
205 | * | ||
206 | * Resets the cached number of outputs for the specified widget and all widgets | ||
207 | * that can be reached via incoming paths from the widget. | ||
208 | * | ||
209 | * This function must be called if the number of output paths for a widget might | ||
210 | * have changed. E.g. if the sink state of a widget changes or a path is added | ||
211 | * or activated with the widget as the source. | ||
212 | */ | ||
213 | static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) | ||
214 | { | ||
215 | struct snd_soc_dapm_widget *source; | ||
216 | struct snd_soc_dapm_path *p; | ||
217 | LIST_HEAD(list); | ||
218 | |||
219 | dapm_assert_locked(w->dapm); | ||
220 | |||
221 | if (w->outputs == -1) | ||
222 | return; | ||
223 | |||
224 | w->outputs = -1; | ||
225 | list_add_tail(&w->work_list, &list); | ||
226 | |||
227 | list_for_each_entry(w, &list, work_list) { | ||
228 | list_for_each_entry(p, &w->sources, list_sink) { | ||
229 | if (p->is_supply || p->weak || !p->connect) | ||
230 | continue; | ||
231 | source = p->source; | ||
232 | if (source->outputs != -1) { | ||
233 | source->outputs = -1; | ||
234 | list_add_tail(&source->work_list, &list); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs | ||
242 | * for the widgets connected to a path | ||
243 | * @p: The path to invalidate | ||
244 | * | ||
245 | * Resets the cached number of inputs for the sink of the path and the cached | ||
246 | * number of outputs for the source of the path. | ||
247 | * | ||
248 | * This function must be called when a path is added, removed or the connected | ||
249 | * state changes. | ||
250 | */ | ||
251 | static void dapm_path_invalidate(struct snd_soc_dapm_path *p) | ||
252 | { | ||
253 | /* | ||
254 | * Weak paths or supply paths do not influence the number of input or | ||
255 | * output paths of their neighbors. | ||
256 | */ | ||
257 | if (p->weak || p->is_supply) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * The number of connected endpoints is the sum of the number of | ||
262 | * connected endpoints of all neighbors. If a node with 0 connected | ||
263 | * endpoints is either connected or disconnected that sum won't change, | ||
264 | * so there is no need to re-check the path. | ||
265 | */ | ||
266 | if (p->source->inputs != 0) | ||
267 | dapm_widget_invalidate_input_paths(p->sink); | ||
268 | if (p->sink->outputs != 0) | ||
269 | dapm_widget_invalidate_output_paths(p->source); | ||
270 | } | ||
271 | |||
272 | void dapm_mark_endpoints_dirty(struct snd_soc_card *card) | ||
163 | { | 273 | { |
164 | struct snd_soc_card *card = dapm->card; | ||
165 | struct snd_soc_dapm_widget *w; | 274 | struct snd_soc_dapm_widget *w; |
166 | 275 | ||
167 | mutex_lock(&card->dapm_mutex); | 276 | mutex_lock(&card->dapm_mutex); |
168 | 277 | ||
169 | list_for_each_entry(w, &card->widgets, list) { | 278 | list_for_each_entry(w, &card->widgets, list) { |
170 | switch (w->id) { | 279 | if (w->is_sink || w->is_source) { |
171 | case snd_soc_dapm_input: | 280 | dapm_mark_dirty(w, "Rechecking endpoints"); |
172 | case snd_soc_dapm_output: | 281 | if (w->is_sink) |
173 | dapm_mark_dirty(w, "Rechecking inputs and outputs"); | 282 | dapm_widget_invalidate_output_paths(w); |
174 | break; | 283 | if (w->is_source) |
175 | default: | 284 | dapm_widget_invalidate_input_paths(w); |
176 | break; | ||
177 | } | 285 | } |
178 | } | 286 | } |
179 | 287 | ||
180 | mutex_unlock(&card->dapm_mutex); | 288 | mutex_unlock(&card->dapm_mutex); |
181 | } | 289 | } |
182 | EXPORT_SYMBOL_GPL(dapm_mark_io_dirty); | 290 | EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); |
183 | 291 | ||
184 | /* create a new dapm widget */ | 292 | /* create a new dapm widget */ |
185 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | 293 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card) | |||
386 | list_for_each_entry(w, &card->widgets, list) { | 494 | list_for_each_entry(w, &card->widgets, list) { |
387 | w->new_power = w->power; | 495 | w->new_power = w->power; |
388 | w->power_checked = false; | 496 | w->power_checked = false; |
389 | w->inputs = -1; | ||
390 | w->outputs = -1; | ||
391 | } | 497 | } |
392 | } | 498 | } |
393 | 499 | ||
@@ -469,10 +575,9 @@ out: | |||
469 | 575 | ||
470 | /* connect mux widget to its interconnecting audio paths */ | 576 | /* connect mux widget to its interconnecting audio paths */ |
471 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | 577 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
472 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 578 | struct snd_soc_dapm_path *path, const char *control_name) |
473 | struct snd_soc_dapm_path *path, const char *control_name, | ||
474 | const struct snd_kcontrol_new *kcontrol) | ||
475 | { | 579 | { |
580 | const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0]; | ||
476 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 581 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
477 | unsigned int val, item; | 582 | unsigned int val, item; |
478 | int i; | 583 | int i; |
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
493 | 598 | ||
494 | for (i = 0; i < e->items; i++) { | 599 | for (i = 0; i < e->items; i++) { |
495 | if (!(strcmp(control_name, e->texts[i]))) { | 600 | if (!(strcmp(control_name, e->texts[i]))) { |
496 | list_add(&path->list, &dapm->card->paths); | 601 | path->name = e->texts[i]; |
497 | list_add(&path->list_sink, &dest->sources); | ||
498 | list_add(&path->list_source, &src->sinks); | ||
499 | path->name = (char*)e->texts[i]; | ||
500 | if (i == item) | 602 | if (i == item) |
501 | path->connect = 1; | 603 | path->connect = 1; |
502 | else | 604 | else |
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
509 | } | 611 | } |
510 | 612 | ||
511 | /* set up initial codec paths */ | 613 | /* set up initial codec paths */ |
512 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | 614 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) |
513 | struct snd_soc_dapm_path *p, int i) | ||
514 | { | 615 | { |
515 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 616 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
516 | w->kcontrol_news[i].private_value; | 617 | p->sink->kcontrol_news[i].private_value; |
517 | unsigned int reg = mc->reg; | 618 | unsigned int reg = mc->reg; |
518 | unsigned int shift = mc->shift; | 619 | unsigned int shift = mc->shift; |
519 | unsigned int max = mc->max; | 620 | unsigned int max = mc->max; |
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
522 | unsigned int val; | 623 | unsigned int val; |
523 | 624 | ||
524 | if (reg != SND_SOC_NOPM) { | 625 | if (reg != SND_SOC_NOPM) { |
525 | soc_dapm_read(w->dapm, reg, &val); | 626 | soc_dapm_read(p->sink->dapm, reg, &val); |
526 | val = (val >> shift) & mask; | 627 | val = (val >> shift) & mask; |
527 | if (invert) | 628 | if (invert) |
528 | val = max - val; | 629 | val = max - val; |
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
534 | 635 | ||
535 | /* connect mixer widget to its interconnecting audio paths */ | 636 | /* connect mixer widget to its interconnecting audio paths */ |
536 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 637 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
537 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
538 | struct snd_soc_dapm_path *path, const char *control_name) | 638 | struct snd_soc_dapm_path *path, const char *control_name) |
539 | { | 639 | { |
540 | int i; | 640 | int i; |
541 | 641 | ||
542 | /* search for mixer kcontrol */ | 642 | /* search for mixer kcontrol */ |
543 | for (i = 0; i < dest->num_kcontrols; i++) { | 643 | for (i = 0; i < path->sink->num_kcontrols; i++) { |
544 | if (!strcmp(control_name, dest->kcontrol_news[i].name)) { | 644 | if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { |
545 | list_add(&path->list, &dapm->card->paths); | 645 | path->name = path->sink->kcontrol_news[i].name; |
546 | list_add(&path->list_sink, &dest->sources); | 646 | dapm_set_mixer_path_status(path, i); |
547 | list_add(&path->list_source, &src->sinks); | ||
548 | path->name = dest->kcontrol_news[i].name; | ||
549 | dapm_set_mixer_path_status(dest, path, i); | ||
550 | return 0; | 647 | return 0; |
551 | } | 648 | } |
552 | } | 649 | } |
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
738 | if (ret < 0) | 835 | if (ret < 0) |
739 | return ret; | 836 | return ret; |
740 | 837 | ||
741 | list_for_each_entry(path, &w->sources, list_sink) | 838 | list_for_each_entry(path, &w->sources, list_sink) { |
742 | dapm_kcontrol_add_path(w->kcontrols[0], path); | 839 | if (path->name) |
840 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
841 | } | ||
743 | 842 | ||
744 | return 0; | 843 | return 0; |
745 | } | 844 | } |
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) | |||
754 | return 0; | 853 | return 0; |
755 | } | 854 | } |
756 | 855 | ||
757 | /* reset 'walked' bit for each dapm path */ | ||
758 | static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm, | ||
759 | struct list_head *sink) | ||
760 | { | ||
761 | struct snd_soc_dapm_path *p; | ||
762 | |||
763 | list_for_each_entry(p, sink, list_source) { | ||
764 | if (p->walked) { | ||
765 | p->walked = 0; | ||
766 | dapm_clear_walk_output(dapm, &p->sink->sinks); | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | |||
771 | static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm, | ||
772 | struct list_head *source) | ||
773 | { | ||
774 | struct snd_soc_dapm_path *p; | ||
775 | |||
776 | list_for_each_entry(p, source, list_sink) { | ||
777 | if (p->walked) { | ||
778 | p->walked = 0; | ||
779 | dapm_clear_walk_input(dapm, &p->source->sources); | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | |||
784 | |||
785 | /* We implement power down on suspend by checking the power state of | 856 | /* We implement power down on suspend by checking the power state of |
786 | * the ALSA card - when we are suspending the ALSA state for the card | 857 | * the ALSA card - when we are suspending the ALSA state for the card |
787 | * is set to D3. | 858 | * is set to D3. |
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
856 | 927 | ||
857 | DAPM_UPDATE_STAT(widget, path_checks); | 928 | DAPM_UPDATE_STAT(widget, path_checks); |
858 | 929 | ||
859 | switch (widget->id) { | 930 | if (widget->is_sink && widget->connected) { |
860 | case snd_soc_dapm_supply: | 931 | widget->outputs = snd_soc_dapm_suspend_check(widget); |
861 | case snd_soc_dapm_regulator_supply: | 932 | return widget->outputs; |
862 | case snd_soc_dapm_clock_supply: | ||
863 | case snd_soc_dapm_kcontrol: | ||
864 | return 0; | ||
865 | default: | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | switch (widget->id) { | ||
870 | case snd_soc_dapm_adc: | ||
871 | case snd_soc_dapm_aif_out: | ||
872 | case snd_soc_dapm_dai_out: | ||
873 | if (widget->active) { | ||
874 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
875 | return widget->outputs; | ||
876 | } | ||
877 | default: | ||
878 | break; | ||
879 | } | ||
880 | |||
881 | if (widget->connected) { | ||
882 | /* connected pin ? */ | ||
883 | if (widget->id == snd_soc_dapm_output && !widget->ext) { | ||
884 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
885 | return widget->outputs; | ||
886 | } | ||
887 | |||
888 | /* connected jack or spk ? */ | ||
889 | if (widget->id == snd_soc_dapm_hp || | ||
890 | widget->id == snd_soc_dapm_spk || | ||
891 | (widget->id == snd_soc_dapm_line && | ||
892 | !list_empty(&widget->sources))) { | ||
893 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
894 | return widget->outputs; | ||
895 | } | ||
896 | } | 933 | } |
897 | 934 | ||
898 | list_for_each_entry(path, &widget->sinks, list_source) { | 935 | list_for_each_entry(path, &widget->sinks, list_source) { |
899 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 936 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
900 | 937 | ||
901 | if (path->weak) | 938 | if (path->weak || path->is_supply) |
902 | continue; | 939 | continue; |
903 | 940 | ||
904 | if (path->walking) | 941 | if (path->walking) |
905 | return 1; | 942 | return 1; |
906 | 943 | ||
907 | if (path->walked) | ||
908 | continue; | ||
909 | |||
910 | trace_snd_soc_dapm_output_path(widget, path); | 944 | trace_snd_soc_dapm_output_path(widget, path); |
911 | 945 | ||
912 | if (path->sink && path->connect) { | 946 | if (path->connect) { |
913 | path->walked = 1; | ||
914 | path->walking = 1; | 947 | path->walking = 1; |
915 | 948 | ||
916 | /* do we need to add this widget to the list ? */ | 949 | /* do we need to add this widget to the list ? */ |
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
952 | 985 | ||
953 | DAPM_UPDATE_STAT(widget, path_checks); | 986 | DAPM_UPDATE_STAT(widget, path_checks); |
954 | 987 | ||
955 | switch (widget->id) { | 988 | if (widget->is_source && widget->connected) { |
956 | case snd_soc_dapm_supply: | 989 | widget->inputs = snd_soc_dapm_suspend_check(widget); |
957 | case snd_soc_dapm_regulator_supply: | 990 | return widget->inputs; |
958 | case snd_soc_dapm_clock_supply: | ||
959 | case snd_soc_dapm_kcontrol: | ||
960 | return 0; | ||
961 | default: | ||
962 | break; | ||
963 | } | ||
964 | |||
965 | /* active stream ? */ | ||
966 | switch (widget->id) { | ||
967 | case snd_soc_dapm_dac: | ||
968 | case snd_soc_dapm_aif_in: | ||
969 | case snd_soc_dapm_dai_in: | ||
970 | if (widget->active) { | ||
971 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
972 | return widget->inputs; | ||
973 | } | ||
974 | default: | ||
975 | break; | ||
976 | } | ||
977 | |||
978 | if (widget->connected) { | ||
979 | /* connected pin ? */ | ||
980 | if (widget->id == snd_soc_dapm_input && !widget->ext) { | ||
981 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
982 | return widget->inputs; | ||
983 | } | ||
984 | |||
985 | /* connected VMID/Bias for lower pops */ | ||
986 | if (widget->id == snd_soc_dapm_vmid) { | ||
987 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
988 | return widget->inputs; | ||
989 | } | ||
990 | |||
991 | /* connected jack ? */ | ||
992 | if (widget->id == snd_soc_dapm_mic || | ||
993 | (widget->id == snd_soc_dapm_line && | ||
994 | !list_empty(&widget->sinks))) { | ||
995 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
996 | return widget->inputs; | ||
997 | } | ||
998 | |||
999 | /* signal generator */ | ||
1000 | if (widget->id == snd_soc_dapm_siggen) { | ||
1001 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
1002 | return widget->inputs; | ||
1003 | } | ||
1004 | } | 991 | } |
1005 | 992 | ||
1006 | list_for_each_entry(path, &widget->sources, list_sink) { | 993 | list_for_each_entry(path, &widget->sources, list_sink) { |
1007 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 994 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
1008 | 995 | ||
1009 | if (path->weak) | 996 | if (path->weak || path->is_supply) |
1010 | continue; | 997 | continue; |
1011 | 998 | ||
1012 | if (path->walking) | 999 | if (path->walking) |
1013 | return 1; | 1000 | return 1; |
1014 | 1001 | ||
1015 | if (path->walked) | ||
1016 | continue; | ||
1017 | |||
1018 | trace_snd_soc_dapm_input_path(widget, path); | 1002 | trace_snd_soc_dapm_input_path(widget, path); |
1019 | 1003 | ||
1020 | if (path->source && path->connect) { | 1004 | if (path->connect) { |
1021 | path->walked = 1; | ||
1022 | path->walking = 1; | 1005 | path->walking = 1; |
1023 | 1006 | ||
1024 | /* do we need to add this widget to the list ? */ | 1007 | /* do we need to add this widget to the list ? */ |
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
1060 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 1043 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
1061 | struct snd_soc_dapm_widget_list **list) | 1044 | struct snd_soc_dapm_widget_list **list) |
1062 | { | 1045 | { |
1063 | struct snd_soc_card *card = dai->card; | 1046 | struct snd_soc_card *card = dai->component->card; |
1047 | struct snd_soc_dapm_widget *w; | ||
1064 | int paths; | 1048 | int paths; |
1065 | 1049 | ||
1066 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 1050 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1067 | dapm_reset(card); | ||
1068 | 1051 | ||
1069 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1052 | /* |
1053 | * For is_connected_{output,input}_ep fully discover the graph we need | ||
1054 | * to reset the cached number of inputs and outputs. | ||
1055 | */ | ||
1056 | list_for_each_entry(w, &card->widgets, list) { | ||
1057 | w->inputs = -1; | ||
1058 | w->outputs = -1; | ||
1059 | } | ||
1060 | |||
1061 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1070 | paths = is_connected_output_ep(dai->playback_widget, list); | 1062 | paths = is_connected_output_ep(dai->playback_widget, list); |
1071 | dapm_clear_walk_output(&card->dapm, | 1063 | else |
1072 | &dai->playback_widget->sinks); | ||
1073 | } else { | ||
1074 | paths = is_connected_input_ep(dai->capture_widget, list); | 1064 | paths = is_connected_input_ep(dai->capture_widget, list); |
1075 | dapm_clear_walk_input(&card->dapm, | ||
1076 | &dai->capture_widget->sources); | ||
1077 | } | ||
1078 | 1065 | ||
1079 | trace_snd_soc_dapm_connected(paths, stream); | 1066 | trace_snd_soc_dapm_connected(paths, stream); |
1080 | mutex_unlock(&card->dapm_mutex); | 1067 | mutex_unlock(&card->dapm_mutex); |
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
1163 | DAPM_UPDATE_STAT(w, power_checks); | 1150 | DAPM_UPDATE_STAT(w, power_checks); |
1164 | 1151 | ||
1165 | in = is_connected_input_ep(w, NULL); | 1152 | in = is_connected_input_ep(w, NULL); |
1166 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1167 | out = is_connected_output_ep(w, NULL); | 1153 | out = is_connected_output_ep(w, NULL); |
1168 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1169 | return out != 0 && in != 0; | 1154 | return out != 0 && in != 0; |
1170 | } | 1155 | } |
1171 | 1156 | ||
1172 | /* Check to see if an ADC has power */ | ||
1173 | static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | ||
1174 | { | ||
1175 | int in; | ||
1176 | |||
1177 | DAPM_UPDATE_STAT(w, power_checks); | ||
1178 | |||
1179 | if (w->active) { | ||
1180 | in = is_connected_input_ep(w, NULL); | ||
1181 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1182 | return in != 0; | ||
1183 | } else { | ||
1184 | return dapm_generic_check_power(w); | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | /* Check to see if a DAC has power */ | ||
1189 | static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) | ||
1190 | { | ||
1191 | int out; | ||
1192 | |||
1193 | DAPM_UPDATE_STAT(w, power_checks); | ||
1194 | |||
1195 | if (w->active) { | ||
1196 | out = is_connected_output_ep(w, NULL); | ||
1197 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1198 | return out != 0; | ||
1199 | } else { | ||
1200 | return dapm_generic_check_power(w); | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | /* Check to see if a power supply is needed */ | 1157 | /* Check to see if a power supply is needed */ |
1205 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | 1158 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) |
1206 | { | 1159 | { |
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
1219 | !path->connected(path->source, path->sink)) | 1172 | !path->connected(path->source, path->sink)) |
1220 | continue; | 1173 | continue; |
1221 | 1174 | ||
1222 | if (!path->sink) | ||
1223 | continue; | ||
1224 | |||
1225 | if (dapm_widget_power_check(path->sink)) | 1175 | if (dapm_widget_power_check(path->sink)) |
1226 | return 1; | 1176 | return 1; |
1227 | } | 1177 | } |
@@ -1636,27 +1586,14 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1636 | /* If we changed our power state perhaps our neigbours changed | 1586 | /* If we changed our power state perhaps our neigbours changed |
1637 | * also. | 1587 | * also. |
1638 | */ | 1588 | */ |
1639 | list_for_each_entry(path, &w->sources, list_sink) { | 1589 | list_for_each_entry(path, &w->sources, list_sink) |
1640 | if (path->source) { | 1590 | dapm_widget_set_peer_power(path->source, power, path->connect); |
1641 | dapm_widget_set_peer_power(path->source, power, | 1591 | |
1592 | /* Supplies can't affect their outputs, only their inputs */ | ||
1593 | if (!w->is_supply) { | ||
1594 | list_for_each_entry(path, &w->sinks, list_source) | ||
1595 | dapm_widget_set_peer_power(path->sink, power, | ||
1642 | path->connect); | 1596 | path->connect); |
1643 | } | ||
1644 | } | ||
1645 | switch (w->id) { | ||
1646 | case snd_soc_dapm_supply: | ||
1647 | case snd_soc_dapm_regulator_supply: | ||
1648 | case snd_soc_dapm_clock_supply: | ||
1649 | case snd_soc_dapm_kcontrol: | ||
1650 | /* Supplies can't affect their outputs, only their inputs */ | ||
1651 | break; | ||
1652 | default: | ||
1653 | list_for_each_entry(path, &w->sinks, list_source) { | ||
1654 | if (path->sink) { | ||
1655 | dapm_widget_set_peer_power(path->sink, power, | ||
1656 | path->connect); | ||
1657 | } | ||
1658 | } | ||
1659 | break; | ||
1660 | } | 1597 | } |
1661 | 1598 | ||
1662 | if (power) | 1599 | if (power) |
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1863 | if (!buf) | 1800 | if (!buf) |
1864 | return -ENOMEM; | 1801 | return -ENOMEM; |
1865 | 1802 | ||
1866 | in = is_connected_input_ep(w, NULL); | 1803 | /* Supply widgets are not handled by is_connected_{input,output}_ep() */ |
1867 | dapm_clear_walk_input(w->dapm, &w->sources); | 1804 | if (w->is_supply) { |
1868 | out = is_connected_output_ep(w, NULL); | 1805 | in = 0; |
1869 | dapm_clear_walk_output(w->dapm, &w->sinks); | 1806 | out = 0; |
1807 | } else { | ||
1808 | in = is_connected_input_ep(w, NULL); | ||
1809 | out = is_connected_output_ep(w, NULL); | ||
1810 | } | ||
1870 | 1811 | ||
1871 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", | 1812 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
1872 | w->name, w->power ? "On" : "Off", | 1813 | w->name, w->power ? "On" : "Off", |
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
2011 | 1952 | ||
2012 | #endif | 1953 | #endif |
2013 | 1954 | ||
1955 | /* | ||
1956 | * soc_dapm_connect_path() - Connects or disconnects a path | ||
1957 | * @path: The path to update | ||
1958 | * @connect: The new connect state of the path. True if the path is connected, | ||
1959 | * false if it is disconneted. | ||
1960 | * @reason: The reason why the path changed (for debugging only) | ||
1961 | */ | ||
1962 | static void soc_dapm_connect_path(struct snd_soc_dapm_path *path, | ||
1963 | bool connect, const char *reason) | ||
1964 | { | ||
1965 | if (path->connect == connect) | ||
1966 | return; | ||
1967 | |||
1968 | path->connect = connect; | ||
1969 | dapm_mark_dirty(path->source, reason); | ||
1970 | dapm_mark_dirty(path->sink, reason); | ||
1971 | dapm_path_invalidate(path); | ||
1972 | } | ||
1973 | |||
2014 | /* test and update the power status of a mux widget */ | 1974 | /* test and update the power status of a mux widget */ |
2015 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, | 1975 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
2016 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 1976 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
2017 | { | 1977 | { |
2018 | struct snd_soc_dapm_path *path; | 1978 | struct snd_soc_dapm_path *path; |
2019 | int found = 0; | 1979 | int found = 0; |
1980 | bool connect; | ||
2020 | 1981 | ||
2021 | lockdep_assert_held(&card->dapm_mutex); | 1982 | lockdep_assert_held(&card->dapm_mutex); |
2022 | 1983 | ||
2023 | /* find dapm widget path assoc with kcontrol */ | 1984 | /* find dapm widget path assoc with kcontrol */ |
2024 | dapm_kcontrol_for_each_path(path, kcontrol) { | 1985 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2025 | if (!path->name || !e->texts[mux]) | ||
2026 | continue; | ||
2027 | |||
2028 | found = 1; | 1986 | found = 1; |
2029 | /* we now need to match the string in the enum to the path */ | 1987 | /* we now need to match the string in the enum to the path */ |
2030 | if (!(strcmp(path->name, e->texts[mux]))) { | 1988 | if (!(strcmp(path->name, e->texts[mux]))) |
2031 | path->connect = 1; /* new connection */ | 1989 | connect = true; |
2032 | dapm_mark_dirty(path->source, "mux connection"); | 1990 | else |
2033 | } else { | 1991 | connect = false; |
2034 | if (path->connect) | 1992 | |
2035 | dapm_mark_dirty(path->source, | 1993 | soc_dapm_connect_path(path, connect, "mux update"); |
2036 | "mux disconnection"); | ||
2037 | path->connect = 0; /* old connection must be powered down */ | ||
2038 | } | ||
2039 | dapm_mark_dirty(path->sink, "mux change"); | ||
2040 | } | 1994 | } |
2041 | 1995 | ||
2042 | if (found) | 1996 | if (found) |
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
2075 | /* find dapm widget path assoc with kcontrol */ | 2029 | /* find dapm widget path assoc with kcontrol */ |
2076 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2030 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2077 | found = 1; | 2031 | found = 1; |
2078 | path->connect = connect; | 2032 | soc_dapm_connect_path(path, connect, "mixer update"); |
2079 | dapm_mark_dirty(path->source, "mixer connection"); | ||
2080 | dapm_mark_dirty(path->sink, "mixer update"); | ||
2081 | } | 2033 | } |
2082 | 2034 | ||
2083 | if (found) | 2035 | if (found) |
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2255 | return -EINVAL; | 2207 | return -EINVAL; |
2256 | } | 2208 | } |
2257 | 2209 | ||
2258 | if (w->connected != status) | 2210 | if (w->connected != status) { |
2259 | dapm_mark_dirty(w, "pin configuration"); | 2211 | dapm_mark_dirty(w, "pin configuration"); |
2212 | dapm_widget_invalidate_input_paths(w); | ||
2213 | dapm_widget_invalidate_output_paths(w); | ||
2214 | } | ||
2260 | 2215 | ||
2261 | w->connected = status; | 2216 | w->connected = status; |
2262 | if (status == 0) | 2217 | if (status == 0) |
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2309 | } | 2264 | } |
2310 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2265 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2311 | 2266 | ||
2267 | /* | ||
2268 | * dapm_update_widget_flags() - Re-compute widget sink and source flags | ||
2269 | * @w: The widget for which to update the flags | ||
2270 | * | ||
2271 | * Some widgets have a dynamic category which depends on which neighbors they | ||
2272 | * are connected to. This function update the category for these widgets. | ||
2273 | * | ||
2274 | * This function must be called whenever a path is added or removed to a widget. | ||
2275 | */ | ||
2276 | static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) | ||
2277 | { | ||
2278 | struct snd_soc_dapm_path *p; | ||
2279 | |||
2280 | switch (w->id) { | ||
2281 | case snd_soc_dapm_input: | ||
2282 | w->is_source = 1; | ||
2283 | list_for_each_entry(p, &w->sources, list_sink) { | ||
2284 | if (p->source->id == snd_soc_dapm_micbias || | ||
2285 | p->source->id == snd_soc_dapm_mic || | ||
2286 | p->source->id == snd_soc_dapm_line || | ||
2287 | p->source->id == snd_soc_dapm_output) { | ||
2288 | w->is_source = 0; | ||
2289 | break; | ||
2290 | } | ||
2291 | } | ||
2292 | break; | ||
2293 | case snd_soc_dapm_output: | ||
2294 | w->is_sink = 1; | ||
2295 | list_for_each_entry(p, &w->sinks, list_source) { | ||
2296 | if (p->sink->id == snd_soc_dapm_spk || | ||
2297 | p->sink->id == snd_soc_dapm_hp || | ||
2298 | p->sink->id == snd_soc_dapm_line || | ||
2299 | p->sink->id == snd_soc_dapm_input) { | ||
2300 | w->is_sink = 0; | ||
2301 | break; | ||
2302 | } | ||
2303 | } | ||
2304 | break; | ||
2305 | case snd_soc_dapm_line: | ||
2306 | w->is_sink = !list_empty(&w->sources); | ||
2307 | w->is_source = !list_empty(&w->sinks); | ||
2308 | break; | ||
2309 | default: | ||
2310 | break; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2312 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | 2314 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2313 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | 2315 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2314 | const char *control, | 2316 | const char *control, |
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2318 | struct snd_soc_dapm_path *path; | 2320 | struct snd_soc_dapm_path *path; |
2319 | int ret; | 2321 | int ret; |
2320 | 2322 | ||
2323 | if (wsink->is_supply && !wsource->is_supply) { | ||
2324 | dev_err(dapm->dev, | ||
2325 | "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n", | ||
2326 | wsource->name, wsink->name); | ||
2327 | return -EINVAL; | ||
2328 | } | ||
2329 | |||
2330 | if (connected && !wsource->is_supply) { | ||
2331 | dev_err(dapm->dev, | ||
2332 | "connected() callback only supported for supply widgets (%s -> %s)\n", | ||
2333 | wsource->name, wsink->name); | ||
2334 | return -EINVAL; | ||
2335 | } | ||
2336 | |||
2337 | if (wsource->is_supply && control) { | ||
2338 | dev_err(dapm->dev, | ||
2339 | "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n", | ||
2340 | wsource->name, control, wsink->name); | ||
2341 | return -EINVAL; | ||
2342 | } | ||
2343 | |||
2321 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2344 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2322 | if (!path) | 2345 | if (!path) |
2323 | return -ENOMEM; | 2346 | return -ENOMEM; |
@@ -2330,85 +2353,49 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2330 | INIT_LIST_HEAD(&path->list_source); | 2353 | INIT_LIST_HEAD(&path->list_source); |
2331 | INIT_LIST_HEAD(&path->list_sink); | 2354 | INIT_LIST_HEAD(&path->list_sink); |
2332 | 2355 | ||
2333 | /* check for external widgets */ | 2356 | if (wsource->is_supply || wsink->is_supply) |
2334 | if (wsink->id == snd_soc_dapm_input) { | 2357 | path->is_supply = 1; |
2335 | if (wsource->id == snd_soc_dapm_micbias || | ||
2336 | wsource->id == snd_soc_dapm_mic || | ||
2337 | wsource->id == snd_soc_dapm_line || | ||
2338 | wsource->id == snd_soc_dapm_output) | ||
2339 | wsink->ext = 1; | ||
2340 | } | ||
2341 | if (wsource->id == snd_soc_dapm_output) { | ||
2342 | if (wsink->id == snd_soc_dapm_spk || | ||
2343 | wsink->id == snd_soc_dapm_hp || | ||
2344 | wsink->id == snd_soc_dapm_line || | ||
2345 | wsink->id == snd_soc_dapm_input) | ||
2346 | wsource->ext = 1; | ||
2347 | } | ||
2348 | |||
2349 | dapm_mark_dirty(wsource, "Route added"); | ||
2350 | dapm_mark_dirty(wsink, "Route added"); | ||
2351 | 2358 | ||
2352 | /* connect static paths */ | 2359 | /* connect static paths */ |
2353 | if (control == NULL) { | 2360 | if (control == NULL) { |
2354 | list_add(&path->list, &dapm->card->paths); | ||
2355 | list_add(&path->list_sink, &wsink->sources); | ||
2356 | list_add(&path->list_source, &wsource->sinks); | ||
2357 | path->connect = 1; | 2361 | path->connect = 1; |
2358 | return 0; | 2362 | } else { |
2359 | } | 2363 | /* connect dynamic paths */ |
2360 | 2364 | switch (wsink->id) { | |
2361 | /* connect dynamic paths */ | 2365 | case snd_soc_dapm_mux: |
2362 | switch (wsink->id) { | 2366 | ret = dapm_connect_mux(dapm, path, control); |
2363 | case snd_soc_dapm_adc: | 2367 | if (ret != 0) |
2364 | case snd_soc_dapm_dac: | 2368 | goto err; |
2365 | case snd_soc_dapm_pga: | 2369 | break; |
2366 | case snd_soc_dapm_out_drv: | 2370 | case snd_soc_dapm_switch: |
2367 | case snd_soc_dapm_input: | 2371 | case snd_soc_dapm_mixer: |
2368 | case snd_soc_dapm_output: | 2372 | case snd_soc_dapm_mixer_named_ctl: |
2369 | case snd_soc_dapm_siggen: | 2373 | ret = dapm_connect_mixer(dapm, path, control); |
2370 | case snd_soc_dapm_micbias: | 2374 | if (ret != 0) |
2371 | case snd_soc_dapm_vmid: | 2375 | goto err; |
2372 | case snd_soc_dapm_pre: | 2376 | break; |
2373 | case snd_soc_dapm_post: | 2377 | default: |
2374 | case snd_soc_dapm_supply: | 2378 | dev_err(dapm->dev, |
2375 | case snd_soc_dapm_regulator_supply: | 2379 | "Control not supported for path %s -> [%s] -> %s\n", |
2376 | case snd_soc_dapm_clock_supply: | 2380 | wsource->name, control, wsink->name); |
2377 | case snd_soc_dapm_aif_in: | 2381 | ret = -EINVAL; |
2378 | case snd_soc_dapm_aif_out: | ||
2379 | case snd_soc_dapm_dai_in: | ||
2380 | case snd_soc_dapm_dai_out: | ||
2381 | case snd_soc_dapm_dai_link: | ||
2382 | case snd_soc_dapm_kcontrol: | ||
2383 | list_add(&path->list, &dapm->card->paths); | ||
2384 | list_add(&path->list_sink, &wsink->sources); | ||
2385 | list_add(&path->list_source, &wsource->sinks); | ||
2386 | path->connect = 1; | ||
2387 | return 0; | ||
2388 | case snd_soc_dapm_mux: | ||
2389 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | ||
2390 | &wsink->kcontrol_news[0]); | ||
2391 | if (ret != 0) | ||
2392 | goto err; | ||
2393 | break; | ||
2394 | case snd_soc_dapm_switch: | ||
2395 | case snd_soc_dapm_mixer: | ||
2396 | case snd_soc_dapm_mixer_named_ctl: | ||
2397 | ret = dapm_connect_mixer(dapm, wsource, wsink, path, control); | ||
2398 | if (ret != 0) | ||
2399 | goto err; | 2382 | goto err; |
2400 | break; | 2383 | } |
2401 | case snd_soc_dapm_hp: | ||
2402 | case snd_soc_dapm_mic: | ||
2403 | case snd_soc_dapm_line: | ||
2404 | case snd_soc_dapm_spk: | ||
2405 | list_add(&path->list, &dapm->card->paths); | ||
2406 | list_add(&path->list_sink, &wsink->sources); | ||
2407 | list_add(&path->list_source, &wsource->sinks); | ||
2408 | path->connect = 0; | ||
2409 | return 0; | ||
2410 | } | 2384 | } |
2411 | 2385 | ||
2386 | list_add(&path->list, &dapm->card->paths); | ||
2387 | list_add(&path->list_sink, &wsink->sources); | ||
2388 | list_add(&path->list_source, &wsource->sinks); | ||
2389 | |||
2390 | dapm_update_widget_flags(wsource); | ||
2391 | dapm_update_widget_flags(wsink); | ||
2392 | |||
2393 | dapm_mark_dirty(wsource, "Route added"); | ||
2394 | dapm_mark_dirty(wsink, "Route added"); | ||
2395 | |||
2396 | if (dapm->card->instantiated && path->connect) | ||
2397 | dapm_path_invalidate(path); | ||
2398 | |||
2412 | return 0; | 2399 | return 0; |
2413 | err: | 2400 | err: |
2414 | kfree(path); | 2401 | kfree(path); |
@@ -2489,6 +2476,7 @@ err: | |||
2489 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | 2476 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, |
2490 | const struct snd_soc_dapm_route *route) | 2477 | const struct snd_soc_dapm_route *route) |
2491 | { | 2478 | { |
2479 | struct snd_soc_dapm_widget *wsource, *wsink; | ||
2492 | struct snd_soc_dapm_path *path, *p; | 2480 | struct snd_soc_dapm_path *path, *p; |
2493 | const char *sink; | 2481 | const char *sink; |
2494 | const char *source; | 2482 | const char *source; |
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2526 | } | 2514 | } |
2527 | 2515 | ||
2528 | if (path) { | 2516 | if (path) { |
2529 | dapm_mark_dirty(path->source, "Route removed"); | 2517 | wsource = path->source; |
2530 | dapm_mark_dirty(path->sink, "Route removed"); | 2518 | wsink = path->sink; |
2519 | |||
2520 | dapm_mark_dirty(wsource, "Route removed"); | ||
2521 | dapm_mark_dirty(wsink, "Route removed"); | ||
2522 | if (path->connect) | ||
2523 | dapm_path_invalidate(path); | ||
2531 | 2524 | ||
2532 | dapm_free_path(path); | 2525 | dapm_free_path(path); |
2526 | |||
2527 | /* Update any path related flags */ | ||
2528 | dapm_update_widget_flags(wsource); | ||
2529 | dapm_update_widget_flags(wsink); | ||
2533 | } else { | 2530 | } else { |
2534 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", | 2531 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", |
2535 | source, sink); | 2532 | source, sink); |
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3087 | } | 3084 | } |
3088 | 3085 | ||
3089 | switch (w->id) { | 3086 | switch (w->id) { |
3090 | case snd_soc_dapm_switch: | 3087 | case snd_soc_dapm_mic: |
3091 | case snd_soc_dapm_mixer: | 3088 | case snd_soc_dapm_input: |
3092 | case snd_soc_dapm_mixer_named_ctl: | 3089 | w->is_source = 1; |
3093 | w->power_check = dapm_generic_check_power; | 3090 | w->power_check = dapm_generic_check_power; |
3094 | break; | 3091 | break; |
3095 | case snd_soc_dapm_mux: | 3092 | case snd_soc_dapm_spk: |
3093 | case snd_soc_dapm_hp: | ||
3094 | case snd_soc_dapm_output: | ||
3095 | w->is_sink = 1; | ||
3096 | w->power_check = dapm_generic_check_power; | 3096 | w->power_check = dapm_generic_check_power; |
3097 | break; | 3097 | break; |
3098 | case snd_soc_dapm_dai_out: | 3098 | case snd_soc_dapm_vmid: |
3099 | w->power_check = dapm_adc_check_power; | 3099 | case snd_soc_dapm_siggen: |
3100 | break; | 3100 | w->is_source = 1; |
3101 | case snd_soc_dapm_dai_in: | 3101 | w->power_check = dapm_always_on_check_power; |
3102 | w->power_check = dapm_dac_check_power; | ||
3103 | break; | 3102 | break; |
3103 | case snd_soc_dapm_mux: | ||
3104 | case snd_soc_dapm_switch: | ||
3105 | case snd_soc_dapm_mixer: | ||
3106 | case snd_soc_dapm_mixer_named_ctl: | ||
3104 | case snd_soc_dapm_adc: | 3107 | case snd_soc_dapm_adc: |
3105 | case snd_soc_dapm_aif_out: | 3108 | case snd_soc_dapm_aif_out: |
3106 | case snd_soc_dapm_dac: | 3109 | case snd_soc_dapm_dac: |
3107 | case snd_soc_dapm_aif_in: | 3110 | case snd_soc_dapm_aif_in: |
3108 | case snd_soc_dapm_pga: | 3111 | case snd_soc_dapm_pga: |
3109 | case snd_soc_dapm_out_drv: | 3112 | case snd_soc_dapm_out_drv: |
3110 | case snd_soc_dapm_input: | ||
3111 | case snd_soc_dapm_output: | ||
3112 | case snd_soc_dapm_micbias: | 3113 | case snd_soc_dapm_micbias: |
3113 | case snd_soc_dapm_spk: | ||
3114 | case snd_soc_dapm_hp: | ||
3115 | case snd_soc_dapm_mic: | ||
3116 | case snd_soc_dapm_line: | 3114 | case snd_soc_dapm_line: |
3117 | case snd_soc_dapm_dai_link: | 3115 | case snd_soc_dapm_dai_link: |
3116 | case snd_soc_dapm_dai_out: | ||
3117 | case snd_soc_dapm_dai_in: | ||
3118 | w->power_check = dapm_generic_check_power; | 3118 | w->power_check = dapm_generic_check_power; |
3119 | break; | 3119 | break; |
3120 | case snd_soc_dapm_supply: | 3120 | case snd_soc_dapm_supply: |
3121 | case snd_soc_dapm_regulator_supply: | 3121 | case snd_soc_dapm_regulator_supply: |
3122 | case snd_soc_dapm_clock_supply: | 3122 | case snd_soc_dapm_clock_supply: |
3123 | case snd_soc_dapm_kcontrol: | 3123 | case snd_soc_dapm_kcontrol: |
3124 | w->is_supply = 1; | ||
3124 | w->power_check = dapm_supply_check_power; | 3125 | w->power_check = dapm_supply_check_power; |
3125 | break; | 3126 | break; |
3126 | default: | 3127 | default: |
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3137 | INIT_LIST_HEAD(&w->dirty); | 3138 | INIT_LIST_HEAD(&w->dirty); |
3138 | list_add(&w->list, &dapm->card->widgets); | 3139 | list_add(&w->list, &dapm->card->widgets); |
3139 | 3140 | ||
3141 | w->inputs = -1; | ||
3142 | w->outputs = -1; | ||
3143 | |||
3140 | /* machine layer set ups unconnected pins and insertions */ | 3144 | /* machine layer set ups unconnected pins and insertions */ |
3141 | w->connected = 1; | 3145 | w->connected = 1; |
3142 | return w; | 3146 | return w; |
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, | |||
3484 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 3488 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: |
3485 | break; | 3489 | break; |
3486 | } | 3490 | } |
3491 | |||
3492 | if (w->id == snd_soc_dapm_dai_in) { | ||
3493 | w->is_source = w->active; | ||
3494 | dapm_widget_invalidate_input_paths(w); | ||
3495 | } else { | ||
3496 | w->is_sink = w->active; | ||
3497 | dapm_widget_invalidate_output_paths(w); | ||
3498 | } | ||
3487 | } | 3499 | } |
3488 | } | 3500 | } |
3489 | 3501 | ||
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | |||
3610 | } | 3622 | } |
3611 | 3623 | ||
3612 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); | 3624 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); |
3613 | w->connected = 1; | 3625 | if (!w->connected) { |
3626 | /* | ||
3627 | * w->force does not affect the number of input or output paths, | ||
3628 | * so we only have to recheck if w->connected is changed | ||
3629 | */ | ||
3630 | dapm_widget_invalidate_input_paths(w); | ||
3631 | dapm_widget_invalidate_output_paths(w); | ||
3632 | w->connected = 1; | ||
3633 | } | ||
3614 | w->force = 1; | 3634 | w->force = 1; |
3615 | dapm_mark_dirty(w, "force enable"); | 3635 | dapm_mark_dirty(w, "force enable"); |
3616 | 3636 | ||
@@ -3788,35 +3808,54 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, | |||
3788 | } | 3808 | } |
3789 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); | 3809 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); |
3790 | 3810 | ||
3811 | /** | ||
3812 | * dapm_is_external_path() - Checks if a path is a external path | ||
3813 | * @card: The card the path belongs to | ||
3814 | * @path: The path to check | ||
3815 | * | ||
3816 | * Returns true if the path is either between two different DAPM contexts or | ||
3817 | * between two external pins of the same DAPM context. Otherwise returns | ||
3818 | * false. | ||
3819 | */ | ||
3820 | static bool dapm_is_external_path(struct snd_soc_card *card, | ||
3821 | struct snd_soc_dapm_path *path) | ||
3822 | { | ||
3823 | dev_dbg(card->dev, | ||
3824 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | ||
3825 | path->source->name, path->source->id, path->source->dapm, | ||
3826 | path->sink->name, path->sink->id, path->sink->dapm); | ||
3827 | |||
3828 | /* Connection between two different DAPM contexts */ | ||
3829 | if (path->source->dapm != path->sink->dapm) | ||
3830 | return true; | ||
3831 | |||
3832 | /* Loopback connection from external pin to external pin */ | ||
3833 | if (path->sink->id == snd_soc_dapm_input) { | ||
3834 | switch (path->source->id) { | ||
3835 | case snd_soc_dapm_output: | ||
3836 | case snd_soc_dapm_micbias: | ||
3837 | return true; | ||
3838 | default: | ||
3839 | break; | ||
3840 | } | ||
3841 | } | ||
3842 | |||
3843 | return false; | ||
3844 | } | ||
3845 | |||
3791 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, | 3846 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, |
3792 | struct snd_soc_dapm_widget *w) | 3847 | struct snd_soc_dapm_widget *w) |
3793 | { | 3848 | { |
3794 | struct snd_soc_dapm_path *p; | 3849 | struct snd_soc_dapm_path *p; |
3795 | 3850 | ||
3796 | list_for_each_entry(p, &card->paths, list) { | 3851 | list_for_each_entry(p, &w->sources, list_sink) { |
3797 | if ((p->source == w) || (p->sink == w)) { | 3852 | if (dapm_is_external_path(card, p)) |
3798 | dev_dbg(card->dev, | 3853 | return true; |
3799 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | 3854 | } |
3800 | p->source->name, p->source->id, p->source->dapm, | ||
3801 | p->sink->name, p->sink->id, p->sink->dapm); | ||
3802 | 3855 | ||
3803 | /* Connected to something other than the codec */ | 3856 | list_for_each_entry(p, &w->sinks, list_source) { |
3804 | if (p->source->dapm != p->sink->dapm) | 3857 | if (dapm_is_external_path(card, p)) |
3805 | return true; | 3858 | return true; |
3806 | /* | ||
3807 | * Loopback connection from codec external pin to | ||
3808 | * codec external pin | ||
3809 | */ | ||
3810 | if (p->sink->id == snd_soc_dapm_input) { | ||
3811 | switch (p->source->id) { | ||
3812 | case snd_soc_dapm_output: | ||
3813 | case snd_soc_dapm_micbias: | ||
3814 | return true; | ||
3815 | default: | ||
3816 | break; | ||
3817 | } | ||
3818 | } | ||
3819 | } | ||
3820 | } | 3859 | } |
3821 | 3860 | ||
3822 | return false; | 3861 | return false; |
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c new file mode 100644 index 000000000000..100d92b5b77e --- /dev/null +++ b/sound/soc/soc-ops.c | |||
@@ -0,0 +1,952 @@ | |||
1 | /* | ||
2 | * soc-ops.c -- Generic ASoC operations | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | ||
10 | * with code, comments and ideas from :- | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/ctype.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/jack.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dpcm.h> | ||
33 | #include <sound/initval.h> | ||
34 | |||
35 | /** | ||
36 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
37 | * @kcontrol: mixer control | ||
38 | * @uinfo: control element information | ||
39 | * | ||
40 | * Callback to provide information about a double enumerated | ||
41 | * mixer control. | ||
42 | * | ||
43 | * Returns 0 for success. | ||
44 | */ | ||
45 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
46 | struct snd_ctl_elem_info *uinfo) | ||
47 | { | ||
48 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
49 | |||
50 | return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2, | ||
51 | e->items, e->texts); | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
54 | |||
55 | /** | ||
56 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
57 | * @kcontrol: mixer control | ||
58 | * @ucontrol: control element information | ||
59 | * | ||
60 | * Callback to get the value of a double enumerated mixer. | ||
61 | * | ||
62 | * Returns 0 for success. | ||
63 | */ | ||
64 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
65 | struct snd_ctl_elem_value *ucontrol) | ||
66 | { | ||
67 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
68 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
69 | unsigned int val, item; | ||
70 | unsigned int reg_val; | ||
71 | int ret; | ||
72 | |||
73 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
74 | if (ret) | ||
75 | return ret; | ||
76 | val = (reg_val >> e->shift_l) & e->mask; | ||
77 | item = snd_soc_enum_val_to_item(e, val); | ||
78 | ucontrol->value.enumerated.item[0] = item; | ||
79 | if (e->shift_l != e->shift_r) { | ||
80 | val = (reg_val >> e->shift_l) & e->mask; | ||
81 | item = snd_soc_enum_val_to_item(e, val); | ||
82 | ucontrol->value.enumerated.item[1] = item; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
88 | |||
89 | /** | ||
90 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
91 | * @kcontrol: mixer control | ||
92 | * @ucontrol: control element information | ||
93 | * | ||
94 | * Callback to set the value of a double enumerated mixer. | ||
95 | * | ||
96 | * Returns 0 for success. | ||
97 | */ | ||
98 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
102 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
103 | unsigned int *item = ucontrol->value.enumerated.item; | ||
104 | unsigned int val; | ||
105 | unsigned int mask; | ||
106 | |||
107 | if (item[0] >= e->items) | ||
108 | return -EINVAL; | ||
109 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
110 | mask = e->mask << e->shift_l; | ||
111 | if (e->shift_l != e->shift_r) { | ||
112 | if (item[1] >= e->items) | ||
113 | return -EINVAL; | ||
114 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
115 | mask |= e->mask << e->shift_r; | ||
116 | } | ||
117 | |||
118 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
121 | |||
122 | /** | ||
123 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
124 | * @component: component | ||
125 | * @reg: Register to read | ||
126 | * @mask: Mask to use after shifting the register value | ||
127 | * @shift: Right shift of register value | ||
128 | * @sign_bit: Bit that describes if a number is negative or not. | ||
129 | * @signed_val: Pointer to where the read value should be stored | ||
130 | * | ||
131 | * This functions reads a codec register. The register value is shifted right | ||
132 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
133 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
134 | * | ||
135 | * Returns 0 on sucess, otherwise an error value | ||
136 | */ | ||
137 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
138 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
139 | unsigned int sign_bit, int *signed_val) | ||
140 | { | ||
141 | int ret; | ||
142 | unsigned int val; | ||
143 | |||
144 | ret = snd_soc_component_read(component, reg, &val); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | |||
148 | val = (val >> shift) & mask; | ||
149 | |||
150 | if (!sign_bit) { | ||
151 | *signed_val = val; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* non-negative number */ | ||
156 | if (!(val & BIT(sign_bit))) { | ||
157 | *signed_val = val; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | ret = val; | ||
162 | |||
163 | /* | ||
164 | * The register most probably does not contain a full-sized int. | ||
165 | * Instead we have an arbitrary number of bits in a signed | ||
166 | * representation which has to be translated into a full-sized int. | ||
167 | * This is done by filling up all bits above the sign-bit. | ||
168 | */ | ||
169 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
170 | |||
171 | *signed_val = ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_info_volsw - single mixer info callback | ||
178 | * @kcontrol: mixer control | ||
179 | * @uinfo: control element information | ||
180 | * | ||
181 | * Callback to provide information about a single mixer control, or a double | ||
182 | * mixer control that spans 2 registers. | ||
183 | * | ||
184 | * Returns 0 for success. | ||
185 | */ | ||
186 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
187 | struct snd_ctl_elem_info *uinfo) | ||
188 | { | ||
189 | struct soc_mixer_control *mc = | ||
190 | (struct soc_mixer_control *)kcontrol->private_value; | ||
191 | int platform_max; | ||
192 | |||
193 | if (!mc->platform_max) | ||
194 | mc->platform_max = mc->max; | ||
195 | platform_max = mc->platform_max; | ||
196 | |||
197 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
198 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
199 | else | ||
200 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
201 | |||
202 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
203 | uinfo->value.integer.min = 0; | ||
204 | uinfo->value.integer.max = platform_max - mc->min; | ||
205 | return 0; | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
208 | |||
209 | /** | ||
210 | * snd_soc_get_volsw - single mixer get callback | ||
211 | * @kcontrol: mixer control | ||
212 | * @ucontrol: control element information | ||
213 | * | ||
214 | * Callback to get the value of a single mixer control, or a double mixer | ||
215 | * control that spans 2 registers. | ||
216 | * | ||
217 | * Returns 0 for success. | ||
218 | */ | ||
219 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
220 | struct snd_ctl_elem_value *ucontrol) | ||
221 | { | ||
222 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
223 | struct soc_mixer_control *mc = | ||
224 | (struct soc_mixer_control *)kcontrol->private_value; | ||
225 | unsigned int reg = mc->reg; | ||
226 | unsigned int reg2 = mc->rreg; | ||
227 | unsigned int shift = mc->shift; | ||
228 | unsigned int rshift = mc->rshift; | ||
229 | int max = mc->max; | ||
230 | int min = mc->min; | ||
231 | int sign_bit = mc->sign_bit; | ||
232 | unsigned int mask = (1 << fls(max)) - 1; | ||
233 | unsigned int invert = mc->invert; | ||
234 | int val; | ||
235 | int ret; | ||
236 | |||
237 | if (sign_bit) | ||
238 | mask = BIT(sign_bit + 1) - 1; | ||
239 | |||
240 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
241 | if (ret) | ||
242 | return ret; | ||
243 | |||
244 | ucontrol->value.integer.value[0] = val - min; | ||
245 | if (invert) | ||
246 | ucontrol->value.integer.value[0] = | ||
247 | max - ucontrol->value.integer.value[0]; | ||
248 | |||
249 | if (snd_soc_volsw_is_stereo(mc)) { | ||
250 | if (reg == reg2) | ||
251 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
252 | sign_bit, &val); | ||
253 | else | ||
254 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
255 | sign_bit, &val); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | ucontrol->value.integer.value[1] = val - min; | ||
260 | if (invert) | ||
261 | ucontrol->value.integer.value[1] = | ||
262 | max - ucontrol->value.integer.value[1]; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
268 | |||
269 | /** | ||
270 | * snd_soc_put_volsw - single mixer put callback | ||
271 | * @kcontrol: mixer control | ||
272 | * @ucontrol: control element information | ||
273 | * | ||
274 | * Callback to set the value of a single mixer control, or a double mixer | ||
275 | * control that spans 2 registers. | ||
276 | * | ||
277 | * Returns 0 for success. | ||
278 | */ | ||
279 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
280 | struct snd_ctl_elem_value *ucontrol) | ||
281 | { | ||
282 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
283 | struct soc_mixer_control *mc = | ||
284 | (struct soc_mixer_control *)kcontrol->private_value; | ||
285 | unsigned int reg = mc->reg; | ||
286 | unsigned int reg2 = mc->rreg; | ||
287 | unsigned int shift = mc->shift; | ||
288 | unsigned int rshift = mc->rshift; | ||
289 | int max = mc->max; | ||
290 | int min = mc->min; | ||
291 | unsigned int sign_bit = mc->sign_bit; | ||
292 | unsigned int mask = (1 << fls(max)) - 1; | ||
293 | unsigned int invert = mc->invert; | ||
294 | int err; | ||
295 | bool type_2r = false; | ||
296 | unsigned int val2 = 0; | ||
297 | unsigned int val, val_mask; | ||
298 | |||
299 | if (sign_bit) | ||
300 | mask = BIT(sign_bit + 1) - 1; | ||
301 | |||
302 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
303 | if (invert) | ||
304 | val = max - val; | ||
305 | val_mask = mask << shift; | ||
306 | val = val << shift; | ||
307 | if (snd_soc_volsw_is_stereo(mc)) { | ||
308 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
309 | if (invert) | ||
310 | val2 = max - val2; | ||
311 | if (reg == reg2) { | ||
312 | val_mask |= mask << rshift; | ||
313 | val |= val2 << rshift; | ||
314 | } else { | ||
315 | val2 = val2 << shift; | ||
316 | type_2r = true; | ||
317 | } | ||
318 | } | ||
319 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
320 | if (err < 0) | ||
321 | return err; | ||
322 | |||
323 | if (type_2r) | ||
324 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
325 | val2); | ||
326 | |||
327 | return err; | ||
328 | } | ||
329 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
330 | |||
331 | /** | ||
332 | * snd_soc_get_volsw_sx - single mixer get callback | ||
333 | * @kcontrol: mixer control | ||
334 | * @ucontrol: control element information | ||
335 | * | ||
336 | * Callback to get the value of a single mixer control, or a double mixer | ||
337 | * control that spans 2 registers. | ||
338 | * | ||
339 | * Returns 0 for success. | ||
340 | */ | ||
341 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
342 | struct snd_ctl_elem_value *ucontrol) | ||
343 | { | ||
344 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
345 | struct soc_mixer_control *mc = | ||
346 | (struct soc_mixer_control *)kcontrol->private_value; | ||
347 | unsigned int reg = mc->reg; | ||
348 | unsigned int reg2 = mc->rreg; | ||
349 | unsigned int shift = mc->shift; | ||
350 | unsigned int rshift = mc->rshift; | ||
351 | int max = mc->max; | ||
352 | int min = mc->min; | ||
353 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
354 | unsigned int val; | ||
355 | int ret; | ||
356 | |||
357 | ret = snd_soc_component_read(component, reg, &val); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
362 | |||
363 | if (snd_soc_volsw_is_stereo(mc)) { | ||
364 | ret = snd_soc_component_read(component, reg2, &val); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | val = ((val >> rshift) - min) & mask; | ||
369 | ucontrol->value.integer.value[1] = val; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
375 | |||
376 | /** | ||
377 | * snd_soc_put_volsw_sx - double mixer set callback | ||
378 | * @kcontrol: mixer control | ||
379 | * @uinfo: control element information | ||
380 | * | ||
381 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
382 | * | ||
383 | * Returns 0 for success. | ||
384 | */ | ||
385 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
386 | struct snd_ctl_elem_value *ucontrol) | ||
387 | { | ||
388 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
389 | struct soc_mixer_control *mc = | ||
390 | (struct soc_mixer_control *)kcontrol->private_value; | ||
391 | |||
392 | unsigned int reg = mc->reg; | ||
393 | unsigned int reg2 = mc->rreg; | ||
394 | unsigned int shift = mc->shift; | ||
395 | unsigned int rshift = mc->rshift; | ||
396 | int max = mc->max; | ||
397 | int min = mc->min; | ||
398 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
399 | int err = 0; | ||
400 | unsigned int val, val_mask, val2 = 0; | ||
401 | |||
402 | val_mask = mask << shift; | ||
403 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
404 | val = val << shift; | ||
405 | |||
406 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
407 | if (err < 0) | ||
408 | return err; | ||
409 | |||
410 | if (snd_soc_volsw_is_stereo(mc)) { | ||
411 | val_mask = mask << rshift; | ||
412 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
413 | val2 = val2 << rshift; | ||
414 | |||
415 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
416 | val2); | ||
417 | } | ||
418 | return err; | ||
419 | } | ||
420 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
421 | |||
422 | /** | ||
423 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
424 | * @kcontrol: mixer control | ||
425 | * @uinfo: control element information | ||
426 | * | ||
427 | * Callback to provide information, within a range, about a single | ||
428 | * mixer control. | ||
429 | * | ||
430 | * returns 0 for success. | ||
431 | */ | ||
432 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_info *uinfo) | ||
434 | { | ||
435 | struct soc_mixer_control *mc = | ||
436 | (struct soc_mixer_control *)kcontrol->private_value; | ||
437 | int platform_max; | ||
438 | int min = mc->min; | ||
439 | |||
440 | if (!mc->platform_max) | ||
441 | mc->platform_max = mc->max; | ||
442 | platform_max = mc->platform_max; | ||
443 | |||
444 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
445 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
446 | uinfo->value.integer.min = 0; | ||
447 | uinfo->value.integer.max = platform_max - min; | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
452 | |||
453 | /** | ||
454 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
455 | * @kcontrol: mixer control | ||
456 | * @ucontrol: control element information | ||
457 | * | ||
458 | * Callback to set the value, within a range, for a single mixer control. | ||
459 | * | ||
460 | * Returns 0 for success. | ||
461 | */ | ||
462 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | struct soc_mixer_control *mc = | ||
466 | (struct soc_mixer_control *)kcontrol->private_value; | ||
467 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
468 | unsigned int reg = mc->reg; | ||
469 | unsigned int rreg = mc->rreg; | ||
470 | unsigned int shift = mc->shift; | ||
471 | int min = mc->min; | ||
472 | int max = mc->max; | ||
473 | unsigned int mask = (1 << fls(max)) - 1; | ||
474 | unsigned int invert = mc->invert; | ||
475 | unsigned int val, val_mask; | ||
476 | int ret; | ||
477 | |||
478 | if (invert) | ||
479 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
480 | else | ||
481 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
482 | val_mask = mask << shift; | ||
483 | val = val << shift; | ||
484 | |||
485 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
486 | if (ret < 0) | ||
487 | return ret; | ||
488 | |||
489 | if (snd_soc_volsw_is_stereo(mc)) { | ||
490 | if (invert) | ||
491 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
492 | else | ||
493 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
494 | val_mask = mask << shift; | ||
495 | val = val << shift; | ||
496 | |||
497 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
498 | val); | ||
499 | } | ||
500 | |||
501 | return ret; | ||
502 | } | ||
503 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
504 | |||
505 | /** | ||
506 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
507 | * @kcontrol: mixer control | ||
508 | * @ucontrol: control element information | ||
509 | * | ||
510 | * Callback to get the value, within a range, of a single mixer control. | ||
511 | * | ||
512 | * Returns 0 for success. | ||
513 | */ | ||
514 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
515 | struct snd_ctl_elem_value *ucontrol) | ||
516 | { | ||
517 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
518 | struct soc_mixer_control *mc = | ||
519 | (struct soc_mixer_control *)kcontrol->private_value; | ||
520 | unsigned int reg = mc->reg; | ||
521 | unsigned int rreg = mc->rreg; | ||
522 | unsigned int shift = mc->shift; | ||
523 | int min = mc->min; | ||
524 | int max = mc->max; | ||
525 | unsigned int mask = (1 << fls(max)) - 1; | ||
526 | unsigned int invert = mc->invert; | ||
527 | unsigned int val; | ||
528 | int ret; | ||
529 | |||
530 | ret = snd_soc_component_read(component, reg, &val); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | |||
534 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
535 | if (invert) | ||
536 | ucontrol->value.integer.value[0] = | ||
537 | max - ucontrol->value.integer.value[0]; | ||
538 | else | ||
539 | ucontrol->value.integer.value[0] = | ||
540 | ucontrol->value.integer.value[0] - min; | ||
541 | |||
542 | if (snd_soc_volsw_is_stereo(mc)) { | ||
543 | ret = snd_soc_component_read(component, rreg, &val); | ||
544 | if (ret) | ||
545 | return ret; | ||
546 | |||
547 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
548 | if (invert) | ||
549 | ucontrol->value.integer.value[1] = | ||
550 | max - ucontrol->value.integer.value[1]; | ||
551 | else | ||
552 | ucontrol->value.integer.value[1] = | ||
553 | ucontrol->value.integer.value[1] - min; | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
559 | |||
560 | /** | ||
561 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
562 | * | ||
563 | * @codec: where to look for the control | ||
564 | * @name: Name of the control | ||
565 | * @max: new maximum limit | ||
566 | * | ||
567 | * Return 0 for success, else error. | ||
568 | */ | ||
569 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
570 | const char *name, int max) | ||
571 | { | ||
572 | struct snd_card *card = codec->component.card->snd_card; | ||
573 | struct snd_kcontrol *kctl; | ||
574 | struct soc_mixer_control *mc; | ||
575 | int found = 0; | ||
576 | int ret = -EINVAL; | ||
577 | |||
578 | /* Sanity check for name and max */ | ||
579 | if (unlikely(!name || max <= 0)) | ||
580 | return -EINVAL; | ||
581 | |||
582 | list_for_each_entry(kctl, &card->controls, list) { | ||
583 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
584 | found = 1; | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | if (found) { | ||
589 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
590 | if (max <= mc->max) { | ||
591 | mc->platform_max = max; | ||
592 | ret = 0; | ||
593 | } | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
598 | |||
599 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
600 | struct snd_ctl_elem_info *uinfo) | ||
601 | { | ||
602 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
603 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
604 | |||
605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
606 | uinfo->count = params->num_regs * component->val_bytes; | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
611 | |||
612 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
613 | struct snd_ctl_elem_value *ucontrol) | ||
614 | { | ||
615 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
616 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
617 | int ret; | ||
618 | |||
619 | if (component->regmap) | ||
620 | ret = regmap_raw_read(component->regmap, params->base, | ||
621 | ucontrol->value.bytes.data, | ||
622 | params->num_regs * component->val_bytes); | ||
623 | else | ||
624 | ret = -EINVAL; | ||
625 | |||
626 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
627 | if (ret == 0 && params->mask) { | ||
628 | switch (component->val_bytes) { | ||
629 | case 1: | ||
630 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
631 | break; | ||
632 | case 2: | ||
633 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
634 | &= cpu_to_be16(~params->mask); | ||
635 | break; | ||
636 | case 4: | ||
637 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
638 | &= cpu_to_be32(~params->mask); | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
648 | |||
649 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
650 | struct snd_ctl_elem_value *ucontrol) | ||
651 | { | ||
652 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
653 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
654 | int ret, len; | ||
655 | unsigned int val, mask; | ||
656 | void *data; | ||
657 | |||
658 | if (!component->regmap || !params->num_regs) | ||
659 | return -EINVAL; | ||
660 | |||
661 | len = params->num_regs * component->val_bytes; | ||
662 | |||
663 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
664 | if (!data) | ||
665 | return -ENOMEM; | ||
666 | |||
667 | /* | ||
668 | * If we've got a mask then we need to preserve the register | ||
669 | * bits. We shouldn't modify the incoming data so take a | ||
670 | * copy. | ||
671 | */ | ||
672 | if (params->mask) { | ||
673 | ret = regmap_read(component->regmap, params->base, &val); | ||
674 | if (ret != 0) | ||
675 | goto out; | ||
676 | |||
677 | val &= params->mask; | ||
678 | |||
679 | switch (component->val_bytes) { | ||
680 | case 1: | ||
681 | ((u8 *)data)[0] &= ~params->mask; | ||
682 | ((u8 *)data)[0] |= val; | ||
683 | break; | ||
684 | case 2: | ||
685 | mask = ~params->mask; | ||
686 | ret = regmap_parse_val(component->regmap, | ||
687 | &mask, &mask); | ||
688 | if (ret != 0) | ||
689 | goto out; | ||
690 | |||
691 | ((u16 *)data)[0] &= mask; | ||
692 | |||
693 | ret = regmap_parse_val(component->regmap, | ||
694 | &val, &val); | ||
695 | if (ret != 0) | ||
696 | goto out; | ||
697 | |||
698 | ((u16 *)data)[0] |= val; | ||
699 | break; | ||
700 | case 4: | ||
701 | mask = ~params->mask; | ||
702 | ret = regmap_parse_val(component->regmap, | ||
703 | &mask, &mask); | ||
704 | if (ret != 0) | ||
705 | goto out; | ||
706 | |||
707 | ((u32 *)data)[0] &= mask; | ||
708 | |||
709 | ret = regmap_parse_val(component->regmap, | ||
710 | &val, &val); | ||
711 | if (ret != 0) | ||
712 | goto out; | ||
713 | |||
714 | ((u32 *)data)[0] |= val; | ||
715 | break; | ||
716 | default: | ||
717 | ret = -EINVAL; | ||
718 | goto out; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | ret = regmap_raw_write(component->regmap, params->base, | ||
723 | data, len); | ||
724 | |||
725 | out: | ||
726 | kfree(data); | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
731 | |||
732 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
733 | struct snd_ctl_elem_info *ucontrol) | ||
734 | { | ||
735 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
736 | |||
737 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
738 | ucontrol->count = params->max; | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
743 | |||
744 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
745 | unsigned int size, unsigned int __user *tlv) | ||
746 | { | ||
747 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
748 | unsigned int count = size < params->max ? size : params->max; | ||
749 | int ret = -ENXIO; | ||
750 | |||
751 | switch (op_flag) { | ||
752 | case SNDRV_CTL_TLV_OP_READ: | ||
753 | if (params->get) | ||
754 | ret = params->get(tlv, count); | ||
755 | break; | ||
756 | case SNDRV_CTL_TLV_OP_WRITE: | ||
757 | if (params->put) | ||
758 | ret = params->put(tlv, count); | ||
759 | break; | ||
760 | } | ||
761 | return ret; | ||
762 | } | ||
763 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
764 | |||
765 | /** | ||
766 | * snd_soc_info_xr_sx - signed multi register info callback | ||
767 | * @kcontrol: mreg control | ||
768 | * @uinfo: control element information | ||
769 | * | ||
770 | * Callback to provide information of a control that can | ||
771 | * span multiple codec registers which together | ||
772 | * forms a single signed value in a MSB/LSB manner. | ||
773 | * | ||
774 | * Returns 0 for success. | ||
775 | */ | ||
776 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
777 | struct snd_ctl_elem_info *uinfo) | ||
778 | { | ||
779 | struct soc_mreg_control *mc = | ||
780 | (struct soc_mreg_control *)kcontrol->private_value; | ||
781 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
782 | uinfo->count = 1; | ||
783 | uinfo->value.integer.min = mc->min; | ||
784 | uinfo->value.integer.max = mc->max; | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
789 | |||
790 | /** | ||
791 | * snd_soc_get_xr_sx - signed multi register get callback | ||
792 | * @kcontrol: mreg control | ||
793 | * @ucontrol: control element information | ||
794 | * | ||
795 | * Callback to get the value of a control that can span | ||
796 | * multiple codec registers which together forms a single | ||
797 | * signed value in a MSB/LSB manner. The control supports | ||
798 | * specifying total no of bits used to allow for bitfields | ||
799 | * across the multiple codec registers. | ||
800 | * | ||
801 | * Returns 0 for success. | ||
802 | */ | ||
803 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
804 | struct snd_ctl_elem_value *ucontrol) | ||
805 | { | ||
806 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
807 | struct soc_mreg_control *mc = | ||
808 | (struct soc_mreg_control *)kcontrol->private_value; | ||
809 | unsigned int regbase = mc->regbase; | ||
810 | unsigned int regcount = mc->regcount; | ||
811 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
812 | unsigned int regwmask = (1<<regwshift)-1; | ||
813 | unsigned int invert = mc->invert; | ||
814 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
815 | long min = mc->min; | ||
816 | long max = mc->max; | ||
817 | long val = 0; | ||
818 | unsigned int regval; | ||
819 | unsigned int i; | ||
820 | int ret; | ||
821 | |||
822 | for (i = 0; i < regcount; i++) { | ||
823 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
824 | if (ret) | ||
825 | return ret; | ||
826 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
827 | } | ||
828 | val &= mask; | ||
829 | if (min < 0 && val > max) | ||
830 | val |= ~mask; | ||
831 | if (invert) | ||
832 | val = max - val; | ||
833 | ucontrol->value.integer.value[0] = val; | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
838 | |||
839 | /** | ||
840 | * snd_soc_put_xr_sx - signed multi register get callback | ||
841 | * @kcontrol: mreg control | ||
842 | * @ucontrol: control element information | ||
843 | * | ||
844 | * Callback to set the value of a control that can span | ||
845 | * multiple codec registers which together forms a single | ||
846 | * signed value in a MSB/LSB manner. The control supports | ||
847 | * specifying total no of bits used to allow for bitfields | ||
848 | * across the multiple codec registers. | ||
849 | * | ||
850 | * Returns 0 for success. | ||
851 | */ | ||
852 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
853 | struct snd_ctl_elem_value *ucontrol) | ||
854 | { | ||
855 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
856 | struct soc_mreg_control *mc = | ||
857 | (struct soc_mreg_control *)kcontrol->private_value; | ||
858 | unsigned int regbase = mc->regbase; | ||
859 | unsigned int regcount = mc->regcount; | ||
860 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
861 | unsigned int regwmask = (1<<regwshift)-1; | ||
862 | unsigned int invert = mc->invert; | ||
863 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
864 | long max = mc->max; | ||
865 | long val = ucontrol->value.integer.value[0]; | ||
866 | unsigned int i, regval, regmask; | ||
867 | int err; | ||
868 | |||
869 | if (invert) | ||
870 | val = max - val; | ||
871 | val &= mask; | ||
872 | for (i = 0; i < regcount; i++) { | ||
873 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
874 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
875 | err = snd_soc_component_update_bits(component, regbase+i, | ||
876 | regmask, regval); | ||
877 | if (err < 0) | ||
878 | return err; | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
884 | |||
885 | /** | ||
886 | * snd_soc_get_strobe - strobe get callback | ||
887 | * @kcontrol: mixer control | ||
888 | * @ucontrol: control element information | ||
889 | * | ||
890 | * Callback get the value of a strobe mixer control. | ||
891 | * | ||
892 | * Returns 0 for success. | ||
893 | */ | ||
894 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
895 | struct snd_ctl_elem_value *ucontrol) | ||
896 | { | ||
897 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
898 | struct soc_mixer_control *mc = | ||
899 | (struct soc_mixer_control *)kcontrol->private_value; | ||
900 | unsigned int reg = mc->reg; | ||
901 | unsigned int shift = mc->shift; | ||
902 | unsigned int mask = 1 << shift; | ||
903 | unsigned int invert = mc->invert != 0; | ||
904 | unsigned int val; | ||
905 | int ret; | ||
906 | |||
907 | ret = snd_soc_component_read(component, reg, &val); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | |||
911 | val &= mask; | ||
912 | |||
913 | if (shift != 0 && val != 0) | ||
914 | val = val >> shift; | ||
915 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
920 | |||
921 | /** | ||
922 | * snd_soc_put_strobe - strobe put callback | ||
923 | * @kcontrol: mixer control | ||
924 | * @ucontrol: control element information | ||
925 | * | ||
926 | * Callback strobe a register bit to high then low (or the inverse) | ||
927 | * in one pass of a single mixer enum control. | ||
928 | * | ||
929 | * Returns 1 for success. | ||
930 | */ | ||
931 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
932 | struct snd_ctl_elem_value *ucontrol) | ||
933 | { | ||
934 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
935 | struct soc_mixer_control *mc = | ||
936 | (struct soc_mixer_control *)kcontrol->private_value; | ||
937 | unsigned int reg = mc->reg; | ||
938 | unsigned int shift = mc->shift; | ||
939 | unsigned int mask = 1 << shift; | ||
940 | unsigned int invert = mc->invert != 0; | ||
941 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
942 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
943 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
944 | int err; | ||
945 | |||
946 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
947 | if (err < 0) | ||
948 | return err; | ||
949 | |||
950 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
951 | } | ||
952 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 002311afdeaa..5de2440ff25c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
654 | codec_dai->rate = 0; | 654 | codec_dai->rate = 0; |
655 | } | 655 | } |
656 | 656 | ||
657 | snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); | ||
658 | |||
657 | if (cpu_dai->driver->ops->shutdown) | 659 | if (cpu_dai->driver->ops->shutdown) |
658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 660 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
659 | 661 | ||
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
772 | for (i = 0; i < rtd->num_codecs; i++) | 774 | for (i = 0; i < rtd->num_codecs; i++) |
773 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, | 775 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, |
774 | substream->stream); | 776 | substream->stream); |
777 | snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); | ||
775 | 778 | ||
776 | out: | 779 | out: |
777 | mutex_unlock(&rtd->pcm_mutex); | 780 | mutex_unlock(&rtd->pcm_mutex); |
@@ -1522,13 +1525,36 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) | |||
1522 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture); | 1525 | dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture); |
1523 | } | 1526 | } |
1524 | 1527 | ||
1528 | static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd); | ||
1529 | |||
1530 | /* Set FE's runtime_update state; the state is protected via PCM stream lock | ||
1531 | * for avoiding the race with trigger callback. | ||
1532 | * If the state is unset and a trigger is pending while the previous operation, | ||
1533 | * process the pending trigger action here. | ||
1534 | */ | ||
1535 | static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, | ||
1536 | int stream, enum snd_soc_dpcm_update state) | ||
1537 | { | ||
1538 | struct snd_pcm_substream *substream = | ||
1539 | snd_soc_dpcm_get_substream(fe, stream); | ||
1540 | |||
1541 | snd_pcm_stream_lock_irq(substream); | ||
1542 | if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) { | ||
1543 | dpcm_fe_dai_do_trigger(substream, | ||
1544 | fe->dpcm[stream].trigger_pending - 1); | ||
1545 | fe->dpcm[stream].trigger_pending = 0; | ||
1546 | } | ||
1547 | fe->dpcm[stream].runtime_update = state; | ||
1548 | snd_pcm_stream_unlock_irq(substream); | ||
1549 | } | ||
1550 | |||
1525 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) | 1551 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) |
1526 | { | 1552 | { |
1527 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | 1553 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
1528 | struct snd_pcm_runtime *runtime = fe_substream->runtime; | 1554 | struct snd_pcm_runtime *runtime = fe_substream->runtime; |
1529 | int stream = fe_substream->stream, ret = 0; | 1555 | int stream = fe_substream->stream, ret = 0; |
1530 | 1556 | ||
1531 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1557 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
1532 | 1558 | ||
1533 | ret = dpcm_be_dai_startup(fe, fe_substream->stream); | 1559 | ret = dpcm_be_dai_startup(fe, fe_substream->stream); |
1534 | if (ret < 0) { | 1560 | if (ret < 0) { |
@@ -1550,13 +1576,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) | |||
1550 | dpcm_set_fe_runtime(fe_substream); | 1576 | dpcm_set_fe_runtime(fe_substream); |
1551 | snd_pcm_limit_hw_rates(runtime); | 1577 | snd_pcm_limit_hw_rates(runtime); |
1552 | 1578 | ||
1553 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1579 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
1554 | return 0; | 1580 | return 0; |
1555 | 1581 | ||
1556 | unwind: | 1582 | unwind: |
1557 | dpcm_be_dai_startup_unwind(fe, fe_substream->stream); | 1583 | dpcm_be_dai_startup_unwind(fe, fe_substream->stream); |
1558 | be_err: | 1584 | be_err: |
1559 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1585 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
1560 | return ret; | 1586 | return ret; |
1561 | } | 1587 | } |
1562 | 1588 | ||
@@ -1603,7 +1629,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) | |||
1603 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1629 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1604 | int stream = substream->stream; | 1630 | int stream = substream->stream; |
1605 | 1631 | ||
1606 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1632 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
1607 | 1633 | ||
1608 | /* shutdown the BEs */ | 1634 | /* shutdown the BEs */ |
1609 | dpcm_be_dai_shutdown(fe, substream->stream); | 1635 | dpcm_be_dai_shutdown(fe, substream->stream); |
@@ -1617,7 +1643,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) | |||
1617 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | 1643 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); |
1618 | 1644 | ||
1619 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1645 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1620 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1646 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
1621 | return 0; | 1647 | return 0; |
1622 | } | 1648 | } |
1623 | 1649 | ||
@@ -1641,6 +1667,10 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | |||
1641 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1667 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1642 | continue; | 1668 | continue; |
1643 | 1669 | ||
1670 | /* do not free hw if this BE is used by other FE */ | ||
1671 | if (be->dpcm[stream].users > 1) | ||
1672 | continue; | ||
1673 | |||
1644 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1674 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1645 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1675 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1646 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1676 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
@@ -1665,7 +1695,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) | |||
1665 | int err, stream = substream->stream; | 1695 | int err, stream = substream->stream; |
1666 | 1696 | ||
1667 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1697 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1668 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1698 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
1669 | 1699 | ||
1670 | dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); | 1700 | dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); |
1671 | 1701 | ||
@@ -1680,7 +1710,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) | |||
1680 | err = dpcm_be_dai_hw_free(fe, stream); | 1710 | err = dpcm_be_dai_hw_free(fe, stream); |
1681 | 1711 | ||
1682 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; | 1712 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; |
1683 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1713 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
1684 | 1714 | ||
1685 | mutex_unlock(&fe->card->mutex); | 1715 | mutex_unlock(&fe->card->mutex); |
1686 | return 0; | 1716 | return 0; |
@@ -1773,7 +1803,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, | |||
1773 | int ret, stream = substream->stream; | 1803 | int ret, stream = substream->stream; |
1774 | 1804 | ||
1775 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1805 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1776 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1806 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
1777 | 1807 | ||
1778 | memcpy(&fe->dpcm[substream->stream].hw_params, params, | 1808 | memcpy(&fe->dpcm[substream->stream].hw_params, params, |
1779 | sizeof(struct snd_pcm_hw_params)); | 1809 | sizeof(struct snd_pcm_hw_params)); |
@@ -1796,7 +1826,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, | |||
1796 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; | 1826 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; |
1797 | 1827 | ||
1798 | out: | 1828 | out: |
1799 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1829 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
1800 | mutex_unlock(&fe->card->mutex); | 1830 | mutex_unlock(&fe->card->mutex); |
1801 | return ret; | 1831 | return ret; |
1802 | } | 1832 | } |
@@ -1910,7 +1940,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, | |||
1910 | } | 1940 | } |
1911 | EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); | 1941 | EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); |
1912 | 1942 | ||
1913 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) | 1943 | static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) |
1914 | { | 1944 | { |
1915 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1945 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1916 | int stream = substream->stream, ret; | 1946 | int stream = substream->stream, ret; |
@@ -1984,6 +2014,23 @@ out: | |||
1984 | return ret; | 2014 | return ret; |
1985 | } | 2015 | } |
1986 | 2016 | ||
2017 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) | ||
2018 | { | ||
2019 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
2020 | int stream = substream->stream; | ||
2021 | |||
2022 | /* if FE's runtime_update is already set, we're in race; | ||
2023 | * process this trigger later at exit | ||
2024 | */ | ||
2025 | if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) { | ||
2026 | fe->dpcm[stream].trigger_pending = cmd + 1; | ||
2027 | return 0; /* delayed, assuming it's successful */ | ||
2028 | } | ||
2029 | |||
2030 | /* we're alone, let's trigger */ | ||
2031 | return dpcm_fe_dai_do_trigger(substream, cmd); | ||
2032 | } | ||
2033 | |||
1987 | int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) | 2034 | int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) |
1988 | { | 2035 | { |
1989 | struct snd_soc_dpcm *dpcm; | 2036 | struct snd_soc_dpcm *dpcm; |
@@ -2027,7 +2074,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) | |||
2027 | 2074 | ||
2028 | dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); | 2075 | dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); |
2029 | 2076 | ||
2030 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 2077 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); |
2031 | 2078 | ||
2032 | /* there is no point preparing this FE if there are no BEs */ | 2079 | /* there is no point preparing this FE if there are no BEs */ |
2033 | if (list_empty(&fe->dpcm[stream].be_clients)) { | 2080 | if (list_empty(&fe->dpcm[stream].be_clients)) { |
@@ -2054,7 +2101,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) | |||
2054 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | 2101 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; |
2055 | 2102 | ||
2056 | out: | 2103 | out: |
2057 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 2104 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
2058 | mutex_unlock(&fe->card->mutex); | 2105 | mutex_unlock(&fe->card->mutex); |
2059 | 2106 | ||
2060 | return ret; | 2107 | return ret; |
@@ -2201,11 +2248,11 @@ static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) | |||
2201 | { | 2248 | { |
2202 | int ret; | 2249 | int ret; |
2203 | 2250 | ||
2204 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 2251 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); |
2205 | ret = dpcm_run_update_startup(fe, stream); | 2252 | ret = dpcm_run_update_startup(fe, stream); |
2206 | if (ret < 0) | 2253 | if (ret < 0) |
2207 | dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); | 2254 | dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); |
2208 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 2255 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
2209 | 2256 | ||
2210 | return ret; | 2257 | return ret; |
2211 | } | 2258 | } |
@@ -2214,11 +2261,11 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) | |||
2214 | { | 2261 | { |
2215 | int ret; | 2262 | int ret; |
2216 | 2263 | ||
2217 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 2264 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); |
2218 | ret = dpcm_run_update_shutdown(fe, stream); | 2265 | ret = dpcm_run_update_shutdown(fe, stream); |
2219 | if (ret < 0) | 2266 | if (ret < 0) |
2220 | dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); | 2267 | dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); |
2221 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 2268 | dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); |
2222 | 2269 | ||
2223 | return ret; | 2270 | return ret; |
2224 | } | 2271 | } |
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index cd71fd889d8b..00b7e2d02690 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c | |||
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
292 | struct snd_card *card = rtd->card->snd_card; | 292 | struct snd_card *card = rtd->card->snd_card; |
293 | struct snd_soc_dai *dai = rtd->cpu_dai; | 293 | struct snd_soc_dai *dai = rtd->cpu_dai; |
294 | struct snd_pcm *pcm = rtd->pcm; | 294 | struct snd_pcm *pcm = rtd->pcm; |
295 | struct platform_device *pdev = to_platform_device(dai->platform->dev); | 295 | struct platform_device *pdev = to_platform_device(rtd->platform->dev); |
296 | struct txx9aclc_soc_device *dev; | 296 | struct txx9aclc_soc_device *dev; |
297 | struct resource *r; | 297 | struct resource *r; |
298 | int i; | 298 | int i; |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 7ecd0e8a5c51..f61ebb17cc64 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -591,18 +591,19 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
591 | { | 591 | { |
592 | struct snd_card *card; | 592 | struct snd_card *card; |
593 | struct list_head *p; | 593 | struct list_head *p; |
594 | bool was_shutdown; | ||
594 | 595 | ||
595 | if (chip == (void *)-1L) | 596 | if (chip == (void *)-1L) |
596 | return; | 597 | return; |
597 | 598 | ||
598 | card = chip->card; | 599 | card = chip->card; |
599 | down_write(&chip->shutdown_rwsem); | 600 | down_write(&chip->shutdown_rwsem); |
601 | was_shutdown = chip->shutdown; | ||
600 | chip->shutdown = 1; | 602 | chip->shutdown = 1; |
601 | up_write(&chip->shutdown_rwsem); | 603 | up_write(&chip->shutdown_rwsem); |
602 | 604 | ||
603 | mutex_lock(®ister_mutex); | 605 | mutex_lock(®ister_mutex); |
604 | chip->num_interfaces--; | 606 | if (!was_shutdown) { |
605 | if (chip->num_interfaces <= 0) { | ||
606 | struct snd_usb_endpoint *ep; | 607 | struct snd_usb_endpoint *ep; |
607 | 608 | ||
608 | snd_card_disconnect(card); | 609 | snd_card_disconnect(card); |
@@ -622,6 +623,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
622 | list_for_each(p, &chip->mixer_list) { | 623 | list_for_each(p, &chip->mixer_list) { |
623 | snd_usb_mixer_disconnect(p); | 624 | snd_usb_mixer_disconnect(p); |
624 | } | 625 | } |
626 | } | ||
627 | |||
628 | chip->num_interfaces--; | ||
629 | if (chip->num_interfaces <= 0) { | ||
625 | usb_chip[chip->index] = NULL; | 630 | usb_chip[chip->index] = NULL; |
626 | mutex_unlock(®ister_mutex); | 631 | mutex_unlock(®ister_mutex); |
627 | snd_card_free_when_closed(card); | 632 | snd_card_free_when_closed(card); |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2e4a9dbc51fa..6e354d326858 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -2033,10 +2033,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2033 | cval->res = 1; | 2033 | cval->res = 1; |
2034 | cval->initialized = 1; | 2034 | cval->initialized = 1; |
2035 | 2035 | ||
2036 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | 2036 | if (state->mixer->protocol == UAC_VERSION_1) |
2037 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
2038 | else | ||
2039 | cval->control = 0; | 2037 | cval->control = 0; |
2038 | else /* UAC_VERSION_2 */ | ||
2039 | cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ? | ||
2040 | UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR; | ||
2040 | 2041 | ||
2041 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); | 2042 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
2042 | if (!namelist) { | 2043 | if (!namelist) { |
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f119a41ed9a9..8c9bf4b7aaf0 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -593,10 +593,10 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, | |||
593 | if (mixer->chip->shutdown) | 593 | if (mixer->chip->shutdown) |
594 | ret = -ENODEV; | 594 | ret = -ENODEV; |
595 | else | 595 | else |
596 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | 596 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, |
597 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 597 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
598 | 0, wIndex, | 598 | 0, wIndex, |
599 | &tmp, sizeof(tmp), 1000); | 599 | &tmp, sizeof(tmp)); |
600 | up_read(&mixer->chip->shutdown_rwsem); | 600 | up_read(&mixer->chip->shutdown_rwsem); |
601 | 601 | ||
602 | if (ret < 0) { | 602 | if (ret < 0) { |
@@ -885,6 +885,11 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, | |||
885 | return changed; | 885 | return changed; |
886 | } | 886 | } |
887 | 887 | ||
888 | static void kctl_private_value_free(struct snd_kcontrol *kctl) | ||
889 | { | ||
890 | kfree((void *)kctl->private_value); | ||
891 | } | ||
892 | |||
888 | static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, | 893 | static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, |
889 | int validx, int bUnitID) | 894 | int validx, int bUnitID) |
890 | { | 895 | { |
@@ -919,6 +924,7 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, | |||
919 | return -ENOMEM; | 924 | return -ENOMEM; |
920 | } | 925 | } |
921 | 926 | ||
927 | kctl->private_free = kctl_private_value_free; | ||
922 | err = snd_ctl_add(mixer->chip->card, kctl); | 928 | err = snd_ctl_add(mixer->chip->card, kctl); |
923 | if (err < 0) | 929 | if (err < 0) |
924 | return err; | 930 | return err; |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 223c47b33ba3..c657752a420c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -385,6 +385,36 @@ YAMAHA_DEVICE(0x105d, NULL), | |||
385 | } | 385 | } |
386 | }, | 386 | }, |
387 | { | 387 | { |
388 | USB_DEVICE(0x0499, 0x1509), | ||
389 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
390 | /* .vendor_name = "Yamaha", */ | ||
391 | /* .product_name = "Steinberg UR22", */ | ||
392 | .ifnum = QUIRK_ANY_INTERFACE, | ||
393 | .type = QUIRK_COMPOSITE, | ||
394 | .data = (const struct snd_usb_audio_quirk[]) { | ||
395 | { | ||
396 | .ifnum = 1, | ||
397 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
398 | }, | ||
399 | { | ||
400 | .ifnum = 2, | ||
401 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
402 | }, | ||
403 | { | ||
404 | .ifnum = 3, | ||
405 | .type = QUIRK_MIDI_YAMAHA | ||
406 | }, | ||
407 | { | ||
408 | .ifnum = 4, | ||
409 | .type = QUIRK_IGNORE_INTERFACE | ||
410 | }, | ||
411 | { | ||
412 | .ifnum = -1 | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | }, | ||
417 | { | ||
388 | USB_DEVICE(0x0499, 0x150a), | 418 | USB_DEVICE(0x0499, 0x150a), |
389 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 419 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
390 | /* .vendor_name = "Yamaha", */ | 420 | /* .vendor_name = "Yamaha", */ |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index d2aa45a8d895..60dfe0d28771 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -1146,6 +1146,20 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, | |||
1146 | if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && | 1146 | if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && |
1147 | (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) | 1147 | (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) |
1148 | mdelay(20); | 1148 | mdelay(20); |
1149 | |||
1150 | /* Marantz/Denon devices with USB DAC functionality need a delay | ||
1151 | * after each class compliant request | ||
1152 | */ | ||
1153 | if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) && | ||
1154 | (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) { | ||
1155 | |||
1156 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
1157 | case 0x3005: /* Marantz HD-DAC1 */ | ||
1158 | case 0x3006: /* Marantz SA-14S1 */ | ||
1159 | mdelay(20); | ||
1160 | break; | ||
1161 | } | ||
1162 | } | ||
1149 | } | 1163 | } |
1150 | 1164 | ||
1151 | /* | 1165 | /* |
@@ -1179,12 +1193,12 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1179 | /* iFi Audio micro/nano iDSD */ | 1193 | /* iFi Audio micro/nano iDSD */ |
1180 | case USB_ID(0x20b1, 0x3008): | 1194 | case USB_ID(0x20b1, 0x3008): |
1181 | if (fp->altsetting == 2) | 1195 | if (fp->altsetting == 2) |
1182 | return SNDRV_PCM_FMTBIT_DSD_U32_LE; | 1196 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1183 | break; | 1197 | break; |
1184 | /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ | 1198 | /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ |
1185 | case USB_ID(0x20b1, 0x2009): | 1199 | case USB_ID(0x20b1, 0x2009): |
1186 | if (fp->altsetting == 3) | 1200 | if (fp->altsetting == 3) |
1187 | return SNDRV_PCM_FMTBIT_DSD_U32_LE; | 1201 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1188 | break; | 1202 | break; |
1189 | default: | 1203 | default: |
1190 | break; | 1204 | break; |