|
@@ -28,6 +28,8 @@
|
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/platform_data/davinci_asp.h>
|
|
#include <linux/platform_data/davinci_asp.h>
|
|
|
#include <linux/math64.h>
|
|
#include <linux/math64.h>
|
|
|
|
|
+#include <linux/bitmap.h>
|
|
|
|
|
+#include <linux/gpio/driver.h>
|
|
|
|
|
|
|
|
#include <sound/asoundef.h>
|
|
#include <sound/asoundef.h>
|
|
|
#include <sound/core.h>
|
|
#include <sound/core.h>
|
|
@@ -36,9 +38,11 @@
|
|
|
#include <sound/initval.h>
|
|
#include <sound/initval.h>
|
|
|
#include <sound/soc.h>
|
|
#include <sound/soc.h>
|
|
|
#include <sound/dmaengine_pcm.h>
|
|
#include <sound/dmaengine_pcm.h>
|
|
|
|
|
+#include <dt-bindings/sound/ti-mcasp.h>
|
|
|
|
|
|
|
|
#include "edma-pcm.h"
|
|
#include "edma-pcm.h"
|
|
|
-#include "../omap/sdma-pcm.h"
|
|
|
|
|
|
|
+#include "sdma-pcm.h"
|
|
|
|
|
+#include "udma-pcm.h"
|
|
|
#include "davinci-mcasp.h"
|
|
#include "davinci-mcasp.h"
|
|
|
|
|
|
|
|
#define MCASP_MAX_AFIFO_DEPTH 64
|
|
#define MCASP_MAX_AFIFO_DEPTH 64
|
|
@@ -53,6 +57,7 @@ static u32 context_regs[] = {
|
|
|
DAVINCI_MCASP_AHCLKXCTL_REG,
|
|
DAVINCI_MCASP_AHCLKXCTL_REG,
|
|
|
DAVINCI_MCASP_AHCLKRCTL_REG,
|
|
DAVINCI_MCASP_AHCLKRCTL_REG,
|
|
|
DAVINCI_MCASP_PDIR_REG,
|
|
DAVINCI_MCASP_PDIR_REG,
|
|
|
|
|
+ DAVINCI_MCASP_PFUNC_REG,
|
|
|
DAVINCI_MCASP_RXMASK_REG,
|
|
DAVINCI_MCASP_RXMASK_REG,
|
|
|
DAVINCI_MCASP_TXMASK_REG,
|
|
DAVINCI_MCASP_TXMASK_REG,
|
|
|
DAVINCI_MCASP_RXTDM_REG,
|
|
DAVINCI_MCASP_RXTDM_REG,
|
|
@@ -84,6 +89,7 @@ struct davinci_mcasp {
|
|
|
u32 tdm_mask[2];
|
|
u32 tdm_mask[2];
|
|
|
int slot_width;
|
|
int slot_width;
|
|
|
u8 op_mode;
|
|
u8 op_mode;
|
|
|
|
|
+ u8 dismod;
|
|
|
u8 num_serializer;
|
|
u8 num_serializer;
|
|
|
u8 *serial_dir;
|
|
u8 *serial_dir;
|
|
|
u8 version;
|
|
u8 version;
|
|
@@ -95,6 +101,8 @@ struct davinci_mcasp {
|
|
|
int sysclk_freq;
|
|
int sysclk_freq;
|
|
|
bool bclk_master;
|
|
bool bclk_master;
|
|
|
|
|
|
|
|
|
|
+ unsigned long pdir; /* Pin direction bitfield */
|
|
|
|
|
+
|
|
|
/* McASP FIFO related */
|
|
/* McASP FIFO related */
|
|
|
u8 txnumevt;
|
|
u8 txnumevt;
|
|
|
u8 rxnumevt;
|
|
u8 rxnumevt;
|
|
@@ -104,7 +112,11 @@ struct davinci_mcasp {
|
|
|
/* Used for comstraint setting on the second stream */
|
|
/* Used for comstraint setting on the second stream */
|
|
|
u32 channels;
|
|
u32 channels;
|
|
|
|
|
|
|
|
-#ifdef CONFIG_PM_SLEEP
|
|
|
|
|
|
|
+#ifdef CONFIG_GPIOLIB
|
|
|
|
|
+ struct gpio_chip gpio_chip;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
struct davinci_mcasp_context context;
|
|
struct davinci_mcasp_context context;
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
@@ -169,6 +181,30 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
|
|
|
return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
|
|
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)
|
|
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
|
|
|
{
|
|
{
|
|
|
if (mcasp->rxnumevt) { /* enable FIFO */
|
|
if (mcasp->rxnumevt) { /* enable FIFO */
|
|
@@ -192,6 +228,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Activate serializer(s) */
|
|
/* Activate serializer(s) */
|
|
|
|
|
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
|
|
|
/* Release RX state machine */
|
|
/* Release RX state machine */
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
|
|
@@ -219,7 +256,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
|
|
|
/* Start clocks */
|
|
/* Start clocks */
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
|
|
|
|
|
+ mcasp_set_clk_pdir(mcasp, true);
|
|
|
|
|
+
|
|
|
/* Activate serializer(s) */
|
|
/* Activate serializer(s) */
|
|
|
|
|
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
|
|
|
|
|
|
|
|
/* wait for XDATA to be cleared */
|
|
/* wait for XDATA to be cleared */
|
|
@@ -228,6 +268,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
|
|
|
(cnt < 100000))
|
|
(cnt < 100000))
|
|
|
cnt++;
|
|
cnt++;
|
|
|
|
|
|
|
|
|
|
+ mcasp_set_axr_pdir(mcasp, true);
|
|
|
|
|
+
|
|
|
/* Release TX state machine */
|
|
/* Release TX state machine */
|
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
|
|
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
|
|
|
/* Release Frame Sync generator */
|
|
/* Release Frame Sync generator */
|
|
@@ -258,8 +300,10 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
|
|
|
* In synchronous mode stop the TX clocks if no other stream is
|
|
* In synchronous mode stop the TX clocks if no other stream is
|
|
|
* running
|
|
* 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_GBLCTLX_REG, 0);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
|
|
@@ -285,6 +329,9 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
|
|
|
*/
|
|
*/
|
|
|
if (mcasp_is_synchronous(mcasp) && mcasp->streams)
|
|
if (mcasp_is_synchronous(mcasp) && mcasp->streams)
|
|
|
val = TXHCLKRST | TXCLKRST | TXFSRST;
|
|
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_GBLCTLX_REG, val);
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
@@ -294,6 +341,8 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
|
|
|
|
|
|
|
|
mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
|
|
mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ mcasp_set_axr_pdir(mcasp, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
|
|
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
|
|
@@ -444,8 +493,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_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
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;
|
|
mcasp->bclk_master = 1;
|
|
|
break;
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBS_CFM:
|
|
case SND_SOC_DAIFMT_CBS_CFM:
|
|
@@ -456,8 +510,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_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
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;
|
|
mcasp->bclk_master = 1;
|
|
|
break;
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBM_CFS:
|
|
case SND_SOC_DAIFMT_CBM_CFS:
|
|
@@ -468,8 +527,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_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
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;
|
|
mcasp->bclk_master = 0;
|
|
|
break;
|
|
break;
|
|
|
case SND_SOC_DAIFMT_CBM_CFM:
|
|
case SND_SOC_DAIFMT_CBM_CFM:
|
|
@@ -480,8 +544,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_ACLKRCTL_REG, ACLKRE);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
|
|
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;
|
|
mcasp->bclk_master = 0;
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
@@ -593,18 +662,39 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|
|
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
|
|
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
|
|
|
|
|
|
|
|
pm_runtime_get_sync(mcasp->dev);
|
|
pm_runtime_get_sync(mcasp->dev);
|
|
|
- if (dir == SND_SOC_CLOCK_OUT) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (dir == SND_SOC_CLOCK_IN) {
|
|
|
|
|
+ switch (clk_id) {
|
|
|
|
|
+ case MCASP_CLK_HCLK_AHCLK:
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
|
|
|
|
|
+ AHCLKXE);
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
|
|
|
|
|
+ AHCLKRE);
|
|
|
|
|
+ clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case MCASP_CLK_HCLK_AUXCLK:
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
|
|
|
|
|
+ AHCLKXE);
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
|
|
|
|
|
+ AHCLKRE);
|
|
|
|
|
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id);
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ /* Select AUXCLK as HCLK */
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
|
|
|
|
|
- } 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);
|
|
|
|
|
|
|
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
+ * When AHCLK X/R is selected to be output it means that the HCLK is
|
|
|
|
|
+ * the same clock - coming via AUXCLK.
|
|
|
|
|
+ */
|
|
|
mcasp->sysclk_freq = freq;
|
|
mcasp->sysclk_freq = freq;
|
|
|
-
|
|
|
|
|
|
|
+out:
|
|
|
pm_runtime_put(mcasp->dev);
|
|
pm_runtime_put(mcasp->dev);
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
@@ -757,9 +847,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
|
|
if (mcasp->version < MCASP_VERSION_3)
|
|
if (mcasp->version < MCASP_VERSION_3)
|
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
|
|
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
|
|
|
|
|
|
|
|
- /* All PINS as McASP */
|
|
|
|
|
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
|
|
|
|
|
-
|
|
|
|
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
|
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
|
|
mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
|
|
@@ -773,17 +860,23 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
|
|
|
mcasp->serial_dir[i]);
|
|
mcasp->serial_dir[i]);
|
|
|
if (mcasp->serial_dir[i] == TX_MODE &&
|
|
if (mcasp->serial_dir[i] == TX_MODE &&
|
|
|
tx_ser < max_active_serializers) {
|
|
tx_ser < max_active_serializers) {
|
|
|
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
|
|
|
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
|
- DISMOD_LOW, DISMOD_MASK);
|
|
|
|
|
|
|
+ mcasp->dismod, DISMOD_MASK);
|
|
|
|
|
+ set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
tx_ser++;
|
|
tx_ser++;
|
|
|
} else if (mcasp->serial_dir[i] == RX_MODE &&
|
|
} else if (mcasp->serial_dir[i] == RX_MODE &&
|
|
|
rx_ser < max_active_serializers) {
|
|
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++;
|
|
rx_ser++;
|
|
|
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
|
|
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
|
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
|
SRMOD_INACTIVE, SRMOD_MASK);
|
|
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 */
|
|
|
|
|
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
|
|
|
|
|
+ mcasp->dismod, DISMOD_MASK);
|
|
|
|
|
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1041,6 +1134,42 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
|
|
|
return error_ppm;
|
|
return error_ppm;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!mcasp->txnumevt)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!mcasp->rxnumevt)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static snd_pcm_sframes_t davinci_mcasp_delay(
|
|
|
|
|
+ struct snd_pcm_substream *substream,
|
|
|
|
|
+ struct snd_soc_dai *cpu_dai)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
|
|
|
|
|
+ u32 fifo_use;
|
|
|
|
|
+
|
|
|
|
|
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
|
+ fifo_use = davinci_mcasp_tx_delay(mcasp);
|
|
|
|
|
+ else
|
|
|
|
|
+ fifo_use = davinci_mcasp_rx_delay(mcasp);
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Divide the used locations with the channel count to get the
|
|
|
|
|
+ * FIFO usage in samples (don't care about partial samples in the
|
|
|
|
|
+ * buffer).
|
|
|
|
|
+ */
|
|
|
|
|
+ return fifo_use / substream->runtime->channels;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
|
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
|
|
struct snd_pcm_hw_params *params,
|
|
struct snd_pcm_hw_params *params,
|
|
|
struct snd_soc_dai *cpu_dai)
|
|
struct snd_soc_dai *cpu_dai)
|
|
@@ -1365,6 +1494,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
|
|
|
.startup = davinci_mcasp_startup,
|
|
.startup = davinci_mcasp_startup,
|
|
|
.shutdown = davinci_mcasp_shutdown,
|
|
.shutdown = davinci_mcasp_shutdown,
|
|
|
.trigger = davinci_mcasp_trigger,
|
|
.trigger = davinci_mcasp_trigger,
|
|
|
|
|
+ .delay = davinci_mcasp_delay,
|
|
|
.hw_params = davinci_mcasp_hw_params,
|
|
.hw_params = davinci_mcasp_hw_params,
|
|
|
.set_fmt = davinci_mcasp_set_dai_fmt,
|
|
.set_fmt = davinci_mcasp_set_dai_fmt,
|
|
|
.set_clkdiv = davinci_mcasp_set_clkdiv,
|
|
.set_clkdiv = davinci_mcasp_set_clkdiv,
|
|
@@ -1382,74 +1512,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
|
|
|
return 0;
|
|
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_RATES SNDRV_PCM_RATE_8000_192000
|
|
|
|
|
|
|
|
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
|
|
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
|
|
@@ -1467,8 +1529,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
|
|
|
{
|
|
{
|
|
|
.name = "davinci-mcasp.0",
|
|
.name = "davinci-mcasp.0",
|
|
|
.probe = davinci_mcasp_dai_probe,
|
|
.probe = davinci_mcasp_dai_probe,
|
|
|
- .suspend = davinci_mcasp_suspend,
|
|
|
|
|
- .resume = davinci_mcasp_resume,
|
|
|
|
|
.playback = {
|
|
.playback = {
|
|
|
.channels_min = 1,
|
|
.channels_min = 1,
|
|
|
.channels_max = 32 * 16,
|
|
.channels_max = 32 * 16,
|
|
@@ -1608,6 +1668,7 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
|
|
|
|
|
|
|
|
if (pdev->dev.platform_data) {
|
|
if (pdev->dev.platform_data) {
|
|
|
pdata = pdev->dev.platform_data;
|
|
pdata = pdev->dev.platform_data;
|
|
|
|
|
+ pdata->dismod = DISMOD_LOW;
|
|
|
return pdata;
|
|
return pdata;
|
|
|
} else if (match) {
|
|
} else if (match) {
|
|
|
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
|
|
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
|
|
@@ -1697,6 +1758,18 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
|
|
|
if (ret >= 0)
|
|
if (ret >= 0)
|
|
|
pdata->sram_size_capture = val;
|
|
pdata->sram_size_capture = val;
|
|
|
|
|
|
|
|
|
|
+ ret = of_property_read_u32(np, "dismod", &val);
|
|
|
|
|
+ if (ret >= 0) {
|
|
|
|
|
+ if (val == 0 || val == 2 || val == 3) {
|
|
|
|
|
+ pdata->dismod = DISMOD_VAL(val);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
|
|
|
|
|
+ pdata->dismod = DISMOD_LOW;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ pdata->dismod = DISMOD_LOW;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return pdata;
|
|
return pdata;
|
|
|
|
|
|
|
|
nodata:
|
|
nodata:
|
|
@@ -1711,6 +1784,7 @@ nodata:
|
|
|
enum {
|
|
enum {
|
|
|
PCM_EDMA,
|
|
PCM_EDMA,
|
|
|
PCM_SDMA,
|
|
PCM_SDMA,
|
|
|
|
|
+ PCM_UDMA,
|
|
|
};
|
|
};
|
|
|
static const char *sdma_prefix = "ti,omap";
|
|
static const char *sdma_prefix = "ti,omap";
|
|
|
|
|
|
|
@@ -1748,6 +1822,8 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
|
|
|
dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
|
|
dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
|
|
|
if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
|
|
if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
|
|
|
return PCM_SDMA;
|
|
return PCM_SDMA;
|
|
|
|
|
+ else if (strstr(tmp, "udmap"))
|
|
|
|
|
+ return PCM_UDMA;
|
|
|
|
|
|
|
|
return PCM_EDMA;
|
|
return PCM_EDMA;
|
|
|
}
|
|
}
|
|
@@ -1798,6 +1874,147 @@ static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
|
|
|
return offset;
|
|
return offset;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_GPIOLIB
|
|
|
|
|
+static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+
|
|
|
|
|
+ if (mcasp->num_serializer && offset < mcasp->num_serializer &&
|
|
|
|
|
+ mcasp->serial_dir[offset] != INACTIVE_MODE) {
|
|
|
|
|
+ dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset);
|
|
|
|
|
+ return -EBUSY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Do not change the PIN yet */
|
|
|
|
|
+
|
|
|
|
|
+ return pm_runtime_get_sync(mcasp->dev);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+
|
|
|
|
|
+ /* Set the direction to input */
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
|
|
|
|
|
+
|
|
|
|
|
+ /* Set the pin as McASP pin */
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
|
|
|
|
|
+
|
|
|
|
|
+ pm_runtime_put_sync(mcasp->dev);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip,
|
|
|
|
|
+ unsigned offset, int value)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+ u32 val;
|
|
|
|
|
+
|
|
|
|
|
+ if (value)
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
|
|
|
|
|
+ else
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
|
|
|
|
|
+
|
|
|
|
|
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
|
|
|
|
|
+ if (!(val & BIT(offset))) {
|
|
|
|
|
+ /* Set the pin as GPIO pin */
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
|
|
|
|
|
+
|
|
|
|
|
+ /* Set the direction to output */
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset,
|
|
|
|
|
+ int value)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+
|
|
|
|
|
+ if (value)
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
|
|
|
|
|
+ else
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip,
|
|
|
|
|
+ unsigned offset)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+ u32 val;
|
|
|
|
|
+
|
|
|
|
|
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
|
|
|
|
|
+ if (!(val & BIT(offset))) {
|
|
|
|
|
+ /* Set the direction to input */
|
|
|
|
|
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
|
|
|
|
|
+
|
|
|
|
|
+ /* Set the pin as GPIO pin */
|
|
|
|
|
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+ u32 val;
|
|
|
|
|
+
|
|
|
|
|
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG);
|
|
|
|
|
+ if (val & BIT(offset))
|
|
|
|
|
+ return 1;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip,
|
|
|
|
|
+ unsigned offset)
|
|
|
|
|
+{
|
|
|
|
|
+ struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
|
|
|
|
|
+ u32 val;
|
|
|
|
|
+
|
|
|
|
|
+ val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
|
|
|
|
|
+ if (val & BIT(offset))
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ return 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static const struct gpio_chip davinci_mcasp_template_chip = {
|
|
|
|
|
+ .owner = THIS_MODULE,
|
|
|
|
|
+ .request = davinci_mcasp_gpio_request,
|
|
|
|
|
+ .free = davinci_mcasp_gpio_free,
|
|
|
|
|
+ .direction_output = davinci_mcasp_gpio_direction_out,
|
|
|
|
|
+ .set = davinci_mcasp_gpio_set,
|
|
|
|
|
+ .direction_input = davinci_mcasp_gpio_direction_in,
|
|
|
|
|
+ .get = davinci_mcasp_gpio_get,
|
|
|
|
|
+ .get_direction = davinci_mcasp_gpio_get_direction,
|
|
|
|
|
+ .base = -1,
|
|
|
|
|
+ .ngpio = 32,
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller"))
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ mcasp->gpio_chip = davinci_mcasp_template_chip;
|
|
|
|
|
+ mcasp->gpio_chip.label = dev_name(mcasp->dev);
|
|
|
|
|
+ mcasp->gpio_chip.parent = mcasp->dev;
|
|
|
|
|
+#ifdef CONFIG_OF_GPIO
|
|
|
|
|
+ mcasp->gpio_chip.of_node = mcasp->dev->of_node;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#else /* CONFIG_GPIOLIB */
|
|
|
|
|
+static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
|
|
|
|
|
+{
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+#endif /* CONFIG_GPIOLIB */
|
|
|
|
|
+
|
|
|
static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
{
|
|
{
|
|
|
struct snd_dmaengine_dai_dma_data *dma_data;
|
|
struct snd_dmaengine_dai_dma_data *dma_data;
|
|
@@ -1859,7 +2076,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
mcasp->num_serializer = pdata->num_serializer;
|
|
mcasp->num_serializer = pdata->num_serializer;
|
|
|
-#ifdef CONFIG_PM_SLEEP
|
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
|
|
mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
|
|
|
mcasp->num_serializer, sizeof(u32),
|
|
mcasp->num_serializer, sizeof(u32),
|
|
|
GFP_KERNEL);
|
|
GFP_KERNEL);
|
|
@@ -1872,6 +2089,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
mcasp->version = pdata->version;
|
|
mcasp->version = pdata->version;
|
|
|
mcasp->txnumevt = pdata->txnumevt;
|
|
mcasp->txnumevt = pdata->txnumevt;
|
|
|
mcasp->rxnumevt = pdata->rxnumevt;
|
|
mcasp->rxnumevt = pdata->rxnumevt;
|
|
|
|
|
+ mcasp->dismod = pdata->dismod;
|
|
|
|
|
|
|
|
mcasp->dev = &pdev->dev;
|
|
mcasp->dev = &pdev->dev;
|
|
|
|
|
|
|
@@ -2021,6 +2239,40 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
mcasp_reparent_fck(pdev);
|
|
mcasp_reparent_fck(pdev);
|
|
|
|
|
|
|
|
|
|
+ if (mcasp->version == MCASP_VERSION_4) {
|
|
|
|
|
+ u32 rev;
|
|
|
|
|
+
|
|
|
|
|
+ pm_runtime_get_sync(mcasp->dev);
|
|
|
|
|
+ rev = mcasp_get_reg(mcasp, DAVINCI_MCASP_PID_REG) &
|
|
|
|
|
+ MCASP_V4_REV_MASK;
|
|
|
|
|
+ pm_runtime_put(mcasp->dev);
|
|
|
|
|
+
|
|
|
|
|
+ if (rev < MCASP_V4_REV(3, 3)) {
|
|
|
|
|
+ /*
|
|
|
|
|
+ * ERRATA i868: to avoid race condition between DMA and
|
|
|
|
|
+ * AFIFO events the R/WNUMEVT need to be set to be
|
|
|
|
|
+ * less-than-equal to 32 words.
|
|
|
|
|
+ */
|
|
|
|
|
+ if (mcasp->txnumevt)
|
|
|
|
|
+ mcasp->txnumevt = 32;
|
|
|
|
|
+ if (mcasp->rxnumevt)
|
|
|
|
|
+ mcasp->rxnumevt = 32;
|
|
|
|
|
+
|
|
|
|
|
+ if (mcasp->txnumevt || mcasp->rxnumevt)
|
|
|
|
|
+ dev_info(&pdev->dev,
|
|
|
|
|
+ "ERRATA i868 workaround is enabled\n");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* All PINS as McASP */
|
|
|
|
|
+ pm_runtime_get_sync(mcasp->dev);
|
|
|
|
|
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
|
|
|
|
|
+ pm_runtime_put(mcasp->dev);
|
|
|
|
|
+
|
|
|
|
|
+ ret = davinci_mcasp_init_gpiochip(mcasp);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ goto err;
|
|
|
|
|
+
|
|
|
ret = devm_snd_soc_register_component(&pdev->dev,
|
|
ret = devm_snd_soc_register_component(&pdev->dev,
|
|
|
&davinci_mcasp_component,
|
|
&davinci_mcasp_component,
|
|
|
&davinci_mcasp_dai[pdata->op_mode], 1);
|
|
&davinci_mcasp_dai[pdata->op_mode], 1);
|
|
@@ -2031,9 +2283,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
ret = davinci_mcasp_get_dma_type(mcasp);
|
|
ret = davinci_mcasp_get_dma_type(mcasp);
|
|
|
switch (ret) {
|
|
switch (ret) {
|
|
|
case PCM_EDMA:
|
|
case PCM_EDMA:
|
|
|
-#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
|
|
|
|
|
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
|
|
|
|
|
- IS_MODULE(CONFIG_SND_EDMA_SOC))
|
|
|
|
|
|
|
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \
|
|
|
|
|
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
|
|
|
|
|
+ IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM))
|
|
|
ret = edma_pcm_platform_register(&pdev->dev);
|
|
ret = edma_pcm_platform_register(&pdev->dev);
|
|
|
#else
|
|
#else
|
|
|
dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
|
|
dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
|
|
@@ -2042,14 +2294,25 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|
|
#endif
|
|
#endif
|
|
|
break;
|
|
break;
|
|
|
case PCM_SDMA:
|
|
case PCM_SDMA:
|
|
|
-#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
|
|
|
|
|
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
|
|
|
|
|
- IS_MODULE(CONFIG_SND_SDMA_SOC))
|
|
|
|
|
|
|
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \
|
|
|
|
|
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
|
|
|
|
|
+ IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM))
|
|
|
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
|
|
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
|
|
|
#else
|
|
#else
|
|
|
dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
|
|
dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
|
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
|
goto err;
|
|
goto err;
|
|
|
|
|
+#endif
|
|
|
|
|
+ break;
|
|
|
|
|
+ case PCM_UDMA:
|
|
|
|
|
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_UDMA_PCM) || \
|
|
|
|
|
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
|
|
|
|
|
+ IS_MODULE(CONFIG_SND_SOC_TI_UDMA_PCM))
|
|
|
|
|
+ ret = udma_pcm_platform_register(&pdev->dev);
|
|
|
|
|
+#else
|
|
|
|
|
+ dev_err(&pdev->dev, "Missing SND_SOC_TI_UDMA_PCM\n");
|
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
|
+ goto err;
|
|
|
#endif
|
|
#endif
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
@@ -2078,11 +2341,73 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
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 = {
|
|
static struct platform_driver davinci_mcasp_driver = {
|
|
|
.probe = davinci_mcasp_probe,
|
|
.probe = davinci_mcasp_probe,
|
|
|
.remove = davinci_mcasp_remove,
|
|
.remove = davinci_mcasp_remove,
|
|
|
.driver = {
|
|
.driver = {
|
|
|
.name = "davinci-mcasp",
|
|
.name = "davinci-mcasp",
|
|
|
|
|
+ .pm = &davinci_mcasp_pm_ops,
|
|
|
.of_match_table = mcasp_dt_ids,
|
|
.of_match_table = mcasp_dt_ids,
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|