forked from Minki/linux
Merge remote-tracking branches 'asoc/topic/fsl-easi', 'asoc/topic/fsl-sai', 'asoc/topic/fsl-ssi' and 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
57b027f697
@ -58,13 +58,7 @@ Optional properties:
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dma-names: Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
|
||||
is not defined.
|
||||
- fsl,mode: The operating mode for the SSI interface.
|
||||
"i2s-slave" - I2S mode, SSI is clock slave
|
||||
"i2s-master" - I2S mode, SSI is clock master
|
||||
"lj-slave" - left-justified mode, SSI is clock slave
|
||||
"lj-master" - l.j. mode, SSI is clock master
|
||||
"rj-slave" - right-justified mode, SSI is clock slave
|
||||
"rj-master" - r.j., SSI is clock master
|
||||
- fsl,mode: The operating mode for the AC97 interface only.
|
||||
"ac97-slave" - AC97 mode, SSI is clock slave
|
||||
"ac97-master" - AC97 mode, SSI is clock master
|
||||
|
||||
|
@ -20,9 +20,24 @@ Required properties:
|
||||
See ../pinctrl/pinctrl-bindings.txt for details of the property values.
|
||||
- big-endian: Boolean property, required if all the FTM_PWM registers
|
||||
are big-endian rather than little-endian.
|
||||
- big-endian-data: If this property is absent, the little endian mode will
|
||||
be in use as default, or the big endian mode will be in use for all the
|
||||
fifo data.
|
||||
- lsb-first: Configures whether the LSB or the MSB is transmitted first for
|
||||
the fifo data. If this property is absent, the MSB is transmitted first as
|
||||
default, or the LSB is transmitted first.
|
||||
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
|
||||
that SAI will work in the synchronous mode (sync Tx with Rx) which means
|
||||
both the transimitter and receiver will send and receive data by following
|
||||
receiver's bit clocks and frame sync clocks.
|
||||
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
|
||||
that SAI will work in the asynchronous mode, which means both transimitter
|
||||
and receiver will send and receive data by following their own bit clocks
|
||||
and frame sync clocks separately.
|
||||
|
||||
Note:
|
||||
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
|
||||
default synchronous mode (sync Rx with Tx) will be used, which means both
|
||||
transimitter and receiver will send and receive data by following clocks
|
||||
of transimitter.
|
||||
- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
|
||||
|
||||
Example:
|
||||
sai2: sai@40031000 {
|
||||
@ -38,5 +53,5 @@ sai2: sai@40031000 {
|
||||
dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
|
||||
<&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
|
||||
big-endian;
|
||||
big-endian-data;
|
||||
lsb-first;
|
||||
};
|
||||
|
@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt5640_dmic_enable(struct snd_soc_codec *codec,
|
||||
bool dmic1_data_pin, bool dmic2_data_pin)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
|
||||
|
||||
if (dmic1_data_pin) {
|
||||
regmap_update_bits(rt5640->regmap, RT5640_DMIC,
|
||||
RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
|
||||
}
|
||||
|
||||
if (dmic2_data_pin) {
|
||||
regmap_update_bits(rt5640->regmap, RT5640_DMIC,
|
||||
RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
|
||||
|
||||
static int rt5640_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (rt5640->pdata.dmic_en)
|
||||
rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
|
||||
rt5640->pdata.dmic2_data_pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2195,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
|
||||
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
|
||||
RT5640_IN_DF2, RT5640_IN_DF2);
|
||||
|
||||
if (rt5640->pdata.dmic_en) {
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
|
||||
|
||||
if (rt5640->pdata.dmic1_data_pin) {
|
||||
regmap_update_bits(rt5640->regmap, RT5640_DMIC,
|
||||
RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
|
||||
}
|
||||
|
||||
if (rt5640->pdata.dmic2_data_pin) {
|
||||
regmap_update_bits(rt5640->regmap, RT5640_DMIC,
|
||||
RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
|
||||
regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
|
||||
RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
|
||||
}
|
||||
}
|
||||
|
||||
rt5640->hp_mute = 1;
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
|
||||
|
@ -2097,4 +2097,7 @@ struct rt5640_priv {
|
||||
bool hp_mute;
|
||||
};
|
||||
|
||||
int rt5640_dmic_enable(struct snd_soc_codec *codec,
|
||||
bool dmic1_data_pin, bool dmic2_data_pin);
|
||||
|
||||
#endif
|
||||
|
@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
|
||||
bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
|
||||
u32 val_cr2 = 0, val_cr4 = 0;
|
||||
|
||||
if (!sai->big_endian_data)
|
||||
if (!sai->is_lsb_first)
|
||||
val_cr4 |= FSL_SAI_CR4_MF;
|
||||
|
||||
/* DAI mode */
|
||||
@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
|
||||
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
|
||||
|
||||
if (sai->big_endian_data)
|
||||
if (sai->is_lsb_first)
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(0);
|
||||
else
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
|
||||
@ -330,13 +330,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
u32 xcsr, count = 100;
|
||||
|
||||
/*
|
||||
* The transmitter bit clock and frame sync are to be
|
||||
* used by both the transmitter and receiver.
|
||||
* Asynchronous mode: Clear SYNC for both Tx and Rx.
|
||||
* Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
|
||||
* Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
|
||||
*/
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
|
||||
~FSL_SAI_CR2_SYNC);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
|
||||
FSL_SAI_CR2_SYNC);
|
||||
sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
|
||||
|
||||
/*
|
||||
* It is recommended that the transmitter is the last enabled
|
||||
@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
|
||||
/* Software Reset for both Tx and Rx */
|
||||
regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
|
||||
regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
|
||||
/* Clear SR bit to finish the reset */
|
||||
regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
|
||||
regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
|
||||
FSL_SAI_MAXBURST_TX * 2);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
|
||||
@ -568,7 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
|
||||
sai->sai_on_imx = true;
|
||||
|
||||
sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
|
||||
sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
@ -617,6 +622,33 @@ static int fsl_sai_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sync Tx with Rx as default by following old DT binding */
|
||||
sai->synchronous[RX] = true;
|
||||
sai->synchronous[TX] = false;
|
||||
fsl_sai_dai.symmetric_rates = 1;
|
||||
fsl_sai_dai.symmetric_channels = 1;
|
||||
fsl_sai_dai.symmetric_samplebits = 1;
|
||||
|
||||
if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
|
||||
of_find_property(np, "fsl,sai-asynchronous", NULL)) {
|
||||
/* error out if both synchronous and asynchronous are present */
|
||||
dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
|
||||
/* Sync Rx with Tx */
|
||||
sai->synchronous[RX] = false;
|
||||
sai->synchronous[TX] = true;
|
||||
} else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
|
||||
/* Discard all settings for asynchronous mode */
|
||||
sai->synchronous[RX] = false;
|
||||
sai->synchronous[TX] = false;
|
||||
fsl_sai_dai.symmetric_rates = 0;
|
||||
fsl_sai_dai.symmetric_channels = 0;
|
||||
fsl_sai_dai.symmetric_samplebits = 0;
|
||||
}
|
||||
|
||||
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
|
||||
sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
|
||||
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
|
||||
|
@ -48,6 +48,7 @@
|
||||
/* SAI Transmit/Recieve Control Register */
|
||||
#define FSL_SAI_CSR_TERE BIT(31)
|
||||
#define FSL_SAI_CSR_FR BIT(25)
|
||||
#define FSL_SAI_CSR_SR BIT(24)
|
||||
#define FSL_SAI_CSR_xF_SHIFT 16
|
||||
#define FSL_SAI_CSR_xF_W_SHIFT 18
|
||||
#define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT)
|
||||
@ -131,12 +132,16 @@ struct fsl_sai {
|
||||
struct clk *bus_clk;
|
||||
struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
|
||||
|
||||
bool big_endian_data;
|
||||
bool is_lsb_first;
|
||||
bool is_dsp_mode;
|
||||
bool sai_on_imx;
|
||||
bool synchronous[2];
|
||||
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
};
|
||||
|
||||
#define TX 1
|
||||
#define RX 0
|
||||
|
||||
#endif /* __FSL_SAI_H */
|
||||
|
@ -169,6 +169,7 @@ struct fsl_ssi_private {
|
||||
u8 i2s_mode;
|
||||
bool use_dma;
|
||||
bool use_dual_fifo;
|
||||
bool has_ipg_clk_name;
|
||||
unsigned int fifo_depth;
|
||||
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
|
||||
|
||||
@ -259,6 +260,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
|
||||
SND_SOC_DAIFMT_CBS_CFS;
|
||||
}
|
||||
|
||||
static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
|
||||
{
|
||||
return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
|
||||
SND_SOC_DAIFMT_CBM_CFS;
|
||||
}
|
||||
/**
|
||||
* fsl_ssi_isr: SSI interrupt handler
|
||||
*
|
||||
@ -525,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct fsl_ssi_private *ssi_private =
|
||||
snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(ssi_private->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* When using dual fifo mode, it is safer to ensure an even period
|
||||
* size. If appearing to an odd number while DMA always starts its
|
||||
@ -538,6 +549,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fsl_ssi_shutdown: shutdown the SSI
|
||||
*
|
||||
*/
|
||||
static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct fsl_ssi_private *ssi_private =
|
||||
snd_soc_dai_get_drvdata(rtd->cpu_dai);
|
||||
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
|
||||
*
|
||||
@ -705,6 +731,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
if (!fsl_ssi_is_ac97(ssi_private)) {
|
||||
u8 i2smode;
|
||||
/*
|
||||
* Switch to normal net mode in order to have a frame sync
|
||||
* signal every 32 bits instead of 16 bits
|
||||
*/
|
||||
if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
|
||||
i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
|
||||
CCSR_SSI_SCR_NET;
|
||||
else
|
||||
i2smode = ssi_private->i2s_mode;
|
||||
|
||||
regmap_update_bits(regs, CCSR_SSI_SCR,
|
||||
CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
|
||||
channels == 1 ? 0 : i2smode);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: The documentation says that SxCCR[WL] should not be
|
||||
* modified while the SSI is enabled. The only time this can
|
||||
@ -724,11 +767,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
|
||||
regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
|
||||
wl);
|
||||
|
||||
if (!fsl_ssi_is_ac97(ssi_private))
|
||||
regmap_update_bits(regs, CCSR_SSI_SCR,
|
||||
CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
|
||||
channels == 1 ? 0 : ssi_private->i2s_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -781,6 +819,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
|
||||
regmap_update_bits(regs, CCSR_SSI_STCCR,
|
||||
@ -854,6 +893,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
strcr &= ~CCSR_SSI_STCR_TXDIR;
|
||||
strcr |= CCSR_SSI_STCR_TFDIR;
|
||||
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1021,6 +1065,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
|
||||
|
||||
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
|
||||
.startup = fsl_ssi_startup,
|
||||
.shutdown = fsl_ssi_shutdown,
|
||||
.hw_params = fsl_ssi_hw_params,
|
||||
.hw_free = fsl_ssi_hw_free,
|
||||
.set_fmt = fsl_ssi_set_dai_fmt,
|
||||
@ -1146,17 +1191,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
|
||||
u32 dmas[4];
|
||||
int ret;
|
||||
|
||||
ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (ssi_private->has_ipg_clk_name)
|
||||
ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
else
|
||||
ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(ssi_private->clk)) {
|
||||
ret = PTR_ERR(ssi_private->clk);
|
||||
dev_err(&pdev->dev, "could not get clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ssi_private->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
if (!ssi_private->has_ipg_clk_name) {
|
||||
ret = clk_prepare_enable(ssi_private->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* For those SLAVE implementations, we ingore non-baudclk cases
|
||||
@ -1214,8 +1264,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
|
||||
return 0;
|
||||
|
||||
error_pcm:
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
|
||||
if (!ssi_private->has_ipg_clk_name)
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1224,7 +1275,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
|
||||
{
|
||||
if (!ssi_private->use_dma)
|
||||
imx_pcm_fiq_exit(pdev);
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
if (!ssi_private->has_ipg_clk_name)
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
}
|
||||
|
||||
static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
@ -1263,9 +1315,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
if (sprop) {
|
||||
if (!strcmp(sprop, "ac97-slave"))
|
||||
ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
|
||||
else if (!strcmp(sprop, "i2s-slave"))
|
||||
ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_CBM_CFM;
|
||||
}
|
||||
|
||||
ssi_private->use_dma = !of_property_read_bool(np,
|
||||
@ -1299,8 +1348,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
|
||||
ret = of_property_match_string(np, "clock-names", "ipg");
|
||||
if (ret < 0) {
|
||||
ssi_private->has_ipg_clk_name = false;
|
||||
ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
|
||||
&fsl_ssi_regconfig);
|
||||
} else {
|
||||
ssi_private->has_ipg_clk_name = true;
|
||||
ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
|
||||
"ipg", iomem, &fsl_ssi_regconfig);
|
||||
}
|
||||
if (IS_ERR(ssi_private->regs)) {
|
||||
dev_err(&pdev->dev, "Failed to init register map\n");
|
||||
return PTR_ERR(ssi_private->regs);
|
||||
|
@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = {
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
|
||||
.controls = byt_max98090_controls,
|
||||
.num_controls = ARRAY_SIZE(byt_max98090_controls),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int byt_max98090_probe(struct platform_device *pdev)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
|
||||
static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
|
||||
{"Headset Mic", NULL, "MICBIAS1"},
|
||||
{"IN2P", NULL, "Headset Mic"},
|
||||
{"IN2N", NULL, "Headset Mic"},
|
||||
{"DMIC1", NULL, "Internal Mic"},
|
||||
{"Headphone", NULL, "HPOL"},
|
||||
{"Headphone", NULL, "HPOR"},
|
||||
{"Speaker", NULL, "SPOLP"},
|
||||
@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
|
||||
{"Speaker", NULL, "SPORN"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
|
||||
{"DMIC1", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
|
||||
{"DMIC2", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
|
||||
{"Internal Mic", NULL, "MICBIAS1"},
|
||||
{"IN1P", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
enum {
|
||||
BYT_RT5640_DMIC1_MAP,
|
||||
BYT_RT5640_DMIC2_MAP,
|
||||
BYT_RT5640_IN1_MAP,
|
||||
};
|
||||
|
||||
#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
|
||||
#define BYT_RT5640_DMIC_EN BIT(16)
|
||||
|
||||
static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
|
||||
BYT_RT5640_DMIC_EN;
|
||||
|
||||
static const struct snd_kcontrol_new byt_rt5640_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
byt_rt5640_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
||||
{
|
||||
.callback = byt_rt5640_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
|
||||
},
|
||||
.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
|
||||
},
|
||||
{
|
||||
.callback = byt_rt5640_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
|
||||
},
|
||||
.driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
|
||||
BYT_RT5640_DMIC_EN),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
const struct snd_soc_dapm_route *custom_map;
|
||||
int num_routes;
|
||||
|
||||
card->dapm.idle_bias_off = true;
|
||||
|
||||
@ -93,6 +146,31 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dmi_check_system(byt_rt5640_quirk_table);
|
||||
switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
|
||||
case BYT_RT5640_IN1_MAP:
|
||||
custom_map = byt_rt5640_intmic_in1_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
|
||||
break;
|
||||
case BYT_RT5640_DMIC2_MAP:
|
||||
custom_map = byt_rt5640_intmic_dmic2_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
|
||||
break;
|
||||
default:
|
||||
custom_map = byt_rt5640_intmic_dmic1_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
|
||||
ret = rt5640_dmic_enable(codec, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_dapm_ignore_suspend(dapm, "HPOL");
|
||||
snd_soc_dapm_ignore_suspend(dapm, "HPOR");
|
||||
|
||||
@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = {
|
||||
.num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
|
||||
.dapm_routes = byt_rt5640_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int byt_rt5640_probe(struct platform_device *pdev)
|
||||
|
@ -25,6 +25,179 @@
|
||||
#include "sst-mfld-platform.h"
|
||||
#include "sst-atom-controls.h"
|
||||
|
||||
static int sst_fill_byte_control(struct sst_data *drv,
|
||||
u8 ipc_msg, u8 block,
|
||||
u8 task_id, u8 pipe_id,
|
||||
u16 len, void *cmd_data)
|
||||
{
|
||||
struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
|
||||
|
||||
byte_data->type = SST_CMD_BYTES_SET;
|
||||
byte_data->ipc_msg = ipc_msg;
|
||||
byte_data->block = block;
|
||||
byte_data->task_id = task_id;
|
||||
byte_data->pipe_id = pipe_id;
|
||||
|
||||
if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
|
||||
dev_err(&drv->pdev->dev, "command length too big (%u)", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
byte_data->len = len;
|
||||
memcpy(byte_data->bytes, cmd_data, len);
|
||||
print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
|
||||
byte_data, len + sizeof(*byte_data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
|
||||
u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
|
||||
void *cmd_data, u16 len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = sst_fill_byte_control(drv, ipc_msg,
|
||||
block, task_id, pipe_id, len, cmd_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* sst_fill_and_send_cmd - generate the IPC message and send it to the FW
|
||||
* @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS)
|
||||
* @cmd_data: the IPC payload
|
||||
*/
|
||||
static int sst_fill_and_send_cmd(struct sst_data *drv,
|
||||
u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
|
||||
void *cmd_data, u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&drv->lock);
|
||||
ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
|
||||
task_id, pipe_id, cmd_data, len);
|
||||
mutex_unlock(&drv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sst_send_algo_cmd(struct sst_data *drv,
|
||||
struct sst_algo_control *bc)
|
||||
{
|
||||
int len, ret = 0;
|
||||
struct sst_cmd_set_params *cmd;
|
||||
|
||||
/*bc->max includes sizeof algos + length field*/
|
||||
len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
|
||||
|
||||
cmd = kzalloc(len, GFP_KERNEL);
|
||||
if (cmd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
|
||||
cmd->command_id = bc->cmd_id;
|
||||
memcpy(cmd->params, bc->params, bc->max);
|
||||
|
||||
ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
|
||||
SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct sst_algo_control *bc = (void *)kcontrol->private_value;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
||||
uinfo->count = bc->max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct sst_algo_control *bc = (void *)kcontrol->private_value;
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
switch (bc->type) {
|
||||
case SST_ALGO_PARAMS:
|
||||
memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
|
||||
break;
|
||||
default:
|
||||
dev_err(component->dev, "Invalid Input- algo type:%d\n",
|
||||
bc->type);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int ret = 0;
|
||||
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
||||
struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct sst_algo_control *bc = (void *)kcontrol->private_value;
|
||||
|
||||
dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
|
||||
mutex_lock(&drv->lock);
|
||||
switch (bc->type) {
|
||||
case SST_ALGO_PARAMS:
|
||||
memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&drv->lock);
|
||||
dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
|
||||
bc->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*if pipe is enabled, need to send the algo params from here*/
|
||||
if (bc->w && bc->w->power)
|
||||
ret = sst_send_algo_cmd(drv, bc);
|
||||
mutex_unlock(&drv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new sst_algo_controls[] = {
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
|
||||
SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
|
||||
SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
|
||||
SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
|
||||
SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
|
||||
SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
|
||||
SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
|
||||
SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
|
||||
SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
|
||||
SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
|
||||
SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
|
||||
SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
|
||||
SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
|
||||
SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
|
||||
|
||||
};
|
||||
|
||||
static int sst_algo_control_init(struct device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
struct sst_algo_control *bc;
|
||||
/*allocate space to cache the algo parameters in the driver*/
|
||||
for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
|
||||
bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
|
||||
bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
|
||||
if (bc->params == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -35,5 +208,11 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
|
||||
if (!drv->byte_stream)
|
||||
return -ENOMEM;
|
||||
|
||||
/*Initialize algo control params*/
|
||||
ret = sst_algo_control_init(platform->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
|
||||
ARRAY_SIZE(sst_algo_controls));
|
||||
return ret;
|
||||
}
|
||||
|
@ -309,4 +309,134 @@ enum sst_swm_state {
|
||||
SST_SWM_ON = 3,
|
||||
};
|
||||
|
||||
#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \
|
||||
dst.location_id.p.cell_nbr_idx = (cell_idx); \
|
||||
dst.location_id.p.path_id = (pipe_id); \
|
||||
} while (0)
|
||||
#define SST_FILL_LOCATION_ID(dst, loc_id) (\
|
||||
dst.location_id.f = (loc_id))
|
||||
#define SST_FILL_MODULE_ID(dst, mod_id) (\
|
||||
dst.module_id = (mod_id))
|
||||
|
||||
#define SST_FILL_DESTINATION1(dst, id) do { \
|
||||
SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \
|
||||
SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \
|
||||
} while (0)
|
||||
#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \
|
||||
SST_FILL_LOCATION_ID(dst, loc_id); \
|
||||
SST_FILL_MODULE_ID(dst, mod_id); \
|
||||
} while (0)
|
||||
#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \
|
||||
SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \
|
||||
SST_FILL_MODULE_ID(dst, mod_id); \
|
||||
} while (0)
|
||||
|
||||
#define SST_FILL_DESTINATION(level, dst, ...) \
|
||||
SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
|
||||
#define SST_FILL_DEFAULT_DESTINATION(dst) \
|
||||
SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
|
||||
|
||||
struct sst_destination_id {
|
||||
union sst_location_id {
|
||||
struct {
|
||||
u8 cell_nbr_idx; /* module index */
|
||||
u8 path_id; /* pipe_id */
|
||||
} __packed p; /* part */
|
||||
u16 f; /* full */
|
||||
} __packed location_id;
|
||||
u16 module_id;
|
||||
} __packed;
|
||||
struct sst_dsp_header {
|
||||
struct sst_destination_id dst;
|
||||
u16 command_id;
|
||||
u16 length;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
*
|
||||
* Common Commands
|
||||
*
|
||||
*/
|
||||
struct sst_cmd_generic {
|
||||
struct sst_dsp_header header;
|
||||
} __packed;
|
||||
struct sst_cmd_set_params {
|
||||
struct sst_destination_id dst;
|
||||
u16 command_id;
|
||||
char params[0];
|
||||
} __packed;
|
||||
#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
|
||||
xpname " " xmname " " #xinstance " " xtype
|
||||
|
||||
#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
|
||||
xpname " " xmname " " #xinstance " " xtype " " xsubmodule
|
||||
enum sst_algo_kcontrol_type {
|
||||
SST_ALGO_PARAMS,
|
||||
SST_ALGO_BYPASS,
|
||||
};
|
||||
|
||||
struct sst_algo_control {
|
||||
enum sst_algo_kcontrol_type type;
|
||||
int max;
|
||||
u16 module_id;
|
||||
u16 pipe_id;
|
||||
u16 task_id;
|
||||
u16 cmd_id;
|
||||
bool bypass;
|
||||
unsigned char *params;
|
||||
struct snd_soc_dapm_widget *w;
|
||||
};
|
||||
|
||||
/* size of the control = size of params + size of length field */
|
||||
#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \
|
||||
(struct sst_algo_control){ \
|
||||
.max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \
|
||||
.pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \
|
||||
}
|
||||
|
||||
#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \
|
||||
xtask, xcmd, xtype, xinfo, xget, xput) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||
.name = xname, \
|
||||
.info = xinfo, .get = xget, .put = xput, \
|
||||
.private_value = (unsigned long)& \
|
||||
SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \
|
||||
xmod, xtask, xcmd), \
|
||||
}
|
||||
|
||||
#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \
|
||||
xpipe, xinstance, xtask, xcmd) \
|
||||
SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \
|
||||
xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \
|
||||
sst_algo_bytes_ctl_info, \
|
||||
sst_algo_control_get, sst_algo_control_set)
|
||||
|
||||
#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \
|
||||
SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \
|
||||
0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \
|
||||
snd_soc_info_bool_ext, \
|
||||
sst_algo_control_get, sst_algo_control_set)
|
||||
|
||||
#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \
|
||||
xinstance, xtask, xcmd) \
|
||||
SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \
|
||||
SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
|
||||
|
||||
#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \
|
||||
xpipe, xinstance, xtask, xcmd) \
|
||||
SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \
|
||||
xsubmod), \
|
||||
xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \
|
||||
sst_algo_bytes_ctl_info, \
|
||||
sst_algo_control_get, sst_algo_control_set)
|
||||
|
||||
|
||||
struct sst_enum {
|
||||
bool tx;
|
||||
unsigned short reg;
|
||||
unsigned int max;
|
||||
const char * const *texts;
|
||||
struct snd_soc_dapm_widget *w;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev)
|
||||
return -ENODEV;
|
||||
mutex_lock(&sst_lock);
|
||||
if (sst) {
|
||||
pr_err("we already have a device %s\n", sst->name);
|
||||
dev_err(dev->dev, "we already have a device %s\n", sst->name);
|
||||
module_put(dev->dev->driver->owner);
|
||||
mutex_unlock(&sst_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
pr_debug("registering device %s\n", dev->name);
|
||||
dev_dbg(dev->dev, "registering device %s\n", dev->name);
|
||||
sst = dev;
|
||||
mutex_unlock(&sst_lock);
|
||||
return 0;
|
||||
@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev)
|
||||
}
|
||||
|
||||
module_put(sst->dev->driver->owner);
|
||||
pr_debug("unreg %s\n", sst->name);
|
||||
dev_dbg(dev->dev, "unreg %s\n", sst->name);
|
||||
sst = NULL;
|
||||
mutex_unlock(&sst_lock);
|
||||
return 0;
|
||||
@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream,
|
||||
}
|
||||
|
||||
static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_platform *platform)
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sst_runtime_stream *stream =
|
||||
substream->runtime->private_data;
|
||||
@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
|
||||
struct snd_sst_params str_params = {0};
|
||||
struct snd_sst_alloc_params_ext alloc_params = {0};
|
||||
int ret_val = 0;
|
||||
struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
|
||||
struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
/* set codec params and inform SST driver the same */
|
||||
sst_fill_pcm_params(substream, ¶m);
|
||||
@ -306,9 +306,10 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct sst_runtime_stream *stream =
|
||||
substream->runtime->private_data;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
int ret_val;
|
||||
|
||||
pr_debug("setting buffer ptr param\n");
|
||||
dev_dbg(rtd->dev, "setting buffer ptr param\n");
|
||||
sst_set_stream_status(stream, SST_PLATFORM_INIT);
|
||||
stream->stream_info.period_elapsed = sst_period_elapsed;
|
||||
stream->stream_info.arg = substream;
|
||||
@ -316,11 +317,21 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
|
||||
stream->stream_info.sfreq = substream->runtime->rate;
|
||||
ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
|
||||
if (ret_val)
|
||||
pr_err("control_set ret error %d\n", ret_val);
|
||||
dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
static int power_up_sst(struct sst_runtime_stream *stream)
|
||||
{
|
||||
return stream->ops->power(sst->dev, true);
|
||||
}
|
||||
|
||||
static void power_down_sst(struct sst_runtime_stream *stream)
|
||||
{
|
||||
stream->ops->power(sst->dev, false);
|
||||
}
|
||||
|
||||
static int sst_media_open(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -337,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
|
||||
mutex_lock(&sst_lock);
|
||||
if (!sst ||
|
||||
!try_module_get(sst->dev->driver->owner)) {
|
||||
pr_err("no device available to run\n");
|
||||
dev_err(dai->dev, "no device available to run\n");
|
||||
ret_val = -ENODEV;
|
||||
goto out_ops;
|
||||
}
|
||||
@ -350,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream,
|
||||
/* allocate memory for SST API set */
|
||||
runtime->private_data = stream;
|
||||
|
||||
ret_val = power_up_sst(stream);
|
||||
if (ret_val < 0)
|
||||
return ret_val;
|
||||
|
||||
/* Make sure, that the period size is always even */
|
||||
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS, 2);
|
||||
@ -369,6 +384,8 @@ static void sst_media_close(struct snd_pcm_substream *substream,
|
||||
int ret_val = 0, str_id;
|
||||
|
||||
stream = substream->runtime->private_data;
|
||||
power_down_sst(stream);
|
||||
|
||||
str_id = stream->stream_info.str_id;
|
||||
if (str_id)
|
||||
ret_val = stream->ops->close(sst->dev, str_id);
|
||||
@ -376,19 +393,20 @@ static void sst_media_close(struct snd_pcm_substream *substream,
|
||||
kfree(stream);
|
||||
}
|
||||
|
||||
static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform,
|
||||
static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct sst_data *sst = snd_soc_platform_get_drvdata(platform);
|
||||
struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
|
||||
struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
|
||||
struct sst_runtime_stream *stream =
|
||||
substream->runtime->private_data;
|
||||
u32 str_id = stream->stream_info.str_id;
|
||||
unsigned int pipe_id;
|
||||
|
||||
pipe_id = map[str_id].device_id;
|
||||
|
||||
pr_debug("%s: got pipe_id = %#x for str_id = %d\n",
|
||||
__func__, pipe_id, str_id);
|
||||
dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
|
||||
pipe_id, str_id);
|
||||
return pipe_id;
|
||||
}
|
||||
|
||||
@ -405,7 +423,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream,
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = sst_platform_alloc_stream(substream, dai->platform);
|
||||
ret_val = sst_platform_alloc_stream(substream, dai);
|
||||
if (ret_val <= 0)
|
||||
return ret_val;
|
||||
snprintf(substream->pcm->id, sizeof(substream->pcm->id),
|
||||
@ -459,29 +477,32 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
int ret_val = 0, str_id;
|
||||
struct sst_runtime_stream *stream;
|
||||
int status;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
||||
pr_debug("sst_platform_pcm_trigger called\n");
|
||||
dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
|
||||
if (substream->pcm->internal)
|
||||
return 0;
|
||||
stream = substream->runtime->private_data;
|
||||
str_id = stream->stream_info.str_id;
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
pr_debug("sst: Trigger Start\n");
|
||||
dev_dbg(rtd->dev, "sst: Trigger Start\n");
|
||||
status = SST_PLATFORM_RUNNING;
|
||||
stream->stream_info.arg = substream;
|
||||
ret_val = stream->ops->stream_start(sst->dev, str_id);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
pr_debug("sst: in stop\n");
|
||||
dev_dbg(rtd->dev, "sst: in stop\n");
|
||||
status = SST_PLATFORM_DROPPED;
|
||||
ret_val = stream->ops->stream_drop(sst->dev, str_id);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
pr_debug("sst: in pause\n");
|
||||
dev_dbg(rtd->dev, "sst: in pause\n");
|
||||
status = SST_PLATFORM_PAUSED;
|
||||
ret_val = stream->ops->stream_pause(sst->dev, str_id);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
pr_debug("sst: in pause release\n");
|
||||
dev_dbg(rtd->dev, "sst: in pause release\n");
|
||||
status = SST_PLATFORM_RUNNING;
|
||||
ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
|
||||
break;
|
||||
@ -502,6 +523,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
|
||||
struct sst_runtime_stream *stream;
|
||||
int ret_val, status;
|
||||
struct pcm_stream_info *str_info;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
||||
stream = substream->runtime->private_data;
|
||||
status = sst_get_stream_status(stream);
|
||||
@ -510,7 +532,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
|
||||
str_info = &stream->stream_info;
|
||||
ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
|
||||
if (ret_val) {
|
||||
pr_err("sst: error code = %d\n", ret_val);
|
||||
dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
substream->runtime->delay = str_info->pcm_delay;
|
||||
@ -526,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = {
|
||||
|
||||
static void sst_pcm_free(struct snd_pcm *pcm)
|
||||
{
|
||||
pr_debug("sst_pcm_free called\n");
|
||||
dev_dbg(pcm->dev, "sst_pcm_free called\n");
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
@ -543,7 +565,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
snd_dma_continuous_data(GFP_DMA),
|
||||
SST_MIN_BUFFER, SST_MAX_BUFFER);
|
||||
if (retval) {
|
||||
pr_err("dma buffer allocationf fail\n");
|
||||
dev_err(rtd->dev, "dma buffer allocationf fail\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@ -576,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev)
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
|
||||
if (drv == NULL) {
|
||||
pr_err("kzalloc failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (pdata == NULL) {
|
||||
pr_err("kzalloc failed for pdata\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -594,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev)
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
|
||||
if (ret) {
|
||||
pr_err("registering soc platform failed\n");
|
||||
dev_err(&pdev->dev, "registering soc platform failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &sst_component,
|
||||
sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
|
||||
if (ret) {
|
||||
pr_err("registering cpu dais failed\n");
|
||||
dev_err(&pdev->dev, "registering cpu dais failed\n");
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
}
|
||||
return ret;
|
||||
@ -612,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev)
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
pr_debug("sst_platform_remove success\n");
|
||||
dev_dbg(&pdev->dev, "sst_platform_remove success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -120,15 +120,16 @@ struct compress_sst_ops {
|
||||
};
|
||||
|
||||
struct sst_ops {
|
||||
int (*open) (struct device *dev, struct snd_sst_params *str_param);
|
||||
int (*stream_init) (struct device *dev, struct pcm_stream_info *str_info);
|
||||
int (*stream_start) (struct device *dev, int str_id);
|
||||
int (*stream_drop) (struct device *dev, int str_id);
|
||||
int (*stream_pause) (struct device *dev, int str_id);
|
||||
int (*stream_pause_release) (struct device *dev, int str_id);
|
||||
int (*stream_read_tstamp) (struct device *dev, struct pcm_stream_info *str_info);
|
||||
int (*open)(struct device *dev, struct snd_sst_params *str_param);
|
||||
int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
|
||||
int (*stream_start)(struct device *dev, int str_id);
|
||||
int (*stream_drop)(struct device *dev, int str_id);
|
||||
int (*stream_pause)(struct device *dev, int str_id);
|
||||
int (*stream_pause_release)(struct device *dev, int str_id);
|
||||
int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
|
||||
int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
|
||||
int (*close) (struct device *dev, unsigned int str_id);
|
||||
int (*close)(struct device *dev, unsigned int str_id);
|
||||
int (*power)(struct device *dev, bool state);
|
||||
};
|
||||
|
||||
struct sst_runtime_stream {
|
||||
@ -166,7 +167,7 @@ struct sst_algo_int_control_v2 {
|
||||
struct sst_data {
|
||||
struct platform_device *pdev;
|
||||
struct sst_platform_data *pdata;
|
||||
char *byte_stream;
|
||||
struct snd_sst_bytes_v2 *byte_stream;
|
||||
struct mutex lock;
|
||||
};
|
||||
int sst_register_dsp(struct sst_device *sst);
|
||||
|
Loading…
Reference in New Issue
Block a user