diff options
Diffstat (limited to 'Documentation/sound/soc/usb.rst')
-rw-r--r-- | Documentation/sound/soc/usb.rst | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/Documentation/sound/soc/usb.rst b/Documentation/sound/soc/usb.rst new file mode 100644 index 000000000000..94c12f9d9dd1 --- /dev/null +++ b/Documentation/sound/soc/usb.rst @@ -0,0 +1,482 @@ +================ +ASoC USB support +================ + +Overview +======== +In order to leverage the existing USB sound device support in ALSA, the +ASoC USB APIs are introduced to allow the subsystems to exchange +configuration information. + +One potential use case would be to support USB audio offloading, which is +an implementation that allows for an alternate power-optimized path in the audio +subsystem to handle the transfer of audio data over the USB bus. This would +let the main processor to stay in lower power modes for longer duration. The +following is an example design of how the ASoC and ALSA pieces can be connected +together to achieve this: + +:: + + USB | ASoC + | _________________________ + | | ASoC Platform card | + | |_________________________| + | | | + | ___V____ ____V____ + | |ASoC BE | |ASoC FE | + | |DAI LNK | |DAI LNK | + | |________| |_________| + | ^ ^ ^ + | | |________| + | ___V____ | + | |SoC-USB | | + ________ ________ | | | + |USB SND |<--->|USBSND |<------------>|________| | + |(card.c)| |offld |<---------- | + |________| |________|___ | | | + ^ ^ | | | ____________V_________ + | | | | | |IPC | + __ V_______________V_____ | | | |______________________| + |USB SND (endpoint.c) | | | | ^ + |_________________________| | | | | + ^ | | | ___________V___________ + | | | |->|audio DSP | + ___________V_____________ | | |_______________________| + |XHCI HCD |<- | + |_________________________| | + + +SoC USB driver +============== +Structures +---------- +``struct snd_soc_usb`` + + - ``list``: list head for SND SoC struct list + - ``component``: reference to ASoC component + - ``connection_status_cb``: callback to notify connection events + - ``update_offload_route_info``: callback to fetch selected USB sound card/PCM + device + - ``priv_data``: driver data + +The snd_soc_usb structure can be referenced using the ASoC platform card +device, or a USB device (udev->dev). This is created by the ASoC BE DAI +link, and the USB sound entity will be able to pass information to the +ASoC BE DAI link using this structure. + +``struct snd_soc_usb_device`` + + - ``card_idx``: sound card index associated with USB sound device + - ``chip_idx``: USB sound chip array index + - ``cpcm_idx``: capture pcm device indexes associated with the USB sound device + - ``ppcm_idx``: playback pcm device indexes associated with the USB sound device + - ``num_playback``: number of playback streams + - ``num_capture``: number of capture streams + - ``list``: list head for the USB sound device list + +The struct snd_soc_usb_device is created by the USB sound offload driver. +This will carry basic parameters/limitations that will be used to +determine the possible offloading paths for this USB audio device. + +Functions +--------- +.. code-block:: rst + + int snd_soc_usb_find_supported_format(int card_idx, + struct snd_pcm_hw_params *params, int direction) +.. + + - ``card_idx``: the index into the USB sound chip array. + - ``params``: Requested PCM parameters from the USB DPCM BE DAI link + - ``direction``: capture or playback + +**snd_soc_usb_find_supported_format()** ensures that the requested audio profile +being requested by the external DSP is supported by the USB device. + +Returns 0 on success, and -EOPNOTSUPP on failure. + +.. code-block:: rst + + int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was discovered + - ``sdev``: capabilities of the device + +**snd_soc_usb_connect()** notifies the ASoC USB DCPM BE DAI link of a USB +audio device detection. This can be utilized in the BE DAI +driver to keep track of available USB audio devices. This is intended +to be called by the USB offload driver residing in USB SND. + +Returns 0 on success, negative error code on failure. + +.. code-block:: rst + + int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev) +.. + + - ``usbdev``: the usb device that was removed + - ``sdev``: capabilities to free + +**snd_soc_usb_disconnect()** notifies the ASoC USB DCPM BE DAI link of a USB +audio device removal. This is intended to be called by the USB offload +driver that resides in USB SND. + +.. code-block:: rst + + void *snd_soc_usb_find_priv_data(struct device *usbdev) +.. + + - ``usbdev``: the usb device to reference to find private data + +**snd_soc_usb_find_priv_data()** fetches the private data saved to the SoC USB +device. + +Returns pointer to priv_data on success, NULL on failure. + +.. code-block:: rst + + int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack) +.. + + - ``component``: ASoC component to add the jack + - ``jack``: jack component to populate + +**snd_soc_usb_setup_offload_jack()** is a helper to add a sound jack control to +the platform sound card. This will allow for consistent naming to be used on +designs that support USB audio offloading. Additionally, this will enable the +jack to notify of changes. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, + int direction, enum snd_soc_usb_kctl path, + long *route) +.. + + - ``dev``: USB device to look up offload path mapping + - ``card``: USB sound card index + - ``pcm``: USB sound PCM device index + - ``direction``: direction to fetch offload routing information + - ``path``: kcontrol selector - pcm device or card index + - ``route``: mapping of sound card and pcm indexes for the offload path. This is + an array of two integers that will carry the card and pcm device indexes + in that specific order. This can be used as the array for the kcontrol + output. + +**snd_soc_usb_update_offload_route()** calls a registered callback to the USB BE DAI +link to fetch the information about the mapped ASoC devices for executing USB audio +offload for the device. ``route`` may be a pointer to a kcontrol value output array, +which carries values when the kcontrol is read. + +Returns 0 on success, negative otherwise. + +.. code-block:: rst + + struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, + void *data); +.. + + - ``component``: DPCM BE DAI link component + - ``data``: private data + +**snd_soc_usb_allocate_port()** allocates a SoC USB device and populates standard +parameters that is used for further operations. + +Returns a pointer to struct soc_usb on success, negative on error. + +.. code-block:: rst + + void snd_soc_usb_free_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to free + +**snd_soc_usb_free_port()** frees a SoC USB device. + +.. code-block:: rst + + void snd_soc_usb_add_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to add + +**snd_soc_usb_add_port()** add an allocated SoC USB device to the SOC USB framework. +Once added, this device can be referenced by further operations. + +.. code-block:: rst + + void snd_soc_usb_remove_port(struct snd_soc_usb *usb); +.. + + - ``usb``: SoC USB device to remove + +**snd_soc_usb_remove_port()** removes a SoC USB device from the SoC USB framework. +After removing a device, any SOC USB operations would not be able to reference the +device removed. + +How to Register to SoC USB +-------------------------- +The ASoC DPCM USB BE DAI link is the entity responsible for allocating and +registering the SoC USB device on the component bind. Likewise, it will +also be responsible for freeing the allocated resources. An example can +be shown below: + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + data->usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (!data->usb) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + + ret = snd_soc_usb_add_port(usb); + if (ret < 0) { + dev_err(component->dev, "failed to add usb port\n"); + goto free_usb; + } + ... + } + + static void q6usb_component_remove(struct snd_soc_component *component) + { + ... + snd_soc_usb_remove_port(data->usb); + snd_soc_usb_free_port(data->usb); + } + + static const struct snd_soc_component_driver q6usb_dai_component = { + .probe = q6usb_component_probe, + .remove = q6usb_component_remove, + .name = "q6usb-dai-component", + ... + }; +.. + +BE DAI links can pass along vendor specific information as part of the +call to allocate the SoC USB device. This will allow any BE DAI link +parameters or settings to be accessed by the USB offload driver that +resides in USB SND. + +USB Audio Device Connection Flow +-------------------------------- +USB devices can be hotplugged into the USB ports at any point in time. +The BE DAI link should be aware of the current state of the physical USB +port, i.e. if there are any USB devices with audio interface(s) connected. +connection_status_cb() can be used to notify the BE DAI link of any change. + +This is called whenever there is a USB SND interface bind or remove event, +using snd_soc_usb_connect() or snd_soc_usb_disconnect(): + +.. code-block:: rst + + static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_connect(usb_get_usb_backend(udev), sdev); + ... + } + + static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip) + { + ... + snd_soc_usb_disconnect(usb_get_usb_backend(chip->dev), dev->sdev); + ... + } +.. + +In order to account for conditions where driver or device existence is +not guaranteed, USB SND exposes snd_usb_rediscover_devices() to resend the +connect events for any identified USB audio interfaces. Consider the +the following situation: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> **snd_soc_usb_connect()** exits as USB BE DAI link is not ready + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> The USB audio device connect event is missed + +To ensure connection events are not missed, **snd_usb_rediscover_devices()** +is executed when the SoC USB device is registered. Now, when the BE DAI +link component probe occurs, the following highlights the sequence: + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> SoC USB device added, and **snd_usb_rediscover_devices()** runs + + **snd_usb_rediscover_devices()** + | --> Traverses through usb_chip[] and for non-NULL entries issue + | **connection_status_cb()** + +In the case where the USB offload driver is unbound, while USB SND is ready, +the **snd_usb_rediscover_devices()** is called during module init. This allows +for the offloading path to also be enabled with the following flow: + + **usb_audio_probe()** + | --> USB audio streams allocated and saved to usb_chip[] + | --> Propagate connect event to USB offload driver in USB SND + | --> USB offload driver **NOT** ready! + + BE DAI link component probe + | --> DAI link is probed and SoC USB port is allocated + | --> No USB connect event due to missing USB offload driver + + USB offload driver probe + | --> **qc_usb_audio_offload_init()** + | --> Calls **snd_usb_rediscover_devices()** to notify of devices + +USB Offload Related Kcontrols +============================= +Details +------- +A set of kcontrols can be utilized by applications to help select the proper sound +devices to enable USB audio offloading. SoC USB exposes the get_offload_dev() +callback that designs can use to ensure that the proper indices are returned to the +application. + +Implementation +-------------- + +**Example:** + + **Sound Cards**: + + :: + + 0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D + SM8250-MTP-WCD9380-WSA8810-VA-DMIC + 1 [Seri ]: USB-Audio - Plantronics Blackwire 3225 Seri + Plantronics Plantronics Blackwire + 3225 Seri at usb-xhci-hcd.1.auto-1.1, + full sp + 2 [C320M ]: USB-Audio - Plantronics C320-M + Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed + + **PCM Devices**: + + :: + + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 0: MultiMedia1 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 1: MultiMedia2 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 1: Seri [Plantronics Blackwire 3225 Seri], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 2: C320M [Plantronics C320-M], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + + **USB Sound Card** - card#1: + + :: + + USB Offload Playback Card Route PCM#0 -1 (range -1->32) + USB Offload Playback PCM Route PCM#0 -1 (range -1->255) + + **USB Sound Card** - card#2: + + :: + + USB Offload Playback Card Route PCM#0 0 (range -1->32) + USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +The above example shows a scenario where the system has one ASoC platform card +(card#0) and two USB sound devices connected (card#1 and card#2). When reading +the available kcontrols for each USB audio device, the following kcontrols lists +the mapped offload card and pcm device indexes for the specific USB device: + + ``USB Offload Playback Card Route PCM#*`` + + ``USB Offload Playback PCM Route PCM#*`` + +The kcontrol is indexed, because a USB audio device could potentially have +several PCM devices. The above kcontrols are defined as: + + - ``USB Offload Playback Card Route PCM#`` **(R)**: Returns the ASoC platform sound + card index for a mapped offload path. The output **"0"** (card index) signifies + that there is an available offload path for the USB SND device through card#0. + If **"-1"** is seen, then no offload path is available for the USB SND device. + This kcontrol exists for each USB audio device that exists in the system, and + its expected to derive the current status of offload based on the output value + for the kcontrol along with the PCM route kcontrol. + + - ``USB Offload Playback PCM Route PCM#`` **(R)**: Returns the ASoC platform sound + PCM device index for a mapped offload path. The output **"1"** (PCM device index) + signifies that there is an available offload path for the USB SND device through + PCM device#0. If **"-1"** is seen, then no offload path is available for the USB\ + SND device. This kcontrol exists for each USB audio device that exists in the + system, and its expected to derive the current status of offload based on the + output value for this kcontrol, in addition to the card route kcontrol. + +USB Offload Playback Route Kcontrol +----------------------------------- +In order to allow for vendor specific implementations on audio offloading device +selection, the SoC USB layer exposes the following: + +.. code-block:: rst + + int (*update_offload_route_info)(struct snd_soc_component *component, + int card, int pcm, int direction, + enum snd_soc_usb_kctl path, + long *route) +.. + +These are specific for the **USB Offload Playback Card Route PCM#** and **USB +Offload PCM Route PCM#** kcontrols. + +When users issue get calls to the kcontrol, the registered SoC USB callbacks will +execute the registered function calls to the DPCM BE DAI link. + +**Callback Registration:** + +.. code-block:: rst + + static int q6usb_component_probe(struct snd_soc_component *component) + { + ... + usb = snd_soc_usb_allocate_port(component, 1, &data->priv); + if (IS_ERR(usb)) + return -ENOMEM; + + usb->connection_status_cb = q6usb_alsa_connection_cb; + usb->update_offload_route_info = q6usb_get_offload_dev; + + ret = snd_soc_usb_add_port(usb); +.. + +Existing USB Sound Kcontrol +--------------------------- +With the introduction of USB offload support, the above USB offload kcontrol +will be added to the pre existing list of kcontrols identified by the USB sound +framework. These kcontrols are still the main controls that are used to +modify characteristics pertaining to the USB audio device. + + :: + + Number of controls: 9 + ctl type num name value + 0 INT 2 Capture Channel Map 0, 0 (range 0->36) + 1 INT 2 Playback Channel Map 0, 0 (range 0->36) + 2 BOOL 1 Headset Capture Switch On + 3 INT 1 Headset Capture Volume 10 (range 0->13) + 4 BOOL 1 Sidetone Playback Switch On + 5 INT 1 Sidetone Playback Volume 4096 (range 0->8192) + 6 BOOL 1 Headset Playback Switch On + 7 INT 2 Headset Playback Volume 20, 20 (range 0->24) + 8 INT 1 USB Offload Playback Card Route PCM#0 0 (range -1->32) + 9 INT 1 USB Offload Playback PCM Route PCM#0 1 (range -1->255) + +Since USB audio device controls are handled over the USB control endpoint, use the +existing mechanisms present in the USB mixer to set parameters, such as volume. |