| Dynamic Audio Power Management for Portable Devices |
| =================================================== |
| |
| 1. Description |
| ============== |
| |
| Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices |
| to use the minimum amount of power within the audio subsystem at all times. It |
| is independent of other kernel PM and as such, can easily co-exist with the |
| other PM systems. |
| |
| DAPM is also completely transparent to all user space applications as all power |
| switching is done within the ASoC core. No code changes or recompiling are |
| required for user space applications. DAPM makes power switching descisions based |
| upon any audio stream (capture/playback) activity and audio mixer settings |
| within the device. |
| |
| DAPM spans the whole machine. It covers power control within the entire audio |
| subsystem, this includes internal codec power blocks and machine level power |
| systems. |
| |
| There are 4 power domains within DAPM |
| |
| 1. Codec domain - VREF, VMID (core codec and audio power) |
| Usually controlled at codec probe/remove and suspend/resume, although |
| can be set at stream time if power is not needed for sidetone, etc. |
| |
| 2. Platform/Machine domain - physically connected inputs and outputs |
| Is platform/machine and user action specific, is configured by the |
| machine driver and responds to asynchronous events e.g when HP |
| are inserted |
| |
| 3. Path domain - audio susbsystem signal paths |
| Automatically set when mixer and mux settings are changed by the user. |
| e.g. alsamixer, amixer. |
| |
| 4. Stream domain - DAC's and ADC's. |
| Enabled and disabled when stream playback/capture is started and |
| stopped respectively. e.g. aplay, arecord. |
| |
| All DAPM power switching descisons are made automatically by consulting an audio |
| routing map of the whole machine. This map is specific to each machine and |
| consists of the interconnections between every audio component (including |
| internal codec components). All audio components that effect power are called |
| widgets hereafter. |
| |
| |
| 2. DAPM Widgets |
| =============== |
| |
| Audio DAPM widgets fall into a number of types:- |
| |
| o Mixer - Mixes several analog signals into a single analog signal. |
| o Mux - An analog switch that outputs only 1 of it's inputs. |
| o PGA - A programmable gain amplifier or attenuation widget. |
| o ADC - Analog to Digital Converter |
| o DAC - Digital to Analog Converter |
| o Switch - An analog switch |
| o Input - A codec input pin |
| o Output - A codec output pin |
| o Headphone - Headphone (and optional Jack) |
| o Mic - Mic (and optional Jack) |
| o Line - Line Input/Output (and optional Jack) |
| o Speaker - Speaker |
| o Pre - Special PRE widget (exec before all others) |
| o Post - Special POST widget (exec after all others) |
| |
| (Widgets are defined in include/sound/soc-dapm.h) |
| |
| Widgets are usually added in the codec driver and the machine driver. There are |
| convience macros defined in soc-dapm.h that can be used to quickly build a |
| list of widgets of the codecs and machines DAPM widgets. |
| |
| Most widgets have a name, register, shift and invert. Some widgets have extra |
| parameters for stream name and kcontrols. |
| |
| |
| 2.1 Stream Domain Widgets |
| ------------------------- |
| |
| Stream Widgets relate to the stream power domain and only consist of ADC's |
| (analog to digital converters) and DAC's (digital to analog converters). |
| |
| Stream widgets have the following format:- |
| |
| SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), |
| |
| NOTE: the stream name must match the corresponding stream name in your codecs |
| snd_soc_codec_dai. |
| |
| e.g. stream widgets for HiFi playback and capture |
| |
| SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), |
| SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), |
| |
| |
| 2.2 Path Domain Widgets |
| ----------------------- |
| |
| Path domain widgets have a ability to control or effect the audio signal or |
| audio paths within the audio subsystem. They have the following form:- |
| |
| SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) |
| |
| Any widget kcontrols can be set using the controls and num_controls members. |
| |
| e.g. Mixer widget (the kcontrols are declared first) |
| |
| /* Output Mixer */ |
| static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { |
| SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), |
| SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), |
| SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), |
| }; |
| |
| SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, |
| ARRAY_SIZE(wm8731_output_mixer_controls)), |
| |
| |
| 2.3 Platform/Machine domain Widgets |
| ----------------------------------- |
| |
| Machine widgets are different from codec widgets in that they don't have a |
| codec register bit associated with them. A machine widget is assigned to each |
| machine audio component (non codec) that can be independently powered. e.g. |
| |
| o Speaker Amp |
| o Microphone Bias |
| o Jack connectors |
| |
| A machine widget can have an optional call back. |
| |
| e.g. Jack connector widget for an external Mic that enables Mic Bias |
| when the Mic is inserted:- |
| |
| static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) |
| { |
| if(SND_SOC_DAPM_EVENT_ON(event)) |
| set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); |
| else |
| reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); |
| |
| return 0; |
| } |
| |
| SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), |
| |
| |
| 2.4 Codec Domain |
| ---------------- |
| |
| The Codec power domain has no widgets and is handled by the codecs DAPM event |
| handler. This handler is called when the codec powerstate is changed wrt to any |
| stream event or by kernel PM events. |
| |
| |
| 2.5 Virtual Widgets |
| ------------------- |
| |
| Sometimes widgets exist in the codec or machine audio map that don't have any |
| corresponding register bit for power control. In this case it's necessary to |
| create a virtual widget - a widget with no control bits e.g. |
| |
| SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), |
| |
| This can be used to merge to signal paths together in software. |
| |
| After all the widgets have been defined, they can then be added to the DAPM |
| subsystem individually with a call to snd_soc_dapm_new_control(). |
| |
| |
| 3. Codec Widget Interconnections |
| ================================ |
| |
| Widgets are connected to each other within the codec and machine by audio |
| paths (called interconnections). Each interconnection must be defined in order |
| to create a map of all audio paths between widgets. |
| This is easiest with a diagram of the codec (and schematic of the machine audio |
| system), as it requires joining widgets together via their audio signal paths. |
| |
| i.e. from the WM8731 codec's output mixer (wm8731.c) |
| |
| The WM8731 output mixer has 3 inputs (sources) |
| |
| 1. Line Bypass Input |
| 2. DAC (HiFi playback) |
| 3. Mic Sidetone Input |
| |
| Each input in this example has a kcontrol associated with it (defined in example |
| above) and is connected to the output mixer via it's kcontrol name. We can now |
| connect the destination widget (wrt audio signal) with it's source widgets. |
| |
| /* output mixer */ |
| {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
| {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
| {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, |
| |
| So we have :- |
| |
| Destination Widget <=== Path Name <=== Source Widget |
| |
| Or:- |
| |
| Sink, Path, Source |
| |
| Or :- |
| |
| "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". |
| |
| When there is no path name connecting widgets (e.g. a direct connection) we |
| pass NULL for the path name. |
| |
| Interconnections are created with a call to:- |
| |
| snd_soc_dapm_connect_input(codec, sink, path, source); |
| |
| Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and |
| interconnections have been registered with the core. This causes the core to |
| scan the codec and machine so that the internal DAPM state matches the |
| physical state of the machine. |
| |
| |
| 3.1 Machine Widget Interconnections |
| ----------------------------------- |
| Machine widget interconnections are created in the same way as codec ones and |
| directly connect the codec pins to machine level widgets. |
| |
| e.g. connects the speaker out codec pins to the internal speaker. |
| |
| /* ext speaker connected to codec pins LOUT2, ROUT2 */ |
| {"Ext Spk", NULL , "ROUT2"}, |
| {"Ext Spk", NULL , "LOUT2"}, |
| |
| This allows the DAPM to power on and off pins that are connected (and in use) |
| and pins that are NC respectively. |
| |
| |
| 4 Endpoint Widgets |
| =================== |
| An endpoint is a start or end point (widget) of an audio signal within the |
| machine and includes the codec. e.g. |
| |
| o Headphone Jack |
| o Internal Speaker |
| o Internal Mic |
| o Mic Jack |
| o Codec Pins |
| |
| When a codec pin is NC it can be marked as not used with a call to |
| |
| snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); |
| |
| The last argument is 0 for inactive and 1 for active. This way the pin and its |
| input widget will never be powered up and consume power. |
| |
| This also applies to machine widgets. e.g. if a headphone is connected to a |
| jack then the jack can be marked active. If the headphone is removed, then |
| the headphone jack can be marked inactive. |
| |
| |
| 5 DAPM Widget Events |
| ==================== |
| |
| Some widgets can register their interest with the DAPM core in PM events. |
| e.g. A Speaker with an amplifier registers a widget so the amplifier can be |
| powered only when the spk is in use. |
| |
| /* turn speaker amplifier on/off depending on use */ |
| static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) |
| { |
| if (SND_SOC_DAPM_EVENT_ON(event)) |
| set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); |
| else |
| reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); |
| |
| return 0; |
| } |
| |
| /* corgi machine dapm widgets */ |
| static const struct snd_soc_dapm_widget wm8731_dapm_widgets = |
| SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); |
| |
| Please see soc-dapm.h for all other widgets that support events. |
| |
| |
| 5.1 Event types |
| --------------- |
| |
| The following event types are supported by event widgets. |
| |
| /* dapm event types */ |
| #define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ |
| #define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ |
| #define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ |
| #define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ |
| #define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ |
| #define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ |