Commit 343b8908 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ab8500', 'asoc/topic/adau17x1',...

Merge remote-tracking branches 'asoc/topic/ab8500', 'asoc/topic/adau17x1', 'asoc/topic/ads117x', 'asoc/topic/adsp' and 'asoc/topic/arizona' into asoc-next
Analog Devices ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781
Required properties:
- compatible: Should contain one of the following:
"adi,adau1361"
"adi,adau1461"
"adi,adau1761"
"adi,adau1961"
"adi,adau1381"
"adi,adau1781"
- reg: The i2c address. Value depends on the state of ADDR0
and ADDR1, as wired in hardware.
Examples:
#include <dt-bindings/sound/adau17x1.h>
i2c_bus {
adau1361@38 {
compatible = "adi,adau1761";
reg = <0x38>;
};
};
Texas Intstruments ADS117x ADC
Required properties:
- compatible : "ti,ads1174" or "ti,ads1178"
Example:
ads1178 {
compatible = "ti,ads1178";
};
/*
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961/ADAU1781/ADAU1781 codecs
* Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781 codecs
*
* Copyright 2011-2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......
......@@ -2134,7 +2134,6 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
break;
}
snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
......
/*
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
* Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
*
* Copyright 2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......@@ -44,9 +44,21 @@ static const struct i2c_device_id adau1761_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
#if defined(CONFIG_OF)
static const struct of_device_id adau1761_i2c_dt_ids[] = {
{ .compatible = "adi,adau1361", },
{ .compatible = "adi,adau1461", },
{ .compatible = "adi,adau1761", },
{ .compatible = "adi,adau1961", },
{ },
};
MODULE_DEVICE_TABLE(of, adau1761_i2c_dt_ids);
#endif
static struct i2c_driver adau1761_i2c_driver = {
.driver = {
.name = "adau1761",
.of_match_table = of_match_ptr(adau1761_i2c_dt_ids),
},
.probe = adau1761_i2c_probe,
.remove = adau1761_i2c_remove,
......
/*
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
* Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
*
* Copyright 2014 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......@@ -61,9 +61,21 @@ static const struct spi_device_id adau1761_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
#if defined(CONFIG_OF)
static const struct of_device_id adau1761_spi_dt_ids[] = {
{ .compatible = "adi,adau1361", },
{ .compatible = "adi,adau1461", },
{ .compatible = "adi,adau1761", },
{ .compatible = "adi,adau1961", },
{ },
};
MODULE_DEVICE_TABLE(of, adau1761_spi_dt_ids);
#endif
static struct spi_driver adau1761_spi_driver = {
.driver = {
.name = "adau1761",
.of_match_table = of_match_ptr(adau1761_spi_dt_ids),
},
.probe = adau1761_spi_probe,
.remove = adau1761_spi_remove,
......
/*
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
* Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
*
* Copyright 2011-2013 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......@@ -456,13 +456,17 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
regcache_cache_only(adau->regmap, false);
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
regcache_sync(adau->regmap);
break;
case SND_SOC_BIAS_OFF:
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
regcache_cache_only(adau->regmap, true);
break;
}
......@@ -783,6 +787,10 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
/* Enable cache only mode as we could miss writes before bias level
* reaches standby and the core clock is enabled */
regcache_cache_only(regmap, true);
return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
}
EXPORT_SYMBOL_GPL(adau1761_probe);
......
......@@ -42,9 +42,19 @@ static const struct i2c_device_id adau1781_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
#if defined(CONFIG_OF)
static const struct of_device_id adau1781_i2c_dt_ids[] = {
{ .compatible = "adi,adau1381", },
{ .compatible = "adi,adau1781", },
{ },
};
MODULE_DEVICE_TABLE(of, adau1781_i2c_dt_ids);
#endif
static struct i2c_driver adau1781_i2c_driver = {
.driver = {
.name = "adau1781",
.of_match_table = of_match_ptr(adau1781_i2c_dt_ids),
},
.probe = adau1781_i2c_probe,
.remove = adau1781_i2c_remove,
......
......@@ -59,9 +59,19 @@ static const struct spi_device_id adau1781_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, adau1781_spi_id);
#if defined(CONFIG_OF)
static const struct of_device_id adau1781_spi_dt_ids[] = {
{ .compatible = "adi,adau1381", },
{ .compatible = "adi,adau1781", },
{ },
};
MODULE_DEVICE_TABLE(of, adau1781_spi_dt_ids);
#endif
static struct spi_driver adau1781_spi_driver = {
.driver = {
.name = "adau1781",
.of_match_table = of_match_ptr(adau1781_spi_dt_ids),
},
.probe = adau1781_spi_probe,
.remove = adau1781_spi_remove,
......
/*
* Driver for ADAU1781/ADAU1781 codec
* Driver for ADAU1381/ADAU1781 codec
*
* Copyright 2011-2013 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
......
......@@ -20,6 +20,8 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <linux/of.h>
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
......@@ -75,9 +77,19 @@ static int ads117x_remove(struct platform_device *pdev)
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id ads117x_dt_ids[] = {
{ .compatible = "ti,ads1174" },
{ .compatible = "ti,ads1178" },
{ },
};
MODULE_DEVICE_TABLE(of, ads117x_dt_ids);
#endif
static struct platform_driver ads117x_codec_driver = {
.driver = {
.name = "ads117x-codec",
.of_match_table = of_match_ptr(ads117x_dt_ids),
},
.probe = ads117x_probe,
......
......@@ -1398,29 +1398,6 @@ static const int arizona_48k_bclk_rates[] = {
24576000,
};
static const unsigned int arizona_48k_rates[] = {
12000,
24000,
48000,
96000,
192000,
384000,
768000,
4000,
8000,
16000,
32000,
64000,
128000,
256000,
512000,
};
static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
.count = ARRAY_SIZE(arizona_48k_rates),
.list = arizona_48k_rates,
};
static const int arizona_44k1_bclk_rates[] = {
-1,
44100,
......@@ -1443,22 +1420,7 @@ static const int arizona_44k1_bclk_rates[] = {
22579200,
};
static const unsigned int arizona_44k1_rates[] = {
11025,
22050,
44100,
88200,
176400,
352800,
705600,
};
static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
.count = ARRAY_SIZE(arizona_44k1_rates),
.list = arizona_44k1_rates,
};
static int arizona_sr_vals[] = {
static const unsigned int arizona_sr_vals[] = {
0,
12000,
24000,
......@@ -1485,13 +1447,21 @@ static int arizona_sr_vals[] = {
512000,
};
#define ARIZONA_48K_RATE_MASK 0x0F003E
#define ARIZONA_44K1_RATE_MASK 0x003E00
#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
static const struct snd_pcm_hw_constraint_list arizona_constraint = {
.count = ARRAY_SIZE(arizona_sr_vals),
.list = arizona_sr_vals,
};
static int arizona_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
const struct snd_pcm_hw_constraint_list *constraint;
unsigned int base_rate;
if (!substream->runtime)
......@@ -1509,16 +1479,15 @@ static int arizona_startup(struct snd_pcm_substream *substream,
}
if (base_rate == 0)
return 0;
if (base_rate % 8000)
constraint = &arizona_44k1_constraint;
dai_priv->constraint.mask = ARIZONA_RATE_MASK;
else if (base_rate % 8000)
dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
else
constraint = &arizona_48k_constraint;
dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
constraint);
&dai_priv->constraint);
}
static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
......@@ -1911,6 +1880,7 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
struct arizona_dai_priv *dai_priv = &priv->dai[id];
dai_priv->clk = ARIZONA_CLK_SYSCLK;
dai_priv->constraint = arizona_constraint;
return 0;
}
......@@ -2179,11 +2149,12 @@ static int arizona_calc_fll(struct arizona_fll *fll,
return -EINVAL;
}
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
cfg->fratio, ratio, cfg->outdiv,
cfg->refdiv, 1 << cfg->refdiv);
arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
return 0;
......
......@@ -57,7 +57,7 @@
#define ARIZONA_CLK_98MHZ 5
#define ARIZONA_CLK_147MHZ 6
#define ARIZONA_MAX_DAI 8
#define ARIZONA_MAX_DAI 10
#define ARIZONA_MAX_ADSP 4
#define ARIZONA_DVFS_SR1_RQ 0x001
......@@ -68,6 +68,8 @@ struct wm_adsp;
struct arizona_dai_priv {
int clk;
struct snd_pcm_hw_constraint_list constraint;
};
struct arizona_priv {
......
......@@ -57,6 +57,25 @@ static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
cs47l24_dsp3_regions,
};
static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
unsigned int v;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
return ret;
}
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
return wm_adsp2_early_event(w, kcontrol, event, v);
}
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
......@@ -405,8 +424,8 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
WM_ADSP2("DSP2", 1),
WM_ADSP2("DSP3", 2),
WM_ADSP2("DSP2", 1, cs47l24_adsp_power_ev),
WM_ADSP2("DSP3", 2, cs47l24_adsp_power_ev),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
......@@ -779,6 +798,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
{ "AIF2 Capture", NULL, "SYSCLK" },
{ "AIF3 Capture", NULL, "SYSCLK" },
{ "Voice Control DSP", NULL, "DSP3" },
{ "Voice Control DSP", NULL, "SYSCLK" },
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
......@@ -901,7 +923,7 @@ static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000
#define CS47L24_RATES SNDRV_PCM_RATE_KNOT
#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
......@@ -973,12 +995,68 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.symmetric_rates = 1,
.symmetric_samplebits = 1,
},
{
.name = "cs47l24-cpu-voicectrl",
.capture = {
.stream_name = "Voice Control CPU",
.channels_min = 1,
.channels_max = 1,
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
.compress_new = snd_soc_new_compress,
},
{
.name = "cs47l24-dsp-voicectrl",
.capture = {
.stream_name = "Voice Control DSP",
.channels_min = 1,
.channels_max = 1,
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
},
};
static int cs47l24_open(struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
struct arizona *arizona = priv->core.arizona;
int n_adsp;
if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) {
n_adsp = 2;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
rtd->codec_dai->name);
return -EINVAL;
}
return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
}
static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
{
struct cs47l24_priv *priv = data;
struct arizona *arizona = priv->core.arizona;
int ret;
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]);
if (ret == -ENODEV) {
dev_err(arizona->dev, "Spurious compressed data IRQ\n");
return IRQ_NONE;
}
return IRQ_HANDLED;
}
static int cs47l24_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->core.arizona;
int ret;
priv->core.arizona->dapm = dapm;
......@@ -987,6 +1065,14 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
"ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
priv);
if (ret != 0) {
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
return ret;
}
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
if (ret)
goto err_adsp2_codec_probe;
......@@ -1014,13 +1100,14 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
static int cs47l24_codec_remove(struct snd_soc_codec *codec)
{
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->core.arizona;
wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
priv->core.arizona->dapm = NULL;
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
return 0;
}
......@@ -1057,6 +1144,19 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
};
static struct snd_compr_ops cs47l24_compr_ops = {
.open = cs47l24_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
.get_caps = wm_adsp_compr_get_caps,
.trigger = wm_adsp_compr_trigger,
.pointer = wm_adsp_compr_pointer,
.copy = wm_adsp_compr_copy,
};
static struct snd_soc_platform_driver cs47l24_compr_platform = {
.compr_ops = &cs47l24_compr_ops,
};
static int cs47l24_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
......@@ -1120,12 +1220,25 @@ static int cs47l24_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
return ret;
}
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
snd_soc_unregister_platform(&pdev->dev);
}
return ret;
}
static int cs47l24_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......
......@@ -619,7 +619,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
unsigned int v;
unsigned int v = 0;
int ret;
switch (event) {
......@@ -654,7 +654,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
break;
}
return wm_adsp2_early_event(w, kcontrol, event);
return wm_adsp2_early_event(w, kcontrol, event, v);
}
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
......@@ -1408,7 +1408,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
WM_ADSP2("DSP1", 0, wm5102_adsp_power_ev),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
......@@ -1599,6 +1599,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "Slim2 Capture", NULL, "SYSCLK" },
{ "Slim3 Capture", NULL, "SYSCLK" },
{ "Audio Trace DSP", NULL, "DSP1" },
{ "Audio Trace DSP", NULL, "SYSCLK" },
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
......@@ -1735,7 +1738,7 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
#define WM5102_RATES SNDRV_PCM_RATE_8000_192000
#define WM5102_RATES SNDRV_PCM_RATE_KNOT
#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
......@@ -1864,14 +1867,67 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
},
.ops = &arizona_simple_dai_ops,
},
{
.name = "wm5102-cpu-trace",
.capture = {
.stream_name = "Audio Trace CPU",
.channels_min = 1,
.channels_max = 6,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
.compress_new = snd_soc_new_compress,
},
{
.name = "wm5102-dsp-trace",
.capture = {
.stream_name = "Audio Trace DSP",
.channels_min = 1,
.channels_max = 4,
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
},
};
static int wm5102_open(struct snd_compr_stream *stream)
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
return wm_adsp_compr_open(&priv->core.adsp[0], stream);
}
static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
{
struct wm5102_priv *priv = data;
struct arizona *arizona = priv->core.arizona;
int ret;
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[0]);
if (ret == -ENODEV) {
dev_err(arizona->dev, "Spurious compressed data IRQ\n");
return IRQ_NONE;
}
return IRQ_HANDLED;
}
static int wm5102_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->core.arizona;
int ret;
ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
"ADSP2 Compressed IRQ", wm5102_adsp2_irq,
priv);
if (ret != 0) {
dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
return ret;
}
ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
if (ret)
return ret;
......@@ -1946,6 +2002,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
};
static struct snd_compr_ops wm5102_compr_ops = {
.open = wm5102_open,
.free = wm_adsp_compr_free,
.set_params = wm_adsp_compr_set_params,
.get_caps = wm_adsp_compr_get_caps,
.trigger = wm_adsp_compr_trigger,
.pointer = wm_adsp_compr_pointer,
.copy = wm_adsp_compr_copy,
};
static struct snd_soc_platform_driver wm5102_compr_platform = {
.compr_ops = &wm5102_compr_ops,
};
static int wm5102_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
......@@ -2005,12 +2075,25 @@ static int wm5102_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
return ret;
}
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
wm5102_dai, ARRAY_SIZE(wm5102_dai));
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
snd_soc_unregister_platform(&pdev->dev);
}
return ret;
}
static int wm5102_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......
......@@ -191,6 +191,25 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
return 0;
}
static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
unsigned int v;
int ret;
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
return ret;
}
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
return wm_adsp2_early_event(w, kcontrol, event, v);
}
static const struct reg_sequence wm5110_no_dre_left_enable[] = {
{ 0x3024, 0xE410 },
{ 0x3025, 0x0056 },
......@@ -1179,10 +1198,10 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
WM_ADSP2("DSP1", 0),
WM_ADSP2("DSP2", 1),
WM_ADSP2("DSP3", 2),
WM_ADSP2("DSP4", 3),
WM_ADSP2("DSP1", 0, wm5110_adsp_power_ev),
WM_ADSP2("DSP2", 1, wm5110_adsp_power_ev),
WM_ADSP2("DSP3", 2, wm5110_adsp_power_ev),
WM_ADSP2("DSP4", 3, wm5110_adsp_power_ev),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
......@@ -1809,6 +1828,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "Voice Control DSP", NULL, "DSP3" },
{ "Voice Control DSP", NULL, "SYSCLK" },
{ "Audio Trace DSP", NULL, "DSP1" },
{ "Audio Trace DSP", NULL, "SYSCLK" },
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
......@@ -2002,7 +2024,7 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
#define WM5110_RATES SNDRV_PCM_RATE_8000_192000
#define WM5110_RATES SNDRV_PCM_RATE_KNOT
#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
......@@ -2152,6 +2174,27 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.formats = WM5110_FORMATS,
},
},
{
.name = "wm5110-cpu-trace",
.capture = {
.stream_name = "Audio Trace CPU",
.channels_min = 1,
.channels_max = 6,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.compress_new = snd_soc_new_compress,
},
{
.name = "wm5110-dsp-trace",
.capture = {
.stream_name = "Audio Trace DSP",
.channels_min = 1,
.channels_max = 6,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
},
};
static int wm5110_open(struct snd_compr_stream *stream)
......@@ -2163,6 +2206,8 @@ static int wm5110_open(struct snd_compr_stream *stream)
if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
n_adsp = 2;
} else if (strcmp(rtd->codec_dai->name, "wm5110-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
......@@ -2175,12 +2220,21 @@ static int wm5110_open(struct snd_compr_stream *stream)
static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
{
struct wm5110_priv *florida = data;
int ret;
struct wm5110_priv *priv = data;
struct arizona *arizona = priv->core.arizona;
int serviced = 0;
int i, ret;
ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
if (ret == -ENODEV)
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
if (ret != -ENODEV)
serviced++;
}
if (!serviced) {
dev_err(arizona->dev, "Spurious compressed data IRQ\n");
return IRQ_NONE;
}
return IRQ_HANDLED;
}
......@@ -2366,7 +2420,7 @@ static int wm5110_probe(struct platform_device *pdev)
ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
goto error;
return ret;
}
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
......@@ -2376,7 +2430,6 @@ static int wm5110_probe(struct platform_device *pdev)
snd_soc_unregister_platform(&pdev->dev);
}
error:
return ret;
}
......
......@@ -943,7 +943,7 @@ static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
#define WM8997_RATES SNDRV_PCM_RATE_8000_192000
#define WM8997_RATES SNDRV_PCM_RATE_KNOT
#define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
......
......@@ -1170,7 +1170,7 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = {
{ "DRC1 Signal Activity", NULL, "DRC1R" },
};
#define WM8998_RATES SNDRV_PCM_RATE_8000_192000
#define WM8998_RATES SNDRV_PCM_RATE_KNOT
#define WM8998_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
......
......@@ -32,9 +32,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
#include "wm_adsp.h"
#define adsp_crit(_dsp, fmt, ...) \
......@@ -295,6 +292,8 @@ struct wm_adsp_compr {
u32 *raw_buf;
unsigned int copied_total;
unsigned int sample_rate;
};
#define WM_ADSP_DATA_WORD_SIZE 3
......@@ -328,7 +327,7 @@ struct wm_adsp_buffer_region_def {
unsigned int size_offset;
};
static struct wm_adsp_buffer_region_def ez2control_regions[] = {
static const struct wm_adsp_buffer_region_def default_regions[] = {
{
.mem_type = WMFW_ADSP2_XM,
.base_offset = HOST_BUFFER_FIELD(X_buf_base),
......@@ -350,10 +349,10 @@ struct wm_adsp_fw_caps {
u32 id;
struct snd_codec_desc desc;
int num_regions;
struct wm_adsp_buffer_region_def *region_defs;
const struct wm_adsp_buffer_region_def *region_defs;
};
static const struct wm_adsp_fw_caps ez2control_caps[] = {
static const struct wm_adsp_fw_caps ctrl_caps[] = {
{
.id = SND_AUDIOCODEC_BESPOKE,
.desc = {
......@@ -362,8 +361,26 @@ static const struct wm_adsp_fw_caps ez2control_caps[] = {
.num_sample_rates = 1,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.num_regions = ARRAY_SIZE(ez2control_regions),
.region_defs = ez2control_regions,
.num_regions = ARRAY_SIZE(default_regions),
.region_defs = default_regions,
},
};
static const struct wm_adsp_fw_caps trace_caps[] = {
{
.id = SND_AUDIOCODEC_BESPOKE,
.desc = {
.max_ch = 8,
.sample_rates = {
4000, 8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200,
96000, 176400, 192000
},
.num_sample_rates = 15,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.num_regions = ARRAY_SIZE(default_regions),
.region_defs = default_regions,
},
};
......@@ -382,11 +399,16 @@ static const struct {
[WM_ADSP_FW_CTRL] = {
.file = "ctrl",
.compr_direction = SND_COMPRESS_CAPTURE,
.num_caps = ARRAY_SIZE(ez2control_caps),
.caps = ez2control_caps,
.num_caps = ARRAY_SIZE(ctrl_caps),
.caps = ctrl_caps,
},
[WM_ADSP_FW_ASR] = { .file = "asr" },
[WM_ADSP_FW_TRACE] = { .file = "trace" },
[WM_ADSP_FW_TRACE] = {
.file = "trace",
.compr_direction = SND_COMPRESS_CAPTURE,
.num_caps = ARRAY_SIZE(trace_caps),
.caps = trace_caps,
},
[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
[WM_ADSP_FW_MISC] = { .file = "misc" },
};
......@@ -719,19 +741,19 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
ret = regmap_raw_write(dsp->regmap, reg, scratch,
ctl->len);
len);
if (ret) {
adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
ctl->len, reg, ret);
len, reg, ret);
kfree(scratch);
return ret;
}
adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
kfree(scratch);
......@@ -778,20 +800,20 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
if (ret) {
adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
ctl->len, reg, ret);
len, reg, ret);
kfree(scratch);
return ret;
}
adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
memcpy(buf, scratch, ctl->len);
memcpy(buf, scratch, len);
kfree(scratch);
return 0;
......@@ -855,17 +877,18 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
} else {
kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
}
ret = snd_soc_add_card_controls(dsp->card,
kcontrol, 1);
ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1);
if (ret < 0)
goto err_kcontrol;
kfree(kcontrol);
ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
ctl->name);
ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name);
return 0;
......@@ -885,9 +908,7 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
continue;
ret = wm_coeff_read_control(ctl,
ctl->cache,
ctl->len);
ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
if (ret < 0)
return ret;
}
......@@ -904,9 +925,7 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
if (!ctl->enabled)
continue;
if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
ret = wm_coeff_write_control(ctl,
ctl->cache,
ctl->len);
ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len);
if (ret < 0)
return ret;
}
......@@ -1502,8 +1521,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list: %d\n",
ret);
adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
kfree(alg);
return ERR_PTR(ret);
}
......@@ -2002,8 +2020,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
goto err_mutex;
}
val = (val & dsp->sysclk_mask)
>> dsp->sysclk_shift;
val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
ret = regmap_update_bits(dsp->regmap,
dsp->base + ADSP1_CONTROL_31,
......@@ -2096,8 +2113,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
/* Wait for the RAM to start, should be near instantaneous */
for (count = 0; count < 10; ++count) {
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
&val);
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
if (ret != 0)
return ret;
......@@ -2123,30 +2139,9 @@ static void wm_adsp2_boot_work(struct work_struct *work)
struct wm_adsp,
boot_work);
int ret;
unsigned int val;
mutex_lock(&dsp->pwr_lock);
/*
* For simplicity set the DSP clock rate to be the
* SYSCLK rate rather than making it configurable.
*/
ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
if (ret != 0) {
adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
goto err_mutex;
}
val = (val & ARIZONA_SYSCLK_FREQ_MASK)
>> ARIZONA_SYSCLK_FREQ_SHIFT;
ret = regmap_update_bits_async(dsp->regmap,
dsp->base + ADSP2_CLOCKING,
ADSP2_CLK_SEL_MASK, val);
if (ret != 0) {
adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
goto err_mutex;
}
ret = wm_adsp2_ena(dsp);
if (ret != 0)
goto err_mutex;
......@@ -2186,8 +2181,21 @@ static void wm_adsp2_boot_work(struct work_struct *work)
mutex_unlock(&dsp->pwr_lock);
}
static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
{
int ret;
ret = regmap_update_bits_async(dsp->regmap,
dsp->base + ADSP2_CLOCKING,
ADSP2_CLK_SEL_MASK,
freq << ADSP2_CLK_SEL_SHIFT);
if (ret != 0)
adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
}
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
struct snd_kcontrol *kcontrol, int event,
unsigned int freq)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
......@@ -2197,6 +2205,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
wm_adsp2_set_dspclk(dsp, freq);
queue_work(system_unbound_wq, &dsp->boot_work);
break;
default:
......@@ -2471,6 +2480,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
if (!compr->raw_buf)
return -ENOMEM;
compr->sample_rate = params->codec.sample_rate;
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
......@@ -2810,7 +2821,6 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
mutex_lock(&dsp->pwr_lock);
if (!buf) {
adsp_err(dsp, "Spurious buffer IRQ\n");
ret = -ENODEV;
goto out;
}
......@@ -2841,7 +2851,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
goto out;
}
if (compr->stream)
if (compr && compr->stream)
snd_compr_fragment_elapsed(compr->stream);
out:
......@@ -2911,6 +2921,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
tstamp->copied_total = compr->copied_total;
tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
tstamp->sampling_rate = compr->sample_rate;
out:
mutex_unlock(&dsp->pwr_lock);
......
......@@ -80,7 +80,7 @@ struct wm_adsp {
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
#define WM_ADSP2_E(wname, num, event_fn) \
#define WM_ADSP2(wname, num, event_fn) \
{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
......@@ -88,9 +88,6 @@ struct wm_adsp {
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
#define WM_ADSP2(wname, num) \
WM_ADSP2_E(wname, num, wm_adsp2_early_event)
extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
int wm_adsp1_init(struct wm_adsp *dsp);
......@@ -100,7 +97,8 @@ int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
struct snd_kcontrol *kcontrol, int event,
unsigned int freq);
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment