|
|
@@ -28,6 +28,7 @@
|
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/platform_data/davinci_asp.h>
|
|
|
#include <linux/math64.h>
|
|
|
+#include <linux/bitmap.h>
|
|
|
|
|
|
#include <sound/asoundef.h>
|
|
|
#include <sound/core.h>
|
|
|
@@ -95,6 +96,8 @@ struct davinci_mcasp {
|
|
|
int sysclk_freq;
|
|
|
bool bclk_master;
|
|
|
|
|
|
+ unsigned long pdir; /* Pin direction bitfield */
|
|
|
+
|
|
|
/* McASP FIFO related */
|
|
|
u8 txnumevt;
|
|
|
u8 rxnumevt;
|
|
|
@@ -169,6 +172,30 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
|
|
|
return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
|
|
|
}
|
|
|
|
|
|
+static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
|
|
|
+{
|
|
|
+ u32 bit = PIN_BIT_AMUTE;
|
|
|
+
|
|
|
+ for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
|
|
|
+ if (enable)
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
|
|
|
+ else
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
|
|
|
+{
|
|
|
+ u32 bit;
|
|
|
+
|
|
|
+ for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) {
|
|
|
+ if (enable)
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
|
|
|
+ else
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
|
|
|
{
|
|
|
if (mcasp->rxnumevt) { /* enable FIFO */
|
|
|
@@ -220,6 +247,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
|
|
|
/* Start clocks */
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
|
|
|
+ mcasp_set_clk_pdir(mcasp, true);
|
|
|
+
|
|
|
/* Activate serializer(s) */
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
|
|
|
@@ -230,6 +259,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
|
|
|
(cnt < 100000))
|
|
|
cnt++;
|
|
|
|
|
|
+ mcasp_set_axr_pdir(mcasp, true);
|
|
|
+
|
|
|
/* Release TX state machine */
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
|
|
|
/* Release Frame Sync generator */
|
|
|
@@ -260,8 +291,10 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
|
|
|
* In synchronous mode stop the TX clocks if no other stream is
|
|
|
* running
|
|
|
*/
|
|
|
- if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
|
|
|
+ if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
|
|
|
+ mcasp_set_clk_pdir(mcasp, false);
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
|
|
|
+ }
|
|
|
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
|
|
|
@@ -287,6 +320,9 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
|
|
|
*/
|
|
|
if (mcasp_is_synchronous(mcasp) && mcasp->streams)
|
|
|
val = TXHCLKRST | TXCLKRST | TXFSRST;
|
|
|
+ else
|
|
|
+ mcasp_set_clk_pdir(mcasp, false);
|
|
|
+
|
|
|
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
|
@@ -296,6 +332,8 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
|
|
|
|
|
|
mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
|
|
|
}
|
|
|
+
|
|
|
+ mcasp_set_axr_pdir(mcasp, false);
|
|
|
}
|
|
|
|
|
|
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
|
|
|
@@ -446,8 +484,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
|
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
|
|
|
+ /* BCLK */
|
|
|
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
|
|
|
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
|
|
|
+ /* Frame Sync */
|
|
|
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
|
|
|
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
|
|
|
+
|
|
|
mcasp->bclk_master = 1;
|
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBS_CFM:
|
|
|
@@ -458,8 +501,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
|
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
|
|
|
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
|
|
|
+ /* BCLK */
|
|
|
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
|
|
|
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
|
|
|
+ /* Frame Sync */
|
|
|
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
|
|
|
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
|
|
|
+
|
|
|
mcasp->bclk_master = 1;
|
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBM_CFS:
|
|
|
@@ -470,8 +518,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
|
|
|
|
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
|
|
|
+ /* BCLK */
|
|
|
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
|
|
|
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
|
|
|
+ /* Frame Sync */
|
|
|
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
|
|
|
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
|
|
|
+
|
|
|
mcasp->bclk_master = 0;
|
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBM_CFM:
|
|
|
@@ -482,8 +535,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
|
|
|
|
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
|
|
|
- ACLKX | AFSX | ACLKR | AHCLKR | AFSR);
|
|
|
+ /* BCLK */
|
|
|
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
|
|
|
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
|
|
|
+ /* Frame Sync */
|
|
|
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
|
|
|
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
|
|
|
+
|
|
|
mcasp->bclk_master = 0;
|
|
|
break;
|
|
|
default:
|
|
|
@@ -598,11 +656,11 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|
|
if (dir == SND_SOC_CLOCK_OUT) {
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
|
|
|
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
|
|
|
} else {
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
|
|
|
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
|
|
|
+ clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
|
|
|
}
|
|
|
|
|
|
mcasp->sysclk_freq = freq;
|
|
|
@@ -775,17 +833,21 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
|
|
mcasp->serial_dir[i]);
|
|
|
if (mcasp->serial_dir[i] == TX_MODE &&
|
|
|
tx_ser < max_active_serializers) {
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
|
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
|
DISMOD_LOW, DISMOD_MASK);
|
|
|
+ set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
tx_ser++;
|
|
|
} else if (mcasp->serial_dir[i] == RX_MODE &&
|
|
|
rx_ser < max_active_serializers) {
|
|
|
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
|
|
|
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
rx_ser++;
|
|
|
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
|
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
|
SRMOD_INACTIVE, SRMOD_MASK);
|
|
|
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
+ } else if (mcasp->serial_dir[i] == TX_MODE) {
|
|
|
+ /* Unused TX pins, clear PDIR */
|
|
|
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
}
|
|
|
}
|
|
|
|