"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
"pcm_mclk",
"pcm_sclk";
pcm_mode = <1>; /* 0=slave mode, 1=master mode */
+ dai-format = "dsp_a";
+ dai-tdm-slot-tx-mask = <1>;
+ dai-tdm-slot-rx-mask = <1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <16>;
};
i2s_plat: i2s_platform {
compatible = "amlogic, aml-i2s";
/* counter for pcm clk used */
static int aml_pcm_clk_count;
-static unsigned int aml_pcm_format = SND_SOC_DAIFMT_DSP_B;
-
-void aml_set_pcm_format(int pcm_mode)
-{
- pr_info(" %s, pcm format:0x%x\n", __func__, pcm_mode);
-
- aml_pcm_format = pcm_mode;
-}
-
static uint32_t aml_audin_read_bits(uint32_t reg, const uint32_t start,
const uint32_t len)
{
aml_audin_read(PCMIN_CTRL1));
}
-void pcm_master_in_enable(struct snd_pcm_substream *substream, int flag)
+void pcm_master_in_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable)
{
unsigned int fs_offset;
+ unsigned int slots = cfg.slots;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A)
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A)
fs_offset = 1;
else {
fs_offset = 0;
- if (aml_pcm_format != SND_SOC_DAIFMT_DSP_B)
+ if (cfg.fmt != SND_SOC_DAIFMT_DSP_B)
pr_err("Unsupport DSP mode\n");
}
/* disable pcmin */
aml_audin_update_bits(PCMIN_CTRL0, 1 << 31, 0 << 31);
- if (flag) {
+ if (enable) {
unsigned int pcm_mode = 1, pcm_wlen = 16;
unsigned int num_slot = substream->runtime->channels;
unsigned int valid_slot = valid_channel[num_slot - 1];
unsigned int max_bits;
unsigned int valid_bits;
+ /* if no slots is set, use the channel num */
+ if (slots == 0)
+ slots = num_slot;
+
/* whatever pcm out is enable */
aml_pcm_clk_count++;
unsigned int bit_offset_s = 0, slot_offset_s = 0,
bit_offset_e = 0, slot_offset_e = 0;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = pcm_wlen - 1;
- slot_offset_s = num_slot - 1;
+ slot_offset_s = slots - 1;
bit_offset_e = 0;
slot_offset_e = 0;
- } else if (aml_pcm_format == SND_SOC_DAIFMT_DSP_B) {
+ } else if (cfg.fmt == SND_SOC_DAIFMT_DSP_B) {
bit_offset_s = 0;
slot_offset_s = 0;
bit_offset_e = 1;
/* underrun use mute constant */
(0 << 29) |
/* pcmo max slot number in one frame*/
- ((num_slot - 1) << 22) |
+ ((slots - 1) << 22) |
/* pcmo max bit number in one slot*/
(valid_bits << 16) |
(valid_slot << 0)
}
}
- pr_debug("PCMIN %s\n", flag ? "enable" : "disable");
+ pr_debug("PCMIN %s\n", enable ? "enable" : "disable");
pcm_in_register_show();
}
-void pcm_in_enable(struct snd_pcm_substream *substream, int flag)
+void pcm_in_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable)
{
unsigned int fs_offset;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A)
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A)
fs_offset = 1;
else {
fs_offset = 0;
- if (aml_pcm_format != SND_SOC_DAIFMT_DSP_B)
+ if (cfg.fmt != SND_SOC_DAIFMT_DSP_B)
pr_err("Unsupport DSP mode\n");
}
/* reset fifo */
/* disable pcmin */
aml_audin_update_bits(PCMIN_CTRL0, 1 << 31, 0 << 31);
- if (flag) {
+ if (enable) {
unsigned int pcm_mode = 1;
unsigned int num_slot = substream->runtime->channels;
unsigned int valid_slot = valid_channel[num_slot - 1];
(1 << 0)); /* left justified */
}
- pr_debug("PCMIN %s\n", flag ? "enable" : "disable");
+ pr_debug("PCMIN %s\n", enable ? "enable" : "disable");
pcm_in_register_show();
}
aml_audin_read(PCMOUT_CTRL3));
}
-void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag)
+void pcm_master_out_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable)
{
unsigned int pcm_mode = 1, pcm_wlen = 16;
unsigned int num_slot = substream->runtime->channels;
unsigned int valid_bits;
unsigned int bit_offset_s = 0, slot_offset_s = 0,
bit_offset_e = 0, slot_offset_e = 0;
+ unsigned int slots = cfg.slots;
+
+ /* if no slots is set, use the channel num */
+ if (slots == 0)
+ slots = num_slot;
switch (substream->runtime->format) {
case SNDRV_PCM_FORMAT_S32_LE:
pcm_mode = (pcm_wlen >> 3) - 1;
valid_bits = pcm_wlen - 1;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = pcm_wlen - 1;
- slot_offset_s = num_slot - 1;
+ slot_offset_s = slots - 1;
bit_offset_e = 0;
slot_offset_e = 0;
- } else if (aml_pcm_format == SND_SOC_DAIFMT_DSP_B) {
+ } else if (cfg.fmt == SND_SOC_DAIFMT_DSP_B) {
bit_offset_s = 0;
slot_offset_s = 0;
bit_offset_e = 1;
} else
pr_err("Unsupport DSP mode\n");
- pr_info("pcm master out, pcm mode:%d, valid bits:0x%x, valid slot:0x%x\n",
+ pr_info("%s(), mode:%d, valid bits:0x%x, valid slot:0x%x, slots:%d\n",
+ __func__,
pcm_mode,
valid_bits,
- valid_slot);
+ valid_slot,
+ slots);
/* reset fifo */
aml_audin_update_bits(AUDOUT_CTRL, 1 << 30, 1 << 30);
aml_audin_update_bits(PCMOUT_CTRL0, 1 << 31, 0 << 31);
}
- if (flag) {
+ if (enable) {
/* set buffer start ptr end */
aml_audin_write(AUDOUT_BUF0_STA, pcmout_buffer_addr);
aml_audin_write(AUDOUT_BUF0_WPTR, pcmout_buffer_addr);
/* underrun use mute constant */
(0 << 29) |
/* pcmo max slot number in one frame */
- ((num_slot - 1) << 22) |
+ ((slots - 1) << 22) |
/* pcmo max bit number in one slot */
(valid_bits << 16) |
/* pcmo valid slot. each bit for one slot */
}
}
- pr_debug("PCMOUT %s\n", flag ? "enable" : "disable");
+ pr_debug("PCMOUT %s\n", enable ? "enable" : "disable");
pcm_out_register_show();
}
-void pcm_out_enable(struct snd_pcm_substream *substream, int flag)
+void pcm_out_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable)
{
unsigned int pcm_mode = 1;
unsigned int num_slot = substream->runtime->channels;
unsigned int valid_bits = 0xf;
unsigned int bit_offset_s, slot_offset_s, bit_offset_e, slot_offset_e;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = 0xF;
slot_offset_s = num_slot - 1;
bit_offset_e = 0;
slot_offset_e = 0;
} else {
- if (aml_pcm_format != SND_SOC_DAIFMT_DSP_B)
+ if (cfg.fmt != SND_SOC_DAIFMT_DSP_B)
pr_err("Unsupport DSP mode\n");
bit_offset_s = 0;
case SNDRV_PCM_FORMAT_S32_LE:
pcm_mode = 3;
valid_bits = 0x1f;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = 0xF;
slot_offset_s = (num_slot << 1) - 1;
bit_offset_e = 0;
case SNDRV_PCM_FORMAT_S24_LE:
pcm_mode = 2;
valid_bits = 0x1f;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = 0xF;
slot_offset_s = (num_slot << 1) - 8 - 1;
bit_offset_e = 0;
case SNDRV_PCM_FORMAT_S8:
pcm_mode = 0;
valid_bits = 0x7;
- if (aml_pcm_format == SND_SOC_DAIFMT_DSP_A) {
+ if (cfg.fmt == SND_SOC_DAIFMT_DSP_A) {
bit_offset_s = 0x7;
slot_offset_s = (num_slot >> 1) - 1;
bit_offset_e = 0;
/* disable pcmout */
aml_audin_update_bits(PCMOUT_CTRL0, 1 << 31, 0 << 31);
- if (flag) {
+ if (enable) {
/* set buffer start ptr end */
aml_audin_write(AUDOUT_BUF0_STA, pcmout_buffer_addr);
aml_audin_write(AUDOUT_BUF0_WPTR, pcmout_buffer_addr);
(0 << 0));
}
- pr_debug("PCMOUT %s\n", flag ? "enable" : "disable");
+ pr_debug("PCMOUT %s\n", enable ? "enable" : "disable");
pcm_out_register_show();
}
#include "audio_hw.h"
-void aml_set_pcm_format(int pcm_mode);
-void pcm_in_enable(struct snd_pcm_substream *substream, int flag);
+struct tdm_config {
+ unsigned int fmt;
+ unsigned int tx_slot_mask;
+ unsigned int rx_slot_mask;
+ unsigned int slots;
+ unsigned int slot_width;
+};
+
+void pcm_in_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable);
void pcm_in_set_buf(unsigned int addr, unsigned int size);
int pcm_in_is_enable(void);
unsigned int pcm_in_rd_ptr(void);
unsigned int pcm_in_set_rd_ptr(unsigned int value);
unsigned int pcm_in_fifo_int(void);
-void pcm_out_enable(struct snd_pcm_substream *substream, int flag);
+void pcm_out_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable);
void pcm_out_mute(int flag);
void pcm_out_set_buf(unsigned int addr, unsigned int size);
int pcm_out_is_enable(void);
unsigned int pcm_out_wr_ptr(void);
unsigned int pcm_out_set_wr_ptr(unsigned int value);
-void pcm_master_in_enable(struct snd_pcm_substream *substream, int flag);
-void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag);
+void pcm_master_in_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable);
+void pcm_master_out_enable(struct snd_pcm_substream *substream,
+ struct tdm_config cfg, int enable);
#endif
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "pcm_dai.h"
#include "pcm.h"
-#include "i2s.h"
+//#include "i2s.h"
#include "audio_hw_pcm.h"
-#include <linux/of.h>
#define DEV_NAME "aml-pcm-dai"
struct aml_pcm_runtime_data *prtd = runtime->private_data;
struct aml_pcm *pcm = snd_soc_dai_get_drvdata(dai);
int mclk_rate, pcm_bit;
+ unsigned int slots = pcm->cfg.slots;
- pr_debug("***Entered %s\n", __func__);
+ pr_debug("***Entered %s, slots %d\n", __func__, slots);
+
+ /* if no slots is set, use the channel num */
+ if (slots == 0)
+ slots = runtime->channels;
/* set bclk */
if (runtime->format == SNDRV_PCM_FORMAT_S32_LE)
else
pcm_bit = 16;
- mclk_rate = runtime->rate * pcm_bit * runtime->channels;
- pr_info("%s rate:%d, bits:%d, channels:%d, mclk:%d\n",
+ mclk_rate = runtime->rate * pcm_bit * slots;
+ pr_info("%s rate:%d, bits:%d, slots:%d, mclk:%d\n",
__func__,
runtime->rate,
pcm_bit,
- runtime->channels,
+ slots,
mclk_rate);
aml_pcm_set_clk(pcm, mclk_rate);
pr_info("aiu pcm master stream %d enable\n\n",
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm_master_out_enable(substream, 1);
+ pcm_master_out_enable(substream, pcm_p->cfg, 1);
else
- pcm_master_in_enable(substream, 1);
+ pcm_master_in_enable(substream, pcm_p->cfg, 1);
} else {
pr_info("aiu slave pcm stream %d enable\n\n",
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm_out_enable(substream, 1);
+ pcm_out_enable(substream, pcm_p->cfg, 1);
else
- pcm_in_enable(substream, 1);
+ pcm_in_enable(substream, pcm_p->cfg, 1);
}
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_info("aiu master pcm stream %d disable\n\n",
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm_master_out_enable(substream, 0);
+ pcm_master_out_enable(substream, pcm_p->cfg, 0);
else
- pcm_master_in_enable(substream, 0);
+ pcm_master_in_enable(substream, pcm_p->cfg, 0);
} else {
pr_info("aiu slave pcm stream %d disable\n\n",
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- pcm_out_enable(substream, 0);
+ pcm_out_enable(substream, pcm_p->cfg, 0);
else
- pcm_in_enable(substream, 0);
+ pcm_in_enable(substream, pcm_p->cfg, 0);
}
break;
default:
{
pr_debug("***Entered %s\n", __func__);
- aml_set_pcm_format(fmt & SND_SOC_DAIFMT_FORMAT_MASK);
-
return 0;
}
.name = DEV_NAME,
};
+static int parse_tdm_configs(struct device_node *node, struct aml_pcm *pcm_p)
+{
+ struct tdm_config *cfg = &pcm_p->cfg;
+ unsigned int fmt = 0;
+
+ fmt = snd_soc_of_parse_daifmt(node, NULL, NULL, NULL);
+ cfg->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+ snd_soc_of_parse_tdm_slot(node,
+ &cfg->tx_slot_mask,
+ &cfg->rx_slot_mask,
+ &cfg->slots,
+ &cfg->slot_width);
+ pr_info("tdm config: %#x, %#x, %d, %d\n",
+ cfg->tx_slot_mask,
+ cfg->rx_slot_mask,
+ cfg->slots,
+ cfg->slot_width);
+
+ if (cfg->fmt == 0)
+ cfg->fmt = SND_SOC_DAIFMT_DSP_A;
+
+ if (cfg->tx_slot_mask != cfg->rx_slot_mask) {
+ pr_info("%s(), rx equals to tx\n", __func__);
+ cfg->rx_slot_mask = cfg->tx_slot_mask;
+ }
+
+ return 0;
+}
+
static int aml_pcm_dai_probe(struct platform_device *pdev)
{
struct pinctrl *pin_ctl;
"Can't enable pcm clk_pcm_sync clock: %d\n", ret);
goto err;
}
+ parse_tdm_configs((&pdev->dev)->of_node, pcm_p);
}
ret = snd_soc_register_component(&pdev->dev, &aml_component,
#ifndef AML_DAI_H
#define AML_DAI_H
+#include <sound/soc.h>
+#include "audio_hw_pcm.h"
+
struct aml_pcm {
struct clk *clk_mpll;
struct clk *clk_pcm_mclk;
struct clk *clk_pcm_sync;
int pcm_mode;
+ struct tdm_config cfg;
};
#endif