mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
ASoC: Fixes for v5.2
There's an awful lot of fixes here, almost all for the newly introduced SoF DSP drivers (including a few things it turned up in shared code). This is a large and complex piece of code so it's not surprising that there have been quite a few issues here, fortunately things seem to have mostly calmed down now. Otherwise there's just a smattering of small fixes. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl0CaS4THGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0Ia0B/9wO0pSbtZjH63zg6khj+HQKuw5HG+5 3tYMZml0c/vAmJxHCPlgGZRwRSq7rFCyJS+e4bBMCfWdjHtFuFkZtQ+jNbOxN5vf 50/L/ixXs/iWQ4u9CV7wBUSTQgqQav4T5KWCQcYcY56hR20ubmT8K/MFTYOVIwhs VftWpUThi/onqgRoO08ZyKjcIoqJK9UqvNllSbCb2qY2zgCc9GmWcWbtTYKbFsLP czcHx9Wid0k3FlY+FqleGRyre7m1Gun94cxc3MQFOt7CO47x8gVQdMJVI+iAwRlQ 5Fz+l+7oaYYpAgLhdrw0scHGU58C46h3KCQmAhYUk8NzqLB9ev6QGe18 =SMgt -----END PGP SIGNATURE----- Merge tag 'asoc-fix-v5.2-rc4' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Fixes for v5.2 There's an awful lot of fixes here, almost all for the newly introduced SoF DSP drivers (including a few things it turned up in shared code). This is a large and complex piece of code so it's not surprising that there have been quite a few issues here, fortunately things seem to have mostly calmed down now. Otherwise there's just a smattering of small fixes.
This commit is contained in:
commit
84396d1418
@ -49,6 +49,7 @@ enum sof_ipc_dai_type {
|
||||
SOF_DAI_INTEL_SSP, /**< Intel SSP */
|
||||
SOF_DAI_INTEL_DMIC, /**< Intel DMIC */
|
||||
SOF_DAI_INTEL_HDA, /**< Intel HD/A */
|
||||
SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */
|
||||
};
|
||||
|
||||
/* general purpose DAI configuration */
|
||||
|
@ -48,6 +48,7 @@
|
||||
#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U)
|
||||
#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U)
|
||||
#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
|
||||
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
|
||||
|
||||
/*
|
||||
* DSP Command Message Types
|
||||
@ -78,6 +79,7 @@
|
||||
#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002)
|
||||
#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003)
|
||||
#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004)
|
||||
#define SOF_IPC_COMP_NOTIFICATION SOF_CMD_TYPE(0x005)
|
||||
|
||||
/* DAI messages */
|
||||
#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001)
|
||||
@ -153,6 +155,27 @@ struct sof_ipc_compound_hdr {
|
||||
uint32_t count; /**< count of 0 means end of compound sequence */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* OOPS header architecture specific data.
|
||||
*/
|
||||
struct sof_ipc_dsp_oops_arch_hdr {
|
||||
uint32_t arch; /* Identifier of architecture */
|
||||
uint32_t totalsize; /* Total size of oops message */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* OOPS header platform specific data.
|
||||
*/
|
||||
struct sof_ipc_dsp_oops_plat_hdr {
|
||||
uint32_t configidhi; /* ConfigID hi 32bits */
|
||||
uint32_t configidlo; /* ConfigID lo 32bits */
|
||||
uint32_t numaregs; /* Special regs num */
|
||||
uint32_t stackoffset; /* Offset to stack pointer from beginning of
|
||||
* oops message
|
||||
*/
|
||||
uint32_t stackptr; /* Stack ptr */
|
||||
} __packed;
|
||||
|
||||
/** @}*/
|
||||
|
||||
#endif
|
||||
|
@ -18,6 +18,14 @@
|
||||
|
||||
#define SOF_IPC_MAX_ELEMS 16
|
||||
|
||||
/*
|
||||
* Firmware boot info flag bits (64-bit)
|
||||
*/
|
||||
#define SOF_IPC_INFO_BUILD BIT(0)
|
||||
#define SOF_IPC_INFO_LOCKS BIT(1)
|
||||
#define SOF_IPC_INFO_LOCKSV BIT(2)
|
||||
#define SOF_IPC_INFO_GDB BIT(3)
|
||||
|
||||
/* extended data types that can be appended onto end of sof_ipc_fw_ready */
|
||||
enum sof_ipc_ext_data {
|
||||
SOF_IPC_EXT_DMA_BUFFER = 0,
|
||||
@ -49,16 +57,8 @@ struct sof_ipc_fw_ready {
|
||||
uint32_t hostbox_size;
|
||||
struct sof_ipc_fw_version version;
|
||||
|
||||
/* Miscellaneous debug flags showing build/debug features enabled */
|
||||
union {
|
||||
uint64_t reserved;
|
||||
struct {
|
||||
uint64_t build:1;
|
||||
uint64_t locks:1;
|
||||
uint64_t locks_verbose:1;
|
||||
uint64_t gdb:1;
|
||||
} bits;
|
||||
} debug;
|
||||
/* Miscellaneous flags */
|
||||
uint64_t flags;
|
||||
|
||||
/* reserved for future use */
|
||||
uint32_t reserved[4];
|
||||
|
@ -17,7 +17,8 @@
|
||||
|
||||
/* Xtensa Firmware Oops data */
|
||||
struct sof_ipc_dsp_oops_xtensa {
|
||||
struct sof_ipc_hdr hdr;
|
||||
struct sof_ipc_dsp_oops_arch_hdr arch_hdr;
|
||||
struct sof_ipc_dsp_oops_plat_hdr plat_hdr;
|
||||
uint32_t exccause;
|
||||
uint32_t excvaddr;
|
||||
uint32_t ps;
|
||||
@ -38,7 +39,11 @@ struct sof_ipc_dsp_oops_xtensa {
|
||||
uint32_t intenable;
|
||||
uint32_t interrupt;
|
||||
uint32_t sar;
|
||||
uint32_t stack;
|
||||
uint32_t debugcause;
|
||||
uint32_t windowbase;
|
||||
uint32_t windowstart;
|
||||
uint32_t excsave1;
|
||||
uint32_t ar[];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
/* SOF ABI version major, minor and patch numbers */
|
||||
#define SOF_ABI_MAJOR 3
|
||||
#define SOF_ABI_MINOR 4
|
||||
#define SOF_ABI_MINOR 6
|
||||
#define SOF_ABI_PATCH 0
|
||||
|
||||
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
|
||||
|
@ -170,7 +170,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
|
||||
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
|
||||
{
|
||||
snd_hdac_device_exit(hdev);
|
||||
kfree(hdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
|
||||
|
||||
|
@ -840,7 +840,14 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
|
||||
if (codec->core.type == HDA_DEV_LEGACY)
|
||||
snd_hdac_device_unregister(&codec->core);
|
||||
codec_display_power(codec, false);
|
||||
put_device(hda_codec_dev(codec));
|
||||
|
||||
/*
|
||||
* In the case of ASoC HD-audio bus, the device refcount is released in
|
||||
* snd_hdac_ext_bus_device_remove() explicitly.
|
||||
*/
|
||||
if (codec->core.type == HDA_DEV_LEGACY)
|
||||
put_device(hda_codec_dev(codec));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -304,7 +304,10 @@ static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
|
||||
AK4458_00_CONTROL1,
|
||||
AK4458_RSTN_MASK,
|
||||
0x0);
|
||||
return ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4458_hw_params(struct snd_pcm_substream *substream,
|
||||
@ -536,9 +539,10 @@ static void ak4458_power_on(struct ak4458_priv *ak4458)
|
||||
}
|
||||
}
|
||||
|
||||
static void ak4458_init(struct snd_soc_component *component)
|
||||
static int ak4458_init(struct snd_soc_component *component)
|
||||
{
|
||||
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
/* External Mute ON */
|
||||
if (ak4458->mute_gpiod)
|
||||
@ -546,21 +550,21 @@ static void ak4458_init(struct snd_soc_component *component)
|
||||
|
||||
ak4458_power_on(ak4458);
|
||||
|
||||
snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
|
||||
ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
|
||||
0x80, 0x80); /* ACKS bit = 1; 10000000 */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ak4458_rstn_control(component, 1);
|
||||
return ak4458_rstn_control(component, 1);
|
||||
}
|
||||
|
||||
static int ak4458_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ak4458_init(component);
|
||||
|
||||
ak4458->fs = 48000;
|
||||
|
||||
return 0;
|
||||
return ak4458_init(component);
|
||||
}
|
||||
|
||||
static void ak4458_remove(struct snd_soc_component *component)
|
||||
|
@ -60,7 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = {
|
||||
static bool cs4265_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2:
|
||||
case CS4265_CHIP_ID ... CS4265_MAX_REGISTER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -558,6 +558,7 @@ static int cs42xx8_runtime_resume(struct device *dev)
|
||||
msleep(5);
|
||||
|
||||
regcache_cache_only(cs42xx8->regmap, false);
|
||||
regcache_mark_dirty(cs42xx8->regmap);
|
||||
|
||||
ret = regcache_sync(cs42xx8->regmap);
|
||||
if (ret) {
|
||||
|
@ -1909,6 +1909,21 @@ static int max98090_configure_dmic(struct max98090_priv *max98090,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98090_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int fmt = max98090->dai_fmt;
|
||||
|
||||
/* Remove 24-bit format support if it is not in right justified mode. */
|
||||
if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_RIGHT_J) {
|
||||
substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
|
||||
snd_pcm_hw_constraint_msbits(substream->runtime, 0, 16, 16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
@ -2316,6 +2331,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect);
|
||||
#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops max98090_dai_ops = {
|
||||
.startup = max98090_dai_startup,
|
||||
.set_sysclk = max98090_dai_set_sysclk,
|
||||
.set_fmt = max98090_dai_set_fmt,
|
||||
.set_tdm_slot = max98090_set_tdm_slot,
|
||||
|
@ -405,6 +405,8 @@ static int rt274_mic_detect(struct snd_soc_component *component,
|
||||
{
|
||||
struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
rt274->jack = jack;
|
||||
|
||||
if (jack == NULL) {
|
||||
/* Disable jack detection */
|
||||
regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
|
||||
@ -412,7 +414,6 @@ static int rt274_mic_detect(struct snd_soc_component *component,
|
||||
|
||||
return 0;
|
||||
}
|
||||
rt274->jack = jack;
|
||||
|
||||
regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
|
||||
RT274_IRQ_EN, RT274_IRQ_EN);
|
||||
|
@ -2882,6 +2882,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE3),
|
||||
},
|
||||
{
|
||||
.callback = rt5670_quirk_cb,
|
||||
.ident = "Aegex 10 tablet (RU2)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
|
||||
RT5670_DMIC2_INR |
|
||||
RT5670_DEV_GPIO |
|
||||
RT5670_JD_MODE3),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -101,7 +101,7 @@ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
|
||||
u32 word_size = min_t(u32, dstlen, 8);
|
||||
|
||||
for (w = 0; w < dstlen; w += word_size) {
|
||||
for (i = 0; i < word_size; i++) {
|
||||
for (i = 0; i < word_size && i + w < dstlen; i++) {
|
||||
si = w + word_size - i - 1;
|
||||
dst[w + i] = si < srclen ? src[si] : 0;
|
||||
}
|
||||
@ -152,8 +152,9 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
|
||||
status |= spi_sync(g_spi, &m);
|
||||
mutex_unlock(&spi_mutex);
|
||||
|
||||
|
||||
/* Copy data back to caller buffer */
|
||||
rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len);
|
||||
rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -282,8 +282,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((outrate > 8000 && outrate < 30000) &&
|
||||
(outrate/inrate > 24 || inrate/outrate > 8)) {
|
||||
if ((outrate >= 8000 && outrate <= 30000) &&
|
||||
(outrate > 24 * inrate || inrate > 8 * outrate)) {
|
||||
pair_err("exceed supported ratio range [1/24, 8] for \
|
||||
inrate/outrate: %d/%d\n", inrate, outrate);
|
||||
return -EINVAL;
|
||||
|
@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
|
||||
{
|
||||
struct ipc_post *msg;
|
||||
|
||||
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
|
||||
msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
if (large) {
|
||||
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
|
||||
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
|
||||
if (!msg->mailbox_data) {
|
||||
kfree(msg);
|
||||
return -ENOMEM;
|
||||
|
@ -495,6 +495,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* override plaform name, if required */
|
||||
byt_cht_es8316_card.dev = dev;
|
||||
platform_name = mach->mach_params.platform;
|
||||
|
||||
ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card,
|
||||
@ -575,7 +576,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
|
||||
(quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo",
|
||||
mic_name[BYT_CHT_ES8316_MAP(quirk)]);
|
||||
byt_cht_es8316_card.long_name = long_name;
|
||||
byt_cht_es8316_card.dev = dev;
|
||||
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
|
||||
|
||||
ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card);
|
||||
|
@ -454,6 +454,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* override plaform name, if required */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
platform_name = mach->mach_params.platform;
|
||||
|
||||
@ -463,7 +464,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
return ret_val;
|
||||
|
||||
/* register the soc card */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
|
||||
|
||||
if (drv->quirks & QUIRK_PMC_PLT_CLK_0)
|
||||
|
@ -257,6 +257,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
|
||||
|
||||
/* override plaform name, if required */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
mach = (&pdev->dev)->platform_data;
|
||||
platform_name = mach->mach_params.platform;
|
||||
|
||||
@ -266,7 +267,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
return ret_val;
|
||||
|
||||
/* register the soc card */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@ -426,6 +426,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* override plaform name, if required */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
platform_name = mach->mach_params.platform;
|
||||
|
||||
ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
|
||||
@ -443,7 +444,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
|
||||
|
||||
/* register the soc card */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@ -29,9 +29,10 @@
|
||||
#define SOF_RT5682_MCLK_EN BIT(3)
|
||||
#define SOF_RT5682_MCLK_24MHZ BIT(4)
|
||||
#define SOF_SPEAKER_AMP_PRESENT BIT(5)
|
||||
#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6))
|
||||
#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
|
||||
#define SOF_RT5682_SSP_AMP_SHIFT 6
|
||||
#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
|
||||
#define SOF_RT5682_SSP_AMP(quirk) \
|
||||
(((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
|
||||
|
||||
/* Default: MCLK on, MCLK 19.2M, SSP0 */
|
||||
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
|
||||
@ -144,9 +145,9 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
jack = &ctx->sof_headset;
|
||||
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
ret = snd_soc_component_set_jack(component, jack, NULL);
|
||||
|
||||
if (ret) {
|
||||
|
@ -22,6 +22,7 @@ static unsigned long byt_machine_id;
|
||||
|
||||
#define BYT_THINKPAD_10 1
|
||||
#define BYT_POV_P1006W 2
|
||||
#define BYT_AEGEX_10 3
|
||||
|
||||
static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
@ -35,6 +36,12 @@ static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int byt_aegex10_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
byt_machine_id = BYT_AEGEX_10;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id byt_table[] = {
|
||||
{
|
||||
.callback = byt_thinkpad10_quirk_cb,
|
||||
@ -75,9 +82,18 @@ static const struct dmi_system_id byt_table[] = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Aegex 10 tablet (RU2) */
|
||||
.callback = byt_aegex10_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* The Thinkapd 10 and Aegex 10 tablets have the same ID problem */
|
||||
static struct snd_soc_acpi_mach byt_thinkpad_10 = {
|
||||
.id = "10EC5640",
|
||||
.drv_name = "cht-bsw-rt5672",
|
||||
@ -104,6 +120,7 @@ static struct snd_soc_acpi_mach *byt_quirk(void *arg)
|
||||
|
||||
switch (byt_machine_id) {
|
||||
case BYT_THINKPAD_10:
|
||||
case BYT_AEGEX_10:
|
||||
return &byt_thinkpad_10;
|
||||
case BYT_POV_P1006W:
|
||||
return &byt_pov_p1006w;
|
||||
|
@ -28,12 +28,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
|
||||
.sof_fw_filename = "sof-cnl.ri",
|
||||
.sof_tplg_filename = "sof-cnl-rt274.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10EC5682",
|
||||
.drv_name = "sof_rt5682",
|
||||
.sof_fw_filename = "sof-cnl.ri",
|
||||
.sof_tplg_filename = "sof-cml-rt5682.tplg",
|
||||
},
|
||||
{
|
||||
.id = "MX98357A",
|
||||
.drv_name = "sof_rt5682",
|
||||
@ -41,6 +35,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
|
||||
.sof_fw_filename = "sof-cnl.ri",
|
||||
.sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10EC5682",
|
||||
.drv_name = "sof_rt5682",
|
||||
.sof_fw_filename = "sof-cnl.ri",
|
||||
.sof_tplg_filename = "sof-cml-rt5682.tplg",
|
||||
},
|
||||
|
||||
{},
|
||||
};
|
||||
|
@ -132,7 +132,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A
|
||||
|
||||
config SND_SOC_MT8183_DA7219_MAX98357A
|
||||
tristate "ASoC Audio driver for MT8183 with DA7219 MAX98357A codec"
|
||||
depends on SND_SOC_MT8183
|
||||
depends on SND_SOC_MT8183 && I2C
|
||||
select SND_SOC_MT6358
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_DA7219
|
||||
|
@ -228,7 +228,10 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
|
||||
|
||||
static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
|
||||
{
|
||||
if (!card->debugfs_card_root)
|
||||
return;
|
||||
debugfs_remove_recursive(card->debugfs_card_root);
|
||||
card->debugfs_card_root = NULL;
|
||||
}
|
||||
|
||||
static void snd_soc_debugfs_init(void)
|
||||
@ -2037,8 +2040,10 @@ match:
|
||||
static int soc_cleanup_card_resources(struct snd_soc_card *card)
|
||||
{
|
||||
/* free the ALSA card at first; this syncs with pending operations */
|
||||
if (card->snd_card)
|
||||
if (card->snd_card) {
|
||||
snd_card_free(card->snd_card);
|
||||
card->snd_card = NULL;
|
||||
}
|
||||
|
||||
/* remove and free each DAI */
|
||||
soc_remove_dai_links(card);
|
||||
@ -2065,6 +2070,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
|
||||
int ret, i, order;
|
||||
|
||||
mutex_lock(&client_mutex);
|
||||
for_each_card_prelinks(card, i, dai_link) {
|
||||
ret = soc_init_dai_link(card, dai_link);
|
||||
if (ret) {
|
||||
soc_cleanup_platform(card);
|
||||
dev_err(card->dev, "ASoC: failed to init link %s: %d\n",
|
||||
dai_link->name, ret);
|
||||
mutex_unlock(&client_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
|
||||
|
||||
card->dapm.bias_level = SND_SOC_BIAS_OFF;
|
||||
@ -2789,26 +2804,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
||||
*/
|
||||
int snd_soc_register_card(struct snd_soc_card *card)
|
||||
{
|
||||
int i, ret;
|
||||
struct snd_soc_dai_link *link;
|
||||
|
||||
if (!card->name || !card->dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&client_mutex);
|
||||
for_each_card_prelinks(card, i, link) {
|
||||
|
||||
ret = soc_init_dai_link(card, link);
|
||||
if (ret) {
|
||||
soc_cleanup_platform(card);
|
||||
dev_err(card->dev, "ASoC: failed to init link %s\n",
|
||||
link->name);
|
||||
mutex_unlock(&client_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client_mutex);
|
||||
|
||||
dev_set_drvdata(card->dev, card);
|
||||
|
||||
snd_soc_initialize_card_lists(card);
|
||||
@ -2839,12 +2837,14 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
|
||||
snd_soc_dapm_shutdown(card);
|
||||
snd_soc_flush_all_delayed_work(card);
|
||||
|
||||
mutex_lock(&client_mutex);
|
||||
/* remove all components used by DAI links on this card */
|
||||
for_each_comp_order(order) {
|
||||
for_each_card_rtds(card, rtd) {
|
||||
soc_remove_link_components(card, rtd, order);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client_mutex);
|
||||
|
||||
soc_cleanup_card_resources(card);
|
||||
if (!unregister)
|
||||
|
@ -2193,7 +2193,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
|
||||
|
||||
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
if (!dapm->debugfs_dapm)
|
||||
return;
|
||||
debugfs_remove_recursive(dapm->debugfs_dapm);
|
||||
dapm->debugfs_dapm = NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
@ -3831,8 +3834,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
source->active++;
|
||||
}
|
||||
source->active++;
|
||||
ret = soc_dai_hw_params(&substream, params, source);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -3853,8 +3856,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
sink->active++;
|
||||
}
|
||||
sink->active++;
|
||||
ret = soc_dai_hw_params(&substream, params, sink);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -2479,7 +2479,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
|
||||
|
||||
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
|
||||
continue;
|
||||
|
||||
dev_dbg(be->dev, "ASoC: prepare BE %s\n",
|
||||
|
@ -44,7 +44,10 @@ config SND_SOC_SOF_OPTIONS
|
||||
if SND_SOC_SOF_OPTIONS
|
||||
|
||||
config SND_SOC_SOF_NOCODEC
|
||||
tristate "SOF nocodec mode Support"
|
||||
tristate
|
||||
|
||||
config SND_SOC_SOF_NOCODEC_SUPPORT
|
||||
bool "SOF nocodec mode support"
|
||||
help
|
||||
This adds support for a dummy/nocodec machine driver fallback
|
||||
option if no known codec is detected. This is typically only
|
||||
@ -80,7 +83,7 @@ if SND_SOC_SOF_DEBUG
|
||||
|
||||
config SND_SOC_SOF_FORCE_NOCODEC_MODE
|
||||
bool "SOF force nocodec Mode"
|
||||
depends on SND_SOC_SOF_NOCODEC
|
||||
depends on SND_SOC_SOF_NOCODEC_SUPPORT
|
||||
help
|
||||
This forces SOF to use dummy/nocodec as machine driver, even
|
||||
though there is a codec detected on the real platform. This is
|
||||
@ -135,6 +138,7 @@ endif ## SND_SOC_SOF_OPTIONS
|
||||
config SND_SOC_SOF
|
||||
tristate
|
||||
select SND_SOC_TOPOLOGY
|
||||
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
|
||||
help
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level
|
||||
|
@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
struct sof_abi_hdr *data = cdata->data;
|
||||
size_t size = data->size + sizeof(*data);
|
||||
int ret, err;
|
||||
|
||||
if (be->max > sizeof(ucontrol->value.bytes.data)) {
|
||||
@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data->size > be->max) {
|
||||
if (size > be->max) {
|
||||
dev_err_ratelimited(sdev->dev,
|
||||
"error: size too big %d bytes max is %d\n",
|
||||
data->size, be->max);
|
||||
"error: size too big %zu bytes max is %d\n",
|
||||
size, be->max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
/* copy from kcontrol */
|
||||
memcpy(data, ucontrol->value.bytes.data, data->size);
|
||||
memcpy(data, ucontrol->value.bytes.data, size);
|
||||
|
||||
/* notify DSP of byte control updates */
|
||||
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
|
@ -382,7 +382,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
|
||||
|
||||
if (IS_ERR(plat_data->pdev_mach)) {
|
||||
ret = PTR_ERR(plat_data->pdev_mach);
|
||||
goto comp_err;
|
||||
goto fw_run_err;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "created machine %s\n",
|
||||
@ -393,8 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
|
||||
|
||||
return 0;
|
||||
|
||||
comp_err:
|
||||
snd_soc_unregister_component(sdev->dev);
|
||||
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
|
||||
fw_run_err:
|
||||
snd_sof_fw_unload(sdev);
|
||||
fw_load_err:
|
||||
@ -403,6 +402,21 @@ ipc_err:
|
||||
snd_sof_free_debug(sdev);
|
||||
dbg_err:
|
||||
snd_sof_remove(sdev);
|
||||
#else
|
||||
|
||||
/*
|
||||
* when the probe_continue is handled in a work queue, the
|
||||
* probe does not fail so we don't release resources here.
|
||||
* They will be released with an explicit call to
|
||||
* snd_sof_device_remove() when the PCI/ACPI device is removed
|
||||
*/
|
||||
|
||||
fw_run_err:
|
||||
fw_load_err:
|
||||
ipc_err:
|
||||
dbg_err:
|
||||
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -484,7 +498,6 @@ int snd_sof_device_remove(struct device *dev)
|
||||
snd_sof_ipc_free(sdev);
|
||||
snd_sof_free_debug(sdev);
|
||||
snd_sof_free_trace(sdev);
|
||||
snd_sof_remove(sdev);
|
||||
|
||||
/*
|
||||
* Unregister machine driver. This will unbind the snd_card which
|
||||
@ -494,6 +507,14 @@ int snd_sof_device_remove(struct device *dev)
|
||||
if (!IS_ERR_OR_NULL(pdata->pdev_mach))
|
||||
platform_device_unregister(pdata->pdev_mach);
|
||||
|
||||
/*
|
||||
* Unregistering the machine driver results in unloading the topology.
|
||||
* Some widgets, ex: scheduler, attempt to power down the core they are
|
||||
* scheduled on, when they are unloaded. Therefore, the DSP must be
|
||||
* removed only after the topology has been unloaded.
|
||||
*/
|
||||
snd_sof_remove(sdev);
|
||||
|
||||
/* release firmware */
|
||||
release_firmware(pdata->fw);
|
||||
pdata->fw = NULL;
|
||||
|
@ -220,17 +220,20 @@ static void bdw_get_registers(struct snd_sof_dev *sdev,
|
||||
struct sof_ipc_panic_info *panic_info,
|
||||
u32 *stack, size_t stack_words)
|
||||
{
|
||||
/* first read regsisters */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
|
||||
u32 offset = sdev->dsp_oops_offset;
|
||||
|
||||
/* first read registers */
|
||||
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
|
||||
|
||||
/* note: variable AR register array is not read */
|
||||
|
||||
/* then get panic info */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
|
||||
panic_info, sizeof(*panic_info));
|
||||
offset += xoops->arch_hdr.totalsize;
|
||||
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
|
||||
|
||||
/* then get the stack */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
|
||||
sizeof(*panic_info), stack,
|
||||
stack_words * sizeof(u32));
|
||||
offset += sizeof(*panic_info);
|
||||
sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));
|
||||
}
|
||||
|
||||
static void bdw_dump(struct snd_sof_dev *sdev, u32 flags)
|
||||
@ -283,6 +286,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
|
||||
SHIM_IMRX, SHIM_IMRX_DONE,
|
||||
SHIM_IMRX_DONE);
|
||||
|
||||
spin_lock_irq(&sdev->ipc_lock);
|
||||
|
||||
/*
|
||||
* handle immediate reply from DSP core. If the msg is
|
||||
* found, set done bit in cmd_done which is called at the
|
||||
@ -294,6 +299,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
|
||||
snd_sof_ipc_reply(sdev, ipcx);
|
||||
|
||||
bdw_dsp_done(sdev);
|
||||
|
||||
spin_unlock_irq(&sdev->ipc_lock);
|
||||
}
|
||||
|
||||
ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
|
||||
@ -485,7 +492,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_ipc_msg *msg = sdev->msg;
|
||||
struct sof_ipc_reply reply;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -501,8 +507,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
|
||||
/* get reply */
|
||||
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
|
||||
|
||||
spin_lock_irqsave(&sdev->ipc_lock, flags);
|
||||
|
||||
if (reply.error < 0) {
|
||||
memcpy(msg->reply_data, &reply, sizeof(reply));
|
||||
ret = reply.error;
|
||||
@ -521,8 +525,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
|
||||
}
|
||||
|
||||
msg->reply_error = ret;
|
||||
|
||||
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
|
||||
}
|
||||
|
||||
static void bdw_host_done(struct snd_sof_dev *sdev)
|
||||
|
@ -265,17 +265,20 @@ static void byt_get_registers(struct snd_sof_dev *sdev,
|
||||
struct sof_ipc_panic_info *panic_info,
|
||||
u32 *stack, size_t stack_words)
|
||||
{
|
||||
u32 offset = sdev->dsp_oops_offset;
|
||||
|
||||
/* first read regsisters */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
|
||||
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
|
||||
|
||||
/* note: variable AR register array is not read */
|
||||
|
||||
/* then get panic info */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
|
||||
panic_info, sizeof(*panic_info));
|
||||
offset += xoops->arch_hdr.totalsize;
|
||||
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
|
||||
|
||||
/* then get the stack */
|
||||
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
|
||||
sizeof(*panic_info), stack,
|
||||
stack_words * sizeof(u32));
|
||||
offset += sizeof(*panic_info);
|
||||
sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));
|
||||
}
|
||||
|
||||
static void byt_dump(struct snd_sof_dev *sdev, u32 flags)
|
||||
@ -329,6 +332,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
|
||||
SHIM_IMRX,
|
||||
SHIM_IMRX_DONE,
|
||||
SHIM_IMRX_DONE);
|
||||
|
||||
spin_lock_irq(&sdev->ipc_lock);
|
||||
|
||||
/*
|
||||
* handle immediate reply from DSP core. If the msg is
|
||||
* found, set done bit in cmd_done which is called at the
|
||||
@ -340,6 +346,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
|
||||
snd_sof_ipc_reply(sdev, ipcx);
|
||||
|
||||
byt_dsp_done(sdev);
|
||||
|
||||
spin_unlock_irq(&sdev->ipc_lock);
|
||||
}
|
||||
|
||||
/* new message from DSP */
|
||||
@ -383,7 +391,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_ipc_msg *msg = sdev->msg;
|
||||
struct sof_ipc_reply reply;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -399,8 +406,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
|
||||
/* get reply */
|
||||
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
|
||||
|
||||
spin_lock_irqsave(&sdev->ipc_lock, flags);
|
||||
|
||||
if (reply.error < 0) {
|
||||
memcpy(msg->reply_data, &reply, sizeof(reply));
|
||||
ret = reply.error;
|
||||
@ -419,8 +424,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
|
||||
}
|
||||
|
||||
msg->reply_error = ret;
|
||||
|
||||
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
|
||||
}
|
||||
|
||||
static void byt_host_done(struct snd_sof_dev *sdev)
|
||||
|
@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
|
||||
CNL_DSP_REG_HIPCCTL,
|
||||
CNL_DSP_REG_HIPCCTL_DONE, 0);
|
||||
|
||||
spin_lock_irq(&sdev->ipc_lock);
|
||||
|
||||
/* handle immediate reply from DSP core */
|
||||
hda_dsp_ipc_get_reply(sdev);
|
||||
snd_sof_ipc_reply(sdev, msg);
|
||||
@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
|
||||
|
||||
cnl_ipc_dsp_done(sdev);
|
||||
|
||||
spin_unlock_irq(&sdev->ipc_lock);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
/*
|
||||
* While performing reset, controller may not come back properly and causing
|
||||
* issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
|
||||
* (init chip) and then again set CGCTL.MISCBDCGE to 1
|
||||
*/
|
||||
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
int ret;
|
||||
struct hdac_stream *stream;
|
||||
int sd_offset, ret = 0;
|
||||
|
||||
if (bus->chip_init)
|
||||
return 0;
|
||||
|
||||
hda_dsp_ctrl_misc_clock_gating(sdev, false);
|
||||
ret = snd_hdac_bus_init_chip(bus, full_reset);
|
||||
|
||||
if (full_reset) {
|
||||
/* clear WAKESTS */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
|
||||
SOF_HDA_WAKESTS_INT_MASK,
|
||||
SOF_HDA_WAKESTS_INT_MASK);
|
||||
|
||||
/* reset HDA controller */
|
||||
ret = hda_dsp_ctrl_link_reset(sdev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to reset HDA controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(500, 1000);
|
||||
|
||||
/* exit HDA controller reset */
|
||||
ret = hda_dsp_ctrl_link_reset(sdev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1200);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
/* check to see if controller is ready */
|
||||
if (!snd_hdac_chip_readb(bus, GCTL)) {
|
||||
dev_dbg(bus->dev, "controller not ready!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Accept unsolicited responses */
|
||||
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
|
||||
|
||||
/* detect codecs */
|
||||
if (!bus->codec_mask) {
|
||||
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
|
||||
dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clear stream status */
|
||||
list_for_each_entry(stream, &bus->stream_list, list) {
|
||||
sd_offset = SOF_STREAM_SD_OFFSET(stream);
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
sd_offset +
|
||||
SOF_HDA_ADSP_REG_CL_SD_STS,
|
||||
SOF_HDA_CL_DMA_SD_INT_MASK,
|
||||
SOF_HDA_CL_DMA_SD_INT_MASK);
|
||||
}
|
||||
|
||||
/* clear WAKESTS */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
|
||||
SOF_HDA_WAKESTS_INT_MASK,
|
||||
SOF_HDA_WAKESTS_INT_MASK);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
/* clear rirb status */
|
||||
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
|
||||
#endif
|
||||
|
||||
/* clear interrupt status register */
|
||||
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
/* initialize the codec command I/O */
|
||||
snd_hdac_bus_init_cmd_io(bus);
|
||||
#endif
|
||||
|
||||
/* enable CIE and GIE interrupts */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
/* program the position buffer */
|
||||
if (bus->use_posbuf && bus->posbuf.addr) {
|
||||
snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
|
||||
snd_hdac_chip_writel(bus, DPUBASE,
|
||||
upper_32_bits(bus->posbuf.addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
bus->chip_init = true;
|
||||
|
||||
hda_dsp_ctrl_misc_clock_gating(sdev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
|
||||
struct snd_sof_ipc_msg *msg = sdev->msg;
|
||||
struct sof_ipc_reply reply;
|
||||
struct sof_ipc_cmd_hdr *hdr;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
|
||||
dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
|
||||
return;
|
||||
}
|
||||
spin_lock_irqsave(&sdev->ipc_lock, flags);
|
||||
|
||||
hdr = msg->msg_data;
|
||||
if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) {
|
||||
@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
|
||||
out:
|
||||
msg->reply_error = ret;
|
||||
|
||||
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
|
||||
}
|
||||
|
||||
static bool hda_dsp_ipc_is_sof(uint32_t msg)
|
||||
@ -172,6 +169,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
|
||||
HDA_DSP_REG_HIPCCTL,
|
||||
HDA_DSP_REG_HIPCCTL_DONE, 0);
|
||||
|
||||
/*
|
||||
* Make sure the interrupt thread cannot be preempted between
|
||||
* waking up the sender and re-enabling the interrupt. Also
|
||||
* protect against a theoretical race with sof_ipc_tx_message():
|
||||
* if the DSP is fast enough to receive an IPC message, reply to
|
||||
* it, and the host interrupt processing calls this function on
|
||||
* a different core from the one, where the sending is taking
|
||||
* place, the message might not yet be marked as expecting a
|
||||
* reply.
|
||||
*/
|
||||
spin_lock_irq(&sdev->ipc_lock);
|
||||
|
||||
/* handle immediate reply from DSP core - ignore ROM messages */
|
||||
if (hda_dsp_ipc_is_sof(msg)) {
|
||||
hda_dsp_ipc_get_reply(sdev);
|
||||
@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
|
||||
/* set the done bit */
|
||||
hda_dsp_ipc_dsp_done(sdev);
|
||||
|
||||
spin_unlock_irq(&sdev->ipc_lock);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -108,17 +108,21 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
|
||||
struct sof_ipc_panic_info *panic_info,
|
||||
u32 *stack, size_t stack_words)
|
||||
{
|
||||
u32 offset = sdev->dsp_oops_offset;
|
||||
|
||||
/* first read registers */
|
||||
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops,
|
||||
sizeof(*xoops));
|
||||
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
|
||||
|
||||
/* note: variable AR register array is not read */
|
||||
|
||||
/* then get panic info */
|
||||
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
|
||||
sizeof(*xoops), panic_info, sizeof(*panic_info));
|
||||
offset += xoops->arch_hdr.totalsize;
|
||||
sof_block_read(sdev, sdev->mmio_bar, offset,
|
||||
panic_info, sizeof(*panic_info));
|
||||
|
||||
/* then get the stack */
|
||||
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
|
||||
sizeof(*xoops) + sizeof(*panic_info), stack,
|
||||
offset += sizeof(*panic_info);
|
||||
sof_block_read(sdev, sdev->mmio_bar, offset, stack,
|
||||
stack_words * sizeof(u32));
|
||||
}
|
||||
|
||||
@ -223,7 +227,9 @@ static int hda_init(struct snd_sof_dev *sdev)
|
||||
|
||||
/* initialise hdac bus */
|
||||
bus->addr = pci_resource_start(pci, 0);
|
||||
#if IS_ENABLED(CONFIG_PCI)
|
||||
bus->remap_addr = pci_ioremap_bar(pci, 0);
|
||||
#endif
|
||||
if (!bus->remap_addr) {
|
||||
dev_err(bus->dev, "error: ioremap error\n");
|
||||
return -ENXIO;
|
||||
@ -264,9 +270,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
|
||||
return tplg_filename;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
struct hdac_ext_link *hlink;
|
||||
struct snd_soc_acpi_mach_params *mach_params;
|
||||
struct snd_soc_acpi_mach *hda_mach;
|
||||
@ -274,8 +283,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
const char *tplg_filename;
|
||||
int codec_num = 0;
|
||||
int ret = 0;
|
||||
int i;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
device_disable_async_suspend(bus->dev);
|
||||
|
||||
@ -283,6 +293,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
if (bus->ppcap)
|
||||
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
|
||||
|
||||
ret = hda_dsp_ctrl_init_chip(sdev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
if (bus->mlcap)
|
||||
snd_hdac_ext_bus_get_ml_capabilities(bus);
|
||||
|
||||
@ -293,12 +311,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hda_dsp_ctrl_init_chip(sdev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* codec detection */
|
||||
if (!bus->codec_mask) {
|
||||
dev_info(bus->dev, "no hda codecs found!\n");
|
||||
@ -339,8 +351,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
/* use local variable for readability */
|
||||
tplg_filename = pdata->tplg_filename;
|
||||
tplg_filename = fixup_tplg_name(sdev, tplg_filename);
|
||||
if (!tplg_filename)
|
||||
goto out;
|
||||
if (!tplg_filename) {
|
||||
hda_codec_i915_exit(sdev);
|
||||
return ret;
|
||||
}
|
||||
pdata->tplg_filename = tplg_filename;
|
||||
}
|
||||
}
|
||||
@ -364,34 +378,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
*/
|
||||
list_for_each_entry(hlink, &bus->hlink_list, list)
|
||||
snd_hdac_ext_bus_link_put(bus, hlink);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
hda_codec_i915_exit(sdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int hda_init_caps(struct snd_sof_dev *sdev)
|
||||
{
|
||||
/*
|
||||
* set CGCTL.MISCBDCGE to 0 during reset and set back to 1
|
||||
* when reset finished.
|
||||
* TODO: maybe no need for init_caps?
|
||||
*/
|
||||
hda_dsp_ctrl_misc_clock_gating(sdev, 0);
|
||||
|
||||
/* clear WAKESTS */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
|
||||
SOF_HDA_WAKESTS_INT_MASK,
|
||||
SOF_HDA_WAKESTS_INT_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sof_intel_dsp_desc
|
||||
*get_chip_info(struct snd_sof_pdata *pdata)
|
||||
@ -409,9 +398,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
struct pci_dev *pci = to_pci_dev(sdev->dev);
|
||||
struct sof_intel_hda_dev *hdev;
|
||||
struct hdac_bus *bus;
|
||||
struct hdac_stream *stream;
|
||||
const struct sof_intel_dsp_desc *chip;
|
||||
int sd_offset, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* detect DSP by checking class/subclass/prog-id information
|
||||
@ -468,7 +456,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
goto hdac_bus_unmap;
|
||||
|
||||
/* DSP base */
|
||||
#if IS_ENABLED(CONFIG_PCI)
|
||||
sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
|
||||
#endif
|
||||
if (!sdev->bar[HDA_DSP_BAR]) {
|
||||
dev_err(sdev->dev, "error: ioremap error\n");
|
||||
ret = -ENXIO;
|
||||
@ -558,56 +548,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
if (ret < 0)
|
||||
goto free_ipc_irq;
|
||||
|
||||
/* reset HDA controller */
|
||||
ret = hda_dsp_ctrl_link_reset(sdev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to reset HDA controller\n");
|
||||
goto free_ipc_irq;
|
||||
}
|
||||
|
||||
/* exit HDA controller reset */
|
||||
ret = hda_dsp_ctrl_link_reset(sdev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
|
||||
goto free_ipc_irq;
|
||||
}
|
||||
|
||||
/* clear stream status */
|
||||
list_for_each_entry(stream, &bus->stream_list, list) {
|
||||
sd_offset = SOF_STREAM_SD_OFFSET(stream);
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
sd_offset +
|
||||
SOF_HDA_ADSP_REG_CL_SD_STS,
|
||||
SOF_HDA_CL_DMA_SD_INT_MASK,
|
||||
SOF_HDA_CL_DMA_SD_INT_MASK);
|
||||
}
|
||||
|
||||
/* clear WAKESTS */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
|
||||
SOF_HDA_WAKESTS_INT_MASK,
|
||||
SOF_HDA_WAKESTS_INT_MASK);
|
||||
|
||||
/* clear interrupt status register */
|
||||
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
|
||||
|
||||
/* enable CIE and GIE interrupts */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
|
||||
|
||||
/* re-enable CGCTL.MISCBDCGE after reset */
|
||||
hda_dsp_ctrl_misc_clock_gating(sdev, true);
|
||||
|
||||
device_disable_async_suspend(&pci->dev);
|
||||
|
||||
/* enable DSP features */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN);
|
||||
|
||||
/* enable DSP IRQ */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE);
|
||||
/* enable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, true);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
|
||||
|
||||
/* initialize waitq for code loading */
|
||||
init_waitqueue_head(&sdev->waitq);
|
||||
|
@ -115,7 +115,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
|
||||
}
|
||||
break;
|
||||
case SOF_IPC_GLB_COMP_MSG:
|
||||
str = "GLB_COMP_MSG: SET_VALUE";
|
||||
str = "GLB_COMP_MSG";
|
||||
switch (type) {
|
||||
case SOF_IPC_COMP_SET_VALUE:
|
||||
str2 = "SET_VALUE"; break;
|
||||
@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message);
|
||||
int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
|
||||
{
|
||||
struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Protect against a theoretical race with sof_ipc_tx_message(): if the
|
||||
* DSP is fast enough to receive an IPC message, reply to it, and the
|
||||
* host interrupt processing calls this function on a different core
|
||||
* from the one, where the sending is taking place, the message might
|
||||
* not yet be marked as expecting a reply.
|
||||
*/
|
||||
spin_lock_irqsave(&sdev->ipc_lock, flags);
|
||||
|
||||
if (msg->ipc_complete) {
|
||||
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
|
||||
dev_err(sdev->dev, "error: no reply expected, received 0x%x",
|
||||
msg_id);
|
||||
return -EINVAL;
|
||||
@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
|
||||
msg->ipc_complete = true;
|
||||
wake_up(&msg->waitq);
|
||||
|
||||
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_sof_ipc_reply);
|
||||
@ -776,16 +763,19 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
|
||||
}
|
||||
}
|
||||
|
||||
if (ready->debug.bits.build) {
|
||||
if (ready->flags & SOF_IPC_INFO_BUILD) {
|
||||
dev_info(sdev->dev,
|
||||
"Firmware debug build %d on %s-%s - options:\n"
|
||||
" GDB: %s\n"
|
||||
" lock debug: %s\n"
|
||||
" lock vdebug: %s\n",
|
||||
v->build, v->date, v->time,
|
||||
ready->debug.bits.gdb ? "enabled" : "disabled",
|
||||
ready->debug.bits.locks ? "enabled" : "disabled",
|
||||
ready->debug.bits.locks_verbose ? "enabled" : "disabled");
|
||||
ready->flags & SOF_IPC_INFO_GDB ?
|
||||
"enabled" : "disabled",
|
||||
ready->flags & SOF_IPC_INFO_LOCKS ?
|
||||
"enabled" : "disabled",
|
||||
ready->flags & SOF_IPC_INFO_LOCKSV ?
|
||||
"enabled" : "disabled");
|
||||
}
|
||||
|
||||
/* copy the fw_version into debugfs at first boot */
|
||||
|
@ -372,6 +372,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
|
||||
msecs_to_jiffies(sdev->boot_timeout));
|
||||
if (ret == 0) {
|
||||
dev_err(sdev->dev, "error: firmware boot failure\n");
|
||||
/* after this point FW_READY msg should be ignored */
|
||||
sdev->boot_complete = true;
|
||||
snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
|
||||
SOF_DBG_TEXT | SOF_DBG_PCI);
|
||||
return -EIO;
|
||||
|
@ -211,8 +211,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
/* save pcm hw_params */
|
||||
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
|
||||
|
||||
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
|
||||
sof_pcm_period_elapsed_work);
|
||||
/* clear hw_params_upon_resume flag */
|
||||
spcm->hw_params_upon_resume[substream->stream] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -429,8 +429,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
|
||||
dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
|
||||
substream->stream);
|
||||
|
||||
/* clear hw_params_upon_resume flag */
|
||||
spcm->hw_params_upon_resume[substream->stream] = 0;
|
||||
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
|
||||
sof_pcm_period_elapsed_work);
|
||||
|
||||
caps = &spcm->pcm.caps[substream->stream];
|
||||
|
||||
|
@ -110,7 +110,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
|
||||
u32 stack_words)
|
||||
{
|
||||
struct sof_ipc_dsp_oops_xtensa *xoops = oops;
|
||||
u32 stack_ptr = xoops->stack;
|
||||
u32 stack_ptr = xoops->plat_hdr.stackptr;
|
||||
/* 4 * 8chars + 3 ws + 1 terminating NUL */
|
||||
unsigned char buf[4 * 8 + 3 + 1];
|
||||
int i;
|
||||
|
@ -1329,6 +1329,15 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
|
||||
gpiod_set_value_cansleep(scodec->gpio_pa,
|
||||
!!SND_SOC_DAPM_EVENT_ON(event));
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
/*
|
||||
* Need a delay to wait for DAC to push the data. 700ms seems
|
||||
* to be the best compromise not to feel this delay while
|
||||
* playing a sound.
|
||||
*/
|
||||
msleep(700);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@
|
||||
|
||||
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
|
||||
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
|
||||
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
|
||||
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
|
||||
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
|
||||
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
|
||||
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
|
||||
@ -460,6 +460,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET(offset));
|
||||
|
||||
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
|
||||
SUN8I_I2S_TX_CHAN_OFFSET(offset));
|
||||
}
|
||||
|
||||
regmap_field_write(i2s->field_fmt_mode, val);
|
||||
|
Loading…
Reference in New Issue
Block a user