1c01f3af4SKuninori Morimoto /* SPDX-License-Identifier: GPL-2.0
2c01f3af4SKuninori Morimoto *
3808db4a4SRichard Purdie * linux/sound/soc-dapm.h -- ALSA SoC Dynamic Audio Power Management
4808db4a4SRichard Purdie *
5808db4a4SRichard Purdie * Author: Liam Girdwood
6808db4a4SRichard Purdie * Created: Aug 11th 2005
7808db4a4SRichard Purdie * Copyright: Wolfson Microelectronics. PLC.
8808db4a4SRichard Purdie */
9808db4a4SRichard Purdie
10808db4a4SRichard Purdie #ifndef __LINUX_SND_SOC_DAPM_H
11808db4a4SRichard Purdie #define __LINUX_SND_SOC_DAPM_H
12808db4a4SRichard Purdie
13808db4a4SRichard Purdie #include <linux/types.h>
14808db4a4SRichard Purdie #include <sound/control.h>
158a978234SLiam Girdwood #include <sound/soc-topology.h>
16c147c0e1SLiam Girdwood #include <sound/asoc.h>
17808db4a4SRichard Purdie
18313162d0SPaul Gortmaker struct device;
19fdff966bSLucas Tanure struct snd_pcm_substream;
203d62ef42STzung-Bi Shih struct snd_soc_pcm_runtime;
213d62ef42STzung-Bi Shih struct soc_enum;
22313162d0SPaul Gortmaker
23808db4a4SRichard Purdie /* widget has no PM register bit */
24808db4a4SRichard Purdie #define SND_SOC_NOPM -1
25808db4a4SRichard Purdie
26808db4a4SRichard Purdie /*
27b7d2a803SJoe Perches * SoC dynamic audio power management
28808db4a4SRichard Purdie *
29808db4a4SRichard Purdie * We can have up to 4 power domains
30808db4a4SRichard Purdie * 1. Codec domain - VREF, VMID
31808db4a4SRichard Purdie * Usually controlled at codec probe/remove, although can be set
32808db4a4SRichard Purdie * at stream time if power is not needed for sidetone, etc.
33808db4a4SRichard Purdie * 2. Platform/Machine domain - physically connected inputs and outputs
34808db4a4SRichard Purdie * Is platform/machine and user action specific, is set in the machine
35808db4a4SRichard Purdie * driver and by userspace e.g when HP are inserted
36808db4a4SRichard Purdie * 3. Path domain - Internal codec path mixers
37808db4a4SRichard Purdie * Are automatically set when mixer and mux settings are
38808db4a4SRichard Purdie * changed by the user.
39808db4a4SRichard Purdie * 4. Stream domain - DAC's and ADC's.
40808db4a4SRichard Purdie * Enabled when stream playback/capture is started.
41808db4a4SRichard Purdie */
42808db4a4SRichard Purdie
43808db4a4SRichard Purdie /* codec domain */
44808db4a4SRichard Purdie #define SND_SOC_DAPM_VMID(wname) \
4512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
4612e58fecSHerve Codina .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
47808db4a4SRichard Purdie .num_kcontrols = 0}
48808db4a4SRichard Purdie
49808db4a4SRichard Purdie /* platform domain */
501ab97c8cSMark Brown #define SND_SOC_DAPM_SIGGEN(wname) \
5112e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
5212e58fecSHerve Codina .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
531ab97c8cSMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM }
5456b4437fSVinod Koul #define SND_SOC_DAPM_SINK(wname) \
5512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
5612e58fecSHerve Codina .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
5756b4437fSVinod Koul .num_kcontrols = 0, .reg = SND_SOC_NOPM }
58808db4a4SRichard Purdie #define SND_SOC_DAPM_INPUT(wname) \
5912e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
6012e58fecSHerve Codina .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
610ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM }
62808db4a4SRichard Purdie #define SND_SOC_DAPM_OUTPUT(wname) \
6312e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
6412e58fecSHerve Codina .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
650ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM }
66808db4a4SRichard Purdie #define SND_SOC_DAPM_MIC(wname, wevent) \
6712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
6812e58fecSHerve Codina .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
690ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
70808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
71808db4a4SRichard Purdie #define SND_SOC_DAPM_HP(wname, wevent) \
7212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
7312e58fecSHerve Codina .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
740ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
75808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
76808db4a4SRichard Purdie #define SND_SOC_DAPM_SPK(wname, wevent) \
7712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
7812e58fecSHerve Codina .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
790ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
80808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
81808db4a4SRichard Purdie #define SND_SOC_DAPM_LINE(wname, wevent) \
8212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
8312e58fecSHerve Codina .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
840ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
85808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
86808db4a4SRichard Purdie
87de9ba98bSLars-Peter Clausen #define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
88de9ba98bSLars-Peter Clausen .reg = wreg, .mask = 1, .shift = wshift, \
89de9ba98bSLars-Peter Clausen .on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
90de9ba98bSLars-Peter Clausen
91808db4a4SRichard Purdie /* path domain */
92808db4a4SRichard Purdie #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
93808db4a4SRichard Purdie wcontrols, wncontrols) \
9412e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
9512e58fecSHerve Codina .id = snd_soc_dapm_pga, .name = wname, \
96de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
97de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
98d88429a6SOlaya, Margarita #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
99d88429a6SOlaya, Margarita wcontrols, wncontrols) \
10012e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
10112e58fecSHerve Codina .id = snd_soc_dapm_out_drv, .name = wname, \
102de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
103de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
104808db4a4SRichard Purdie #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
105808db4a4SRichard Purdie wcontrols, wncontrols)\
10612e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
10712e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
108de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
109de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
110ca9c1aaeSIan Molton #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
111ca9c1aaeSIan Molton wcontrols, wncontrols)\
11212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
11312e58fecSHerve Codina .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
114de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
115de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
11632902177SJohn Keeping /* DEPRECATED: use SND_SOC_DAPM_SUPPLY */
117808db4a4SRichard Purdie #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
11812e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
11912e58fecSHerve Codina .id = snd_soc_dapm_micbias, .name = wname, \
120de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
121de9ba98bSLars-Peter Clausen .kcontrol_news = NULL, .num_kcontrols = 0}
122808db4a4SRichard Purdie #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
12312e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
12412e58fecSHerve Codina .id = snd_soc_dapm_switch, .name = wname, \
125de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
126de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = 1}
127808db4a4SRichard Purdie #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
12812e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
12912e58fecSHerve Codina .id = snd_soc_dapm_mux, .name = wname, \
130faf6615bSStephen Warren SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
131de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = 1}
132d714f97cSLars-Peter Clausen #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
13312e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
13412e58fecSHerve Codina .id = snd_soc_dapm_demux, .name = wname, \
135d714f97cSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
136d714f97cSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = 1}
137808db4a4SRichard Purdie
1388484c63fSGuennadi Liakhovetski /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
1398484c63fSGuennadi Liakhovetski #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
1408484c63fSGuennadi Liakhovetski wcontrols) \
14112e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
14212e58fecSHerve Codina .id = snd_soc_dapm_pga, .name = wname, \
143de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
144de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
1458484c63fSGuennadi Liakhovetski #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
1468484c63fSGuennadi Liakhovetski wcontrols)\
14712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
14812e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
149de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
150de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
1518484c63fSGuennadi Liakhovetski #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
1528484c63fSGuennadi Liakhovetski wcontrols)\
15312e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
15412e58fecSHerve Codina .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
155de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
156de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
1578484c63fSGuennadi Liakhovetski
158808db4a4SRichard Purdie /* path domain with event - event handler must return 0 for success */
159808db4a4SRichard Purdie #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
160808db4a4SRichard Purdie wncontrols, wevent, wflags) \
16112e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
16212e58fecSHerve Codina .id = snd_soc_dapm_pga, .name = wname, \
163de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
164de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
165808db4a4SRichard Purdie .event = wevent, .event_flags = wflags}
166d88429a6SOlaya, Margarita #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
167d88429a6SOlaya, Margarita wncontrols, wevent, wflags) \
16812e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
16912e58fecSHerve Codina .id = snd_soc_dapm_out_drv, .name = wname, \
170de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
171de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
172d88429a6SOlaya, Margarita .event = wevent, .event_flags = wflags}
173808db4a4SRichard Purdie #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
174808db4a4SRichard Purdie wncontrols, wevent, wflags) \
17512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
17612e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
177de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
178de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
179808db4a4SRichard Purdie .event = wevent, .event_flags = wflags}
180ca9c1aaeSIan Molton #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
181ca9c1aaeSIan Molton wcontrols, wncontrols, wevent, wflags) \
18212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
18312e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
184de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
185de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, \
186ca9c1aaeSIan Molton .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
187808db4a4SRichard Purdie #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
188808db4a4SRichard Purdie wevent, wflags) \
18912e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
19012e58fecSHerve Codina .id = snd_soc_dapm_switch, .name = wname, \
191de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
192de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = 1, \
193808db4a4SRichard Purdie .event = wevent, .event_flags = wflags}
194808db4a4SRichard Purdie #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
195808db4a4SRichard Purdie wevent, wflags) \
19612e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
19712e58fecSHerve Codina .id = snd_soc_dapm_mux, .name = wname, \
198de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
199de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = 1, \
200808db4a4SRichard Purdie .event = wevent, .event_flags = wflags}
201808db4a4SRichard Purdie
20220e4859dSMark Brown /* additional sequencing control within an event type */
2033d23c73fSMark Brown #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
2043d23c73fSMark Brown wevent, wflags) \
20512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
20612e58fecSHerve Codina .id = snd_soc_dapm_pga, .name = wname, \
207de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
208de9ba98bSLars-Peter Clausen .event = wevent, .event_flags = wflags, \
2093d23c73fSMark Brown .subseq = wsubseq}
21020e4859dSMark Brown #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
21120e4859dSMark Brown wflags) \
21212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
21312e58fecSHerve Codina .id = snd_soc_dapm_supply, .name = wname, \
214de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
215de9ba98bSLars-Peter Clausen .event = wevent, .event_flags = wflags, .subseq = wsubseq}
21620e4859dSMark Brown
2178484c63fSGuennadi Liakhovetski /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
2188484c63fSGuennadi Liakhovetski #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
2198484c63fSGuennadi Liakhovetski wevent, wflags) \
22012e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
22112e58fecSHerve Codina .id = snd_soc_dapm_pga, .name = wname, \
222de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
223de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
2248484c63fSGuennadi Liakhovetski .event = wevent, .event_flags = wflags}
2258484c63fSGuennadi Liakhovetski #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
2268484c63fSGuennadi Liakhovetski wevent, wflags) \
22712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
22812e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
229de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
230de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
2318484c63fSGuennadi Liakhovetski .event = wevent, .event_flags = wflags}
2328484c63fSGuennadi Liakhovetski #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
2338484c63fSGuennadi Liakhovetski wcontrols, wevent, wflags) \
23412e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
23512e58fecSHerve Codina .id = snd_soc_dapm_mixer, .name = wname, \
236de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
237de9ba98bSLars-Peter Clausen .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
238de9ba98bSLars-Peter Clausen .event = wevent, .event_flags = wflags}
2398484c63fSGuennadi Liakhovetski
240808db4a4SRichard Purdie /* events that are pre and post DAPM */
241808db4a4SRichard Purdie #define SND_SOC_DAPM_PRE(wname, wevent) \
24212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
24312e58fecSHerve Codina .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
2440ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
245808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
246808db4a4SRichard Purdie #define SND_SOC_DAPM_POST(wname, wevent) \
24712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
24812e58fecSHerve Codina .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
2490ca03cd7SMark Brown .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
250808db4a4SRichard Purdie .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
251808db4a4SRichard Purdie
252808db4a4SRichard Purdie /* stream domain */
253078a85f2SCharles Keepax #define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \
25412e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
25512e58fecSHerve Codina .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
256078a85f2SCharles Keepax .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
257078a85f2SCharles Keepax #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \
258ea0d09deSMark Brown wevent, wflags) \
25912e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
26012e58fecSHerve Codina .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
261078a85f2SCharles Keepax .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
262ea0d09deSMark Brown .event = wevent, .event_flags = wflags }
263078a85f2SCharles Keepax #define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \
26412e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
26512e58fecSHerve Codina .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
266078a85f2SCharles Keepax .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
267078a85f2SCharles Keepax #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \
268ea0d09deSMark Brown wevent, wflags) \
26912e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
27012e58fecSHerve Codina .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
271078a85f2SCharles Keepax .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
272ea0d09deSMark Brown .event = wevent, .event_flags = wflags }
273808db4a4SRichard Purdie #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
27412e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
27512e58fecSHerve Codina .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
276de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
277f6d655a6SMark Brown #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
278f6d655a6SMark Brown wevent, wflags) \
27912e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
28012e58fecSHerve Codina .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
281de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
282f6d655a6SMark Brown .event = wevent, .event_flags = wflags}
283de9ba98bSLars-Peter Clausen
284808db4a4SRichard Purdie #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
28512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
28612e58fecSHerve Codina .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
287de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
288f6d655a6SMark Brown #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
289f6d655a6SMark Brown wevent, wflags) \
29012e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
29112e58fecSHerve Codina .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
292de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
293f6d655a6SMark Brown .event = wevent, .event_flags = wflags}
294d7e7eb91SOla Lilja #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
29512e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
29612e58fecSHerve Codina .id = snd_soc_dapm_clock_supply, .name = wname, \
297d7e7eb91SOla Lilja .reg = SND_SOC_NOPM, .event = dapm_clock_event, \
298d7e7eb91SOla Lilja .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
299808db4a4SRichard Purdie
300246d0a17SMark Brown /* generic widgets */
301e2be2ccfSJarkko Nikula #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
30212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
30312e58fecSHerve Codina .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
30494986198SLars-Peter Clausen .reg = wreg, .shift = wshift, .mask = wmask, \
30594986198SLars-Peter Clausen .on_val = won_val, .off_val = woff_val, }
306246d0a17SMark Brown #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
30712e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
30812e58fecSHerve Codina .id = snd_soc_dapm_supply, .name = wname, \
309de9ba98bSLars-Peter Clausen SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
310de9ba98bSLars-Peter Clausen .event = wevent, .event_flags = wflags}
311822b4b8dSMark Brown #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \
31212e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
31312e58fecSHerve Codina .id = snd_soc_dapm_regulator_supply, .name = wname, \
31462ea874aSMark Brown .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
315822b4b8dSMark Brown .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
316de9ba98bSLars-Peter Clausen .on_val = wflags}
3175b2d15bbSSrinivas Kandagatla #define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \
31812e58fecSHerve Codina (struct snd_soc_dapm_widget) { \
31912e58fecSHerve Codina .id = snd_soc_dapm_pinctrl, .name = wname, \
3205b2d15bbSSrinivas Kandagatla .priv = (&(struct snd_soc_dapm_pinctrl_priv) \
3215b2d15bbSSrinivas Kandagatla { .active_state = active, .sleep_state = sleep,}), \
3225b2d15bbSSrinivas Kandagatla .reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \
3235b2d15bbSSrinivas Kandagatla .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
3245b2d15bbSSrinivas Kandagatla
325e2be2ccfSJarkko Nikula
326d7e7eb91SOla Lilja
327808db4a4SRichard Purdie /* dapm kcontrol types */
3289ee7ef31SChen-Yu Tsai #define SOC_DAPM_DOUBLE(xname, reg, lshift, rshift, max, invert) \
3299ee7ef31SChen-Yu Tsai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
3309ee7ef31SChen-Yu Tsai .info = snd_soc_info_volsw, \
3319ee7ef31SChen-Yu Tsai .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
3329ee7ef31SChen-Yu Tsai .private_value = SOC_DOUBLE_VALUE(reg, lshift, rshift, max, invert, 0) }
33302866eabSChen-Yu Tsai #define SOC_DAPM_DOUBLE_R(xname, lreg, rreg, shift, max, invert) \
33402866eabSChen-Yu Tsai { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
33502866eabSChen-Yu Tsai .info = snd_soc_info_volsw, \
33602866eabSChen-Yu Tsai .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
33702866eabSChen-Yu Tsai .private_value = SOC_DOUBLE_R_VALUE(lreg, rreg, shift, max, invert) }
338a7a4ac86SPhilipp Zabel #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
339808db4a4SRichard Purdie { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
340808db4a4SRichard Purdie .info = snd_soc_info_volsw, \
341808db4a4SRichard Purdie .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
34257295073SLars-Peter Clausen .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
34357295073SLars-Peter Clausen #define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \
34457295073SLars-Peter Clausen { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
34557295073SLars-Peter Clausen .info = snd_soc_info_volsw, \
34657295073SLars-Peter Clausen .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
34757295073SLars-Peter Clausen .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
348249ce138SLars-Peter Clausen #define SOC_DAPM_SINGLE_VIRT(xname, max) \
349249ce138SLars-Peter Clausen SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0)
350a7a4ac86SPhilipp Zabel #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
351a7a4ac86SPhilipp Zabel { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
352a7a4ac86SPhilipp Zabel .info = snd_soc_info_volsw, \
353a7a4ac86SPhilipp Zabel .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
354a7a4ac86SPhilipp Zabel .tlv.p = (tlv_array), \
355a7a4ac86SPhilipp Zabel .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
35657295073SLars-Peter Clausen .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
35757295073SLars-Peter Clausen #define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \
35857295073SLars-Peter Clausen { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
35957295073SLars-Peter Clausen .info = snd_soc_info_volsw, \
36057295073SLars-Peter Clausen .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
36157295073SLars-Peter Clausen .tlv.p = (tlv_array), \
36257295073SLars-Peter Clausen .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
363a2d97723SCharles Keepax .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
364249ce138SLars-Peter Clausen #define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
365249ce138SLars-Peter Clausen SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
366808db4a4SRichard Purdie #define SOC_DAPM_ENUM(xname, xenum) \
367808db4a4SRichard Purdie { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
368808db4a4SRichard Purdie .info = snd_soc_info_enum_double, \
369808db4a4SRichard Purdie .get = snd_soc_dapm_get_enum_double, \
370808db4a4SRichard Purdie .put = snd_soc_dapm_put_enum_double, \
371808db4a4SRichard Purdie .private_value = (unsigned long)&xenum }
372c219c809SLiam Girdwood #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
373c219c809SLiam Girdwood { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
374c219c809SLiam Girdwood .info = snd_soc_info_enum_double, \
375c219c809SLiam Girdwood .get = xget, \
376c219c809SLiam Girdwood .put = xput, \
377c219c809SLiam Girdwood .private_value = (unsigned long)&xenum }
3788b37dbd2SMark Brown #define SOC_DAPM_PIN_SWITCH(xname) \
3798b37dbd2SMark Brown { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
3808b37dbd2SMark Brown .info = snd_soc_dapm_info_pin_switch, \
3818b37dbd2SMark Brown .get = snd_soc_dapm_get_pin_switch, \
3828b37dbd2SMark Brown .put = snd_soc_dapm_put_pin_switch, \
3838b37dbd2SMark Brown .private_value = (unsigned long)xname }
384808db4a4SRichard Purdie
385808db4a4SRichard Purdie /* dapm stream operations */
386808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_NOP 0x0
387808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_START 0x1
388808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_STOP 0x2
389808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_SUSPEND 0x4
390808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_RESUME 0x8
391808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
392808db4a4SRichard Purdie #define SND_SOC_DAPM_STREAM_PAUSE_RELEASE 0x20
393808db4a4SRichard Purdie
394808db4a4SRichard Purdie /* dapm event types */
395808db4a4SRichard Purdie #define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
396808db4a4SRichard Purdie #define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
397808db4a4SRichard Purdie #define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
398808db4a4SRichard Purdie #define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
399808db4a4SRichard Purdie #define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
400808db4a4SRichard Purdie #define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
40180114129SMark Brown #define SND_SOC_DAPM_WILL_PMU 0x40 /* called at start of sequence */
40280114129SMark Brown #define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */
403f3779b16SKuninori Morimoto #define SND_SOC_DAPM_PRE_POST_PMD (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
404f3779b16SKuninori Morimoto #define SND_SOC_DAPM_PRE_POST_PMU (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
405808db4a4SRichard Purdie
406808db4a4SRichard Purdie /* convenience event type detection */
407f3779b16SKuninori Morimoto #define SND_SOC_DAPM_EVENT_ON(e) (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
408f3779b16SKuninori Morimoto #define SND_SOC_DAPM_EVENT_OFF(e) (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
409808db4a4SRichard Purdie
410c05b84d1SMark Brown /* regulator widget flags */
411c05b84d1SMark Brown #define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
412c05b84d1SMark Brown
413808db4a4SRichard Purdie struct snd_soc_dapm_widget;
414808db4a4SRichard Purdie enum snd_soc_dapm_type;
415808db4a4SRichard Purdie struct snd_soc_dapm_path;
416808db4a4SRichard Purdie struct snd_soc_dapm_pin;
417105f1c28SMark Brown struct snd_soc_dapm_route;
418ce6120ccSLiam Girdwood struct snd_soc_dapm_context;
419a3cc056bSLiam Girdwood struct regulator;
420ec2e3031SLiam Girdwood struct snd_soc_dapm_widget_list;
4216b3fc03bSLars-Peter Clausen struct snd_soc_dapm_update;
4226742064aSPiotr Stankiewicz enum snd_soc_dapm_direction;
423808db4a4SRichard Purdie
42410e83409STzung-Bi Shih /*
42510e83409STzung-Bi Shih * Bias levels
42610e83409STzung-Bi Shih *
42710e83409STzung-Bi Shih * @ON: Bias is fully on for audio playback and capture operations.
42810e83409STzung-Bi Shih * @PREPARE: Prepare for audio operations. Called before DAPM switching for
42910e83409STzung-Bi Shih * stream start and stop operations.
43010e83409STzung-Bi Shih * @STANDBY: Low power standby state when no playback/capture operations are
43110e83409STzung-Bi Shih * in progress. NOTE: The transition time between STANDBY and ON
43210e83409STzung-Bi Shih * should be as fast as possible and no longer than 10ms.
43310e83409STzung-Bi Shih * @OFF: Power Off. No restrictions on transition times.
43410e83409STzung-Bi Shih */
43510e83409STzung-Bi Shih enum snd_soc_bias_level {
43610e83409STzung-Bi Shih SND_SOC_BIAS_OFF = 0,
43710e83409STzung-Bi Shih SND_SOC_BIAS_STANDBY = 1,
43810e83409STzung-Bi Shih SND_SOC_BIAS_PREPARE = 2,
43910e83409STzung-Bi Shih SND_SOC_BIAS_ON = 3,
44010e83409STzung-Bi Shih };
44110e83409STzung-Bi Shih
442f3779b16SKuninori Morimoto int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
443f3779b16SKuninori Morimoto int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
444f3779b16SKuninori Morimoto int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
44511589418SMark Brown
446808db4a4SRichard Purdie /* dapm controls */
447f3779b16SKuninori Morimoto int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
448f3779b16SKuninori Morimoto int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
449808db4a4SRichard Purdie int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
450808db4a4SRichard Purdie struct snd_ctl_elem_value *ucontrol);
451808db4a4SRichard Purdie int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
452808db4a4SRichard Purdie struct snd_ctl_elem_value *ucontrol);
4538b37dbd2SMark Brown int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
4548b37dbd2SMark Brown struct snd_ctl_elem_info *uinfo);
4558b37dbd2SMark Brown int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
4568b37dbd2SMark Brown struct snd_ctl_elem_value *uncontrol);
4578b37dbd2SMark Brown int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
4588b37dbd2SMark Brown struct snd_ctl_elem_value *uncontrol);
459ce6120ccSLiam Girdwood int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
460f3779b16SKuninori Morimoto const struct snd_soc_dapm_widget *widget, int num);
461f3779b16SKuninori Morimoto struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
462a5d5639fSSubhransu S. Prusty const struct snd_soc_dapm_widget *widget);
463f3779b16SKuninori Morimoto struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
464db33f00dSAmadeusz Sławiński const struct snd_soc_dapm_widget *widget);
465f3779b16SKuninori Morimoto int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai);
466da039809SCezary Rojewski void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
467888df395SMark Brown int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
468b893ea5fSLiam Girdwood void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
469808db4a4SRichard Purdie
470078a85f2SCharles Keepax int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
471f3779b16SKuninori Morimoto struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
472*76aca10cSKrzysztof Kozlowski int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s);
473078a85f2SCharles Keepax
474808db4a4SRichard Purdie /* dapm path setup */
475824ef826SLars-Peter Clausen int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
476ce6120ccSLiam Girdwood void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
47795c267ddSKuninori Morimoto void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
478f3779b16SKuninori Morimoto struct snd_soc_card *card, struct snd_soc_component *component);
479ce6120ccSLiam Girdwood int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
480105f1c28SMark Brown const struct snd_soc_dapm_route *route, int num);
481efcc3c61SMark Brown int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
482efcc3c61SMark Brown const struct snd_soc_dapm_route *route, int num);
483bf3a9e13SMark Brown int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
484bf3a9e13SMark Brown const struct snd_soc_dapm_route *route, int num);
485b97e2698SLars-Peter Clausen void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
486808db4a4SRichard Purdie
487808db4a4SRichard Purdie /* dapm events */
488f3779b16SKuninori Morimoto void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event);
4893f4cf797SKuninori Morimoto void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream);
490f0fba2adSLiam Girdwood void snd_soc_dapm_shutdown(struct snd_soc_card *card);
491808db4a4SRichard Purdie
49240f02cd9SLiam Girdwood /* external DAPM widget events */
493ce6cfaf1SLars-Peter Clausen int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
494f3779b16SKuninori Morimoto struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update);
495ce6cfaf1SLars-Peter Clausen int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
4966b3fc03bSLars-Peter Clausen struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
4976b3fc03bSLars-Peter Clausen struct snd_soc_dapm_update *update);
49840f02cd9SLiam Girdwood
499808db4a4SRichard Purdie /* dapm sys fs - used by the core */
500d29697dcSTakashi Iwai extern struct attribute *soc_dapm_dev_attrs[];
501f3779b16SKuninori Morimoto void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent);
502808db4a4SRichard Purdie
503a5302181SLiam Girdwood /* dapm audio pin control and status */
504f3779b16SKuninori Morimoto int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
505f3779b16SKuninori Morimoto int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
506f3779b16SKuninori Morimoto int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
507f3779b16SKuninori Morimoto int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
508ce6120ccSLiam Girdwood int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
509f3779b16SKuninori Morimoto int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
510f3779b16SKuninori Morimoto int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin);
511ce6120ccSLiam Girdwood int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
5123eb29dfbSCharles Keepax int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
513f3779b16SKuninori Morimoto int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
514f3779b16SKuninori Morimoto int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
515f3779b16SKuninori Morimoto int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin);
5165dc0158aSSubhransu S. Prusty unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
517808db4a4SRichard Purdie
51825c77c5fSMark Brown /* Mostly internal - should not normally be used */
5198be4da29SLars-Peter Clausen void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
52025c77c5fSMark Brown
521ec2e3031SLiam Girdwood /* dapm path query */
522ec2e3031SLiam Girdwood int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
5236742064aSPiotr Stankiewicz struct snd_soc_dapm_widget_list **list,
524f3779b16SKuninori Morimoto bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction));
52552645e33SKuninori Morimoto void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list);
526ec2e3031SLiam Girdwood
527f3779b16SKuninori Morimoto struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol);
528f3779b16SKuninori Morimoto struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol);
529eee5d7f9SLars-Peter Clausen
530f3779b16SKuninori Morimoto int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level);
531fa880775SLars-Peter Clausen
532808db4a4SRichard Purdie /* dapm widget types */
533808db4a4SRichard Purdie enum snd_soc_dapm_type {
534808db4a4SRichard Purdie snd_soc_dapm_input = 0, /* input pin */
535808db4a4SRichard Purdie snd_soc_dapm_output, /* output pin */
536808db4a4SRichard Purdie snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
537d714f97cSLars-Peter Clausen snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
538808db4a4SRichard Purdie snd_soc_dapm_mixer, /* mixes several analog signals together */
539ca9c1aaeSIan Molton snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
540808db4a4SRichard Purdie snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
541d88429a6SOlaya, Margarita snd_soc_dapm_out_drv, /* output driver */
542808db4a4SRichard Purdie snd_soc_dapm_adc, /* analog to digital converter */
543808db4a4SRichard Purdie snd_soc_dapm_dac, /* digital to analog converter */
54432902177SJohn Keeping snd_soc_dapm_micbias, /* microphone bias (power) - DEPRECATED: use snd_soc_dapm_supply */
545808db4a4SRichard Purdie snd_soc_dapm_mic, /* microphone */
546808db4a4SRichard Purdie snd_soc_dapm_hp, /* headphones */
547808db4a4SRichard Purdie snd_soc_dapm_spk, /* speaker */
548808db4a4SRichard Purdie snd_soc_dapm_line, /* line input/output */
549808db4a4SRichard Purdie snd_soc_dapm_switch, /* analog switch */
550808db4a4SRichard Purdie snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
551808db4a4SRichard Purdie snd_soc_dapm_pre, /* machine specific pre widget - exec first */
552808db4a4SRichard Purdie snd_soc_dapm_post, /* machine specific post widget - exec last */
553246d0a17SMark Brown snd_soc_dapm_supply, /* power/clock supply */
5545b2d15bbSSrinivas Kandagatla snd_soc_dapm_pinctrl, /* pinctrl */
55562ea874aSMark Brown snd_soc_dapm_regulator_supply, /* external regulator */
556d7e7eb91SOla Lilja snd_soc_dapm_clock_supply, /* external clock */
557010ff262SMark Brown snd_soc_dapm_aif_in, /* audio interface input */
558010ff262SMark Brown snd_soc_dapm_aif_out, /* audio interface output */
5591ab97c8cSMark Brown snd_soc_dapm_siggen, /* signal generator */
56056b4437fSVinod Koul snd_soc_dapm_sink,
5614616274dSMark Brown snd_soc_dapm_dai_in, /* link to DAI structure */
5624616274dSMark Brown snd_soc_dapm_dai_out,
563c74184edSMark Brown snd_soc_dapm_dai_link, /* link between two DAI structures */
56457295073SLars-Peter Clausen snd_soc_dapm_kcontrol, /* Auto-disabled kcontrol */
5658a70b454SLiam Girdwood snd_soc_dapm_buffer, /* DSP/CODEC internal buffer */
5668a70b454SLiam Girdwood snd_soc_dapm_scheduler, /* DSP/CODEC internal scheduler */
5678a70b454SLiam Girdwood snd_soc_dapm_effect, /* DSP/CODEC effect component */
5688a70b454SLiam Girdwood snd_soc_dapm_src, /* DSP/CODEC SRC component */
5698a70b454SLiam Girdwood snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */
5708a70b454SLiam Girdwood snd_soc_dapm_encoder, /* FW/SW audio encoder component */
5718a70b454SLiam Girdwood snd_soc_dapm_decoder, /* FW/SW audio decoder component */
572f13d4b5fSPierre-Louis Bossart
573f13d4b5fSPierre-Louis Bossart /* Don't edit below this line */
574f13d4b5fSPierre-Louis Bossart SND_SOC_DAPM_TYPE_COUNT
575808db4a4SRichard Purdie };
576808db4a4SRichard Purdie
577105f1c28SMark Brown /*
578105f1c28SMark Brown * DAPM audio route definition.
579105f1c28SMark Brown *
580105f1c28SMark Brown * Defines an audio route originating at source via control and finishing
581105f1c28SMark Brown * at sink.
582105f1c28SMark Brown */
583105f1c28SMark Brown struct snd_soc_dapm_route {
584105f1c28SMark Brown const char *sink;
585105f1c28SMark Brown const char *control;
586105f1c28SMark Brown const char *source;
587215edda3SMark Brown
588215edda3SMark Brown /* Note: currently only supported for links where source is a supply */
589215edda3SMark Brown int (*connected)(struct snd_soc_dapm_widget *source,
590215edda3SMark Brown struct snd_soc_dapm_widget *sink);
5915c30f43fSRanjani Sridharan
5925c30f43fSRanjani Sridharan struct snd_soc_dobj dobj;
593105f1c28SMark Brown };
594105f1c28SMark Brown
595808db4a4SRichard Purdie /* dapm audio path between two widgets */
596808db4a4SRichard Purdie struct snd_soc_dapm_path {
5973056557fSMark Brown const char *name;
598808db4a4SRichard Purdie
599a3423b02SLars-Peter Clausen /*
600a3423b02SLars-Peter Clausen * source (input) and sink (output) widgets
601a3423b02SLars-Peter Clausen * The union is for convience, since it is a lot nicer to type
602a3423b02SLars-Peter Clausen * p->source, rather than p->node[SND_SOC_DAPM_DIR_IN]
603a3423b02SLars-Peter Clausen */
604a3423b02SLars-Peter Clausen union {
605a3423b02SLars-Peter Clausen struct {
606808db4a4SRichard Purdie struct snd_soc_dapm_widget *source;
607808db4a4SRichard Purdie struct snd_soc_dapm_widget *sink;
608a3423b02SLars-Peter Clausen };
609a3423b02SLars-Peter Clausen struct snd_soc_dapm_widget *node[2];
610a3423b02SLars-Peter Clausen };
611808db4a4SRichard Purdie
612808db4a4SRichard Purdie /* status */
613808db4a4SRichard Purdie u32 connect:1; /* source and sink widgets are connected */
6148af294b4SMark Brown u32 walking:1; /* path is in the process of being walked */
615169d5a83SMark Brown u32 weak:1; /* path ignored for power management */
616c1862c8bSLars-Peter Clausen u32 is_supply:1; /* At least one of the connected widgets is a supply */
617808db4a4SRichard Purdie
618215edda3SMark Brown int (*connected)(struct snd_soc_dapm_widget *source,
619215edda3SMark Brown struct snd_soc_dapm_widget *sink);
620215edda3SMark Brown
621a3423b02SLars-Peter Clausen struct list_head list_node[2];
6225106b92fSLars-Peter Clausen struct list_head list_kcontrol;
623808db4a4SRichard Purdie struct list_head list;
624808db4a4SRichard Purdie };
625808db4a4SRichard Purdie
626808db4a4SRichard Purdie /* dapm widget */
627808db4a4SRichard Purdie struct snd_soc_dapm_widget {
628808db4a4SRichard Purdie enum snd_soc_dapm_type id;
6293056557fSMark Brown const char *name; /* widget name */
6303056557fSMark Brown const char *sname; /* stream name */
631808db4a4SRichard Purdie struct list_head list;
632ce6120ccSLiam Girdwood struct snd_soc_dapm_context *dapm;
633808db4a4SRichard Purdie
63462ea874aSMark Brown void *priv; /* widget specific data */
635a3cc056bSLiam Girdwood struct regulator *regulator; /* attached regulator */
6365b2d15bbSSrinivas Kandagatla struct pinctrl *pinctrl; /* attached pinctrl */
63762ea874aSMark Brown
638808db4a4SRichard Purdie /* dapm control */
63941b5b3bdSMark Brown int reg; /* negative reg = no direct dapm */
640808db4a4SRichard Purdie unsigned char shift; /* bits to shift */
641e2be2ccfSJarkko Nikula unsigned int mask; /* non-shifted mask */
642e2be2ccfSJarkko Nikula unsigned int on_val; /* on state value */
643e2be2ccfSJarkko Nikula unsigned int off_val; /* off state value */
644808db4a4SRichard Purdie unsigned char power:1; /* block power status */
645808db4a4SRichard Purdie unsigned char active:1; /* active stream on DAC, ADC's */
646808db4a4SRichard Purdie unsigned char connected:1; /* connected codec pin */
647808db4a4SRichard Purdie unsigned char new:1; /* cnew complete */
648da34183eSMark Brown unsigned char force:1; /* force state */
6491547aba9SMark Brown unsigned char ignore_suspend:1; /* kept enabled over suspend */
6509b8a83b2SMark Brown unsigned char new_power:1; /* power from this run */
6519b8a83b2SMark Brown unsigned char power_checked:1; /* power checked this run */
6526dd98b0aSLars-Peter Clausen unsigned char is_supply:1; /* Widget is a supply type widget */
653a3423b02SLars-Peter Clausen unsigned char is_ep:2; /* Widget is a endpoint type widget */
654f7f4a5adSJyri Sarha unsigned char no_wname_in_kcontrol_name:1; /* No widget name prefix in kcontrol name */
65520e4859dSMark Brown int subseq; /* sort within widget type */
656808db4a4SRichard Purdie
657b75576d7SMark Brown int (*power_check)(struct snd_soc_dapm_widget *w);
658b75576d7SMark Brown
659808db4a4SRichard Purdie /* external events */
660808db4a4SRichard Purdie unsigned short event_flags; /* flags to specify event types */
6619af6d956SLaim Girdwood int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
662808db4a4SRichard Purdie
663808db4a4SRichard Purdie /* kcontrols that relate to this widget */
664808db4a4SRichard Purdie int num_kcontrols;
66582cfecdcSStephen Warren const struct snd_kcontrol_new *kcontrol_news;
666fad59888SStephen Warren struct snd_kcontrol **kcontrols;
6678a978234SLiam Girdwood struct snd_soc_dobj dobj;
668808db4a4SRichard Purdie
669a3423b02SLars-Peter Clausen /* widget input and output edges */
670a3423b02SLars-Peter Clausen struct list_head edges[2];
6716d3ddc81SMark Brown
6726d3ddc81SMark Brown /* used during DAPM updates */
67392a99ea4SLars-Peter Clausen struct list_head work_list;
6746d3ddc81SMark Brown struct list_head power_list;
675db432b41SMark Brown struct list_head dirty;
676a3423b02SLars-Peter Clausen int endpoints[2];
677d7e7eb91SOla Lilja
678d7e7eb91SOla Lilja struct clk *clk;
679078a85f2SCharles Keepax
680078a85f2SCharles Keepax int channel;
681808db4a4SRichard Purdie };
682808db4a4SRichard Purdie
68397404f2eSMark Brown struct snd_soc_dapm_update {
68497404f2eSMark Brown struct snd_kcontrol *kcontrol;
68597404f2eSMark Brown int reg;
68697404f2eSMark Brown int mask;
68797404f2eSMark Brown int val;
688e411b0b5SChen-Yu Tsai int reg2;
689e411b0b5SChen-Yu Tsai int mask2;
690e411b0b5SChen-Yu Tsai int val2;
691e411b0b5SChen-Yu Tsai bool has_second_set;
69297404f2eSMark Brown };
69397404f2eSMark Brown
694ce6120ccSLiam Girdwood /* DAPM context */
695ce6120ccSLiam Girdwood struct snd_soc_dapm_context {
696ce6120ccSLiam Girdwood enum snd_soc_bias_level bias_level;
697f3779b16SKuninori Morimoto
698f3779b16SKuninori Morimoto /* bit field */
699ce6120ccSLiam Girdwood unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
700f3779b16SKuninori Morimoto unsigned int suspend_bias_off:1; /* Use BIAS_OFF in suspend if the DAPM is idle */
701474b62d6SMark Brown
702ce6120ccSLiam Girdwood struct device *dev; /* from parent - for debug */
703e2c330b9SLars-Peter Clausen struct snd_soc_component *component; /* parent component */
7043a45b867SJarkko Nikula struct snd_soc_card *card; /* parent card */
7057be31be8SJarkko Nikula
7067be31be8SJarkko Nikula /* used during DAPM updates */
70756fba41fSMark Brown enum snd_soc_bias_level target_bias_level;
7087be31be8SJarkko Nikula struct list_head list;
7097be31be8SJarkko Nikula
71086b94c39SKuninori Morimoto struct snd_soc_dapm_widget *wcache_sink;
71186b94c39SKuninori Morimoto struct snd_soc_dapm_widget *wcache_source;
71245a110a1SCharles Keepax
713ce6120ccSLiam Girdwood #ifdef CONFIG_DEBUG_FS
714ce6120ccSLiam Girdwood struct dentry *debugfs_dapm;
715ce6120ccSLiam Girdwood #endif
716ce6120ccSLiam Girdwood };
717ce6120ccSLiam Girdwood
718fafd2176SStephen Warren /* A list of widgets associated with an object, typically a snd_kcontrol */
719fafd2176SStephen Warren struct snd_soc_dapm_widget_list {
720fafd2176SStephen Warren int num_widgets;
7212d6201eeSGustavo A. R. Silva struct snd_soc_dapm_widget *widgets[];
722fafd2176SStephen Warren };
723fafd2176SStephen Warren
72409e88f8aSKuninori Morimoto #define for_each_dapm_widgets(list, i, widget) \
72509e88f8aSKuninori Morimoto for ((i) = 0; \
72609e88f8aSKuninori Morimoto (i) < list->num_widgets && (widget = list->widgets[i]); \
72709e88f8aSKuninori Morimoto (i)++)
72809e88f8aSKuninori Morimoto
729de02d078SMark Brown struct snd_soc_dapm_stats {
730de02d078SMark Brown int power_checks;
731de02d078SMark Brown int path_checks;
732e56235e0SMark Brown int neighbour_checks;
733de02d078SMark Brown };
734de02d078SMark Brown
7355b2d15bbSSrinivas Kandagatla struct snd_soc_dapm_pinctrl_priv {
7365b2d15bbSSrinivas Kandagatla const char *active_state;
7375b2d15bbSSrinivas Kandagatla const char *sleep_state;
7385b2d15bbSSrinivas Kandagatla };
7395b2d15bbSSrinivas Kandagatla
740fa880775SLars-Peter Clausen /**
741fa880775SLars-Peter Clausen * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
742fa880775SLars-Peter Clausen * @dapm: The DAPM context to initialize
743fa880775SLars-Peter Clausen * @level: The DAPM level to initialize to
744fa880775SLars-Peter Clausen *
745fa880775SLars-Peter Clausen * This function only sets the driver internal state of the DAPM level and will
746fa880775SLars-Peter Clausen * not modify the state of the device. Hence it should not be used during normal
747fa880775SLars-Peter Clausen * operation, but only to synchronize the internal state to the device state.
748fa880775SLars-Peter Clausen * E.g. during driver probe to set the DAPM level to the one corresponding with
749fa880775SLars-Peter Clausen * the power-on reset state of the device.
750fa880775SLars-Peter Clausen *
751fa880775SLars-Peter Clausen * To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
752fa880775SLars-Peter Clausen */
snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context * dapm,enum snd_soc_bias_level level)753fa880775SLars-Peter Clausen static inline void snd_soc_dapm_init_bias_level(
754fa880775SLars-Peter Clausen struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
755fa880775SLars-Peter Clausen {
756fa880775SLars-Peter Clausen dapm->bias_level = level;
757fa880775SLars-Peter Clausen }
758fa880775SLars-Peter Clausen
759fa880775SLars-Peter Clausen /**
760fa880775SLars-Peter Clausen * snd_soc_dapm_get_bias_level() - Get current DAPM bias level
761fa880775SLars-Peter Clausen * @dapm: The context for which to get the bias level
762fa880775SLars-Peter Clausen *
763fa880775SLars-Peter Clausen * Returns: The current bias level of the passed DAPM context.
764fa880775SLars-Peter Clausen */
snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context * dapm)765fa880775SLars-Peter Clausen static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
766fa880775SLars-Peter Clausen struct snd_soc_dapm_context *dapm)
767fa880775SLars-Peter Clausen {
768fa880775SLars-Peter Clausen return dapm->bias_level;
769fa880775SLars-Peter Clausen }
770fa880775SLars-Peter Clausen
771a3423b02SLars-Peter Clausen enum snd_soc_dapm_direction {
772a3423b02SLars-Peter Clausen SND_SOC_DAPM_DIR_IN,
773a3423b02SLars-Peter Clausen SND_SOC_DAPM_DIR_OUT
774a3423b02SLars-Peter Clausen };
775a3423b02SLars-Peter Clausen
776a3423b02SLars-Peter Clausen #define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
777a3423b02SLars-Peter Clausen
778a3423b02SLars-Peter Clausen #define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
779a3423b02SLars-Peter Clausen #define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
780a3423b02SLars-Peter Clausen
781a3423b02SLars-Peter Clausen /**
782c670a224SKuninori Morimoto * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the
783a3423b02SLars-Peter Clausen * specified direction of a widget
784a3423b02SLars-Peter Clausen * @w: The widget
785a3423b02SLars-Peter Clausen * @dir: Whether to iterate over the paths where the specified widget is the
786a3423b02SLars-Peter Clausen * incoming or outgoing widgets
787a3423b02SLars-Peter Clausen * @p: The path iterator variable
788a3423b02SLars-Peter Clausen */
789a3423b02SLars-Peter Clausen #define snd_soc_dapm_widget_for_each_path(w, dir, p) \
790a3423b02SLars-Peter Clausen list_for_each_entry(p, &w->edges[dir], list_node[dir])
791a3423b02SLars-Peter Clausen
792a3423b02SLars-Peter Clausen /**
793c670a224SKuninori Morimoto * snd_soc_dapm_widget_for_each_path_safe - Iterates over all paths in the
794a3423b02SLars-Peter Clausen * specified direction of a widget
795a3423b02SLars-Peter Clausen * @w: The widget
796a3423b02SLars-Peter Clausen * @dir: Whether to iterate over the paths where the specified widget is the
797a3423b02SLars-Peter Clausen * incoming or outgoing widgets
798a3423b02SLars-Peter Clausen * @p: The path iterator variable
799a3423b02SLars-Peter Clausen * @next_p: Temporary storage for the next path
800a3423b02SLars-Peter Clausen *
801c670a224SKuninori Morimoto * This function works like snd_soc_dapm_widget_for_each_path, expect that
802a3423b02SLars-Peter Clausen * it is safe to remove the current path from the list while iterating
803a3423b02SLars-Peter Clausen */
804a3423b02SLars-Peter Clausen #define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
805a3423b02SLars-Peter Clausen list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
806a3423b02SLars-Peter Clausen
807e63bfd45SLars-Peter Clausen /**
808e63bfd45SLars-Peter Clausen * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a
809e63bfd45SLars-Peter Clausen * widget
810e63bfd45SLars-Peter Clausen * @w: The widget
811e63bfd45SLars-Peter Clausen * @p: The path iterator variable
812e63bfd45SLars-Peter Clausen */
813e63bfd45SLars-Peter Clausen #define snd_soc_dapm_widget_for_each_sink_path(w, p) \
814a3423b02SLars-Peter Clausen snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_IN, p)
815e63bfd45SLars-Peter Clausen
816e63bfd45SLars-Peter Clausen /**
817e63bfd45SLars-Peter Clausen * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to
818e63bfd45SLars-Peter Clausen * a widget
819e63bfd45SLars-Peter Clausen * @w: The widget
820e63bfd45SLars-Peter Clausen * @p: The path iterator variable
821e63bfd45SLars-Peter Clausen */
822e63bfd45SLars-Peter Clausen #define snd_soc_dapm_widget_for_each_source_path(w, p) \
823a3423b02SLars-Peter Clausen snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_OUT, p)
824e63bfd45SLars-Peter Clausen
825808db4a4SRichard Purdie #endif
826