ASoC: Fixes for v7.4

A moderately large collection of fixes and quirks that have come in
 during the merge window, everything here is driver specific and none of
 it unusually severe.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQReagvpf3TrrA7BoYYv73Ows9A4iQUCauON8gAKCRAv73Ows9A4
 iZm5AQCsGUaurJF/x2A5bcxt7eQay8hm6SZl4dQ1IBRZSjXwCAEA8GfpfWkrs1H0
 OjjEhpZxvqsc2EToBBOQrtRYFqRKhQE=
 =hdcF
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v7.4-merge-window' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v7.4

A moderately large collection of fixes and quirks that have come in
during the merge window, everything here is driver specific and none of
it unusually severe.
This commit is contained in:
Takashi Iwai 2026-10-31 16:31:50 +01:00
commit 74f6055d0c
38 changed files with 685 additions and 248 deletions

View File

@ -209,6 +209,9 @@ struct snd_ctl_elem_value;
#define CS35L56_GPIO_FN_GPIO 0x00000001
/* DSP1_FW_VER */
#define CS35L56_FW_MAIN_VERSION_MASK GENMASK(19, 0)
/* Mixer input sources */
#define CS35L56_INPUT_SRC_NONE 0x00
#define CS35L56_INPUT_SRC_ASP1RX1 0x08
@ -446,6 +449,7 @@ int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base,
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
bool *fw_missing, unsigned int *fw_version);
void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base);
bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base);
void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base);

View File

@ -360,6 +360,8 @@ static int acp3x_dma_close(struct snd_soc_component *component,
}
}
kfree(ins);
return 0;
}

View File

@ -759,6 +759,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8BD6"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8DC2"),
}
},
{
.driver_data = &acp6x_card,
.matches = {

View File

@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/soundwire/sdw.h>
@ -36,6 +37,9 @@
#define CS35L56_LATE_READ_POLL_US 10
#define CS35L56_LATE_READ_TIMEOUT_US 1000
static DEFINE_MUTEX(cs35l56_fw_idle_wait_lock);
static bool cs35l56_fw_idle_wait_pending;
static int cs35l56_sdw_poll_mem_status(struct sdw_slave *peripheral,
unsigned int mask,
unsigned int match)
@ -387,14 +391,34 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
return 0;
}
static int cs35l56_sdw_system_suspend_prepare(struct device *dev)
{
cs35l56_fw_idle_wait_pending = true;
return 0;
}
static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
int ret;
if (cs35l56->sdw_attached)
cs35l56_mask_soundwire_interrupts(cs35l56);
return cs35l56_system_suspend(dev);
ret = cs35l56_system_suspend(dev);
if (ret < 0)
return ret;
scoped_guard(mutex, &cs35l56_fw_idle_wait_lock) {
if (cs35l56_fw_idle_wait_pending && cs35l56->needs_wait_for_fw_idle) {
dev_dbg(cs35l56->base.dev, "Wait for FW timer expiry\n");
msleep(CS35L56_FW_REQ_ACTIVE_TIMEOUT_MS + 10);
cs35l56_fw_idle_wait_pending = false;
}
}
return 0;
}
static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id)
@ -460,6 +484,7 @@ static void cs35l56_sdw_remove(struct sdw_slave *peripheral)
}
static const struct dev_pm_ops cs35l56_sdw_pm = {
.prepare = cs35l56_sdw_system_suspend_prepare,
SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)

View File

@ -1379,6 +1379,44 @@ void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_warn_if_firmware_missing, "SND_SOC_CS35L56_SHARED");
bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base)
{
unsigned int fw_ver;
bool prot_sts;
int ret;
switch (cs35l56_base->type) {
case 0x54:
case 0x56:
case 0x57:
switch (cs35l56_base->rev) {
case 0xb0:
ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver);
if (ret)
return true;
if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x30d07)
return true;
return false;
case 0xb2:
ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver);
if (ret)
return true;
if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x40710)
return true;
return false;
default:
return false;
}
default:
return false;
}
}
EXPORT_SYMBOL_NS_GPL(cs35l56_needs_wait_for_firmware_timer_expiry, "SND_SOC_CS35L56_SHARED");
void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp)
{
__be32 pid, sid, tid;

View File

@ -1703,6 +1703,10 @@ int cs35l56_system_resume(struct device *dev)
dev_dbg(dev, "system_resume\n");
/* Assume the firmware reset to default until we can check it */
if (cs35l56->base.init_done)
cs35l56->needs_wait_for_fw_idle = true;
/*
* We might have done a hard reset or the CS35L56 was power-cycled
* so wait for control port to be ready.
@ -1717,6 +1721,16 @@ int cs35l56_system_resume(struct device *dev)
if (ret)
return ret;
if (cs35l56->sdw_peripheral && cs35l56->base.init_done) {
ret = pm_runtime_resume_and_get(cs35l56->base.dev);
if (ret < 0)
return ret;
cs35l56->needs_wait_for_fw_idle =
cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base);
pm_runtime_put_autosuspend(cs35l56->base.dev);
}
/* Firmware won't have been loaded if the component hasn't probed */
if (!cs35l56->component)
return 0;
@ -2241,6 +2255,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
if (ret)
return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
cs35l56->needs_wait_for_fw_idle =
cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base);
cs35l56->base.init_done = true;
complete_all(&cs35l56->init_completion);

View File

@ -43,6 +43,7 @@ struct cs35l56_private {
bool soft_resetting;
bool sdw_attached;
bool component_registered;
bool needs_wait_for_fw_idle;
struct completion init_completion;
int speaker_id;

View File

@ -419,7 +419,6 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,

View File

@ -353,7 +353,7 @@ static const struct snd_kcontrol_new es8326_snd_controls[] = {
SOC_SINGLE_TLV("DRE Gate Volume", ES8326_ADC_DRE_GATE,
4, 0x07, 0, dre_gate_tlv),
SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0),
SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL,
SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_RECOVERY,
0, 4, 0, drc_recovery_tlv),
SOC_ENUM("ALC Capture Winsize", alc_winsize),
SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,

View File

@ -199,68 +199,68 @@ struct _coeff_div {
static const struct _coeff_div coeff_div[] = {
{32, 256000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
{32, 1536000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
{32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{32, 1536000, 48000, 0x05, 0xB3, 0xD5, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{36, 288000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
{36, 1728000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
{48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
{48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
{48, 2304000, 48000, 0x05, 0x11, 0x53, 0x55, 0x17, 0x20, 0x92, 0x00, 0x28, 2, 2},
{50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
{50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
{50, 2400000, 48000, 0x05, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
{64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
{64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
{64, 3072000, 48000, 0x05, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
{72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
{72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
{72, 3456000, 48000, 0x05, 0x11, 0x53, 0x33, 0x23, 0x08, 0x92, 0x00, 0x1F, 2, 2},
{96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
{96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
{96, 4608000, 48000, 0x15, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
{100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
{100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x93, 0x00, 0x27, 2, 2},
{100, 4800000, 48000, 0x03, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
{128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x93, 0x01, 0x1F, 2, 2},
{128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
{128, 6144000, 48000, 0x03, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
{144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x93, 0x01, 0x1F, 2, 2},
{144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
{144, 6912000, 48000, 0x03, 0x00, 0x31, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
{192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x93, 0x02, 0x1F, 2, 2},
{192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
{192, 9216000, 48000, 0x15, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
{250, 12000000, 48000, 0x25, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
{256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
{256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
{256, 12288000, 48000, 0x0B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
{384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
{384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
{384, 18432000, 48000, 0x13, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
{400, 19200000, 48000, 0x1B, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
{500, 24000000, 48000, 0x23, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
{512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
{512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
{512, 24576000, 48000, 0x1B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
{768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
{768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
{1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
{1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
{1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
{1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
{1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
{1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
{1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
{1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
{2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x1F, 0x1F, 2, 2},
{2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x23, 0x1F, 2, 2},
{2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x25, 0x27, 2, 2},
{3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x2F, 0x1F, 2, 2},
{32, 3072000, 96000, 0x05, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
{64, 6144000, 96000, 0x03, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
{96, 9216000, 96000, 0x15, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
{128, 12288000, 96000, 0x0B, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x01, 0x37, 2, 2},
{36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{36, 1728000, 48000, 0x05, 0xB3, 0xD5, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
{48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
{48, 2304000, 48000, 0x05, 0x91, 0x53, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
{50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{50, 2400000, 48000, 0x05, 0x91, 0x53, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{64, 3072000, 48000, 0x05, 0x91, 0x53, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{72, 3456000, 48000, 0x05, 0x91, 0x53, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
{96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{96, 4608000, 48000, 0x15, 0xB3, 0xD5, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
{100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{100, 4800000, 48000, 0x03, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
{128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
{128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
{128, 6144000, 48000, 0x03, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
{144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
{144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
{144, 6912000, 48000, 0x03, 0x80, 0x31, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
{192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
{192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
{192, 9216000, 48000, 0x15, 0x91, 0x53, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
{250, 12000000, 48000, 0x25, 0x91, 0x53, 0x55, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
{256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
{256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
{256, 12288000, 48000, 0x0B, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
{384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
{384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
{384, 18432000, 48000, 0x13, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
{400, 19200000, 48000, 0x1B, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
{500, 24000000, 48000, 0x23, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
{512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
{512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
{512, 24576000, 48000, 0x1B, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
{768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0B, 0x1F, 2, 2},
{768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0B, 0x1F, 2, 2},
{1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
{1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
{1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
{1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
{1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x11, 0x27, 2, 2},
{1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x11, 0x27, 2, 2},
{1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x17, 0x1F, 2, 2},
{1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x17, 0x1F, 2, 2},
{2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x1F, 0x1F, 2, 2},
{2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x23, 0x1F, 2, 2},
{2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x25, 0x27, 2, 2},
{3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x2F, 0x1F, 2, 2},
{32, 3072000, 96000, 0x05, 0x91, 0x53, 0x55, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
{64, 6144000, 96000, 0x03, 0x80, 0x31, 0x33, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
{96, 9216000, 96000, 0x15, 0x91, 0x53, 0x55, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
{128, 12288000, 96000, 0x0B, 0x80, 0x31, 0x33, 0x0F, 0x00, 0x95, 0x01, 0x37, 2, 2},
};
static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
@ -543,18 +543,20 @@ static void es8375_init(struct snd_soc_component *component)
regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x02);
regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x05);
regmap_write(es8375->regmap, ES8375_CSM1, 0x82);
regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x20);
regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x20);
regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x28);
regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xFC);
regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x10);
regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x10);
regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x2F);
regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xEC);
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE0);
regmap_write(es8375->regmap, ES8375_VMID_SEL, 0xFE);
regmap_write(es8375->regmap, ES8375_ANALOG1, 0xB8);
regmap_write(es8375->regmap, ES8375_VSEL2, 0x05);
regmap_write(es8375->regmap, ES8375_LP_DAC, 0xCC);
regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x03);
regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0x16);
regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
msleep(80);
regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x00);
regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x08);
regmap_write(es8375->regmap, ES8375_CSM1, 0x86);
regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x0B);
regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x00);
@ -566,7 +568,7 @@ static void es8375_init(struct snd_soc_component *component)
regmap_write(es8375->regmap, ES8375_ADC2, 0x00);
regmap_write(es8375->regmap, ES8375_DAC2, 0x00);
regmap_write(es8375->regmap, ES8375_DAC_OTP, 0x88);
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE7);
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE3);
regmap_write(es8375->regmap, ES8375_ANALOG2, 0xF0);
regmap_write(es8375->regmap, ES8375_ANALOG3, 0x40);
regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0xFE);

View File

@ -49,6 +49,9 @@
#define ES8375_ANALOG_SPK2 0x29
#define ES8375_VMID_SEL 0x2D
#define ES8375_ANALOG1 0x2E
#define ES8375_VSEL1 0x2F
#define ES8375_VSEL2 0x30
#define ES8375_LP_DAC 0x31
#define ES8375_ANALOG2 0x32
#define ES8375_ANALOG3 0x37
#define ES8375_ADC2DAC_CLKTRI 0xF8
@ -91,7 +94,7 @@
// Function values
#define ES8375_ADC_OSR_GAIN_MAX 0x3F
#define ES8375_DMIC_GAIN_MAX 0x04
#define ES8375_DMIC_GAIN_MAX 0x03
#define ES8375_ADC_AUTOMUTE_ATTN_MAX 0x1F
#define ES8375_AUTOMUTE_NG_MAX 0x07
#define ES8375_ADC_VOLUME_MAX 0xFF

View File

@ -352,7 +352,7 @@ static int es9356_sdca_headset_detect(struct es9356_sdw_priv *es9356)
if (reg) {
regmap_write(es9356->regmap,
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_SELECTED_MODE, 0), reg);
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0x75);
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0x74);
} else {
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
}
@ -403,7 +403,7 @@ static void es9356_interrupt_handler(struct work_struct *work)
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4);
mod_delayed_work(system_power_efficient_wq,
&es9356->button_detect_work, msecs_to_jiffies(280));
&es9356->button_detect_work, msecs_to_jiffies(50));
}
}
@ -450,7 +450,7 @@ static void es9356_button_detect_handler(struct work_struct *work)
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4);
mod_delayed_work(system_power_efficient_wq,
&es9356->button_detect_work, msecs_to_jiffies(280));
&es9356->button_detect_work, msecs_to_jiffies(50));
}
return;
@ -724,68 +724,122 @@ static bool es9356_sdca_volatile_register(struct device *dev, unsigned int reg)
}
}
static bool es9356_writeable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case ES9356_VERSION:
case ES9356_BUF_ADDR_HID:
case ES9356_HID_BYTE2:
case ES9356_HID_BYTE3:
case ES9356_HID_BYTE4:
return false;
default:
return true;
}
}
static const struct regmap_config es9356_sdca_regmap = {
.reg_bits = 32,
.val_bits = 16,
.volatile_reg = es9356_sdca_volatile_register,
.writeable_reg = es9356_writeable_register,
.max_register = 0x45ffffff,
.cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
static void es9356_register_init(struct es9356_sdw_priv *es9356)
static int es9356_register_init(struct es9356_sdw_priv *es9356)
{
unsigned int version;
int ret;
ret = regmap_read(es9356->regmap, ES9356_VERSION, &version);
if (ret < 0) {
pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
return ret;
}
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x2c);
if (!(version >> 1))
regmap_write(es9356->regmap, ES9356_HP_VOLUME, 0x11);
else
regmap_write(es9356->regmap, ES9356_HP_VOLUME, 0x00);
regmap_write(es9356->regmap, ES9356_SPKCLK_CTL, 0xc3);
regmap_write(es9356->regmap, ES9356_STATE, 0x02);
regmap_write(es9356->regmap, ES9356_ENDPOINT_MODE, 0x24);
regmap_write(es9356->regmap, ES9356_PRE_DIV_CTL, 0x00);
regmap_write(es9356->regmap, ES9356_ADC_OSR, 0x18);
regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x13);
regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x11);
regmap_write(es9356->regmap, ES9356_DAC_OSR, 0x16);
regmap_write(es9356->regmap, ES9356_CLK_CTL, 0x0f);
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
if (!(version >> 1))
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
else
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x10);
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
regmap_write(es9356->regmap, ES9356_DETCLK_CTL, 0x51);
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x10);
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x00);
regmap_write(es9356->regmap, ES9356_MICBIAS_CTL, 0x10);
regmap_write(es9356->regmap, ES9356_HPDETECT_CTL, 0x07);
regmap_write(es9356->regmap, ES9356_ADC_ANA, 0x30);
regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xa8);
regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xaa);
regmap_write(es9356->regmap, ES9356_ADC_INT, 0xaa);
regmap_write(es9356->regmap, ES9356_ADC_LP, 0x19);
regmap_write(es9356->regmap, ES9356_VMID1SEL, 0xbc);
regmap_write(es9356->regmap, ES9356_VMID_TIME, 0x0b);
regmap_write(es9356->regmap, ES9356_STATE_TIME, 0xbb);
regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x77);
regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x7a);
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
if ((version & GENMASK(1, 0)) == 0x03)
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
else
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x25);
regmap_write(es9356->regmap, ES9356_SPARE_REGISTER3, 0x00);
regmap_write(es9356->regmap, ES9356_KEY_PRESS_TIME, 0xff);
regmap_write(es9356->regmap, ES9356_KEY_RELEASE_TIME, 0xff);
regmap_write(es9356->regmap, ES9356_KEY_HOLD_TIME, 0x0f);
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
if ((version & GENMASK(1, 0)) == 0x03)
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x04);
else
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
regmap_write(es9356->regmap, ES9356_KEYD_DETECT, 0x18);
regmap_write(es9356->regmap, ES9356_MICBIAS_RES, 0x03);
regmap_write(es9356->regmap, ES9356_BUTTON_CHARGE, 0x00);
regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x13);
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x1a);
if (!(version >> 1)) {
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xc3);
} else {
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
regmap_write(es9356->regmap, ES9356_SPK_SCP, 0x55);
}
regmap_write(es9356->regmap, ES9356_SPK_VOLUME, 0x33);
regmap_write(es9356->regmap, ES9356_DAC_VROI, 0x01);
regmap_write(es9356->regmap, ES9356_DAC_LP, 0x00);
regmap_write(es9356->regmap, ES9356_HP_IBIAS, 0x04);
regmap_write(es9356->regmap, ES9356_HP_LP, 0x03);
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x65);
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x6c);
regmap_write(es9356->regmap, ES9356_SPKBIAS_COMP, 0x09);
regmap_write(es9356->regmap, ES9356_VMID1STL, 0x00);
regmap_write(es9356->regmap, ES9356_VMID1STL, 0x01);
regmap_write(es9356->regmap, ES9356_VMID2STL, 0x00);
regmap_write(es9356->regmap, ES9356_VSEL, 0xfc);
regmap_write(es9356->regmap, ES9356_IBIASGEN, 0x10);
regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x0d);
regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x05);
regmap_write(es9356->regmap, ES9356_STATE, 0x0e);
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x00);
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x08);
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE, 0x31);
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE_WINSIZE, 0x3D);
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE_RESULT1, 0x80);
regmap_write(es9356->regmap,
SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
@ -806,11 +860,14 @@ static void es9356_register_init(struct es9356_sdw_priv *es9356)
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
regmap_write(es9356->regmap,
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
return 0;
}
static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
{
struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
int ret = 0;
if (es9356->hw_init)
return 0;
@ -825,7 +882,11 @@ static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
es9356_register_init(es9356);
ret = es9356_register_init(es9356);
if (ret < 0) {
regcache_cache_only(es9356->regmap, true);
goto err_out;
}
}
pm_runtime_get_noresume(&slave->dev);
@ -852,10 +913,11 @@ static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
es9356->hw_init = true;
err_out:
pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
return 0;
return ret;
}
static int es9356_sdw_update_status(struct sdw_slave *slave,
@ -1000,10 +1062,10 @@ static int es9356_sdw_interrupt_callback(struct sdw_slave *slave,
count++;
} while (stat != 0 && count < retry);
/* The 280 ms figure was determined through testing */
/* The 50 ms figure was determined through testing */
if (status->sdca_cascade && !es9356->disable_irq)
mod_delayed_work(system_power_efficient_wq,
&es9356->interrupt_handle_work, msecs_to_jiffies(280));
&es9356->interrupt_handle_work, msecs_to_jiffies(50));
mutex_unlock(&es9356->disable_irq_lock);
return 0;

View File

@ -4,6 +4,7 @@
#define __ES9356_H__
/*ES9356 Implementation-define*/
#define ES9356_VERSION 0x2000
#define ES9356_FLAGS_HP 0x2003
#define ES9356_CSM_RESET 0x2020
#define ES9356_FUC_RESET 0x2021
@ -37,6 +38,7 @@
#define ES9356_MICBIAS_CTL 0x2047
#define ES9356_HPDETECT_CTL 0x2048
#define ES9356_MICBIAS_RES 0x2049
#define ES9356_SPARE_REGISTER3 0x204a
/*CLK*/
#define ES9356_CLK_SEL 0x2050
@ -81,6 +83,9 @@
#define ES9356_DAC_RAMP 0x2093
#define ES9356_DAC_VPPSCALE 0x2094
#define ES9356_DAC_SWAP 0x2097
#define ES9356_DAC_AUTOMUTE 0x2098
#define ES9356_DAC_AUTOMUTE_WINSIZE 0x2099
#define ES9356_DAC_AUTOMUTE_RESULT1 0x209B
#define ES9356_SPKCMP_VPPSC 0x20A0
#define ES9356_CALIBRATION_TIME 0x20A1
#define ES9356_CALIBRATION_SETTING 0x20A2

View File

@ -514,6 +514,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
snd_hdac_display_power(hdev->bus,
HDA_CODEC_IDX_CONTROLLER, false);
/* The codec is in D0, the status is RPM_SUSPENDED after a previous unbind */
pm_runtime_set_active(&hdev->dev);
/* match for forbid call in snd_hda_codec_device_new() */
pm_runtime_allow(&hdev->dev);
@ -554,6 +557,13 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
return;
}
/*
* Resume the codec to have its link reference (dropped below) and
* codec_powered bit in the same state as after the probe.
*/
pm_runtime_get_sync(&hdev->dev);
/* prevent runtime PM callbacks while the link and the codec are torn down */
pm_runtime_disable(&hdev->dev);
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
@ -561,6 +571,12 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
driver->ops->remove(codec);
snd_hda_codec_cleanup_for_unbind(codec);
/* Balances the disable above, cleanup_for_unbind keeps runtime PM disabled */
pm_runtime_enable(&hdev->dev);
pm_runtime_put_noidle(&hdev->dev);
/* The codec is cleaned up, system suspend must skip it from now on */
pm_runtime_set_suspended(&hdev->dev);
}
static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
@ -617,12 +633,35 @@ static const struct snd_soc_component_driver hdac_hda_hdmi_codec = {
.endianness = 1,
};
static void hdac_hda_restore_dev_type(void *data)
{
struct hdac_device *hdev = data;
hdev->type = HDA_DEV_LEGACY;
}
static int hdac_hda_dev_probe(struct hdac_device *hdev)
{
struct hdac_hda_priv *hda_pvt = dev_get_drvdata(&hdev->dev);
struct hdac_hda_priv *hda_pvt;
struct hdac_ext_link *hlink;
int ret;
hda_pvt = devm_kzalloc(&hdev->dev, sizeof(*hda_pvt), GFP_KERNEL);
if (!hda_pvt)
return -ENOMEM;
hda_pvt->codec = dev_to_hda_codec(&hdev->dev);
hda_pvt->dev_index = hdev->addr;
/* Intel iDisp (HDMI/DP) codec */
if (((hdev->vendor_id >> 16) & 0xFFFF) == 0x8086)
hda_pvt->need_display_power = true;
dev_set_drvdata(&hdev->dev, hda_pvt);
/* Allow the legacy codec driver to match again after unbind */
ret = devm_add_action(&hdev->dev, hdac_hda_restore_dev_type, hdev);
if (ret)
return ret;
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {

View File

@ -92,7 +92,6 @@ static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x2000026:
case 0x200002c:
case 0x200003c:
case 0x2000046:
case 0x5810000:
case 0x5810033:
case 0x5810036:
@ -174,7 +173,6 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re
case 0x2000026:
case 0x200002c:
case 0x2000030:
case 0x2000046:
case 0x2000067:
case 0x2000084:
case 0x2000086:

View File

@ -63,8 +63,6 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
@ -91,13 +89,11 @@ static const struct reg_default rt721_sdca_mbq_defaults[] = {
{ 0x2000003, 0x0000 },
{ 0x2000013, 0x8001 },
{ 0x200003c, 0x0000 },
{ 0x2000046, 0x3400 },
{ 0x5b10017, 0x1b07 },
{ 0x5f00044, 0x6040 },
{ 0x5f00045, 0x3333 },
{ 0x5f00048, 0x0000 },
{ 0x6100005, 0x0005 },
{ 0x6100006, 0x0000 },
{ 0x6100007, 0x0007 },
{ 0x610000d, 0x0051 },
{ 0x6100010, 0x0180 },

View File

@ -1652,6 +1652,17 @@ int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave
&soc_sdca_dev_rt722, rt722_sdca_dai, ARRAY_SIZE(rt722_sdca_dai));
}
static const struct dmi_system_id dmi_dell_mono_spk_quirk_table[] = {
{
.ident = "Dell Pro 5 Micro P5M1270",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0EBA"),
}
},
{}
};
static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
{
unsigned int mic_func_status;
@ -1741,6 +1752,13 @@ static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
if (rt722->hw_vid == RT722_VB)
regmap_write(rt722->regmap, 0x2f54, 0x00);
/* This Dell machine only uses the mono speaker */
if (dmi_check_system(dmi_dell_mono_spk_quirk_table)) {
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL2, 0x391a);
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
RT722_MISC_CTRL2, 0x0010, 0x0010);
}
/* clear flag */
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),

View File

@ -68,9 +68,11 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_ANALOG_BIAS_CTL3 0x04
#define RT722_MISC_CTRL1 0x07
#define RT722_JD_CTRL1 0x09
#define RT722_MISC_CTRL2 0x0d
#define RT722_LDO2_3_CTL1 0x0e
#define RT722_LDO1_CTL 0x1a
#define RT722_HP_JD_CTRL 0x24
#define RT722_CLSD_CTRL2 0x38
#define RT722_CLSD_CTRL6 0x3c
#define RT722_COMBO_JACK_AUTO_CTL1 0x45
#define RT722_COMBO_JACK_AUTO_CTL2 0x46

View File

@ -318,6 +318,9 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
u8 divisor;
if (!rate)
return -EINVAL;
divisor = DIV_ROUND_UP(parent_rate, rate);
if (divisor > AIC32X4_DIV_MAX)
return -EINVAL;
@ -331,8 +334,11 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
{
unsigned long divisor;
if (!req->rate)
return -EINVAL;
divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
if (divisor > AIC32X4_DIV_MAX)
if (!divisor || divisor > AIC32X4_DIV_MAX)
return -EINVAL;
req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);

View File

@ -163,9 +163,12 @@ static void wm8958_micd_set_rate(struct snd_soc_component *component)
static int configure_aif_clock(struct snd_soc_component *component, int aif)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct clk *mclk = NULL;
bool switch_mclk;
int rate;
int reg1 = 0;
int offset;
int ret;
if (aif)
offset = 4;
@ -174,11 +177,13 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
switch (wm8994->sysclk[aif]) {
case WM8994_SYSCLK_MCLK1:
mclk = wm8994->mclk[WM8994_MCLK1].clk;
rate = wm8994->mclk_rate[0];
break;
case WM8994_SYSCLK_MCLK2:
reg1 |= 0x8;
mclk = wm8994->mclk[WM8994_MCLK2].clk;
rate = wm8994->mclk_rate[1];
break;
@ -196,6 +201,20 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
return -EINVAL;
}
/*
* If the AIF clock is running, enable the new MCLK before switching
* to it and release the previous one afterwards.
*/
switch_mclk = wm8994->aif_clk_on[aif] && mclk != wm8994->aif_mclk[aif];
if (switch_mclk) {
ret = clk_prepare_enable(mclk);
if (ret < 0) {
dev_err(component->dev,
"Failed to enable MCLK for AIF%d\n", aif + 1);
return ret;
}
}
if (rate >= 13500000) {
rate /= 2;
reg1 |= WM8994_AIF1CLK_DIV;
@ -210,6 +229,11 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
reg1);
if (switch_mclk) {
clk_disable_unprepare(wm8994->aif_mclk[aif]);
wm8994->aif_mclk[aif] = mclk;
}
return 0;
}
@ -1059,13 +1083,25 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
unsigned int offset, val, clk_idx;
int ret;
/*
* The AIF clock source may be changed while the AIF clock is
* running, so release the MCLK which has been enabled for it
* instead of the one currently selected.
*/
if (!enable) {
clk_disable_unprepare(wm8994->aif_mclk[aif]);
wm8994->aif_mclk[aif] = NULL;
wm8994->aif_clk_on[aif] = false;
return 0;
}
if (aif)
offset = 4;
else
offset = 0;
val = snd_soc_component_read(component, WM8994_AIF1_CLOCKING_1 + offset);
val &= WM8994_AIF1CLK_SRC_MASK;
val = (val & WM8994_AIF1CLK_SRC_MASK) >> WM8994_AIF1CLK_SRC_SHIFT;
switch (val) {
case 0:
@ -1075,19 +1111,18 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
clk_idx = WM8994_MCLK2;
break;
default:
wm8994->aif_clk_on[aif] = true;
return 0;
}
if (enable) {
ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
if (ret < 0) {
dev_err(component->dev, "Failed to enable MCLK%d\n",
clk_idx);
return ret;
}
} else {
clk_disable_unprepare(wm8994->mclk[clk_idx].clk);
ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
if (ret < 0) {
dev_err(component->dev, "Failed to enable MCLK%d\n",
clk_idx + 1);
return ret;
}
wm8994->aif_mclk[aif] = wm8994->mclk[clk_idx].clk;
wm8994->aif_clk_on[aif] = true;
return 0;
}
@ -2199,6 +2234,44 @@ static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
return 0;
}
/*
* If SYSCLK is less than 50kHz adjust AIFnCLK dividers for detection,
* restoring the original ones once SYSCLK is fast enough again.
*/
static void wm8994_update_aif_clk_rate(struct snd_soc_component *component)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
/* Don't overwrite the saved dividers with the 128fs ones */
if (!wm8994->aifdiv[0]) {
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
wm8994->aifdiv[0] = snd_soc_component_read(component,
WM8994_AIF1_RATE)
& WM8994_AIF1CLK_RATE_MASK;
wm8994->aifdiv[1] = snd_soc_component_read(component,
WM8994_AIF2_RATE)
& WM8994_AIF1CLK_RATE_MASK;
}
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK, 0x1);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK, 0x1);
} else if (wm8994->aifdiv[0]) {
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK,
wm8994->aifdiv[0]);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK,
wm8994->aifdiv[1]);
wm8994->aifdiv[0] = 0;
wm8994->aifdiv[1] = 0;
}
}
static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
unsigned int freq_in, unsigned int freq_out)
{
@ -2433,33 +2506,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
configure_clock(component);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
& WM8994_AIF1CLK_RATE_MASK;
wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
& WM8994_AIF1CLK_RATE_MASK;
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK, 0x1);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK, 0x1);
} else if (wm8994->aifdiv[0]) {
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK,
wm8994->aifdiv[0]);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK,
wm8994->aifdiv[1]);
wm8994->aifdiv[0] = 0;
wm8994->aifdiv[1] = 0;
}
wm8994_update_aif_clk_rate(component);
return 0;
}
@ -2519,7 +2566,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
case WM8994_SYSCLK_MCLK1:
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK1, &freq);
if (ret < 0)
return ret;
@ -2532,7 +2579,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
/* TODO: Set GPIO AF */
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK2, &freq);
if (ret < 0)
return ret;
@ -2577,33 +2624,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
configure_clock(component);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
& WM8994_AIF1CLK_RATE_MASK;
wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
& WM8994_AIF1CLK_RATE_MASK;
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK, 0x1);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK, 0x1);
} else if (wm8994->aifdiv[0]) {
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK,
wm8994->aifdiv[0]);
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK,
wm8994->aifdiv[1]);
wm8994->aifdiv[0] = 0;
wm8994->aifdiv[1] = 0;
}
wm8994_update_aif_clk_rate(component);
return 0;
}

View File

@ -81,6 +81,8 @@ struct wm8994_priv {
struct wm_hubs_data hubs;
struct wm8994 *wm8994;
struct clk_bulk_data mclk[WM8994_NUM_MCLK];
struct clk *aif_mclk[2];
bool aif_clk_on[2];
int sysclk[2];
int sysclk_rate[2];
int mclk_rate[2];

View File

@ -1115,11 +1115,19 @@ static int wsa881x_probe(struct sdw_slave *pdev,
if (!wsa881x)
return -ENOMEM;
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
/*
* The powerdown GPIO may be shared between several amplifiers. Request
* it asserted, so the shared GPIO proxy treats powerdown as the default
* state and keeps the line de-asserted as long as any amplifier needs
* it, then power up this amplifier.
*/
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
if (IS_ERR(wsa881x->sd_n))
return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
"Shutdown Control GPIO not found\n");
gpiod_set_value_cansleep(wsa881x->sd_n, 0);
dev_set_drvdata(dev, wsa881x);
wsa881x->slave = pdev;
wsa881x->dev = dev;
@ -1154,7 +1162,7 @@ static int wsa881x_runtime_suspend(struct device *dev)
struct regmap *regmap = dev_get_regmap(dev, NULL);
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
gpiod_direction_output(wsa881x->sd_n, 1);
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
regcache_cache_only(regmap, true);
regcache_mark_dirty(regmap);
@ -1169,11 +1177,11 @@ static int wsa881x_runtime_resume(struct device *dev)
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
int ret;
gpiod_direction_output(wsa881x->sd_n, 0);
gpiod_set_value_cansleep(wsa881x->sd_n, 0);
ret = sdw_slave_wait_for_init(slave, WSA881X_PROBE_TIMEOUT);
if (ret) {
gpiod_direction_output(wsa881x->sd_n, 1);
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
return ret;
}
@ -1182,7 +1190,7 @@ static int wsa881x_runtime_resume(struct device *dev)
if (ret) {
regcache_cache_only(regmap, true);
regcache_mark_dirty(regmap);
gpiod_direction_output(wsa881x->sd_n, 1);
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
return ret;
}

View File

@ -456,10 +456,11 @@
/*
* Device will report senseless data in many cases, so discard any measurements
* outside of valid range.
* outside of the two-point trim range. Do not narrow this to ambient: a
* speaker that has been playing easily runs well above 45 degC.
*/
#define WSA883X_LOW_TEMP_THRESHOLD 5
#define WSA883X_HIGH_TEMP_THRESHOLD 45
#define WSA883X_LOW_TEMP_THRESHOLD WSA883X_T1_TEMP
#define WSA883X_HIGH_TEMP_THRESHOLD WSA883X_T2_TEMP
struct wsa883x_priv {
struct regmap *regmap;
@ -551,7 +552,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
.num = WSA883X_PORT_VISENSE + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.max_ch = 2,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
}
@ -572,7 +573,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
},
[WSA883X_PORT_VISENSE] = {
.num = WSA883X_PORT_VISENSE + 1,
.ch_mask = 0x1,
.ch_mask = 0x3,
},
};
@ -1430,7 +1431,7 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
unsigned int dmeas_msb = 0, dmeas_lsb = 0;
int d1, d2, dmeas;
unsigned int mask;
int ret, range;
int ret;
long val;
guard(mutex)(&wsa883x->sp_lock);
@ -1493,8 +1494,8 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
}
val = WSA883X_T1_TEMP + (((dmeas - d1) * (WSA883X_T2_TEMP - WSA883X_T1_TEMP)) / (d2 - d1));
range = WSA883X_HIGH_TEMP_THRESHOLD - WSA883X_LOW_TEMP_THRESHOLD;
if (in_range(val, WSA883X_LOW_TEMP_THRESHOLD, range)) {
if (val >= WSA883X_LOW_TEMP_THRESHOLD &&
val <= WSA883X_HIGH_TEMP_THRESHOLD) {
wsa883x->temperature = val;
*temp = val * 1000;
ret = 0;
@ -1668,7 +1669,9 @@ static int wsa883x_probe(struct sdw_slave *pdev,
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
goto err;
ret = devm_snd_soc_register_component(dev,
&wsa883x_component_drv,

View File

@ -720,10 +720,11 @@
/*
* Device will report senseless data in many cases, so discard any measurements
* outside of valid range.
* outside of the two-point trim range. Do not narrow this to ambient: a
* speaker that has been playing easily runs well above 45 degC.
*/
#define WSA884X_LOW_TEMP_THRESHOLD 5
#define WSA884X_HIGH_TEMP_THRESHOLD 45
#define WSA884X_LOW_TEMP_THRESHOLD WSA884X_T1_TEMP
#define WSA884X_HIGH_TEMP_THRESHOLD WSA884X_T2_TEMP
struct wsa884x_priv {
struct regmap *regmap;
@ -858,7 +859,7 @@ static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = {
.num = WSA884X_PORT_VISENSE + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.max_ch = 2,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
},
@ -891,7 +892,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
},
[WSA884X_PORT_VISENSE] = {
.num = WSA884X_PORT_VISENSE + 1,
.ch_mask = 0x1,
.ch_mask = 0x3,
},
[WSA884X_PORT_CPS] = {
.num = WSA884X_PORT_CPS + 1,
@ -1929,8 +1930,8 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n",
val, dmeas, d1, d2);
if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
(val < WSA884X_HIGH_TEMP_THRESHOLD)) {
if (val >= WSA884X_LOW_TEMP_THRESHOLD &&
val <= WSA884X_HIGH_TEMP_THRESHOLD) {
wsa884x->temperature = val;
*temp = val * 1000;
ret = 0;
@ -2124,7 +2125,9 @@ static int wsa884x_probe(struct sdw_slave *pdev,
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
return devm_snd_soc_register_component(dev,
&wsa884x_component_drv,

View File

@ -153,6 +153,9 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
}
EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);
/* Fractional audio PLLs may sit a few Hz off nominal */
#define FSL_RATE_CONSTR_TOL_HZ 100
/**
* fsl_asoc_constrain_rates - constrain rates according to clocks
*
@ -172,6 +175,7 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
{
int i, j, k = 0;
u64 clk_rate[3];
u32 rate, rem;
*target_constr = *original_constr;
if (pll8k_clk || pll11k_clk || ext_clk) {
@ -181,10 +185,25 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
clk_rate[0] = clk_get_rate(pll8k_clk);
clk_rate[1] = clk_get_rate(pll11k_clk);
clk_rate[2] = clk_get_rate(ext_clk);
rate = original_constr->list[i];
for (j = 0; j < 3; j++) {
if (clk_rate[j] != 0 &&
do_div(clk_rate[j], original_constr->list[i]) == 0) {
target_rates[k++] = original_constr->list[i];
if (clk_rate[j] == 0)
continue;
rem = do_div(clk_rate[j], rate);
/*
* The audio PLLs are fractional and cannot
* always reproduce their nominal rate: after
* any clk_set_rate() they may sit a few Hz
* off (observed on i.MX8M Plus: audio_pll1
* reads 393215997 after restoring 393216000),
* which must not disqualify the entire rate
* family. Accept near-integer ratios; the
* other family misses by tens of kHz, so a
* small tolerance cannot mix families.
*/
if (rem <= FSL_RATE_CONSTR_TOL_HZ ||
rem >= rate - FSL_RATE_CONSTR_TOL_HZ) {
target_rates[k++] = rate;
target_constr->count++;
break;
}

View File

@ -178,6 +178,16 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
static int imx_rpmsg_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct rpmsg_info *info = dev_get_drvdata(component->dev);
flush_workqueue(info->rpmsg_wq);
return 0;
}
static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@ -285,9 +295,6 @@ static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
struct rpmsg_info *info = dev_get_drvdata(component->dev);
struct rpmsg_msg *msg;
/* Flush work in workqueue to make TX_CLOSE is the last message */
flush_workqueue(info->rpmsg_wq);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
msg = &info->msg[TX_CLOSE];
msg->s_msg.header.cmd = TX_CLOSE;
@ -624,6 +631,7 @@ static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
.open = imx_rpmsg_pcm_open,
.close = imx_rpmsg_pcm_close,
.hw_params = imx_rpmsg_pcm_hw_params,
.hw_free = imx_rpmsg_pcm_hw_free,
.trigger = imx_rpmsg_pcm_trigger,
.pointer = imx_rpmsg_pcm_pointer,
.ack = imx_rpmsg_pcm_ack,

View File

@ -70,6 +70,23 @@ static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = {
},
};
static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
/* Jack Endpoint */
{
.num = 0,
.aggregated = 0,
.group_position = 0,
.group_id = 0,
},
/* DMIC Endpoint */
{
.num = 1,
.aggregated = 0,
.group_position = 0,
.group_id = 0,
},
};
static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = {
{
.adr = 0x00023001FA355601ull,
@ -301,6 +318,35 @@ static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = {
}
};
/*
* MSI Raider 16 Max HX B2WI (MS-2651): RT713 (jack/dmic, "VB" SDCA variant)
* on link 0, two RT1320 speaker amps sharing link 2 (unique_id 0 = left,
* unique_id 1 = right).
*/
static const struct snd_soc_acpi_adr_device rt713_vb_0_adr[] = {
{
.adr = 0x000030025D071301ull,
.num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
.endpoints = jack_dmic_endpoints,
.name_prefix = "rt713"
}
};
static const struct snd_soc_acpi_adr_device rt1320_2_lr_adr[] = {
{
.adr = 0x000230025D132001ull,
.num_endpoints = 1,
.endpoints = &spk_l_endpoint,
.name_prefix = "rt1320-1"
},
{
.adr = 0x000231025D132001ull,
.num_endpoints = 1,
.endpoints = &spk_r_endpoint,
.name_prefix = "rt1320-2"
}
};
static const struct snd_soc_acpi_link_adr arl_n_mrd_es9356_link1[] = {
{
.mask = BIT(1),
@ -454,6 +500,20 @@ static const struct snd_soc_acpi_link_adr arl_rt711_l0_rt1316_l3[] = {
{}
};
static const struct snd_soc_acpi_link_adr arl_rt713_vb_l0_rt1320_l2[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt713_vb_0_adr),
.adr_d = rt713_vb_0_adr,
},
{
.mask = BIT(2),
.num_adr = ARRAY_SIZE(rt1320_2_lr_adr),
.adr_d = rt1320_2_lr_adr,
},
{}
};
static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = {
{
.mask = BIT(0),
@ -482,6 +542,15 @@ static const struct snd_soc_acpi_link_adr arl_rt712_l0_rt1320_l3[] = {
{}
};
static const struct snd_soc_acpi_link_adr arl_rt712_l0[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt712_0_agg_adr),
.adr_d = rt712_0_agg_adr,
},
{}
};
static const struct snd_soc_acpi_codecs arl_essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
@ -617,6 +686,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = arl_rt713_vb_l0_rt1320_l2,
.drv_name = "sof_sdw",
.machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
.sof_tplg_filename = "sof-arl-dummy.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = arl_rt722_l0_rt1320_l2,
@ -646,6 +723,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = arl_rt712_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-dummy.tplg",
.get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = arl_cs42l43_l0,

View File

@ -393,6 +393,7 @@ struct q6afe {
struct q6core_svc_api_info ainfo;
struct mutex lock;
struct aprv2_ibasic_rsp_result_t result;
uint32_t vote_result;
wait_queue_head_t wait;
struct list_head port_list;
spinlock_t port_list_lock;
@ -1010,13 +1011,14 @@ static int q6afe_callback(struct apr_device *adev, const struct apr_resp_pkt *da
const struct aprv2_ibasic_rsp_result_t *res;
const struct apr_hdr *hdr = &data->hdr;
struct q6afe_port *port;
uint32_t *vote_res;
if (!data->payload_size)
return 0;
res = data->payload;
switch (hdr->opcode) {
case APR_BASIC_RSP_RESULT: {
res = data->payload;
if (res->status) {
dev_err(afe->dev, "cmd = 0x%x returned error = 0x%x\n",
res->opcode, res->status);
@ -1043,8 +1045,10 @@ static int q6afe_callback(struct apr_device *adev, const struct apr_resp_pkt *da
}
break;
case AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST:
vote_res = data->payload;
afe->result.opcode = hdr->opcode;
afe->result.status = res->status;
afe->result.status = 0;
afe->vote_result = *vote_res;
wake_up(&afe->wait);
break;
default:
@ -1955,6 +1959,8 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST);
if (ret)
dev_err(afe->dev, "AFE failed to vote (%d)\n", hw_block_id);
else
*client_handle = afe->vote_result;
return ret;
}

View File

@ -322,15 +322,15 @@ int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr
}
EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id,
static int __q6apm_unmap_memory_fixed_region(struct q6apm *apm, unsigned int graph_id,
bool is_pos_buf)
{
struct apm_cmd_shared_mem_unmap_regions *cmd;
struct q6apm *apm = dev_get_drvdata(dev->parent);
struct audioreach_graph_info *info;
uint32_t mem_map_handle;
uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
APM_CMD_SHARED_MEM_UNMAP_REGIONS, (graph_id | pos_mask));
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@ -357,13 +357,15 @@ static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int gr
int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
{
return __q6apm_unmap_memory_fixed_region(dev, graph_id, false);
return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
graph_id, false);
}
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
int q6apm_unmap_pos_buffer(struct device *dev, unsigned int graph_id)
{
return __q6apm_unmap_memory_fixed_region(dev, graph_id, true);
return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
graph_id, true);
}
EXPORT_SYMBOL_GPL(q6apm_unmap_pos_buffer);
@ -850,6 +852,21 @@ static int q6apm_audio_probe(struct snd_soc_component *component)
static void q6apm_audio_remove(struct snd_soc_component *component)
{
struct q6apm *apm = dev_get_drvdata(component->dev);
struct audioreach_graph_info *info;
int id;
/*
* The card core removes components before freeing the PCMs, so
* q6apm-dai's pcm_free() runs after the topology (and graph_info)
* is gone and can no longer unmap. Release the DSP mappings here,
* otherwise the next pcm_new() fails to map the same buffer again.
*/
idr_for_each_entry(&apm->graph_info_idr, info, id) {
__q6apm_unmap_memory_fixed_region(apm, id, false);
__q6apm_unmap_memory_fixed_region(apm, id, true);
}
/* remove topology */
snd_soc_tplg_component_remove(component);
}
@ -960,17 +977,23 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
wake_up(&apm->wait);
break;
case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
apm->result.opcode = hdr->opcode;
apm->result.status = 0;
rsp = data->payload;
info = idr_find(&apm->graph_info_idr, hdr->token);
if (info)
info->mem_map_handle = 0;
else
apm->result.opcode = result->opcode;
apm->result.status = result->status;
if (result->status)
dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
result->opcode);
graph_id = hdr->token & APM_MMAP_TOKEN_GID_MASK;
is_pos_buf = hdr->token & APM_MMAP_TOKEN_MAP_TYPE_POS_BUF;
info = idr_find(&apm->graph_info_idr, graph_id);
if (info && !result->status) {
if (is_pos_buf)
info->pos_buf_mem_map_handle = 0;
else
info->mem_map_handle = 0;
}
wake_up(&apm->wait);
break;
default:

View File

@ -312,22 +312,37 @@ audioreach_get_module_priv_data(const struct snd_soc_tplg_private *private)
for (sz = 0; sz < le32_to_cpu(private->size); ) {
const struct snd_soc_tplg_vendor_array *mod_array;
u32 array_size;
mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
array_size = le32_to_cpu(mod_array->size);
if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) {
struct audioreach_module_priv_data *pdata;
u32 nwords;
pdata = kzalloc_flex(*pdata, data,
le32_to_cpu(mod_array->size));
/* size is the byte count of the __le32 data[] */
nwords = array_size / sizeof(__le32);
/* the blob must lie within the private data */
if (sizeof(*pdata) + (u64)array_size >
le32_to_cpu(private->size) - sz)
return ERR_PTR(-EINVAL);
pdata = kzalloc_flex(*pdata, data, nwords);
if (!pdata)
return ERR_PTR(-ENOMEM);
memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data,
le32_to_cpu(mod_array->size)));
memcpy(pdata, ((u8 *)private->data + sz),
struct_size(pdata, data, nwords));
return pdata;
}
sz = sz + le32_to_cpu(mod_array->size);
/* a zero size would never advance the walk */
if (!array_size)
return ERR_PTR(-EINVAL);
sz = sz + array_size;
}
return NULL;
@ -611,6 +626,12 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon
return mod ? PTR_ERR(mod) : -ENODEV;
mod->data = audioreach_get_module_priv_data(&tplg_w->priv);
if (IS_ERR(mod->data)) {
int rc = PTR_ERR(mod->data);
mod->data = NULL;
return rc;
}
dobj = &w->dobj;
dobj->private = mod;

View File

@ -39,6 +39,16 @@ static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
case USB_RX:
return qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack,
&data->usb_offload_jack_setup);
case RX_CODEC_DMA_RX_0:
/*
* The RX macro digital gain goes up to +40 dB. Userspace that
* maps full volume to the top of the range (PipeWire, PulseAudio)
* would clip there, so stop the interpolator gains at 0 dB.
*/
snd_soc_limit_volume(rtd->card, "RX_RX0 Digital Volume", 84);
snd_soc_limit_volume(rtd->card, "RX_RX1 Digital Volume", 84);
snd_soc_limit_volume(rtd->card, "RX_RX2 Digital Volume", 84);
fallthrough;
default:
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
}

View File

@ -25,7 +25,8 @@
*/
#define MCLK1_RATE 24000000U
#define MCLK2_RATE 32768U
#define DEFAULT_FLL1_RATE 11289600U
/* Matches the codec's default AIF1 configuration: 48kHz, 256fs */
#define DEFAULT_FLL1_RATE 12288000U
struct midas_priv {
struct gpio_desc *gpio_fm_sel;
@ -34,6 +35,7 @@ struct midas_priv {
struct gpio_desc *gpio_headset_key;
struct iio_channel *adc_headset_detect;
unsigned int fll1_rate;
unsigned int aif1clk_rate;
struct snd_soc_jack headset_jack;
};
@ -171,11 +173,12 @@ static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
if (!rate)
rate = priv->fll1_rate;
/*
* If no new rate is requested, set FLL1 to a sane default for jack
* detection.
* If no new rate is requested, set FLL1 to the rate the codec's AIF1
* is currently configured for, as its digital paths can be powered
* up without an active stream.
*/
if (!rate)
rate = DEFAULT_FLL1_RATE;
rate = priv->aif1clk_rate ?: DEFAULT_FLL1_RATE;
if (rate != priv->fll1_rate && priv->fll1_rate) {
/* while reconfiguring, switch to MCLK2 for SYSCLK */
@ -241,6 +244,7 @@ static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct midas_priv *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned int pll_out;
/* AIF1CLK should be at least 3MHz for "optimal performance" */
@ -249,6 +253,8 @@ static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
else
pll_out = params_rate(params) * 256;
priv->aif1clk_rate = pll_out;
return midas_start_fll1(rtd, pll_out);
}

View File

@ -27,8 +27,11 @@
static int class_read_prop(struct sdw_slave *sdw)
{
struct sdw_slave_prop *prop = &sdw->prop;
int ret;
sdw_slave_read_prop(sdw);
ret = sdw_slave_read_prop(sdw);
if (ret)
return ret;
prop->use_domain_irq = true;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
@ -194,8 +197,10 @@ int sdca_class_probe(struct sdw_slave *sdw,
pm_runtime_get_noresume(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
if (ret) {
pm_runtime_put_sync(dev);
return ret;
}
queue_work(system_long_wq, &drv->boot_work);
@ -260,6 +265,7 @@ int sdca_class_system_suspend(struct sdca_class_drv *drv)
ret = pm_runtime_force_suspend(drv->dev);
if (ret) {
dev_err(drv->dev, "failed to force suspend: %d\n", ret);
enable_irq(drv->sdw->irq);
return ret;
}

View File

@ -7,6 +7,7 @@
config SND_SOC_SOF_AMD_TOPLEVEL
tristate "SOF support for AMD audio DSPs"
depends on SOUNDWIRE_AMD || !SOUNDWIRE_AMD
depends on ACPI
depends on X86 || COMPILE_TEST
help
This adds support for Sound Open Firmware for AMD platforms.

View File

@ -15,8 +15,6 @@
#include "hda.h"
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
#include "../../codecs/hdac_hda.h"
#define CODEC_PROBE_RETRIES 3
#define IDISP_VID_INTEL 0x80860000
@ -148,7 +146,6 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i
/* probe individual codec */
static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
{
struct hdac_hda_priv *hda_priv;
struct hda_bus *hbus = sof_to_hbus(sdev);
struct hda_codec *codec;
u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
@ -168,27 +165,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
address, resp);
hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL);
if (!hda_priv)
return -ENOMEM;
codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_LEGACY);
ret = PTR_ERR_OR_ZERO(codec);
if (ret < 0)
return ret;
hda_priv->codec = codec;
hda_priv->dev_index = address;
dev_set_drvdata(&codec->core.dev, hda_priv);
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) {
if (!hbus->core.audio_component) {
dev_dbg(sdev->dev,
"iDisp hw present but no driver\n");
ret = -ENOENT;
goto out;
}
hda_priv->need_display_power = true;
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL && !hbus->core.audio_component) {
dev_dbg(sdev->dev, "iDisp hw present but no driver\n");
ret = -ENOENT;
goto out;
}
if (is_generic_config(hbus))

View File

@ -349,6 +349,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
bus->chip_init = false;
}
EXPORT_SYMBOL_NS(hda_dsp_ctrl_stop_chip, "SND_SOC_SOF_INTEL_HDA_COMMON");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF helpers for HDaudio platforms");

View File

@ -939,6 +939,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
hda_dsp_ctrl_ppcap_enable(sdev, false);
}
free_ipc_irq:
hda_dsp_ctrl_stop_chip(sdev);
free_irq(sdev->ipc_irq, sdev);
free_irq_vector:
if (sdev->msi_enabled)
@ -1006,6 +1007,9 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
snd_dma_free_pages(&hda->iccmax_dmab);
skip_disable_dsp:
/* stop CORB/RIRB and position buffer DMA before the buffers are freed */
hda_dsp_ctrl_stop_chip(sdev);
free_irq(sdev->ipc_irq, sdev);
if (sdev->msi_enabled)
pci_free_irq_vectors(pci);

View File

@ -6,6 +6,7 @@
//
// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@ -55,8 +56,8 @@
#define CFG_S2MM_XFER_SHIFT 29
#define CFG_S2MM_PKG_MASK BIT(28)
#define AUD_CTRL_DATA_WIDTH_SHIFT 16
#define AUD_CTRL_ACTIVE_CH_SHIFT 19
#define AUD_CTRL_DATA_WIDTH_MASK GENMASK(18, 16)
#define AUD_CTRL_ACTIVE_CH_MASK GENMASK(22, 19)
#define PERIOD_CFG_PERIODS_SHIFT 16
#define PERIODS_MIN 2
@ -506,28 +507,29 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
val &= ~(AUD_CTRL_DATA_WIDTH_MASK | AUD_CTRL_ACTIVE_CH_MASK);
bits_per_sample = params_width(params);
switch (bits_per_sample) {
case 8:
val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_8);
break;
case 16:
val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_16);
break;
case 20:
val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_20);
break;
case 24:
val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_24);
break;
case 32:
val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_32);
break;
default:
return -EINVAL;
}
val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
val |= FIELD_PREP(AUD_CTRL_ACTIVE_CH_MASK, active_ch);
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT)