Commit 9bffb1fb7c22c96d51d4ba06e2e023dd568a5872
Committed by
Mark Brown
1 parent
29594404d7
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
ASoC: Prevent pop_wait overwrite
pop_wait is used to determine if a deferred playback close needs to be cancelled when the a PCM is open or if after the power-down delay expires it needs to run. pop_wait is associated with the CODEC DAI, so the CODEC DAI must be unique. This holds true for most CODECs, except for the dummy CODEC and its DAI. In DAI links with non-unique dummy CODECs (e.g. front-ends), pop_wait can be overwritten by another DAI link using also a dummy CODEC. Failure to cancel a deferred close can cause mute due to the DAPM STOP event sent in the deferred work. One scenario where pop_wait is overwritten and causing mute is below (where hw:0,0 and hw:0,1 are two front-ends with default pmdown_time = 5 secs): aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 1 sleep 1 aplay /dev/urandom -D hw:0,1 -c 2 -r 48000 -f S16_LE -d 3 & aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE Since CODECs may not be unique, pop_wait is moved to the PCM runtime structure. Creating separate dummy CODECs for each DAI link can also solve the problem, but at this point it's only pop_wait variable in the CODEC DAI that has negative effects by not being unique. Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 4 changed files with 8 additions and 8 deletions Inline Diff
include/sound/soc-dai.h
1 | /* | 1 | /* |
2 | * linux/sound/soc-dai.h -- ALSA SoC Layer | 2 | * linux/sound/soc-dai.h -- ALSA SoC Layer |
3 | * | 3 | * |
4 | * Copyright: 2005-2008 Wolfson Microelectronics. PLC. | 4 | * Copyright: 2005-2008 Wolfson Microelectronics. PLC. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * Digital Audio Interface (DAI) API. | 10 | * Digital Audio Interface (DAI) API. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __LINUX_SND_SOC_DAI_H | 13 | #ifndef __LINUX_SND_SOC_DAI_H |
14 | #define __LINUX_SND_SOC_DAI_H | 14 | #define __LINUX_SND_SOC_DAI_H |
15 | 15 | ||
16 | 16 | ||
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | 18 | ||
19 | struct snd_pcm_substream; | 19 | struct snd_pcm_substream; |
20 | struct snd_soc_dapm_widget; | 20 | struct snd_soc_dapm_widget; |
21 | struct snd_compr_stream; | 21 | struct snd_compr_stream; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * DAI hardware audio formats. | 24 | * DAI hardware audio formats. |
25 | * | 25 | * |
26 | * Describes the physical PCM data formating and clocking. Add new formats | 26 | * Describes the physical PCM data formating and clocking. Add new formats |
27 | * to the end. | 27 | * to the end. |
28 | */ | 28 | */ |
29 | #define SND_SOC_DAIFMT_I2S 1 /* I2S mode */ | 29 | #define SND_SOC_DAIFMT_I2S 1 /* I2S mode */ |
30 | #define SND_SOC_DAIFMT_RIGHT_J 2 /* Right Justified mode */ | 30 | #define SND_SOC_DAIFMT_RIGHT_J 2 /* Right Justified mode */ |
31 | #define SND_SOC_DAIFMT_LEFT_J 3 /* Left Justified mode */ | 31 | #define SND_SOC_DAIFMT_LEFT_J 3 /* Left Justified mode */ |
32 | #define SND_SOC_DAIFMT_DSP_A 4 /* L data MSB after FRM LRC */ | 32 | #define SND_SOC_DAIFMT_DSP_A 4 /* L data MSB after FRM LRC */ |
33 | #define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */ | 33 | #define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */ |
34 | #define SND_SOC_DAIFMT_AC97 6 /* AC97 */ | 34 | #define SND_SOC_DAIFMT_AC97 6 /* AC97 */ |
35 | #define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */ | 35 | #define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */ |
36 | 36 | ||
37 | /* left and right justified also known as MSB and LSB respectively */ | 37 | /* left and right justified also known as MSB and LSB respectively */ |
38 | #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J | 38 | #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J |
39 | #define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J | 39 | #define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * DAI Clock gating. | 42 | * DAI Clock gating. |
43 | * | 43 | * |
44 | * DAI bit clocks can be be gated (disabled) when the DAI is not | 44 | * DAI bit clocks can be be gated (disabled) when the DAI is not |
45 | * sending or receiving PCM data in a frame. This can be used to save power. | 45 | * sending or receiving PCM data in a frame. This can be used to save power. |
46 | */ | 46 | */ |
47 | #define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */ | 47 | #define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */ |
48 | #define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */ | 48 | #define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */ |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * DAI hardware signal inversions. | 51 | * DAI hardware signal inversions. |
52 | * | 52 | * |
53 | * Specifies whether the DAI can also support inverted clocks for the specified | 53 | * Specifies whether the DAI can also support inverted clocks for the specified |
54 | * format. | 54 | * format. |
55 | */ | 55 | */ |
56 | #define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ | 56 | #define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ |
57 | #define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ | 57 | #define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ |
58 | #define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ | 58 | #define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ |
59 | #define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */ | 59 | #define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */ |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * DAI hardware clock masters. | 62 | * DAI hardware clock masters. |
63 | * | 63 | * |
64 | * This is wrt the codec, the inverse is true for the interface | 64 | * This is wrt the codec, the inverse is true for the interface |
65 | * i.e. if the codec is clk and FRM master then the interface is | 65 | * i.e. if the codec is clk and FRM master then the interface is |
66 | * clk and frame slave. | 66 | * clk and frame slave. |
67 | */ | 67 | */ |
68 | #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */ | 68 | #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */ |
69 | #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ | 69 | #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ |
70 | #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ | 70 | #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ |
71 | #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ | 71 | #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ |
72 | 72 | ||
73 | #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f | 73 | #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f |
74 | #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 | 74 | #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 |
75 | #define SND_SOC_DAIFMT_INV_MASK 0x0f00 | 75 | #define SND_SOC_DAIFMT_INV_MASK 0x0f00 |
76 | #define SND_SOC_DAIFMT_MASTER_MASK 0xf000 | 76 | #define SND_SOC_DAIFMT_MASTER_MASK 0xf000 |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * Master Clock Directions | 79 | * Master Clock Directions |
80 | */ | 80 | */ |
81 | #define SND_SOC_CLOCK_IN 0 | 81 | #define SND_SOC_CLOCK_IN 0 |
82 | #define SND_SOC_CLOCK_OUT 1 | 82 | #define SND_SOC_CLOCK_OUT 1 |
83 | 83 | ||
84 | #define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\ | 84 | #define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\ |
85 | SNDRV_PCM_FMTBIT_S16_LE |\ | 85 | SNDRV_PCM_FMTBIT_S16_LE |\ |
86 | SNDRV_PCM_FMTBIT_S16_BE |\ | 86 | SNDRV_PCM_FMTBIT_S16_BE |\ |
87 | SNDRV_PCM_FMTBIT_S20_3LE |\ | 87 | SNDRV_PCM_FMTBIT_S20_3LE |\ |
88 | SNDRV_PCM_FMTBIT_S20_3BE |\ | 88 | SNDRV_PCM_FMTBIT_S20_3BE |\ |
89 | SNDRV_PCM_FMTBIT_S24_3LE |\ | 89 | SNDRV_PCM_FMTBIT_S24_3LE |\ |
90 | SNDRV_PCM_FMTBIT_S24_3BE |\ | 90 | SNDRV_PCM_FMTBIT_S24_3BE |\ |
91 | SNDRV_PCM_FMTBIT_S32_LE |\ | 91 | SNDRV_PCM_FMTBIT_S32_LE |\ |
92 | SNDRV_PCM_FMTBIT_S32_BE) | 92 | SNDRV_PCM_FMTBIT_S32_BE) |
93 | 93 | ||
94 | struct snd_soc_dai_driver; | 94 | struct snd_soc_dai_driver; |
95 | struct snd_soc_dai; | 95 | struct snd_soc_dai; |
96 | struct snd_ac97_bus_ops; | 96 | struct snd_ac97_bus_ops; |
97 | 97 | ||
98 | /* Digital Audio Interface registration */ | 98 | /* Digital Audio Interface registration */ |
99 | int snd_soc_register_dai(struct device *dev, | 99 | int snd_soc_register_dai(struct device *dev, |
100 | struct snd_soc_dai_driver *dai_drv); | 100 | struct snd_soc_dai_driver *dai_drv); |
101 | void snd_soc_unregister_dai(struct device *dev); | 101 | void snd_soc_unregister_dai(struct device *dev); |
102 | int snd_soc_register_dais(struct device *dev, | 102 | int snd_soc_register_dais(struct device *dev, |
103 | struct snd_soc_dai_driver *dai_drv, size_t count); | 103 | struct snd_soc_dai_driver *dai_drv, size_t count); |
104 | void snd_soc_unregister_dais(struct device *dev, size_t count); | 104 | void snd_soc_unregister_dais(struct device *dev, size_t count); |
105 | 105 | ||
106 | /* Digital Audio Interface clocking API.*/ | 106 | /* Digital Audio Interface clocking API.*/ |
107 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 107 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
108 | unsigned int freq, int dir); | 108 | unsigned int freq, int dir); |
109 | 109 | ||
110 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | 110 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, |
111 | int div_id, int div); | 111 | int div_id, int div); |
112 | 112 | ||
113 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | 113 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, |
114 | int pll_id, int source, unsigned int freq_in, unsigned int freq_out); | 114 | int pll_id, int source, unsigned int freq_in, unsigned int freq_out); |
115 | 115 | ||
116 | /* Digital Audio interface formatting */ | 116 | /* Digital Audio interface formatting */ |
117 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); | 117 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); |
118 | 118 | ||
119 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 119 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
120 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); | 120 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); |
121 | 121 | ||
122 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, | 122 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, |
123 | unsigned int tx_num, unsigned int *tx_slot, | 123 | unsigned int tx_num, unsigned int *tx_slot, |
124 | unsigned int rx_num, unsigned int *rx_slot); | 124 | unsigned int rx_num, unsigned int *rx_slot); |
125 | 125 | ||
126 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); | 126 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); |
127 | 127 | ||
128 | /* Digital Audio Interface mute */ | 128 | /* Digital Audio Interface mute */ |
129 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); | 129 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); |
130 | 130 | ||
131 | struct snd_soc_dai_ops { | 131 | struct snd_soc_dai_ops { |
132 | /* | 132 | /* |
133 | * DAI clocking configuration, all optional. | 133 | * DAI clocking configuration, all optional. |
134 | * Called by soc_card drivers, normally in their hw_params. | 134 | * Called by soc_card drivers, normally in their hw_params. |
135 | */ | 135 | */ |
136 | int (*set_sysclk)(struct snd_soc_dai *dai, | 136 | int (*set_sysclk)(struct snd_soc_dai *dai, |
137 | int clk_id, unsigned int freq, int dir); | 137 | int clk_id, unsigned int freq, int dir); |
138 | int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, | 138 | int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, |
139 | unsigned int freq_in, unsigned int freq_out); | 139 | unsigned int freq_in, unsigned int freq_out); |
140 | int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); | 140 | int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); |
141 | 141 | ||
142 | /* | 142 | /* |
143 | * DAI format configuration | 143 | * DAI format configuration |
144 | * Called by soc_card drivers, normally in their hw_params. | 144 | * Called by soc_card drivers, normally in their hw_params. |
145 | */ | 145 | */ |
146 | int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); | 146 | int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); |
147 | int (*set_tdm_slot)(struct snd_soc_dai *dai, | 147 | int (*set_tdm_slot)(struct snd_soc_dai *dai, |
148 | unsigned int tx_mask, unsigned int rx_mask, | 148 | unsigned int tx_mask, unsigned int rx_mask, |
149 | int slots, int slot_width); | 149 | int slots, int slot_width); |
150 | int (*set_channel_map)(struct snd_soc_dai *dai, | 150 | int (*set_channel_map)(struct snd_soc_dai *dai, |
151 | unsigned int tx_num, unsigned int *tx_slot, | 151 | unsigned int tx_num, unsigned int *tx_slot, |
152 | unsigned int rx_num, unsigned int *rx_slot); | 152 | unsigned int rx_num, unsigned int *rx_slot); |
153 | int (*set_tristate)(struct snd_soc_dai *dai, int tristate); | 153 | int (*set_tristate)(struct snd_soc_dai *dai, int tristate); |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * DAI digital mute - optional. | 156 | * DAI digital mute - optional. |
157 | * Called by soc-core to minimise any pops. | 157 | * Called by soc-core to minimise any pops. |
158 | */ | 158 | */ |
159 | int (*digital_mute)(struct snd_soc_dai *dai, int mute); | 159 | int (*digital_mute)(struct snd_soc_dai *dai, int mute); |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * ALSA PCM audio operations - all optional. | 162 | * ALSA PCM audio operations - all optional. |
163 | * Called by soc-core during audio PCM operations. | 163 | * Called by soc-core during audio PCM operations. |
164 | */ | 164 | */ |
165 | int (*startup)(struct snd_pcm_substream *, | 165 | int (*startup)(struct snd_pcm_substream *, |
166 | struct snd_soc_dai *); | 166 | struct snd_soc_dai *); |
167 | void (*shutdown)(struct snd_pcm_substream *, | 167 | void (*shutdown)(struct snd_pcm_substream *, |
168 | struct snd_soc_dai *); | 168 | struct snd_soc_dai *); |
169 | int (*hw_params)(struct snd_pcm_substream *, | 169 | int (*hw_params)(struct snd_pcm_substream *, |
170 | struct snd_pcm_hw_params *, struct snd_soc_dai *); | 170 | struct snd_pcm_hw_params *, struct snd_soc_dai *); |
171 | int (*hw_free)(struct snd_pcm_substream *, | 171 | int (*hw_free)(struct snd_pcm_substream *, |
172 | struct snd_soc_dai *); | 172 | struct snd_soc_dai *); |
173 | int (*prepare)(struct snd_pcm_substream *, | 173 | int (*prepare)(struct snd_pcm_substream *, |
174 | struct snd_soc_dai *); | 174 | struct snd_soc_dai *); |
175 | int (*trigger)(struct snd_pcm_substream *, int, | 175 | int (*trigger)(struct snd_pcm_substream *, int, |
176 | struct snd_soc_dai *); | 176 | struct snd_soc_dai *); |
177 | int (*bespoke_trigger)(struct snd_pcm_substream *, int, | 177 | int (*bespoke_trigger)(struct snd_pcm_substream *, int, |
178 | struct snd_soc_dai *); | 178 | struct snd_soc_dai *); |
179 | /* | 179 | /* |
180 | * For hardware based FIFO caused delay reporting. | 180 | * For hardware based FIFO caused delay reporting. |
181 | * Optional. | 181 | * Optional. |
182 | */ | 182 | */ |
183 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, | 183 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, |
184 | struct snd_soc_dai *); | 184 | struct snd_soc_dai *); |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* | 187 | /* |
188 | * Digital Audio Interface Driver. | 188 | * Digital Audio Interface Driver. |
189 | * | 189 | * |
190 | * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97 | 190 | * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97 |
191 | * operations and capabilities. Codec and platform drivers will register this | 191 | * operations and capabilities. Codec and platform drivers will register this |
192 | * structure for every DAI they have. | 192 | * structure for every DAI they have. |
193 | * | 193 | * |
194 | * This structure covers the clocking, formating and ALSA operations for each | 194 | * This structure covers the clocking, formating and ALSA operations for each |
195 | * interface. | 195 | * interface. |
196 | */ | 196 | */ |
197 | struct snd_soc_dai_driver { | 197 | struct snd_soc_dai_driver { |
198 | /* DAI description */ | 198 | /* DAI description */ |
199 | const char *name; | 199 | const char *name; |
200 | unsigned int id; | 200 | unsigned int id; |
201 | int ac97_control; | 201 | int ac97_control; |
202 | unsigned int base; | 202 | unsigned int base; |
203 | 203 | ||
204 | /* DAI driver callbacks */ | 204 | /* DAI driver callbacks */ |
205 | int (*probe)(struct snd_soc_dai *dai); | 205 | int (*probe)(struct snd_soc_dai *dai); |
206 | int (*remove)(struct snd_soc_dai *dai); | 206 | int (*remove)(struct snd_soc_dai *dai); |
207 | int (*suspend)(struct snd_soc_dai *dai); | 207 | int (*suspend)(struct snd_soc_dai *dai); |
208 | int (*resume)(struct snd_soc_dai *dai); | 208 | int (*resume)(struct snd_soc_dai *dai); |
209 | /* compress dai */ | 209 | /* compress dai */ |
210 | bool compress_dai; | 210 | bool compress_dai; |
211 | 211 | ||
212 | /* ops */ | 212 | /* ops */ |
213 | const struct snd_soc_dai_ops *ops; | 213 | const struct snd_soc_dai_ops *ops; |
214 | 214 | ||
215 | /* DAI capabilities */ | 215 | /* DAI capabilities */ |
216 | struct snd_soc_pcm_stream capture; | 216 | struct snd_soc_pcm_stream capture; |
217 | struct snd_soc_pcm_stream playback; | 217 | struct snd_soc_pcm_stream playback; |
218 | unsigned int symmetric_rates:1; | 218 | unsigned int symmetric_rates:1; |
219 | 219 | ||
220 | /* probe ordering - for components with runtime dependencies */ | 220 | /* probe ordering - for components with runtime dependencies */ |
221 | int probe_order; | 221 | int probe_order; |
222 | int remove_order; | 222 | int remove_order; |
223 | }; | 223 | }; |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * Digital Audio Interface runtime data. | 226 | * Digital Audio Interface runtime data. |
227 | * | 227 | * |
228 | * Holds runtime data for a DAI. | 228 | * Holds runtime data for a DAI. |
229 | */ | 229 | */ |
230 | struct snd_soc_dai { | 230 | struct snd_soc_dai { |
231 | const char *name; | 231 | const char *name; |
232 | int id; | 232 | int id; |
233 | struct device *dev; | 233 | struct device *dev; |
234 | void *ac97_pdata; /* platform_data for the ac97 codec */ | 234 | void *ac97_pdata; /* platform_data for the ac97 codec */ |
235 | 235 | ||
236 | /* driver ops */ | 236 | /* driver ops */ |
237 | struct snd_soc_dai_driver *driver; | 237 | struct snd_soc_dai_driver *driver; |
238 | 238 | ||
239 | /* DAI runtime info */ | 239 | /* DAI runtime info */ |
240 | unsigned int capture_active:1; /* stream is in use */ | 240 | unsigned int capture_active:1; /* stream is in use */ |
241 | unsigned int playback_active:1; /* stream is in use */ | 241 | unsigned int playback_active:1; /* stream is in use */ |
242 | unsigned int symmetric_rates:1; | 242 | unsigned int symmetric_rates:1; |
243 | struct snd_pcm_runtime *runtime; | 243 | struct snd_pcm_runtime *runtime; |
244 | unsigned int active; | 244 | unsigned int active; |
245 | unsigned char pop_wait:1; | ||
246 | unsigned char probed:1; | 245 | unsigned char probed:1; |
247 | 246 | ||
248 | struct snd_soc_dapm_widget *playback_widget; | 247 | struct snd_soc_dapm_widget *playback_widget; |
249 | struct snd_soc_dapm_widget *capture_widget; | 248 | struct snd_soc_dapm_widget *capture_widget; |
250 | struct snd_soc_dapm_context dapm; | 249 | struct snd_soc_dapm_context dapm; |
251 | 250 | ||
252 | /* DAI DMA data */ | 251 | /* DAI DMA data */ |
253 | void *playback_dma_data; | 252 | void *playback_dma_data; |
254 | void *capture_dma_data; | 253 | void *capture_dma_data; |
255 | 254 | ||
256 | /* Symmetry data - only valid if symmetry is being enforced */ | 255 | /* Symmetry data - only valid if symmetry is being enforced */ |
257 | unsigned int rate; | 256 | unsigned int rate; |
258 | 257 | ||
259 | /* parent platform/codec */ | 258 | /* parent platform/codec */ |
260 | struct snd_soc_platform *platform; | 259 | struct snd_soc_platform *platform; |
261 | struct snd_soc_codec *codec; | 260 | struct snd_soc_codec *codec; |
262 | 261 | ||
263 | struct snd_soc_card *card; | 262 | struct snd_soc_card *card; |
264 | 263 | ||
265 | struct list_head list; | 264 | struct list_head list; |
266 | struct list_head card_list; | 265 | struct list_head card_list; |
267 | }; | 266 | }; |
268 | 267 | ||
269 | static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai, | 268 | static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai, |
270 | const struct snd_pcm_substream *ss) | 269 | const struct snd_pcm_substream *ss) |
271 | { | 270 | { |
272 | return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 271 | return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
273 | dai->playback_dma_data : dai->capture_dma_data; | 272 | dai->playback_dma_data : dai->capture_dma_data; |
274 | } | 273 | } |
275 | 274 | ||
276 | static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai, | 275 | static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai, |
277 | const struct snd_pcm_substream *ss, | 276 | const struct snd_pcm_substream *ss, |
278 | void *data) | 277 | void *data) |
279 | { | 278 | { |
280 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) | 279 | if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) |
281 | dai->playback_dma_data = data; | 280 | dai->playback_dma_data = data; |
282 | else | 281 | else |
283 | dai->capture_dma_data = data; | 282 | dai->capture_dma_data = data; |
284 | } | 283 | } |
285 | 284 | ||
286 | static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai, | 285 | static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai, |
287 | void *data) | 286 | void *data) |
288 | { | 287 | { |
289 | dev_set_drvdata(dai->dev, data); | 288 | dev_set_drvdata(dai->dev, data); |
290 | } | 289 | } |
291 | 290 | ||
292 | static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai) | 291 | static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai) |
293 | { | 292 | { |
294 | return dev_get_drvdata(dai->dev); | 293 | return dev_get_drvdata(dai->dev); |
295 | } | 294 | } |
296 | 295 | ||
297 | #endif | 296 | #endif |
298 | 297 |
include/sound/soc.h
1 | /* | 1 | /* |
2 | * linux/sound/soc.h -- ALSA SoC Layer | 2 | * linux/sound/soc.h -- ALSA SoC Layer |
3 | * | 3 | * |
4 | * Author: Liam Girdwood | 4 | * Author: Liam Girdwood |
5 | * Created: Aug 11th 2005 | 5 | * Created: Aug 11th 2005 |
6 | * Copyright: Wolfson Microelectronics. PLC. | 6 | * Copyright: Wolfson Microelectronics. PLC. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __LINUX_SND_SOC_H | 13 | #ifndef __LINUX_SND_SOC_H |
14 | #define __LINUX_SND_SOC_H | 14 | #define __LINUX_SND_SOC_H |
15 | 15 | ||
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/notifier.h> | 18 | #include <linux/notifier.h> |
19 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
23 | #include <linux/log2.h> | 23 | #include <linux/log2.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
26 | #include <sound/compress_driver.h> | 26 | #include <sound/compress_driver.h> |
27 | #include <sound/control.h> | 27 | #include <sound/control.h> |
28 | #include <sound/ac97_codec.h> | 28 | #include <sound/ac97_codec.h> |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Convenience kcontrol builders | 31 | * Convenience kcontrol builders |
32 | */ | 32 | */ |
33 | #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \ | 33 | #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \ |
34 | ((unsigned long)&(struct soc_mixer_control) \ | 34 | ((unsigned long)&(struct soc_mixer_control) \ |
35 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ | 35 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ |
36 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ | 36 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ |
37 | .invert = xinvert}) | 37 | .invert = xinvert}) |
38 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ | 38 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ |
39 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert) | 39 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert) |
40 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ | 40 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ |
41 | ((unsigned long)&(struct soc_mixer_control) \ | 41 | ((unsigned long)&(struct soc_mixer_control) \ |
42 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) | 42 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) |
43 | #define SOC_DOUBLE_R_VALUE(xlreg, xrreg, xshift, xmax, xinvert) \ | 43 | #define SOC_DOUBLE_R_VALUE(xlreg, xrreg, xshift, xmax, xinvert) \ |
44 | ((unsigned long)&(struct soc_mixer_control) \ | 44 | ((unsigned long)&(struct soc_mixer_control) \ |
45 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 45 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
46 | .max = xmax, .platform_max = xmax, .invert = xinvert}) | 46 | .max = xmax, .platform_max = xmax, .invert = xinvert}) |
47 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ | 47 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ |
48 | ((unsigned long)&(struct soc_mixer_control) \ | 48 | ((unsigned long)&(struct soc_mixer_control) \ |
49 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 49 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
50 | .min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert}) | 50 | .min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert}) |
51 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ | 51 | #define SOC_SINGLE(xname, reg, shift, max, invert) \ |
52 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 52 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
53 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 53 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
54 | .put = snd_soc_put_volsw, \ | 54 | .put = snd_soc_put_volsw, \ |
55 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 55 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } |
56 | #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ | 56 | #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ |
57 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 57 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ | 58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ |
59 | .put = snd_soc_put_volsw_range, \ | 59 | .put = snd_soc_put_volsw_range, \ |
60 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 60 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
61 | {.reg = xreg, .shift = xshift, .min = xmin,\ | 61 | {.reg = xreg, .shift = xshift, .min = xmin,\ |
62 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 62 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
63 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | 63 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ |
64 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 64 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
65 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 65 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
66 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 66 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
67 | .tlv.p = (tlv_array), \ | 67 | .tlv.p = (tlv_array), \ |
68 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 68 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
69 | .put = snd_soc_put_volsw, \ | 69 | .put = snd_soc_put_volsw, \ |
70 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 70 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } |
71 | #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \ | 71 | #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \ |
72 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 72 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
73 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 73 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
74 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 74 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
75 | .tlv.p = (tlv_array),\ | 75 | .tlv.p = (tlv_array),\ |
76 | .info = snd_soc_info_volsw, \ | 76 | .info = snd_soc_info_volsw, \ |
77 | .get = snd_soc_get_volsw_sx,\ | 77 | .get = snd_soc_get_volsw_sx,\ |
78 | .put = snd_soc_put_volsw_sx, \ | 78 | .put = snd_soc_put_volsw_sx, \ |
79 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 79 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
80 | {.reg = xreg, .rreg = xreg, \ | 80 | {.reg = xreg, .rreg = xreg, \ |
81 | .shift = xshift, .rshift = xshift, \ | 81 | .shift = xshift, .rshift = xshift, \ |
82 | .max = xmax, .min = xmin} } | 82 | .max = xmax, .min = xmin} } |
83 | #define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \ | 83 | #define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \ |
84 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 84 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
85 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 85 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
86 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 86 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
87 | .tlv.p = (tlv_array), \ | 87 | .tlv.p = (tlv_array), \ |
88 | .info = snd_soc_info_volsw_range, \ | 88 | .info = snd_soc_info_volsw_range, \ |
89 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ | 89 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ |
90 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 90 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
91 | {.reg = xreg, .shift = xshift, .min = xmin,\ | 91 | {.reg = xreg, .shift = xshift, .min = xmin,\ |
92 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 92 | .max = xmax, .platform_max = xmax, .invert = xinvert} } |
93 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ | 93 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ |
94 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 94 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
95 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 95 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
96 | .put = snd_soc_put_volsw, \ | 96 | .put = snd_soc_put_volsw, \ |
97 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ | 97 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ |
98 | max, invert) } | 98 | max, invert) } |
99 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ | 99 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ |
100 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 100 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
101 | .info = snd_soc_info_volsw, \ | 101 | .info = snd_soc_info_volsw, \ |
102 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ | 102 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ |
103 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ | 103 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ |
104 | xmax, xinvert) } | 104 | xmax, xinvert) } |
105 | #define SOC_DOUBLE_R_RANGE(xname, reg_left, reg_right, xshift, xmin, \ | 105 | #define SOC_DOUBLE_R_RANGE(xname, reg_left, reg_right, xshift, xmin, \ |
106 | xmax, xinvert) \ | 106 | xmax, xinvert) \ |
107 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 107 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
108 | .info = snd_soc_info_volsw_range, \ | 108 | .info = snd_soc_info_volsw_range, \ |
109 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ | 109 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ |
110 | .private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \ | 110 | .private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \ |
111 | xshift, xmin, xmax, xinvert) } | 111 | xshift, xmin, xmax, xinvert) } |
112 | #define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \ | 112 | #define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \ |
113 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 113 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
114 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 114 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
115 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 115 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
116 | .tlv.p = (tlv_array), \ | 116 | .tlv.p = (tlv_array), \ |
117 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 117 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
118 | .put = snd_soc_put_volsw, \ | 118 | .put = snd_soc_put_volsw, \ |
119 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ | 119 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ |
120 | max, invert) } | 120 | max, invert) } |
121 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ | 121 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ |
122 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 122 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
123 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 123 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
124 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 124 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
125 | .tlv.p = (tlv_array), \ | 125 | .tlv.p = (tlv_array), \ |
126 | .info = snd_soc_info_volsw, \ | 126 | .info = snd_soc_info_volsw, \ |
127 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ | 127 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ |
128 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ | 128 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ |
129 | xmax, xinvert) } | 129 | xmax, xinvert) } |
130 | #define SOC_DOUBLE_R_RANGE_TLV(xname, reg_left, reg_right, xshift, xmin, \ | 130 | #define SOC_DOUBLE_R_RANGE_TLV(xname, reg_left, reg_right, xshift, xmin, \ |
131 | xmax, xinvert, tlv_array) \ | 131 | xmax, xinvert, tlv_array) \ |
132 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 132 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
133 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 133 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
134 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 134 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
135 | .tlv.p = (tlv_array), \ | 135 | .tlv.p = (tlv_array), \ |
136 | .info = snd_soc_info_volsw_range, \ | 136 | .info = snd_soc_info_volsw_range, \ |
137 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ | 137 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ |
138 | .private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \ | 138 | .private_value = SOC_DOUBLE_R_RANGE_VALUE(reg_left, reg_right, \ |
139 | xshift, xmin, xmax, xinvert) } | 139 | xshift, xmin, xmax, xinvert) } |
140 | #define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \ | 140 | #define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \ |
141 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 141 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
142 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 142 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
143 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 143 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
144 | .tlv.p = (tlv_array), \ | 144 | .tlv.p = (tlv_array), \ |
145 | .info = snd_soc_info_volsw, \ | 145 | .info = snd_soc_info_volsw, \ |
146 | .get = snd_soc_get_volsw_sx, \ | 146 | .get = snd_soc_get_volsw_sx, \ |
147 | .put = snd_soc_put_volsw_sx, \ | 147 | .put = snd_soc_put_volsw_sx, \ |
148 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 148 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
149 | {.reg = xreg, .rreg = xrreg, \ | 149 | {.reg = xreg, .rreg = xrreg, \ |
150 | .shift = xshift, .rshift = xshift, \ | 150 | .shift = xshift, .rshift = xshift, \ |
151 | .max = xmax, .min = xmin} } | 151 | .max = xmax, .min = xmin} } |
152 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 152 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
153 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 153 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
154 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 154 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
155 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 155 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
156 | .tlv.p = (tlv_array), \ | 156 | .tlv.p = (tlv_array), \ |
157 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ | 157 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ |
158 | .put = snd_soc_put_volsw_s8, \ | 158 | .put = snd_soc_put_volsw_s8, \ |
159 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 159 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
160 | {.reg = xreg, .min = xmin, .max = xmax, \ | 160 | {.reg = xreg, .min = xmin, .max = xmax, \ |
161 | .platform_max = xmax} } | 161 | .platform_max = xmax} } |
162 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ | 162 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ |
163 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 163 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
164 | .max = xmax, .texts = xtexts, \ | 164 | .max = xmax, .texts = xtexts, \ |
165 | .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0} | 165 | .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0} |
166 | #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ | 166 | #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ |
167 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) | 167 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) |
168 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ | 168 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ |
169 | { .max = xmax, .texts = xtexts } | 169 | { .max = xmax, .texts = xtexts } |
170 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ | 170 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ |
171 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 171 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
172 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} | 172 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} |
173 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ | 173 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ |
174 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) | 174 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) |
175 | #define SOC_ENUM(xname, xenum) \ | 175 | #define SOC_ENUM(xname, xenum) \ |
176 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 176 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
177 | .info = snd_soc_info_enum_double, \ | 177 | .info = snd_soc_info_enum_double, \ |
178 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | 178 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ |
179 | .private_value = (unsigned long)&xenum } | 179 | .private_value = (unsigned long)&xenum } |
180 | #define SOC_VALUE_ENUM(xname, xenum) \ | 180 | #define SOC_VALUE_ENUM(xname, xenum) \ |
181 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 181 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
182 | .info = snd_soc_info_enum_double, \ | 182 | .info = snd_soc_info_enum_double, \ |
183 | .get = snd_soc_get_value_enum_double, \ | 183 | .get = snd_soc_get_value_enum_double, \ |
184 | .put = snd_soc_put_value_enum_double, \ | 184 | .put = snd_soc_put_value_enum_double, \ |
185 | .private_value = (unsigned long)&xenum } | 185 | .private_value = (unsigned long)&xenum } |
186 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ | 186 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ |
187 | xhandler_get, xhandler_put) \ | 187 | xhandler_get, xhandler_put) \ |
188 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 188 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
189 | .info = snd_soc_info_volsw, \ | 189 | .info = snd_soc_info_volsw, \ |
190 | .get = xhandler_get, .put = xhandler_put, \ | 190 | .get = xhandler_get, .put = xhandler_put, \ |
191 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 191 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } |
192 | #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\ | 192 | #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\ |
193 | xhandler_get, xhandler_put) \ | 193 | xhandler_get, xhandler_put) \ |
194 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 194 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
195 | .info = snd_soc_info_volsw, \ | 195 | .info = snd_soc_info_volsw, \ |
196 | .get = xhandler_get, .put = xhandler_put, \ | 196 | .get = xhandler_get, .put = xhandler_put, \ |
197 | .private_value = \ | 197 | .private_value = \ |
198 | SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) } | 198 | SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) } |
199 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ | 199 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ |
200 | xhandler_get, xhandler_put, tlv_array) \ | 200 | xhandler_get, xhandler_put, tlv_array) \ |
201 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 201 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
202 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 202 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
203 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 203 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
204 | .tlv.p = (tlv_array), \ | 204 | .tlv.p = (tlv_array), \ |
205 | .info = snd_soc_info_volsw, \ | 205 | .info = snd_soc_info_volsw, \ |
206 | .get = xhandler_get, .put = xhandler_put, \ | 206 | .get = xhandler_get, .put = xhandler_put, \ |
207 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 207 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } |
208 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ | 208 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ |
209 | xhandler_get, xhandler_put, tlv_array) \ | 209 | xhandler_get, xhandler_put, tlv_array) \ |
210 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 210 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
211 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 211 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
212 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 212 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
213 | .tlv.p = (tlv_array), \ | 213 | .tlv.p = (tlv_array), \ |
214 | .info = snd_soc_info_volsw, \ | 214 | .info = snd_soc_info_volsw, \ |
215 | .get = xhandler_get, .put = xhandler_put, \ | 215 | .get = xhandler_get, .put = xhandler_put, \ |
216 | .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \ | 216 | .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \ |
217 | xmax, xinvert) } | 217 | xmax, xinvert) } |
218 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ | 218 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
219 | xhandler_get, xhandler_put, tlv_array) \ | 219 | xhandler_get, xhandler_put, tlv_array) \ |
220 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 220 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
221 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 221 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
222 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 222 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
223 | .tlv.p = (tlv_array), \ | 223 | .tlv.p = (tlv_array), \ |
224 | .info = snd_soc_info_volsw, \ | 224 | .info = snd_soc_info_volsw, \ |
225 | .get = xhandler_get, .put = xhandler_put, \ | 225 | .get = xhandler_get, .put = xhandler_put, \ |
226 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ | 226 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ |
227 | xmax, xinvert) } | 227 | xmax, xinvert) } |
228 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | 228 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ |
229 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 229 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
230 | .info = snd_soc_info_bool_ext, \ | 230 | .info = snd_soc_info_bool_ext, \ |
231 | .get = xhandler_get, .put = xhandler_put, \ | 231 | .get = xhandler_get, .put = xhandler_put, \ |
232 | .private_value = xdata } | 232 | .private_value = xdata } |
233 | #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ | 233 | #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \ |
234 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 234 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
235 | .info = snd_soc_info_enum_ext, \ | 235 | .info = snd_soc_info_enum_ext, \ |
236 | .get = xhandler_get, .put = xhandler_put, \ | 236 | .get = xhandler_get, .put = xhandler_put, \ |
237 | .private_value = (unsigned long)&xenum } | 237 | .private_value = (unsigned long)&xenum } |
238 | 238 | ||
239 | #define SND_SOC_BYTES(xname, xbase, xregs) \ | 239 | #define SND_SOC_BYTES(xname, xbase, xregs) \ |
240 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 240 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
241 | .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ | 241 | .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ |
242 | .put = snd_soc_bytes_put, .private_value = \ | 242 | .put = snd_soc_bytes_put, .private_value = \ |
243 | ((unsigned long)&(struct soc_bytes) \ | 243 | ((unsigned long)&(struct soc_bytes) \ |
244 | {.base = xbase, .num_regs = xregs }) } | 244 | {.base = xbase, .num_regs = xregs }) } |
245 | 245 | ||
246 | #define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \ | 246 | #define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \ |
247 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 247 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
248 | .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ | 248 | .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ |
249 | .put = snd_soc_bytes_put, .private_value = \ | 249 | .put = snd_soc_bytes_put, .private_value = \ |
250 | ((unsigned long)&(struct soc_bytes) \ | 250 | ((unsigned long)&(struct soc_bytes) \ |
251 | {.base = xbase, .num_regs = xregs, \ | 251 | {.base = xbase, .num_regs = xregs, \ |
252 | .mask = xmask }) } | 252 | .mask = xmask }) } |
253 | 253 | ||
254 | #define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \ | 254 | #define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \ |
255 | xmin, xmax, xinvert) \ | 255 | xmin, xmax, xinvert) \ |
256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
257 | .info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \ | 257 | .info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \ |
258 | .put = snd_soc_put_xr_sx, \ | 258 | .put = snd_soc_put_xr_sx, \ |
259 | .private_value = (unsigned long)&(struct soc_mreg_control) \ | 259 | .private_value = (unsigned long)&(struct soc_mreg_control) \ |
260 | {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \ | 260 | {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \ |
261 | .invert = xinvert, .min = xmin, .max = xmax} } | 261 | .invert = xinvert, .min = xmin, .max = xmax} } |
262 | 262 | ||
263 | #define SOC_SINGLE_STROBE(xname, xreg, xshift, xinvert) \ | 263 | #define SOC_SINGLE_STROBE(xname, xreg, xshift, xinvert) \ |
264 | SOC_SINGLE_EXT(xname, xreg, xshift, 1, xinvert, \ | 264 | SOC_SINGLE_EXT(xname, xreg, xshift, 1, xinvert, \ |
265 | snd_soc_get_strobe, snd_soc_put_strobe) | 265 | snd_soc_get_strobe, snd_soc_put_strobe) |
266 | 266 | ||
267 | /* | 267 | /* |
268 | * Simplified versions of above macros, declaring a struct and calculating | 268 | * Simplified versions of above macros, declaring a struct and calculating |
269 | * ARRAY_SIZE internally | 269 | * ARRAY_SIZE internally |
270 | */ | 270 | */ |
271 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ | 271 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ |
272 | struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ | 272 | struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ |
273 | ARRAY_SIZE(xtexts), xtexts) | 273 | ARRAY_SIZE(xtexts), xtexts) |
274 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ | 274 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ |
275 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) | 275 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) |
276 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ | 276 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ |
277 | struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) | 277 | struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) |
278 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ | 278 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ |
279 | struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ | 279 | struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ |
280 | ARRAY_SIZE(xtexts), xtexts, xvalues) | 280 | ARRAY_SIZE(xtexts), xtexts, xvalues) |
281 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ | 281 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ |
282 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) | 282 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) |
283 | 283 | ||
284 | /* | 284 | /* |
285 | * Component probe and remove ordering levels for components with runtime | 285 | * Component probe and remove ordering levels for components with runtime |
286 | * dependencies. | 286 | * dependencies. |
287 | */ | 287 | */ |
288 | #define SND_SOC_COMP_ORDER_FIRST -2 | 288 | #define SND_SOC_COMP_ORDER_FIRST -2 |
289 | #define SND_SOC_COMP_ORDER_EARLY -1 | 289 | #define SND_SOC_COMP_ORDER_EARLY -1 |
290 | #define SND_SOC_COMP_ORDER_NORMAL 0 | 290 | #define SND_SOC_COMP_ORDER_NORMAL 0 |
291 | #define SND_SOC_COMP_ORDER_LATE 1 | 291 | #define SND_SOC_COMP_ORDER_LATE 1 |
292 | #define SND_SOC_COMP_ORDER_LAST 2 | 292 | #define SND_SOC_COMP_ORDER_LAST 2 |
293 | 293 | ||
294 | /* | 294 | /* |
295 | * Bias levels | 295 | * Bias levels |
296 | * | 296 | * |
297 | * @ON: Bias is fully on for audio playback and capture operations. | 297 | * @ON: Bias is fully on for audio playback and capture operations. |
298 | * @PREPARE: Prepare for audio operations. Called before DAPM switching for | 298 | * @PREPARE: Prepare for audio operations. Called before DAPM switching for |
299 | * stream start and stop operations. | 299 | * stream start and stop operations. |
300 | * @STANDBY: Low power standby state when no playback/capture operations are | 300 | * @STANDBY: Low power standby state when no playback/capture operations are |
301 | * in progress. NOTE: The transition time between STANDBY and ON | 301 | * in progress. NOTE: The transition time between STANDBY and ON |
302 | * should be as fast as possible and no longer than 10ms. | 302 | * should be as fast as possible and no longer than 10ms. |
303 | * @OFF: Power Off. No restrictions on transition times. | 303 | * @OFF: Power Off. No restrictions on transition times. |
304 | */ | 304 | */ |
305 | enum snd_soc_bias_level { | 305 | enum snd_soc_bias_level { |
306 | SND_SOC_BIAS_OFF = 0, | 306 | SND_SOC_BIAS_OFF = 0, |
307 | SND_SOC_BIAS_STANDBY = 1, | 307 | SND_SOC_BIAS_STANDBY = 1, |
308 | SND_SOC_BIAS_PREPARE = 2, | 308 | SND_SOC_BIAS_PREPARE = 2, |
309 | SND_SOC_BIAS_ON = 3, | 309 | SND_SOC_BIAS_ON = 3, |
310 | }; | 310 | }; |
311 | 311 | ||
312 | struct device_node; | 312 | struct device_node; |
313 | struct snd_jack; | 313 | struct snd_jack; |
314 | struct snd_soc_card; | 314 | struct snd_soc_card; |
315 | struct snd_soc_pcm_stream; | 315 | struct snd_soc_pcm_stream; |
316 | struct snd_soc_ops; | 316 | struct snd_soc_ops; |
317 | struct snd_soc_pcm_runtime; | 317 | struct snd_soc_pcm_runtime; |
318 | struct snd_soc_dai; | 318 | struct snd_soc_dai; |
319 | struct snd_soc_dai_driver; | 319 | struct snd_soc_dai_driver; |
320 | struct snd_soc_platform; | 320 | struct snd_soc_platform; |
321 | struct snd_soc_dai_link; | 321 | struct snd_soc_dai_link; |
322 | struct snd_soc_platform_driver; | 322 | struct snd_soc_platform_driver; |
323 | struct snd_soc_codec; | 323 | struct snd_soc_codec; |
324 | struct snd_soc_codec_driver; | 324 | struct snd_soc_codec_driver; |
325 | struct soc_enum; | 325 | struct soc_enum; |
326 | struct snd_soc_jack; | 326 | struct snd_soc_jack; |
327 | struct snd_soc_jack_zone; | 327 | struct snd_soc_jack_zone; |
328 | struct snd_soc_jack_pin; | 328 | struct snd_soc_jack_pin; |
329 | struct snd_soc_cache_ops; | 329 | struct snd_soc_cache_ops; |
330 | #include <sound/soc-dapm.h> | 330 | #include <sound/soc-dapm.h> |
331 | #include <sound/soc-dpcm.h> | 331 | #include <sound/soc-dpcm.h> |
332 | 332 | ||
333 | #ifdef CONFIG_GPIOLIB | 333 | #ifdef CONFIG_GPIOLIB |
334 | struct snd_soc_jack_gpio; | 334 | struct snd_soc_jack_gpio; |
335 | #endif | 335 | #endif |
336 | 336 | ||
337 | typedef int (*hw_write_t)(void *,const char* ,int); | 337 | typedef int (*hw_write_t)(void *,const char* ,int); |
338 | 338 | ||
339 | extern struct snd_ac97_bus_ops soc_ac97_ops; | 339 | extern struct snd_ac97_bus_ops soc_ac97_ops; |
340 | 340 | ||
341 | enum snd_soc_control_type { | 341 | enum snd_soc_control_type { |
342 | SND_SOC_I2C = 1, | 342 | SND_SOC_I2C = 1, |
343 | SND_SOC_SPI, | 343 | SND_SOC_SPI, |
344 | SND_SOC_REGMAP, | 344 | SND_SOC_REGMAP, |
345 | }; | 345 | }; |
346 | 346 | ||
347 | enum snd_soc_compress_type { | 347 | enum snd_soc_compress_type { |
348 | SND_SOC_FLAT_COMPRESSION = 1, | 348 | SND_SOC_FLAT_COMPRESSION = 1, |
349 | }; | 349 | }; |
350 | 350 | ||
351 | enum snd_soc_pcm_subclass { | 351 | enum snd_soc_pcm_subclass { |
352 | SND_SOC_PCM_CLASS_PCM = 0, | 352 | SND_SOC_PCM_CLASS_PCM = 0, |
353 | SND_SOC_PCM_CLASS_BE = 1, | 353 | SND_SOC_PCM_CLASS_BE = 1, |
354 | }; | 354 | }; |
355 | 355 | ||
356 | enum snd_soc_card_subclass { | 356 | enum snd_soc_card_subclass { |
357 | SND_SOC_CARD_CLASS_INIT = 0, | 357 | SND_SOC_CARD_CLASS_INIT = 0, |
358 | SND_SOC_CARD_CLASS_RUNTIME = 1, | 358 | SND_SOC_CARD_CLASS_RUNTIME = 1, |
359 | }; | 359 | }; |
360 | 360 | ||
361 | int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, | 361 | int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, |
362 | int source, unsigned int freq, int dir); | 362 | int source, unsigned int freq, int dir); |
363 | int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, | 363 | int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, |
364 | unsigned int freq_in, unsigned int freq_out); | 364 | unsigned int freq_in, unsigned int freq_out); |
365 | 365 | ||
366 | int snd_soc_register_card(struct snd_soc_card *card); | 366 | int snd_soc_register_card(struct snd_soc_card *card); |
367 | int snd_soc_unregister_card(struct snd_soc_card *card); | 367 | int snd_soc_unregister_card(struct snd_soc_card *card); |
368 | int snd_soc_suspend(struct device *dev); | 368 | int snd_soc_suspend(struct device *dev); |
369 | int snd_soc_resume(struct device *dev); | 369 | int snd_soc_resume(struct device *dev); |
370 | int snd_soc_poweroff(struct device *dev); | 370 | int snd_soc_poweroff(struct device *dev); |
371 | int snd_soc_register_platform(struct device *dev, | 371 | int snd_soc_register_platform(struct device *dev, |
372 | struct snd_soc_platform_driver *platform_drv); | 372 | struct snd_soc_platform_driver *platform_drv); |
373 | void snd_soc_unregister_platform(struct device *dev); | 373 | void snd_soc_unregister_platform(struct device *dev); |
374 | int snd_soc_register_codec(struct device *dev, | 374 | int snd_soc_register_codec(struct device *dev, |
375 | const struct snd_soc_codec_driver *codec_drv, | 375 | const struct snd_soc_codec_driver *codec_drv, |
376 | struct snd_soc_dai_driver *dai_drv, int num_dai); | 376 | struct snd_soc_dai_driver *dai_drv, int num_dai); |
377 | void snd_soc_unregister_codec(struct device *dev); | 377 | void snd_soc_unregister_codec(struct device *dev); |
378 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, | 378 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, |
379 | unsigned int reg); | 379 | unsigned int reg); |
380 | int snd_soc_codec_readable_register(struct snd_soc_codec *codec, | 380 | int snd_soc_codec_readable_register(struct snd_soc_codec *codec, |
381 | unsigned int reg); | 381 | unsigned int reg); |
382 | int snd_soc_codec_writable_register(struct snd_soc_codec *codec, | 382 | int snd_soc_codec_writable_register(struct snd_soc_codec *codec, |
383 | unsigned int reg); | 383 | unsigned int reg); |
384 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | 384 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, |
385 | int addr_bits, int data_bits, | 385 | int addr_bits, int data_bits, |
386 | enum snd_soc_control_type control); | 386 | enum snd_soc_control_type control); |
387 | int snd_soc_cache_sync(struct snd_soc_codec *codec); | 387 | int snd_soc_cache_sync(struct snd_soc_codec *codec); |
388 | int snd_soc_cache_init(struct snd_soc_codec *codec); | 388 | int snd_soc_cache_init(struct snd_soc_codec *codec); |
389 | int snd_soc_cache_exit(struct snd_soc_codec *codec); | 389 | int snd_soc_cache_exit(struct snd_soc_codec *codec); |
390 | int snd_soc_cache_write(struct snd_soc_codec *codec, | 390 | int snd_soc_cache_write(struct snd_soc_codec *codec, |
391 | unsigned int reg, unsigned int value); | 391 | unsigned int reg, unsigned int value); |
392 | int snd_soc_cache_read(struct snd_soc_codec *codec, | 392 | int snd_soc_cache_read(struct snd_soc_codec *codec, |
393 | unsigned int reg, unsigned int *value); | 393 | unsigned int reg, unsigned int *value); |
394 | int snd_soc_default_volatile_register(struct snd_soc_codec *codec, | 394 | int snd_soc_default_volatile_register(struct snd_soc_codec *codec, |
395 | unsigned int reg); | 395 | unsigned int reg); |
396 | int snd_soc_default_readable_register(struct snd_soc_codec *codec, | 396 | int snd_soc_default_readable_register(struct snd_soc_codec *codec, |
397 | unsigned int reg); | 397 | unsigned int reg); |
398 | int snd_soc_default_writable_register(struct snd_soc_codec *codec, | 398 | int snd_soc_default_writable_register(struct snd_soc_codec *codec, |
399 | unsigned int reg); | 399 | unsigned int reg); |
400 | int snd_soc_platform_read(struct snd_soc_platform *platform, | 400 | int snd_soc_platform_read(struct snd_soc_platform *platform, |
401 | unsigned int reg); | 401 | unsigned int reg); |
402 | int snd_soc_platform_write(struct snd_soc_platform *platform, | 402 | int snd_soc_platform_write(struct snd_soc_platform *platform, |
403 | unsigned int reg, unsigned int val); | 403 | unsigned int reg, unsigned int val); |
404 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); | 404 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); |
405 | int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); | 405 | int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); |
406 | 406 | ||
407 | struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, | 407 | struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, |
408 | const char *dai_link, int stream); | 408 | const char *dai_link, int stream); |
409 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | 409 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, |
410 | const char *dai_link); | 410 | const char *dai_link); |
411 | 411 | ||
412 | /* Utility functions to get clock rates from various things */ | 412 | /* Utility functions to get clock rates from various things */ |
413 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); | 413 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); |
414 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); | 414 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); |
415 | int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); | 415 | int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); |
416 | int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); | 416 | int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); |
417 | 417 | ||
418 | /* set runtime hw params */ | 418 | /* set runtime hw params */ |
419 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | 419 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, |
420 | const struct snd_pcm_hardware *hw); | 420 | const struct snd_pcm_hardware *hw); |
421 | 421 | ||
422 | int snd_soc_platform_trigger(struct snd_pcm_substream *substream, | 422 | int snd_soc_platform_trigger(struct snd_pcm_substream *substream, |
423 | int cmd, struct snd_soc_platform *platform); | 423 | int cmd, struct snd_soc_platform *platform); |
424 | 424 | ||
425 | /* Jack reporting */ | 425 | /* Jack reporting */ |
426 | int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, | 426 | int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, |
427 | struct snd_soc_jack *jack); | 427 | struct snd_soc_jack *jack); |
428 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); | 428 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); |
429 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | 429 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, |
430 | struct snd_soc_jack_pin *pins); | 430 | struct snd_soc_jack_pin *pins); |
431 | void snd_soc_jack_notifier_register(struct snd_soc_jack *jack, | 431 | void snd_soc_jack_notifier_register(struct snd_soc_jack *jack, |
432 | struct notifier_block *nb); | 432 | struct notifier_block *nb); |
433 | void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack, | 433 | void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack, |
434 | struct notifier_block *nb); | 434 | struct notifier_block *nb); |
435 | int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count, | 435 | int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count, |
436 | struct snd_soc_jack_zone *zones); | 436 | struct snd_soc_jack_zone *zones); |
437 | int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage); | 437 | int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage); |
438 | #ifdef CONFIG_GPIOLIB | 438 | #ifdef CONFIG_GPIOLIB |
439 | int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | 439 | int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, |
440 | struct snd_soc_jack_gpio *gpios); | 440 | struct snd_soc_jack_gpio *gpios); |
441 | void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, | 441 | void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, |
442 | struct snd_soc_jack_gpio *gpios); | 442 | struct snd_soc_jack_gpio *gpios); |
443 | #endif | 443 | #endif |
444 | 444 | ||
445 | /* codec register bit access */ | 445 | /* codec register bit access */ |
446 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 446 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
447 | unsigned int mask, unsigned int value); | 447 | unsigned int mask, unsigned int value); |
448 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | 448 | int snd_soc_update_bits_locked(struct snd_soc_codec *codec, |
449 | unsigned short reg, unsigned int mask, | 449 | unsigned short reg, unsigned int mask, |
450 | unsigned int value); | 450 | unsigned int value); |
451 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 451 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
452 | unsigned int mask, unsigned int value); | 452 | unsigned int mask, unsigned int value); |
453 | 453 | ||
454 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 454 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, |
455 | struct snd_ac97_bus_ops *ops, int num); | 455 | struct snd_ac97_bus_ops *ops, int num); |
456 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | 456 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); |
457 | 457 | ||
458 | /* | 458 | /* |
459 | *Controls | 459 | *Controls |
460 | */ | 460 | */ |
461 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | 461 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, |
462 | void *data, const char *long_name, | 462 | void *data, const char *long_name, |
463 | const char *prefix); | 463 | const char *prefix); |
464 | int snd_soc_add_codec_controls(struct snd_soc_codec *codec, | 464 | int snd_soc_add_codec_controls(struct snd_soc_codec *codec, |
465 | const struct snd_kcontrol_new *controls, int num_controls); | 465 | const struct snd_kcontrol_new *controls, int num_controls); |
466 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, | 466 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, |
467 | const struct snd_kcontrol_new *controls, int num_controls); | 467 | const struct snd_kcontrol_new *controls, int num_controls); |
468 | int snd_soc_add_card_controls(struct snd_soc_card *soc_card, | 468 | int snd_soc_add_card_controls(struct snd_soc_card *soc_card, |
469 | const struct snd_kcontrol_new *controls, int num_controls); | 469 | const struct snd_kcontrol_new *controls, int num_controls); |
470 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | 470 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, |
471 | const struct snd_kcontrol_new *controls, int num_controls); | 471 | const struct snd_kcontrol_new *controls, int num_controls); |
472 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | 472 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, |
473 | struct snd_ctl_elem_info *uinfo); | 473 | struct snd_ctl_elem_info *uinfo); |
474 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | 474 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, |
475 | struct snd_ctl_elem_info *uinfo); | 475 | struct snd_ctl_elem_info *uinfo); |
476 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | 476 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, |
477 | struct snd_ctl_elem_value *ucontrol); | 477 | struct snd_ctl_elem_value *ucontrol); |
478 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 478 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
479 | struct snd_ctl_elem_value *ucontrol); | 479 | struct snd_ctl_elem_value *ucontrol); |
480 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | 480 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, |
481 | struct snd_ctl_elem_value *ucontrol); | 481 | struct snd_ctl_elem_value *ucontrol); |
482 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | 482 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, |
483 | struct snd_ctl_elem_value *ucontrol); | 483 | struct snd_ctl_elem_value *ucontrol); |
484 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 484 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
485 | struct snd_ctl_elem_info *uinfo); | 485 | struct snd_ctl_elem_info *uinfo); |
486 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | 486 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, |
487 | struct snd_ctl_elem_info *uinfo); | 487 | struct snd_ctl_elem_info *uinfo); |
488 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info | 488 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info |
489 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | 489 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, |
490 | struct snd_ctl_elem_value *ucontrol); | 490 | struct snd_ctl_elem_value *ucontrol); |
491 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | 491 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, |
492 | struct snd_ctl_elem_value *ucontrol); | 492 | struct snd_ctl_elem_value *ucontrol); |
493 | #define snd_soc_get_volsw_2r snd_soc_get_volsw | 493 | #define snd_soc_get_volsw_2r snd_soc_get_volsw |
494 | #define snd_soc_put_volsw_2r snd_soc_put_volsw | 494 | #define snd_soc_put_volsw_2r snd_soc_put_volsw |
495 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | 495 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, |
496 | struct snd_ctl_elem_value *ucontrol); | 496 | struct snd_ctl_elem_value *ucontrol); |
497 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | 497 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, |
498 | struct snd_ctl_elem_value *ucontrol); | 498 | struct snd_ctl_elem_value *ucontrol); |
499 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | 499 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, |
500 | struct snd_ctl_elem_info *uinfo); | 500 | struct snd_ctl_elem_info *uinfo); |
501 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | 501 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, |
502 | struct snd_ctl_elem_value *ucontrol); | 502 | struct snd_ctl_elem_value *ucontrol); |
503 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | 503 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, |
504 | struct snd_ctl_elem_value *ucontrol); | 504 | struct snd_ctl_elem_value *ucontrol); |
505 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | 505 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, |
506 | struct snd_ctl_elem_info *uinfo); | 506 | struct snd_ctl_elem_info *uinfo); |
507 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | 507 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, |
508 | struct snd_ctl_elem_value *ucontrol); | 508 | struct snd_ctl_elem_value *ucontrol); |
509 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | 509 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, |
510 | struct snd_ctl_elem_value *ucontrol); | 510 | struct snd_ctl_elem_value *ucontrol); |
511 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | 511 | int snd_soc_limit_volume(struct snd_soc_codec *codec, |
512 | const char *name, int max); | 512 | const char *name, int max); |
513 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | 513 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, |
514 | struct snd_ctl_elem_info *uinfo); | 514 | struct snd_ctl_elem_info *uinfo); |
515 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | 515 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, |
516 | struct snd_ctl_elem_value *ucontrol); | 516 | struct snd_ctl_elem_value *ucontrol); |
517 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | 517 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, |
518 | struct snd_ctl_elem_value *ucontrol); | 518 | struct snd_ctl_elem_value *ucontrol); |
519 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | 519 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, |
520 | struct snd_ctl_elem_info *uinfo); | 520 | struct snd_ctl_elem_info *uinfo); |
521 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | 521 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, |
522 | struct snd_ctl_elem_value *ucontrol); | 522 | struct snd_ctl_elem_value *ucontrol); |
523 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | 523 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, |
524 | struct snd_ctl_elem_value *ucontrol); | 524 | struct snd_ctl_elem_value *ucontrol); |
525 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | 525 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, |
526 | struct snd_ctl_elem_value *ucontrol); | 526 | struct snd_ctl_elem_value *ucontrol); |
527 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | 527 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, |
528 | struct snd_ctl_elem_value *ucontrol); | 528 | struct snd_ctl_elem_value *ucontrol); |
529 | 529 | ||
530 | /** | 530 | /** |
531 | * struct snd_soc_reg_access - Describes whether a given register is | 531 | * struct snd_soc_reg_access - Describes whether a given register is |
532 | * readable, writable or volatile. | 532 | * readable, writable or volatile. |
533 | * | 533 | * |
534 | * @reg: the register number | 534 | * @reg: the register number |
535 | * @read: whether this register is readable | 535 | * @read: whether this register is readable |
536 | * @write: whether this register is writable | 536 | * @write: whether this register is writable |
537 | * @vol: whether this register is volatile | 537 | * @vol: whether this register is volatile |
538 | */ | 538 | */ |
539 | struct snd_soc_reg_access { | 539 | struct snd_soc_reg_access { |
540 | u16 reg; | 540 | u16 reg; |
541 | u16 read; | 541 | u16 read; |
542 | u16 write; | 542 | u16 write; |
543 | u16 vol; | 543 | u16 vol; |
544 | }; | 544 | }; |
545 | 545 | ||
546 | /** | 546 | /** |
547 | * struct snd_soc_jack_pin - Describes a pin to update based on jack detection | 547 | * struct snd_soc_jack_pin - Describes a pin to update based on jack detection |
548 | * | 548 | * |
549 | * @pin: name of the pin to update | 549 | * @pin: name of the pin to update |
550 | * @mask: bits to check for in reported jack status | 550 | * @mask: bits to check for in reported jack status |
551 | * @invert: if non-zero then pin is enabled when status is not reported | 551 | * @invert: if non-zero then pin is enabled when status is not reported |
552 | */ | 552 | */ |
553 | struct snd_soc_jack_pin { | 553 | struct snd_soc_jack_pin { |
554 | struct list_head list; | 554 | struct list_head list; |
555 | const char *pin; | 555 | const char *pin; |
556 | int mask; | 556 | int mask; |
557 | bool invert; | 557 | bool invert; |
558 | }; | 558 | }; |
559 | 559 | ||
560 | /** | 560 | /** |
561 | * struct snd_soc_jack_zone - Describes voltage zones of jack detection | 561 | * struct snd_soc_jack_zone - Describes voltage zones of jack detection |
562 | * | 562 | * |
563 | * @min_mv: start voltage in mv | 563 | * @min_mv: start voltage in mv |
564 | * @max_mv: end voltage in mv | 564 | * @max_mv: end voltage in mv |
565 | * @jack_type: type of jack that is expected for this voltage | 565 | * @jack_type: type of jack that is expected for this voltage |
566 | * @debounce_time: debounce_time for jack, codec driver should wait for this | 566 | * @debounce_time: debounce_time for jack, codec driver should wait for this |
567 | * duration before reading the adc for voltages | 567 | * duration before reading the adc for voltages |
568 | * @:list: list container | 568 | * @:list: list container |
569 | */ | 569 | */ |
570 | struct snd_soc_jack_zone { | 570 | struct snd_soc_jack_zone { |
571 | unsigned int min_mv; | 571 | unsigned int min_mv; |
572 | unsigned int max_mv; | 572 | unsigned int max_mv; |
573 | unsigned int jack_type; | 573 | unsigned int jack_type; |
574 | unsigned int debounce_time; | 574 | unsigned int debounce_time; |
575 | struct list_head list; | 575 | struct list_head list; |
576 | }; | 576 | }; |
577 | 577 | ||
578 | /** | 578 | /** |
579 | * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection | 579 | * struct snd_soc_jack_gpio - Describes a gpio pin for jack detection |
580 | * | 580 | * |
581 | * @gpio: gpio number | 581 | * @gpio: gpio number |
582 | * @name: gpio name | 582 | * @name: gpio name |
583 | * @report: value to report when jack detected | 583 | * @report: value to report when jack detected |
584 | * @invert: report presence in low state | 584 | * @invert: report presence in low state |
585 | * @debouce_time: debouce time in ms | 585 | * @debouce_time: debouce time in ms |
586 | * @wake: enable as wake source | 586 | * @wake: enable as wake source |
587 | * @jack_status_check: callback function which overrides the detection | 587 | * @jack_status_check: callback function which overrides the detection |
588 | * to provide more complex checks (eg, reading an | 588 | * to provide more complex checks (eg, reading an |
589 | * ADC). | 589 | * ADC). |
590 | */ | 590 | */ |
591 | #ifdef CONFIG_GPIOLIB | 591 | #ifdef CONFIG_GPIOLIB |
592 | struct snd_soc_jack_gpio { | 592 | struct snd_soc_jack_gpio { |
593 | unsigned int gpio; | 593 | unsigned int gpio; |
594 | const char *name; | 594 | const char *name; |
595 | int report; | 595 | int report; |
596 | int invert; | 596 | int invert; |
597 | int debounce_time; | 597 | int debounce_time; |
598 | bool wake; | 598 | bool wake; |
599 | 599 | ||
600 | struct snd_soc_jack *jack; | 600 | struct snd_soc_jack *jack; |
601 | struct delayed_work work; | 601 | struct delayed_work work; |
602 | 602 | ||
603 | int (*jack_status_check)(void); | 603 | int (*jack_status_check)(void); |
604 | }; | 604 | }; |
605 | #endif | 605 | #endif |
606 | 606 | ||
607 | struct snd_soc_jack { | 607 | struct snd_soc_jack { |
608 | struct mutex mutex; | 608 | struct mutex mutex; |
609 | struct snd_jack *jack; | 609 | struct snd_jack *jack; |
610 | struct snd_soc_codec *codec; | 610 | struct snd_soc_codec *codec; |
611 | struct list_head pins; | 611 | struct list_head pins; |
612 | int status; | 612 | int status; |
613 | struct blocking_notifier_head notifier; | 613 | struct blocking_notifier_head notifier; |
614 | struct list_head jack_zones; | 614 | struct list_head jack_zones; |
615 | }; | 615 | }; |
616 | 616 | ||
617 | /* SoC PCM stream information */ | 617 | /* SoC PCM stream information */ |
618 | struct snd_soc_pcm_stream { | 618 | struct snd_soc_pcm_stream { |
619 | const char *stream_name; | 619 | const char *stream_name; |
620 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ | 620 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ |
621 | unsigned int rates; /* SNDRV_PCM_RATE_* */ | 621 | unsigned int rates; /* SNDRV_PCM_RATE_* */ |
622 | unsigned int rate_min; /* min rate */ | 622 | unsigned int rate_min; /* min rate */ |
623 | unsigned int rate_max; /* max rate */ | 623 | unsigned int rate_max; /* max rate */ |
624 | unsigned int channels_min; /* min channels */ | 624 | unsigned int channels_min; /* min channels */ |
625 | unsigned int channels_max; /* max channels */ | 625 | unsigned int channels_max; /* max channels */ |
626 | unsigned int sig_bits; /* number of bits of content */ | 626 | unsigned int sig_bits; /* number of bits of content */ |
627 | }; | 627 | }; |
628 | 628 | ||
629 | /* SoC audio ops */ | 629 | /* SoC audio ops */ |
630 | struct snd_soc_ops { | 630 | struct snd_soc_ops { |
631 | int (*startup)(struct snd_pcm_substream *); | 631 | int (*startup)(struct snd_pcm_substream *); |
632 | void (*shutdown)(struct snd_pcm_substream *); | 632 | void (*shutdown)(struct snd_pcm_substream *); |
633 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); | 633 | int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); |
634 | int (*hw_free)(struct snd_pcm_substream *); | 634 | int (*hw_free)(struct snd_pcm_substream *); |
635 | int (*prepare)(struct snd_pcm_substream *); | 635 | int (*prepare)(struct snd_pcm_substream *); |
636 | int (*trigger)(struct snd_pcm_substream *, int); | 636 | int (*trigger)(struct snd_pcm_substream *, int); |
637 | }; | 637 | }; |
638 | 638 | ||
639 | struct snd_soc_compr_ops { | 639 | struct snd_soc_compr_ops { |
640 | int (*startup)(struct snd_compr_stream *); | 640 | int (*startup)(struct snd_compr_stream *); |
641 | void (*shutdown)(struct snd_compr_stream *); | 641 | void (*shutdown)(struct snd_compr_stream *); |
642 | int (*set_params)(struct snd_compr_stream *); | 642 | int (*set_params)(struct snd_compr_stream *); |
643 | int (*trigger)(struct snd_compr_stream *); | 643 | int (*trigger)(struct snd_compr_stream *); |
644 | }; | 644 | }; |
645 | 645 | ||
646 | /* SoC cache ops */ | 646 | /* SoC cache ops */ |
647 | struct snd_soc_cache_ops { | 647 | struct snd_soc_cache_ops { |
648 | const char *name; | 648 | const char *name; |
649 | enum snd_soc_compress_type id; | 649 | enum snd_soc_compress_type id; |
650 | int (*init)(struct snd_soc_codec *codec); | 650 | int (*init)(struct snd_soc_codec *codec); |
651 | int (*exit)(struct snd_soc_codec *codec); | 651 | int (*exit)(struct snd_soc_codec *codec); |
652 | int (*read)(struct snd_soc_codec *codec, unsigned int reg, | 652 | int (*read)(struct snd_soc_codec *codec, unsigned int reg, |
653 | unsigned int *value); | 653 | unsigned int *value); |
654 | int (*write)(struct snd_soc_codec *codec, unsigned int reg, | 654 | int (*write)(struct snd_soc_codec *codec, unsigned int reg, |
655 | unsigned int value); | 655 | unsigned int value); |
656 | int (*sync)(struct snd_soc_codec *codec); | 656 | int (*sync)(struct snd_soc_codec *codec); |
657 | }; | 657 | }; |
658 | 658 | ||
659 | /* SoC Audio Codec device */ | 659 | /* SoC Audio Codec device */ |
660 | struct snd_soc_codec { | 660 | struct snd_soc_codec { |
661 | const char *name; | 661 | const char *name; |
662 | const char *name_prefix; | 662 | const char *name_prefix; |
663 | int id; | 663 | int id; |
664 | struct device *dev; | 664 | struct device *dev; |
665 | const struct snd_soc_codec_driver *driver; | 665 | const struct snd_soc_codec_driver *driver; |
666 | 666 | ||
667 | struct mutex mutex; | 667 | struct mutex mutex; |
668 | struct snd_soc_card *card; | 668 | struct snd_soc_card *card; |
669 | struct list_head list; | 669 | struct list_head list; |
670 | struct list_head card_list; | 670 | struct list_head card_list; |
671 | int num_dai; | 671 | int num_dai; |
672 | enum snd_soc_compress_type compress_type; | 672 | enum snd_soc_compress_type compress_type; |
673 | size_t reg_size; /* reg_cache_size * reg_word_size */ | 673 | size_t reg_size; /* reg_cache_size * reg_word_size */ |
674 | int (*volatile_register)(struct snd_soc_codec *, unsigned int); | 674 | int (*volatile_register)(struct snd_soc_codec *, unsigned int); |
675 | int (*readable_register)(struct snd_soc_codec *, unsigned int); | 675 | int (*readable_register)(struct snd_soc_codec *, unsigned int); |
676 | int (*writable_register)(struct snd_soc_codec *, unsigned int); | 676 | int (*writable_register)(struct snd_soc_codec *, unsigned int); |
677 | 677 | ||
678 | /* runtime */ | 678 | /* runtime */ |
679 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | 679 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ |
680 | unsigned int active; | 680 | unsigned int active; |
681 | unsigned int cache_bypass:1; /* Suppress access to the cache */ | 681 | unsigned int cache_bypass:1; /* Suppress access to the cache */ |
682 | unsigned int suspended:1; /* Codec is in suspend PM state */ | 682 | unsigned int suspended:1; /* Codec is in suspend PM state */ |
683 | unsigned int probed:1; /* Codec has been probed */ | 683 | unsigned int probed:1; /* Codec has been probed */ |
684 | unsigned int ac97_registered:1; /* Codec has been AC97 registered */ | 684 | unsigned int ac97_registered:1; /* Codec has been AC97 registered */ |
685 | unsigned int ac97_created:1; /* Codec has been created by SoC */ | 685 | unsigned int ac97_created:1; /* Codec has been created by SoC */ |
686 | unsigned int sysfs_registered:1; /* codec has been sysfs registered */ | 686 | unsigned int sysfs_registered:1; /* codec has been sysfs registered */ |
687 | unsigned int cache_init:1; /* codec cache has been initialized */ | 687 | unsigned int cache_init:1; /* codec cache has been initialized */ |
688 | unsigned int using_regmap:1; /* using regmap access */ | 688 | unsigned int using_regmap:1; /* using regmap access */ |
689 | u32 cache_only; /* Suppress writes to hardware */ | 689 | u32 cache_only; /* Suppress writes to hardware */ |
690 | u32 cache_sync; /* Cache needs to be synced to hardware */ | 690 | u32 cache_sync; /* Cache needs to be synced to hardware */ |
691 | 691 | ||
692 | /* codec IO */ | 692 | /* codec IO */ |
693 | void *control_data; /* codec control (i2c/3wire) data */ | 693 | void *control_data; /* codec control (i2c/3wire) data */ |
694 | enum snd_soc_control_type control_type; | 694 | enum snd_soc_control_type control_type; |
695 | hw_write_t hw_write; | 695 | hw_write_t hw_write; |
696 | unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); | 696 | unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); |
697 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 697 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
698 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); | 698 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); |
699 | int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t); | 699 | int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t); |
700 | void *reg_cache; | 700 | void *reg_cache; |
701 | const void *reg_def_copy; | 701 | const void *reg_def_copy; |
702 | const struct snd_soc_cache_ops *cache_ops; | 702 | const struct snd_soc_cache_ops *cache_ops; |
703 | struct mutex cache_rw_mutex; | 703 | struct mutex cache_rw_mutex; |
704 | int val_bytes; | 704 | int val_bytes; |
705 | 705 | ||
706 | /* dapm */ | 706 | /* dapm */ |
707 | struct snd_soc_dapm_context dapm; | 707 | struct snd_soc_dapm_context dapm; |
708 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | 708 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ |
709 | 709 | ||
710 | #ifdef CONFIG_DEBUG_FS | 710 | #ifdef CONFIG_DEBUG_FS |
711 | struct dentry *debugfs_codec_root; | 711 | struct dentry *debugfs_codec_root; |
712 | struct dentry *debugfs_reg; | 712 | struct dentry *debugfs_reg; |
713 | struct dentry *debugfs_dapm; | 713 | struct dentry *debugfs_dapm; |
714 | #endif | 714 | #endif |
715 | }; | 715 | }; |
716 | 716 | ||
717 | /* codec driver */ | 717 | /* codec driver */ |
718 | struct snd_soc_codec_driver { | 718 | struct snd_soc_codec_driver { |
719 | 719 | ||
720 | /* driver ops */ | 720 | /* driver ops */ |
721 | int (*probe)(struct snd_soc_codec *); | 721 | int (*probe)(struct snd_soc_codec *); |
722 | int (*remove)(struct snd_soc_codec *); | 722 | int (*remove)(struct snd_soc_codec *); |
723 | int (*suspend)(struct snd_soc_codec *); | 723 | int (*suspend)(struct snd_soc_codec *); |
724 | int (*resume)(struct snd_soc_codec *); | 724 | int (*resume)(struct snd_soc_codec *); |
725 | 725 | ||
726 | /* Default control and setup, added after probe() is run */ | 726 | /* Default control and setup, added after probe() is run */ |
727 | const struct snd_kcontrol_new *controls; | 727 | const struct snd_kcontrol_new *controls; |
728 | int num_controls; | 728 | int num_controls; |
729 | const struct snd_soc_dapm_widget *dapm_widgets; | 729 | const struct snd_soc_dapm_widget *dapm_widgets; |
730 | int num_dapm_widgets; | 730 | int num_dapm_widgets; |
731 | const struct snd_soc_dapm_route *dapm_routes; | 731 | const struct snd_soc_dapm_route *dapm_routes; |
732 | int num_dapm_routes; | 732 | int num_dapm_routes; |
733 | 733 | ||
734 | /* codec wide operations */ | 734 | /* codec wide operations */ |
735 | int (*set_sysclk)(struct snd_soc_codec *codec, | 735 | int (*set_sysclk)(struct snd_soc_codec *codec, |
736 | int clk_id, int source, unsigned int freq, int dir); | 736 | int clk_id, int source, unsigned int freq, int dir); |
737 | int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source, | 737 | int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source, |
738 | unsigned int freq_in, unsigned int freq_out); | 738 | unsigned int freq_in, unsigned int freq_out); |
739 | 739 | ||
740 | /* codec IO */ | 740 | /* codec IO */ |
741 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 741 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
742 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); | 742 | int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); |
743 | int (*display_register)(struct snd_soc_codec *, char *, | 743 | int (*display_register)(struct snd_soc_codec *, char *, |
744 | size_t, unsigned int); | 744 | size_t, unsigned int); |
745 | int (*volatile_register)(struct snd_soc_codec *, unsigned int); | 745 | int (*volatile_register)(struct snd_soc_codec *, unsigned int); |
746 | int (*readable_register)(struct snd_soc_codec *, unsigned int); | 746 | int (*readable_register)(struct snd_soc_codec *, unsigned int); |
747 | int (*writable_register)(struct snd_soc_codec *, unsigned int); | 747 | int (*writable_register)(struct snd_soc_codec *, unsigned int); |
748 | unsigned int reg_cache_size; | 748 | unsigned int reg_cache_size; |
749 | short reg_cache_step; | 749 | short reg_cache_step; |
750 | short reg_word_size; | 750 | short reg_word_size; |
751 | const void *reg_cache_default; | 751 | const void *reg_cache_default; |
752 | short reg_access_size; | 752 | short reg_access_size; |
753 | const struct snd_soc_reg_access *reg_access_default; | 753 | const struct snd_soc_reg_access *reg_access_default; |
754 | enum snd_soc_compress_type compress_type; | 754 | enum snd_soc_compress_type compress_type; |
755 | 755 | ||
756 | /* codec bias level */ | 756 | /* codec bias level */ |
757 | int (*set_bias_level)(struct snd_soc_codec *, | 757 | int (*set_bias_level)(struct snd_soc_codec *, |
758 | enum snd_soc_bias_level level); | 758 | enum snd_soc_bias_level level); |
759 | bool idle_bias_off; | 759 | bool idle_bias_off; |
760 | 760 | ||
761 | void (*seq_notifier)(struct snd_soc_dapm_context *, | 761 | void (*seq_notifier)(struct snd_soc_dapm_context *, |
762 | enum snd_soc_dapm_type, int); | 762 | enum snd_soc_dapm_type, int); |
763 | 763 | ||
764 | /* codec stream completion event */ | 764 | /* codec stream completion event */ |
765 | int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); | 765 | int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); |
766 | 766 | ||
767 | bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */ | 767 | bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */ |
768 | 768 | ||
769 | /* probe ordering - for components with runtime dependencies */ | 769 | /* probe ordering - for components with runtime dependencies */ |
770 | int probe_order; | 770 | int probe_order; |
771 | int remove_order; | 771 | int remove_order; |
772 | }; | 772 | }; |
773 | 773 | ||
774 | /* SoC platform interface */ | 774 | /* SoC platform interface */ |
775 | struct snd_soc_platform_driver { | 775 | struct snd_soc_platform_driver { |
776 | 776 | ||
777 | int (*probe)(struct snd_soc_platform *); | 777 | int (*probe)(struct snd_soc_platform *); |
778 | int (*remove)(struct snd_soc_platform *); | 778 | int (*remove)(struct snd_soc_platform *); |
779 | int (*suspend)(struct snd_soc_dai *dai); | 779 | int (*suspend)(struct snd_soc_dai *dai); |
780 | int (*resume)(struct snd_soc_dai *dai); | 780 | int (*resume)(struct snd_soc_dai *dai); |
781 | 781 | ||
782 | /* pcm creation and destruction */ | 782 | /* pcm creation and destruction */ |
783 | int (*pcm_new)(struct snd_soc_pcm_runtime *); | 783 | int (*pcm_new)(struct snd_soc_pcm_runtime *); |
784 | void (*pcm_free)(struct snd_pcm *); | 784 | void (*pcm_free)(struct snd_pcm *); |
785 | 785 | ||
786 | /* Default control and setup, added after probe() is run */ | 786 | /* Default control and setup, added after probe() is run */ |
787 | const struct snd_kcontrol_new *controls; | 787 | const struct snd_kcontrol_new *controls; |
788 | int num_controls; | 788 | int num_controls; |
789 | const struct snd_soc_dapm_widget *dapm_widgets; | 789 | const struct snd_soc_dapm_widget *dapm_widgets; |
790 | int num_dapm_widgets; | 790 | int num_dapm_widgets; |
791 | const struct snd_soc_dapm_route *dapm_routes; | 791 | const struct snd_soc_dapm_route *dapm_routes; |
792 | int num_dapm_routes; | 792 | int num_dapm_routes; |
793 | 793 | ||
794 | /* | 794 | /* |
795 | * For platform caused delay reporting. | 795 | * For platform caused delay reporting. |
796 | * Optional. | 796 | * Optional. |
797 | */ | 797 | */ |
798 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, | 798 | snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, |
799 | struct snd_soc_dai *); | 799 | struct snd_soc_dai *); |
800 | 800 | ||
801 | /* platform stream pcm ops */ | 801 | /* platform stream pcm ops */ |
802 | struct snd_pcm_ops *ops; | 802 | struct snd_pcm_ops *ops; |
803 | 803 | ||
804 | /* platform stream compress ops */ | 804 | /* platform stream compress ops */ |
805 | struct snd_compr_ops *compr_ops; | 805 | struct snd_compr_ops *compr_ops; |
806 | 806 | ||
807 | /* platform stream completion event */ | 807 | /* platform stream completion event */ |
808 | int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); | 808 | int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); |
809 | 809 | ||
810 | /* probe ordering - for components with runtime dependencies */ | 810 | /* probe ordering - for components with runtime dependencies */ |
811 | int probe_order; | 811 | int probe_order; |
812 | int remove_order; | 812 | int remove_order; |
813 | 813 | ||
814 | /* platform IO - used for platform DAPM */ | 814 | /* platform IO - used for platform DAPM */ |
815 | unsigned int (*read)(struct snd_soc_platform *, unsigned int); | 815 | unsigned int (*read)(struct snd_soc_platform *, unsigned int); |
816 | int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); | 816 | int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); |
817 | int (*bespoke_trigger)(struct snd_pcm_substream *, int); | 817 | int (*bespoke_trigger)(struct snd_pcm_substream *, int); |
818 | }; | 818 | }; |
819 | 819 | ||
820 | struct snd_soc_platform { | 820 | struct snd_soc_platform { |
821 | const char *name; | 821 | const char *name; |
822 | int id; | 822 | int id; |
823 | struct device *dev; | 823 | struct device *dev; |
824 | struct snd_soc_platform_driver *driver; | 824 | struct snd_soc_platform_driver *driver; |
825 | struct mutex mutex; | 825 | struct mutex mutex; |
826 | 826 | ||
827 | unsigned int suspended:1; /* platform is suspended */ | 827 | unsigned int suspended:1; /* platform is suspended */ |
828 | unsigned int probed:1; | 828 | unsigned int probed:1; |
829 | 829 | ||
830 | struct snd_soc_card *card; | 830 | struct snd_soc_card *card; |
831 | struct list_head list; | 831 | struct list_head list; |
832 | struct list_head card_list; | 832 | struct list_head card_list; |
833 | 833 | ||
834 | struct snd_soc_dapm_context dapm; | 834 | struct snd_soc_dapm_context dapm; |
835 | 835 | ||
836 | #ifdef CONFIG_DEBUG_FS | 836 | #ifdef CONFIG_DEBUG_FS |
837 | struct dentry *debugfs_platform_root; | 837 | struct dentry *debugfs_platform_root; |
838 | struct dentry *debugfs_dapm; | 838 | struct dentry *debugfs_dapm; |
839 | #endif | 839 | #endif |
840 | }; | 840 | }; |
841 | 841 | ||
842 | struct snd_soc_dai_link { | 842 | struct snd_soc_dai_link { |
843 | /* config - must be set by machine driver */ | 843 | /* config - must be set by machine driver */ |
844 | const char *name; /* Codec name */ | 844 | const char *name; /* Codec name */ |
845 | const char *stream_name; /* Stream name */ | 845 | const char *stream_name; /* Stream name */ |
846 | /* | 846 | /* |
847 | * You MAY specify the link's CPU-side device, either by device name, | 847 | * You MAY specify the link's CPU-side device, either by device name, |
848 | * or by DT/OF node, but not both. If this information is omitted, | 848 | * or by DT/OF node, but not both. If this information is omitted, |
849 | * the CPU-side DAI is matched using .cpu_dai_name only, which hence | 849 | * the CPU-side DAI is matched using .cpu_dai_name only, which hence |
850 | * must be globally unique. These fields are currently typically used | 850 | * must be globally unique. These fields are currently typically used |
851 | * only for codec to codec links, or systems using device tree. | 851 | * only for codec to codec links, or systems using device tree. |
852 | */ | 852 | */ |
853 | const char *cpu_name; | 853 | const char *cpu_name; |
854 | const struct device_node *cpu_of_node; | 854 | const struct device_node *cpu_of_node; |
855 | /* | 855 | /* |
856 | * You MAY specify the DAI name of the CPU DAI. If this information is | 856 | * You MAY specify the DAI name of the CPU DAI. If this information is |
857 | * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node | 857 | * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node |
858 | * only, which only works well when that device exposes a single DAI. | 858 | * only, which only works well when that device exposes a single DAI. |
859 | */ | 859 | */ |
860 | const char *cpu_dai_name; | 860 | const char *cpu_dai_name; |
861 | /* | 861 | /* |
862 | * You MUST specify the link's codec, either by device name, or by | 862 | * You MUST specify the link's codec, either by device name, or by |
863 | * DT/OF node, but not both. | 863 | * DT/OF node, but not both. |
864 | */ | 864 | */ |
865 | const char *codec_name; | 865 | const char *codec_name; |
866 | const struct device_node *codec_of_node; | 866 | const struct device_node *codec_of_node; |
867 | /* You MUST specify the DAI name within the codec */ | 867 | /* You MUST specify the DAI name within the codec */ |
868 | const char *codec_dai_name; | 868 | const char *codec_dai_name; |
869 | /* | 869 | /* |
870 | * You MAY specify the link's platform/PCM/DMA driver, either by | 870 | * You MAY specify the link's platform/PCM/DMA driver, either by |
871 | * device name, or by DT/OF node, but not both. Some forms of link | 871 | * device name, or by DT/OF node, but not both. Some forms of link |
872 | * do not need a platform. | 872 | * do not need a platform. |
873 | */ | 873 | */ |
874 | const char *platform_name; | 874 | const char *platform_name; |
875 | const struct device_node *platform_of_node; | 875 | const struct device_node *platform_of_node; |
876 | int be_id; /* optional ID for machine driver BE identification */ | 876 | int be_id; /* optional ID for machine driver BE identification */ |
877 | 877 | ||
878 | const struct snd_soc_pcm_stream *params; | 878 | const struct snd_soc_pcm_stream *params; |
879 | 879 | ||
880 | unsigned int dai_fmt; /* format to set on init */ | 880 | unsigned int dai_fmt; /* format to set on init */ |
881 | 881 | ||
882 | enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ | 882 | enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ |
883 | 883 | ||
884 | /* Keep DAI active over suspend */ | 884 | /* Keep DAI active over suspend */ |
885 | unsigned int ignore_suspend:1; | 885 | unsigned int ignore_suspend:1; |
886 | 886 | ||
887 | /* Symmetry requirements */ | 887 | /* Symmetry requirements */ |
888 | unsigned int symmetric_rates:1; | 888 | unsigned int symmetric_rates:1; |
889 | 889 | ||
890 | /* Do not create a PCM for this DAI link (Backend link) */ | 890 | /* Do not create a PCM for this DAI link (Backend link) */ |
891 | unsigned int no_pcm:1; | 891 | unsigned int no_pcm:1; |
892 | 892 | ||
893 | /* This DAI link can route to other DAI links at runtime (Frontend)*/ | 893 | /* This DAI link can route to other DAI links at runtime (Frontend)*/ |
894 | unsigned int dynamic:1; | 894 | unsigned int dynamic:1; |
895 | 895 | ||
896 | /* pmdown_time is ignored at stop */ | 896 | /* pmdown_time is ignored at stop */ |
897 | unsigned int ignore_pmdown_time:1; | 897 | unsigned int ignore_pmdown_time:1; |
898 | 898 | ||
899 | /* codec/machine specific init - e.g. add machine controls */ | 899 | /* codec/machine specific init - e.g. add machine controls */ |
900 | int (*init)(struct snd_soc_pcm_runtime *rtd); | 900 | int (*init)(struct snd_soc_pcm_runtime *rtd); |
901 | 901 | ||
902 | /* optional hw_params re-writing for BE and FE sync */ | 902 | /* optional hw_params re-writing for BE and FE sync */ |
903 | int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, | 903 | int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, |
904 | struct snd_pcm_hw_params *params); | 904 | struct snd_pcm_hw_params *params); |
905 | 905 | ||
906 | /* machine stream operations */ | 906 | /* machine stream operations */ |
907 | struct snd_soc_ops *ops; | 907 | struct snd_soc_ops *ops; |
908 | struct snd_soc_compr_ops *compr_ops; | 908 | struct snd_soc_compr_ops *compr_ops; |
909 | }; | 909 | }; |
910 | 910 | ||
911 | struct snd_soc_codec_conf { | 911 | struct snd_soc_codec_conf { |
912 | const char *dev_name; | 912 | const char *dev_name; |
913 | 913 | ||
914 | /* | 914 | /* |
915 | * optional map of kcontrol, widget and path name prefixes that are | 915 | * optional map of kcontrol, widget and path name prefixes that are |
916 | * associated per device | 916 | * associated per device |
917 | */ | 917 | */ |
918 | const char *name_prefix; | 918 | const char *name_prefix; |
919 | 919 | ||
920 | /* | 920 | /* |
921 | * set this to the desired compression type if you want to | 921 | * set this to the desired compression type if you want to |
922 | * override the one supplied in codec->driver->compress_type | 922 | * override the one supplied in codec->driver->compress_type |
923 | */ | 923 | */ |
924 | enum snd_soc_compress_type compress_type; | 924 | enum snd_soc_compress_type compress_type; |
925 | }; | 925 | }; |
926 | 926 | ||
927 | struct snd_soc_aux_dev { | 927 | struct snd_soc_aux_dev { |
928 | const char *name; /* Codec name */ | 928 | const char *name; /* Codec name */ |
929 | const char *codec_name; /* for multi-codec */ | 929 | const char *codec_name; /* for multi-codec */ |
930 | 930 | ||
931 | /* codec/machine specific init - e.g. add machine controls */ | 931 | /* codec/machine specific init - e.g. add machine controls */ |
932 | int (*init)(struct snd_soc_dapm_context *dapm); | 932 | int (*init)(struct snd_soc_dapm_context *dapm); |
933 | }; | 933 | }; |
934 | 934 | ||
935 | /* SoC card */ | 935 | /* SoC card */ |
936 | struct snd_soc_card { | 936 | struct snd_soc_card { |
937 | const char *name; | 937 | const char *name; |
938 | const char *long_name; | 938 | const char *long_name; |
939 | const char *driver_name; | 939 | const char *driver_name; |
940 | struct device *dev; | 940 | struct device *dev; |
941 | struct snd_card *snd_card; | 941 | struct snd_card *snd_card; |
942 | struct module *owner; | 942 | struct module *owner; |
943 | 943 | ||
944 | struct list_head list; | 944 | struct list_head list; |
945 | struct mutex mutex; | 945 | struct mutex mutex; |
946 | struct mutex dapm_mutex; | 946 | struct mutex dapm_mutex; |
947 | 947 | ||
948 | bool instantiated; | 948 | bool instantiated; |
949 | 949 | ||
950 | int (*probe)(struct snd_soc_card *card); | 950 | int (*probe)(struct snd_soc_card *card); |
951 | int (*late_probe)(struct snd_soc_card *card); | 951 | int (*late_probe)(struct snd_soc_card *card); |
952 | int (*remove)(struct snd_soc_card *card); | 952 | int (*remove)(struct snd_soc_card *card); |
953 | 953 | ||
954 | /* the pre and post PM functions are used to do any PM work before and | 954 | /* the pre and post PM functions are used to do any PM work before and |
955 | * after the codec and DAI's do any PM work. */ | 955 | * after the codec and DAI's do any PM work. */ |
956 | int (*suspend_pre)(struct snd_soc_card *card); | 956 | int (*suspend_pre)(struct snd_soc_card *card); |
957 | int (*suspend_post)(struct snd_soc_card *card); | 957 | int (*suspend_post)(struct snd_soc_card *card); |
958 | int (*resume_pre)(struct snd_soc_card *card); | 958 | int (*resume_pre)(struct snd_soc_card *card); |
959 | int (*resume_post)(struct snd_soc_card *card); | 959 | int (*resume_post)(struct snd_soc_card *card); |
960 | 960 | ||
961 | /* callbacks */ | 961 | /* callbacks */ |
962 | int (*set_bias_level)(struct snd_soc_card *, | 962 | int (*set_bias_level)(struct snd_soc_card *, |
963 | struct snd_soc_dapm_context *dapm, | 963 | struct snd_soc_dapm_context *dapm, |
964 | enum snd_soc_bias_level level); | 964 | enum snd_soc_bias_level level); |
965 | int (*set_bias_level_post)(struct snd_soc_card *, | 965 | int (*set_bias_level_post)(struct snd_soc_card *, |
966 | struct snd_soc_dapm_context *dapm, | 966 | struct snd_soc_dapm_context *dapm, |
967 | enum snd_soc_bias_level level); | 967 | enum snd_soc_bias_level level); |
968 | 968 | ||
969 | long pmdown_time; | 969 | long pmdown_time; |
970 | 970 | ||
971 | /* CPU <--> Codec DAI links */ | 971 | /* CPU <--> Codec DAI links */ |
972 | struct snd_soc_dai_link *dai_link; | 972 | struct snd_soc_dai_link *dai_link; |
973 | int num_links; | 973 | int num_links; |
974 | struct snd_soc_pcm_runtime *rtd; | 974 | struct snd_soc_pcm_runtime *rtd; |
975 | int num_rtd; | 975 | int num_rtd; |
976 | 976 | ||
977 | /* optional codec specific configuration */ | 977 | /* optional codec specific configuration */ |
978 | struct snd_soc_codec_conf *codec_conf; | 978 | struct snd_soc_codec_conf *codec_conf; |
979 | int num_configs; | 979 | int num_configs; |
980 | 980 | ||
981 | /* | 981 | /* |
982 | * optional auxiliary devices such as amplifiers or codecs with DAI | 982 | * optional auxiliary devices such as amplifiers or codecs with DAI |
983 | * link unused | 983 | * link unused |
984 | */ | 984 | */ |
985 | struct snd_soc_aux_dev *aux_dev; | 985 | struct snd_soc_aux_dev *aux_dev; |
986 | int num_aux_devs; | 986 | int num_aux_devs; |
987 | struct snd_soc_pcm_runtime *rtd_aux; | 987 | struct snd_soc_pcm_runtime *rtd_aux; |
988 | int num_aux_rtd; | 988 | int num_aux_rtd; |
989 | 989 | ||
990 | const struct snd_kcontrol_new *controls; | 990 | const struct snd_kcontrol_new *controls; |
991 | int num_controls; | 991 | int num_controls; |
992 | 992 | ||
993 | /* | 993 | /* |
994 | * Card-specific routes and widgets. | 994 | * Card-specific routes and widgets. |
995 | */ | 995 | */ |
996 | const struct snd_soc_dapm_widget *dapm_widgets; | 996 | const struct snd_soc_dapm_widget *dapm_widgets; |
997 | int num_dapm_widgets; | 997 | int num_dapm_widgets; |
998 | const struct snd_soc_dapm_route *dapm_routes; | 998 | const struct snd_soc_dapm_route *dapm_routes; |
999 | int num_dapm_routes; | 999 | int num_dapm_routes; |
1000 | bool fully_routed; | 1000 | bool fully_routed; |
1001 | 1001 | ||
1002 | struct work_struct deferred_resume_work; | 1002 | struct work_struct deferred_resume_work; |
1003 | 1003 | ||
1004 | /* lists of probed devices belonging to this card */ | 1004 | /* lists of probed devices belonging to this card */ |
1005 | struct list_head codec_dev_list; | 1005 | struct list_head codec_dev_list; |
1006 | struct list_head platform_dev_list; | 1006 | struct list_head platform_dev_list; |
1007 | struct list_head dai_dev_list; | 1007 | struct list_head dai_dev_list; |
1008 | 1008 | ||
1009 | struct list_head widgets; | 1009 | struct list_head widgets; |
1010 | struct list_head paths; | 1010 | struct list_head paths; |
1011 | struct list_head dapm_list; | 1011 | struct list_head dapm_list; |
1012 | struct list_head dapm_dirty; | 1012 | struct list_head dapm_dirty; |
1013 | 1013 | ||
1014 | /* Generic DAPM context for the card */ | 1014 | /* Generic DAPM context for the card */ |
1015 | struct snd_soc_dapm_context dapm; | 1015 | struct snd_soc_dapm_context dapm; |
1016 | struct snd_soc_dapm_stats dapm_stats; | 1016 | struct snd_soc_dapm_stats dapm_stats; |
1017 | 1017 | ||
1018 | #ifdef CONFIG_DEBUG_FS | 1018 | #ifdef CONFIG_DEBUG_FS |
1019 | struct dentry *debugfs_card_root; | 1019 | struct dentry *debugfs_card_root; |
1020 | struct dentry *debugfs_pop_time; | 1020 | struct dentry *debugfs_pop_time; |
1021 | #endif | 1021 | #endif |
1022 | u32 pop_time; | 1022 | u32 pop_time; |
1023 | 1023 | ||
1024 | void *drvdata; | 1024 | void *drvdata; |
1025 | }; | 1025 | }; |
1026 | 1026 | ||
1027 | /* SoC machine DAI configuration, glues a codec and cpu DAI together */ | 1027 | /* SoC machine DAI configuration, glues a codec and cpu DAI together */ |
1028 | struct snd_soc_pcm_runtime { | 1028 | struct snd_soc_pcm_runtime { |
1029 | struct device *dev; | 1029 | struct device *dev; |
1030 | struct snd_soc_card *card; | 1030 | struct snd_soc_card *card; |
1031 | struct snd_soc_dai_link *dai_link; | 1031 | struct snd_soc_dai_link *dai_link; |
1032 | struct mutex pcm_mutex; | 1032 | struct mutex pcm_mutex; |
1033 | enum snd_soc_pcm_subclass pcm_subclass; | 1033 | enum snd_soc_pcm_subclass pcm_subclass; |
1034 | struct snd_pcm_ops ops; | 1034 | struct snd_pcm_ops ops; |
1035 | 1035 | ||
1036 | unsigned int dev_registered:1; | 1036 | unsigned int dev_registered:1; |
1037 | 1037 | ||
1038 | /* Dynamic PCM BE runtime data */ | 1038 | /* Dynamic PCM BE runtime data */ |
1039 | struct snd_soc_dpcm_runtime dpcm[2]; | 1039 | struct snd_soc_dpcm_runtime dpcm[2]; |
1040 | 1040 | ||
1041 | long pmdown_time; | 1041 | long pmdown_time; |
1042 | unsigned char pop_wait:1; | ||
1042 | 1043 | ||
1043 | /* runtime devices */ | 1044 | /* runtime devices */ |
1044 | struct snd_pcm *pcm; | 1045 | struct snd_pcm *pcm; |
1045 | struct snd_compr *compr; | 1046 | struct snd_compr *compr; |
1046 | struct snd_soc_codec *codec; | 1047 | struct snd_soc_codec *codec; |
1047 | struct snd_soc_platform *platform; | 1048 | struct snd_soc_platform *platform; |
1048 | struct snd_soc_dai *codec_dai; | 1049 | struct snd_soc_dai *codec_dai; |
1049 | struct snd_soc_dai *cpu_dai; | 1050 | struct snd_soc_dai *cpu_dai; |
1050 | 1051 | ||
1051 | struct delayed_work delayed_work; | 1052 | struct delayed_work delayed_work; |
1052 | #ifdef CONFIG_DEBUG_FS | 1053 | #ifdef CONFIG_DEBUG_FS |
1053 | struct dentry *debugfs_dpcm_root; | 1054 | struct dentry *debugfs_dpcm_root; |
1054 | struct dentry *debugfs_dpcm_state; | 1055 | struct dentry *debugfs_dpcm_state; |
1055 | #endif | 1056 | #endif |
1056 | }; | 1057 | }; |
1057 | 1058 | ||
1058 | /* mixer control */ | 1059 | /* mixer control */ |
1059 | struct soc_mixer_control { | 1060 | struct soc_mixer_control { |
1060 | int min, max, platform_max; | 1061 | int min, max, platform_max; |
1061 | unsigned int reg, rreg, shift, rshift, invert; | 1062 | unsigned int reg, rreg, shift, rshift, invert; |
1062 | }; | 1063 | }; |
1063 | 1064 | ||
1064 | struct soc_bytes { | 1065 | struct soc_bytes { |
1065 | int base; | 1066 | int base; |
1066 | int num_regs; | 1067 | int num_regs; |
1067 | u32 mask; | 1068 | u32 mask; |
1068 | }; | 1069 | }; |
1069 | 1070 | ||
1070 | /* multi register control */ | 1071 | /* multi register control */ |
1071 | struct soc_mreg_control { | 1072 | struct soc_mreg_control { |
1072 | long min, max; | 1073 | long min, max; |
1073 | unsigned int regbase, regcount, nbits, invert; | 1074 | unsigned int regbase, regcount, nbits, invert; |
1074 | }; | 1075 | }; |
1075 | 1076 | ||
1076 | /* enumerated kcontrol */ | 1077 | /* enumerated kcontrol */ |
1077 | struct soc_enum { | 1078 | struct soc_enum { |
1078 | unsigned short reg; | 1079 | unsigned short reg; |
1079 | unsigned short reg2; | 1080 | unsigned short reg2; |
1080 | unsigned char shift_l; | 1081 | unsigned char shift_l; |
1081 | unsigned char shift_r; | 1082 | unsigned char shift_r; |
1082 | unsigned int max; | 1083 | unsigned int max; |
1083 | unsigned int mask; | 1084 | unsigned int mask; |
1084 | const char * const *texts; | 1085 | const char * const *texts; |
1085 | const unsigned int *values; | 1086 | const unsigned int *values; |
1086 | void *dapm; | 1087 | void *dapm; |
1087 | }; | 1088 | }; |
1088 | 1089 | ||
1089 | /* codec IO */ | 1090 | /* codec IO */ |
1090 | unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); | 1091 | unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); |
1091 | unsigned int snd_soc_write(struct snd_soc_codec *codec, | 1092 | unsigned int snd_soc_write(struct snd_soc_codec *codec, |
1092 | unsigned int reg, unsigned int val); | 1093 | unsigned int reg, unsigned int val); |
1093 | unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, | 1094 | unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, |
1094 | unsigned int reg, const void *data, size_t len); | 1095 | unsigned int reg, const void *data, size_t len); |
1095 | 1096 | ||
1096 | /* device driver data */ | 1097 | /* device driver data */ |
1097 | 1098 | ||
1098 | static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, | 1099 | static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, |
1099 | void *data) | 1100 | void *data) |
1100 | { | 1101 | { |
1101 | card->drvdata = data; | 1102 | card->drvdata = data; |
1102 | } | 1103 | } |
1103 | 1104 | ||
1104 | static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) | 1105 | static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) |
1105 | { | 1106 | { |
1106 | return card->drvdata; | 1107 | return card->drvdata; |
1107 | } | 1108 | } |
1108 | 1109 | ||
1109 | static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec, | 1110 | static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec, |
1110 | void *data) | 1111 | void *data) |
1111 | { | 1112 | { |
1112 | dev_set_drvdata(codec->dev, data); | 1113 | dev_set_drvdata(codec->dev, data); |
1113 | } | 1114 | } |
1114 | 1115 | ||
1115 | static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec) | 1116 | static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec) |
1116 | { | 1117 | { |
1117 | return dev_get_drvdata(codec->dev); | 1118 | return dev_get_drvdata(codec->dev); |
1118 | } | 1119 | } |
1119 | 1120 | ||
1120 | static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform, | 1121 | static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform, |
1121 | void *data) | 1122 | void *data) |
1122 | { | 1123 | { |
1123 | dev_set_drvdata(platform->dev, data); | 1124 | dev_set_drvdata(platform->dev, data); |
1124 | } | 1125 | } |
1125 | 1126 | ||
1126 | static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform) | 1127 | static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform) |
1127 | { | 1128 | { |
1128 | return dev_get_drvdata(platform->dev); | 1129 | return dev_get_drvdata(platform->dev); |
1129 | } | 1130 | } |
1130 | 1131 | ||
1131 | static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd, | 1132 | static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd, |
1132 | void *data) | 1133 | void *data) |
1133 | { | 1134 | { |
1134 | dev_set_drvdata(rtd->dev, data); | 1135 | dev_set_drvdata(rtd->dev, data); |
1135 | } | 1136 | } |
1136 | 1137 | ||
1137 | static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd) | 1138 | static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd) |
1138 | { | 1139 | { |
1139 | return dev_get_drvdata(rtd->dev); | 1140 | return dev_get_drvdata(rtd->dev); |
1140 | } | 1141 | } |
1141 | 1142 | ||
1142 | static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) | 1143 | static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) |
1143 | { | 1144 | { |
1144 | INIT_LIST_HEAD(&card->dai_dev_list); | 1145 | INIT_LIST_HEAD(&card->dai_dev_list); |
1145 | INIT_LIST_HEAD(&card->codec_dev_list); | 1146 | INIT_LIST_HEAD(&card->codec_dev_list); |
1146 | INIT_LIST_HEAD(&card->platform_dev_list); | 1147 | INIT_LIST_HEAD(&card->platform_dev_list); |
1147 | INIT_LIST_HEAD(&card->widgets); | 1148 | INIT_LIST_HEAD(&card->widgets); |
1148 | INIT_LIST_HEAD(&card->paths); | 1149 | INIT_LIST_HEAD(&card->paths); |
1149 | INIT_LIST_HEAD(&card->dapm_list); | 1150 | INIT_LIST_HEAD(&card->dapm_list); |
1150 | } | 1151 | } |
1151 | 1152 | ||
1152 | static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) | 1153 | static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) |
1153 | { | 1154 | { |
1154 | if (mc->reg == mc->rreg && mc->shift == mc->rshift) | 1155 | if (mc->reg == mc->rreg && mc->shift == mc->rshift) |
1155 | return 0; | 1156 | return 0; |
1156 | /* | 1157 | /* |
1157 | * mc->reg == mc->rreg && mc->shift != mc->rshift, or | 1158 | * mc->reg == mc->rreg && mc->shift != mc->rshift, or |
1158 | * mc->reg != mc->rreg means that the control is | 1159 | * mc->reg != mc->rreg means that the control is |
1159 | * stereo (bits in one register or in two registers) | 1160 | * stereo (bits in one register or in two registers) |
1160 | */ | 1161 | */ |
1161 | return 1; | 1162 | return 1; |
1162 | } | 1163 | } |
1163 | 1164 | ||
1164 | int snd_soc_util_init(void); | 1165 | int snd_soc_util_init(void); |
1165 | void snd_soc_util_exit(void); | 1166 | void snd_soc_util_exit(void); |
1166 | 1167 | ||
1167 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, | 1168 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, |
1168 | const char *propname); | 1169 | const char *propname); |
1169 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | 1170 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
1170 | const char *propname); | 1171 | const char *propname); |
1171 | 1172 | ||
1172 | #include <sound/soc-dai.h> | 1173 | #include <sound/soc-dai.h> |
1173 | 1174 | ||
1174 | #ifdef CONFIG_DEBUG_FS | 1175 | #ifdef CONFIG_DEBUG_FS |
1175 | extern struct dentry *snd_soc_debugfs_root; | 1176 | extern struct dentry *snd_soc_debugfs_root; |
1176 | #endif | 1177 | #endif |
1177 | 1178 | ||
1178 | extern const struct dev_pm_ops snd_soc_pm_ops; | 1179 | extern const struct dev_pm_ops snd_soc_pm_ops; |
1179 | 1180 | ||
1180 | #endif | 1181 | #endif |
1181 | 1182 |
sound/soc/soc-compress.c
1 | /* | 1 | /* |
2 | * soc-compress.c -- ALSA SoC Compress | 2 | * soc-compress.c -- ALSA SoC Compress |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Intel Corp. | 4 | * Copyright (C) 2012 Intel Corp. |
5 | * | 5 | * |
6 | * Authors: Namarta Kohli <namartax.kohli@intel.com> | 6 | * Authors: Namarta Kohli <namartax.kohli@intel.com> |
7 | * Ramesh Babu K V <ramesh.babu@linux.intel.com> | 7 | * Ramesh Babu K V <ramesh.babu@linux.intel.com> |
8 | * Vinod Koul <vinod.koul@linux.intel.com> | 8 | * Vinod Koul <vinod.koul@linux.intel.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/compress_params.h> | 23 | #include <sound/compress_params.h> |
24 | #include <sound/compress_driver.h> | 24 | #include <sound/compress_driver.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
27 | 27 | ||
28 | static int soc_compr_open(struct snd_compr_stream *cstream) | 28 | static int soc_compr_open(struct snd_compr_stream *cstream) |
29 | { | 29 | { |
30 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 30 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
31 | struct snd_soc_platform *platform = rtd->platform; | 31 | struct snd_soc_platform *platform = rtd->platform; |
32 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 32 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
33 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 33 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
34 | int ret = 0; | 34 | int ret = 0; |
35 | 35 | ||
36 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { | 36 | if (platform->driver->compr_ops && platform->driver->compr_ops->open) { |
37 | ret = platform->driver->compr_ops->open(cstream); | 37 | ret = platform->driver->compr_ops->open(cstream); |
38 | if (ret < 0) { | 38 | if (ret < 0) { |
39 | pr_err("compress asoc: can't open platform %s\n", platform->name); | 39 | pr_err("compress asoc: can't open platform %s\n", platform->name); |
40 | goto out; | 40 | goto out; |
41 | } | 41 | } |
42 | } | 42 | } |
43 | 43 | ||
44 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { | 44 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { |
45 | ret = rtd->dai_link->compr_ops->startup(cstream); | 45 | ret = rtd->dai_link->compr_ops->startup(cstream); |
46 | if (ret < 0) { | 46 | if (ret < 0) { |
47 | pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name); | 47 | pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name); |
48 | goto machine_err; | 48 | goto machine_err; |
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 52 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
53 | cpu_dai->playback_active++; | 53 | cpu_dai->playback_active++; |
54 | codec_dai->playback_active++; | 54 | codec_dai->playback_active++; |
55 | } else { | 55 | } else { |
56 | cpu_dai->capture_active++; | 56 | cpu_dai->capture_active++; |
57 | codec_dai->capture_active++; | 57 | codec_dai->capture_active++; |
58 | } | 58 | } |
59 | 59 | ||
60 | cpu_dai->active++; | 60 | cpu_dai->active++; |
61 | codec_dai->active++; | 61 | codec_dai->active++; |
62 | rtd->codec->active++; | 62 | rtd->codec->active++; |
63 | 63 | ||
64 | return 0; | 64 | return 0; |
65 | 65 | ||
66 | machine_err: | 66 | machine_err: |
67 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) | 67 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) |
68 | platform->driver->compr_ops->free(cstream); | 68 | platform->driver->compr_ops->free(cstream); |
69 | out: | 69 | out: |
70 | return ret; | 70 | return ret; |
71 | } | 71 | } |
72 | 72 | ||
73 | static int soc_compr_free(struct snd_compr_stream *cstream) | 73 | static int soc_compr_free(struct snd_compr_stream *cstream) |
74 | { | 74 | { |
75 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 75 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
76 | struct snd_soc_platform *platform = rtd->platform; | 76 | struct snd_soc_platform *platform = rtd->platform; |
77 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 77 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
78 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 78 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
79 | struct snd_soc_codec *codec = rtd->codec; | 79 | struct snd_soc_codec *codec = rtd->codec; |
80 | 80 | ||
81 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 81 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
82 | cpu_dai->playback_active--; | 82 | cpu_dai->playback_active--; |
83 | codec_dai->playback_active--; | 83 | codec_dai->playback_active--; |
84 | } else { | 84 | } else { |
85 | cpu_dai->capture_active--; | 85 | cpu_dai->capture_active--; |
86 | codec_dai->capture_active--; | 86 | codec_dai->capture_active--; |
87 | } | 87 | } |
88 | 88 | ||
89 | snd_soc_dai_digital_mute(codec_dai, 1); | 89 | snd_soc_dai_digital_mute(codec_dai, 1); |
90 | 90 | ||
91 | cpu_dai->active--; | 91 | cpu_dai->active--; |
92 | codec_dai->active--; | 92 | codec_dai->active--; |
93 | codec->active--; | 93 | codec->active--; |
94 | 94 | ||
95 | if (!cpu_dai->active) | 95 | if (!cpu_dai->active) |
96 | cpu_dai->rate = 0; | 96 | cpu_dai->rate = 0; |
97 | 97 | ||
98 | if (!codec_dai->active) | 98 | if (!codec_dai->active) |
99 | codec_dai->rate = 0; | 99 | codec_dai->rate = 0; |
100 | 100 | ||
101 | 101 | ||
102 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) | 102 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) |
103 | rtd->dai_link->compr_ops->shutdown(cstream); | 103 | rtd->dai_link->compr_ops->shutdown(cstream); |
104 | 104 | ||
105 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) | 105 | if (platform->driver->compr_ops && platform->driver->compr_ops->free) |
106 | platform->driver->compr_ops->free(cstream); | 106 | platform->driver->compr_ops->free(cstream); |
107 | cpu_dai->runtime = NULL; | 107 | cpu_dai->runtime = NULL; |
108 | 108 | ||
109 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 109 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
110 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 110 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || |
111 | rtd->dai_link->ignore_pmdown_time) { | 111 | rtd->dai_link->ignore_pmdown_time) { |
112 | snd_soc_dapm_stream_event(rtd, | 112 | snd_soc_dapm_stream_event(rtd, |
113 | SNDRV_PCM_STREAM_PLAYBACK, | 113 | SNDRV_PCM_STREAM_PLAYBACK, |
114 | SND_SOC_DAPM_STREAM_STOP); | 114 | SND_SOC_DAPM_STREAM_STOP); |
115 | } else | 115 | } else |
116 | codec_dai->pop_wait = 1; | 116 | rtd->pop_wait = 1; |
117 | schedule_delayed_work(&rtd->delayed_work, | 117 | schedule_delayed_work(&rtd->delayed_work, |
118 | msecs_to_jiffies(rtd->pmdown_time)); | 118 | msecs_to_jiffies(rtd->pmdown_time)); |
119 | } else { | 119 | } else { |
120 | /* capture streams can be powered down now */ | 120 | /* capture streams can be powered down now */ |
121 | snd_soc_dapm_stream_event(rtd, | 121 | snd_soc_dapm_stream_event(rtd, |
122 | SNDRV_PCM_STREAM_CAPTURE, | 122 | SNDRV_PCM_STREAM_CAPTURE, |
123 | SND_SOC_DAPM_STREAM_STOP); | 123 | SND_SOC_DAPM_STREAM_STOP); |
124 | } | 124 | } |
125 | 125 | ||
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) | 129 | static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) |
130 | { | 130 | { |
131 | 131 | ||
132 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 132 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
133 | struct snd_soc_platform *platform = rtd->platform; | 133 | struct snd_soc_platform *platform = rtd->platform; |
134 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 134 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
135 | int ret = 0; | 135 | int ret = 0; |
136 | 136 | ||
137 | if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { | 137 | if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { |
138 | ret = platform->driver->compr_ops->trigger(cstream, cmd); | 138 | ret = platform->driver->compr_ops->trigger(cstream, cmd); |
139 | if (ret < 0) | 139 | if (ret < 0) |
140 | return ret; | 140 | return ret; |
141 | } | 141 | } |
142 | 142 | ||
143 | if (cmd == SNDRV_PCM_TRIGGER_START) | 143 | if (cmd == SNDRV_PCM_TRIGGER_START) |
144 | snd_soc_dai_digital_mute(codec_dai, 0); | 144 | snd_soc_dai_digital_mute(codec_dai, 0); |
145 | else if (cmd == SNDRV_PCM_TRIGGER_STOP) | 145 | else if (cmd == SNDRV_PCM_TRIGGER_STOP) |
146 | snd_soc_dai_digital_mute(codec_dai, 1); | 146 | snd_soc_dai_digital_mute(codec_dai, 1); |
147 | 147 | ||
148 | return ret; | 148 | return ret; |
149 | } | 149 | } |
150 | 150 | ||
151 | static int soc_compr_set_params(struct snd_compr_stream *cstream, | 151 | static int soc_compr_set_params(struct snd_compr_stream *cstream, |
152 | struct snd_compr_params *params) | 152 | struct snd_compr_params *params) |
153 | { | 153 | { |
154 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 154 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
155 | struct snd_soc_platform *platform = rtd->platform; | 155 | struct snd_soc_platform *platform = rtd->platform; |
156 | int ret = 0; | 156 | int ret = 0; |
157 | 157 | ||
158 | /* first we call set_params for the platform driver | 158 | /* first we call set_params for the platform driver |
159 | * this should configure the soc side | 159 | * this should configure the soc side |
160 | * if the machine has compressed ops then we call that as well | 160 | * if the machine has compressed ops then we call that as well |
161 | * expectation is that platform and machine will configure everything | 161 | * expectation is that platform and machine will configure everything |
162 | * for this compress path, like configuring pcm port for codec | 162 | * for this compress path, like configuring pcm port for codec |
163 | */ | 163 | */ |
164 | if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { | 164 | if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { |
165 | ret = platform->driver->compr_ops->set_params(cstream, params); | 165 | ret = platform->driver->compr_ops->set_params(cstream, params); |
166 | if (ret < 0) | 166 | if (ret < 0) |
167 | return ret; | 167 | return ret; |
168 | } | 168 | } |
169 | 169 | ||
170 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { | 170 | if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { |
171 | ret = rtd->dai_link->compr_ops->set_params(cstream); | 171 | ret = rtd->dai_link->compr_ops->set_params(cstream); |
172 | if (ret < 0) | 172 | if (ret < 0) |
173 | return ret; | 173 | return ret; |
174 | } | 174 | } |
175 | 175 | ||
176 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, | 176 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, |
177 | SND_SOC_DAPM_STREAM_START); | 177 | SND_SOC_DAPM_STREAM_START); |
178 | 178 | ||
179 | return ret; | 179 | return ret; |
180 | } | 180 | } |
181 | 181 | ||
182 | static int soc_compr_get_params(struct snd_compr_stream *cstream, | 182 | static int soc_compr_get_params(struct snd_compr_stream *cstream, |
183 | struct snd_codec *params) | 183 | struct snd_codec *params) |
184 | { | 184 | { |
185 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 185 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
186 | struct snd_soc_platform *platform = rtd->platform; | 186 | struct snd_soc_platform *platform = rtd->platform; |
187 | int ret = 0; | 187 | int ret = 0; |
188 | 188 | ||
189 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) | 189 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) |
190 | ret = platform->driver->compr_ops->get_params(cstream, params); | 190 | ret = platform->driver->compr_ops->get_params(cstream, params); |
191 | 191 | ||
192 | return ret; | 192 | return ret; |
193 | } | 193 | } |
194 | 194 | ||
195 | static int soc_compr_get_caps(struct snd_compr_stream *cstream, | 195 | static int soc_compr_get_caps(struct snd_compr_stream *cstream, |
196 | struct snd_compr_caps *caps) | 196 | struct snd_compr_caps *caps) |
197 | { | 197 | { |
198 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 198 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
199 | struct snd_soc_platform *platform = rtd->platform; | 199 | struct snd_soc_platform *platform = rtd->platform; |
200 | int ret = 0; | 200 | int ret = 0; |
201 | 201 | ||
202 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) | 202 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) |
203 | ret = platform->driver->compr_ops->get_caps(cstream, caps); | 203 | ret = platform->driver->compr_ops->get_caps(cstream, caps); |
204 | 204 | ||
205 | return ret; | 205 | return ret; |
206 | } | 206 | } |
207 | 207 | ||
208 | static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, | 208 | static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, |
209 | struct snd_compr_codec_caps *codec) | 209 | struct snd_compr_codec_caps *codec) |
210 | { | 210 | { |
211 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 211 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
212 | struct snd_soc_platform *platform = rtd->platform; | 212 | struct snd_soc_platform *platform = rtd->platform; |
213 | int ret = 0; | 213 | int ret = 0; |
214 | 214 | ||
215 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) | 215 | if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) |
216 | ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); | 216 | ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); |
217 | 217 | ||
218 | return ret; | 218 | return ret; |
219 | } | 219 | } |
220 | 220 | ||
221 | static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) | 221 | static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) |
222 | { | 222 | { |
223 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 223 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
224 | struct snd_soc_platform *platform = rtd->platform; | 224 | struct snd_soc_platform *platform = rtd->platform; |
225 | int ret = 0; | 225 | int ret = 0; |
226 | 226 | ||
227 | if (platform->driver->compr_ops && platform->driver->compr_ops->ack) | 227 | if (platform->driver->compr_ops && platform->driver->compr_ops->ack) |
228 | ret = platform->driver->compr_ops->ack(cstream, bytes); | 228 | ret = platform->driver->compr_ops->ack(cstream, bytes); |
229 | 229 | ||
230 | return ret; | 230 | return ret; |
231 | } | 231 | } |
232 | 232 | ||
233 | static int soc_compr_pointer(struct snd_compr_stream *cstream, | 233 | static int soc_compr_pointer(struct snd_compr_stream *cstream, |
234 | struct snd_compr_tstamp *tstamp) | 234 | struct snd_compr_tstamp *tstamp) |
235 | { | 235 | { |
236 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 236 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
237 | struct snd_soc_platform *platform = rtd->platform; | 237 | struct snd_soc_platform *platform = rtd->platform; |
238 | 238 | ||
239 | if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) | 239 | if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) |
240 | platform->driver->compr_ops->pointer(cstream, tstamp); | 240 | platform->driver->compr_ops->pointer(cstream, tstamp); |
241 | 241 | ||
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* ASoC Compress operations */ | 245 | /* ASoC Compress operations */ |
246 | static struct snd_compr_ops soc_compr_ops = { | 246 | static struct snd_compr_ops soc_compr_ops = { |
247 | .open = soc_compr_open, | 247 | .open = soc_compr_open, |
248 | .free = soc_compr_free, | 248 | .free = soc_compr_free, |
249 | .set_params = soc_compr_set_params, | 249 | .set_params = soc_compr_set_params, |
250 | .get_params = soc_compr_get_params, | 250 | .get_params = soc_compr_get_params, |
251 | .trigger = soc_compr_trigger, | 251 | .trigger = soc_compr_trigger, |
252 | .pointer = soc_compr_pointer, | 252 | .pointer = soc_compr_pointer, |
253 | .ack = soc_compr_ack, | 253 | .ack = soc_compr_ack, |
254 | .get_caps = soc_compr_get_caps, | 254 | .get_caps = soc_compr_get_caps, |
255 | .get_codec_caps = soc_compr_get_codec_caps | 255 | .get_codec_caps = soc_compr_get_codec_caps |
256 | }; | 256 | }; |
257 | 257 | ||
258 | /* create a new compress */ | 258 | /* create a new compress */ |
259 | int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) | 259 | int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) |
260 | { | 260 | { |
261 | struct snd_soc_codec *codec = rtd->codec; | 261 | struct snd_soc_codec *codec = rtd->codec; |
262 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 262 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
263 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 263 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
264 | struct snd_compr *compr; | 264 | struct snd_compr *compr; |
265 | char new_name[64]; | 265 | char new_name[64]; |
266 | int ret = 0, direction = 0; | 266 | int ret = 0, direction = 0; |
267 | 267 | ||
268 | /* check client and interface hw capabilities */ | 268 | /* check client and interface hw capabilities */ |
269 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 269 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
270 | rtd->dai_link->stream_name, codec_dai->name, num); | 270 | rtd->dai_link->stream_name, codec_dai->name, num); |
271 | direction = SND_COMPRESS_PLAYBACK; | 271 | direction = SND_COMPRESS_PLAYBACK; |
272 | compr = kzalloc(sizeof(*compr), GFP_KERNEL); | 272 | compr = kzalloc(sizeof(*compr), GFP_KERNEL); |
273 | if (compr == NULL) { | 273 | if (compr == NULL) { |
274 | snd_printk(KERN_ERR "Cannot allocate compr\n"); | 274 | snd_printk(KERN_ERR "Cannot allocate compr\n"); |
275 | return -ENOMEM; | 275 | return -ENOMEM; |
276 | } | 276 | } |
277 | 277 | ||
278 | compr->ops = &soc_compr_ops; | 278 | compr->ops = &soc_compr_ops; |
279 | mutex_init(&compr->lock); | 279 | mutex_init(&compr->lock); |
280 | ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); | 280 | ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); |
281 | if (ret < 0) { | 281 | if (ret < 0) { |
282 | pr_err("compress asoc: can't create compress for codec %s\n", | 282 | pr_err("compress asoc: can't create compress for codec %s\n", |
283 | codec->name); | 283 | codec->name); |
284 | kfree(compr); | 284 | kfree(compr); |
285 | return ret; | 285 | return ret; |
286 | } | 286 | } |
287 | 287 | ||
288 | rtd->compr = compr; | 288 | rtd->compr = compr; |
289 | compr->private_data = rtd; | 289 | compr->private_data = rtd; |
290 | 290 | ||
291 | printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, | 291 | printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, |
292 | cpu_dai->name); | 292 | cpu_dai->name); |
293 | return ret; | 293 | return ret; |
294 | } | 294 | } |
295 | 295 |
sound/soc/soc-pcm.c
1 | /* | 1 | /* |
2 | * soc-pcm.c -- ALSA SoC PCM | 2 | * soc-pcm.c -- ALSA SoC PCM |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * Copyright (C) 2010 Slimlogic Ltd. | 6 | * Copyright (C) 2010 Slimlogic Ltd. |
7 | * Copyright (C) 2010 Texas Instruments Inc. | 7 | * Copyright (C) 2010 Texas Instruments Inc. |
8 | * | 8 | * |
9 | * Authors: Liam Girdwood <lrg@ti.com> | 9 | * Authors: Liam Girdwood <lrg@ti.com> |
10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | 10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
14 | * Free Software Foundation; either version 2 of the License, or (at your | 14 | * Free Software Foundation; either version 2 of the License, or (at your |
15 | * option) any later version. | 15 | * option) any later version. |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/export.h> | 25 | #include <linux/export.h> |
26 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
27 | #include <sound/core.h> | 27 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 29 | #include <sound/pcm_params.h> |
30 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
31 | #include <sound/soc-dpcm.h> | 31 | #include <sound/soc-dpcm.h> |
32 | #include <sound/initval.h> | 32 | #include <sound/initval.h> |
33 | 33 | ||
34 | #define DPCM_MAX_BE_USERS 8 | 34 | #define DPCM_MAX_BE_USERS 8 |
35 | 35 | ||
36 | /* DPCM stream event, send event to FE and all active BEs. */ | 36 | /* DPCM stream event, send event to FE and all active BEs. */ |
37 | static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, | 37 | static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, |
38 | int event) | 38 | int event) |
39 | { | 39 | { |
40 | struct snd_soc_dpcm *dpcm; | 40 | struct snd_soc_dpcm *dpcm; |
41 | 41 | ||
42 | list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { | 42 | list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { |
43 | 43 | ||
44 | struct snd_soc_pcm_runtime *be = dpcm->be; | 44 | struct snd_soc_pcm_runtime *be = dpcm->be; |
45 | 45 | ||
46 | dev_dbg(be->dev, "pm: BE %s event %d dir %d\n", | 46 | dev_dbg(be->dev, "pm: BE %s event %d dir %d\n", |
47 | be->dai_link->name, event, dir); | 47 | be->dai_link->name, event, dir); |
48 | 48 | ||
49 | snd_soc_dapm_stream_event(be, dir, event); | 49 | snd_soc_dapm_stream_event(be, dir, event); |
50 | } | 50 | } |
51 | 51 | ||
52 | snd_soc_dapm_stream_event(fe, dir, event); | 52 | snd_soc_dapm_stream_event(fe, dir, event); |
53 | 53 | ||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, | 57 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, |
58 | struct snd_soc_dai *soc_dai) | 58 | struct snd_soc_dai *soc_dai) |
59 | { | 59 | { |
60 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 60 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
61 | int ret; | 61 | int ret; |
62 | 62 | ||
63 | if (!soc_dai->driver->symmetric_rates && | 63 | if (!soc_dai->driver->symmetric_rates && |
64 | !rtd->dai_link->symmetric_rates) | 64 | !rtd->dai_link->symmetric_rates) |
65 | return 0; | 65 | return 0; |
66 | 66 | ||
67 | /* This can happen if multiple streams are starting simultaneously - | 67 | /* This can happen if multiple streams are starting simultaneously - |
68 | * the second can need to get its constraints before the first has | 68 | * the second can need to get its constraints before the first has |
69 | * picked a rate. Complain and allow the application to carry on. | 69 | * picked a rate. Complain and allow the application to carry on. |
70 | */ | 70 | */ |
71 | if (!soc_dai->rate) { | 71 | if (!soc_dai->rate) { |
72 | dev_warn(soc_dai->dev, | 72 | dev_warn(soc_dai->dev, |
73 | "Not enforcing symmetric_rates due to race\n"); | 73 | "Not enforcing symmetric_rates due to race\n"); |
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate); | 77 | dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate); |
78 | 78 | ||
79 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | 79 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, |
80 | SNDRV_PCM_HW_PARAM_RATE, | 80 | SNDRV_PCM_HW_PARAM_RATE, |
81 | soc_dai->rate, soc_dai->rate); | 81 | soc_dai->rate, soc_dai->rate); |
82 | if (ret < 0) { | 82 | if (ret < 0) { |
83 | dev_err(soc_dai->dev, | 83 | dev_err(soc_dai->dev, |
84 | "Unable to apply rate symmetry constraint: %d\n", ret); | 84 | "Unable to apply rate symmetry constraint: %d\n", ret); |
85 | return ret; | 85 | return ret; |
86 | } | 86 | } |
87 | 87 | ||
88 | return 0; | 88 | return 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * List of sample sizes that might go over the bus for parameter | 92 | * List of sample sizes that might go over the bus for parameter |
93 | * application. There ought to be a wildcard sample size for things | 93 | * application. There ought to be a wildcard sample size for things |
94 | * like the DAC/ADC resolution to use but there isn't right now. | 94 | * like the DAC/ADC resolution to use but there isn't right now. |
95 | */ | 95 | */ |
96 | static int sample_sizes[] = { | 96 | static int sample_sizes[] = { |
97 | 24, 32, | 97 | 24, 32, |
98 | }; | 98 | }; |
99 | 99 | ||
100 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, | 100 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, |
101 | struct snd_soc_dai *dai) | 101 | struct snd_soc_dai *dai) |
102 | { | 102 | { |
103 | int ret, i, bits; | 103 | int ret, i, bits; |
104 | 104 | ||
105 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 105 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
106 | bits = dai->driver->playback.sig_bits; | 106 | bits = dai->driver->playback.sig_bits; |
107 | else | 107 | else |
108 | bits = dai->driver->capture.sig_bits; | 108 | bits = dai->driver->capture.sig_bits; |
109 | 109 | ||
110 | if (!bits) | 110 | if (!bits) |
111 | return; | 111 | return; |
112 | 112 | ||
113 | for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { | 113 | for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { |
114 | if (bits >= sample_sizes[i]) | 114 | if (bits >= sample_sizes[i]) |
115 | continue; | 115 | continue; |
116 | 116 | ||
117 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, | 117 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, |
118 | sample_sizes[i], bits); | 118 | sample_sizes[i], bits); |
119 | if (ret != 0) | 119 | if (ret != 0) |
120 | dev_warn(dai->dev, | 120 | dev_warn(dai->dev, |
121 | "Failed to set MSB %d/%d: %d\n", | 121 | "Failed to set MSB %d/%d: %d\n", |
122 | bits, sample_sizes[i], ret); | 122 | bits, sample_sizes[i], ret); |
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | 127 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is |
128 | * then initialized and any private data can be allocated. This also calls | 128 | * then initialized and any private data can be allocated. This also calls |
129 | * startup for the cpu DAI, platform, machine and codec DAI. | 129 | * startup for the cpu DAI, platform, machine and codec DAI. |
130 | */ | 130 | */ |
131 | static int soc_pcm_open(struct snd_pcm_substream *substream) | 131 | static int soc_pcm_open(struct snd_pcm_substream *substream) |
132 | { | 132 | { |
133 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 133 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
134 | struct snd_pcm_runtime *runtime = substream->runtime; | 134 | struct snd_pcm_runtime *runtime = substream->runtime; |
135 | struct snd_soc_platform *platform = rtd->platform; | 135 | struct snd_soc_platform *platform = rtd->platform; |
136 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 136 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
137 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 137 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
138 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 138 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; |
139 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | 139 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; |
140 | int ret = 0; | 140 | int ret = 0; |
141 | 141 | ||
142 | pm_runtime_get_sync(cpu_dai->dev); | 142 | pm_runtime_get_sync(cpu_dai->dev); |
143 | pm_runtime_get_sync(codec_dai->dev); | 143 | pm_runtime_get_sync(codec_dai->dev); |
144 | pm_runtime_get_sync(platform->dev); | 144 | pm_runtime_get_sync(platform->dev); |
145 | 145 | ||
146 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 146 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
147 | 147 | ||
148 | /* startup the audio subsystem */ | 148 | /* startup the audio subsystem */ |
149 | if (cpu_dai->driver->ops->startup) { | 149 | if (cpu_dai->driver->ops->startup) { |
150 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); | 150 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); |
151 | if (ret < 0) { | 151 | if (ret < 0) { |
152 | dev_err(cpu_dai->dev, "can't open interface %s: %d\n", | 152 | dev_err(cpu_dai->dev, "can't open interface %s: %d\n", |
153 | cpu_dai->name, ret); | 153 | cpu_dai->name, ret); |
154 | goto out; | 154 | goto out; |
155 | } | 155 | } |
156 | } | 156 | } |
157 | 157 | ||
158 | if (platform->driver->ops && platform->driver->ops->open) { | 158 | if (platform->driver->ops && platform->driver->ops->open) { |
159 | ret = platform->driver->ops->open(substream); | 159 | ret = platform->driver->ops->open(substream); |
160 | if (ret < 0) { | 160 | if (ret < 0) { |
161 | dev_err(platform->dev, "can't open platform %s: %d\n", | 161 | dev_err(platform->dev, "can't open platform %s: %d\n", |
162 | platform->name, ret); | 162 | platform->name, ret); |
163 | goto platform_err; | 163 | goto platform_err; |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | if (codec_dai->driver->ops->startup) { | 167 | if (codec_dai->driver->ops->startup) { |
168 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | 168 | ret = codec_dai->driver->ops->startup(substream, codec_dai); |
169 | if (ret < 0) { | 169 | if (ret < 0) { |
170 | dev_err(codec_dai->dev, "can't open codec %s: %d\n", | 170 | dev_err(codec_dai->dev, "can't open codec %s: %d\n", |
171 | codec_dai->name, ret); | 171 | codec_dai->name, ret); |
172 | goto codec_dai_err; | 172 | goto codec_dai_err; |
173 | } | 173 | } |
174 | } | 174 | } |
175 | 175 | ||
176 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | 176 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { |
177 | ret = rtd->dai_link->ops->startup(substream); | 177 | ret = rtd->dai_link->ops->startup(substream); |
178 | if (ret < 0) { | 178 | if (ret < 0) { |
179 | pr_err("asoc: %s startup failed: %d\n", | 179 | pr_err("asoc: %s startup failed: %d\n", |
180 | rtd->dai_link->name, ret); | 180 | rtd->dai_link->name, ret); |
181 | goto machine_err; | 181 | goto machine_err; |
182 | } | 182 | } |
183 | } | 183 | } |
184 | 184 | ||
185 | /* Dynamic PCM DAI links compat checks use dynamic capabilities */ | 185 | /* Dynamic PCM DAI links compat checks use dynamic capabilities */ |
186 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) | 186 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) |
187 | goto dynamic; | 187 | goto dynamic; |
188 | 188 | ||
189 | /* Check that the codec and cpu DAIs are compatible */ | 189 | /* Check that the codec and cpu DAIs are compatible */ |
190 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 190 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
191 | runtime->hw.rate_min = | 191 | runtime->hw.rate_min = |
192 | max(codec_dai_drv->playback.rate_min, | 192 | max(codec_dai_drv->playback.rate_min, |
193 | cpu_dai_drv->playback.rate_min); | 193 | cpu_dai_drv->playback.rate_min); |
194 | runtime->hw.rate_max = | 194 | runtime->hw.rate_max = |
195 | min(codec_dai_drv->playback.rate_max, | 195 | min(codec_dai_drv->playback.rate_max, |
196 | cpu_dai_drv->playback.rate_max); | 196 | cpu_dai_drv->playback.rate_max); |
197 | runtime->hw.channels_min = | 197 | runtime->hw.channels_min = |
198 | max(codec_dai_drv->playback.channels_min, | 198 | max(codec_dai_drv->playback.channels_min, |
199 | cpu_dai_drv->playback.channels_min); | 199 | cpu_dai_drv->playback.channels_min); |
200 | runtime->hw.channels_max = | 200 | runtime->hw.channels_max = |
201 | min(codec_dai_drv->playback.channels_max, | 201 | min(codec_dai_drv->playback.channels_max, |
202 | cpu_dai_drv->playback.channels_max); | 202 | cpu_dai_drv->playback.channels_max); |
203 | runtime->hw.formats = | 203 | runtime->hw.formats = |
204 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; | 204 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; |
205 | runtime->hw.rates = | 205 | runtime->hw.rates = |
206 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; | 206 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; |
207 | if (codec_dai_drv->playback.rates | 207 | if (codec_dai_drv->playback.rates |
208 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 208 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
209 | runtime->hw.rates |= cpu_dai_drv->playback.rates; | 209 | runtime->hw.rates |= cpu_dai_drv->playback.rates; |
210 | if (cpu_dai_drv->playback.rates | 210 | if (cpu_dai_drv->playback.rates |
211 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 211 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
212 | runtime->hw.rates |= codec_dai_drv->playback.rates; | 212 | runtime->hw.rates |= codec_dai_drv->playback.rates; |
213 | } else { | 213 | } else { |
214 | runtime->hw.rate_min = | 214 | runtime->hw.rate_min = |
215 | max(codec_dai_drv->capture.rate_min, | 215 | max(codec_dai_drv->capture.rate_min, |
216 | cpu_dai_drv->capture.rate_min); | 216 | cpu_dai_drv->capture.rate_min); |
217 | runtime->hw.rate_max = | 217 | runtime->hw.rate_max = |
218 | min(codec_dai_drv->capture.rate_max, | 218 | min(codec_dai_drv->capture.rate_max, |
219 | cpu_dai_drv->capture.rate_max); | 219 | cpu_dai_drv->capture.rate_max); |
220 | runtime->hw.channels_min = | 220 | runtime->hw.channels_min = |
221 | max(codec_dai_drv->capture.channels_min, | 221 | max(codec_dai_drv->capture.channels_min, |
222 | cpu_dai_drv->capture.channels_min); | 222 | cpu_dai_drv->capture.channels_min); |
223 | runtime->hw.channels_max = | 223 | runtime->hw.channels_max = |
224 | min(codec_dai_drv->capture.channels_max, | 224 | min(codec_dai_drv->capture.channels_max, |
225 | cpu_dai_drv->capture.channels_max); | 225 | cpu_dai_drv->capture.channels_max); |
226 | runtime->hw.formats = | 226 | runtime->hw.formats = |
227 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; | 227 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; |
228 | runtime->hw.rates = | 228 | runtime->hw.rates = |
229 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; | 229 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; |
230 | if (codec_dai_drv->capture.rates | 230 | if (codec_dai_drv->capture.rates |
231 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 231 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
232 | runtime->hw.rates |= cpu_dai_drv->capture.rates; | 232 | runtime->hw.rates |= cpu_dai_drv->capture.rates; |
233 | if (cpu_dai_drv->capture.rates | 233 | if (cpu_dai_drv->capture.rates |
234 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | 234 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) |
235 | runtime->hw.rates |= codec_dai_drv->capture.rates; | 235 | runtime->hw.rates |= codec_dai_drv->capture.rates; |
236 | } | 236 | } |
237 | 237 | ||
238 | ret = -EINVAL; | 238 | ret = -EINVAL; |
239 | snd_pcm_limit_hw_rates(runtime); | 239 | snd_pcm_limit_hw_rates(runtime); |
240 | if (!runtime->hw.rates) { | 240 | if (!runtime->hw.rates) { |
241 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | 241 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", |
242 | codec_dai->name, cpu_dai->name); | 242 | codec_dai->name, cpu_dai->name); |
243 | goto config_err; | 243 | goto config_err; |
244 | } | 244 | } |
245 | if (!runtime->hw.formats) { | 245 | if (!runtime->hw.formats) { |
246 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | 246 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", |
247 | codec_dai->name, cpu_dai->name); | 247 | codec_dai->name, cpu_dai->name); |
248 | goto config_err; | 248 | goto config_err; |
249 | } | 249 | } |
250 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | 250 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || |
251 | runtime->hw.channels_min > runtime->hw.channels_max) { | 251 | runtime->hw.channels_min > runtime->hw.channels_max) { |
252 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | 252 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", |
253 | codec_dai->name, cpu_dai->name); | 253 | codec_dai->name, cpu_dai->name); |
254 | goto config_err; | 254 | goto config_err; |
255 | } | 255 | } |
256 | 256 | ||
257 | soc_pcm_apply_msb(substream, codec_dai); | 257 | soc_pcm_apply_msb(substream, codec_dai); |
258 | soc_pcm_apply_msb(substream, cpu_dai); | 258 | soc_pcm_apply_msb(substream, cpu_dai); |
259 | 259 | ||
260 | /* Symmetry only applies if we've already got an active stream. */ | 260 | /* Symmetry only applies if we've already got an active stream. */ |
261 | if (cpu_dai->active) { | 261 | if (cpu_dai->active) { |
262 | ret = soc_pcm_apply_symmetry(substream, cpu_dai); | 262 | ret = soc_pcm_apply_symmetry(substream, cpu_dai); |
263 | if (ret != 0) | 263 | if (ret != 0) |
264 | goto config_err; | 264 | goto config_err; |
265 | } | 265 | } |
266 | 266 | ||
267 | if (codec_dai->active) { | 267 | if (codec_dai->active) { |
268 | ret = soc_pcm_apply_symmetry(substream, codec_dai); | 268 | ret = soc_pcm_apply_symmetry(substream, codec_dai); |
269 | if (ret != 0) | 269 | if (ret != 0) |
270 | goto config_err; | 270 | goto config_err; |
271 | } | 271 | } |
272 | 272 | ||
273 | pr_debug("asoc: %s <-> %s info:\n", | 273 | pr_debug("asoc: %s <-> %s info:\n", |
274 | codec_dai->name, cpu_dai->name); | 274 | codec_dai->name, cpu_dai->name); |
275 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); | 275 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); |
276 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | 276 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, |
277 | runtime->hw.channels_max); | 277 | runtime->hw.channels_max); |
278 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | 278 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, |
279 | runtime->hw.rate_max); | 279 | runtime->hw.rate_max); |
280 | 280 | ||
281 | dynamic: | 281 | dynamic: |
282 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 282 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
283 | cpu_dai->playback_active++; | 283 | cpu_dai->playback_active++; |
284 | codec_dai->playback_active++; | 284 | codec_dai->playback_active++; |
285 | } else { | 285 | } else { |
286 | cpu_dai->capture_active++; | 286 | cpu_dai->capture_active++; |
287 | codec_dai->capture_active++; | 287 | codec_dai->capture_active++; |
288 | } | 288 | } |
289 | cpu_dai->active++; | 289 | cpu_dai->active++; |
290 | codec_dai->active++; | 290 | codec_dai->active++; |
291 | rtd->codec->active++; | 291 | rtd->codec->active++; |
292 | mutex_unlock(&rtd->pcm_mutex); | 292 | mutex_unlock(&rtd->pcm_mutex); |
293 | return 0; | 293 | return 0; |
294 | 294 | ||
295 | config_err: | 295 | config_err: |
296 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 296 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
297 | rtd->dai_link->ops->shutdown(substream); | 297 | rtd->dai_link->ops->shutdown(substream); |
298 | 298 | ||
299 | machine_err: | 299 | machine_err: |
300 | if (codec_dai->driver->ops->shutdown) | 300 | if (codec_dai->driver->ops->shutdown) |
301 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 301 | codec_dai->driver->ops->shutdown(substream, codec_dai); |
302 | 302 | ||
303 | codec_dai_err: | 303 | codec_dai_err: |
304 | if (platform->driver->ops && platform->driver->ops->close) | 304 | if (platform->driver->ops && platform->driver->ops->close) |
305 | platform->driver->ops->close(substream); | 305 | platform->driver->ops->close(substream); |
306 | 306 | ||
307 | platform_err: | 307 | platform_err: |
308 | if (cpu_dai->driver->ops->shutdown) | 308 | if (cpu_dai->driver->ops->shutdown) |
309 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 309 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
310 | out: | 310 | out: |
311 | mutex_unlock(&rtd->pcm_mutex); | 311 | mutex_unlock(&rtd->pcm_mutex); |
312 | 312 | ||
313 | pm_runtime_put(platform->dev); | 313 | pm_runtime_put(platform->dev); |
314 | pm_runtime_put(codec_dai->dev); | 314 | pm_runtime_put(codec_dai->dev); |
315 | pm_runtime_put(cpu_dai->dev); | 315 | pm_runtime_put(cpu_dai->dev); |
316 | 316 | ||
317 | return ret; | 317 | return ret; |
318 | } | 318 | } |
319 | 319 | ||
320 | /* | 320 | /* |
321 | * Power down the audio subsystem pmdown_time msecs after close is called. | 321 | * Power down the audio subsystem pmdown_time msecs after close is called. |
322 | * This is to ensure there are no pops or clicks in between any music tracks | 322 | * This is to ensure there are no pops or clicks in between any music tracks |
323 | * due to DAPM power cycling. | 323 | * due to DAPM power cycling. |
324 | */ | 324 | */ |
325 | static void close_delayed_work(struct work_struct *work) | 325 | static void close_delayed_work(struct work_struct *work) |
326 | { | 326 | { |
327 | struct snd_soc_pcm_runtime *rtd = | 327 | struct snd_soc_pcm_runtime *rtd = |
328 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 328 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
329 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 329 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
330 | 330 | ||
331 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 331 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
332 | 332 | ||
333 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", | 333 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", |
334 | codec_dai->driver->playback.stream_name, | 334 | codec_dai->driver->playback.stream_name, |
335 | codec_dai->playback_active ? "active" : "inactive", | 335 | codec_dai->playback_active ? "active" : "inactive", |
336 | codec_dai->pop_wait ? "yes" : "no"); | 336 | rtd->pop_wait ? "yes" : "no"); |
337 | 337 | ||
338 | /* are we waiting on this codec DAI stream */ | 338 | /* are we waiting on this codec DAI stream */ |
339 | if (codec_dai->pop_wait == 1) { | 339 | if (rtd->pop_wait == 1) { |
340 | codec_dai->pop_wait = 0; | 340 | rtd->pop_wait = 0; |
341 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, | 341 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, |
342 | SND_SOC_DAPM_STREAM_STOP); | 342 | SND_SOC_DAPM_STREAM_STOP); |
343 | } | 343 | } |
344 | 344 | ||
345 | mutex_unlock(&rtd->pcm_mutex); | 345 | mutex_unlock(&rtd->pcm_mutex); |
346 | } | 346 | } |
347 | 347 | ||
348 | /* | 348 | /* |
349 | * Called by ALSA when a PCM substream is closed. Private data can be | 349 | * Called by ALSA when a PCM substream is closed. Private data can be |
350 | * freed here. The cpu DAI, codec DAI, machine and platform are also | 350 | * freed here. The cpu DAI, codec DAI, machine and platform are also |
351 | * shutdown. | 351 | * shutdown. |
352 | */ | 352 | */ |
353 | static int soc_pcm_close(struct snd_pcm_substream *substream) | 353 | static int soc_pcm_close(struct snd_pcm_substream *substream) |
354 | { | 354 | { |
355 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 355 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
356 | struct snd_soc_platform *platform = rtd->platform; | 356 | struct snd_soc_platform *platform = rtd->platform; |
357 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 357 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
358 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 358 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
359 | struct snd_soc_codec *codec = rtd->codec; | 359 | struct snd_soc_codec *codec = rtd->codec; |
360 | 360 | ||
361 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 361 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
362 | 362 | ||
363 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 363 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
364 | cpu_dai->playback_active--; | 364 | cpu_dai->playback_active--; |
365 | codec_dai->playback_active--; | 365 | codec_dai->playback_active--; |
366 | } else { | 366 | } else { |
367 | cpu_dai->capture_active--; | 367 | cpu_dai->capture_active--; |
368 | codec_dai->capture_active--; | 368 | codec_dai->capture_active--; |
369 | } | 369 | } |
370 | 370 | ||
371 | cpu_dai->active--; | 371 | cpu_dai->active--; |
372 | codec_dai->active--; | 372 | codec_dai->active--; |
373 | codec->active--; | 373 | codec->active--; |
374 | 374 | ||
375 | /* clear the corresponding DAIs rate when inactive */ | 375 | /* clear the corresponding DAIs rate when inactive */ |
376 | if (!cpu_dai->active) | 376 | if (!cpu_dai->active) |
377 | cpu_dai->rate = 0; | 377 | cpu_dai->rate = 0; |
378 | 378 | ||
379 | if (!codec_dai->active) | 379 | if (!codec_dai->active) |
380 | codec_dai->rate = 0; | 380 | codec_dai->rate = 0; |
381 | 381 | ||
382 | /* Muting the DAC suppresses artifacts caused during digital | 382 | /* Muting the DAC suppresses artifacts caused during digital |
383 | * shutdown, for example from stopping clocks. | 383 | * shutdown, for example from stopping clocks. |
384 | */ | 384 | */ |
385 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 385 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
386 | snd_soc_dai_digital_mute(codec_dai, 1); | 386 | snd_soc_dai_digital_mute(codec_dai, 1); |
387 | 387 | ||
388 | if (cpu_dai->driver->ops->shutdown) | 388 | if (cpu_dai->driver->ops->shutdown) |
389 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 389 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
390 | 390 | ||
391 | if (codec_dai->driver->ops->shutdown) | 391 | if (codec_dai->driver->ops->shutdown) |
392 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 392 | codec_dai->driver->ops->shutdown(substream, codec_dai); |
393 | 393 | ||
394 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 394 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
395 | rtd->dai_link->ops->shutdown(substream); | 395 | rtd->dai_link->ops->shutdown(substream); |
396 | 396 | ||
397 | if (platform->driver->ops && platform->driver->ops->close) | 397 | if (platform->driver->ops && platform->driver->ops->close) |
398 | platform->driver->ops->close(substream); | 398 | platform->driver->ops->close(substream); |
399 | cpu_dai->runtime = NULL; | 399 | cpu_dai->runtime = NULL; |
400 | 400 | ||
401 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 401 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
402 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 402 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || |
403 | rtd->dai_link->ignore_pmdown_time) { | 403 | rtd->dai_link->ignore_pmdown_time) { |
404 | /* powered down playback stream now */ | 404 | /* powered down playback stream now */ |
405 | snd_soc_dapm_stream_event(rtd, | 405 | snd_soc_dapm_stream_event(rtd, |
406 | SNDRV_PCM_STREAM_PLAYBACK, | 406 | SNDRV_PCM_STREAM_PLAYBACK, |
407 | SND_SOC_DAPM_STREAM_STOP); | 407 | SND_SOC_DAPM_STREAM_STOP); |
408 | } else { | 408 | } else { |
409 | /* start delayed pop wq here for playback streams */ | 409 | /* start delayed pop wq here for playback streams */ |
410 | codec_dai->pop_wait = 1; | 410 | rtd->pop_wait = 1; |
411 | schedule_delayed_work(&rtd->delayed_work, | 411 | schedule_delayed_work(&rtd->delayed_work, |
412 | msecs_to_jiffies(rtd->pmdown_time)); | 412 | msecs_to_jiffies(rtd->pmdown_time)); |
413 | } | 413 | } |
414 | } else { | 414 | } else { |
415 | /* capture streams can be powered down now */ | 415 | /* capture streams can be powered down now */ |
416 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, | 416 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, |
417 | SND_SOC_DAPM_STREAM_STOP); | 417 | SND_SOC_DAPM_STREAM_STOP); |
418 | } | 418 | } |
419 | 419 | ||
420 | mutex_unlock(&rtd->pcm_mutex); | 420 | mutex_unlock(&rtd->pcm_mutex); |
421 | 421 | ||
422 | pm_runtime_put(platform->dev); | 422 | pm_runtime_put(platform->dev); |
423 | pm_runtime_put(codec_dai->dev); | 423 | pm_runtime_put(codec_dai->dev); |
424 | pm_runtime_put(cpu_dai->dev); | 424 | pm_runtime_put(cpu_dai->dev); |
425 | 425 | ||
426 | return 0; | 426 | return 0; |
427 | } | 427 | } |
428 | 428 | ||
429 | /* | 429 | /* |
430 | * Called by ALSA when the PCM substream is prepared, can set format, sample | 430 | * Called by ALSA when the PCM substream is prepared, can set format, sample |
431 | * rate, etc. This function is non atomic and can be called multiple times, | 431 | * rate, etc. This function is non atomic and can be called multiple times, |
432 | * it can refer to the runtime info. | 432 | * it can refer to the runtime info. |
433 | */ | 433 | */ |
434 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | 434 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) |
435 | { | 435 | { |
436 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 436 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
437 | struct snd_soc_platform *platform = rtd->platform; | 437 | struct snd_soc_platform *platform = rtd->platform; |
438 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 438 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
439 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 439 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
440 | int ret = 0; | 440 | int ret = 0; |
441 | 441 | ||
442 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 442 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
443 | 443 | ||
444 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { | 444 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { |
445 | ret = rtd->dai_link->ops->prepare(substream); | 445 | ret = rtd->dai_link->ops->prepare(substream); |
446 | if (ret < 0) { | 446 | if (ret < 0) { |
447 | pr_err("asoc: machine prepare error: %d\n", ret); | 447 | pr_err("asoc: machine prepare error: %d\n", ret); |
448 | goto out; | 448 | goto out; |
449 | } | 449 | } |
450 | } | 450 | } |
451 | 451 | ||
452 | if (platform->driver->ops && platform->driver->ops->prepare) { | 452 | if (platform->driver->ops && platform->driver->ops->prepare) { |
453 | ret = platform->driver->ops->prepare(substream); | 453 | ret = platform->driver->ops->prepare(substream); |
454 | if (ret < 0) { | 454 | if (ret < 0) { |
455 | dev_err(platform->dev, "platform prepare error: %d\n", | 455 | dev_err(platform->dev, "platform prepare error: %d\n", |
456 | ret); | 456 | ret); |
457 | goto out; | 457 | goto out; |
458 | } | 458 | } |
459 | } | 459 | } |
460 | 460 | ||
461 | if (codec_dai->driver->ops->prepare) { | 461 | if (codec_dai->driver->ops->prepare) { |
462 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | 462 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); |
463 | if (ret < 0) { | 463 | if (ret < 0) { |
464 | dev_err(codec_dai->dev, "DAI prepare error: %d\n", | 464 | dev_err(codec_dai->dev, "DAI prepare error: %d\n", |
465 | ret); | 465 | ret); |
466 | goto out; | 466 | goto out; |
467 | } | 467 | } |
468 | } | 468 | } |
469 | 469 | ||
470 | if (cpu_dai->driver->ops->prepare) { | 470 | if (cpu_dai->driver->ops->prepare) { |
471 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); | 471 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); |
472 | if (ret < 0) { | 472 | if (ret < 0) { |
473 | dev_err(cpu_dai->dev, "DAI prepare error: %d\n", | 473 | dev_err(cpu_dai->dev, "DAI prepare error: %d\n", |
474 | ret); | 474 | ret); |
475 | goto out; | 475 | goto out; |
476 | } | 476 | } |
477 | } | 477 | } |
478 | 478 | ||
479 | /* cancel any delayed stream shutdown that is pending */ | 479 | /* cancel any delayed stream shutdown that is pending */ |
480 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 480 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
481 | codec_dai->pop_wait) { | 481 | rtd->pop_wait) { |
482 | codec_dai->pop_wait = 0; | 482 | rtd->pop_wait = 0; |
483 | cancel_delayed_work(&rtd->delayed_work); | 483 | cancel_delayed_work(&rtd->delayed_work); |
484 | } | 484 | } |
485 | 485 | ||
486 | snd_soc_dapm_stream_event(rtd, substream->stream, | 486 | snd_soc_dapm_stream_event(rtd, substream->stream, |
487 | SND_SOC_DAPM_STREAM_START); | 487 | SND_SOC_DAPM_STREAM_START); |
488 | 488 | ||
489 | snd_soc_dai_digital_mute(codec_dai, 0); | 489 | snd_soc_dai_digital_mute(codec_dai, 0); |
490 | 490 | ||
491 | out: | 491 | out: |
492 | mutex_unlock(&rtd->pcm_mutex); | 492 | mutex_unlock(&rtd->pcm_mutex); |
493 | return ret; | 493 | return ret; |
494 | } | 494 | } |
495 | 495 | ||
496 | /* | 496 | /* |
497 | * Called by ALSA when the hardware params are set by application. This | 497 | * Called by ALSA when the hardware params are set by application. This |
498 | * function can also be called multiple times and can allocate buffers | 498 | * function can also be called multiple times and can allocate buffers |
499 | * (using snd_pcm_lib_* ). It's non-atomic. | 499 | * (using snd_pcm_lib_* ). It's non-atomic. |
500 | */ | 500 | */ |
501 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | 501 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, |
502 | struct snd_pcm_hw_params *params) | 502 | struct snd_pcm_hw_params *params) |
503 | { | 503 | { |
504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
505 | struct snd_soc_platform *platform = rtd->platform; | 505 | struct snd_soc_platform *platform = rtd->platform; |
506 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 506 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
507 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 507 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
508 | int ret = 0; | 508 | int ret = 0; |
509 | 509 | ||
510 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 510 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
511 | 511 | ||
512 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { | 512 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { |
513 | ret = rtd->dai_link->ops->hw_params(substream, params); | 513 | ret = rtd->dai_link->ops->hw_params(substream, params); |
514 | if (ret < 0) { | 514 | if (ret < 0) { |
515 | pr_err("asoc: machine hw_params failed: %d\n", ret); | 515 | pr_err("asoc: machine hw_params failed: %d\n", ret); |
516 | goto out; | 516 | goto out; |
517 | } | 517 | } |
518 | } | 518 | } |
519 | 519 | ||
520 | if (codec_dai->driver->ops->hw_params) { | 520 | if (codec_dai->driver->ops->hw_params) { |
521 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | 521 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); |
522 | if (ret < 0) { | 522 | if (ret < 0) { |
523 | dev_err(codec_dai->dev, "can't set %s hw params: %d\n", | 523 | dev_err(codec_dai->dev, "can't set %s hw params: %d\n", |
524 | codec_dai->name, ret); | 524 | codec_dai->name, ret); |
525 | goto codec_err; | 525 | goto codec_err; |
526 | } | 526 | } |
527 | } | 527 | } |
528 | 528 | ||
529 | if (cpu_dai->driver->ops->hw_params) { | 529 | if (cpu_dai->driver->ops->hw_params) { |
530 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | 530 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); |
531 | if (ret < 0) { | 531 | if (ret < 0) { |
532 | dev_err(cpu_dai->dev, "%s hw params failed: %d\n", | 532 | dev_err(cpu_dai->dev, "%s hw params failed: %d\n", |
533 | cpu_dai->name, ret); | 533 | cpu_dai->name, ret); |
534 | goto interface_err; | 534 | goto interface_err; |
535 | } | 535 | } |
536 | } | 536 | } |
537 | 537 | ||
538 | if (platform->driver->ops && platform->driver->ops->hw_params) { | 538 | if (platform->driver->ops && platform->driver->ops->hw_params) { |
539 | ret = platform->driver->ops->hw_params(substream, params); | 539 | ret = platform->driver->ops->hw_params(substream, params); |
540 | if (ret < 0) { | 540 | if (ret < 0) { |
541 | dev_err(platform->dev, "%s hw params failed: %d\n", | 541 | dev_err(platform->dev, "%s hw params failed: %d\n", |
542 | platform->name, ret); | 542 | platform->name, ret); |
543 | goto platform_err; | 543 | goto platform_err; |
544 | } | 544 | } |
545 | } | 545 | } |
546 | 546 | ||
547 | /* store the rate for each DAIs */ | 547 | /* store the rate for each DAIs */ |
548 | cpu_dai->rate = params_rate(params); | 548 | cpu_dai->rate = params_rate(params); |
549 | codec_dai->rate = params_rate(params); | 549 | codec_dai->rate = params_rate(params); |
550 | 550 | ||
551 | out: | 551 | out: |
552 | mutex_unlock(&rtd->pcm_mutex); | 552 | mutex_unlock(&rtd->pcm_mutex); |
553 | return ret; | 553 | return ret; |
554 | 554 | ||
555 | platform_err: | 555 | platform_err: |
556 | if (cpu_dai->driver->ops->hw_free) | 556 | if (cpu_dai->driver->ops->hw_free) |
557 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 557 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
558 | 558 | ||
559 | interface_err: | 559 | interface_err: |
560 | if (codec_dai->driver->ops->hw_free) | 560 | if (codec_dai->driver->ops->hw_free) |
561 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 561 | codec_dai->driver->ops->hw_free(substream, codec_dai); |
562 | 562 | ||
563 | codec_err: | 563 | codec_err: |
564 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 564 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
565 | rtd->dai_link->ops->hw_free(substream); | 565 | rtd->dai_link->ops->hw_free(substream); |
566 | 566 | ||
567 | mutex_unlock(&rtd->pcm_mutex); | 567 | mutex_unlock(&rtd->pcm_mutex); |
568 | return ret; | 568 | return ret; |
569 | } | 569 | } |
570 | 570 | ||
571 | /* | 571 | /* |
572 | * Frees resources allocated by hw_params, can be called multiple times | 572 | * Frees resources allocated by hw_params, can be called multiple times |
573 | */ | 573 | */ |
574 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | 574 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) |
575 | { | 575 | { |
576 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 576 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
577 | struct snd_soc_platform *platform = rtd->platform; | 577 | struct snd_soc_platform *platform = rtd->platform; |
578 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 578 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
579 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 579 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
580 | struct snd_soc_codec *codec = rtd->codec; | 580 | struct snd_soc_codec *codec = rtd->codec; |
581 | 581 | ||
582 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 582 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
583 | 583 | ||
584 | /* apply codec digital mute */ | 584 | /* apply codec digital mute */ |
585 | if (!codec->active) | 585 | if (!codec->active) |
586 | snd_soc_dai_digital_mute(codec_dai, 1); | 586 | snd_soc_dai_digital_mute(codec_dai, 1); |
587 | 587 | ||
588 | /* free any machine hw params */ | 588 | /* free any machine hw params */ |
589 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 589 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
590 | rtd->dai_link->ops->hw_free(substream); | 590 | rtd->dai_link->ops->hw_free(substream); |
591 | 591 | ||
592 | /* free any DMA resources */ | 592 | /* free any DMA resources */ |
593 | if (platform->driver->ops && platform->driver->ops->hw_free) | 593 | if (platform->driver->ops && platform->driver->ops->hw_free) |
594 | platform->driver->ops->hw_free(substream); | 594 | platform->driver->ops->hw_free(substream); |
595 | 595 | ||
596 | /* now free hw params for the DAIs */ | 596 | /* now free hw params for the DAIs */ |
597 | if (codec_dai->driver->ops->hw_free) | 597 | if (codec_dai->driver->ops->hw_free) |
598 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 598 | codec_dai->driver->ops->hw_free(substream, codec_dai); |
599 | 599 | ||
600 | if (cpu_dai->driver->ops->hw_free) | 600 | if (cpu_dai->driver->ops->hw_free) |
601 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 601 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
602 | 602 | ||
603 | mutex_unlock(&rtd->pcm_mutex); | 603 | mutex_unlock(&rtd->pcm_mutex); |
604 | return 0; | 604 | return 0; |
605 | } | 605 | } |
606 | 606 | ||
607 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 607 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
608 | { | 608 | { |
609 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 609 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
610 | struct snd_soc_platform *platform = rtd->platform; | 610 | struct snd_soc_platform *platform = rtd->platform; |
611 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 611 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
612 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 612 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
613 | int ret; | 613 | int ret; |
614 | 614 | ||
615 | if (codec_dai->driver->ops->trigger) { | 615 | if (codec_dai->driver->ops->trigger) { |
616 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | 616 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); |
617 | if (ret < 0) | 617 | if (ret < 0) |
618 | return ret; | 618 | return ret; |
619 | } | 619 | } |
620 | 620 | ||
621 | if (platform->driver->ops && platform->driver->ops->trigger) { | 621 | if (platform->driver->ops && platform->driver->ops->trigger) { |
622 | ret = platform->driver->ops->trigger(substream, cmd); | 622 | ret = platform->driver->ops->trigger(substream, cmd); |
623 | if (ret < 0) | 623 | if (ret < 0) |
624 | return ret; | 624 | return ret; |
625 | } | 625 | } |
626 | 626 | ||
627 | if (cpu_dai->driver->ops->trigger) { | 627 | if (cpu_dai->driver->ops->trigger) { |
628 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); | 628 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); |
629 | if (ret < 0) | 629 | if (ret < 0) |
630 | return ret; | 630 | return ret; |
631 | } | 631 | } |
632 | return 0; | 632 | return 0; |
633 | } | 633 | } |
634 | 634 | ||
635 | static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, | 635 | static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, |
636 | int cmd) | 636 | int cmd) |
637 | { | 637 | { |
638 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 638 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
639 | struct snd_soc_platform *platform = rtd->platform; | 639 | struct snd_soc_platform *platform = rtd->platform; |
640 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 640 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
641 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 641 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
642 | int ret; | 642 | int ret; |
643 | 643 | ||
644 | if (codec_dai->driver->ops->bespoke_trigger) { | 644 | if (codec_dai->driver->ops->bespoke_trigger) { |
645 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); | 645 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); |
646 | if (ret < 0) | 646 | if (ret < 0) |
647 | return ret; | 647 | return ret; |
648 | } | 648 | } |
649 | 649 | ||
650 | if (platform->driver->bespoke_trigger) { | 650 | if (platform->driver->bespoke_trigger) { |
651 | ret = platform->driver->bespoke_trigger(substream, cmd); | 651 | ret = platform->driver->bespoke_trigger(substream, cmd); |
652 | if (ret < 0) | 652 | if (ret < 0) |
653 | return ret; | 653 | return ret; |
654 | } | 654 | } |
655 | 655 | ||
656 | if (cpu_dai->driver->ops->bespoke_trigger) { | 656 | if (cpu_dai->driver->ops->bespoke_trigger) { |
657 | ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); | 657 | ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); |
658 | if (ret < 0) | 658 | if (ret < 0) |
659 | return ret; | 659 | return ret; |
660 | } | 660 | } |
661 | return 0; | 661 | return 0; |
662 | } | 662 | } |
663 | /* | 663 | /* |
664 | * soc level wrapper for pointer callback | 664 | * soc level wrapper for pointer callback |
665 | * If cpu_dai, codec_dai, platform driver has the delay callback, than | 665 | * If cpu_dai, codec_dai, platform driver has the delay callback, than |
666 | * the runtime->delay will be updated accordingly. | 666 | * the runtime->delay will be updated accordingly. |
667 | */ | 667 | */ |
668 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | 668 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) |
669 | { | 669 | { |
670 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 670 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
671 | struct snd_soc_platform *platform = rtd->platform; | 671 | struct snd_soc_platform *platform = rtd->platform; |
672 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 672 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
673 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 673 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
674 | struct snd_pcm_runtime *runtime = substream->runtime; | 674 | struct snd_pcm_runtime *runtime = substream->runtime; |
675 | snd_pcm_uframes_t offset = 0; | 675 | snd_pcm_uframes_t offset = 0; |
676 | snd_pcm_sframes_t delay = 0; | 676 | snd_pcm_sframes_t delay = 0; |
677 | 677 | ||
678 | if (platform->driver->ops && platform->driver->ops->pointer) | 678 | if (platform->driver->ops && platform->driver->ops->pointer) |
679 | offset = platform->driver->ops->pointer(substream); | 679 | offset = platform->driver->ops->pointer(substream); |
680 | 680 | ||
681 | if (cpu_dai->driver->ops->delay) | 681 | if (cpu_dai->driver->ops->delay) |
682 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | 682 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
683 | 683 | ||
684 | if (codec_dai->driver->ops->delay) | 684 | if (codec_dai->driver->ops->delay) |
685 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | 685 | delay += codec_dai->driver->ops->delay(substream, codec_dai); |
686 | 686 | ||
687 | if (platform->driver->delay) | 687 | if (platform->driver->delay) |
688 | delay += platform->driver->delay(substream, codec_dai); | 688 | delay += platform->driver->delay(substream, codec_dai); |
689 | 689 | ||
690 | runtime->delay = delay; | 690 | runtime->delay = delay; |
691 | 691 | ||
692 | return offset; | 692 | return offset; |
693 | } | 693 | } |
694 | 694 | ||
695 | /* connect a FE and BE */ | 695 | /* connect a FE and BE */ |
696 | static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, | 696 | static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, |
697 | struct snd_soc_pcm_runtime *be, int stream) | 697 | struct snd_soc_pcm_runtime *be, int stream) |
698 | { | 698 | { |
699 | struct snd_soc_dpcm *dpcm; | 699 | struct snd_soc_dpcm *dpcm; |
700 | 700 | ||
701 | /* only add new dpcms */ | 701 | /* only add new dpcms */ |
702 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 702 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
703 | if (dpcm->be == be && dpcm->fe == fe) | 703 | if (dpcm->be == be && dpcm->fe == fe) |
704 | return 0; | 704 | return 0; |
705 | } | 705 | } |
706 | 706 | ||
707 | dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL); | 707 | dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL); |
708 | if (!dpcm) | 708 | if (!dpcm) |
709 | return -ENOMEM; | 709 | return -ENOMEM; |
710 | 710 | ||
711 | dpcm->be = be; | 711 | dpcm->be = be; |
712 | dpcm->fe = fe; | 712 | dpcm->fe = fe; |
713 | be->dpcm[stream].runtime = fe->dpcm[stream].runtime; | 713 | be->dpcm[stream].runtime = fe->dpcm[stream].runtime; |
714 | dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; | 714 | dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; |
715 | list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); | 715 | list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); |
716 | list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); | 716 | list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); |
717 | 717 | ||
718 | dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n", | 718 | dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n", |
719 | stream ? "capture" : "playback", fe->dai_link->name, | 719 | stream ? "capture" : "playback", fe->dai_link->name, |
720 | stream ? "<-" : "->", be->dai_link->name); | 720 | stream ? "<-" : "->", be->dai_link->name); |
721 | 721 | ||
722 | #ifdef CONFIG_DEBUG_FS | 722 | #ifdef CONFIG_DEBUG_FS |
723 | dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, | 723 | dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, |
724 | fe->debugfs_dpcm_root, &dpcm->state); | 724 | fe->debugfs_dpcm_root, &dpcm->state); |
725 | #endif | 725 | #endif |
726 | return 1; | 726 | return 1; |
727 | } | 727 | } |
728 | 728 | ||
729 | /* reparent a BE onto another FE */ | 729 | /* reparent a BE onto another FE */ |
730 | static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, | 730 | static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, |
731 | struct snd_soc_pcm_runtime *be, int stream) | 731 | struct snd_soc_pcm_runtime *be, int stream) |
732 | { | 732 | { |
733 | struct snd_soc_dpcm *dpcm; | 733 | struct snd_soc_dpcm *dpcm; |
734 | struct snd_pcm_substream *fe_substream, *be_substream; | 734 | struct snd_pcm_substream *fe_substream, *be_substream; |
735 | 735 | ||
736 | /* reparent if BE is connected to other FEs */ | 736 | /* reparent if BE is connected to other FEs */ |
737 | if (!be->dpcm[stream].users) | 737 | if (!be->dpcm[stream].users) |
738 | return; | 738 | return; |
739 | 739 | ||
740 | be_substream = snd_soc_dpcm_get_substream(be, stream); | 740 | be_substream = snd_soc_dpcm_get_substream(be, stream); |
741 | 741 | ||
742 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | 742 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
743 | if (dpcm->fe == fe) | 743 | if (dpcm->fe == fe) |
744 | continue; | 744 | continue; |
745 | 745 | ||
746 | dev_dbg(fe->dev, " reparent %s path %s %s %s\n", | 746 | dev_dbg(fe->dev, " reparent %s path %s %s %s\n", |
747 | stream ? "capture" : "playback", | 747 | stream ? "capture" : "playback", |
748 | dpcm->fe->dai_link->name, | 748 | dpcm->fe->dai_link->name, |
749 | stream ? "<-" : "->", dpcm->be->dai_link->name); | 749 | stream ? "<-" : "->", dpcm->be->dai_link->name); |
750 | 750 | ||
751 | fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream); | 751 | fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream); |
752 | be_substream->runtime = fe_substream->runtime; | 752 | be_substream->runtime = fe_substream->runtime; |
753 | break; | 753 | break; |
754 | } | 754 | } |
755 | } | 755 | } |
756 | 756 | ||
757 | /* disconnect a BE and FE */ | 757 | /* disconnect a BE and FE */ |
758 | static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) | 758 | static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) |
759 | { | 759 | { |
760 | struct snd_soc_dpcm *dpcm, *d; | 760 | struct snd_soc_dpcm *dpcm, *d; |
761 | 761 | ||
762 | list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { | 762 | list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { |
763 | dev_dbg(fe->dev, "BE %s disconnect check for %s\n", | 763 | dev_dbg(fe->dev, "BE %s disconnect check for %s\n", |
764 | stream ? "capture" : "playback", | 764 | stream ? "capture" : "playback", |
765 | dpcm->be->dai_link->name); | 765 | dpcm->be->dai_link->name); |
766 | 766 | ||
767 | if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) | 767 | if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) |
768 | continue; | 768 | continue; |
769 | 769 | ||
770 | dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n", | 770 | dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n", |
771 | stream ? "capture" : "playback", fe->dai_link->name, | 771 | stream ? "capture" : "playback", fe->dai_link->name, |
772 | stream ? "<-" : "->", dpcm->be->dai_link->name); | 772 | stream ? "<-" : "->", dpcm->be->dai_link->name); |
773 | 773 | ||
774 | /* BEs still alive need new FE */ | 774 | /* BEs still alive need new FE */ |
775 | dpcm_be_reparent(fe, dpcm->be, stream); | 775 | dpcm_be_reparent(fe, dpcm->be, stream); |
776 | 776 | ||
777 | #ifdef CONFIG_DEBUG_FS | 777 | #ifdef CONFIG_DEBUG_FS |
778 | debugfs_remove(dpcm->debugfs_state); | 778 | debugfs_remove(dpcm->debugfs_state); |
779 | #endif | 779 | #endif |
780 | list_del(&dpcm->list_be); | 780 | list_del(&dpcm->list_be); |
781 | list_del(&dpcm->list_fe); | 781 | list_del(&dpcm->list_fe); |
782 | kfree(dpcm); | 782 | kfree(dpcm); |
783 | } | 783 | } |
784 | } | 784 | } |
785 | 785 | ||
786 | /* get BE for DAI widget and stream */ | 786 | /* get BE for DAI widget and stream */ |
787 | static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | 787 | static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, |
788 | struct snd_soc_dapm_widget *widget, int stream) | 788 | struct snd_soc_dapm_widget *widget, int stream) |
789 | { | 789 | { |
790 | struct snd_soc_pcm_runtime *be; | 790 | struct snd_soc_pcm_runtime *be; |
791 | int i; | 791 | int i; |
792 | 792 | ||
793 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 793 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
794 | for (i = 0; i < card->num_links; i++) { | 794 | for (i = 0; i < card->num_links; i++) { |
795 | be = &card->rtd[i]; | 795 | be = &card->rtd[i]; |
796 | 796 | ||
797 | if (!be->dai_link->no_pcm) | 797 | if (!be->dai_link->no_pcm) |
798 | continue; | 798 | continue; |
799 | 799 | ||
800 | if (be->cpu_dai->playback_widget == widget || | 800 | if (be->cpu_dai->playback_widget == widget || |
801 | be->codec_dai->playback_widget == widget) | 801 | be->codec_dai->playback_widget == widget) |
802 | return be; | 802 | return be; |
803 | } | 803 | } |
804 | } else { | 804 | } else { |
805 | 805 | ||
806 | for (i = 0; i < card->num_links; i++) { | 806 | for (i = 0; i < card->num_links; i++) { |
807 | be = &card->rtd[i]; | 807 | be = &card->rtd[i]; |
808 | 808 | ||
809 | if (!be->dai_link->no_pcm) | 809 | if (!be->dai_link->no_pcm) |
810 | continue; | 810 | continue; |
811 | 811 | ||
812 | if (be->cpu_dai->capture_widget == widget || | 812 | if (be->cpu_dai->capture_widget == widget || |
813 | be->codec_dai->capture_widget == widget) | 813 | be->codec_dai->capture_widget == widget) |
814 | return be; | 814 | return be; |
815 | } | 815 | } |
816 | } | 816 | } |
817 | 817 | ||
818 | dev_err(card->dev, "can't get %s BE for %s\n", | 818 | dev_err(card->dev, "can't get %s BE for %s\n", |
819 | stream ? "capture" : "playback", widget->name); | 819 | stream ? "capture" : "playback", widget->name); |
820 | return NULL; | 820 | return NULL; |
821 | } | 821 | } |
822 | 822 | ||
823 | static inline struct snd_soc_dapm_widget * | 823 | static inline struct snd_soc_dapm_widget * |
824 | rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream) | 824 | rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream) |
825 | { | 825 | { |
826 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 826 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
827 | return rtd->cpu_dai->playback_widget; | 827 | return rtd->cpu_dai->playback_widget; |
828 | else | 828 | else |
829 | return rtd->cpu_dai->capture_widget; | 829 | return rtd->cpu_dai->capture_widget; |
830 | } | 830 | } |
831 | 831 | ||
832 | static inline struct snd_soc_dapm_widget * | 832 | static inline struct snd_soc_dapm_widget * |
833 | rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream) | 833 | rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream) |
834 | { | 834 | { |
835 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 835 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
836 | return rtd->codec_dai->playback_widget; | 836 | return rtd->codec_dai->playback_widget; |
837 | else | 837 | else |
838 | return rtd->codec_dai->capture_widget; | 838 | return rtd->codec_dai->capture_widget; |
839 | } | 839 | } |
840 | 840 | ||
841 | static int widget_in_list(struct snd_soc_dapm_widget_list *list, | 841 | static int widget_in_list(struct snd_soc_dapm_widget_list *list, |
842 | struct snd_soc_dapm_widget *widget) | 842 | struct snd_soc_dapm_widget *widget) |
843 | { | 843 | { |
844 | int i; | 844 | int i; |
845 | 845 | ||
846 | for (i = 0; i < list->num_widgets; i++) { | 846 | for (i = 0; i < list->num_widgets; i++) { |
847 | if (widget == list->widgets[i]) | 847 | if (widget == list->widgets[i]) |
848 | return 1; | 848 | return 1; |
849 | } | 849 | } |
850 | 850 | ||
851 | return 0; | 851 | return 0; |
852 | } | 852 | } |
853 | 853 | ||
854 | static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, | 854 | static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, |
855 | int stream, struct snd_soc_dapm_widget_list **list_) | 855 | int stream, struct snd_soc_dapm_widget_list **list_) |
856 | { | 856 | { |
857 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | 857 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; |
858 | struct snd_soc_dapm_widget_list *list; | 858 | struct snd_soc_dapm_widget_list *list; |
859 | int paths; | 859 | int paths; |
860 | 860 | ||
861 | list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + | 861 | list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + |
862 | sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); | 862 | sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); |
863 | if (list == NULL) | 863 | if (list == NULL) |
864 | return -ENOMEM; | 864 | return -ENOMEM; |
865 | 865 | ||
866 | /* get number of valid DAI paths and their widgets */ | 866 | /* get number of valid DAI paths and their widgets */ |
867 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); | 867 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); |
868 | 868 | ||
869 | dev_dbg(fe->dev, "found %d audio %s paths\n", paths, | 869 | dev_dbg(fe->dev, "found %d audio %s paths\n", paths, |
870 | stream ? "capture" : "playback"); | 870 | stream ? "capture" : "playback"); |
871 | 871 | ||
872 | *list_ = list; | 872 | *list_ = list; |
873 | return paths; | 873 | return paths; |
874 | } | 874 | } |
875 | 875 | ||
876 | static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) | 876 | static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) |
877 | { | 877 | { |
878 | kfree(*list); | 878 | kfree(*list); |
879 | } | 879 | } |
880 | 880 | ||
881 | static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | 881 | static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, |
882 | struct snd_soc_dapm_widget_list **list_) | 882 | struct snd_soc_dapm_widget_list **list_) |
883 | { | 883 | { |
884 | struct snd_soc_dpcm *dpcm; | 884 | struct snd_soc_dpcm *dpcm; |
885 | struct snd_soc_dapm_widget_list *list = *list_; | 885 | struct snd_soc_dapm_widget_list *list = *list_; |
886 | struct snd_soc_dapm_widget *widget; | 886 | struct snd_soc_dapm_widget *widget; |
887 | int prune = 0; | 887 | int prune = 0; |
888 | 888 | ||
889 | /* Destroy any old FE <--> BE connections */ | 889 | /* Destroy any old FE <--> BE connections */ |
890 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 890 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
891 | 891 | ||
892 | /* is there a valid CPU DAI widget for this BE */ | 892 | /* is there a valid CPU DAI widget for this BE */ |
893 | widget = rtd_get_cpu_widget(dpcm->be, stream); | 893 | widget = rtd_get_cpu_widget(dpcm->be, stream); |
894 | 894 | ||
895 | /* prune the BE if it's no longer in our active list */ | 895 | /* prune the BE if it's no longer in our active list */ |
896 | if (widget && widget_in_list(list, widget)) | 896 | if (widget && widget_in_list(list, widget)) |
897 | continue; | 897 | continue; |
898 | 898 | ||
899 | /* is there a valid CODEC DAI widget for this BE */ | 899 | /* is there a valid CODEC DAI widget for this BE */ |
900 | widget = rtd_get_codec_widget(dpcm->be, stream); | 900 | widget = rtd_get_codec_widget(dpcm->be, stream); |
901 | 901 | ||
902 | /* prune the BE if it's no longer in our active list */ | 902 | /* prune the BE if it's no longer in our active list */ |
903 | if (widget && widget_in_list(list, widget)) | 903 | if (widget && widget_in_list(list, widget)) |
904 | continue; | 904 | continue; |
905 | 905 | ||
906 | dev_dbg(fe->dev, "pruning %s BE %s for %s\n", | 906 | dev_dbg(fe->dev, "pruning %s BE %s for %s\n", |
907 | stream ? "capture" : "playback", | 907 | stream ? "capture" : "playback", |
908 | dpcm->be->dai_link->name, fe->dai_link->name); | 908 | dpcm->be->dai_link->name, fe->dai_link->name); |
909 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 909 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
910 | dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 910 | dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; |
911 | prune++; | 911 | prune++; |
912 | } | 912 | } |
913 | 913 | ||
914 | dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune); | 914 | dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune); |
915 | return prune; | 915 | return prune; |
916 | } | 916 | } |
917 | 917 | ||
918 | static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, | 918 | static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, |
919 | struct snd_soc_dapm_widget_list **list_) | 919 | struct snd_soc_dapm_widget_list **list_) |
920 | { | 920 | { |
921 | struct snd_soc_card *card = fe->card; | 921 | struct snd_soc_card *card = fe->card; |
922 | struct snd_soc_dapm_widget_list *list = *list_; | 922 | struct snd_soc_dapm_widget_list *list = *list_; |
923 | struct snd_soc_pcm_runtime *be; | 923 | struct snd_soc_pcm_runtime *be; |
924 | int i, new = 0, err; | 924 | int i, new = 0, err; |
925 | 925 | ||
926 | /* Create any new FE <--> BE connections */ | 926 | /* Create any new FE <--> BE connections */ |
927 | for (i = 0; i < list->num_widgets; i++) { | 927 | for (i = 0; i < list->num_widgets; i++) { |
928 | 928 | ||
929 | if (list->widgets[i]->id != snd_soc_dapm_dai) | 929 | if (list->widgets[i]->id != snd_soc_dapm_dai) |
930 | continue; | 930 | continue; |
931 | 931 | ||
932 | /* is there a valid BE rtd for this widget */ | 932 | /* is there a valid BE rtd for this widget */ |
933 | be = dpcm_get_be(card, list->widgets[i], stream); | 933 | be = dpcm_get_be(card, list->widgets[i], stream); |
934 | if (!be) { | 934 | if (!be) { |
935 | dev_err(fe->dev, "no BE found for %s\n", | 935 | dev_err(fe->dev, "no BE found for %s\n", |
936 | list->widgets[i]->name); | 936 | list->widgets[i]->name); |
937 | continue; | 937 | continue; |
938 | } | 938 | } |
939 | 939 | ||
940 | /* make sure BE is a real BE */ | 940 | /* make sure BE is a real BE */ |
941 | if (!be->dai_link->no_pcm) | 941 | if (!be->dai_link->no_pcm) |
942 | continue; | 942 | continue; |
943 | 943 | ||
944 | /* don't connect if FE is not running */ | 944 | /* don't connect if FE is not running */ |
945 | if (!fe->dpcm[stream].runtime) | 945 | if (!fe->dpcm[stream].runtime) |
946 | continue; | 946 | continue; |
947 | 947 | ||
948 | /* newly connected FE and BE */ | 948 | /* newly connected FE and BE */ |
949 | err = dpcm_be_connect(fe, be, stream); | 949 | err = dpcm_be_connect(fe, be, stream); |
950 | if (err < 0) { | 950 | if (err < 0) { |
951 | dev_err(fe->dev, "can't connect %s\n", | 951 | dev_err(fe->dev, "can't connect %s\n", |
952 | list->widgets[i]->name); | 952 | list->widgets[i]->name); |
953 | break; | 953 | break; |
954 | } else if (err == 0) /* already connected */ | 954 | } else if (err == 0) /* already connected */ |
955 | continue; | 955 | continue; |
956 | 956 | ||
957 | /* new */ | 957 | /* new */ |
958 | be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 958 | be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; |
959 | new++; | 959 | new++; |
960 | } | 960 | } |
961 | 961 | ||
962 | dev_dbg(fe->dev, "found %d new BE paths\n", new); | 962 | dev_dbg(fe->dev, "found %d new BE paths\n", new); |
963 | return new; | 963 | return new; |
964 | } | 964 | } |
965 | 965 | ||
966 | /* | 966 | /* |
967 | * Find the corresponding BE DAIs that source or sink audio to this | 967 | * Find the corresponding BE DAIs that source or sink audio to this |
968 | * FE substream. | 968 | * FE substream. |
969 | */ | 969 | */ |
970 | static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, | 970 | static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, |
971 | int stream, struct snd_soc_dapm_widget_list **list, int new) | 971 | int stream, struct snd_soc_dapm_widget_list **list, int new) |
972 | { | 972 | { |
973 | if (new) | 973 | if (new) |
974 | return dpcm_add_paths(fe, stream, list); | 974 | return dpcm_add_paths(fe, stream, list); |
975 | else | 975 | else |
976 | return dpcm_prune_paths(fe, stream, list); | 976 | return dpcm_prune_paths(fe, stream, list); |
977 | } | 977 | } |
978 | 978 | ||
979 | static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) | 979 | static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) |
980 | { | 980 | { |
981 | struct snd_soc_dpcm *dpcm; | 981 | struct snd_soc_dpcm *dpcm; |
982 | 982 | ||
983 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | 983 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
984 | dpcm->be->dpcm[stream].runtime_update = | 984 | dpcm->be->dpcm[stream].runtime_update = |
985 | SND_SOC_DPCM_UPDATE_NO; | 985 | SND_SOC_DPCM_UPDATE_NO; |
986 | } | 986 | } |
987 | 987 | ||
988 | static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, | 988 | static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, |
989 | int stream) | 989 | int stream) |
990 | { | 990 | { |
991 | struct snd_soc_dpcm *dpcm; | 991 | struct snd_soc_dpcm *dpcm; |
992 | 992 | ||
993 | /* disable any enabled and non active backends */ | 993 | /* disable any enabled and non active backends */ |
994 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 994 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
995 | 995 | ||
996 | struct snd_soc_pcm_runtime *be = dpcm->be; | 996 | struct snd_soc_pcm_runtime *be = dpcm->be; |
997 | struct snd_pcm_substream *be_substream = | 997 | struct snd_pcm_substream *be_substream = |
998 | snd_soc_dpcm_get_substream(be, stream); | 998 | snd_soc_dpcm_get_substream(be, stream); |
999 | 999 | ||
1000 | if (be->dpcm[stream].users == 0) | 1000 | if (be->dpcm[stream].users == 0) |
1001 | dev_err(be->dev, "no users %s at close - state %d\n", | 1001 | dev_err(be->dev, "no users %s at close - state %d\n", |
1002 | stream ? "capture" : "playback", | 1002 | stream ? "capture" : "playback", |
1003 | be->dpcm[stream].state); | 1003 | be->dpcm[stream].state); |
1004 | 1004 | ||
1005 | if (--be->dpcm[stream].users != 0) | 1005 | if (--be->dpcm[stream].users != 0) |
1006 | continue; | 1006 | continue; |
1007 | 1007 | ||
1008 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) | 1008 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) |
1009 | continue; | 1009 | continue; |
1010 | 1010 | ||
1011 | soc_pcm_close(be_substream); | 1011 | soc_pcm_close(be_substream); |
1012 | be_substream->runtime = NULL; | 1012 | be_substream->runtime = NULL; |
1013 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1013 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1014 | } | 1014 | } |
1015 | } | 1015 | } |
1016 | 1016 | ||
1017 | static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) | 1017 | static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) |
1018 | { | 1018 | { |
1019 | struct snd_soc_dpcm *dpcm; | 1019 | struct snd_soc_dpcm *dpcm; |
1020 | int err, count = 0; | 1020 | int err, count = 0; |
1021 | 1021 | ||
1022 | /* only startup BE DAIs that are either sinks or sources to this FE DAI */ | 1022 | /* only startup BE DAIs that are either sinks or sources to this FE DAI */ |
1023 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1023 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1024 | 1024 | ||
1025 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1025 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1026 | struct snd_pcm_substream *be_substream = | 1026 | struct snd_pcm_substream *be_substream = |
1027 | snd_soc_dpcm_get_substream(be, stream); | 1027 | snd_soc_dpcm_get_substream(be, stream); |
1028 | 1028 | ||
1029 | /* is this op for this BE ? */ | 1029 | /* is this op for this BE ? */ |
1030 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1030 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1031 | continue; | 1031 | continue; |
1032 | 1032 | ||
1033 | /* first time the dpcm is open ? */ | 1033 | /* first time the dpcm is open ? */ |
1034 | if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) | 1034 | if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) |
1035 | dev_err(be->dev, "too many users %s at open %d\n", | 1035 | dev_err(be->dev, "too many users %s at open %d\n", |
1036 | stream ? "capture" : "playback", | 1036 | stream ? "capture" : "playback", |
1037 | be->dpcm[stream].state); | 1037 | be->dpcm[stream].state); |
1038 | 1038 | ||
1039 | if (be->dpcm[stream].users++ != 0) | 1039 | if (be->dpcm[stream].users++ != 0) |
1040 | continue; | 1040 | continue; |
1041 | 1041 | ||
1042 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && | 1042 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && |
1043 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) | 1043 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) |
1044 | continue; | 1044 | continue; |
1045 | 1045 | ||
1046 | dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name); | 1046 | dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name); |
1047 | 1047 | ||
1048 | be_substream->runtime = be->dpcm[stream].runtime; | 1048 | be_substream->runtime = be->dpcm[stream].runtime; |
1049 | err = soc_pcm_open(be_substream); | 1049 | err = soc_pcm_open(be_substream); |
1050 | if (err < 0) { | 1050 | if (err < 0) { |
1051 | dev_err(be->dev, "BE open failed %d\n", err); | 1051 | dev_err(be->dev, "BE open failed %d\n", err); |
1052 | be->dpcm[stream].users--; | 1052 | be->dpcm[stream].users--; |
1053 | if (be->dpcm[stream].users < 0) | 1053 | if (be->dpcm[stream].users < 0) |
1054 | dev_err(be->dev, "no users %s at unwind %d\n", | 1054 | dev_err(be->dev, "no users %s at unwind %d\n", |
1055 | stream ? "capture" : "playback", | 1055 | stream ? "capture" : "playback", |
1056 | be->dpcm[stream].state); | 1056 | be->dpcm[stream].state); |
1057 | 1057 | ||
1058 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1058 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1059 | goto unwind; | 1059 | goto unwind; |
1060 | } | 1060 | } |
1061 | 1061 | ||
1062 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | 1062 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; |
1063 | count++; | 1063 | count++; |
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | return count; | 1066 | return count; |
1067 | 1067 | ||
1068 | unwind: | 1068 | unwind: |
1069 | /* disable any enabled and non active backends */ | 1069 | /* disable any enabled and non active backends */ |
1070 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1070 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1071 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1071 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1072 | struct snd_pcm_substream *be_substream = | 1072 | struct snd_pcm_substream *be_substream = |
1073 | snd_soc_dpcm_get_substream(be, stream); | 1073 | snd_soc_dpcm_get_substream(be, stream); |
1074 | 1074 | ||
1075 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1075 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1076 | continue; | 1076 | continue; |
1077 | 1077 | ||
1078 | if (be->dpcm[stream].users == 0) | 1078 | if (be->dpcm[stream].users == 0) |
1079 | dev_err(be->dev, "no users %s at close %d\n", | 1079 | dev_err(be->dev, "no users %s at close %d\n", |
1080 | stream ? "capture" : "playback", | 1080 | stream ? "capture" : "playback", |
1081 | be->dpcm[stream].state); | 1081 | be->dpcm[stream].state); |
1082 | 1082 | ||
1083 | if (--be->dpcm[stream].users != 0) | 1083 | if (--be->dpcm[stream].users != 0) |
1084 | continue; | 1084 | continue; |
1085 | 1085 | ||
1086 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) | 1086 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) |
1087 | continue; | 1087 | continue; |
1088 | 1088 | ||
1089 | soc_pcm_close(be_substream); | 1089 | soc_pcm_close(be_substream); |
1090 | be_substream->runtime = NULL; | 1090 | be_substream->runtime = NULL; |
1091 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1091 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | return err; | 1094 | return err; |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) | 1097 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) |
1098 | { | 1098 | { |
1099 | struct snd_pcm_runtime *runtime = substream->runtime; | 1099 | struct snd_pcm_runtime *runtime = substream->runtime; |
1100 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1100 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1101 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1101 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1102 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 1102 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; |
1103 | 1103 | ||
1104 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1104 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
1105 | runtime->hw.rate_min = cpu_dai_drv->playback.rate_min; | 1105 | runtime->hw.rate_min = cpu_dai_drv->playback.rate_min; |
1106 | runtime->hw.rate_max = cpu_dai_drv->playback.rate_max; | 1106 | runtime->hw.rate_max = cpu_dai_drv->playback.rate_max; |
1107 | runtime->hw.channels_min = cpu_dai_drv->playback.channels_min; | 1107 | runtime->hw.channels_min = cpu_dai_drv->playback.channels_min; |
1108 | runtime->hw.channels_max = cpu_dai_drv->playback.channels_max; | 1108 | runtime->hw.channels_max = cpu_dai_drv->playback.channels_max; |
1109 | runtime->hw.formats &= cpu_dai_drv->playback.formats; | 1109 | runtime->hw.formats &= cpu_dai_drv->playback.formats; |
1110 | runtime->hw.rates = cpu_dai_drv->playback.rates; | 1110 | runtime->hw.rates = cpu_dai_drv->playback.rates; |
1111 | } else { | 1111 | } else { |
1112 | runtime->hw.rate_min = cpu_dai_drv->capture.rate_min; | 1112 | runtime->hw.rate_min = cpu_dai_drv->capture.rate_min; |
1113 | runtime->hw.rate_max = cpu_dai_drv->capture.rate_max; | 1113 | runtime->hw.rate_max = cpu_dai_drv->capture.rate_max; |
1114 | runtime->hw.channels_min = cpu_dai_drv->capture.channels_min; | 1114 | runtime->hw.channels_min = cpu_dai_drv->capture.channels_min; |
1115 | runtime->hw.channels_max = cpu_dai_drv->capture.channels_max; | 1115 | runtime->hw.channels_max = cpu_dai_drv->capture.channels_max; |
1116 | runtime->hw.formats &= cpu_dai_drv->capture.formats; | 1116 | runtime->hw.formats &= cpu_dai_drv->capture.formats; |
1117 | runtime->hw.rates = cpu_dai_drv->capture.rates; | 1117 | runtime->hw.rates = cpu_dai_drv->capture.rates; |
1118 | } | 1118 | } |
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) | 1121 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) |
1122 | { | 1122 | { |
1123 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | 1123 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
1124 | struct snd_pcm_runtime *runtime = fe_substream->runtime; | 1124 | struct snd_pcm_runtime *runtime = fe_substream->runtime; |
1125 | int stream = fe_substream->stream, ret = 0; | 1125 | int stream = fe_substream->stream, ret = 0; |
1126 | 1126 | ||
1127 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1127 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1128 | 1128 | ||
1129 | ret = dpcm_be_dai_startup(fe, fe_substream->stream); | 1129 | ret = dpcm_be_dai_startup(fe, fe_substream->stream); |
1130 | if (ret < 0) { | 1130 | if (ret < 0) { |
1131 | dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret); | 1131 | dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret); |
1132 | goto be_err; | 1132 | goto be_err; |
1133 | } | 1133 | } |
1134 | 1134 | ||
1135 | dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name); | 1135 | dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name); |
1136 | 1136 | ||
1137 | /* start the DAI frontend */ | 1137 | /* start the DAI frontend */ |
1138 | ret = soc_pcm_open(fe_substream); | 1138 | ret = soc_pcm_open(fe_substream); |
1139 | if (ret < 0) { | 1139 | if (ret < 0) { |
1140 | dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret); | 1140 | dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret); |
1141 | goto unwind; | 1141 | goto unwind; |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | 1144 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; |
1145 | 1145 | ||
1146 | dpcm_set_fe_runtime(fe_substream); | 1146 | dpcm_set_fe_runtime(fe_substream); |
1147 | snd_pcm_limit_hw_rates(runtime); | 1147 | snd_pcm_limit_hw_rates(runtime); |
1148 | 1148 | ||
1149 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1149 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1150 | return 0; | 1150 | return 0; |
1151 | 1151 | ||
1152 | unwind: | 1152 | unwind: |
1153 | dpcm_be_dai_startup_unwind(fe, fe_substream->stream); | 1153 | dpcm_be_dai_startup_unwind(fe, fe_substream->stream); |
1154 | be_err: | 1154 | be_err: |
1155 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1155 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1156 | return ret; | 1156 | return ret; |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) | 1159 | static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) |
1160 | { | 1160 | { |
1161 | struct snd_soc_dpcm *dpcm; | 1161 | struct snd_soc_dpcm *dpcm; |
1162 | 1162 | ||
1163 | /* only shutdown BEs that are either sinks or sources to this FE DAI */ | 1163 | /* only shutdown BEs that are either sinks or sources to this FE DAI */ |
1164 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1164 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1165 | 1165 | ||
1166 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1166 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1167 | struct snd_pcm_substream *be_substream = | 1167 | struct snd_pcm_substream *be_substream = |
1168 | snd_soc_dpcm_get_substream(be, stream); | 1168 | snd_soc_dpcm_get_substream(be, stream); |
1169 | 1169 | ||
1170 | /* is this op for this BE ? */ | 1170 | /* is this op for this BE ? */ |
1171 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1171 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1172 | continue; | 1172 | continue; |
1173 | 1173 | ||
1174 | if (be->dpcm[stream].users == 0) | 1174 | if (be->dpcm[stream].users == 0) |
1175 | dev_err(be->dev, "no users %s at close - state %d\n", | 1175 | dev_err(be->dev, "no users %s at close - state %d\n", |
1176 | stream ? "capture" : "playback", | 1176 | stream ? "capture" : "playback", |
1177 | be->dpcm[stream].state); | 1177 | be->dpcm[stream].state); |
1178 | 1178 | ||
1179 | if (--be->dpcm[stream].users != 0) | 1179 | if (--be->dpcm[stream].users != 0) |
1180 | continue; | 1180 | continue; |
1181 | 1181 | ||
1182 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1182 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
1183 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) | 1183 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) |
1184 | continue; | 1184 | continue; |
1185 | 1185 | ||
1186 | dev_dbg(be->dev, "dpcm: close BE %s\n", | 1186 | dev_dbg(be->dev, "dpcm: close BE %s\n", |
1187 | dpcm->fe->dai_link->name); | 1187 | dpcm->fe->dai_link->name); |
1188 | 1188 | ||
1189 | soc_pcm_close(be_substream); | 1189 | soc_pcm_close(be_substream); |
1190 | be_substream->runtime = NULL; | 1190 | be_substream->runtime = NULL; |
1191 | 1191 | ||
1192 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1192 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1193 | } | 1193 | } |
1194 | return 0; | 1194 | return 0; |
1195 | } | 1195 | } |
1196 | 1196 | ||
1197 | static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) | 1197 | static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) |
1198 | { | 1198 | { |
1199 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1199 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1200 | int stream = substream->stream; | 1200 | int stream = substream->stream; |
1201 | 1201 | ||
1202 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1202 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1203 | 1203 | ||
1204 | /* shutdown the BEs */ | 1204 | /* shutdown the BEs */ |
1205 | dpcm_be_dai_shutdown(fe, substream->stream); | 1205 | dpcm_be_dai_shutdown(fe, substream->stream); |
1206 | 1206 | ||
1207 | dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name); | 1207 | dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name); |
1208 | 1208 | ||
1209 | /* now shutdown the frontend */ | 1209 | /* now shutdown the frontend */ |
1210 | soc_pcm_close(substream); | 1210 | soc_pcm_close(substream); |
1211 | 1211 | ||
1212 | /* run the stream event for each BE */ | 1212 | /* run the stream event for each BE */ |
1213 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | 1213 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); |
1214 | 1214 | ||
1215 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 1215 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
1216 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1216 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1217 | return 0; | 1217 | return 0; |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | 1220 | static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) |
1221 | { | 1221 | { |
1222 | struct snd_soc_dpcm *dpcm; | 1222 | struct snd_soc_dpcm *dpcm; |
1223 | 1223 | ||
1224 | /* only hw_params backends that are either sinks or sources | 1224 | /* only hw_params backends that are either sinks or sources |
1225 | * to this frontend DAI */ | 1225 | * to this frontend DAI */ |
1226 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1226 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1227 | 1227 | ||
1228 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1228 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1229 | struct snd_pcm_substream *be_substream = | 1229 | struct snd_pcm_substream *be_substream = |
1230 | snd_soc_dpcm_get_substream(be, stream); | 1230 | snd_soc_dpcm_get_substream(be, stream); |
1231 | 1231 | ||
1232 | /* is this op for this BE ? */ | 1232 | /* is this op for this BE ? */ |
1233 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1233 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1234 | continue; | 1234 | continue; |
1235 | 1235 | ||
1236 | /* only free hw when no longer used - check all FEs */ | 1236 | /* only free hw when no longer used - check all FEs */ |
1237 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1237 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1238 | continue; | 1238 | continue; |
1239 | 1239 | ||
1240 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1240 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1241 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1241 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1242 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1242 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
1243 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | 1243 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) |
1244 | continue; | 1244 | continue; |
1245 | 1245 | ||
1246 | dev_dbg(be->dev, "dpcm: hw_free BE %s\n", | 1246 | dev_dbg(be->dev, "dpcm: hw_free BE %s\n", |
1247 | dpcm->fe->dai_link->name); | 1247 | dpcm->fe->dai_link->name); |
1248 | 1248 | ||
1249 | soc_pcm_hw_free(be_substream); | 1249 | soc_pcm_hw_free(be_substream); |
1250 | 1250 | ||
1251 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; | 1251 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | return 0; | 1254 | return 0; |
1255 | } | 1255 | } |
1256 | 1256 | ||
1257 | static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) | 1257 | static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) |
1258 | { | 1258 | { |
1259 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1259 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1260 | int err, stream = substream->stream; | 1260 | int err, stream = substream->stream; |
1261 | 1261 | ||
1262 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1262 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1263 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1263 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1264 | 1264 | ||
1265 | dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name); | 1265 | dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name); |
1266 | 1266 | ||
1267 | /* call hw_free on the frontend */ | 1267 | /* call hw_free on the frontend */ |
1268 | err = soc_pcm_hw_free(substream); | 1268 | err = soc_pcm_hw_free(substream); |
1269 | if (err < 0) | 1269 | if (err < 0) |
1270 | dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", | 1270 | dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", |
1271 | fe->dai_link->name); | 1271 | fe->dai_link->name); |
1272 | 1272 | ||
1273 | /* only hw_params backends that are either sinks or sources | 1273 | /* only hw_params backends that are either sinks or sources |
1274 | * to this frontend DAI */ | 1274 | * to this frontend DAI */ |
1275 | err = dpcm_be_dai_hw_free(fe, stream); | 1275 | err = dpcm_be_dai_hw_free(fe, stream); |
1276 | 1276 | ||
1277 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; | 1277 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; |
1278 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1278 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1279 | 1279 | ||
1280 | mutex_unlock(&fe->card->mutex); | 1280 | mutex_unlock(&fe->card->mutex); |
1281 | return 0; | 1281 | return 0; |
1282 | } | 1282 | } |
1283 | 1283 | ||
1284 | static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) | 1284 | static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) |
1285 | { | 1285 | { |
1286 | struct snd_soc_dpcm *dpcm; | 1286 | struct snd_soc_dpcm *dpcm; |
1287 | int ret; | 1287 | int ret; |
1288 | 1288 | ||
1289 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1289 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1290 | 1290 | ||
1291 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1291 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1292 | struct snd_pcm_substream *be_substream = | 1292 | struct snd_pcm_substream *be_substream = |
1293 | snd_soc_dpcm_get_substream(be, stream); | 1293 | snd_soc_dpcm_get_substream(be, stream); |
1294 | 1294 | ||
1295 | /* is this op for this BE ? */ | 1295 | /* is this op for this BE ? */ |
1296 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1296 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1297 | continue; | 1297 | continue; |
1298 | 1298 | ||
1299 | /* only allow hw_params() if no connected FEs are running */ | 1299 | /* only allow hw_params() if no connected FEs are running */ |
1300 | if (!snd_soc_dpcm_can_be_params(fe, be, stream)) | 1300 | if (!snd_soc_dpcm_can_be_params(fe, be, stream)) |
1301 | continue; | 1301 | continue; |
1302 | 1302 | ||
1303 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && | 1303 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && |
1304 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1304 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1305 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) | 1305 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) |
1306 | continue; | 1306 | continue; |
1307 | 1307 | ||
1308 | dev_dbg(be->dev, "dpcm: hw_params BE %s\n", | 1308 | dev_dbg(be->dev, "dpcm: hw_params BE %s\n", |
1309 | dpcm->fe->dai_link->name); | 1309 | dpcm->fe->dai_link->name); |
1310 | 1310 | ||
1311 | /* copy params for each dpcm */ | 1311 | /* copy params for each dpcm */ |
1312 | memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params, | 1312 | memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params, |
1313 | sizeof(struct snd_pcm_hw_params)); | 1313 | sizeof(struct snd_pcm_hw_params)); |
1314 | 1314 | ||
1315 | /* perform any hw_params fixups */ | 1315 | /* perform any hw_params fixups */ |
1316 | if (be->dai_link->be_hw_params_fixup) { | 1316 | if (be->dai_link->be_hw_params_fixup) { |
1317 | ret = be->dai_link->be_hw_params_fixup(be, | 1317 | ret = be->dai_link->be_hw_params_fixup(be, |
1318 | &dpcm->hw_params); | 1318 | &dpcm->hw_params); |
1319 | if (ret < 0) { | 1319 | if (ret < 0) { |
1320 | dev_err(be->dev, | 1320 | dev_err(be->dev, |
1321 | "dpcm: hw_params BE fixup failed %d\n", | 1321 | "dpcm: hw_params BE fixup failed %d\n", |
1322 | ret); | 1322 | ret); |
1323 | goto unwind; | 1323 | goto unwind; |
1324 | } | 1324 | } |
1325 | } | 1325 | } |
1326 | 1326 | ||
1327 | ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); | 1327 | ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); |
1328 | if (ret < 0) { | 1328 | if (ret < 0) { |
1329 | dev_err(dpcm->be->dev, | 1329 | dev_err(dpcm->be->dev, |
1330 | "dpcm: hw_params BE failed %d\n", ret); | 1330 | "dpcm: hw_params BE failed %d\n", ret); |
1331 | goto unwind; | 1331 | goto unwind; |
1332 | } | 1332 | } |
1333 | 1333 | ||
1334 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; | 1334 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; |
1335 | } | 1335 | } |
1336 | return 0; | 1336 | return 0; |
1337 | 1337 | ||
1338 | unwind: | 1338 | unwind: |
1339 | /* disable any enabled and non active backends */ | 1339 | /* disable any enabled and non active backends */ |
1340 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1340 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1341 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1341 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1342 | struct snd_pcm_substream *be_substream = | 1342 | struct snd_pcm_substream *be_substream = |
1343 | snd_soc_dpcm_get_substream(be, stream); | 1343 | snd_soc_dpcm_get_substream(be, stream); |
1344 | 1344 | ||
1345 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1345 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1346 | continue; | 1346 | continue; |
1347 | 1347 | ||
1348 | /* only allow hw_free() if no connected FEs are running */ | 1348 | /* only allow hw_free() if no connected FEs are running */ |
1349 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1349 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1350 | continue; | 1350 | continue; |
1351 | 1351 | ||
1352 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && | 1352 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && |
1353 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1353 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1354 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1354 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
1355 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | 1355 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) |
1356 | continue; | 1356 | continue; |
1357 | 1357 | ||
1358 | soc_pcm_hw_free(be_substream); | 1358 | soc_pcm_hw_free(be_substream); |
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | return ret; | 1361 | return ret; |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, | 1364 | static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, |
1365 | struct snd_pcm_hw_params *params) | 1365 | struct snd_pcm_hw_params *params) |
1366 | { | 1366 | { |
1367 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1367 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1368 | int ret, stream = substream->stream; | 1368 | int ret, stream = substream->stream; |
1369 | 1369 | ||
1370 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1370 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1371 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1371 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1372 | 1372 | ||
1373 | memcpy(&fe->dpcm[substream->stream].hw_params, params, | 1373 | memcpy(&fe->dpcm[substream->stream].hw_params, params, |
1374 | sizeof(struct snd_pcm_hw_params)); | 1374 | sizeof(struct snd_pcm_hw_params)); |
1375 | ret = dpcm_be_dai_hw_params(fe, substream->stream); | 1375 | ret = dpcm_be_dai_hw_params(fe, substream->stream); |
1376 | if (ret < 0) { | 1376 | if (ret < 0) { |
1377 | dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret); | 1377 | dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret); |
1378 | goto out; | 1378 | goto out; |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n", | 1381 | dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n", |
1382 | fe->dai_link->name, params_rate(params), | 1382 | fe->dai_link->name, params_rate(params), |
1383 | params_channels(params), params_format(params)); | 1383 | params_channels(params), params_format(params)); |
1384 | 1384 | ||
1385 | /* call hw_params on the frontend */ | 1385 | /* call hw_params on the frontend */ |
1386 | ret = soc_pcm_hw_params(substream, params); | 1386 | ret = soc_pcm_hw_params(substream, params); |
1387 | if (ret < 0) { | 1387 | if (ret < 0) { |
1388 | dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret); | 1388 | dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret); |
1389 | dpcm_be_dai_hw_free(fe, stream); | 1389 | dpcm_be_dai_hw_free(fe, stream); |
1390 | } else | 1390 | } else |
1391 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; | 1391 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; |
1392 | 1392 | ||
1393 | out: | 1393 | out: |
1394 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1394 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1395 | mutex_unlock(&fe->card->mutex); | 1395 | mutex_unlock(&fe->card->mutex); |
1396 | return ret; | 1396 | return ret; |
1397 | } | 1397 | } |
1398 | 1398 | ||
1399 | static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, | 1399 | static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, |
1400 | struct snd_pcm_substream *substream, int cmd) | 1400 | struct snd_pcm_substream *substream, int cmd) |
1401 | { | 1401 | { |
1402 | int ret; | 1402 | int ret; |
1403 | 1403 | ||
1404 | dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n", | 1404 | dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n", |
1405 | dpcm->fe->dai_link->name, cmd); | 1405 | dpcm->fe->dai_link->name, cmd); |
1406 | 1406 | ||
1407 | ret = soc_pcm_trigger(substream, cmd); | 1407 | ret = soc_pcm_trigger(substream, cmd); |
1408 | if (ret < 0) | 1408 | if (ret < 0) |
1409 | dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret); | 1409 | dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret); |
1410 | 1410 | ||
1411 | return ret; | 1411 | return ret; |
1412 | } | 1412 | } |
1413 | 1413 | ||
1414 | static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, | 1414 | static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, |
1415 | int cmd) | 1415 | int cmd) |
1416 | { | 1416 | { |
1417 | struct snd_soc_dpcm *dpcm; | 1417 | struct snd_soc_dpcm *dpcm; |
1418 | int ret = 0; | 1418 | int ret = 0; |
1419 | 1419 | ||
1420 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1420 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1421 | 1421 | ||
1422 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1422 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1423 | struct snd_pcm_substream *be_substream = | 1423 | struct snd_pcm_substream *be_substream = |
1424 | snd_soc_dpcm_get_substream(be, stream); | 1424 | snd_soc_dpcm_get_substream(be, stream); |
1425 | 1425 | ||
1426 | /* is this op for this BE ? */ | 1426 | /* is this op for this BE ? */ |
1427 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1427 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1428 | continue; | 1428 | continue; |
1429 | 1429 | ||
1430 | switch (cmd) { | 1430 | switch (cmd) { |
1431 | case SNDRV_PCM_TRIGGER_START: | 1431 | case SNDRV_PCM_TRIGGER_START: |
1432 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1432 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1433 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | 1433 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) |
1434 | continue; | 1434 | continue; |
1435 | 1435 | ||
1436 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1436 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1437 | if (ret) | 1437 | if (ret) |
1438 | return ret; | 1438 | return ret; |
1439 | 1439 | ||
1440 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | 1440 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; |
1441 | break; | 1441 | break; |
1442 | case SNDRV_PCM_TRIGGER_RESUME: | 1442 | case SNDRV_PCM_TRIGGER_RESUME: |
1443 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) | 1443 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) |
1444 | continue; | 1444 | continue; |
1445 | 1445 | ||
1446 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1446 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1447 | if (ret) | 1447 | if (ret) |
1448 | return ret; | 1448 | return ret; |
1449 | 1449 | ||
1450 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | 1450 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; |
1451 | break; | 1451 | break; |
1452 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1452 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1453 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) | 1453 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) |
1454 | continue; | 1454 | continue; |
1455 | 1455 | ||
1456 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1456 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1457 | if (ret) | 1457 | if (ret) |
1458 | return ret; | 1458 | return ret; |
1459 | 1459 | ||
1460 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | 1460 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; |
1461 | break; | 1461 | break; |
1462 | case SNDRV_PCM_TRIGGER_STOP: | 1462 | case SNDRV_PCM_TRIGGER_STOP: |
1463 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | 1463 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) |
1464 | continue; | 1464 | continue; |
1465 | 1465 | ||
1466 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1466 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1467 | continue; | 1467 | continue; |
1468 | 1468 | ||
1469 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1469 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1470 | if (ret) | 1470 | if (ret) |
1471 | return ret; | 1471 | return ret; |
1472 | 1472 | ||
1473 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; | 1473 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; |
1474 | break; | 1474 | break; |
1475 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1475 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1476 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) | 1476 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) |
1477 | continue; | 1477 | continue; |
1478 | 1478 | ||
1479 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1479 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1480 | continue; | 1480 | continue; |
1481 | 1481 | ||
1482 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1482 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1483 | if (ret) | 1483 | if (ret) |
1484 | return ret; | 1484 | return ret; |
1485 | 1485 | ||
1486 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; | 1486 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; |
1487 | break; | 1487 | break; |
1488 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1488 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1489 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | 1489 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) |
1490 | continue; | 1490 | continue; |
1491 | 1491 | ||
1492 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1492 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1493 | continue; | 1493 | continue; |
1494 | 1494 | ||
1495 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | 1495 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); |
1496 | if (ret) | 1496 | if (ret) |
1497 | return ret; | 1497 | return ret; |
1498 | 1498 | ||
1499 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; | 1499 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; |
1500 | break; | 1500 | break; |
1501 | } | 1501 | } |
1502 | } | 1502 | } |
1503 | 1503 | ||
1504 | return ret; | 1504 | return ret; |
1505 | } | 1505 | } |
1506 | EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); | 1506 | EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); |
1507 | 1507 | ||
1508 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) | 1508 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) |
1509 | { | 1509 | { |
1510 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1510 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1511 | int stream = substream->stream, ret; | 1511 | int stream = substream->stream, ret; |
1512 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | 1512 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; |
1513 | 1513 | ||
1514 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1514 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1515 | 1515 | ||
1516 | switch (trigger) { | 1516 | switch (trigger) { |
1517 | case SND_SOC_DPCM_TRIGGER_PRE: | 1517 | case SND_SOC_DPCM_TRIGGER_PRE: |
1518 | /* call trigger on the frontend before the backend. */ | 1518 | /* call trigger on the frontend before the backend. */ |
1519 | 1519 | ||
1520 | dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n", | 1520 | dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n", |
1521 | fe->dai_link->name, cmd); | 1521 | fe->dai_link->name, cmd); |
1522 | 1522 | ||
1523 | ret = soc_pcm_trigger(substream, cmd); | 1523 | ret = soc_pcm_trigger(substream, cmd); |
1524 | if (ret < 0) { | 1524 | if (ret < 0) { |
1525 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | 1525 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); |
1526 | goto out; | 1526 | goto out; |
1527 | } | 1527 | } |
1528 | 1528 | ||
1529 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); | 1529 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); |
1530 | break; | 1530 | break; |
1531 | case SND_SOC_DPCM_TRIGGER_POST: | 1531 | case SND_SOC_DPCM_TRIGGER_POST: |
1532 | /* call trigger on the frontend after the backend. */ | 1532 | /* call trigger on the frontend after the backend. */ |
1533 | 1533 | ||
1534 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); | 1534 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); |
1535 | if (ret < 0) { | 1535 | if (ret < 0) { |
1536 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | 1536 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); |
1537 | goto out; | 1537 | goto out; |
1538 | } | 1538 | } |
1539 | 1539 | ||
1540 | dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n", | 1540 | dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n", |
1541 | fe->dai_link->name, cmd); | 1541 | fe->dai_link->name, cmd); |
1542 | 1542 | ||
1543 | ret = soc_pcm_trigger(substream, cmd); | 1543 | ret = soc_pcm_trigger(substream, cmd); |
1544 | break; | 1544 | break; |
1545 | case SND_SOC_DPCM_TRIGGER_BESPOKE: | 1545 | case SND_SOC_DPCM_TRIGGER_BESPOKE: |
1546 | /* bespoke trigger() - handles both FE and BEs */ | 1546 | /* bespoke trigger() - handles both FE and BEs */ |
1547 | 1547 | ||
1548 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", | 1548 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", |
1549 | fe->dai_link->name, cmd); | 1549 | fe->dai_link->name, cmd); |
1550 | 1550 | ||
1551 | ret = soc_pcm_bespoke_trigger(substream, cmd); | 1551 | ret = soc_pcm_bespoke_trigger(substream, cmd); |
1552 | if (ret < 0) { | 1552 | if (ret < 0) { |
1553 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | 1553 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); |
1554 | goto out; | 1554 | goto out; |
1555 | } | 1555 | } |
1556 | break; | 1556 | break; |
1557 | default: | 1557 | default: |
1558 | dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, | 1558 | dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, |
1559 | fe->dai_link->name); | 1559 | fe->dai_link->name); |
1560 | ret = -EINVAL; | 1560 | ret = -EINVAL; |
1561 | goto out; | 1561 | goto out; |
1562 | } | 1562 | } |
1563 | 1563 | ||
1564 | switch (cmd) { | 1564 | switch (cmd) { |
1565 | case SNDRV_PCM_TRIGGER_START: | 1565 | case SNDRV_PCM_TRIGGER_START: |
1566 | case SNDRV_PCM_TRIGGER_RESUME: | 1566 | case SNDRV_PCM_TRIGGER_RESUME: |
1567 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1567 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1568 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | 1568 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; |
1569 | break; | 1569 | break; |
1570 | case SNDRV_PCM_TRIGGER_STOP: | 1570 | case SNDRV_PCM_TRIGGER_STOP: |
1571 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1571 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1572 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1572 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1573 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; | 1573 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; |
1574 | break; | 1574 | break; |
1575 | } | 1575 | } |
1576 | 1576 | ||
1577 | out: | 1577 | out: |
1578 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1578 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1579 | return ret; | 1579 | return ret; |
1580 | } | 1580 | } |
1581 | 1581 | ||
1582 | static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) | 1582 | static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) |
1583 | { | 1583 | { |
1584 | struct snd_soc_dpcm *dpcm; | 1584 | struct snd_soc_dpcm *dpcm; |
1585 | int ret = 0; | 1585 | int ret = 0; |
1586 | 1586 | ||
1587 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1587 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1588 | 1588 | ||
1589 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1589 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1590 | struct snd_pcm_substream *be_substream = | 1590 | struct snd_pcm_substream *be_substream = |
1591 | snd_soc_dpcm_get_substream(be, stream); | 1591 | snd_soc_dpcm_get_substream(be, stream); |
1592 | 1592 | ||
1593 | /* is this op for this BE ? */ | 1593 | /* is this op for this BE ? */ |
1594 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | 1594 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) |
1595 | continue; | 1595 | continue; |
1596 | 1596 | ||
1597 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1597 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1598 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | 1598 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) |
1599 | continue; | 1599 | continue; |
1600 | 1600 | ||
1601 | dev_dbg(be->dev, "dpcm: prepare BE %s\n", | 1601 | dev_dbg(be->dev, "dpcm: prepare BE %s\n", |
1602 | dpcm->fe->dai_link->name); | 1602 | dpcm->fe->dai_link->name); |
1603 | 1603 | ||
1604 | ret = soc_pcm_prepare(be_substream); | 1604 | ret = soc_pcm_prepare(be_substream); |
1605 | if (ret < 0) { | 1605 | if (ret < 0) { |
1606 | dev_err(be->dev, "dpcm: backend prepare failed %d\n", | 1606 | dev_err(be->dev, "dpcm: backend prepare failed %d\n", |
1607 | ret); | 1607 | ret); |
1608 | break; | 1608 | break; |
1609 | } | 1609 | } |
1610 | 1610 | ||
1611 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | 1611 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; |
1612 | } | 1612 | } |
1613 | return ret; | 1613 | return ret; |
1614 | } | 1614 | } |
1615 | 1615 | ||
1616 | static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) | 1616 | static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) |
1617 | { | 1617 | { |
1618 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 1618 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
1619 | int stream = substream->stream, ret = 0; | 1619 | int stream = substream->stream, ret = 0; |
1620 | 1620 | ||
1621 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1621 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1622 | 1622 | ||
1623 | dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name); | 1623 | dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name); |
1624 | 1624 | ||
1625 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 1625 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
1626 | 1626 | ||
1627 | /* there is no point preparing this FE if there are no BEs */ | 1627 | /* there is no point preparing this FE if there are no BEs */ |
1628 | if (list_empty(&fe->dpcm[stream].be_clients)) { | 1628 | if (list_empty(&fe->dpcm[stream].be_clients)) { |
1629 | dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n", | 1629 | dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n", |
1630 | fe->dai_link->name); | 1630 | fe->dai_link->name); |
1631 | ret = -EINVAL; | 1631 | ret = -EINVAL; |
1632 | goto out; | 1632 | goto out; |
1633 | } | 1633 | } |
1634 | 1634 | ||
1635 | ret = dpcm_be_dai_prepare(fe, substream->stream); | 1635 | ret = dpcm_be_dai_prepare(fe, substream->stream); |
1636 | if (ret < 0) | 1636 | if (ret < 0) |
1637 | goto out; | 1637 | goto out; |
1638 | 1638 | ||
1639 | /* call prepare on the frontend */ | 1639 | /* call prepare on the frontend */ |
1640 | ret = soc_pcm_prepare(substream); | 1640 | ret = soc_pcm_prepare(substream); |
1641 | if (ret < 0) { | 1641 | if (ret < 0) { |
1642 | dev_err(fe->dev,"dpcm: prepare FE %s failed\n", | 1642 | dev_err(fe->dev,"dpcm: prepare FE %s failed\n", |
1643 | fe->dai_link->name); | 1643 | fe->dai_link->name); |
1644 | goto out; | 1644 | goto out; |
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | /* run the stream event for each BE */ | 1647 | /* run the stream event for each BE */ |
1648 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | 1648 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); |
1649 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | 1649 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; |
1650 | 1650 | ||
1651 | out: | 1651 | out: |
1652 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1652 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1653 | mutex_unlock(&fe->card->mutex); | 1653 | mutex_unlock(&fe->card->mutex); |
1654 | 1654 | ||
1655 | return ret; | 1655 | return ret; |
1656 | } | 1656 | } |
1657 | 1657 | ||
1658 | static int soc_pcm_ioctl(struct snd_pcm_substream *substream, | 1658 | static int soc_pcm_ioctl(struct snd_pcm_substream *substream, |
1659 | unsigned int cmd, void *arg) | 1659 | unsigned int cmd, void *arg) |
1660 | { | 1660 | { |
1661 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1661 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1662 | struct snd_soc_platform *platform = rtd->platform; | 1662 | struct snd_soc_platform *platform = rtd->platform; |
1663 | 1663 | ||
1664 | if (platform->driver->ops->ioctl) | 1664 | if (platform->driver->ops->ioctl) |
1665 | return platform->driver->ops->ioctl(substream, cmd, arg); | 1665 | return platform->driver->ops->ioctl(substream, cmd, arg); |
1666 | return snd_pcm_lib_ioctl(substream, cmd, arg); | 1666 | return snd_pcm_lib_ioctl(substream, cmd, arg); |
1667 | } | 1667 | } |
1668 | 1668 | ||
1669 | static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) | 1669 | static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) |
1670 | { | 1670 | { |
1671 | struct snd_pcm_substream *substream = | 1671 | struct snd_pcm_substream *substream = |
1672 | snd_soc_dpcm_get_substream(fe, stream); | 1672 | snd_soc_dpcm_get_substream(fe, stream); |
1673 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | 1673 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; |
1674 | int err; | 1674 | int err; |
1675 | 1675 | ||
1676 | dev_dbg(fe->dev, "runtime %s close on FE %s\n", | 1676 | dev_dbg(fe->dev, "runtime %s close on FE %s\n", |
1677 | stream ? "capture" : "playback", fe->dai_link->name); | 1677 | stream ? "capture" : "playback", fe->dai_link->name); |
1678 | 1678 | ||
1679 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { | 1679 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { |
1680 | /* call bespoke trigger - FE takes care of all BE triggers */ | 1680 | /* call bespoke trigger - FE takes care of all BE triggers */ |
1681 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", | 1681 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", |
1682 | fe->dai_link->name); | 1682 | fe->dai_link->name); |
1683 | 1683 | ||
1684 | err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); | 1684 | err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); |
1685 | if (err < 0) | 1685 | if (err < 0) |
1686 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); | 1686 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); |
1687 | } else { | 1687 | } else { |
1688 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", | 1688 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", |
1689 | fe->dai_link->name); | 1689 | fe->dai_link->name); |
1690 | 1690 | ||
1691 | err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); | 1691 | err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); |
1692 | if (err < 0) | 1692 | if (err < 0) |
1693 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); | 1693 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); |
1694 | } | 1694 | } |
1695 | 1695 | ||
1696 | err = dpcm_be_dai_hw_free(fe, stream); | 1696 | err = dpcm_be_dai_hw_free(fe, stream); |
1697 | if (err < 0) | 1697 | if (err < 0) |
1698 | dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err); | 1698 | dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err); |
1699 | 1699 | ||
1700 | err = dpcm_be_dai_shutdown(fe, stream); | 1700 | err = dpcm_be_dai_shutdown(fe, stream); |
1701 | if (err < 0) | 1701 | if (err < 0) |
1702 | dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err); | 1702 | dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err); |
1703 | 1703 | ||
1704 | /* run the stream event for each BE */ | 1704 | /* run the stream event for each BE */ |
1705 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); | 1705 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); |
1706 | 1706 | ||
1707 | return 0; | 1707 | return 0; |
1708 | } | 1708 | } |
1709 | 1709 | ||
1710 | static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) | 1710 | static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) |
1711 | { | 1711 | { |
1712 | struct snd_pcm_substream *substream = | 1712 | struct snd_pcm_substream *substream = |
1713 | snd_soc_dpcm_get_substream(fe, stream); | 1713 | snd_soc_dpcm_get_substream(fe, stream); |
1714 | struct snd_soc_dpcm *dpcm; | 1714 | struct snd_soc_dpcm *dpcm; |
1715 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | 1715 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; |
1716 | int ret; | 1716 | int ret; |
1717 | 1717 | ||
1718 | dev_dbg(fe->dev, "runtime %s open on FE %s\n", | 1718 | dev_dbg(fe->dev, "runtime %s open on FE %s\n", |
1719 | stream ? "capture" : "playback", fe->dai_link->name); | 1719 | stream ? "capture" : "playback", fe->dai_link->name); |
1720 | 1720 | ||
1721 | /* Only start the BE if the FE is ready */ | 1721 | /* Only start the BE if the FE is ready */ |
1722 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || | 1722 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || |
1723 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) | 1723 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) |
1724 | return -EINVAL; | 1724 | return -EINVAL; |
1725 | 1725 | ||
1726 | /* startup must always be called for new BEs */ | 1726 | /* startup must always be called for new BEs */ |
1727 | ret = dpcm_be_dai_startup(fe, stream); | 1727 | ret = dpcm_be_dai_startup(fe, stream); |
1728 | if (ret < 0) { | 1728 | if (ret < 0) { |
1729 | goto disconnect; | 1729 | goto disconnect; |
1730 | return ret; | 1730 | return ret; |
1731 | } | 1731 | } |
1732 | 1732 | ||
1733 | /* keep going if FE state is > open */ | 1733 | /* keep going if FE state is > open */ |
1734 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN) | 1734 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN) |
1735 | return 0; | 1735 | return 0; |
1736 | 1736 | ||
1737 | ret = dpcm_be_dai_hw_params(fe, stream); | 1737 | ret = dpcm_be_dai_hw_params(fe, stream); |
1738 | if (ret < 0) { | 1738 | if (ret < 0) { |
1739 | goto close; | 1739 | goto close; |
1740 | return ret; | 1740 | return ret; |
1741 | } | 1741 | } |
1742 | 1742 | ||
1743 | /* keep going if FE state is > hw_params */ | 1743 | /* keep going if FE state is > hw_params */ |
1744 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS) | 1744 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS) |
1745 | return 0; | 1745 | return 0; |
1746 | 1746 | ||
1747 | 1747 | ||
1748 | ret = dpcm_be_dai_prepare(fe, stream); | 1748 | ret = dpcm_be_dai_prepare(fe, stream); |
1749 | if (ret < 0) { | 1749 | if (ret < 0) { |
1750 | goto hw_free; | 1750 | goto hw_free; |
1751 | return ret; | 1751 | return ret; |
1752 | } | 1752 | } |
1753 | 1753 | ||
1754 | /* run the stream event for each BE */ | 1754 | /* run the stream event for each BE */ |
1755 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); | 1755 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); |
1756 | 1756 | ||
1757 | /* keep going if FE state is > prepare */ | 1757 | /* keep going if FE state is > prepare */ |
1758 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE || | 1758 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE || |
1759 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) | 1759 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) |
1760 | return 0; | 1760 | return 0; |
1761 | 1761 | ||
1762 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { | 1762 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { |
1763 | /* call trigger on the frontend - FE takes care of all BE triggers */ | 1763 | /* call trigger on the frontend - FE takes care of all BE triggers */ |
1764 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", | 1764 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", |
1765 | fe->dai_link->name); | 1765 | fe->dai_link->name); |
1766 | 1766 | ||
1767 | ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); | 1767 | ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); |
1768 | if (ret < 0) { | 1768 | if (ret < 0) { |
1769 | dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); | 1769 | dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); |
1770 | goto hw_free; | 1770 | goto hw_free; |
1771 | } | 1771 | } |
1772 | } else { | 1772 | } else { |
1773 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", | 1773 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", |
1774 | fe->dai_link->name); | 1774 | fe->dai_link->name); |
1775 | 1775 | ||
1776 | ret = dpcm_be_dai_trigger(fe, stream, | 1776 | ret = dpcm_be_dai_trigger(fe, stream, |
1777 | SNDRV_PCM_TRIGGER_START); | 1777 | SNDRV_PCM_TRIGGER_START); |
1778 | if (ret < 0) { | 1778 | if (ret < 0) { |
1779 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | 1779 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); |
1780 | goto hw_free; | 1780 | goto hw_free; |
1781 | } | 1781 | } |
1782 | } | 1782 | } |
1783 | 1783 | ||
1784 | return 0; | 1784 | return 0; |
1785 | 1785 | ||
1786 | hw_free: | 1786 | hw_free: |
1787 | dpcm_be_dai_hw_free(fe, stream); | 1787 | dpcm_be_dai_hw_free(fe, stream); |
1788 | close: | 1788 | close: |
1789 | dpcm_be_dai_shutdown(fe, stream); | 1789 | dpcm_be_dai_shutdown(fe, stream); |
1790 | disconnect: | 1790 | disconnect: |
1791 | /* disconnect any non started BEs */ | 1791 | /* disconnect any non started BEs */ |
1792 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1792 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1793 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1793 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1794 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | 1794 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) |
1795 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 1795 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
1796 | } | 1796 | } |
1797 | 1797 | ||
1798 | return ret; | 1798 | return ret; |
1799 | } | 1799 | } |
1800 | 1800 | ||
1801 | static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) | 1801 | static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) |
1802 | { | 1802 | { |
1803 | int ret; | 1803 | int ret; |
1804 | 1804 | ||
1805 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 1805 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; |
1806 | ret = dpcm_run_update_startup(fe, stream); | 1806 | ret = dpcm_run_update_startup(fe, stream); |
1807 | if (ret < 0) | 1807 | if (ret < 0) |
1808 | dev_err(fe->dev, "failed to startup some BEs\n"); | 1808 | dev_err(fe->dev, "failed to startup some BEs\n"); |
1809 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1809 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1810 | 1810 | ||
1811 | return ret; | 1811 | return ret; |
1812 | } | 1812 | } |
1813 | 1813 | ||
1814 | static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) | 1814 | static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) |
1815 | { | 1815 | { |
1816 | int ret; | 1816 | int ret; |
1817 | 1817 | ||
1818 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | 1818 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; |
1819 | ret = dpcm_run_update_shutdown(fe, stream); | 1819 | ret = dpcm_run_update_shutdown(fe, stream); |
1820 | if (ret < 0) | 1820 | if (ret < 0) |
1821 | dev_err(fe->dev, "failed to shutdown some BEs\n"); | 1821 | dev_err(fe->dev, "failed to shutdown some BEs\n"); |
1822 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 1822 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
1823 | 1823 | ||
1824 | return ret; | 1824 | return ret; |
1825 | } | 1825 | } |
1826 | 1826 | ||
1827 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and | 1827 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and |
1828 | * any DAI links. | 1828 | * any DAI links. |
1829 | */ | 1829 | */ |
1830 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) | 1830 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) |
1831 | { | 1831 | { |
1832 | struct snd_soc_card *card; | 1832 | struct snd_soc_card *card; |
1833 | int i, old, new, paths; | 1833 | int i, old, new, paths; |
1834 | 1834 | ||
1835 | if (widget->codec) | 1835 | if (widget->codec) |
1836 | card = widget->codec->card; | 1836 | card = widget->codec->card; |
1837 | else if (widget->platform) | 1837 | else if (widget->platform) |
1838 | card = widget->platform->card; | 1838 | card = widget->platform->card; |
1839 | else | 1839 | else |
1840 | return -EINVAL; | 1840 | return -EINVAL; |
1841 | 1841 | ||
1842 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1842 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1843 | for (i = 0; i < card->num_rtd; i++) { | 1843 | for (i = 0; i < card->num_rtd; i++) { |
1844 | struct snd_soc_dapm_widget_list *list; | 1844 | struct snd_soc_dapm_widget_list *list; |
1845 | struct snd_soc_pcm_runtime *fe = &card->rtd[i]; | 1845 | struct snd_soc_pcm_runtime *fe = &card->rtd[i]; |
1846 | 1846 | ||
1847 | /* make sure link is FE */ | 1847 | /* make sure link is FE */ |
1848 | if (!fe->dai_link->dynamic) | 1848 | if (!fe->dai_link->dynamic) |
1849 | continue; | 1849 | continue; |
1850 | 1850 | ||
1851 | /* only check active links */ | 1851 | /* only check active links */ |
1852 | if (!fe->cpu_dai->active) | 1852 | if (!fe->cpu_dai->active) |
1853 | continue; | 1853 | continue; |
1854 | 1854 | ||
1855 | /* DAPM sync will call this to update DSP paths */ | 1855 | /* DAPM sync will call this to update DSP paths */ |
1856 | dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", | 1856 | dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", |
1857 | fe->dai_link->name); | 1857 | fe->dai_link->name); |
1858 | 1858 | ||
1859 | /* skip if FE doesn't have playback capability */ | 1859 | /* skip if FE doesn't have playback capability */ |
1860 | if (!fe->cpu_dai->driver->playback.channels_min) | 1860 | if (!fe->cpu_dai->driver->playback.channels_min) |
1861 | goto capture; | 1861 | goto capture; |
1862 | 1862 | ||
1863 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); | 1863 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); |
1864 | if (paths < 0) { | 1864 | if (paths < 0) { |
1865 | dev_warn(fe->dev, "%s no valid %s path\n", | 1865 | dev_warn(fe->dev, "%s no valid %s path\n", |
1866 | fe->dai_link->name, "playback"); | 1866 | fe->dai_link->name, "playback"); |
1867 | mutex_unlock(&card->mutex); | 1867 | mutex_unlock(&card->mutex); |
1868 | return paths; | 1868 | return paths; |
1869 | } | 1869 | } |
1870 | 1870 | ||
1871 | /* update any new playback paths */ | 1871 | /* update any new playback paths */ |
1872 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1); | 1872 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1); |
1873 | if (new) { | 1873 | if (new) { |
1874 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1874 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1875 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1875 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1876 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1876 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1877 | } | 1877 | } |
1878 | 1878 | ||
1879 | /* update any old playback paths */ | 1879 | /* update any old playback paths */ |
1880 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0); | 1880 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0); |
1881 | if (old) { | 1881 | if (old) { |
1882 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1882 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1883 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1883 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1884 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | 1884 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); |
1885 | } | 1885 | } |
1886 | 1886 | ||
1887 | capture: | 1887 | capture: |
1888 | /* skip if FE doesn't have capture capability */ | 1888 | /* skip if FE doesn't have capture capability */ |
1889 | if (!fe->cpu_dai->driver->capture.channels_min) | 1889 | if (!fe->cpu_dai->driver->capture.channels_min) |
1890 | continue; | 1890 | continue; |
1891 | 1891 | ||
1892 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); | 1892 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); |
1893 | if (paths < 0) { | 1893 | if (paths < 0) { |
1894 | dev_warn(fe->dev, "%s no valid %s path\n", | 1894 | dev_warn(fe->dev, "%s no valid %s path\n", |
1895 | fe->dai_link->name, "capture"); | 1895 | fe->dai_link->name, "capture"); |
1896 | mutex_unlock(&card->mutex); | 1896 | mutex_unlock(&card->mutex); |
1897 | return paths; | 1897 | return paths; |
1898 | } | 1898 | } |
1899 | 1899 | ||
1900 | /* update any new capture paths */ | 1900 | /* update any new capture paths */ |
1901 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1); | 1901 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1); |
1902 | if (new) { | 1902 | if (new) { |
1903 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); | 1903 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); |
1904 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); | 1904 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); |
1905 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); | 1905 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); |
1906 | } | 1906 | } |
1907 | 1907 | ||
1908 | /* update any old capture paths */ | 1908 | /* update any old capture paths */ |
1909 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0); | 1909 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0); |
1910 | if (old) { | 1910 | if (old) { |
1911 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); | 1911 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); |
1912 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); | 1912 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); |
1913 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); | 1913 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); |
1914 | } | 1914 | } |
1915 | 1915 | ||
1916 | dpcm_path_put(&list); | 1916 | dpcm_path_put(&list); |
1917 | } | 1917 | } |
1918 | 1918 | ||
1919 | mutex_unlock(&card->mutex); | 1919 | mutex_unlock(&card->mutex); |
1920 | return 0; | 1920 | return 0; |
1921 | } | 1921 | } |
1922 | int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) | 1922 | int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) |
1923 | { | 1923 | { |
1924 | struct snd_soc_dpcm *dpcm; | 1924 | struct snd_soc_dpcm *dpcm; |
1925 | struct list_head *clients = | 1925 | struct list_head *clients = |
1926 | &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; | 1926 | &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; |
1927 | 1927 | ||
1928 | list_for_each_entry(dpcm, clients, list_be) { | 1928 | list_for_each_entry(dpcm, clients, list_be) { |
1929 | 1929 | ||
1930 | struct snd_soc_pcm_runtime *be = dpcm->be; | 1930 | struct snd_soc_pcm_runtime *be = dpcm->be; |
1931 | struct snd_soc_dai *dai = be->codec_dai; | 1931 | struct snd_soc_dai *dai = be->codec_dai; |
1932 | struct snd_soc_dai_driver *drv = dai->driver; | 1932 | struct snd_soc_dai_driver *drv = dai->driver; |
1933 | 1933 | ||
1934 | if (be->dai_link->ignore_suspend) | 1934 | if (be->dai_link->ignore_suspend) |
1935 | continue; | 1935 | continue; |
1936 | 1936 | ||
1937 | dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name); | 1937 | dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name); |
1938 | 1938 | ||
1939 | if (drv->ops->digital_mute && dai->playback_active) | 1939 | if (drv->ops->digital_mute && dai->playback_active) |
1940 | drv->ops->digital_mute(dai, mute); | 1940 | drv->ops->digital_mute(dai, mute); |
1941 | } | 1941 | } |
1942 | 1942 | ||
1943 | return 0; | 1943 | return 0; |
1944 | } | 1944 | } |
1945 | 1945 | ||
1946 | static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) | 1946 | static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) |
1947 | { | 1947 | { |
1948 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | 1948 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
1949 | struct snd_soc_dpcm *dpcm; | 1949 | struct snd_soc_dpcm *dpcm; |
1950 | struct snd_soc_dapm_widget_list *list; | 1950 | struct snd_soc_dapm_widget_list *list; |
1951 | int ret; | 1951 | int ret; |
1952 | int stream = fe_substream->stream; | 1952 | int stream = fe_substream->stream; |
1953 | 1953 | ||
1954 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1954 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1955 | fe->dpcm[stream].runtime = fe_substream->runtime; | 1955 | fe->dpcm[stream].runtime = fe_substream->runtime; |
1956 | 1956 | ||
1957 | if (dpcm_path_get(fe, stream, &list) <= 0) { | 1957 | if (dpcm_path_get(fe, stream, &list) <= 0) { |
1958 | dev_dbg(fe->dev, "asoc: %s no valid %s route\n", | 1958 | dev_dbg(fe->dev, "asoc: %s no valid %s route\n", |
1959 | fe->dai_link->name, stream ? "capture" : "playback"); | 1959 | fe->dai_link->name, stream ? "capture" : "playback"); |
1960 | } | 1960 | } |
1961 | 1961 | ||
1962 | /* calculate valid and active FE <-> BE dpcms */ | 1962 | /* calculate valid and active FE <-> BE dpcms */ |
1963 | dpcm_process_paths(fe, stream, &list, 1); | 1963 | dpcm_process_paths(fe, stream, &list, 1); |
1964 | 1964 | ||
1965 | ret = dpcm_fe_dai_startup(fe_substream); | 1965 | ret = dpcm_fe_dai_startup(fe_substream); |
1966 | if (ret < 0) { | 1966 | if (ret < 0) { |
1967 | /* clean up all links */ | 1967 | /* clean up all links */ |
1968 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | 1968 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
1969 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 1969 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
1970 | 1970 | ||
1971 | dpcm_be_disconnect(fe, stream); | 1971 | dpcm_be_disconnect(fe, stream); |
1972 | fe->dpcm[stream].runtime = NULL; | 1972 | fe->dpcm[stream].runtime = NULL; |
1973 | } | 1973 | } |
1974 | 1974 | ||
1975 | dpcm_clear_pending_state(fe, stream); | 1975 | dpcm_clear_pending_state(fe, stream); |
1976 | dpcm_path_put(&list); | 1976 | dpcm_path_put(&list); |
1977 | mutex_unlock(&fe->card->mutex); | 1977 | mutex_unlock(&fe->card->mutex); |
1978 | return ret; | 1978 | return ret; |
1979 | } | 1979 | } |
1980 | 1980 | ||
1981 | static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | 1981 | static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) |
1982 | { | 1982 | { |
1983 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | 1983 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; |
1984 | struct snd_soc_dpcm *dpcm; | 1984 | struct snd_soc_dpcm *dpcm; |
1985 | int stream = fe_substream->stream, ret; | 1985 | int stream = fe_substream->stream, ret; |
1986 | 1986 | ||
1987 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1987 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1988 | ret = dpcm_fe_dai_shutdown(fe_substream); | 1988 | ret = dpcm_fe_dai_shutdown(fe_substream); |
1989 | 1989 | ||
1990 | /* mark FE's links ready to prune */ | 1990 | /* mark FE's links ready to prune */ |
1991 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | 1991 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
1992 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 1992 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
1993 | 1993 | ||
1994 | dpcm_be_disconnect(fe, stream); | 1994 | dpcm_be_disconnect(fe, stream); |
1995 | 1995 | ||
1996 | fe->dpcm[stream].runtime = NULL; | 1996 | fe->dpcm[stream].runtime = NULL; |
1997 | mutex_unlock(&fe->card->mutex); | 1997 | mutex_unlock(&fe->card->mutex); |
1998 | return ret; | 1998 | return ret; |
1999 | } | 1999 | } |
2000 | 2000 | ||
2001 | /* create a new pcm */ | 2001 | /* create a new pcm */ |
2002 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 2002 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
2003 | { | 2003 | { |
2004 | struct snd_soc_platform *platform = rtd->platform; | 2004 | struct snd_soc_platform *platform = rtd->platform; |
2005 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2005 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
2006 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2006 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2007 | struct snd_pcm *pcm; | 2007 | struct snd_pcm *pcm; |
2008 | char new_name[64]; | 2008 | char new_name[64]; |
2009 | int ret = 0, playback = 0, capture = 0; | 2009 | int ret = 0, playback = 0, capture = 0; |
2010 | 2010 | ||
2011 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { | 2011 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
2012 | if (cpu_dai->driver->playback.channels_min) | 2012 | if (cpu_dai->driver->playback.channels_min) |
2013 | playback = 1; | 2013 | playback = 1; |
2014 | if (cpu_dai->driver->capture.channels_min) | 2014 | if (cpu_dai->driver->capture.channels_min) |
2015 | capture = 1; | 2015 | capture = 1; |
2016 | } else { | 2016 | } else { |
2017 | if (codec_dai->driver->playback.channels_min) | 2017 | if (codec_dai->driver->playback.channels_min) |
2018 | playback = 1; | 2018 | playback = 1; |
2019 | if (codec_dai->driver->capture.channels_min) | 2019 | if (codec_dai->driver->capture.channels_min) |
2020 | capture = 1; | 2020 | capture = 1; |
2021 | } | 2021 | } |
2022 | 2022 | ||
2023 | /* create the PCM */ | 2023 | /* create the PCM */ |
2024 | if (rtd->dai_link->no_pcm) { | 2024 | if (rtd->dai_link->no_pcm) { |
2025 | snprintf(new_name, sizeof(new_name), "(%s)", | 2025 | snprintf(new_name, sizeof(new_name), "(%s)", |
2026 | rtd->dai_link->stream_name); | 2026 | rtd->dai_link->stream_name); |
2027 | 2027 | ||
2028 | ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, | 2028 | ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, |
2029 | playback, capture, &pcm); | 2029 | playback, capture, &pcm); |
2030 | } else { | 2030 | } else { |
2031 | if (rtd->dai_link->dynamic) | 2031 | if (rtd->dai_link->dynamic) |
2032 | snprintf(new_name, sizeof(new_name), "%s (*)", | 2032 | snprintf(new_name, sizeof(new_name), "%s (*)", |
2033 | rtd->dai_link->stream_name); | 2033 | rtd->dai_link->stream_name); |
2034 | else | 2034 | else |
2035 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 2035 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
2036 | rtd->dai_link->stream_name, codec_dai->name, num); | 2036 | rtd->dai_link->stream_name, codec_dai->name, num); |
2037 | 2037 | ||
2038 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, | 2038 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, |
2039 | capture, &pcm); | 2039 | capture, &pcm); |
2040 | } | 2040 | } |
2041 | if (ret < 0) { | 2041 | if (ret < 0) { |
2042 | dev_err(rtd->card->dev, "can't create pcm for %s\n", | 2042 | dev_err(rtd->card->dev, "can't create pcm for %s\n", |
2043 | rtd->dai_link->name); | 2043 | rtd->dai_link->name); |
2044 | return ret; | 2044 | return ret; |
2045 | } | 2045 | } |
2046 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); | 2046 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); |
2047 | 2047 | ||
2048 | /* DAPM dai link stream work */ | 2048 | /* DAPM dai link stream work */ |
2049 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | 2049 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); |
2050 | 2050 | ||
2051 | rtd->pcm = pcm; | 2051 | rtd->pcm = pcm; |
2052 | pcm->private_data = rtd; | 2052 | pcm->private_data = rtd; |
2053 | 2053 | ||
2054 | if (rtd->dai_link->no_pcm) { | 2054 | if (rtd->dai_link->no_pcm) { |
2055 | if (playback) | 2055 | if (playback) |
2056 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; | 2056 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; |
2057 | if (capture) | 2057 | if (capture) |
2058 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; | 2058 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; |
2059 | goto out; | 2059 | goto out; |
2060 | } | 2060 | } |
2061 | 2061 | ||
2062 | /* ASoC PCM operations */ | 2062 | /* ASoC PCM operations */ |
2063 | if (rtd->dai_link->dynamic) { | 2063 | if (rtd->dai_link->dynamic) { |
2064 | rtd->ops.open = dpcm_fe_dai_open; | 2064 | rtd->ops.open = dpcm_fe_dai_open; |
2065 | rtd->ops.hw_params = dpcm_fe_dai_hw_params; | 2065 | rtd->ops.hw_params = dpcm_fe_dai_hw_params; |
2066 | rtd->ops.prepare = dpcm_fe_dai_prepare; | 2066 | rtd->ops.prepare = dpcm_fe_dai_prepare; |
2067 | rtd->ops.trigger = dpcm_fe_dai_trigger; | 2067 | rtd->ops.trigger = dpcm_fe_dai_trigger; |
2068 | rtd->ops.hw_free = dpcm_fe_dai_hw_free; | 2068 | rtd->ops.hw_free = dpcm_fe_dai_hw_free; |
2069 | rtd->ops.close = dpcm_fe_dai_close; | 2069 | rtd->ops.close = dpcm_fe_dai_close; |
2070 | rtd->ops.pointer = soc_pcm_pointer; | 2070 | rtd->ops.pointer = soc_pcm_pointer; |
2071 | rtd->ops.ioctl = soc_pcm_ioctl; | 2071 | rtd->ops.ioctl = soc_pcm_ioctl; |
2072 | } else { | 2072 | } else { |
2073 | rtd->ops.open = soc_pcm_open; | 2073 | rtd->ops.open = soc_pcm_open; |
2074 | rtd->ops.hw_params = soc_pcm_hw_params; | 2074 | rtd->ops.hw_params = soc_pcm_hw_params; |
2075 | rtd->ops.prepare = soc_pcm_prepare; | 2075 | rtd->ops.prepare = soc_pcm_prepare; |
2076 | rtd->ops.trigger = soc_pcm_trigger; | 2076 | rtd->ops.trigger = soc_pcm_trigger; |
2077 | rtd->ops.hw_free = soc_pcm_hw_free; | 2077 | rtd->ops.hw_free = soc_pcm_hw_free; |
2078 | rtd->ops.close = soc_pcm_close; | 2078 | rtd->ops.close = soc_pcm_close; |
2079 | rtd->ops.pointer = soc_pcm_pointer; | 2079 | rtd->ops.pointer = soc_pcm_pointer; |
2080 | rtd->ops.ioctl = soc_pcm_ioctl; | 2080 | rtd->ops.ioctl = soc_pcm_ioctl; |
2081 | } | 2081 | } |
2082 | 2082 | ||
2083 | if (platform->driver->ops) { | 2083 | if (platform->driver->ops) { |
2084 | rtd->ops.ack = platform->driver->ops->ack; | 2084 | rtd->ops.ack = platform->driver->ops->ack; |
2085 | rtd->ops.copy = platform->driver->ops->copy; | 2085 | rtd->ops.copy = platform->driver->ops->copy; |
2086 | rtd->ops.silence = platform->driver->ops->silence; | 2086 | rtd->ops.silence = platform->driver->ops->silence; |
2087 | rtd->ops.page = platform->driver->ops->page; | 2087 | rtd->ops.page = platform->driver->ops->page; |
2088 | rtd->ops.mmap = platform->driver->ops->mmap; | 2088 | rtd->ops.mmap = platform->driver->ops->mmap; |
2089 | } | 2089 | } |
2090 | 2090 | ||
2091 | if (playback) | 2091 | if (playback) |
2092 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); | 2092 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); |
2093 | 2093 | ||
2094 | if (capture) | 2094 | if (capture) |
2095 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); | 2095 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); |
2096 | 2096 | ||
2097 | if (platform->driver->pcm_new) { | 2097 | if (platform->driver->pcm_new) { |
2098 | ret = platform->driver->pcm_new(rtd); | 2098 | ret = platform->driver->pcm_new(rtd); |
2099 | if (ret < 0) { | 2099 | if (ret < 0) { |
2100 | dev_err(platform->dev, "pcm constructor failed\n"); | 2100 | dev_err(platform->dev, "pcm constructor failed\n"); |
2101 | return ret; | 2101 | return ret; |
2102 | } | 2102 | } |
2103 | } | 2103 | } |
2104 | 2104 | ||
2105 | pcm->private_free = platform->driver->pcm_free; | 2105 | pcm->private_free = platform->driver->pcm_free; |
2106 | out: | 2106 | out: |
2107 | dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name, | 2107 | dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name, |
2108 | cpu_dai->name); | 2108 | cpu_dai->name); |
2109 | return ret; | 2109 | return ret; |
2110 | } | 2110 | } |
2111 | 2111 | ||
2112 | /* is the current PCM operation for this FE ? */ | 2112 | /* is the current PCM operation for this FE ? */ |
2113 | int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) | 2113 | int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) |
2114 | { | 2114 | { |
2115 | if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) | 2115 | if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) |
2116 | return 1; | 2116 | return 1; |
2117 | return 0; | 2117 | return 0; |
2118 | } | 2118 | } |
2119 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update); | 2119 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update); |
2120 | 2120 | ||
2121 | /* is the current PCM operation for this BE ? */ | 2121 | /* is the current PCM operation for this BE ? */ |
2122 | int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, | 2122 | int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, |
2123 | struct snd_soc_pcm_runtime *be, int stream) | 2123 | struct snd_soc_pcm_runtime *be, int stream) |
2124 | { | 2124 | { |
2125 | if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || | 2125 | if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || |
2126 | ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) && | 2126 | ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) && |
2127 | be->dpcm[stream].runtime_update)) | 2127 | be->dpcm[stream].runtime_update)) |
2128 | return 1; | 2128 | return 1; |
2129 | return 0; | 2129 | return 0; |
2130 | } | 2130 | } |
2131 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update); | 2131 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update); |
2132 | 2132 | ||
2133 | /* get the substream for this BE */ | 2133 | /* get the substream for this BE */ |
2134 | struct snd_pcm_substream * | 2134 | struct snd_pcm_substream * |
2135 | snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream) | 2135 | snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream) |
2136 | { | 2136 | { |
2137 | return be->pcm->streams[stream].substream; | 2137 | return be->pcm->streams[stream].substream; |
2138 | } | 2138 | } |
2139 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream); | 2139 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream); |
2140 | 2140 | ||
2141 | /* get the BE runtime state */ | 2141 | /* get the BE runtime state */ |
2142 | enum snd_soc_dpcm_state | 2142 | enum snd_soc_dpcm_state |
2143 | snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream) | 2143 | snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream) |
2144 | { | 2144 | { |
2145 | return be->dpcm[stream].state; | 2145 | return be->dpcm[stream].state; |
2146 | } | 2146 | } |
2147 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state); | 2147 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state); |
2148 | 2148 | ||
2149 | /* set the BE runtime state */ | 2149 | /* set the BE runtime state */ |
2150 | void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, | 2150 | void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, |
2151 | int stream, enum snd_soc_dpcm_state state) | 2151 | int stream, enum snd_soc_dpcm_state state) |
2152 | { | 2152 | { |
2153 | be->dpcm[stream].state = state; | 2153 | be->dpcm[stream].state = state; |
2154 | } | 2154 | } |
2155 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state); | 2155 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state); |
2156 | 2156 | ||
2157 | /* | 2157 | /* |
2158 | * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE | 2158 | * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE |
2159 | * are not running, paused or suspended for the specified stream direction. | 2159 | * are not running, paused or suspended for the specified stream direction. |
2160 | */ | 2160 | */ |
2161 | int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, | 2161 | int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, |
2162 | struct snd_soc_pcm_runtime *be, int stream) | 2162 | struct snd_soc_pcm_runtime *be, int stream) |
2163 | { | 2163 | { |
2164 | struct snd_soc_dpcm *dpcm; | 2164 | struct snd_soc_dpcm *dpcm; |
2165 | int state; | 2165 | int state; |
2166 | 2166 | ||
2167 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | 2167 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
2168 | 2168 | ||
2169 | if (dpcm->fe == fe) | 2169 | if (dpcm->fe == fe) |
2170 | continue; | 2170 | continue; |
2171 | 2171 | ||
2172 | state = dpcm->fe->dpcm[stream].state; | 2172 | state = dpcm->fe->dpcm[stream].state; |
2173 | if (state == SND_SOC_DPCM_STATE_START || | 2173 | if (state == SND_SOC_DPCM_STATE_START || |
2174 | state == SND_SOC_DPCM_STATE_PAUSED || | 2174 | state == SND_SOC_DPCM_STATE_PAUSED || |
2175 | state == SND_SOC_DPCM_STATE_SUSPEND) | 2175 | state == SND_SOC_DPCM_STATE_SUSPEND) |
2176 | return 0; | 2176 | return 0; |
2177 | } | 2177 | } |
2178 | 2178 | ||
2179 | /* it's safe to free/stop this BE DAI */ | 2179 | /* it's safe to free/stop this BE DAI */ |
2180 | return 1; | 2180 | return 1; |
2181 | } | 2181 | } |
2182 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); | 2182 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); |
2183 | 2183 | ||
2184 | /* | 2184 | /* |
2185 | * We can only change hw params a BE DAI if any of it's FE are not prepared, | 2185 | * We can only change hw params a BE DAI if any of it's FE are not prepared, |
2186 | * running, paused or suspended for the specified stream direction. | 2186 | * running, paused or suspended for the specified stream direction. |
2187 | */ | 2187 | */ |
2188 | int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, | 2188 | int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, |
2189 | struct snd_soc_pcm_runtime *be, int stream) | 2189 | struct snd_soc_pcm_runtime *be, int stream) |
2190 | { | 2190 | { |
2191 | struct snd_soc_dpcm *dpcm; | 2191 | struct snd_soc_dpcm *dpcm; |
2192 | int state; | 2192 | int state; |
2193 | 2193 | ||
2194 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | 2194 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { |
2195 | 2195 | ||
2196 | if (dpcm->fe == fe) | 2196 | if (dpcm->fe == fe) |
2197 | continue; | 2197 | continue; |
2198 | 2198 | ||
2199 | state = dpcm->fe->dpcm[stream].state; | 2199 | state = dpcm->fe->dpcm[stream].state; |
2200 | if (state == SND_SOC_DPCM_STATE_START || | 2200 | if (state == SND_SOC_DPCM_STATE_START || |
2201 | state == SND_SOC_DPCM_STATE_PAUSED || | 2201 | state == SND_SOC_DPCM_STATE_PAUSED || |
2202 | state == SND_SOC_DPCM_STATE_SUSPEND || | 2202 | state == SND_SOC_DPCM_STATE_SUSPEND || |
2203 | state == SND_SOC_DPCM_STATE_PREPARE) | 2203 | state == SND_SOC_DPCM_STATE_PREPARE) |
2204 | return 0; | 2204 | return 0; |
2205 | } | 2205 | } |
2206 | 2206 | ||
2207 | /* it's safe to change hw_params */ | 2207 | /* it's safe to change hw_params */ |
2208 | return 1; | 2208 | return 1; |
2209 | } | 2209 | } |
2210 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); | 2210 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); |
2211 | 2211 | ||
2212 | int snd_soc_platform_trigger(struct snd_pcm_substream *substream, | 2212 | int snd_soc_platform_trigger(struct snd_pcm_substream *substream, |
2213 | int cmd, struct snd_soc_platform *platform) | 2213 | int cmd, struct snd_soc_platform *platform) |
2214 | { | 2214 | { |
2215 | if (platform->driver->ops->trigger) | 2215 | if (platform->driver->ops->trigger) |
2216 | return platform->driver->ops->trigger(substream, cmd); | 2216 | return platform->driver->ops->trigger(substream, cmd); |
2217 | return 0; | 2217 | return 0; |
2218 | } | 2218 | } |
2219 | EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); | 2219 | EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); |
2220 | 2220 | ||
2221 | #ifdef CONFIG_DEBUG_FS | 2221 | #ifdef CONFIG_DEBUG_FS |
2222 | static char *dpcm_state_string(enum snd_soc_dpcm_state state) | 2222 | static char *dpcm_state_string(enum snd_soc_dpcm_state state) |
2223 | { | 2223 | { |
2224 | switch (state) { | 2224 | switch (state) { |
2225 | case SND_SOC_DPCM_STATE_NEW: | 2225 | case SND_SOC_DPCM_STATE_NEW: |
2226 | return "new"; | 2226 | return "new"; |
2227 | case SND_SOC_DPCM_STATE_OPEN: | 2227 | case SND_SOC_DPCM_STATE_OPEN: |
2228 | return "open"; | 2228 | return "open"; |
2229 | case SND_SOC_DPCM_STATE_HW_PARAMS: | 2229 | case SND_SOC_DPCM_STATE_HW_PARAMS: |
2230 | return "hw_params"; | 2230 | return "hw_params"; |
2231 | case SND_SOC_DPCM_STATE_PREPARE: | 2231 | case SND_SOC_DPCM_STATE_PREPARE: |
2232 | return "prepare"; | 2232 | return "prepare"; |
2233 | case SND_SOC_DPCM_STATE_START: | 2233 | case SND_SOC_DPCM_STATE_START: |
2234 | return "start"; | 2234 | return "start"; |
2235 | case SND_SOC_DPCM_STATE_STOP: | 2235 | case SND_SOC_DPCM_STATE_STOP: |
2236 | return "stop"; | 2236 | return "stop"; |
2237 | case SND_SOC_DPCM_STATE_SUSPEND: | 2237 | case SND_SOC_DPCM_STATE_SUSPEND: |
2238 | return "suspend"; | 2238 | return "suspend"; |
2239 | case SND_SOC_DPCM_STATE_PAUSED: | 2239 | case SND_SOC_DPCM_STATE_PAUSED: |
2240 | return "paused"; | 2240 | return "paused"; |
2241 | case SND_SOC_DPCM_STATE_HW_FREE: | 2241 | case SND_SOC_DPCM_STATE_HW_FREE: |
2242 | return "hw_free"; | 2242 | return "hw_free"; |
2243 | case SND_SOC_DPCM_STATE_CLOSE: | 2243 | case SND_SOC_DPCM_STATE_CLOSE: |
2244 | return "close"; | 2244 | return "close"; |
2245 | } | 2245 | } |
2246 | 2246 | ||
2247 | return "unknown"; | 2247 | return "unknown"; |
2248 | } | 2248 | } |
2249 | 2249 | ||
2250 | static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, | 2250 | static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, |
2251 | int stream, char *buf, size_t size) | 2251 | int stream, char *buf, size_t size) |
2252 | { | 2252 | { |
2253 | struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; | 2253 | struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; |
2254 | struct snd_soc_dpcm *dpcm; | 2254 | struct snd_soc_dpcm *dpcm; |
2255 | ssize_t offset = 0; | 2255 | ssize_t offset = 0; |
2256 | 2256 | ||
2257 | /* FE state */ | 2257 | /* FE state */ |
2258 | offset += snprintf(buf + offset, size - offset, | 2258 | offset += snprintf(buf + offset, size - offset, |
2259 | "[%s - %s]\n", fe->dai_link->name, | 2259 | "[%s - %s]\n", fe->dai_link->name, |
2260 | stream ? "Capture" : "Playback"); | 2260 | stream ? "Capture" : "Playback"); |
2261 | 2261 | ||
2262 | offset += snprintf(buf + offset, size - offset, "State: %s\n", | 2262 | offset += snprintf(buf + offset, size - offset, "State: %s\n", |
2263 | dpcm_state_string(fe->dpcm[stream].state)); | 2263 | dpcm_state_string(fe->dpcm[stream].state)); |
2264 | 2264 | ||
2265 | if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && | 2265 | if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
2266 | (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) | 2266 | (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
2267 | offset += snprintf(buf + offset, size - offset, | 2267 | offset += snprintf(buf + offset, size - offset, |
2268 | "Hardware Params: " | 2268 | "Hardware Params: " |
2269 | "Format = %s, Channels = %d, Rate = %d\n", | 2269 | "Format = %s, Channels = %d, Rate = %d\n", |
2270 | snd_pcm_format_name(params_format(params)), | 2270 | snd_pcm_format_name(params_format(params)), |
2271 | params_channels(params), | 2271 | params_channels(params), |
2272 | params_rate(params)); | 2272 | params_rate(params)); |
2273 | 2273 | ||
2274 | /* BEs state */ | 2274 | /* BEs state */ |
2275 | offset += snprintf(buf + offset, size - offset, "Backends:\n"); | 2275 | offset += snprintf(buf + offset, size - offset, "Backends:\n"); |
2276 | 2276 | ||
2277 | if (list_empty(&fe->dpcm[stream].be_clients)) { | 2277 | if (list_empty(&fe->dpcm[stream].be_clients)) { |
2278 | offset += snprintf(buf + offset, size - offset, | 2278 | offset += snprintf(buf + offset, size - offset, |
2279 | " No active DSP links\n"); | 2279 | " No active DSP links\n"); |
2280 | goto out; | 2280 | goto out; |
2281 | } | 2281 | } |
2282 | 2282 | ||
2283 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 2283 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
2284 | struct snd_soc_pcm_runtime *be = dpcm->be; | 2284 | struct snd_soc_pcm_runtime *be = dpcm->be; |
2285 | params = &dpcm->hw_params; | 2285 | params = &dpcm->hw_params; |
2286 | 2286 | ||
2287 | offset += snprintf(buf + offset, size - offset, | 2287 | offset += snprintf(buf + offset, size - offset, |
2288 | "- %s\n", be->dai_link->name); | 2288 | "- %s\n", be->dai_link->name); |
2289 | 2289 | ||
2290 | offset += snprintf(buf + offset, size - offset, | 2290 | offset += snprintf(buf + offset, size - offset, |
2291 | " State: %s\n", | 2291 | " State: %s\n", |
2292 | dpcm_state_string(be->dpcm[stream].state)); | 2292 | dpcm_state_string(be->dpcm[stream].state)); |
2293 | 2293 | ||
2294 | if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && | 2294 | if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && |
2295 | (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) | 2295 | (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) |
2296 | offset += snprintf(buf + offset, size - offset, | 2296 | offset += snprintf(buf + offset, size - offset, |
2297 | " Hardware Params: " | 2297 | " Hardware Params: " |
2298 | "Format = %s, Channels = %d, Rate = %d\n", | 2298 | "Format = %s, Channels = %d, Rate = %d\n", |
2299 | snd_pcm_format_name(params_format(params)), | 2299 | snd_pcm_format_name(params_format(params)), |
2300 | params_channels(params), | 2300 | params_channels(params), |
2301 | params_rate(params)); | 2301 | params_rate(params)); |
2302 | } | 2302 | } |
2303 | 2303 | ||
2304 | out: | 2304 | out: |
2305 | return offset; | 2305 | return offset; |
2306 | } | 2306 | } |
2307 | 2307 | ||
2308 | static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, | 2308 | static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, |
2309 | size_t count, loff_t *ppos) | 2309 | size_t count, loff_t *ppos) |
2310 | { | 2310 | { |
2311 | struct snd_soc_pcm_runtime *fe = file->private_data; | 2311 | struct snd_soc_pcm_runtime *fe = file->private_data; |
2312 | ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; | 2312 | ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; |
2313 | char *buf; | 2313 | char *buf; |
2314 | 2314 | ||
2315 | buf = kmalloc(out_count, GFP_KERNEL); | 2315 | buf = kmalloc(out_count, GFP_KERNEL); |
2316 | if (!buf) | 2316 | if (!buf) |
2317 | return -ENOMEM; | 2317 | return -ENOMEM; |
2318 | 2318 | ||
2319 | if (fe->cpu_dai->driver->playback.channels_min) | 2319 | if (fe->cpu_dai->driver->playback.channels_min) |
2320 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, | 2320 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, |
2321 | buf + offset, out_count - offset); | 2321 | buf + offset, out_count - offset); |
2322 | 2322 | ||
2323 | if (fe->cpu_dai->driver->capture.channels_min) | 2323 | if (fe->cpu_dai->driver->capture.channels_min) |
2324 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, | 2324 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, |
2325 | buf + offset, out_count - offset); | 2325 | buf + offset, out_count - offset); |
2326 | 2326 | ||
2327 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); | 2327 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); |
2328 | 2328 | ||
2329 | kfree(buf); | 2329 | kfree(buf); |
2330 | return ret; | 2330 | return ret; |
2331 | } | 2331 | } |
2332 | 2332 | ||
2333 | static const struct file_operations dpcm_state_fops = { | 2333 | static const struct file_operations dpcm_state_fops = { |
2334 | .open = simple_open, | 2334 | .open = simple_open, |
2335 | .read = dpcm_state_read_file, | 2335 | .read = dpcm_state_read_file, |
2336 | .llseek = default_llseek, | 2336 | .llseek = default_llseek, |
2337 | }; | 2337 | }; |
2338 | 2338 | ||
2339 | int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) | 2339 | int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) |
2340 | { | 2340 | { |
2341 | if (!rtd->dai_link) | 2341 | if (!rtd->dai_link) |
2342 | return 0; | 2342 | return 0; |
2343 | 2343 | ||
2344 | rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, | 2344 | rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, |
2345 | rtd->card->debugfs_card_root); | 2345 | rtd->card->debugfs_card_root); |
2346 | if (!rtd->debugfs_dpcm_root) { | 2346 | if (!rtd->debugfs_dpcm_root) { |
2347 | dev_dbg(rtd->dev, | 2347 | dev_dbg(rtd->dev, |
2348 | "ASoC: Failed to create dpcm debugfs directory %s\n", | 2348 | "ASoC: Failed to create dpcm debugfs directory %s\n", |
2349 | rtd->dai_link->name); | 2349 | rtd->dai_link->name); |
2350 | return -EINVAL; | 2350 | return -EINVAL; |
2351 | } | 2351 | } |
2352 | 2352 | ||
2353 | rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444, | 2353 | rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444, |
2354 | rtd->debugfs_dpcm_root, | 2354 | rtd->debugfs_dpcm_root, |
2355 | rtd, &dpcm_state_fops); | 2355 | rtd, &dpcm_state_fops); |
2356 | 2356 | ||
2357 | return 0; | 2357 | return 0; |
2358 | } | 2358 | } |
2359 | #endif | 2359 | #endif |
2360 | 2360 |