mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
sound fixes for 5.7-rc3
This became a slightly big pull request, as the accumulated ASoC fixes are included here. Some highlights: - Revert of ASoC DAI startup changes that caused regression on some x86 platforms - Regression fix in HD-audio power management and driver blacklist - A collection of ASoC DAPM and topology fixes - Continued USB-audio fixes and quirks - Lots of small device-specific fixes - Rockchip S/PDIF DT stuff update for validation issues -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAl6hjcEOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE+Grw//eRweQIK8CcbWQu5BbXkclZ+1aeJfxYniHQNm 6izeOOu0vBO+HrK2NMFkJVhHQHu/S3B7cyC0ekV+EHsrMdXwBOGW+uB1tpq5A6QY kVKuV8wXYPQrc6PbZQowWWK0pF1fuWdZ92kKj6jX8CSOz31mAFT45C14k82LAfYP Q0MLhLHohmR/rloyTVIQqTjz+xbmtVcuPkgmbY0LzZODGkrBPIXWUSWJRXG2+egk B0Tato29jezBNZHLu4G/+H/EIyXgra0hzOC0ecqK9+VB0DQWsa6UI3fskumK1FZi XWTdbZXZmlL7f2KJzaMWR5On3cewBb/YtR6cG/hdEKWUQDqzitwnZ0JZ+jvZQgE1 5YpgJl6brqKiv603oqOOyEgEmU96cqkXkBxpHcHe5RdpmCtovuR1PktAf+azeeW3 mb3IGkiyLXr0zEoOlX4i7HRXRzzKLgCfipVy0a++bcObhnpwSpUUMN+XDqVeXHNd 8Rtt92NruBlXer9FswE7K41/BfYTkEI8XKs09eVBbudcXQN72eJTB9oVvyCDXsCs m6mitM5naAPFDAyua2eoU/Ob2PGImH/bCsH/L4u8rkHYN81W+Kn163P7hDaATIB0 DNn1q7pVX0zdfOu6ODKNHvsL8cwzMj40rsMhrezamwkfrREajrTeicVqCmyXnaMS 8/In/lM= =17wz -----END PGP SIGNATURE----- Merge tag 'sound-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound fixes from Takashi Iwai: "This became a slightly big pull request, as the accumulated ASoC fixes are included here. Some highlights: - Revert of ASoC DAI startup changes that caused regression on some x86 platforms - Regression fix in HD-audio power management and driver blacklist - A collection of ASoC DAPM and topology fixes - Continued USB-audio fixes and quirks - Lots of small device-specific fixes - Rockchip S/PDIF DT stuff update for validation issues" * tag 'sound-5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (51 commits) ALSA: hda: Always use jackpoll helper for jack update after resume ALSA: hda/realtek - Add new codec supported for ALC245 ALSA: usb-audio: Fix usb audio refcnt leak when getting spdif ALSA: usb-audio: Add connector notifier delegation ALSA: usb-audio: Apply async workaround for Scarlett 2i4 2nd gen ASoC: wm8960: Fix wrong clock after suspend & resume ALSA: usx2y: Fix potential NULL dereference ALSA: usb-audio: Add quirk for Focusrite Scarlett 2i2 ASoC: wm89xx: Add missing dependency ASoC: dapm: fixup dapm kcontrol widget ASoC: rsnd: Fix "status check failed" spam for multi-SSI ASoC: rsnd: Don't treat master SSI in multi SSI setup as parent ASoC: meson: gx-card: fix codec-to-codec link setup ASoC: meson: axg-card: fix codec-to-codec link setup ALSA: usb-audio: Add static mapping table for ALC1220-VB-based mobos ALSA: hda: Remove ASUS ROG Zenith from the blacklist ALSA: hda/realtek - Fix unexpected init_amp override ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices ASoC: SOF: Intel: add min/max channels for SSP on Baytrail/Broadwell ASoC: stm32: sai: fix sai probe ...
This commit is contained in:
commit
b4ecf26ea2
@ -56,6 +56,9 @@ properties:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
rockchip,capture-channels:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
@ -1,45 +0,0 @@
|
||||
* Rockchip SPDIF transceiver
|
||||
|
||||
The S/PDIF audio block is a stereo transceiver that allows the
|
||||
processor to receive and transmit digital audio via an coaxial cable or
|
||||
a fibre cable.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the following:
|
||||
- "rockchip,rk3066-spdif"
|
||||
- "rockchip,rk3188-spdif"
|
||||
- "rockchip,rk3228-spdif"
|
||||
- "rockchip,rk3288-spdif"
|
||||
- "rockchip,rk3328-spdif"
|
||||
- "rockchip,rk3366-spdif"
|
||||
- "rockchip,rk3368-spdif"
|
||||
- "rockchip,rk3399-spdif"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: should contain the SPDIF interrupt.
|
||||
- dmas: DMA specifiers for tx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt
|
||||
- dma-names: should be "tx"
|
||||
- clocks: a list of phandle + clock-specifier pairs, one for each entry
|
||||
in clock-names.
|
||||
- clock-names: should contain following:
|
||||
- "hclk": clock for SPDIF controller
|
||||
- "mclk" : clock for SPDIF bus
|
||||
|
||||
Required properties on RK3288:
|
||||
- rockchip,grf: the phandle of the syscon node for the general register
|
||||
file (GRF)
|
||||
|
||||
Example for the rk3188 SPDIF controller:
|
||||
|
||||
spdif: spdif@1011e000 {
|
||||
compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif";
|
||||
reg = <0x1011e000 0x2000>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmac1_s 8>;
|
||||
dma-names = "tx";
|
||||
clock-names = "hclk", "mclk";
|
||||
clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
101
Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
Normal file
101
Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
Normal file
@ -0,0 +1,101 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/rockchip-spdif.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip SPDIF transceiver
|
||||
|
||||
description:
|
||||
The S/PDIF audio block is a stereo transceiver that allows the
|
||||
processor to receive and transmit digital audio via a coaxial or
|
||||
fibre cable.
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: rockchip,rk3066-spdif
|
||||
- const: rockchip,rk3228-spdif
|
||||
- const: rockchip,rk3328-spdif
|
||||
- const: rockchip,rk3366-spdif
|
||||
- const: rockchip,rk3368-spdif
|
||||
- const: rockchip,rk3399-spdif
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3188-spdif
|
||||
- rockchip,rk3288-spdif
|
||||
- const: rockchip,rk3066-spdif
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: clock for SPDIF bus
|
||||
- description: clock for SPDIF controller
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: hclk
|
||||
|
||||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
dma-names:
|
||||
const: tx
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The phandle of the syscon node for the GRF register.
|
||||
Required property on RK3288.
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- dmas
|
||||
- dma-names
|
||||
- "#sound-dai-cells"
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: rockchip,rk3288-spdif
|
||||
|
||||
then:
|
||||
required:
|
||||
- rockchip,grf
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3188-cru.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
spdif: spdif@1011e000 {
|
||||
compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif";
|
||||
reg = <0x1011e000 0x2000>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_SPDIF>, <&cru HCLK_SPDIF>;
|
||||
clock-names = "mclk", "hclk";
|
||||
dmas = <&dmac1_s 8>;
|
||||
dma-names = "tx";
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
@ -351,7 +351,6 @@ struct snd_soc_dai {
|
||||
|
||||
/* bit field */
|
||||
unsigned int probed:1;
|
||||
unsigned int started[SNDRV_PCM_STREAM_LAST + 1];
|
||||
};
|
||||
|
||||
static inline struct snd_soc_pcm_stream *
|
||||
|
@ -790,6 +790,9 @@ struct snd_soc_dai_link {
|
||||
const struct snd_soc_pcm_stream *params;
|
||||
unsigned int num_params;
|
||||
|
||||
struct snd_soc_dapm_widget *playback_widget;
|
||||
struct snd_soc_dapm_widget *capture_widget;
|
||||
|
||||
unsigned int dai_fmt; /* format to set on init */
|
||||
|
||||
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
|
||||
|
@ -641,8 +641,18 @@ static void hda_jackpoll_work(struct work_struct *work)
|
||||
struct hda_codec *codec =
|
||||
container_of(work, struct hda_codec, jackpoll_work.work);
|
||||
|
||||
snd_hda_jack_set_dirty_all(codec);
|
||||
snd_hda_jack_poll_all(codec);
|
||||
/* for non-polling trigger: we need nothing if already powered on */
|
||||
if (!codec->jackpoll_interval && snd_hdac_is_power_on(&codec->core))
|
||||
return;
|
||||
|
||||
/* the power-up/down sequence triggers the runtime resume */
|
||||
snd_hda_power_up_pm(codec);
|
||||
/* update jacks manually if polling is required, too */
|
||||
if (codec->jackpoll_interval) {
|
||||
snd_hda_jack_set_dirty_all(codec);
|
||||
snd_hda_jack_poll_all(codec);
|
||||
}
|
||||
snd_hda_power_down_pm(codec);
|
||||
|
||||
if (!codec->jackpoll_interval)
|
||||
return;
|
||||
@ -2951,18 +2961,14 @@ static int hda_codec_runtime_resume(struct device *dev)
|
||||
static int hda_codec_force_resume(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
bool forced_resume = hda_codec_need_resume(codec);
|
||||
int ret;
|
||||
|
||||
/* The get/put pair below enforces the runtime resume even if the
|
||||
* device hasn't been used at suspend time. This trick is needed to
|
||||
* update the jack state change during the sleep.
|
||||
*/
|
||||
if (forced_resume)
|
||||
pm_runtime_get_noresume(dev);
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (forced_resume)
|
||||
pm_runtime_put(dev);
|
||||
/* schedule jackpoll work for jack detection update */
|
||||
if (codec->jackpoll_interval ||
|
||||
(pm_runtime_suspended(dev) && hda_codec_need_resume(codec)))
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1004,8 @@ static void __azx_runtime_resume(struct azx *chip, bool from_rt)
|
||||
|
||||
if (status && from_rt) {
|
||||
list_for_each_codec(codec, &chip->bus)
|
||||
if (status & (1 << codec->addr))
|
||||
if (!codec->relaxed_resume &&
|
||||
(status & (1 << codec->addr)))
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
@ -1044,9 +1045,7 @@ static int azx_suspend(struct device *dev)
|
||||
static int azx_resume(struct device *dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec;
|
||||
struct azx *chip;
|
||||
bool forced_resume = false;
|
||||
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
@ -1058,19 +1057,7 @@ static int azx_resume(struct device *dev)
|
||||
if (azx_acquire_irq(chip, 1) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* check for the forced resume */
|
||||
list_for_each_codec(codec, &chip->bus) {
|
||||
if (hda_codec_need_resume(codec)) {
|
||||
forced_resume = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (forced_resume)
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_force_resume(dev);
|
||||
if (forced_resume)
|
||||
pm_runtime_put(dev);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
|
||||
trace_azx_resume(chip);
|
||||
@ -2092,7 +2079,6 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
|
||||
* should be ignored from the beginning.
|
||||
*/
|
||||
static const struct snd_pci_quirk driver_blacklist[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x874f, "ASUS ROG Zenith II / Strix", 0),
|
||||
SND_PCI_QUIRK(0x1462, 0xcb59, "MSI TRX40 Creator", 0),
|
||||
SND_PCI_QUIRK(0x1462, 0xcb60, "MSI TRX40", 0),
|
||||
{}
|
||||
|
@ -38,6 +38,10 @@ static bool static_hdmi_pcm;
|
||||
module_param(static_hdmi_pcm, bool, 0644);
|
||||
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
|
||||
|
||||
static bool enable_acomp = true;
|
||||
module_param(enable_acomp, bool, 0444);
|
||||
MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
|
||||
|
||||
struct hdmi_spec_per_cvt {
|
||||
hda_nid_t cvt_nid;
|
||||
int assigned;
|
||||
@ -2505,6 +2509,11 @@ static void generic_acomp_init(struct hda_codec *codec,
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
|
||||
if (!enable_acomp) {
|
||||
codec_info(codec, "audio component disabled by module option\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spec->port2pin = port2pin;
|
||||
setup_drm_audio_ops(codec, ops);
|
||||
if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
|
||||
|
@ -377,6 +377,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
|
||||
case 0x10ec0233:
|
||||
case 0x10ec0235:
|
||||
case 0x10ec0236:
|
||||
case 0x10ec0245:
|
||||
case 0x10ec0255:
|
||||
case 0x10ec0256:
|
||||
case 0x10ec0257:
|
||||
@ -797,9 +798,11 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
|
||||
{
|
||||
if (!alc_subsystem_id(codec, ports)) {
|
||||
struct alc_spec *spec = codec->spec;
|
||||
codec_dbg(codec,
|
||||
"realtek: Enable default setup for auto mode as fallback\n");
|
||||
spec->init_amp = ALC_INIT_DEFAULT;
|
||||
if (spec->init_amp == ALC_INIT_UNDEFINED) {
|
||||
codec_dbg(codec,
|
||||
"realtek: Enable default setup for auto mode as fallback\n");
|
||||
spec->init_amp = ALC_INIT_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8196,6 +8199,7 @@ static int patch_alc269(struct hda_codec *codec)
|
||||
spec->gen.mixer_nid = 0;
|
||||
break;
|
||||
case 0x10ec0215:
|
||||
case 0x10ec0245:
|
||||
case 0x10ec0285:
|
||||
case 0x10ec0289:
|
||||
spec->codec_variant = ALC269_TYPE_ALC215;
|
||||
@ -9457,6 +9461,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
|
||||
HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
|
||||
HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
|
||||
|
@ -89,9 +89,9 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
||||
ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
|
||||
if (ret) {
|
||||
|
@ -1525,6 +1525,7 @@ config SND_SOC_WM8804_SPI
|
||||
|
||||
config SND_SOC_WM8900
|
||||
tristate
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8903
|
||||
tristate "Wolfson Microelectronics WM8903 CODEC"
|
||||
@ -1576,6 +1577,7 @@ config SND_SOC_WM8985
|
||||
|
||||
config SND_SOC_WM8988
|
||||
tristate
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8990
|
||||
tristate
|
||||
@ -1594,6 +1596,7 @@ config SND_SOC_WM8994
|
||||
|
||||
config SND_SOC_WM8995
|
||||
tristate
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
|
||||
config SND_SOC_WM8996
|
||||
tristate
|
||||
|
@ -142,14 +142,14 @@ static struct hdac_hdmi_pcm *
|
||||
hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
|
||||
struct hdac_hdmi_cvt *cvt)
|
||||
{
|
||||
struct hdac_hdmi_pcm *pcm = NULL;
|
||||
struct hdac_hdmi_pcm *pcm;
|
||||
|
||||
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
|
||||
if (pcm->cvt == cvt)
|
||||
break;
|
||||
return pcm;
|
||||
}
|
||||
|
||||
return pcm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
|
||||
|
@ -1903,7 +1903,6 @@ const struct soc_enum madera_isrc_fsh[] = {
|
||||
MADERA_ISRC4_FSH_SHIFT, 0xf,
|
||||
MADERA_RATE_ENUM_SIZE,
|
||||
madera_rate_text, madera_rate_val),
|
||||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_isrc_fsh);
|
||||
|
||||
@ -1924,7 +1923,6 @@ const struct soc_enum madera_isrc_fsl[] = {
|
||||
MADERA_ISRC4_FSL_SHIFT, 0xf,
|
||||
MADERA_RATE_ENUM_SIZE,
|
||||
madera_rate_text, madera_rate_val),
|
||||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_isrc_fsl);
|
||||
|
||||
@ -1938,7 +1936,6 @@ const struct soc_enum madera_asrc1_rate[] = {
|
||||
MADERA_ASYNC_RATE_ENUM_SIZE,
|
||||
madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,
|
||||
madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),
|
||||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_asrc1_rate);
|
||||
|
||||
@ -1964,7 +1961,6 @@ const struct soc_enum madera_asrc2_rate[] = {
|
||||
MADERA_ASYNC_RATE_ENUM_SIZE,
|
||||
madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,
|
||||
madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),
|
||||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(madera_asrc2_rate);
|
||||
|
||||
|
@ -1653,6 +1653,40 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
|
||||
dev_err(&client->dev,
|
||||
"Error %d initializing CHIP_CLK_CTRL\n", ret);
|
||||
|
||||
/* Mute everything to avoid pop from the following power-up */
|
||||
ret = regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_CTRL,
|
||||
SGTL5000_CHIP_ANA_CTRL_DEFAULT);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Error %d muting outputs via CHIP_ANA_CTRL\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* If VAG is powered-on (e.g. from previous boot), it would be disabled
|
||||
* by the write to ANA_POWER in later steps of the probe code. This
|
||||
* may create a loud pop even with all outputs muted. The proper way
|
||||
* to circumvent this is disabling the bit first and waiting the proper
|
||||
* cool-down time.
|
||||
*/
|
||||
ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, &value);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to read ANA_POWER: %d\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
if (value & SGTL5000_VAG_POWERUP) {
|
||||
ret = regmap_update_bits(sgtl5000->regmap,
|
||||
SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP,
|
||||
0);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Error %d disabling VAG\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
msleep(SGTL5000_VAG_POWERDOWN_DELAY);
|
||||
}
|
||||
|
||||
/* Follow section 2.2.1.1 of AN3663 */
|
||||
ana_pwr = SGTL5000_ANA_POWER_DEFAULT;
|
||||
if (sgtl5000->num_supplies <= VDDD) {
|
||||
|
@ -233,6 +233,7 @@
|
||||
/*
|
||||
* SGTL5000_CHIP_ANA_CTRL
|
||||
*/
|
||||
#define SGTL5000_CHIP_ANA_CTRL_DEFAULT 0x0133
|
||||
#define SGTL5000_LINE_OUT_MUTE 0x0100
|
||||
#define SGTL5000_HP_SEL_MASK 0x0040
|
||||
#define SGTL5000_HP_SEL_SHIFT 6
|
||||
|
@ -820,8 +820,10 @@ static int tas571x_i2c_probe(struct i2c_client *client,
|
||||
|
||||
priv->regmap = devm_regmap_init(dev, NULL, client,
|
||||
priv->chip->regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
ret = PTR_ERR(priv->regmap);
|
||||
goto disable_regs;
|
||||
}
|
||||
|
||||
priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->pdn_gpio)) {
|
||||
@ -845,7 +847,7 @@ static int tas571x_i2c_probe(struct i2c_client *client,
|
||||
|
||||
ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto disable_regs;
|
||||
|
||||
usleep_range(50000, 60000);
|
||||
|
||||
@ -861,12 +863,20 @@ static int tas571x_i2c_probe(struct i2c_client *client,
|
||||
*/
|
||||
ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto disable_regs;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&client->dev,
|
||||
ret = devm_snd_soc_register_component(&client->dev,
|
||||
&priv->component_driver,
|
||||
&tas571x_dai, 1);
|
||||
if (ret)
|
||||
goto disable_regs;
|
||||
|
||||
return ret;
|
||||
|
||||
disable_regs:
|
||||
regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tas571x_i2c_remove(struct i2c_client *client)
|
||||
|
@ -860,8 +860,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
wm8960->is_stream_in_use[tx] = true;
|
||||
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON &&
|
||||
!wm8960->is_stream_in_use[!tx])
|
||||
if (!wm8960->is_stream_in_use[!tx])
|
||||
return wm8960_configure_clocking(component);
|
||||
|
||||
return 0;
|
||||
|
@ -394,6 +394,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}, {
|
||||
/* COMP */
|
||||
.num = 2,
|
||||
@ -401,6 +402,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}, {
|
||||
/* BOOST */
|
||||
.num = 3,
|
||||
@ -408,6 +410,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}, {
|
||||
/* VISENSE */
|
||||
.num = 4,
|
||||
@ -415,6 +418,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -113,14 +113,6 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1308_2_adr[] = {
|
||||
{
|
||||
.adr = 0x000210025D130800,
|
||||
.num_endpoints = 1,
|
||||
.endpoints = &single_endpoint,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = {
|
||||
{
|
||||
.adr = 0x000110025D130800,
|
||||
|
@ -87,14 +87,6 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1308_2_adr[] = {
|
||||
{
|
||||
.adr = 0x000210025D130800,
|
||||
.num_endpoints = 1,
|
||||
.endpoints = &single_endpoint,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = {
|
||||
{
|
||||
.adr = 0x000110025D130800,
|
||||
|
@ -338,8 +338,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
|
||||
|
||||
if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node))
|
||||
ret = axg_card_parse_tdm(card, np, index);
|
||||
else if (axg_card_cpu_is_codec(dai_link->cpus->of_node))
|
||||
else if (axg_card_cpu_is_codec(dai_link->cpus->of_node)) {
|
||||
dai_link->params = &codec_params;
|
||||
dai_link->no_pcm = 0; /* link is not a DPCM BE */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -108,8 +108,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
|
||||
ret = gx_card_parse_i2s(card, np, index);
|
||||
|
||||
/* Or apply codec to codec params if necessary */
|
||||
else if (gx_card_cpu_identify(dai_link->cpus, "CODEC CTRL"))
|
||||
else if (gx_card_cpu_identify(dai_link->cpus, "CODEC CTRL")) {
|
||||
dai_link->params = &codec_params;
|
||||
dai_link->no_pcm = 0; /* link is not a DPCM BE */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -116,10 +116,8 @@ static int apq8096_platform_probe(struct platform_device *pdev)
|
||||
card->dev = dev;
|
||||
dev_set_drvdata(dev, card);
|
||||
ret = qcom_snd_parse_of(card);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error parsing OF data\n");
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
apq8096_add_be_ops(card);
|
||||
ret = snd_soc_register_card(card);
|
||||
|
@ -902,6 +902,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -917,6 +919,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -931,6 +935,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -946,6 +952,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -960,6 +968,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -975,6 +985,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -989,6 +1001,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
@ -1004,6 +1018,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -559,10 +559,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
|
||||
card->dev = dev;
|
||||
dev_set_drvdata(dev, card);
|
||||
ret = qcom_snd_parse_of(card);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error parsing OF data\n");
|
||||
if (ret)
|
||||
goto parse_dt_fail;
|
||||
}
|
||||
|
||||
data->card = card;
|
||||
snd_soc_card_set_drvdata(card, data);
|
||||
|
@ -656,60 +656,6 @@ void s3c_i2sv2_cleanup(struct snd_soc_dai *dai,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_cleanup);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct s3c_i2sv2_info *i2s = to_info(dai);
|
||||
u32 iismod;
|
||||
|
||||
if (dai->active) {
|
||||
i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
|
||||
i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
|
||||
i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
|
||||
|
||||
/* some basic suspend checks */
|
||||
|
||||
iismod = readl(i2s->regs + S3C2412_IISMOD);
|
||||
|
||||
if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
|
||||
pr_warn("%s: RXDMA active?\n", __func__);
|
||||
|
||||
if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
|
||||
pr_warn("%s: TXDMA active?\n", __func__);
|
||||
|
||||
if (iismod & S3C2412_IISCON_IIS_ACTIVE)
|
||||
pr_warn("%s: IIS active\n", __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct s3c_i2sv2_info *i2s = to_info(dai);
|
||||
|
||||
pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
|
||||
dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
|
||||
|
||||
if (dai->active) {
|
||||
writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
|
||||
writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
|
||||
writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
|
||||
|
||||
writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
|
||||
i2s->regs + S3C2412_IISFIC);
|
||||
|
||||
ndelay(250);
|
||||
writel(0x0, i2s->regs + S3C2412_IISFIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define s3c2412_i2s_suspend NULL
|
||||
#define s3c2412_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
int s3c_i2sv2_register_component(struct device *dev, int id,
|
||||
const struct snd_soc_component_driver *cmp_drv,
|
||||
struct snd_soc_dai_driver *dai_drv)
|
||||
@ -727,9 +673,6 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
|
||||
if (!ops->delay)
|
||||
ops->delay = s3c2412_i2s_delay;
|
||||
|
||||
dai_drv->suspend = s3c2412_i2s_suspend;
|
||||
dai_drv->resume = s3c2412_i2s_resume;
|
||||
|
||||
return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
|
||||
|
@ -117,6 +117,60 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s3c2412_i2s_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
|
||||
u32 iismod;
|
||||
|
||||
if (component->active) {
|
||||
i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
|
||||
i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
|
||||
i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
|
||||
|
||||
/* some basic suspend checks */
|
||||
|
||||
iismod = readl(i2s->regs + S3C2412_IISMOD);
|
||||
|
||||
if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
|
||||
pr_warn("%s: RXDMA active?\n", __func__);
|
||||
|
||||
if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
|
||||
pr_warn("%s: TXDMA active?\n", __func__);
|
||||
|
||||
if (iismod & S3C2412_IISCON_IIS_ACTIVE)
|
||||
pr_warn("%s: IIS active\n", __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2412_i2s_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
|
||||
|
||||
pr_info("component_active %d, IISMOD %08x, IISCON %08x\n",
|
||||
component->active, i2s->suspend_iismod, i2s->suspend_iiscon);
|
||||
|
||||
if (component->active) {
|
||||
writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
|
||||
writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
|
||||
writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
|
||||
|
||||
writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
|
||||
i2s->regs + S3C2412_IISFIC);
|
||||
|
||||
ndelay(250);
|
||||
writel(0x0, i2s->regs + S3C2412_IISFIC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define s3c2412_i2s_suspend NULL
|
||||
#define s3c2412_i2s_resume NULL
|
||||
#endif
|
||||
|
||||
#define S3C2412_I2S_RATES \
|
||||
(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
|
||||
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
||||
@ -146,6 +200,8 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
|
||||
|
||||
static const struct snd_soc_component_driver s3c2412_i2s_component = {
|
||||
.name = "s3c2412-i2s",
|
||||
.suspend = s3c2412_i2s_suspend,
|
||||
.resume = s3c2412_i2s_resume,
|
||||
};
|
||||
|
||||
static int s3c2412_iis_dev_probe(struct platform_device *pdev)
|
||||
|
@ -594,10 +594,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
|
||||
* Capture: It might not receave data. Do nothing
|
||||
*/
|
||||
if (rsnd_io_is_play(io)) {
|
||||
rsnd_mod_write(mod, SSICR, cr | EN);
|
||||
rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
|
||||
rsnd_ssi_status_check(mod, DIRQ);
|
||||
}
|
||||
|
||||
/* In multi-SSI mode, stop is performed by setting ssi0129 in
|
||||
* SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
|
||||
*/
|
||||
if (rsnd_ssi_multi_slaves_runtime(io))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* disable SSI,
|
||||
* and, wait idle state
|
||||
@ -737,6 +743,9 @@ static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
|
||||
if (!rsnd_rdai_is_clk_master(rdai))
|
||||
return;
|
||||
|
||||
if (rsnd_ssi_is_multi_slave(mod, io))
|
||||
return;
|
||||
|
||||
switch (rsnd_mod_id(mod)) {
|
||||
case 1:
|
||||
case 2:
|
||||
|
@ -221,7 +221,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
|
||||
i;
|
||||
|
||||
for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
|
||||
shift = (i * 4) + 16;
|
||||
shift = (i * 4) + 20;
|
||||
val = (val & ~(0xF << shift)) |
|
||||
rsnd_mod_id(pos) << shift;
|
||||
}
|
||||
|
@ -295,24 +295,17 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!dai->started[substream->stream] &&
|
||||
dai->driver->ops->startup)
|
||||
if (dai->driver->ops->startup)
|
||||
ret = dai->driver->ops->startup(substream, dai);
|
||||
|
||||
if (ret == 0)
|
||||
dai->started[substream->stream] = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
if (dai->started[substream->stream] &&
|
||||
dai->driver->ops->shutdown)
|
||||
if (dai->driver->ops->shutdown)
|
||||
dai->driver->ops->shutdown(substream, dai);
|
||||
|
||||
dai->started[substream->stream] = 0;
|
||||
}
|
||||
|
||||
int snd_soc_dai_prepare(struct snd_soc_dai *dai,
|
||||
|
@ -423,7 +423,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
template.reg = e->reg;
|
||||
template.mask = e->mask << e->shift_l;
|
||||
template.mask = e->mask;
|
||||
template.shift = e->shift_l;
|
||||
template.off_val = snd_soc_enum_item_to_val(e, 0);
|
||||
template.on_val = template.off_val;
|
||||
@ -546,8 +546,22 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
|
||||
if (data->value == value)
|
||||
return false;
|
||||
|
||||
if (data->widget)
|
||||
data->widget->on_val = value;
|
||||
if (data->widget) {
|
||||
switch (dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->id) {
|
||||
case snd_soc_dapm_switch:
|
||||
case snd_soc_dapm_mixer:
|
||||
case snd_soc_dapm_mixer_named_ctl:
|
||||
data->widget->on_val = value & data->widget->mask;
|
||||
break;
|
||||
case snd_soc_dapm_demux:
|
||||
case snd_soc_dapm_mux:
|
||||
data->widget->on_val = value >> data->widget->shift;
|
||||
break;
|
||||
default:
|
||||
data->widget->on_val = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data->value = value;
|
||||
|
||||
@ -4165,6 +4179,8 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
|
||||
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
|
||||
if (IS_ERR(w)) {
|
||||
ret = PTR_ERR(w);
|
||||
dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n",
|
||||
link_name, ret);
|
||||
goto outfree_kcontrol_news;
|
||||
}
|
||||
|
||||
@ -4283,52 +4299,58 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dapm_add_valid_dai_widget(struct snd_soc_card *card,
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *codec_dai,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
static void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_soc_dai *src_dai,
|
||||
struct snd_soc_dapm_widget *src,
|
||||
struct snd_soc_dapm_widget *dai,
|
||||
struct snd_soc_dai *sink_dai,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_dapm_widget *playback = NULL, *capture = NULL;
|
||||
struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu;
|
||||
dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n",
|
||||
src_dai->component->name, src->name,
|
||||
sink_dai->component->name, sink->name);
|
||||
|
||||
if (dai) {
|
||||
snd_soc_dapm_add_path(dapm, src, dai, NULL, NULL);
|
||||
src = dai;
|
||||
}
|
||||
|
||||
snd_soc_dapm_add_path(dapm, src, sink, NULL, NULL);
|
||||
}
|
||||
|
||||
static void dapm_connect_dai_pair(struct snd_soc_card *card,
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *codec_dai,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
struct snd_soc_dapm_widget *dai, *codec, *playback_cpu, *capture_cpu;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm_str *streams = rtd->pcm->streams;
|
||||
|
||||
if (rtd->dai_link->params) {
|
||||
if (dai_link->params) {
|
||||
playback_cpu = cpu_dai->capture_widget;
|
||||
capture_cpu = cpu_dai->playback_widget;
|
||||
} else {
|
||||
playback = cpu_dai->playback_widget;
|
||||
capture = cpu_dai->capture_widget;
|
||||
playback_cpu = playback;
|
||||
capture_cpu = capture;
|
||||
playback_cpu = cpu_dai->playback_widget;
|
||||
capture_cpu = cpu_dai->capture_widget;
|
||||
}
|
||||
|
||||
/* connect BE DAI playback if widgets are valid */
|
||||
codec = codec_dai->playback_widget;
|
||||
|
||||
if (playback_cpu && codec) {
|
||||
if (!playback) {
|
||||
if (dai_link->params && !dai_link->playback_widget) {
|
||||
substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
playback = snd_soc_dapm_new_dai(card, substream,
|
||||
"playback");
|
||||
if (IS_ERR(playback)) {
|
||||
dev_err(rtd->dev,
|
||||
"ASoC: Failed to create DAI %s: %ld\n",
|
||||
codec_dai->name,
|
||||
PTR_ERR(playback));
|
||||
dai = snd_soc_dapm_new_dai(card, substream, "playback");
|
||||
if (IS_ERR(dai))
|
||||
goto capture;
|
||||
}
|
||||
|
||||
snd_soc_dapm_add_path(&card->dapm, playback_cpu,
|
||||
playback, NULL, NULL);
|
||||
dai_link->playback_widget = dai;
|
||||
}
|
||||
|
||||
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
|
||||
cpu_dai->component->name, playback_cpu->name,
|
||||
codec_dai->component->name, codec->name);
|
||||
|
||||
snd_soc_dapm_add_path(&card->dapm, playback, codec,
|
||||
NULL, NULL);
|
||||
dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu,
|
||||
dai_link->playback_widget,
|
||||
codec_dai, codec);
|
||||
}
|
||||
|
||||
capture:
|
||||
@ -4336,52 +4358,20 @@ static void dapm_add_valid_dai_widget(struct snd_soc_card *card,
|
||||
codec = codec_dai->capture_widget;
|
||||
|
||||
if (codec && capture_cpu) {
|
||||
if (!capture) {
|
||||
if (dai_link->params && !dai_link->capture_widget) {
|
||||
substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream;
|
||||
capture = snd_soc_dapm_new_dai(card, substream,
|
||||
"capture");
|
||||
if (IS_ERR(capture)) {
|
||||
dev_err(rtd->dev,
|
||||
"ASoC: Failed to create DAI %s: %ld\n",
|
||||
codec_dai->name,
|
||||
PTR_ERR(capture));
|
||||
dai = snd_soc_dapm_new_dai(card, substream, "capture");
|
||||
if (IS_ERR(dai))
|
||||
return;
|
||||
}
|
||||
|
||||
snd_soc_dapm_add_path(&card->dapm, capture,
|
||||
capture_cpu, NULL, NULL);
|
||||
dai_link->capture_widget = dai;
|
||||
}
|
||||
|
||||
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
|
||||
codec_dai->component->name, codec->name,
|
||||
cpu_dai->component->name, capture_cpu->name);
|
||||
|
||||
snd_soc_dapm_add_path(&card->dapm, codec, capture,
|
||||
NULL, NULL);
|
||||
dapm_connect_dai_routes(&card->dapm, codec_dai, codec,
|
||||
dai_link->capture_widget,
|
||||
cpu_dai, capture_cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int i;
|
||||
|
||||
if (rtd->num_cpus == 1) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_add_valid_dai_widget(card, rtd, codec_dai,
|
||||
rtd->cpu_dais[0]);
|
||||
} else if (rtd->num_codecs == rtd->num_cpus) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_add_valid_dai_widget(card, rtd, codec_dai,
|
||||
rtd->cpu_dais[i]);
|
||||
} else {
|
||||
dev_err(card->dev,
|
||||
"N cpus to M codecs link is not supported yet\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
|
||||
int event)
|
||||
{
|
||||
@ -4422,6 +4412,8 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
|
||||
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int i;
|
||||
|
||||
/* for each BE DAI link... */
|
||||
for_each_card_rtds(card, rtd) {
|
||||
@ -4432,7 +4424,18 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
|
||||
if (rtd->dai_link->dynamic)
|
||||
continue;
|
||||
|
||||
dapm_connect_dai_link_widgets(card, rtd);
|
||||
if (rtd->num_cpus == 1) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai,
|
||||
rtd->cpu_dais[0]);
|
||||
} else if (rtd->num_codecs == rtd->num_cpus) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai,
|
||||
rtd->cpu_dais[i]);
|
||||
} else {
|
||||
dev_err(card->dev,
|
||||
"N cpus to M codecs link is not supported yet\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2911,8 +2911,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
|
||||
int i;
|
||||
|
||||
if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
|
||||
playback = rtd->dai_link->dpcm_playback;
|
||||
capture = rtd->dai_link->dpcm_capture;
|
||||
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
if (rtd->num_cpus > 1) {
|
||||
dev_err(rtd->dev,
|
||||
"DPCM doesn't support Multi CPU yet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
playback = rtd->dai_link->dpcm_playback &&
|
||||
snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
capture = rtd->dai_link->dpcm_capture &&
|
||||
snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
} else {
|
||||
/* Adapt stream for codec2codec links */
|
||||
int cpu_capture = rtd->dai_link->params ?
|
||||
|
@ -894,7 +894,13 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
|
||||
}
|
||||
|
||||
/* create any TLV data */
|
||||
soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
|
||||
err = soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
|
||||
if (err < 0) {
|
||||
dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
|
||||
mc->hdr.name);
|
||||
kfree(sm);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* pass control to driver for optional further init */
|
||||
err = soc_tplg_init_kcontrol(tplg, &kc,
|
||||
@ -1118,6 +1124,7 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
|
||||
struct snd_soc_tplg_hdr *hdr)
|
||||
{
|
||||
struct snd_soc_tplg_ctl_hdr *control_hdr;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (tplg->pass != SOC_TPLG_PASS_MIXER) {
|
||||
@ -1146,25 +1153,30 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
|
||||
case SND_SOC_TPLG_CTL_RANGE:
|
||||
case SND_SOC_TPLG_DAPM_CTL_VOLSW:
|
||||
case SND_SOC_TPLG_DAPM_CTL_PIN:
|
||||
soc_tplg_dmixer_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
ret = soc_tplg_dmixer_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
break;
|
||||
case SND_SOC_TPLG_CTL_ENUM:
|
||||
case SND_SOC_TPLG_CTL_ENUM_VALUE:
|
||||
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
|
||||
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
|
||||
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
|
||||
soc_tplg_denum_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
ret = soc_tplg_denum_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
break;
|
||||
case SND_SOC_TPLG_CTL_BYTES:
|
||||
soc_tplg_dbytes_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
ret = soc_tplg_dbytes_create(tplg, 1,
|
||||
le32_to_cpu(hdr->payload_size));
|
||||
break;
|
||||
default:
|
||||
soc_bind_err(tplg, control_hdr, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(tplg->dev, "ASoC: invalid control\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1272,7 +1284,9 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
|
||||
routes[i]->dobj.index = tplg->index;
|
||||
list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list);
|
||||
|
||||
soc_tplg_add_route(tplg, routes[i]);
|
||||
ret = soc_tplg_add_route(tplg, routes[i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
/* add route, but keep going if some fail */
|
||||
snd_soc_dapm_add_routes(dapm, routes[i], 1);
|
||||
@ -1355,7 +1369,13 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
|
||||
}
|
||||
|
||||
/* create any TLV data */
|
||||
soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
|
||||
err = soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
|
||||
if (err < 0) {
|
||||
dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
|
||||
mc->hdr.name);
|
||||
kfree(sm);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* pass control to driver for optional further init */
|
||||
err = soc_tplg_init_kcontrol(tplg, &kc[i],
|
||||
@ -1766,10 +1786,13 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_stream_info(struct snd_soc_pcm_stream *stream,
|
||||
static int set_stream_info(struct snd_soc_pcm_stream *stream,
|
||||
struct snd_soc_tplg_stream_caps *caps)
|
||||
{
|
||||
stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
|
||||
if (!stream->stream_name)
|
||||
return -ENOMEM;
|
||||
|
||||
stream->channels_min = le32_to_cpu(caps->channels_min);
|
||||
stream->channels_max = le32_to_cpu(caps->channels_max);
|
||||
stream->rates = le32_to_cpu(caps->rates);
|
||||
@ -1777,6 +1800,8 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream,
|
||||
stream->rate_max = le32_to_cpu(caps->rate_max);
|
||||
stream->formats = le64_to_cpu(caps->formats);
|
||||
stream->sig_bits = le32_to_cpu(caps->sig_bits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
|
||||
@ -1812,20 +1837,29 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
|
||||
if (dai_drv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (strlen(pcm->dai_name))
|
||||
if (strlen(pcm->dai_name)) {
|
||||
dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
|
||||
if (!dai_drv->name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
dai_drv->id = le32_to_cpu(pcm->dai_id);
|
||||
|
||||
if (pcm->playback) {
|
||||
stream = &dai_drv->playback;
|
||||
caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
|
||||
set_stream_info(stream, caps);
|
||||
ret = set_stream_info(stream, caps);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pcm->capture) {
|
||||
stream = &dai_drv->capture;
|
||||
caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
|
||||
set_stream_info(stream, caps);
|
||||
ret = set_stream_info(stream, caps);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pcm->compress)
|
||||
@ -1835,11 +1869,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
|
||||
ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
|
||||
kfree(dai_drv->playback.stream_name);
|
||||
kfree(dai_drv->capture.stream_name);
|
||||
kfree(dai_drv->name);
|
||||
kfree(dai_drv);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dai_drv->dobj.index = tplg->index;
|
||||
@ -1860,6 +1890,14 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(dai_drv->playback.stream_name);
|
||||
kfree(dai_drv->capture.stream_name);
|
||||
kfree(dai_drv->name);
|
||||
kfree(dai_drv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1916,11 +1954,20 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
|
||||
if (strlen(pcm->pcm_name)) {
|
||||
link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
|
||||
link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
|
||||
if (!link->name || !link->stream_name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
link->id = le32_to_cpu(pcm->pcm_id);
|
||||
|
||||
if (strlen(pcm->dai_name))
|
||||
if (strlen(pcm->dai_name)) {
|
||||
link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
|
||||
if (!link->cpus->dai_name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
link->codecs->name = "snd-soc-dummy";
|
||||
link->codecs->dai_name = "snd-soc-dummy-dai";
|
||||
@ -2088,7 +2135,9 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
|
||||
_pcm = pcm;
|
||||
} else {
|
||||
abi_match = false;
|
||||
pcm_new_ver(tplg, pcm, &_pcm);
|
||||
ret = pcm_new_ver(tplg, pcm, &_pcm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* create the FE DAIs and DAI links */
|
||||
@ -2436,13 +2485,17 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
|
||||
if (d->playback) {
|
||||
stream = &dai_drv->playback;
|
||||
caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
|
||||
set_stream_info(stream, caps);
|
||||
ret = set_stream_info(stream, caps);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (d->capture) {
|
||||
stream = &dai_drv->capture;
|
||||
caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
|
||||
set_stream_info(stream, caps);
|
||||
ret = set_stream_info(stream, caps);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (d->flag_mask)
|
||||
@ -2454,10 +2507,15 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
|
||||
ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
|
||||
if (ret < 0) {
|
||||
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(dai_drv->playback.stream_name);
|
||||
kfree(dai_drv->capture.stream_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* load physical DAI elements */
|
||||
@ -2466,7 +2524,7 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
|
||||
{
|
||||
struct snd_soc_tplg_dai *dai;
|
||||
int count;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
count = le32_to_cpu(hdr->count);
|
||||
|
||||
@ -2481,7 +2539,12 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_tplg_dai_config(tplg, dai);
|
||||
ret = soc_tplg_dai_config(tplg, dai);
|
||||
if (ret < 0) {
|
||||
dev_err(tplg->dev, "ASoC: failed to configure DAI\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
tplg->pos += (sizeof(*dai) + le32_to_cpu(dai->priv.size));
|
||||
}
|
||||
|
||||
@ -2589,7 +2652,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
|
||||
}
|
||||
|
||||
/* big endian firmware objects not supported atm */
|
||||
if (hdr->magic == SOC_TPLG_MAGIC_BIG_ENDIAN) {
|
||||
if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) {
|
||||
dev_err(tplg->dev,
|
||||
"ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
|
||||
tplg->pass, hdr->magic,
|
||||
|
@ -567,9 +567,25 @@ static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach,
|
||||
static struct snd_soc_dai_driver bdw_dai[] = {
|
||||
{
|
||||
.name = "ssp0-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "ssp1-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -459,21 +459,69 @@ static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach,
|
||||
static struct snd_soc_dai_driver byt_dai[] = {
|
||||
{
|
||||
.name = "ssp0-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "ssp1-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "ssp2-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "ssp3-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "ssp4-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "ssp5-port",
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -837,7 +837,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
|
||||
cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_32);
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "Data format not supported");
|
||||
dev_err(cpu_dai->dev, "Data format not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1547,6 +1547,9 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
|
||||
conf = &stm32_sai_pcm_config_spdif;
|
||||
|
||||
ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
@ -1556,15 +1559,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &stm32_component,
|
||||
&sai->cpu_dai_drv, 1);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
snd_dmaengine_pcm_unregister(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
|
||||
conf = &stm32_sai_pcm_config_spdif;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_sai_sub_remove(struct platform_device *pdev)
|
||||
|
@ -277,6 +277,52 @@ static bool s1810c_valid_sample_rate(struct audioformat *fp,
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Many Focusrite devices supports a limited set of sampling rates per
|
||||
* altsetting. Maximum rate is exposed in the last 4 bytes of Format Type
|
||||
* descriptor which has a non-standard bLength = 10.
|
||||
*/
|
||||
static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp,
|
||||
unsigned int rate)
|
||||
{
|
||||
struct usb_interface *iface;
|
||||
struct usb_host_interface *alts;
|
||||
unsigned char *fmt;
|
||||
unsigned int max_rate;
|
||||
|
||||
iface = usb_ifnum_to_if(chip->dev, fp->iface);
|
||||
if (!iface)
|
||||
return true;
|
||||
|
||||
alts = &iface->altsetting[fp->altset_idx];
|
||||
fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen,
|
||||
NULL, UAC_FORMAT_TYPE);
|
||||
if (!fmt)
|
||||
return true;
|
||||
|
||||
if (fmt[0] == 10) { /* bLength */
|
||||
max_rate = combine_quad(&fmt[6]);
|
||||
|
||||
/* Validate max rate */
|
||||
if (max_rate != 48000 &&
|
||||
max_rate != 96000 &&
|
||||
max_rate != 192000 &&
|
||||
max_rate != 384000) {
|
||||
|
||||
usb_audio_info(chip,
|
||||
"%u:%d : unexpected max rate: %u\n",
|
||||
fp->iface, fp->altsetting, max_rate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return rate <= max_rate;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to walk the array of sample rate triplets reported by
|
||||
* the device. The problem is that we need to parse whole array first to
|
||||
@ -319,6 +365,11 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
|
||||
!s1810c_valid_sample_rate(fp, rate))
|
||||
goto skip_rate;
|
||||
|
||||
/* Filter out invalid rates on Focusrite devices */
|
||||
if (USB_ID_VENDOR(chip->usb_id) == 0x1235 &&
|
||||
!focusrite_valid_sample_rate(chip, fp, rate))
|
||||
goto skip_rate;
|
||||
|
||||
if (fp->rate_table)
|
||||
fp->rate_table[nr_rates] = rate;
|
||||
if (!fp->rate_min || rate < fp->rate_min)
|
||||
|
@ -1776,8 +1776,10 @@ static void build_connector_control(struct usb_mixer_interface *mixer,
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
struct usb_mixer_elem_info *cval;
|
||||
const struct usbmix_name_map *map;
|
||||
|
||||
if (check_ignored_ctl(find_map(imap, term->id, 0)))
|
||||
map = find_map(imap, term->id, 0);
|
||||
if (check_ignored_ctl(map))
|
||||
return;
|
||||
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
@ -1809,8 +1811,12 @@ static void build_connector_control(struct usb_mixer_interface *mixer,
|
||||
usb_mixer_elem_info_free(cval);
|
||||
return;
|
||||
}
|
||||
get_connector_control_name(mixer, term, is_input, kctl->id.name,
|
||||
sizeof(kctl->id.name));
|
||||
|
||||
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)))
|
||||
strlcat(kctl->id.name, " Jack", sizeof(kctl->id.name));
|
||||
else
|
||||
get_connector_control_name(mixer, term, is_input, kctl->id.name,
|
||||
sizeof(kctl->id.name));
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
@ -3111,6 +3117,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
|
||||
if (map->id == state.chip->usb_id) {
|
||||
state.map = map->map;
|
||||
state.selector_map = map->selector_map;
|
||||
mixer->connector_map = map->connector_map;
|
||||
mixer->ignore_ctl_error |= map->ignore_ctl_error;
|
||||
break;
|
||||
}
|
||||
@ -3192,10 +3199,32 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delegate_notify(struct usb_mixer_interface *mixer, int unitid,
|
||||
u8 *control, u8 *channel)
|
||||
{
|
||||
const struct usbmix_connector_map *map = mixer->connector_map;
|
||||
|
||||
if (!map)
|
||||
return unitid;
|
||||
|
||||
for (; map->id; map++) {
|
||||
if (map->id == unitid) {
|
||||
if (control && map->control)
|
||||
*control = map->control;
|
||||
if (channel && map->channel)
|
||||
*channel = map->channel;
|
||||
return map->delegated_id;
|
||||
}
|
||||
}
|
||||
return unitid;
|
||||
}
|
||||
|
||||
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
|
||||
{
|
||||
struct usb_mixer_elem_list *list;
|
||||
|
||||
unitid = delegate_notify(mixer, unitid, NULL, NULL);
|
||||
|
||||
for_each_mixer_elem(list, mixer, unitid) {
|
||||
struct usb_mixer_elem_info *info =
|
||||
mixer_elem_list_to_info(list);
|
||||
@ -3265,6 +3294,8 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
|
||||
return;
|
||||
}
|
||||
|
||||
unitid = delegate_notify(mixer, unitid, &control, &channel);
|
||||
|
||||
for_each_mixer_elem(list, mixer, unitid)
|
||||
count++;
|
||||
|
||||
|
@ -6,6 +6,13 @@
|
||||
|
||||
struct media_mixer_ctl;
|
||||
|
||||
struct usbmix_connector_map {
|
||||
u8 id;
|
||||
u8 delegated_id;
|
||||
u8 control;
|
||||
u8 channel;
|
||||
};
|
||||
|
||||
struct usb_mixer_interface {
|
||||
struct snd_usb_audio *chip;
|
||||
struct usb_host_interface *hostif;
|
||||
@ -18,6 +25,9 @@ struct usb_mixer_interface {
|
||||
/* the usb audio specification version this interface complies to */
|
||||
int protocol;
|
||||
|
||||
/* optional connector delegation map */
|
||||
const struct usbmix_connector_map *connector_map;
|
||||
|
||||
/* Sound Blaster remote control stuff */
|
||||
const struct rc_config *rc_cfg;
|
||||
u32 rc_code;
|
||||
|
@ -27,6 +27,7 @@ struct usbmix_ctl_map {
|
||||
u32 id;
|
||||
const struct usbmix_name_map *map;
|
||||
const struct usbmix_selector_map *selector_map;
|
||||
const struct usbmix_connector_map *connector_map;
|
||||
int ignore_ctl_error;
|
||||
};
|
||||
|
||||
@ -369,6 +370,33 @@ static const struct usbmix_name_map asus_rog_map[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
/* TRX40 mobos with Realtek ALC1220-VB */
|
||||
static const struct usbmix_name_map trx40_mobo_map[] = {
|
||||
{ 18, NULL }, /* OT, IEC958 - broken response, disabled */
|
||||
{ 19, NULL, 12 }, /* FU, Input Gain Pad - broken response, disabled */
|
||||
{ 16, "Speaker" }, /* OT */
|
||||
{ 22, "Speaker Playback" }, /* FU */
|
||||
{ 7, "Line" }, /* IT */
|
||||
{ 19, "Line Capture" }, /* FU */
|
||||
{ 17, "Front Headphone" }, /* OT */
|
||||
{ 23, "Front Headphone Playback" }, /* FU */
|
||||
{ 8, "Mic" }, /* IT */
|
||||
{ 20, "Mic Capture" }, /* FU */
|
||||
{ 9, "Front Mic" }, /* IT */
|
||||
{ 21, "Front Mic Capture" }, /* FU */
|
||||
{ 24, "IEC958 Playback" }, /* FU */
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct usbmix_connector_map trx40_mobo_connector_map[] = {
|
||||
{ 10, 16 }, /* (Back) Speaker */
|
||||
{ 11, 17 }, /* Front Headphone */
|
||||
{ 13, 7 }, /* Line */
|
||||
{ 14, 8 }, /* Mic */
|
||||
{ 15, 9 }, /* Front Mic */
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Control map entries
|
||||
*/
|
||||
@ -500,7 +528,8 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
},
|
||||
{ /* Gigabyte TRX40 Aorus Pro WiFi */
|
||||
.id = USB_ID(0x0414, 0xa002),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ /* ASUS ROG Zenith II */
|
||||
.id = USB_ID(0x0b05, 0x1916),
|
||||
@ -512,11 +541,13 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
||||
},
|
||||
{ /* MSI TRX40 Creator */
|
||||
.id = USB_ID(0x0db0, 0x0d64),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ /* MSI TRX40 */
|
||||
.id = USB_ID(0x0db0, 0x543d),
|
||||
.map = asus_rog_map,
|
||||
.map = trx40_mobo_map,
|
||||
.connector_map = trx40_mobo_connector_map,
|
||||
},
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
@ -1509,11 +1509,15 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
|
||||
|
||||
/* use known values for that card: interface#1 altsetting#1 */
|
||||
iface = usb_ifnum_to_if(chip->dev, 1);
|
||||
if (!iface || iface->num_altsetting < 2)
|
||||
return -EINVAL;
|
||||
if (!iface || iface->num_altsetting < 2) {
|
||||
err = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
alts = &iface->altsetting[1];
|
||||
if (get_iface_desc(alts)->bNumEndpoints < 1)
|
||||
return -EINVAL;
|
||||
if (get_iface_desc(alts)->bNumEndpoints < 1) {
|
||||
err = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
ep = get_endpoint(alts, 0)->bEndpointAddress;
|
||||
|
||||
err = snd_usb_ctl_msg(chip->dev,
|
||||
|
@ -2756,90 +2756,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.type = QUIRK_MIDI_NOVATION
|
||||
}
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Focusrite Scarlett Solo 2nd generation
|
||||
* Reports that playback should use Synch: Synchronous
|
||||
* while still providing a feedback endpoint. Synchronous causes
|
||||
* snapping on some sample rates.
|
||||
* Force it to use Synch: Asynchronous.
|
||||
*/
|
||||
USB_DEVICE(0x1235, 0x8205),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 2,
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = 0,
|
||||
.endpoint = 0x01,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC,
|
||||
.protocol = UAC_VERSION_2,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 192000,
|
||||
.nr_rates = 6,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000, 88200,
|
||||
96000, 176400, 192000
|
||||
},
|
||||
.clock = 41
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 2,
|
||||
.iface = 2,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = 0,
|
||||
.endpoint = 0x82,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC |
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
.protocol = UAC_VERSION_2,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 |
|
||||
SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 192000,
|
||||
.nr_rates = 6,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000, 88200,
|
||||
96000, 176400, 192000
|
||||
},
|
||||
.clock = 41
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Access Music devices */
|
||||
{
|
||||
@ -3635,4 +3551,18 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
||||
}
|
||||
},
|
||||
|
||||
#define ALC1220_VB_DESKTOP(vend, prod) { \
|
||||
USB_DEVICE(vend, prod), \
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
|
||||
.vendor_name = "Realtek", \
|
||||
.product_name = "ALC1220-VB-DT", \
|
||||
.profile_name = "Realtek-ALC1220-VB-Desktop", \
|
||||
.ifnum = QUIRK_NO_INTERFACE \
|
||||
} \
|
||||
}
|
||||
ALC1220_VB_DESKTOP(0x0414, 0xa002), /* Gigabyte TRX40 Aorus Pro WiFi */
|
||||
ALC1220_VB_DESKTOP(0x0db0, 0x0d64), /* MSI TRX40 Creator */
|
||||
ALC1220_VB_DESKTOP(0x0db0, 0x543d), /* MSI TRX40 */
|
||||
#undef ALC1220_VB_DESKTOP
|
||||
|
||||
#undef USB_DEVICE_VENDOR_SPEC
|
||||
|
@ -1806,6 +1806,20 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
|
||||
*/
|
||||
fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX;
|
||||
break;
|
||||
case USB_ID(0x1235, 0x8200): /* Focusrite Scarlett 2i4 2nd gen */
|
||||
case USB_ID(0x1235, 0x8202): /* Focusrite Scarlett 2i2 2nd gen */
|
||||
case USB_ID(0x1235, 0x8205): /* Focusrite Scarlett Solo 2nd gen */
|
||||
/*
|
||||
* Reports that playback should use Synch: Synchronous
|
||||
* while still providing a feedback endpoint.
|
||||
* Synchronous causes snapping on some sample rates.
|
||||
* Force it to use Synch: Asynchronous.
|
||||
*/
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
|
||||
fp->ep_attr |= USB_ENDPOINT_SYNC_ASYNC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,6 +681,8 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
|
||||
us->submitted = 2*NOOF_SETRATE_URBS;
|
||||
for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
|
||||
struct urb *urb = us->urb[i];
|
||||
if (!urb)
|
||||
continue;
|
||||
if (urb->status) {
|
||||
if (!err)
|
||||
err = -ENODEV;
|
||||
|
Loading…
Reference in New Issue
Block a user