aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/amd/vangogh
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/amd/vangogh')
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c31
-rw-r--r--sound/soc/amd/vangogh/acp5x-mach.c52
-rw-r--r--sound/soc/amd/vangogh/acp5x-pcm-dma.c78
-rw-r--r--sound/soc/amd/vangogh/acp5x.h31
-rw-r--r--sound/soc/amd/vangogh/pci-acp5x.c4
5 files changed, 117 insertions, 79 deletions
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index 002db3971ca9..773e96f1b4dd 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
}
mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
switch (mode) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
adata->master_mode = I2S_MASTER_MODE_ENABLE;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
adata->master_mode = I2S_MASTER_MODE_DISABLE;
break;
}
@@ -88,10 +88,9 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_soc_card *card;
struct acp5x_platform_info *pinfo;
struct i2s_dev_data *adata;
- union acp_i2stdm_mstrclkgen mclkgen;
u32 val;
- u32 reg_val, frmt_reg, master_reg;
+ u32 reg_val, frmt_reg;
u32 lrclk_div_val, bclk_div_val;
lrclk_div_val = 0;
@@ -160,20 +159,6 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
acp_writel(val, rtd->acp5x_base + reg_val);
if (adata->master_mode) {
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- master_reg = ACP_I2STDM2_MSTRCLKGEN;
- break;
- case I2S_SP_INSTANCE:
- default:
- master_reg = ACP_I2STDM0_MSTRCLKGEN;
- break;
- }
- mclkgen.bits.i2stdm_master_mode = 0x1;
- if (adata->tdm_mode)
- mclkgen.bits.i2stdm_format_mode = 0x01;
- else
- mclkgen.bits.i2stdm_format_mode = 0x0;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
switch (params_rate(params)) {
@@ -238,9 +223,8 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
default:
return -EINVAL;
}
- mclkgen.bits.i2stdm_bclk_div_val = bclk_div_val;
- mclkgen.bits.i2stdm_lrclk_div_val = lrclk_div_val;
- acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg);
+ rtd->lrclk_div = lrclk_div_val;
+ rtd->bclk_div = bclk_div_val;
}
return 0;
}
@@ -249,9 +233,11 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct i2s_stream_instance *rtd;
+ struct i2s_dev_data *adata;
u32 ret, val, period_bytes, reg_val, ier_val, water_val;
u32 buf_size, buf_reg;
+ adata = snd_soc_dai_get_drvdata(dai);
rtd = substream->runtime->private_data;
period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size);
@@ -300,6 +286,8 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
}
acp_writel(period_bytes, rtd->acp5x_base + water_val);
acp_writel(buf_size, rtd->acp5x_base + buf_reg);
+ if (adata->master_mode)
+ acp5x_set_i2s_clk(adata, rtd);
val = acp_readl(rtd->acp5x_base + reg_val);
val = val | BIT(0);
acp_writel(val, rtd->acp5x_base + reg_val);
@@ -357,6 +345,7 @@ static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
static const struct snd_soc_component_driver acp5x_dai_component = {
.name = "acp5x-i2s",
+ .legacy_dai_naming = 1,
};
static struct snd_soc_dai_driver acp5x_i2s_dai = {
diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c
index 14cf325e4b23..eebf2650ad27 100644
--- a/sound/soc/amd/vangogh/acp5x-mach.c
+++ b/sound/soc/amd/vangogh/acp5x-mach.c
@@ -17,10 +17,8 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
-#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
-#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
@@ -33,6 +31,8 @@
#define DUAL_CHANNEL 2
#define ACP5X_NUVOTON_CODEC_DAI "nau8821-hifi"
#define VG_JUPITER 1
+#define ACP5X_NUVOTON_BCLK 3072000
+#define ACP5X_NAU8821_FREQ_OUT 12288000
static unsigned long acp5x_machine_id;
static struct snd_soc_jack vg_headset;
@@ -59,10 +59,10 @@ static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
- &vg_headset, acp5x_nau8821_jack_pins,
- ARRAY_SIZE(acp5x_nau8821_jack_pins));
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &vg_headset, acp5x_nau8821_jack_pins,
+ ARRAY_SIZE(acp5x_nau8821_jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
@@ -98,10 +98,17 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
+static const unsigned int acp5x_nau8821_format[] = {32};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
+ .list = acp5x_nau8821_format,
+ .count = ARRAY_SIZE(acp5x_nau8821_format),
+};
+
static int acp5x_8821_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -113,13 +120,16 @@ static int acp5x_8821_startup(struct snd_pcm_substream *substream)
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ &constraints_sample_bits);
return 0;
}
static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai =
snd_soc_card_get_codec_dai(card,
@@ -141,7 +151,7 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -158,17 +168,17 @@ static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai;
int ret, i;
- unsigned int num_codecs = rtd->num_codecs;
+ unsigned int num_codecs = rtd->dai_link->num_codecs;
unsigned int bclk_val;
+ ret = 0;
for (i = 0; i < num_codecs; i++) {
codec_dai = asoc_rtd_to_codec(rtd, i);
- if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) ||
- (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) {
+ if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) {
switch (params_rate(params)) {
case 48000:
bclk_val = 1536000;
@@ -230,7 +240,7 @@ SND_SOC_DAILINK_DEF(platform,
static struct snd_soc_dai_link acp5x_dai[] = {
{
- .name = "acp5x-8825-play",
+ .name = "acp5x-8821-play",
.stream_name = "Playback/Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
@@ -274,6 +284,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
dev_err(card->dev, "set sysclk err = %d\n", ret);
return -EIO;
}
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set BLK clock %d\n", ret);
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, ACP5X_NUVOTON_BCLK,
+ ACP5X_NAU8821_FREQ_OUT);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
}
return ret;
}
@@ -289,7 +308,7 @@ static const struct snd_soc_dapm_widget acp5x_8821_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_POST_PMD),
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route acp5x_8821_audio_route[] = {
@@ -320,7 +339,6 @@ static struct snd_soc_card acp5x_card = {
.num_controls = ARRAY_SIZE(acp5x_8821_controls),
};
-
static int acp5x_vg_quirk_cb(const struct dmi_system_id *id)
{
acp5x_machine_id = VG_JUPITER;
@@ -350,7 +368,7 @@ static int acp5x_probe(struct platform_device *pdev)
return -ENOMEM;
dmi_check_system(acp5x_vg_quirk_table);
- switch(acp5x_machine_id) {
+ switch (acp5x_machine_id) {
case VG_JUPITER:
card = &acp5x_card;
acp5x_card.dev = &pdev->dev;
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index f10de38976cb..d36bb718370f 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -281,7 +281,7 @@ static int acp5x_dma_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
size = params_buffer_bytes(params);
- rtd->dma_addr = substream->dma_buffer.addr;
+ rtd->dma_addr = substream->runtime->dma_addr;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
config_acp5x_dma(rtd, substream->stream);
return 0;
@@ -388,13 +388,11 @@ static int acp5x_audio_probe(struct platform_device *pdev)
if (!adata->acp5x_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
+ status = platform_get_irq(pdev, 0);
+ if (status < 0)
+ return status;
+ adata->i2s_irq = status;
- adata->i2s_irq = res->start;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
&acp5x_i2s_component,
@@ -426,51 +424,51 @@ static int acp5x_audio_remove(struct platform_device *pdev)
static int __maybe_unused acp5x_pcm_resume(struct device *dev)
{
struct i2s_dev_data *adata;
- u32 val, reg_val, frmt_val;
+ struct i2s_stream_instance *rtd;
+ u32 val;
- reg_val = 0;
- frmt_val = 0;
adata = dev_get_drvdata(dev);
if (adata->play_stream && adata->play_stream->runtime) {
- struct i2s_stream_instance *rtd =
- adata->play_stream->runtime->private_data;
+ rtd = adata->play_stream->runtime->private_data;
config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- reg_val = ACP_HSTDM_ITER;
- frmt_val = ACP_HSTDM_TXFRMT;
- break;
- case I2S_SP_INSTANCE:
- default:
- reg_val = ACP_I2STDM_ITER;
- frmt_val = ACP_I2STDM_TXFRMT;
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_ITER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_TXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_HSTDM_ITER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_ITER);
+ }
+ }
+ if (adata->i2ssp_play_stream && adata->i2ssp_play_stream->runtime) {
+ rtd = adata->i2ssp_play_stream->runtime->private_data;
+ config_acp5x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_ITER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_TXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_I2STDM_ITER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_ITER);
}
- acp_writel((rtd->xfer_resolution << 3),
- rtd->acp5x_base + reg_val);
}
if (adata->capture_stream && adata->capture_stream->runtime) {
- struct i2s_stream_instance *rtd =
- adata->capture_stream->runtime->private_data;
+ rtd = adata->capture_stream->runtime->private_data;
config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
- switch (rtd->i2s_instance) {
- case I2S_HS_INSTANCE:
- reg_val = ACP_HSTDM_IRER;
- frmt_val = ACP_HSTDM_RXFRMT;
- break;
- case I2S_SP_INSTANCE:
- default:
- reg_val = ACP_I2STDM_IRER;
- frmt_val = ACP_I2STDM_RXFRMT;
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_HSTDM_IRER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_HSTDM_RXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_HSTDM_IRER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_HSTDM_IRER);
}
- acp_writel((rtd->xfer_resolution << 3),
- rtd->acp5x_base + reg_val);
}
- if (adata->tdm_mode == TDM_ENABLE) {
- acp_writel(adata->tdm_fmt, adata->acp5x_base + frmt_val);
- val = acp_readl(adata->acp5x_base + reg_val);
- acp_writel(val | 0x2, adata->acp5x_base + reg_val);
+ if (adata->i2ssp_capture_stream && adata->i2ssp_capture_stream->runtime) {
+ rtd = adata->i2ssp_capture_stream->runtime->private_data;
+ config_acp5x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+ acp_writel((rtd->xfer_resolution << 3), rtd->acp5x_base + ACP_I2STDM_IRER);
+ if (adata->tdm_mode == TDM_ENABLE) {
+ acp_writel(adata->tdm_fmt, adata->acp5x_base + ACP_I2STDM_RXFRMT);
+ val = acp_readl(adata->acp5x_base + ACP_I2STDM_IRER);
+ acp_writel(val | 0x2, adata->acp5x_base + ACP_I2STDM_IRER);
+ }
}
acp_writel(1, adata->acp5x_base + ACP_EXTERNAL_INTR_ENB);
return 0;
diff --git a/sound/soc/amd/vangogh/acp5x.h b/sound/soc/amd/vangogh/acp5x.h
index fe5e1fa98974..bd9f1c5684d1 100644
--- a/sound/soc/amd/vangogh/acp5x.h
+++ b/sound/soc/amd/vangogh/acp5x.h
@@ -85,7 +85,7 @@
struct i2s_dev_data {
bool tdm_mode;
bool master_mode;
- unsigned int i2s_irq;
+ int i2s_irq;
u16 i2s_instance;
u32 tdm_fmt;
void __iomem *acp5x_base;
@@ -105,6 +105,8 @@ struct i2s_stream_instance {
dma_addr_t dma_addr;
u64 bytescount;
void __iomem *acp5x_base;
+ u32 lrclk_div;
+ u32 bclk_div;
};
union acp_dma_count {
@@ -191,3 +193,30 @@ static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd,
}
return byte_count.bytescount;
}
+
+static inline void acp5x_set_i2s_clk(struct i2s_dev_data *adata,
+ struct i2s_stream_instance *rtd)
+{
+ union acp_i2stdm_mstrclkgen mclkgen;
+ u32 master_reg;
+
+ switch (rtd->i2s_instance) {
+ case I2S_HS_INSTANCE:
+ master_reg = ACP_I2STDM2_MSTRCLKGEN;
+ break;
+ case I2S_SP_INSTANCE:
+ default:
+ master_reg = ACP_I2STDM0_MSTRCLKGEN;
+ break;
+ }
+
+ mclkgen.bits.i2stdm_master_mode = 0x1;
+ if (adata->tdm_mode)
+ mclkgen.bits.i2stdm_format_mode = 0x01;
+ else
+ mclkgen.bits.i2stdm_format_mode = 0x00;
+
+ mclkgen.bits.i2stdm_bclk_div_val = rtd->bclk_div;
+ mclkgen.bits.i2stdm_lrclk_div_val = rtd->lrclk_div;
+ acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg);
+}
diff --git a/sound/soc/amd/vangogh/pci-acp5x.c b/sound/soc/amd/vangogh/pci-acp5x.c
index 2b6b9edc36e2..e0df17c88e8e 100644
--- a/sound/soc/amd/vangogh/pci-acp5x.c
+++ b/sound/soc/amd/vangogh/pci-acp5x.c
@@ -92,12 +92,14 @@ static int acp5x_init(void __iomem *acp5x_base)
pr_err("ACP5x power on failed\n");
return ret;
}
+ acp_writel(0x01, acp5x_base + ACP_CONTROL);
/* Reset */
ret = acp5x_reset(acp5x_base);
if (ret) {
pr_err("ACP5x reset failed\n");
return ret;
}
+ acp_writel(0x03, acp5x_base + ACP_CLKMUX_SEL);
acp5x_enable_interrupts(acp5x_base);
return 0;
}
@@ -113,6 +115,8 @@ static int acp5x_deinit(void __iomem *acp5x_base)
pr_err("ACP5x reset failed\n");
return ret;
}
+ acp_writel(0x00, acp5x_base + ACP_CLKMUX_SEL);
+ acp_writel(0x00, acp5x_base + ACP_CONTROL);
return 0;
}