forked from Minki/linux
ASoC: Updates for v5.17
A few more updates for v5.17, nothing hugely stand out in the few days since the initial pull request was sent. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmHcKrQACgkQJNaLcl1U h9CLHgf/eA8SDvjL0PzrGiNusrSKhNd0hDrDyrOGGKLjxEvauIr5WGRIgG3F9Frs wQiyC7tJBJZ3kQ7WTkXbqY53cwO4QYDyQj9k/Knx/MouPSNcEfgHB+UWxOi8A9ON 5ySGN2PJTgqtGfBQdtQFvzNqs6kOzf83rl52ovTgvROmhJwnOV1iT2Oge5ynZeFM jC/Dhs/DXy3V09LY2OcWAcv4/QGek7pblj5OS0/3yvFeMsjIuU3LhO+8lUptAtmw eTbOoOXUdci5HVgSDw5O9cBlv+OS4Zk4VdXF4KvQ2Cp/Hlj3xdm2dSRyjBdYMGXb X+L9BeJpFjEnv57zrzXcoycVjNHKCQ== =iAwF -----END PGP SIGNATURE----- Merge tag 'asoc-v5.17-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus ASoC: Updates for v5.17 A few more updates for v5.17, nothing hugely stand out in the few days since the initial pull request was sent.
This commit is contained in:
commit
f66229aa35
@ -2744,10 +2744,16 @@ EXPORT_SYMBOL_GPL(cs_dsp_stop);
|
||||
|
||||
static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
|
||||
{
|
||||
return regmap_update_bits(dsp->regmap,
|
||||
dsp->base + HALO_CCM_CORE_CONTROL,
|
||||
HALO_CORE_RESET | HALO_CORE_EN,
|
||||
HALO_CORE_RESET | HALO_CORE_EN);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
|
||||
HALO_CORE_RESET | HALO_CORE_EN,
|
||||
HALO_CORE_RESET | HALO_CORE_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
|
||||
HALO_CORE_RESET, 0);
|
||||
}
|
||||
|
||||
static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)
|
||||
|
@ -40,6 +40,9 @@
|
||||
#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034
|
||||
#define CS35L41_GPIO_PAD_CONTROL 0x0000242C
|
||||
#define CS35L41_JTAG_CONTROL 0x00002438
|
||||
#define CS35L41_PWRMGT_CTL 0x00002900
|
||||
#define CS35L41_WAKESRC_CTL 0x00002904
|
||||
#define CS35L41_PWRMGT_STS 0x00002908
|
||||
#define CS35L41_PLL_CLK_CTRL 0x00002C04
|
||||
#define CS35L41_DSP_CLK_CTRL 0x00002C08
|
||||
#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C
|
||||
@ -635,6 +638,8 @@
|
||||
#define CS35L41_INPUT_DSP_TX1 0x32
|
||||
#define CS35L41_INPUT_DSP_TX2 0x33
|
||||
|
||||
#define CS35L41_WR_PEND_STS_MASK 0x2
|
||||
|
||||
#define CS35L41_PLL_CLK_SEL_MASK 0x07
|
||||
#define CS35L41_PLL_CLK_SEL_SHIFT 0
|
||||
#define CS35L41_PLL_CLK_EN_MASK 0x10
|
||||
@ -762,6 +767,8 @@ struct cs35l41_otp_map_element_t {
|
||||
extern struct regmap_config cs35l41_regmap_i2c;
|
||||
extern struct regmap_config cs35l41_regmap_spi;
|
||||
|
||||
int cs35l41_test_key_unlock(struct device *dev, struct regmap *regmap);
|
||||
int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap);
|
||||
int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap);
|
||||
int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid);
|
||||
int cs35l41_set_channels(struct device *dev, struct regmap *reg,
|
||||
|
@ -293,8 +293,8 @@ static const struct snd_soc_ops acp_card_rt5682s_ops = {
|
||||
|
||||
/* Declare RT1019 codec components */
|
||||
SND_SOC_DAILINK_DEF(rt1019,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"),
|
||||
COMP_CODEC("i2c-10EC1019:02", "rt1019-aif")));
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
|
||||
COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
|
||||
|
||||
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
|
||||
{ "Left Spk", NULL, "Left SPO" },
|
||||
@ -303,11 +303,11 @@ static const struct snd_soc_dapm_route rt1019_map_lr[] = {
|
||||
|
||||
static struct snd_soc_codec_conf rt1019_conf[] = {
|
||||
{
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
|
||||
.name_prefix = "Left",
|
||||
},
|
||||
{
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:02"),
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
|
||||
.name_prefix = "Right",
|
||||
},
|
||||
};
|
||||
|
@ -438,7 +438,6 @@ static int ak4375_power_on(struct ak4375_priv *ak4375)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int __maybe_unused ak4375_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ak4375_priv *ak4375 = dev_get_drvdata(dev);
|
||||
@ -463,7 +462,6 @@ static int __maybe_unused ak4375_runtime_resume(struct device *dev)
|
||||
|
||||
return regcache_sync(ak4375->regmap);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct snd_soc_component_driver soc_codec_dev_ak4375 = {
|
||||
.controls = ak4375_snd_controls,
|
||||
|
@ -22,6 +22,8 @@
|
||||
static const struct i2c_device_id cs35l41_id_i2c[] = {
|
||||
{ "cs35l40", 0 },
|
||||
{ "cs35l41", 0 },
|
||||
{ "cs35l51", 0 },
|
||||
{ "cs35l53", 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -84,6 +86,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
|
||||
static struct i2c_driver cs35l41_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs35l41",
|
||||
.pm = &cs35l41_pm_ops,
|
||||
.of_match_table = of_match_ptr(cs35l41_of_match),
|
||||
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
|
||||
},
|
||||
|
@ -20,6 +20,11 @@ static const struct reg_default cs35l41_reg[] = {
|
||||
{ CS35L41_PWR_CTRL2, 0x00000000 },
|
||||
{ CS35L41_PWR_CTRL3, 0x01000010 },
|
||||
{ CS35L41_GPIO_PAD_CONTROL, 0x00000000 },
|
||||
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 },
|
||||
{ CS35L41_TST_FS_MON0, 0x00020016 },
|
||||
{ CS35L41_BSTCVRT_COEFF, 0x00002424 },
|
||||
{ CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 },
|
||||
{ CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A },
|
||||
{ CS35L41_SP_ENABLES, 0x00000000 },
|
||||
{ CS35L41_SP_RATE_CTRL, 0x00000028 },
|
||||
{ CS35L41_SP_FORMAT, 0x18180200 },
|
||||
@ -48,11 +53,16 @@ static const struct reg_default cs35l41_reg[] = {
|
||||
{ CS35L41_WKFET_CFG, 0x00000111 },
|
||||
{ CS35L41_NG_CFG, 0x00000033 },
|
||||
{ CS35L41_AMP_GAIN_CTRL, 0x00000000 },
|
||||
{ CS35L41_IRQ1_MASK1, 0xFFFFFFFF },
|
||||
{ CS35L41_IRQ1_MASK2, 0xFFFFFFFF },
|
||||
{ CS35L41_IRQ1_MASK3, 0xFFFF87FF },
|
||||
{ CS35L41_IRQ1_MASK4, 0xFEFFFFFF },
|
||||
{ CS35L41_GPIO1_CTRL1, 0xE1000001 },
|
||||
{ CS35L41_GPIO2_CTRL1, 0xE1000001 },
|
||||
{ CS35L41_MIXER_NGATE_CFG, 0x00000000 },
|
||||
{ CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 },
|
||||
{ CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 },
|
||||
{ CS35L41_DSP1_CCM_CORE_CTRL, 0x00000101 },
|
||||
};
|
||||
|
||||
static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
|
||||
@ -80,10 +90,14 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_PROTECT_REL_ERR_IGN:
|
||||
case CS35L41_GPIO_PAD_CONTROL:
|
||||
case CS35L41_JTAG_CONTROL:
|
||||
case CS35L41_PWRMGT_CTL:
|
||||
case CS35L41_WAKESRC_CTL:
|
||||
case CS35L41_PWRMGT_STS:
|
||||
case CS35L41_PLL_CLK_CTRL:
|
||||
case CS35L41_DSP_CLK_CTRL:
|
||||
case CS35L41_GLOBAL_CLK_CTRL:
|
||||
case CS35L41_DATA_FS_SEL:
|
||||
case CS35L41_TST_FS_MON0:
|
||||
case CS35L41_MDSYNC_EN:
|
||||
case CS35L41_MDSYNC_TX_ID:
|
||||
case CS35L41_MDSYNC_PWR_CTRL:
|
||||
@ -342,7 +356,10 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
|
||||
static bool cs35l41_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS35L41_TEST_KEY_CTL:
|
||||
case CS35L41_USER_KEY_CTL:
|
||||
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
|
||||
case CS35L41_TST_FS_MON0:
|
||||
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
|
||||
case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:
|
||||
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
|
||||
@ -359,6 +376,12 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_SFT_RESET:
|
||||
case CS35L41_FABID:
|
||||
case CS35L41_REVID:
|
||||
case CS35L41_OTPID:
|
||||
case CS35L41_TEST_KEY_CTL:
|
||||
case CS35L41_USER_KEY_CTL:
|
||||
case CS35L41_PWRMGT_CTL:
|
||||
case CS35L41_WAKESRC_CTL:
|
||||
case CS35L41_PWRMGT_STS:
|
||||
case CS35L41_DTEMP_EN:
|
||||
case CS35L41_IRQ1_STATUS:
|
||||
case CS35L41_IRQ1_STATUS1:
|
||||
@ -369,17 +392,6 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_IRQ1_RAW_STATUS2:
|
||||
case CS35L41_IRQ1_RAW_STATUS3:
|
||||
case CS35L41_IRQ1_RAW_STATUS4:
|
||||
case CS35L41_IRQ1_FRC1:
|
||||
case CS35L41_IRQ1_FRC2:
|
||||
case CS35L41_IRQ1_FRC3:
|
||||
case CS35L41_IRQ1_FRC4:
|
||||
case CS35L41_IRQ1_EDGE1:
|
||||
case CS35L41_IRQ1_EDGE4:
|
||||
case CS35L41_IRQ1_POL1:
|
||||
case CS35L41_IRQ1_POL2:
|
||||
case CS35L41_IRQ1_POL3:
|
||||
case CS35L41_IRQ1_POL4:
|
||||
case CS35L41_IRQ1_DB3:
|
||||
case CS35L41_IRQ2_STATUS:
|
||||
case CS35L41_IRQ2_STATUS1:
|
||||
case CS35L41_IRQ2_STATUS2:
|
||||
@ -389,54 +401,7 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_IRQ2_RAW_STATUS2:
|
||||
case CS35L41_IRQ2_RAW_STATUS3:
|
||||
case CS35L41_IRQ2_RAW_STATUS4:
|
||||
case CS35L41_IRQ2_FRC1:
|
||||
case CS35L41_IRQ2_FRC2:
|
||||
case CS35L41_IRQ2_FRC3:
|
||||
case CS35L41_IRQ2_FRC4:
|
||||
case CS35L41_IRQ2_EDGE1:
|
||||
case CS35L41_IRQ2_EDGE4:
|
||||
case CS35L41_IRQ2_POL1:
|
||||
case CS35L41_IRQ2_POL2:
|
||||
case CS35L41_IRQ2_POL3:
|
||||
case CS35L41_IRQ2_POL4:
|
||||
case CS35L41_IRQ2_DB3:
|
||||
case CS35L41_GPIO_STATUS1:
|
||||
case CS35L41_OTP_TRIM_1:
|
||||
case CS35L41_OTP_TRIM_2:
|
||||
case CS35L41_OTP_TRIM_3:
|
||||
case CS35L41_OTP_TRIM_4:
|
||||
case CS35L41_OTP_TRIM_5:
|
||||
case CS35L41_OTP_TRIM_6:
|
||||
case CS35L41_OTP_TRIM_7:
|
||||
case CS35L41_OTP_TRIM_8:
|
||||
case CS35L41_OTP_TRIM_9:
|
||||
case CS35L41_OTP_TRIM_10:
|
||||
case CS35L41_OTP_TRIM_11:
|
||||
case CS35L41_OTP_TRIM_12:
|
||||
case CS35L41_OTP_TRIM_13:
|
||||
case CS35L41_OTP_TRIM_14:
|
||||
case CS35L41_OTP_TRIM_15:
|
||||
case CS35L41_OTP_TRIM_16:
|
||||
case CS35L41_OTP_TRIM_17:
|
||||
case CS35L41_OTP_TRIM_18:
|
||||
case CS35L41_OTP_TRIM_19:
|
||||
case CS35L41_OTP_TRIM_20:
|
||||
case CS35L41_OTP_TRIM_21:
|
||||
case CS35L41_OTP_TRIM_22:
|
||||
case CS35L41_OTP_TRIM_23:
|
||||
case CS35L41_OTP_TRIM_24:
|
||||
case CS35L41_OTP_TRIM_25:
|
||||
case CS35L41_OTP_TRIM_26:
|
||||
case CS35L41_OTP_TRIM_27:
|
||||
case CS35L41_OTP_TRIM_28:
|
||||
case CS35L41_OTP_TRIM_29:
|
||||
case CS35L41_OTP_TRIM_30:
|
||||
case CS35L41_OTP_TRIM_31:
|
||||
case CS35L41_OTP_TRIM_32:
|
||||
case CS35L41_OTP_TRIM_33:
|
||||
case CS35L41_OTP_TRIM_34:
|
||||
case CS35L41_OTP_TRIM_35:
|
||||
case CS35L41_OTP_TRIM_36:
|
||||
case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:
|
||||
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
|
||||
case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046:
|
||||
@ -445,7 +410,11 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:
|
||||
case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:
|
||||
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
|
||||
case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS:
|
||||
case CS35L41_DSP1_SCRATCH1:
|
||||
case CS35L41_DSP1_SCRATCH2:
|
||||
case CS35L41_DSP1_SCRATCH3:
|
||||
case CS35L41_DSP1_SCRATCH4:
|
||||
case CS35L41_DSP1_CCM_CLK_OVERRIDE ... CS35L41_DSP1_WDT_STATUS:
|
||||
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
|
||||
return true;
|
||||
default:
|
||||
@ -660,8 +629,6 @@ static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM]
|
||||
};
|
||||
|
||||
static const struct reg_sequence cs35l41_reva0_errata_patch[] = {
|
||||
{ 0x00000040, 0x00005555 },
|
||||
{ 0x00000040, 0x0000AAAA },
|
||||
{ 0x00003854, 0x05180240 },
|
||||
{ CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 },
|
||||
{ 0x00004310, 0x00000000 },
|
||||
@ -674,38 +641,28 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = {
|
||||
{ CS35L41_IRQ2_DB3, 0x00000000 },
|
||||
{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ 0x00000040, 0x0000CCCC },
|
||||
{ 0x00000040, 0x00003333 },
|
||||
{ CS35L41_PWR_CTRL2, 0x00000000 },
|
||||
{ CS35L41_AMP_GAIN_CTRL, 0x00000000 },
|
||||
};
|
||||
|
||||
static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
|
||||
{ 0x00000040, 0x00005555 },
|
||||
{ 0x00000040, 0x0000AAAA },
|
||||
{ CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 },
|
||||
{ 0x00004310, 0x00000000 },
|
||||
{ CS35L41_VPVBST_FS_SEL, 0x00000000 },
|
||||
{ CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 },
|
||||
{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ 0x00000040, 0x0000CCCC },
|
||||
{ 0x00000040, 0x00003333 },
|
||||
{ CS35L41_PWR_CTRL2, 0x00000000 },
|
||||
{ CS35L41_AMP_GAIN_CTRL, 0x00000000 },
|
||||
};
|
||||
|
||||
static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
|
||||
{ 0x00000040, 0x00005555 },
|
||||
{ 0x00000040, 0x0000AAAA },
|
||||
{ CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 },
|
||||
{ 0x00004310, 0x00000000 },
|
||||
{ CS35L41_VPVBST_FS_SEL, 0x00000000 },
|
||||
{ CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 },
|
||||
{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
|
||||
{ 0x00000040, 0x0000CCCC },
|
||||
{ 0x00000040, 0x00003333 },
|
||||
{ CS35L41_PWR_CTRL2, 0x00000000 },
|
||||
{ CS35L41_AMP_GAIN_CTRL, 0x00000000 },
|
||||
};
|
||||
@ -793,6 +750,39 @@ static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cs35l41_test_key_unlock(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
static const struct reg_sequence unlock[] = {
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000055 },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000AA },
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock));
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to unlock test key: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs35l41_test_key_unlock);
|
||||
|
||||
int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
static const struct reg_sequence unlock[] = {
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000CC },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000033 },
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock));
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to lock test key: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs35l41_test_key_lock);
|
||||
|
||||
/* Must be called with the TEST_KEY unlocked */
|
||||
int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
const struct cs35l41_otp_map_element_t *otp_map_match;
|
||||
@ -831,17 +821,6 @@ int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap)
|
||||
bit_offset = otp_map_match->bit_offset;
|
||||
word_offset = otp_map_match->word_offset;
|
||||
|
||||
ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x00000055);
|
||||
if (ret) {
|
||||
dev_err(dev, "Write Unlock key failed 1/2: %d\n", ret);
|
||||
goto err_otp_unpack;
|
||||
}
|
||||
ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x000000AA);
|
||||
if (ret) {
|
||||
dev_err(dev, "Write Unlock key failed 2/2: %d\n", ret);
|
||||
goto err_otp_unpack;
|
||||
}
|
||||
|
||||
for (i = 0; i < otp_map_match->num_elements; i++) {
|
||||
dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n",
|
||||
bit_offset, word_offset, bit_sum % 32);
|
||||
@ -877,16 +856,6 @@ int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap)
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x000000CC);
|
||||
if (ret) {
|
||||
dev_err(dev, "Write Lock key failed 1/2: %d\n", ret);
|
||||
goto err_otp_unpack;
|
||||
}
|
||||
ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x00000033);
|
||||
if (ret) {
|
||||
dev_err(dev, "Write Lock key failed 2/2: %d\n", ret);
|
||||
goto err_otp_unpack;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
err_otp_unpack:
|
||||
@ -896,6 +865,7 @@ err_otp_unpack:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs35l41_otp_unpack);
|
||||
|
||||
/* Must be called with the TEST_KEY unlocked */
|
||||
int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid)
|
||||
{
|
||||
char *rev;
|
||||
|
@ -20,6 +20,8 @@
|
||||
static const struct spi_device_id cs35l41_id_spi[] = {
|
||||
{ "cs35l40", 0 },
|
||||
{ "cs35l41", 0 },
|
||||
{ "cs35l51", 0 },
|
||||
{ "cs35l53", 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -82,6 +84,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
|
||||
static struct spi_driver cs35l41_spi_driver = {
|
||||
.driver = {
|
||||
.name = "cs35l41",
|
||||
.pm = &cs35l41_pm_ops,
|
||||
.of_match_table = of_match_ptr(cs35l41_of_match),
|
||||
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
|
||||
},
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -181,17 +182,27 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp,
|
||||
static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (cs35l41->dsp.cs_dsp.booted)
|
||||
return 0;
|
||||
|
||||
return wm_adsp_early_event(w, kcontrol, event);
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
ret = wm_adsp_early_event(w, kcontrol, event);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (cs35l41->dsp.preloaded)
|
||||
return 0;
|
||||
|
||||
return wm_adsp_event(w, kcontrol, event);
|
||||
if (cs35l41->dsp.cs_dsp.running) {
|
||||
ret = wm_adsp_event(w, kcontrol, event);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return wm_adsp_early_event(w, kcontrol, event);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -205,6 +216,7 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
|
||||
case CSPL_MBOX_CMD_UNKNOWN_CMD:
|
||||
return true;
|
||||
case CSPL_MBOX_CMD_PAUSE:
|
||||
case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:
|
||||
return (sts == CSPL_MBOX_STS_PAUSED);
|
||||
case CSPL_MBOX_CMD_RESUME:
|
||||
return (sts == CSPL_MBOX_STS_RUNNING);
|
||||
@ -226,7 +238,8 @@ static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41,
|
||||
// Set mailbox cmd
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Failed to write MBOX: %d\n", ret);
|
||||
if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
|
||||
dev_err(cs35l41->dev, "Failed to write MBOX: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -409,6 +422,8 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
|
||||
int ret = IRQ_NONE;
|
||||
unsigned int i;
|
||||
|
||||
pm_runtime_get_sync(cs35l41->dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(status); i++) {
|
||||
regmap_read(cs35l41->regmap,
|
||||
CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE),
|
||||
@ -421,7 +436,7 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
|
||||
/* Check to see if unmasked bits are active */
|
||||
if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) &&
|
||||
!(status[2] & ~masks[2]) && !(status[3] & ~masks[3]))
|
||||
return IRQ_NONE;
|
||||
goto done;
|
||||
|
||||
if (status[3] & CS35L41_OTP_BOOT_DONE) {
|
||||
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK4,
|
||||
@ -526,23 +541,27 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
done:
|
||||
pm_runtime_mark_last_busy(cs35l41->dev);
|
||||
pm_runtime_put_autosuspend(cs35l41->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct reg_sequence cs35l41_pup_patch[] = {
|
||||
{ 0x00000040, 0x00000055 },
|
||||
{ 0x00000040, 0x000000AA },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000055 },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000AA },
|
||||
{ 0x00002084, 0x002F1AA0 },
|
||||
{ 0x00000040, 0x000000CC },
|
||||
{ 0x00000040, 0x00000033 },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000CC },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000033 },
|
||||
};
|
||||
|
||||
static const struct reg_sequence cs35l41_pdn_patch[] = {
|
||||
{ 0x00000040, 0x00000055 },
|
||||
{ 0x00000040, 0x000000AA },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000055 },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000AA },
|
||||
{ 0x00002084, 0x002F1AA3 },
|
||||
{ 0x00000040, 0x000000CC },
|
||||
{ 0x00000040, 0x00000033 },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x000000CC },
|
||||
{ CS35L41_TEST_KEY_CTL, 0x00000033 },
|
||||
};
|
||||
|
||||
static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
|
||||
@ -1176,6 +1195,7 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
|
||||
dsp->cs_dsp.type = WMFW_HALO;
|
||||
dsp->cs_dsp.rev = 0;
|
||||
dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
|
||||
dsp->toggle_preload = true;
|
||||
dsp->cs_dsp.dev = cs35l41->dev;
|
||||
dsp->cs_dsp.regmap = cs35l41->regmap;
|
||||
dsp->cs_dsp.base = CS35L41_DSP1_CTRL_BASE;
|
||||
@ -1325,10 +1345,20 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
goto err;
|
||||
}
|
||||
|
||||
cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
|
||||
|
||||
ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
|
||||
|
||||
irq_pol = cs35l41_irq_gpio_config(cs35l41);
|
||||
|
||||
/* Set interrupt masks for critical errors */
|
||||
@ -1338,19 +1368,11 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED | irq_pol,
|
||||
"cs35l41", cs35l41);
|
||||
|
||||
/* CS35L41 needs INT for PDN_DONE */
|
||||
if (ret != 0) {
|
||||
dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = cs35l41_set_pdata(cs35l41);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret);
|
||||
@ -1361,20 +1383,32 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
|
||||
pm_runtime_use_autosuspend(cs35l41->dev);
|
||||
pm_runtime_mark_last_busy(cs35l41->dev);
|
||||
pm_runtime_set_active(cs35l41->dev);
|
||||
pm_runtime_get_noresume(cs35l41->dev);
|
||||
pm_runtime_enable(cs35l41->dev);
|
||||
|
||||
ret = devm_snd_soc_register_component(cs35l41->dev,
|
||||
&soc_component_dev_cs35l41,
|
||||
cs35l41_dai, ARRAY_SIZE(cs35l41_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Register codec failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
goto err_pm;
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(cs35l41->dev);
|
||||
|
||||
dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n",
|
||||
regid, reg_revid);
|
||||
|
||||
return 0;
|
||||
|
||||
err_dsp:
|
||||
err_pm:
|
||||
pm_runtime_disable(cs35l41->dev);
|
||||
pm_runtime_put_noidle(cs35l41->dev);
|
||||
|
||||
wm_adsp2_remove(&cs35l41->dsp);
|
||||
err:
|
||||
regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
|
||||
@ -1386,13 +1420,178 @@ EXPORT_SYMBOL_GPL(cs35l41_probe);
|
||||
|
||||
void cs35l41_remove(struct cs35l41_private *cs35l41)
|
||||
{
|
||||
pm_runtime_get_sync(cs35l41->dev);
|
||||
pm_runtime_disable(cs35l41->dev);
|
||||
|
||||
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
|
||||
wm_adsp2_remove(&cs35l41->dsp);
|
||||
|
||||
pm_runtime_put_noidle(cs35l41->dev);
|
||||
|
||||
regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
|
||||
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cs35l41_remove);
|
||||
|
||||
static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(cs35l41->dev, "Runtime suspend\n");
|
||||
|
||||
if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running)
|
||||
return 0;
|
||||
|
||||
dev_dbg(cs35l41->dev, "Enter hibernate\n");
|
||||
|
||||
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
|
||||
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
|
||||
|
||||
// Don't wait for ACK since bus activity would wake the device
|
||||
regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1,
|
||||
CSPL_MBOX_CMD_HIBERNATE);
|
||||
|
||||
regcache_cache_only(cs35l41->regmap, true);
|
||||
regcache_mark_dirty(cs35l41->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41)
|
||||
{
|
||||
const int pwrmgt_retries = 10;
|
||||
unsigned int sts;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < pwrmgt_retries; i++) {
|
||||
ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts);
|
||||
if (ret)
|
||||
dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret);
|
||||
else if (!(sts & CS35L41_WR_PEND_STS_MASK))
|
||||
return;
|
||||
|
||||
udelay(20);
|
||||
}
|
||||
|
||||
dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n");
|
||||
}
|
||||
|
||||
static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41)
|
||||
{
|
||||
const int wake_retries = 20;
|
||||
const int sleep_retries = 5;
|
||||
int ret, i, j;
|
||||
|
||||
for (i = 0; i < sleep_retries; i++) {
|
||||
dev_dbg(cs35l41->dev, "Exit hibernate\n");
|
||||
|
||||
for (j = 0; j < wake_retries; j++) {
|
||||
ret = cs35l41_set_cspl_mbox_cmd(cs35l41,
|
||||
CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
|
||||
if (j < wake_retries) {
|
||||
dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret);
|
||||
|
||||
cs35l41_wait_for_pwrmgt_sts(cs35l41);
|
||||
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
|
||||
|
||||
cs35l41_wait_for_pwrmgt_sts(cs35l41);
|
||||
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
|
||||
|
||||
cs35l41_wait_for_pwrmgt_sts(cs35l41);
|
||||
regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3);
|
||||
}
|
||||
|
||||
dev_err(cs35l41->dev, "Timed out waking device\n");
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
dev_dbg(cs35l41->dev, "Runtime resume\n");
|
||||
|
||||
if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running)
|
||||
return 0;
|
||||
|
||||
regcache_cache_only(cs35l41->regmap, false);
|
||||
|
||||
ret = cs35l41_exit_hibernate(cs35l41);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Test key needs to be unlocked to allow the OTP settings to re-apply */
|
||||
cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
|
||||
ret = regcache_sync(cs35l41->regmap);
|
||||
cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
|
||||
if (ret) {
|
||||
dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l41_sys_suspend(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(cs35l41->dev, "System suspend, disabling IRQ\n");
|
||||
disable_irq(cs35l41->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(cs35l41->dev, "Late system suspend, reenabling IRQ\n");
|
||||
enable_irq(cs35l41->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(cs35l41->dev, "Early system resume, disabling IRQ\n");
|
||||
disable_irq(cs35l41->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l41_sys_resume(struct device *dev)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(cs35l41->dev, "System resume, reenabling IRQ\n");
|
||||
enable_irq(cs35l41->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops cs35l41_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
|
||||
|
||||
SET_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs35l41_pm_ops);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CS35L41 driver");
|
||||
MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -21,6 +21,8 @@
|
||||
#define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
#define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
extern const struct dev_pm_ops cs35l41_pm_ops;
|
||||
|
||||
enum cs35l41_cspl_mbox_status {
|
||||
CSPL_MBOX_STS_RUNNING = 0,
|
||||
CSPL_MBOX_STS_PAUSED = 1,
|
||||
@ -33,6 +35,8 @@ enum cs35l41_cspl_mbox_cmd {
|
||||
CSPL_MBOX_CMD_RESUME = 2,
|
||||
CSPL_MBOX_CMD_REINIT = 3,
|
||||
CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
|
||||
CSPL_MBOX_CMD_HIBERNATE = 5,
|
||||
CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6,
|
||||
CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
|
||||
CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
|
||||
};
|
||||
|
@ -626,6 +626,16 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
|
||||
ARRAY_SIZE(cs4265_dai));
|
||||
}
|
||||
|
||||
static int cs4265_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct cs4265_private *cs4265 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (cs4265->reset_gpio)
|
||||
gpiod_set_value_cansleep(cs4265->reset_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cs4265_of_match[] = {
|
||||
{ .compatible = "cirrus,cs4265", },
|
||||
{ }
|
||||
@ -645,6 +655,7 @@ static struct i2c_driver cs4265_i2c_driver = {
|
||||
},
|
||||
.id_table = cs4265_id,
|
||||
.probe = cs4265_i2c_probe,
|
||||
.remove = cs4265_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(cs4265_i2c_driver);
|
||||
|
@ -2160,7 +2160,11 @@ static bool rt5640_jack_inserted(struct snd_soc_component *component)
|
||||
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
|
||||
int val;
|
||||
|
||||
val = snd_soc_component_read(component, RT5640_INT_IRQ_ST);
|
||||
if (rt5640->jd_gpio)
|
||||
val = gpiod_get_value(rt5640->jd_gpio) ? RT5640_JD_STATUS : 0;
|
||||
else
|
||||
val = snd_soc_component_read(component, RT5640_INT_IRQ_ST);
|
||||
|
||||
dev_dbg(component->dev, "irq status %#04x\n", val);
|
||||
|
||||
if (rt5640->jd_inverted)
|
||||
@ -2298,7 +2302,7 @@ EXPORT_SYMBOL_GPL(rt5640_detect_headset);
|
||||
static void rt5640_jack_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5640_priv *rt5640 =
|
||||
container_of(work, struct rt5640_priv, jack_work);
|
||||
container_of(work, struct rt5640_priv, jack_work.work);
|
||||
struct snd_soc_component *component = rt5640->component;
|
||||
int status;
|
||||
|
||||
@ -2381,7 +2385,7 @@ static void rt5640_jack_work(struct work_struct *work)
|
||||
* disabled the OVCD IRQ, the IRQ pin will stay high and as
|
||||
* we react to edges, we miss the unplug event -> recheck.
|
||||
*/
|
||||
queue_work(system_long_wq, &rt5640->jack_work);
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2390,7 +2394,17 @@ static irqreturn_t rt5640_irq(int irq, void *data)
|
||||
struct rt5640_priv *rt5640 = data;
|
||||
|
||||
if (rt5640->jack)
|
||||
queue_work(system_long_wq, &rt5640->jack_work);
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = data;
|
||||
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work,
|
||||
msecs_to_jiffies(JACK_SETTLE_TIME));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -2399,7 +2413,7 @@ static void rt5640_cancel_work(void *data)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = data;
|
||||
|
||||
cancel_work_sync(&rt5640->jack_work);
|
||||
cancel_delayed_work_sync(&rt5640->jack_work);
|
||||
cancel_delayed_work_sync(&rt5640->bp_work);
|
||||
}
|
||||
|
||||
@ -2439,7 +2453,12 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
|
||||
if (!rt5640->jack)
|
||||
return;
|
||||
|
||||
free_irq(rt5640->irq, rt5640);
|
||||
if (rt5640->jd_gpio_irq_requested)
|
||||
free_irq(rt5640->jd_gpio_irq, rt5640);
|
||||
|
||||
if (rt5640->irq_requested)
|
||||
free_irq(rt5640->irq, rt5640);
|
||||
|
||||
rt5640_cancel_work(rt5640);
|
||||
|
||||
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
|
||||
@ -2448,11 +2467,15 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
|
||||
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
|
||||
}
|
||||
|
||||
rt5640->jd_gpio_irq_requested = false;
|
||||
rt5640->irq_requested = false;
|
||||
rt5640->jd_gpio = NULL;
|
||||
rt5640->jack = NULL;
|
||||
}
|
||||
|
||||
static void rt5640_enable_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack)
|
||||
struct snd_soc_jack *jack,
|
||||
struct rt5640_set_jack_data *jack_data)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
@ -2496,19 +2519,37 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
|
||||
rt5640_enable_micbias1_ovcd_irq(component);
|
||||
}
|
||||
|
||||
if (jack_data && jack_data->codec_irq_override)
|
||||
rt5640->irq = jack_data->codec_irq_override;
|
||||
|
||||
if (jack_data && jack_data->jd_gpio) {
|
||||
rt5640->jd_gpio = jack_data->jd_gpio;
|
||||
rt5640->jd_gpio_irq = gpiod_to_irq(rt5640->jd_gpio);
|
||||
|
||||
ret = request_irq(rt5640->jd_gpio_irq, rt5640_jd_gpio_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"rt5640-jd-gpio", rt5640);
|
||||
if (ret) {
|
||||
dev_warn(component->dev, "Failed to request jd GPIO IRQ %d: %d\n",
|
||||
rt5640->jd_gpio_irq, ret);
|
||||
rt5640_disable_jack_detect(component);
|
||||
return;
|
||||
}
|
||||
rt5640->jd_gpio_irq_requested = true;
|
||||
}
|
||||
|
||||
ret = request_irq(rt5640->irq, rt5640_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"rt5640", rt5640);
|
||||
if (ret) {
|
||||
dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
|
||||
rt5640->irq = -ENXIO;
|
||||
/* Undo above settings */
|
||||
rt5640_disable_jack_detect(component);
|
||||
return;
|
||||
}
|
||||
rt5640->irq_requested = true;
|
||||
|
||||
/* sync initial jack state */
|
||||
queue_work(system_long_wq, &rt5640->jack_work);
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
|
||||
}
|
||||
|
||||
static void rt5640_enable_hda_jack_detect(
|
||||
@ -2546,7 +2587,7 @@ static void rt5640_enable_hda_jack_detect(
|
||||
}
|
||||
|
||||
/* sync initial jack state */
|
||||
queue_work(system_long_wq, &rt5640->jack_work);
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
|
||||
}
|
||||
|
||||
static int rt5640_set_jack(struct snd_soc_component *component,
|
||||
@ -2558,7 +2599,7 @@ static int rt5640_set_jack(struct snd_soc_component *component,
|
||||
if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
|
||||
rt5640_enable_hda_jack_detect(component, jack);
|
||||
else
|
||||
rt5640_enable_jack_detect(component, jack);
|
||||
rt5640_enable_jack_detect(component, jack, data);
|
||||
} else {
|
||||
rt5640_disable_jack_detect(component);
|
||||
}
|
||||
@ -2737,7 +2778,7 @@ static int rt5640_resume(struct snd_soc_component *component)
|
||||
regcache_cache_only(rt5640->regmap, false);
|
||||
regcache_sync(rt5640->regmap);
|
||||
|
||||
if (rt5640->jd_src) {
|
||||
if (rt5640->jack) {
|
||||
if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
|
||||
snd_soc_component_update_bits(component,
|
||||
RT5640_DUMMY2, 0x1100, 0x1100);
|
||||
@ -2745,7 +2786,7 @@ static int rt5640_resume(struct snd_soc_component *component)
|
||||
snd_soc_component_write(component, RT5640_DUMMY2,
|
||||
0x4001);
|
||||
|
||||
queue_work(system_long_wq, &rt5640->jack_work);
|
||||
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2950,7 +2991,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
|
||||
rt5640->hp_mute = true;
|
||||
rt5640->irq = i2c->irq;
|
||||
INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
|
||||
INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
|
||||
INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work);
|
||||
|
||||
/* Make sure work is stopped on probe-error / remove */
|
||||
ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
|
||||
|
@ -2124,6 +2124,7 @@ struct rt5640_priv {
|
||||
|
||||
int ldo1_en; /* GPIO for LDO1_EN */
|
||||
int irq;
|
||||
int jd_gpio_irq;
|
||||
int sysclk;
|
||||
int sysclk_src;
|
||||
int lrck[RT5640_AIFS];
|
||||
@ -2136,6 +2137,8 @@ struct rt5640_priv {
|
||||
|
||||
bool hp_mute;
|
||||
bool asrc_en;
|
||||
bool irq_requested;
|
||||
bool jd_gpio_irq_requested;
|
||||
|
||||
/* Jack and button detect data */
|
||||
bool ovcd_irq_enabled;
|
||||
@ -2145,14 +2148,20 @@ struct rt5640_priv {
|
||||
int release_count;
|
||||
int poll_count;
|
||||
struct delayed_work bp_work;
|
||||
struct work_struct jack_work;
|
||||
struct delayed_work jack_work;
|
||||
struct snd_soc_jack *jack;
|
||||
struct gpio_desc *jd_gpio;
|
||||
unsigned int jd_src;
|
||||
bool jd_inverted;
|
||||
unsigned int ovcd_th;
|
||||
unsigned int ovcd_sf;
|
||||
};
|
||||
|
||||
struct rt5640_set_jack_data {
|
||||
int codec_irq_override;
|
||||
struct gpio_desc *jd_gpio;
|
||||
};
|
||||
|
||||
int rt5640_dmic_enable(struct snd_soc_component *component,
|
||||
bool dmic1_data_pin, bool dmic2_data_pin);
|
||||
int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
|
||||
|
@ -341,7 +341,7 @@ struct wcd9335_codec {
|
||||
int reset_gpio;
|
||||
struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
|
||||
|
||||
unsigned int rx_port_value;
|
||||
unsigned int rx_port_value[WCD9335_RX_MAX];
|
||||
unsigned int tx_port_value;
|
||||
int hph_l_gain;
|
||||
int hph_r_gain;
|
||||
@ -1269,10 +1269,11 @@ static const struct snd_kcontrol_new sb_tx8_mux =
|
||||
static int slim_rx_mux_get(struct snd_kcontrol *kc,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
|
||||
struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
|
||||
struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
|
||||
struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev);
|
||||
u32 port_id = w->shift;
|
||||
|
||||
ucontrol->value.enumerated.item[0] = wcd->rx_port_value;
|
||||
ucontrol->value.enumerated.item[0] = wcd->rx_port_value[port_id];
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1286,9 +1287,9 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
|
||||
struct snd_soc_dapm_update *update = NULL;
|
||||
u32 port_id = w->shift;
|
||||
|
||||
wcd->rx_port_value = ucontrol->value.enumerated.item[0];
|
||||
wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
|
||||
|
||||
switch (wcd->rx_port_value) {
|
||||
switch (wcd->rx_port_value[port_id]) {
|
||||
case 0:
|
||||
list_del_init(&wcd->rx_chs[port_id].list);
|
||||
break;
|
||||
@ -1309,11 +1310,11 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
|
||||
&wcd->dai[AIF4_PB].slim_ch_list);
|
||||
break;
|
||||
default:
|
||||
dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value);
|
||||
dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value[port_id]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value,
|
||||
snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
|
||||
e, update);
|
||||
|
||||
return 0;
|
||||
|
@ -896,11 +896,12 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
struct wm_adsp *dsp = &dsps[mc->shift - 1];
|
||||
char preload[32];
|
||||
|
||||
if (dsp->preloaded == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
||||
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
|
||||
|
||||
dsp->preloaded = ucontrol->value.integer.value[0];
|
||||
|
||||
if (ucontrol->value.integer.value[0])
|
||||
if (ucontrol->value.integer.value[0] || dsp->toggle_preload)
|
||||
snd_soc_component_force_enable_pin(component, preload);
|
||||
else
|
||||
snd_soc_component_disable_pin(component, preload);
|
||||
@ -909,6 +910,13 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
flush_work(&dsp->boot_work);
|
||||
|
||||
dsp->preloaded = ucontrol->value.integer.value[0];
|
||||
|
||||
if (dsp->toggle_preload) {
|
||||
snd_soc_component_disable_pin(component, preload);
|
||||
snd_soc_dapm_sync(dapm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
|
||||
|
@ -41,6 +41,14 @@ struct wm_adsp {
|
||||
|
||||
struct list_head compr_list;
|
||||
struct list_head buffer_list;
|
||||
|
||||
/*
|
||||
* Flag indicating the preloader widget only needs power toggled
|
||||
* on state change rather than held on for the duration of the
|
||||
* preload, useful for devices that can retain firmware memory
|
||||
* across power down.
|
||||
*/
|
||||
bool toggle_preload;
|
||||
};
|
||||
|
||||
#define WM_ADSP1(wname, num) \
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "fsl_asrc.h"
|
||||
|
||||
#define IDEAL_RATIO_DECIMAL_DEPTH 26
|
||||
#define DIVIDER_NUM 64
|
||||
|
||||
#define pair_err(fmt, ...) \
|
||||
dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
|
||||
@ -101,6 +102,55 @@ static unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* According to RM, the divider range is 1 ~ 8,
|
||||
* prescaler is power of 2 from 1 ~ 128.
|
||||
*/
|
||||
static int asrc_clk_divider[DIVIDER_NUM] = {
|
||||
1, 2, 4, 8, 16, 32, 64, 128, /* divider = 1 */
|
||||
2, 4, 8, 16, 32, 64, 128, 256, /* divider = 2 */
|
||||
3, 6, 12, 24, 48, 96, 192, 384, /* divider = 3 */
|
||||
4, 8, 16, 32, 64, 128, 256, 512, /* divider = 4 */
|
||||
5, 10, 20, 40, 80, 160, 320, 640, /* divider = 5 */
|
||||
6, 12, 24, 48, 96, 192, 384, 768, /* divider = 6 */
|
||||
7, 14, 28, 56, 112, 224, 448, 896, /* divider = 7 */
|
||||
8, 16, 32, 64, 128, 256, 512, 1024, /* divider = 8 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Check if the divider is available for internal ratio mode
|
||||
*/
|
||||
static bool fsl_asrc_divider_avail(int clk_rate, int rate, int *div)
|
||||
{
|
||||
u32 rem, i;
|
||||
u64 n;
|
||||
|
||||
if (div)
|
||||
*div = 0;
|
||||
|
||||
if (clk_rate == 0 || rate == 0)
|
||||
return false;
|
||||
|
||||
n = clk_rate;
|
||||
rem = do_div(n, rate);
|
||||
|
||||
if (div)
|
||||
*div = n;
|
||||
|
||||
if (rem != 0)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < DIVIDER_NUM; i++) {
|
||||
if (n == asrc_clk_divider[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == DIVIDER_NUM)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* fsl_asrc_sel_proc - Select the pre-processing and post-processing options
|
||||
* @inrate: input sample rate
|
||||
@ -330,12 +380,12 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
|
||||
enum asrc_word_width input_word_width;
|
||||
enum asrc_word_width output_word_width;
|
||||
u32 inrate, outrate, indiv, outdiv;
|
||||
u32 clk_index[2], div[2], rem[2];
|
||||
u32 clk_index[2], div[2];
|
||||
u64 clk_rate;
|
||||
int in, out, channels;
|
||||
int pre_proc, post_proc;
|
||||
struct clk *clk;
|
||||
bool ideal;
|
||||
bool ideal, div_avail;
|
||||
|
||||
if (!config) {
|
||||
pair_err("invalid pair config\n");
|
||||
@ -415,8 +465,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
|
||||
clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
|
||||
|
||||
clk_rate = clk_get_rate(clk);
|
||||
rem[IN] = do_div(clk_rate, inrate);
|
||||
div[IN] = (u32)clk_rate;
|
||||
div_avail = fsl_asrc_divider_avail(clk_rate, inrate, &div[IN]);
|
||||
|
||||
/*
|
||||
* The divider range is [1, 1024], defined by the hardware. For non-
|
||||
@ -425,7 +474,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
|
||||
* only result in different converting speeds. So remainder does not
|
||||
* matter, as long as we keep the divider within its valid range.
|
||||
*/
|
||||
if (div[IN] == 0 || (!ideal && (div[IN] > 1024 || rem[IN] != 0))) {
|
||||
if (div[IN] == 0 || (!ideal && !div_avail)) {
|
||||
pair_err("failed to support input sample rate %dHz by asrck_%x\n",
|
||||
inrate, clk_index[ideal ? OUT : IN]);
|
||||
return -EINVAL;
|
||||
@ -436,13 +485,12 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
|
||||
clk = asrc_priv->asrck_clk[clk_index[OUT]];
|
||||
clk_rate = clk_get_rate(clk);
|
||||
if (ideal && use_ideal_rate)
|
||||
rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE);
|
||||
div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, &div[OUT]);
|
||||
else
|
||||
rem[OUT] = do_div(clk_rate, outrate);
|
||||
div[OUT] = clk_rate;
|
||||
div_avail = fsl_asrc_divider_avail(clk_rate, outrate, &div[OUT]);
|
||||
|
||||
/* Output divider has the same limitation as the input one */
|
||||
if (div[OUT] == 0 || (!ideal && (div[OUT] > 1024 || rem[OUT] != 0))) {
|
||||
if (div[OUT] == 0 || (!ideal && !div_avail)) {
|
||||
pair_err("failed to support output sample rate %dHz by asrck_%x\n",
|
||||
outrate, clk_index[OUT]);
|
||||
return -EINVAL;
|
||||
@ -621,8 +669,7 @@ static void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv,
|
||||
clk_index = asrc_priv->clk_map[j][i];
|
||||
clk_rate = clk_get_rate(asrc_priv->asrck_clk[clk_index]);
|
||||
/* Only match a perfect clock source with no remainder */
|
||||
if (clk_rate != 0 && (clk_rate / rate[j]) <= 1024 &&
|
||||
(clk_rate % rate[j]) == 0)
|
||||
if (fsl_asrc_divider_avail(clk_rate, rate[j], NULL))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ struct imx_card_data {
|
||||
|
||||
static struct imx_akcodec_fs_mul ak4458_fs_mul[] = {
|
||||
/* Normal, < 32kHz */
|
||||
{ .rmin = 8000, .rmax = 24000, .wmin = 1024, .wmax = 1024, },
|
||||
{ .rmin = 8000, .rmax = 24000, .wmin = 256, .wmax = 1024, },
|
||||
/* Normal, 32kHz */
|
||||
{ .rmin = 32000, .rmax = 32000, .wmin = 256, .wmax = 1024, },
|
||||
/* Normal */
|
||||
@ -151,8 +151,8 @@ static struct imx_akcodec_fs_mul ak4497_fs_mul[] = {
|
||||
* Table 7 - mapping multiplier and speed mode
|
||||
* Tables 8 & 9 - mapping speed mode and LRCK fs
|
||||
*/
|
||||
{ .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, }, /* Normal, <= 32kHz */
|
||||
{ .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, }, /* Normal */
|
||||
{ .rmin = 8000, .rmax = 32000, .wmin = 256, .wmax = 1024, }, /* Normal, <= 32kHz */
|
||||
{ .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 512, }, /* Normal */
|
||||
{ .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, }, /* Double */
|
||||
{ .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, }, /* Quad */
|
||||
{ .rmin = 352800, .rmax = 384000, .wmin = 128, .wmax = 128, }, /* Oct */
|
||||
@ -164,7 +164,7 @@ static struct imx_akcodec_fs_mul ak4497_fs_mul[] = {
|
||||
* (Table 4 from datasheet)
|
||||
*/
|
||||
static struct imx_akcodec_fs_mul ak5558_fs_mul[] = {
|
||||
{ .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, },
|
||||
{ .rmin = 8000, .rmax = 32000, .wmin = 512, .wmax = 1024, },
|
||||
{ .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, },
|
||||
{ .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, },
|
||||
{ .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, },
|
||||
@ -247,13 +247,14 @@ static bool codec_is_akcodec(unsigned int type)
|
||||
}
|
||||
|
||||
static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
struct snd_pcm_hw_params *params,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
const struct imx_card_plat_data *plat_data = data->plat_data;
|
||||
struct dai_link_data *link_data = &data->link_data[rtd->num];
|
||||
unsigned int width = link_data->slots * link_data->slot_width;
|
||||
unsigned int width = slots * slot_width;
|
||||
unsigned int rate = params_rate(params);
|
||||
int i;
|
||||
|
||||
@ -349,7 +350,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
/* Set MCLK freq */
|
||||
if (codec_is_akcodec(plat_data->type))
|
||||
mclk_freq = akcodec_get_mclk_rate(substream, params);
|
||||
mclk_freq = akcodec_get_mclk_rate(substream, params, slots, slot_width);
|
||||
else
|
||||
mclk_freq = params_rate(params) * slots * slot_width;
|
||||
/* Use the maximum freq from DSD512 (512*44100 = 22579200) */
|
||||
@ -553,8 +554,23 @@ static int imx_card_parse_of(struct imx_card_data *data)
|
||||
link_data->cpu_sysclk_id = FSL_SAI_CLK_MAST1;
|
||||
|
||||
/* sai may support mclk/bclk = 1 */
|
||||
if (of_find_property(np, "fsl,mclk-equal-bclk", NULL))
|
||||
if (of_find_property(np, "fsl,mclk-equal-bclk", NULL)) {
|
||||
link_data->one2one_ratio = true;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/*
|
||||
* i.MX8MQ don't support one2one ratio, then
|
||||
* with ak4497 only 16bit case is supported.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ak4497_fs_mul); i++) {
|
||||
if (ak4497_fs_mul[i].rmin == 705600 &&
|
||||
ak4497_fs_mul[i].rmax == 768000) {
|
||||
ak4497_fs_mul[i].wmin = 32;
|
||||
ak4497_fs_mul[i].wmax = 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
link->cpus->of_node = args.np;
|
||||
|
@ -40,6 +40,8 @@ enum {
|
||||
BYT_RT5640_NO_INTERNAL_MIC_MAP,
|
||||
};
|
||||
|
||||
#define RT5640_JD_SRC_EXT_GPIO 0x0f
|
||||
|
||||
enum {
|
||||
BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4),
|
||||
BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4),
|
||||
@ -47,6 +49,7 @@ enum {
|
||||
BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4),
|
||||
BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4),
|
||||
BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4),
|
||||
BYT_RT5640_JD_SRC_EXT_GPIO = (RT5640_JD_SRC_EXT_GPIO << 4)
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -79,6 +82,7 @@ enum {
|
||||
#define BYT_RT5640_LINEOUT_AS_HP2 BIT(26)
|
||||
#define BYT_RT5640_HSMIC2_ON_IN1 BIT(27)
|
||||
#define BYT_RT5640_JD_HP_ELITEP_1000G2 BIT(28)
|
||||
#define BYT_RT5640_USE_AMCR0F28 BIT(29)
|
||||
|
||||
#define BYTCR_INPUT_DEFAULTS \
|
||||
(BYT_RT5640_IN3_MAP | \
|
||||
@ -93,6 +97,7 @@ enum {
|
||||
struct byt_rt5640_private {
|
||||
struct snd_soc_jack jack;
|
||||
struct snd_soc_jack jack2;
|
||||
struct rt5640_set_jack_data jack_data;
|
||||
struct gpio_desc *hsmic_detect;
|
||||
struct clk *mclk;
|
||||
struct device *codec_dev;
|
||||
@ -597,7 +602,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
||||
BYT_RT5640_OVCD_TH_2000UA |
|
||||
BYT_RT5640_OVCD_SF_0P75 |
|
||||
BYT_RT5640_SSP0_AIF1 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_USE_AMCR0F28),
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
@ -624,6 +630,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
||||
BYT_RT5640_SSP0_AIF2 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
|
||||
BYT_RT5640_JD_SRC_EXT_GPIO |
|
||||
BYT_RT5640_OVCD_TH_2000UA |
|
||||
BYT_RT5640_OVCD_SF_0P75 |
|
||||
BYT_RT5640_SSP0_AIF1 |
|
||||
BYT_RT5640_MCLK_EN |
|
||||
BYT_RT5640_USE_AMCR0F28),
|
||||
},
|
||||
{ /* Chuwi Vi8 (CWI506) */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
@ -1080,9 +1099,11 @@ static int byt_rt5640_add_codec_device_props(struct device *i2c_dev,
|
||||
}
|
||||
|
||||
if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) {
|
||||
props[cnt++] = PROPERTY_ENTRY_U32(
|
||||
"realtek,jack-detect-source",
|
||||
BYT_RT5640_JDSRC(byt_rt5640_quirk));
|
||||
if (BYT_RT5640_JDSRC(byt_rt5640_quirk) != RT5640_JD_SRC_EXT_GPIO) {
|
||||
props[cnt++] = PROPERTY_ENTRY_U32(
|
||||
"realtek,jack-detect-source",
|
||||
BYT_RT5640_JDSRC(byt_rt5640_quirk));
|
||||
}
|
||||
|
||||
props[cnt++] = PROPERTY_ENTRY_U32(
|
||||
"realtek,over-current-threshold-microamp",
|
||||
@ -1109,6 +1130,51 @@ static int byt_rt5640_add_codec_device_props(struct device *i2c_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Some Android devs specify IRQs/GPIOS in a special AMCR0F28 ACPI device */
|
||||
static const struct acpi_gpio_params amcr0f28_jd_gpio = { 1, 0, false };
|
||||
|
||||
static const struct acpi_gpio_mapping amcr0f28_gpios[] = {
|
||||
{ "rt5640-jd-gpios", &amcr0f28_jd_gpio, 1 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int byt_rt5640_get_amcr0f28_settings(struct snd_soc_card *card)
|
||||
{
|
||||
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
|
||||
struct rt5640_set_jack_data *data = &priv->jack_data;
|
||||
struct acpi_device *adev;
|
||||
int ret = 0;
|
||||
|
||||
adev = acpi_dev_get_first_match_dev("AMCR0F28", "1", -1);
|
||||
if (!adev) {
|
||||
dev_err(card->dev, "error cannot find AMCR0F28 adev\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
data->codec_irq_override = acpi_dev_gpio_irq_get(adev, 0);
|
||||
if (data->codec_irq_override < 0) {
|
||||
ret = data->codec_irq_override;
|
||||
dev_err(card->dev, "error %d getting codec IRQ\n", ret);
|
||||
goto put_adev;
|
||||
}
|
||||
|
||||
if (BYT_RT5640_JDSRC(byt_rt5640_quirk) == RT5640_JD_SRC_EXT_GPIO) {
|
||||
acpi_dev_add_driver_gpios(adev, amcr0f28_gpios);
|
||||
data->jd_gpio = devm_fwnode_gpiod_get(card->dev, acpi_fwnode_handle(adev),
|
||||
"rt5640-jd", GPIOD_IN, "rt5640-jd");
|
||||
acpi_dev_remove_driver_gpios(adev);
|
||||
|
||||
if (IS_ERR(data->jd_gpio)) {
|
||||
ret = PTR_ERR(data->jd_gpio);
|
||||
dev_err(card->dev, "error %d getting jd GPIO\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
put_adev:
|
||||
acpi_dev_put(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
@ -1244,7 +1310,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
||||
}
|
||||
snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
|
||||
KEY_PLAYPAUSE);
|
||||
snd_soc_component_set_jack(component, &priv->jack, NULL);
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_USE_AMCR0F28) {
|
||||
ret = byt_rt5640_get_amcr0f28_settings(card);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_component_set_jack(component, &priv->jack, &priv->jack_data);
|
||||
}
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) {
|
||||
@ -1448,7 +1521,8 @@ static int byt_rt5640_resume(struct snd_soc_card *card)
|
||||
for_each_card_components(card, component) {
|
||||
if (!strcmp(component->name, byt_rt5640_codec_name)) {
|
||||
dev_dbg(component->dev, "re-enabling jack detect after resume\n");
|
||||
snd_soc_component_set_jack(component, &priv->jack, NULL);
|
||||
snd_soc_component_set_jack(component, &priv->jack,
|
||||
&priv->jack_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ struct soc_tplg {
|
||||
const struct firmware *fw;
|
||||
|
||||
/* runtime FW parsing */
|
||||
const u8 *pos; /* read postion */
|
||||
const u8 *pos; /* read position */
|
||||
const u8 *hdr_pos; /* header position */
|
||||
unsigned int pass; /* pass number */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user