Commit b3c4014c authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-fix-v5.0-rc2' of...

Merge tag 'asoc-fix-v5.0-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v5.0

Quite a big batch of fixes here.  There's a couple of things going on,
the main one is that we found some issues with not deferring probe when
we should, causing us to skip some driver initialization.  The fixes for
this then in turn exposed some issues with how we were searching for
components which had previously gone unnoticed due to the original
issue.

There's also been the normal driver specific stuff and there's been what
looks like several batches of automated scanning for issues which have
generated quite a large set of smaller fixes for potential crashes and
missed error handling.
parents 687ae9e2 4cb79ef9
......@@ -985,6 +985,12 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;
/*
* This driver uses legacy platform naming. Set by the core, machine
* drivers should not modify this value.
*/
unsigned int legacy_platform:1;
struct list_head list; /* DAI link list of the soc card */
struct snd_soc_dobj dobj; /* For topology */
};
......
......@@ -541,7 +541,8 @@ static int snd_compress_check_input(struct snd_compr_params *params)
{
/* first let's check the buffer parameter's */
if (params->buffer.fragment_size == 0 ||
params->buffer.fragments > INT_MAX / params->buffer.fragment_size)
params->buffer.fragments > INT_MAX / params->buffer.fragment_size ||
params->buffer.fragments == 0)
return -EINVAL;
/* now codec parameters */
......
......@@ -611,14 +611,16 @@ static int acp3x_audio_probe(struct platform_device *pdev)
}
irqflags = *((unsigned int *)(pdev->dev.platform_data));
adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
return -ENODEV;
}
adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
if (!adata)
return -ENOMEM;
adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
......
......@@ -1400,24 +1400,20 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
if (ret != 0) {
dev_err(component->dev,
"Failed to set digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
goto unlock;
}
regmap_read_poll_timeout(pcm512x->regmap,
PCM512x_ANALOG_MUTE_DET,
mute_det, (mute_det & 0x3) == 0,
200, 10000);
mutex_unlock(&pcm512x->mutex);
} else {
pcm512x->mute &= ~0x1;
ret = pcm512x_update_mute(pcm512x);
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
goto unlock;
}
regmap_read_poll_timeout(pcm512x->regmap,
......@@ -1428,9 +1424,10 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
200, 10000);
}
unlock:
mutex_unlock(&pcm512x->mutex);
return 0;
return ret;
}
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
......
......@@ -1128,8 +1128,11 @@ static int rt274_i2c_probe(struct i2c_client *i2c,
return ret;
}
regmap_read(rt274->regmap,
ret = regmap_read(rt274->regmap,
RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
if (ret)
return ret;
if (val != RT274_VENDOR_ID) {
dev_err(&i2c->dev,
"Device with ID register %#x is not rt274\n", val);
......
......@@ -280,6 +280,8 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),
GFP_KERNEL);
if (!rt5514_dsp)
return -ENOMEM;
rt5514_dsp->dev = &rt5514_spi->dev;
mutex_init(&rt5514_dsp->dma_lock);
......
......@@ -2512,6 +2512,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000);
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
mutex_unlock(&rt5682->calibrate_mutex);
......
......@@ -849,18 +849,18 @@
#define RT5682_SCLK_SRC_PLL2 (0x2 << 13)
#define RT5682_SCLK_SRC_SDW (0x3 << 13)
#define RT5682_SCLK_SRC_RCCLK (0x4 << 13)
#define RT5682_PLL1_SRC_MASK (0x3 << 10)
#define RT5682_PLL1_SRC_SFT 10
#define RT5682_PLL1_SRC_MCLK (0x0 << 10)
#define RT5682_PLL1_SRC_BCLK1 (0x1 << 10)
#define RT5682_PLL1_SRC_SDW (0x2 << 10)
#define RT5682_PLL1_SRC_RC (0x3 << 10)
#define RT5682_PLL2_SRC_MASK (0x3 << 8)
#define RT5682_PLL2_SRC_SFT 8
#define RT5682_PLL2_SRC_MCLK (0x0 << 8)
#define RT5682_PLL2_SRC_BCLK1 (0x1 << 8)
#define RT5682_PLL2_SRC_SDW (0x2 << 8)
#define RT5682_PLL2_SRC_RC (0x3 << 8)
#define RT5682_PLL2_SRC_MASK (0x3 << 10)
#define RT5682_PLL2_SRC_SFT 10
#define RT5682_PLL2_SRC_MCLK (0x0 << 10)
#define RT5682_PLL2_SRC_BCLK1 (0x1 << 10)
#define RT5682_PLL2_SRC_SDW (0x2 << 10)
#define RT5682_PLL2_SRC_RC (0x3 << 10)
#define RT5682_PLL1_SRC_MASK (0x3 << 8)
#define RT5682_PLL1_SRC_SFT 8
#define RT5682_PLL1_SRC_MCLK (0x0 << 8)
#define RT5682_PLL1_SRC_BCLK1 (0x1 << 8)
#define RT5682_PLL1_SRC_SDW (0x2 << 8)
#define RT5682_PLL1_SRC_RC (0x3 << 8)
......
......@@ -822,6 +822,10 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* Initial cold start */
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
break;
/* Switch off BCLK_N Divider */
snd_soc_component_update_bits(component, AIC32X4_BCLKN,
AIC32X4_BCLKEN, 0);
......
......@@ -86,49 +86,49 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
if (!buf)
return -ENOMEM;
ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
pdcr, ptcr);
if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"TxFS output from %s, ",
audmux_port_string((ptcr >> 27) & 0x7));
else
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"TxFS input, ");
if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"TxClk output from %s",
audmux_port_string((ptcr >> 22) & 0x7));
else
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"TxClk input");
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) {
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"Port is symmetric");
} else {
if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"RxFS output from %s, ",
audmux_port_string((ptcr >> 17) & 0x7));
else
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"RxFS input, ");
if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"RxClk output from %s",
audmux_port_string((ptcr >> 12) & 0x7));
else
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"RxClk input");
}
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"\nData received from %s\n",
audmux_port_string((pdcr >> 13) & 0x7));
......
......@@ -91,7 +91,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI
config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms"
default ACPI
depends on X86 && ACPI
depends on X86 && ACPI && PCI
select SND_SST_IPC_ACPI
select SND_SST_ATOM_HIFI2_PLATFORM
select SND_SOC_ACPI_INTEL_MATCH
......
......@@ -399,7 +399,13 @@ static int sst_media_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
int ret;
ret =
snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(params));
if (ret)
return ret;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
return 0;
}
......
......@@ -192,7 +192,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
.stream_name = "Loopback",
.cpu_dai_name = "Loopback Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 0,
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
......
......@@ -55,39 +55,6 @@ enum {
GLK_DPCM_AUDIO_HDMI3_PB,
};
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct snd_soc_dai *codec_dai;
int ret = 0;
codec_dai = snd_soc_card_get_codec_dai(card, GLK_REALTEK_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
return -EIO;
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
if (ret)
dev_err(card->dev, "failed to stop sysclk: %d\n", ret);
} else if (SND_SOC_DAPM_EVENT_ON(event)) {
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
if (ret < 0) {
dev_err(card->dev, "can't set codec pll: %d\n", ret);
return ret;
}
}
if (ret)
dev_err(card->dev, "failed to start internal clk: %d\n", ret);
return ret;
}
static const struct snd_kcontrol_new geminilake_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
......@@ -102,14 +69,10 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = {
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
SND_SOC_DAPM_SPK("HDMI3", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route geminilake_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
......@@ -117,7 +80,6 @@ static const struct snd_soc_dapm_route geminilake_map[] = {
{ "Spk", NULL, "Speaker" },
/* other jacks */
{ "Headset Mic", NULL, "Platform Clock" },
{ "IN1P", NULL, "Headset Mic" },
/* digital mics */
......@@ -177,6 +139,13 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_jack *jack;
int ret;
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
}
/* Configure sysclk for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
......
......@@ -146,7 +146,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
.stream_name = "Loopback",
.cpu_dai_name = "Loopback Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 0,
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
......
......@@ -570,10 +570,10 @@ static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
prtd->audio_client = q6asm_audio_client_alloc(dev,
(q6asm_cb)compress_event_handler,
prtd, stream_id, LEGACY_PCM_MODE);
if (!prtd->audio_client) {
if (IS_ERR(prtd->audio_client)) {
dev_err(dev, "Could not allocate memory\n");
kfree(prtd);
return -ENOMEM;
ret = PTR_ERR(prtd->audio_client);
goto free_prtd;
}
size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
......@@ -582,7 +582,7 @@ static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
&prtd->dma_buffer);
if (ret) {
dev_err(dev, "Cannot allocate buffer(s)\n");
return ret;
goto free_client;
}
if (pdata->sid < 0)
......@@ -595,6 +595,13 @@ static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
runtime->private_data = prtd;
return 0;
free_client:
q6asm_audio_client_free(prtd->audio_client);
free_prtd:
kfree(prtd);
return ret;
}
static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
......@@ -874,7 +881,7 @@ static int of_q6asm_parse_dai_data(struct device *dev,
for_each_child_of_node(dev->of_node, node) {
ret = of_property_read_u32(node, "reg", &id);
if (ret || id > MAX_SESSIONS || id < 0) {
if (ret || id >= MAX_SESSIONS || id < 0) {
dev_err(dev, "valid dai id not found:%d\n", ret);
continue;
}
......
......@@ -158,17 +158,24 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
return ret;
}
static void sdm845_jack_free(struct snd_jack *jack)
{
struct snd_soc_component *component = jack->private_data;
snd_soc_component_set_jack(component, NULL, NULL);
}
static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component;
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
int i, rval;
struct snd_jack *jack;
int rval;
if (!pdata->jack_setup) {
struct snd_jack *jack;
rval = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET |
SND_JACK_HEADPHONE |
......@@ -190,16 +197,22 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
pdata->jack_setup = true;
}
for (i = 0 ; i < dai_link->num_codecs; i++) {
struct snd_soc_dai *dai = rtd->codec_dais[i];
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
jack = pdata->jack.jack;
component = codec_dai->component;
component = dai->component;
rval = snd_soc_component_set_jack(
component, &pdata->jack, NULL);
jack->private_data = component;
jack->private_free = sdm845_jack_free;
rval = snd_soc_component_set_jack(component,
&pdata->jack, NULL);
if (rval != 0 && rval != -ENOTSUPP) {
dev_warn(card->dev, "Failed to set jack: %d\n", rval);
return rval;
}
break;
default:
break;
}
return 0;
......
......@@ -202,7 +202,7 @@ static int camelot_prepare(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
pr_debug("PCM data: addr 0x%08ulx len %d\n",
pr_debug("PCM data: addr 0x%08lx len %d\n",
(u32)runtime->dma_addr, runtime->dma_bytes);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
......
......@@ -742,7 +742,7 @@ static struct snd_soc_component *soc_find_component(
if (of_node) {
if (component->dev->of_node == of_node)
return component;
} else if (strcmp(component->name, name) == 0) {
} else if (name && strcmp(component->name, name) == 0) {
return component;
}
}
......@@ -1034,17 +1034,18 @@ static int snd_soc_init_platform(struct snd_soc_card *card,
* this function should be removed in the future
*/
/* convert Legacy platform link */
if (!platform) {
if (!platform || dai_link->legacy_platform) {
platform = devm_kzalloc(card->dev,
sizeof(struct snd_soc_dai_link_component),
GFP_KERNEL);
if (!platform)
return -ENOMEM;
dai_link->platform = platform;
platform->name = dai_link->platform_name;
platform->of_node = dai_link->platform_of_node;
platform->dai_name = NULL;
dai_link->platform = platform;
dai_link->legacy_platform = 1;
platform->name = dai_link->platform_name;
platform->of_node = dai_link->platform_of_node;
platform->dai_name = NULL;
}
/* if there's no platform we match on the empty platform */
......@@ -1129,6 +1130,15 @@ static int soc_init_dai_link(struct snd_soc_card *card,
link->name);
return -EINVAL;
}
/*
* Defer card registartion if platform dai component is not added to
* component list.
*/
if ((link->platform->of_node || link->platform->name) &&
!soc_find_component(link->platform->of_node, link->platform->name))
return -EPROBE_DEFER;
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
......@@ -1140,6 +1150,15 @@ static int soc_init_dai_link(struct snd_soc_card *card,
link->name);
return -EINVAL;
}
/*
* Defer card registartion if cpu dai component is not added to
* component list.
*/
if ((link->cpu_of_node || link->cpu_name) &&
!soc_find_component(link->cpu_of_node, link->cpu_name))
return -EPROBE_DEFER;
/*
* At least one of CPU DAI name or CPU device name/node must be
* specified
......@@ -2739,15 +2758,18 @@ int snd_soc_register_card(struct snd_soc_card *card)
if (!card->name || !card->dev)
return -EINVAL;
mutex_lock(&client_mutex);
for_each_card_prelinks(card, i, link) {
ret = soc_init_dai_link(card, link);
if (ret) {
dev_err(card->dev, "ASoC: failed to init link %s\n",
link->name);
mutex_unlock(&client_mutex);
return ret;
}
}
mutex_unlock(&client_mutex);
dev_set_drvdata(card->dev, card);
......
......@@ -2019,19 +2019,19 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
out = is_connected_output_ep(w, NULL, NULL);
}
ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
ret = scnprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
w->name, w->power ? "On" : "Off",
w->force ? " (forced)" : "", in, out);
if (w->reg >= 0)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
" - R%d(0x%x) mask 0x%x",
w->reg, w->reg, w->mask << w->shift);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
if (w->sname)
ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
ret += scnprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
w->sname,
w->active ? "active" : "inactive");
......@@ -2044,7 +2044,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (!p->connect)
continue;
ret += snprintf(buf + ret, PAGE_SIZE - ret,
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
" %s \"%s\" \"%s\"\n",
(rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
p->name ? p->name : "static",
......
......@@ -108,7 +108,7 @@ struct davinci_mcasp {
/* Used for comstraint setting on the second stream */
u32 channels;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM
struct davinci_mcasp_context context;
#endif
......@@ -1486,74 +1486,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
u32 reg;
int i;
context->pm_state = pm_runtime_active(mcasp->dev);
if (!context->pm_state)
pm_runtime_get_sync(mcasp->dev);
for (i = 0; i < ARRAY_SIZE(context_regs); i++)
context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
if (mcasp->txnumevt) {
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
}
if (mcasp->rxnumevt) {
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
}
for (i = 0; i < mcasp->num_serializer; i++)
context->xrsr_regs[i] = mcasp_get_reg(mcasp,
DAVINCI_MCASP_XRSRCTL_REG(i));
pm_runtime_put_sync(mcasp->dev);
return 0;
}
static int davinci_mcasp_resume(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
u32 reg;
int i;
pm_runtime_get_sync(mcasp->dev);
for (i = 0; i < ARRAY_SIZE(context_regs); i++)
mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
if (mcasp->txnumevt) {
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
}
if (mcasp->rxnumevt) {
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
}
for (i = 0; i < mcasp->num_serializer; i++)
mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
context->xrsr_regs[i]);
if (!context->pm_state)
pm_runtime_put_sync(mcasp->dev);
return 0;
}
#else
#define davinci_mcasp_suspend NULL
#define davinci_mcasp_resume NULL
#endif
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
......@@ -1571,8 +1503,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
.probe = davinci_mcasp_dai_probe,
.suspend = davinci_mcasp_suspend,
.resume = davinci_mcasp_resume,
.playback = {
.channels_min = 1,
.channels_max = 32 * 16,
......@@ -1976,7 +1906,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
}
mcasp->num_serializer = pdata->num_serializer;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
mcasp->num_serializer, sizeof(u32),
GFP_KERNEL);
......@@ -2196,11 +2126,73 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int davinci_mcasp_runtime_suspend(struct device *dev)
{
struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
struct davinci_mcasp_context *context = &mcasp->context;
u32 reg;
int i;
for (i = 0; i < ARRAY_SIZE(context_regs); i++)
context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
if (mcasp->txnumevt) {
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
}
if (mcasp->rxnumevt) {
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
}
for (i = 0; i < mcasp->num_serializer; i++)
context->xrsr_regs[i] = mcasp_get_reg(mcasp,
DAVINCI_MCASP_XRSRCTL_REG(i));
return 0;
}
static int davinci_mcasp_runtime_resume(struct device *dev)
{
struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
struct davinci_mcasp_context *context = &mcasp->context;
u32 reg;
int i;
for (i = 0; i < ARRAY_SIZE(context_regs); i++)
mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
if (mcasp->txnumevt) {
reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
}
if (mcasp->rxnumevt) {
reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
}
for (i = 0; i < mcasp->num_serializer; i++)
mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
context->xrsr_regs[i]);
return 0;
}
#endif
static const struct dev_pm_ops davinci_mcasp_pm_ops = {
SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
davinci_mcasp_runtime_resume,
NULL)
};
static struct platform_driver davinci_mcasp_driver = {
.probe = davinci_mcasp_probe,
.remove = davinci_mcasp_remove,
.driver = {
.name = "davinci-mcasp",
.pm = &davinci_mcasp_pm_ops,
.of_match_table = mcasp_dt_ids,
},
};
......
config SND_SOC_XILINX_I2S
tristate "Audio support for the the Xilinx I2S"
tristate "Audio support for the Xilinx I2S"
help
Select this option to enable Xilinx I2S Audio. This enables
I2S playback and capture using xilinx soft IP. In transmitter
......
// SPDX-License-Identifier: GPL-2.0
/*
* Xilinx ASoC I2S audio support
*
* Copyright (C) 2018 Xilinx, Inc.
*
* Author: Praveen Vuppala <praveenv@xilinx.com>
* Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
*/
//
// Xilinx ASoC I2S audio support
//
// Copyright (C) 2018 Xilinx, Inc.
//
// Author: Praveen Vuppala <praveenv@xilinx.com>
// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
#include <linux/io.h>
#include <linux/module.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment