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:
Mark Brown 2014-10-06 12:48:59 +01:00
13 changed files with 621 additions and 94 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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,6 +1191,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
u32 dmas[4];
int ret;
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);
@ -1153,11 +1201,13 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
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
* and, instead, abandon MASTER mode that needs baud clock.
@ -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,6 +1275,7 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
{
if (!ssi_private->use_dma)
imx_pcm_fiq_exit(pdev);
if (!ssi_private->has_ipg_clk_name)
clk_disable_unprepare(ssi_private->clk);
}
@ -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;
}
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);

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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, &param);
@ -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;
}

View File

@ -129,6 +129,7 @@ struct sst_ops {
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 (*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);