ASoC: cs35l41: Implement support for dynamic DMA

Implement support for dynamically allocating DMA buffer
in CSPL firmware for firmware.

SQA-1029

Mot-CRs-fixed: (CR): River: AoU bringup on Marley+Prince
Change-Id: I0ff90e85e96ff5029e276f00e82f0503913fb9f1
Signed-off-by: Li Xu <li.xu@cirrus.com>
Reviewed-on: https://gerrit.mot.com/1238847
Tested-by: Jira Key
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Reviewed-by: Konstantin Makariev <kmakariev@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Li Xu 2018-06-15 13:32:44 -05:00 • committed by Patrick Gries
commit 5ec000c5dc
3 changed files with 166 additions and 82 deletions

View file

@ -61,6 +61,7 @@ struct cs35l41_private {
int extclk_freq;
int extclk_cfg;
int sclk;
unsigned int cspl_cmd;
bool tdm_mode;
bool i2s_mode;
bool swire_mode;

View file

@ -216,6 +216,143 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp,
CS35L41_AMP_DIG_VOL_CTRL, 0,
cs35l41_pcm_sftramp_text);
static const char * const cs35l41_cspl_cmd_text[] = {
"CSPL_MBOX_CMD_RESUME",
"CSPL_MBOX_CMD_REINIT",
"CSPL_MBOX_CMD_STOP_PRE_REINIT",
};
static const unsigned int cs35l41_cspl_cmd_val[] = {
(unsigned int)CSPL_MBOX_CMD_RESUME,
(unsigned int)CSPL_MBOX_CMD_REINIT,
(unsigned int)CSPL_MBOX_CMD_STOP_PRE_REINIT,
};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_cspl_cmd, SND_SOC_NOPM, 0, 0,
cs35l41_cspl_cmd_text, cs35l41_cspl_cmd_val);
static bool cs35l41_is_csplmboxsts_correct(enum cs35l41_cspl_mboxcmd cmd,
enum cs35l41_cspl_mboxstate sts)
{
switch (cmd) {
case CSPL_MBOX_CMD_NONE:
case CSPL_MBOX_CMD_UNKNOWN_CMD:
return true;
case CSPL_MBOX_CMD_PAUSE:
return (sts == CSPL_MBOX_STS_PAUSED);
case CSPL_MBOX_CMD_RESUME:
return (sts == CSPL_MBOX_STS_RUNNING);
case CSPL_MBOX_CMD_REINIT:
return (sts == CSPL_MBOX_STS_RUNNING);
case CSPL_MBOX_CMD_STOP_PRE_REINIT:
return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
default:
return false;
}
}
static int cs35l41_set_csplmboxcmd(struct cs35l41_private *cs35l41,
enum cs35l41_cspl_mboxcmd cmd)
{
int ret;
unsigned int sts;
/* Reset DSP sticky bit */
regmap_write(cs35l41->regmap, CS35L41_IRQ2_STATUS2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
/* Reset AP sticky bit */
regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
/*
* Set mailbox cmd
*/
reinit_completion(&cs35l41->mbox_cmd);
/* Unmask DSP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, 0);
/* Unmask AP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, 0);
regmap_write(cs35l41->regmap, CS35L41_CSPL_MBOX_CMD_DRV, cmd);
ret = wait_for_completion_timeout(&cs35l41->mbox_cmd,
usecs_to_jiffies(CS35L41_MBOXWAIT));
if (ret == 0) {
dev_err(cs35l41->dev,
"Timout waiting for DSP to set mbox cmd\n");
ret = -ETIMEDOUT;
}
/* Mask AP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
/* Mask DSP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
if (regmap_read(cs35l41->regmap,
CS35L41_CSPL_MBOX_STS, &sts) < 0) {
dev_err(cs35l41->dev, "Failed to read %u\n",
CS35L41_CSPL_MBOX_STS);
ret = -EACCES;
}
if (!cs35l41_is_csplmboxsts_correct(cmd,
(enum cs35l41_cspl_mboxstate)sts)) {
dev_err(cs35l41->dev,
"Failed to set mailbox(cmd: %u, sts: %u)\n", cmd, sts);
ret = -ENOMSG;
}
return ret;
}
static int cs35l41_cspl_cmd_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec);
struct soc_enum *soc_enum;
unsigned int i = ucontrol->value.enumerated.item[0];
int ret = 0;
soc_enum = (struct soc_enum *)kcontrol->private_value;
cs35l41->cspl_cmd = soc_enum->values[i];
return ret;
}
static int cs35l41_cspl_cmd_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec);
struct soc_enum *soc_enum;
unsigned int i;
int ret = 0;
soc_enum = (struct soc_enum *)kcontrol->private_value;
for (i = 0; i < soc_enum->items; i++) {
if (cs35l41->cspl_cmd == soc_enum->values[i])
break;
}
if (i >= soc_enum->items) {
/* Cannot find value */
dev_err(cs35l41->dev, "Cannot find cspl cmd\n");
i = 0;
ret = -EINVAL;
}
ucontrol->value.enumerated.item[0] = i;
return ret;
}
static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"};
static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum,
@ -326,6 +463,8 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
SOC_SINGLE_RANGE("ASPTX4 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 24,
0, 7, 0),
SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp),
SOC_VALUE_ENUM_EXT("CSPL Command", cs35l41_cspl_cmd,
cs35l41_cspl_cmd_get, cs35l41_cspl_cmd_put),
SOC_SINGLE_EXT("DSP Booted", SND_SOC_NOPM, 0, 1, 0,
cs35l41_halo_booted_get, cs35l41_halo_booted_put),
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
@ -618,80 +757,6 @@ static const struct reg_sequence cs35l41_pdn_patch[] = {
{0x00000040, 0x00000033},
};
static bool cs35l41_is_csplmboxsts_correct(enum cspl_mboxcmd cmd,
enum cspl_mboxstate sts)
{
switch (cmd) {
case CSPL_MBOX_CMD_NONE:
case CSPL_MBOX_CMD_UNKNOWN_CMD:
return true;
case CSPL_MBOX_CMD_PAUSE:
return (sts == CSPL_MBOX_STS_PAUSED);
case CSPL_MBOX_CMD_RESUME:
return (sts == CSPL_MBOX_STS_RUNNING);
default:
return false;
}
}
static int cs35l41_set_csplmboxcmd(struct cs35l41_private *cs35l41,
enum cspl_mboxcmd cmd)
{
int ret;
unsigned int sts;
/* Reset DSP sticky bit */
regmap_write(cs35l41->regmap, CS35L41_IRQ2_STATUS2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
/* Reset AP sticky bit */
regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
/*
* Set mailbox cmd
*/
reinit_completion(&cs35l41->mbox_cmd);
/* Unmask DSP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, 0);
/* Unmask AP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, 0);
regmap_write(cs35l41->regmap, CS35L41_CSPL_MBOX_CMD_DRV, cmd);
ret = wait_for_completion_timeout(&cs35l41->mbox_cmd,
usecs_to_jiffies(CS35L41_MBOXWAIT));
if (ret == 0) {
dev_err(cs35l41->dev,
"Timout waiting for DSP to set mbox cmd\n");
ret = -ETIMEDOUT;
}
/* Mask AP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT,
1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
/* Mask DSP INT */
regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT,
1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
if (regmap_read(cs35l41->regmap,
CS35L41_CSPL_MBOX_STS, &sts) < 0) {
dev_err(cs35l41->dev, "Failed to read %u\n",
CS35L41_CSPL_MBOX_STS);
ret = -EACCES;
}
if (!cs35l41_is_csplmboxsts_correct(cmd, (enum cspl_mboxstate)sts)) {
dev_err(cs35l41->dev,
"Failed to set mailbox(cmd: %u, sts: %u)\n", cmd, sts);
ret = -ENOMSG;
}
return ret;
}
static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@ -711,14 +776,25 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
usleep_range(1000, 1100);
if (cs35l41->halo_booted)
ret = cs35l41_set_csplmboxcmd(cs35l41,
CSPL_MBOX_CMD_RESUME);
if (cs35l41->halo_booted) {
if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT)
/* Send this command on power down event */
ret = cs35l41_set_csplmboxcmd(cs35l41,
CSPL_MBOX_CMD_RESUME);
else
ret = cs35l41_set_csplmboxcmd(cs35l41,
cs35l41->cspl_cmd);
}
break;
case SND_SOC_DAPM_POST_PMD:
if (cs35l41->halo_booted)
ret = cs35l41_set_csplmboxcmd(cs35l41,
CSPL_MBOX_CMD_PAUSE);
if (cs35l41->halo_booted) {
if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT)
ret = cs35l41_set_csplmboxcmd(cs35l41,
cs35l41->cspl_cmd);
else
ret = cs35l41_set_csplmboxcmd(cs35l41,
CSPL_MBOX_CMD_PAUSE);
}
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
CS35L41_GLOBAL_EN_MASK, 0);
@ -1669,6 +1745,9 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
int timeout = 100;
int irq_pol = 0;
/* Default to RESUME cmd */
cs35l41->cspl_cmd = (unsigned int)CSPL_MBOX_CMD_RESUME;
for (i = 0; i < ARRAY_SIZE(cs35l41_supplies); i++)
cs35l41->supplies[i].supply = cs35l41_supplies[i];

View file

@ -741,16 +741,20 @@ extern const struct cs35l41_otp_map_element_t
#define CS35L41_CSPL_MBOX_CMD_DRV CS35L41_DSP_VIRT1_MBOX_1
#define CS35L41_CSPL_MBOX_CMD_DRV_SHIFT CS35L41_DSP_VIRT1_MBOX_SHIFT
enum cspl_mboxstate {
enum cs35l41_cspl_mboxstate {
CSPL_MBOX_STS_RUNNING = 0,
CSPL_MBOX_STS_PAUSED = 1,
CSPL_MBOX_STS_RDY_FOR_REINIT = 2,
};
enum cspl_mboxcmd {
enum cs35l41_cspl_mboxcmd {
CSPL_MBOX_CMD_NONE = 0,
CSPL_MBOX_CMD_PAUSE = 1,
CSPL_MBOX_CMD_RESUME = 2,
CSPL_MBOX_CMD_REINIT = 3,
CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
};
#endif /*__CS35L41_H__*/