summaryrefslogtreecommitdiff
path: root/sound/soc/ti/davinci-mcasp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/ti/davinci-mcasp.c')
-rw-r--r--sound/soc/ti/davinci-mcasp.c176
1 files changed, 152 insertions, 24 deletions
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 017a5a5e56cd..56a19eeec5c7 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -83,6 +83,8 @@ struct davinci_mcasp {
struct snd_pcm_substream *substreams[2];
unsigned int dai_fmt;
+ u32 iec958_status;
+
/* Audio can not be enabled due to missing parameter(s) */
bool missing_audio_param;
@@ -757,6 +759,9 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+ return 0;
+
dev_dbg(mcasp->dev,
"%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
__func__, tx_mask, rx_mask, slots, slot_width);
@@ -827,6 +832,20 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
RXROT(7));
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
+ } else {
+ /*
+ * according to the TRM it should be TXROT=0, this one works:
+ * 16 bit to 23-8 (TXROT=6, rotate 24 bits)
+ * 24 bit to 23-0 (TXROT=0, rotate 0 bits)
+ *
+ * TXROT = 0 only works with 24bit samples
+ */
+ tx_rotate = (sample_width / 4 + 2) & 0x7;
+
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+ TXROT(7));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
+ TXSSZ(0x0F));
}
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
@@ -842,10 +861,16 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 slots = mcasp->tdm_slots;
- u8 max_active_serializers = (channels + slots - 1) / slots;
- u8 max_rx_serializers, max_tx_serializers;
+ u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
int active_serializers, numevt;
u32 reg;
+
+ /* In DIT mode we only allow maximum of one serializers for now */
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+ max_active_serializers = 1;
+ else
+ max_active_serializers = (channels + slots - 1) / slots;
+
/* Default configuration */
if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
@@ -1031,16 +1056,18 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
unsigned int rate)
{
- u32 cs_value = 0;
- u8 *cs_bytes = (u8*) &cs_value;
+ u8 *cs_bytes = (u8 *)&mcasp->iec958_status;
- /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
- and LSB first */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
+ if (!mcasp->dat_port)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);
+
/* Set the TX tdm : for all the slots */
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
@@ -1049,16 +1076,8 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
- /* Only 44100 and 48000 are valid, both have the same setting */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
-
- /* Enable the DIT */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
-
/* Set S/PDIF channel status bits */
- cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
- cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
-
+ cs_bytes[3] &= ~IEC958_AES3_CON_FS;
switch (rate) {
case 22050:
cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
@@ -1088,12 +1107,15 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
break;
default:
- printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
+ dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
return -EINVAL;
}
- mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);
+
+ /* Enable the DIT */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
return 0;
}
@@ -1237,12 +1259,18 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
int slots = mcasp->tdm_slots;
int rate = params_rate(params);
int sbits = params_width(params);
+ unsigned int bclk_target;
if (mcasp->slot_width)
sbits = mcasp->slot_width;
+ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+ bclk_target = rate * sbits * slots;
+ else
+ bclk_target = rate * 128;
+
davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
- rate * sbits * slots, true);
+ bclk_target, true);
}
ret = mcasp_common_hw_param(mcasp, substream->stream,
@@ -1598,6 +1626,77 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_tdm_slot = davinci_mcasp_set_tdm_slot,
};
+static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
+ sizeof(mcasp->iec958_status));
+
+ return 0;
+}
+
+static int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
+ sizeof(mcasp->iec958_status));
+
+ return 0;
+}
+
+static int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
+ return 0;
+}
+
+static const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
+ {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = davinci_mcasp_iec958_info,
+ .get = davinci_mcasp_iec958_get,
+ .put = davinci_mcasp_iec958_put,
+ }, {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+ .info = davinci_mcasp_iec958_info,
+ .get = davinci_mcasp_iec958_con_mask_get,
+ },
+};
+
+static void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
+{
+ unsigned char *cs = (u8 *)&mcasp->iec958_status;
+
+ cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+ cs[1] = IEC958_AES1_CON_PCM_CODER;
+ cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
+ cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+}
+
static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
@@ -1605,6 +1704,12 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
+ davinci_mcasp_init_iec958_status(mcasp);
+ snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
+ ARRAY_SIZE(davinci_mcasp_iec958_ctls));
+ }
+
return 0;
}
@@ -1651,7 +1756,8 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
.channels_min = 1,
.channels_max = 384,
.rates = DAVINCI_MCASP_RATES,
- .formats = DAVINCI_MCASP_PCM_FMTS,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &davinci_mcasp_dai_ops,
},
@@ -1688,6 +1794,12 @@ static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
.version = MCASP_VERSION_4,
};
+static struct davinci_mcasp_pdata omap_mcasp_pdata = {
+ .tx_dma_offset = 0x200,
+ .rx_dma_offset = 0,
+ .version = MCASP_VERSION_OMAP,
+};
+
static const struct of_device_id mcasp_dt_ids[] = {
{
.compatible = "ti,dm646x-mcasp-audio",
@@ -1705,6 +1817,10 @@ static const struct of_device_id mcasp_dt_ids[] = {
.compatible = "ti,dra7-mcasp-audio",
.data = &dra7_mcasp_pdata,
},
+ {
+ .compatible = "ti,omap4-mcasp-audio",
+ .data = &omap_mcasp_pdata,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
@@ -1871,6 +1987,8 @@ out:
} else {
mcasp->tdm_slots = pdata->tdm_slots;
}
+ } else {
+ mcasp->tdm_slots = 32;
}
mcasp->num_serializer = pdata->num_serializer;
@@ -2242,10 +2360,17 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dma_data->filter_data = "tx";
- if (dat)
+ if (dat) {
dma_data->addr = dat->start;
- else
+ /*
+ * According to the TRM there should be 0x200 offset added to
+ * the DAT port address
+ */
+ if (mcasp->version == MCASP_VERSION_OMAP)
+ dma_data->addr += davinci_mcasp_txdma_offset(mcasp->pdata);
+ } else {
dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
+ }
/* RX is not valid in DIT mode */
@@ -2310,7 +2435,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = edma_pcm_platform_register(&pdev->dev);
break;
case PCM_SDMA:
- ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
+ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+ ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
+ else
+ ret = sdma_pcm_platform_register(&pdev->dev, "tx", NULL);
break;
case PCM_UDMA:
ret = udma_pcm_platform_register(&pdev->dev);