Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "The biggest change in this update is the unification of HD-audio codec parsers. Now the HD-audio codec is parsed in a generic parser code which is invoked by each HD-audio codec driver. Some background information is found in David Henningsson's blog entry: http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/ Other than that, some random updates/fixes like USB-audio and a bunch of small AoC updates as usual. Highlights: - Unification of HD-audio parser code (aka generic parser) - Support of new Intel HD-audio controller, new IDT codecs - Fixes for HD-audio HDMI audio hotplug - Haswell HDMI audio fixup - Support of Creative CA0132 DSP code - A few fixes of HDSP driver - USB-audio fix for Roland A-PRO, M-Audio FT C600 - Support PM for aloop driver (and fixes Oops) - Compress API updates for gapless playback support For ASoC part: - Support for a wider range of hardware in the compressed stream code - The ability to mute capture streams as well as playback streams while inactive - DT support for AK4642, FSI, Samsung I2S and WM8962 - AC'97 support for Tegra - New driver for max98090, replacing the stub which was there - A new driver from Dialog Note that due to dependencies, DTification of DMA support for Samsung platforms (used only by the and I2S driver and SPI) is merged here as well." Fix up trivial conflict in drivers/spi/spi-s3c64xx.c due to removed code being changed. * tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (453 commits) ALSA: usb: Fix Processing Unit Descriptor parsers ALSA: hda - hdmi: Notify userspace when ELD control changes ALSA: hda - hdmi: Protect ELD buffer ALSA: hda - hdmi: Refactor hdmi_eld into parsed_hdmi_eld ALSA: hda - hdmi: Do not expose eld data when eld is invalid ALSA: hda - hdmi: ELD shouldn't be valid after unplug ALSA: hda - Fix the silent speaker output on Fujitsu S7020 laptop ALSA: hda - add quirks for mute LED on two HP machines ALSA: usb/quirks, fix out-of-bounds access ASoC: codecs: Add da7213 codec ALSA: au88x0 - Define channel map for au88x0 ALSA: compress: add support for gapless playback ALSA: hda - Remove speaker clicks on CX20549 ALSA: hda - Disable runtime PM for Intel 5 Series/3400 ALSA: hda - Increase badness for missing multi-io ASoC: arizona: Automatically manage input mutes ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts ALSA: hda/ca0132 - Add missing \n to debug prints ALSA: hda/ca0132 - Fix type of INVALID_CHIP_ADDRESS ALSA: hda - update documentation for no-primary-hp fixup ...
This commit is contained in:
@@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CX20442
|
||||
select SND_SOC_DA7210 if I2C
|
||||
select SND_SOC_DA7213 if I2C
|
||||
select SND_SOC_DA732X if I2C
|
||||
select SND_SOC_DA9055 if I2C
|
||||
select SND_SOC_DFBMCS320
|
||||
@@ -98,7 +99,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_WM8782
|
||||
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8900 if I2C
|
||||
select SND_SOC_WM8903 if I2C
|
||||
select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS
|
||||
select SND_SOC_WM8904 if I2C
|
||||
select SND_SOC_WM8940 if I2C
|
||||
select SND_SOC_WM8955 if I2C
|
||||
@@ -247,6 +248,9 @@ config SND_SOC_L3
|
||||
config SND_SOC_DA7210
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA7213
|
||||
tristate
|
||||
|
||||
config SND_SOC_DA732X
|
||||
tristate
|
||||
|
||||
|
@@ -23,6 +23,7 @@ snd-soc-cs4270-objs := cs4270.o
|
||||
snd-soc-cs4271-objs := cs4271.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
snd-soc-da7210-objs := da7210.o
|
||||
snd-soc-da7213-objs := da7213.o
|
||||
snd-soc-da732x-objs := da732x.o
|
||||
snd-soc-da9055-objs := da9055.o
|
||||
snd-soc-dfbmcs320-objs := dfbmcs320.o
|
||||
@@ -147,6 +148,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
|
||||
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
|
||||
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
|
||||
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
|
||||
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
@@ -513,12 +514,31 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static struct of_device_id ak4642_of_match[];
|
||||
static int ak4642_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
const struct snd_soc_codec_driver *driver;
|
||||
|
||||
driver = NULL;
|
||||
if (np) {
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(ak4642_of_match, &i2c->dev);
|
||||
if (of_id)
|
||||
driver = of_id->data;
|
||||
} else {
|
||||
driver = (struct snd_soc_codec_driver *)id->driver_data;
|
||||
}
|
||||
|
||||
if (!driver) {
|
||||
dev_err(&i2c->dev, "no driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev,
|
||||
(struct snd_soc_codec_driver *)id->driver_data,
|
||||
&ak4642_dai, 1);
|
||||
driver, &ak4642_dai, 1);
|
||||
}
|
||||
|
||||
static int ak4642_i2c_remove(struct i2c_client *client)
|
||||
@@ -527,6 +547,14 @@ static int ak4642_i2c_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id ak4642_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642},
|
||||
{ .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642},
|
||||
{ .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4642_of_match);
|
||||
|
||||
static const struct i2c_device_id ak4642_i2c_id[] = {
|
||||
{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
|
||||
{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
|
||||
@@ -539,6 +567,7 @@ static struct i2c_driver ak4642_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak4642-codec",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ak4642_of_match,
|
||||
},
|
||||
.probe = ak4642_i2c_probe,
|
||||
.remove = ak4642_i2c_remove,
|
||||
|
@@ -56,14 +56,14 @@
|
||||
#define arizona_fll_warn(_fll, fmt, ...) \
|
||||
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
|
||||
#define arizona_fll_dbg(_fll, fmt, ...) \
|
||||
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
|
||||
dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
|
||||
|
||||
#define arizona_aif_err(_dai, fmt, ...) \
|
||||
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
|
||||
#define arizona_aif_warn(_dai, fmt, ...) \
|
||||
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
|
||||
#define arizona_aif_dbg(_dai, fmt, ...) \
|
||||
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
|
||||
dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
|
||||
|
||||
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
"None",
|
||||
@@ -141,6 +141,30 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
"ASRC1R",
|
||||
"ASRC2L",
|
||||
"ASRC2R",
|
||||
"ISRC1INT1",
|
||||
"ISRC1INT2",
|
||||
"ISRC1INT3",
|
||||
"ISRC1INT4",
|
||||
"ISRC1DEC1",
|
||||
"ISRC1DEC2",
|
||||
"ISRC1DEC3",
|
||||
"ISRC1DEC4",
|
||||
"ISRC2INT1",
|
||||
"ISRC2INT2",
|
||||
"ISRC2INT3",
|
||||
"ISRC2INT4",
|
||||
"ISRC2DEC1",
|
||||
"ISRC2DEC2",
|
||||
"ISRC2DEC3",
|
||||
"ISRC2DEC4",
|
||||
"ISRC3INT1",
|
||||
"ISRC3INT2",
|
||||
"ISRC3INT3",
|
||||
"ISRC3INT4",
|
||||
"ISRC3DEC1",
|
||||
"ISRC3DEC2",
|
||||
"ISRC3DEC3",
|
||||
"ISRC3DEC4",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
|
||||
|
||||
@@ -220,6 +244,30 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
0x91,
|
||||
0x92,
|
||||
0x93,
|
||||
0xa0, /* ISRC1INT1 */
|
||||
0xa1,
|
||||
0xa2,
|
||||
0xa3,
|
||||
0xa4, /* ISRC1DEC1 */
|
||||
0xa5,
|
||||
0xa6,
|
||||
0xa7,
|
||||
0xa8, /* ISRC2DEC1 */
|
||||
0xa9,
|
||||
0xaa,
|
||||
0xab,
|
||||
0xac, /* ISRC2INT1 */
|
||||
0xad,
|
||||
0xae,
|
||||
0xaf,
|
||||
0xb0, /* ISRC3DEC1 */
|
||||
0xb1,
|
||||
0xb2,
|
||||
0xb3,
|
||||
0xb4, /* ISRC3INT1 */
|
||||
0xb5,
|
||||
0xb6,
|
||||
0xb7,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_mixer_values);
|
||||
|
||||
@@ -275,9 +323,35 @@ const struct soc_enum arizona_lhpf4_mode =
|
||||
arizona_lhpf_mode_text);
|
||||
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
|
||||
|
||||
static const char *arizona_ng_hold_text[] = {
|
||||
"30ms", "120ms", "250ms", "500ms",
|
||||
};
|
||||
|
||||
const struct soc_enum arizona_ng_hold =
|
||||
SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
|
||||
4, arizona_ng_hold_text);
|
||||
EXPORT_SYMBOL_GPL(arizona_ng_hold);
|
||||
|
||||
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
if (w->shift % 2)
|
||||
reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
|
||||
else
|
||||
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
|
||||
ARIZONA_IN1L_MUTE);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_in_ev);
|
||||
@@ -417,6 +491,10 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
case 147456000:
|
||||
val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 0:
|
||||
dev_dbg(arizona->dev, "%s cleared\n", name);
|
||||
*clk = freq;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -635,6 +713,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (base_rate == 0)
|
||||
return 0;
|
||||
|
||||
if (base_rate % 8000)
|
||||
constraint = &arizona_44k1_constraint;
|
||||
else
|
||||
@@ -645,25 +726,81 @@ static int arizona_startup(struct snd_pcm_substream *substream,
|
||||
constraint);
|
||||
}
|
||||
|
||||
static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
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];
|
||||
int base = dai->driver->base;
|
||||
int i, sr_val;
|
||||
|
||||
/*
|
||||
* We will need to be more flexible than this in future,
|
||||
* currently we use a single sample rate for SYSCLK.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
|
||||
if (arizona_sr_vals[i] == params_rate(params))
|
||||
break;
|
||||
if (i == ARRAY_SIZE(arizona_sr_vals)) {
|
||||
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
|
||||
params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
sr_val = i;
|
||||
|
||||
switch (dai_priv->clk) {
|
||||
case ARIZONA_CLK_SYSCLK:
|
||||
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
|
||||
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
|
||||
if (base)
|
||||
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
|
||||
ARIZONA_AIF1_RATE_MASK, 0);
|
||||
break;
|
||||
case ARIZONA_CLK_ASYNCCLK:
|
||||
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
|
||||
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
|
||||
if (base)
|
||||
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
|
||||
ARIZONA_AIF1_RATE_MASK,
|
||||
8 << ARIZONA_AIF1_RATE_SHIFT);
|
||||
break;
|
||||
default:
|
||||
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arizona_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
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];
|
||||
struct arizona *arizona = priv->arizona;
|
||||
int base = dai->driver->base;
|
||||
const int *rates;
|
||||
int i;
|
||||
int bclk, lrclk, wl, frame, sr_val;
|
||||
int i, ret;
|
||||
int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
|
||||
int bclk, lrclk, wl, frame, bclk_target;
|
||||
|
||||
if (params_rate(params) % 8000)
|
||||
rates = &arizona_44k1_bclk_rates[0];
|
||||
else
|
||||
rates = &arizona_48k_bclk_rates[0];
|
||||
|
||||
bclk_target = snd_soc_params_to_bclk(params);
|
||||
if (chan_limit && chan_limit < params_channels(params)) {
|
||||
arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
|
||||
bclk_target /= params_channels(params);
|
||||
bclk_target *= chan_limit;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
|
||||
if (rates[i] >= snd_soc_params_to_bclk(params) &&
|
||||
if (rates[i] >= bclk_target &&
|
||||
rates[i] % params_rate(params) == 0) {
|
||||
bclk = i;
|
||||
break;
|
||||
@@ -675,16 +812,6 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
|
||||
if (arizona_sr_vals[i] == params_rate(params))
|
||||
break;
|
||||
if (i == ARRAY_SIZE(arizona_sr_vals)) {
|
||||
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
|
||||
params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
sr_val = i;
|
||||
|
||||
lrclk = rates[bclk] / params_rate(params);
|
||||
|
||||
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
|
||||
@@ -693,28 +820,9 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
|
||||
wl = snd_pcm_format_width(params_format(params));
|
||||
frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
|
||||
|
||||
/*
|
||||
* We will need to be more flexible than this in future,
|
||||
* currently we use a single sample rate for SYSCLK.
|
||||
*/
|
||||
switch (dai_priv->clk) {
|
||||
case ARIZONA_CLK_SYSCLK:
|
||||
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
|
||||
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
|
||||
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
|
||||
ARIZONA_AIF1_RATE_MASK, 0);
|
||||
break;
|
||||
case ARIZONA_CLK_ASYNCCLK:
|
||||
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
|
||||
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
|
||||
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
|
||||
ARIZONA_AIF1_RATE_MASK,
|
||||
8 << ARIZONA_AIF1_RATE_SHIFT);
|
||||
break;
|
||||
default:
|
||||
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = arizona_hw_params_rate(substream, params, dai);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
|
||||
ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
|
||||
@@ -789,11 +897,27 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
return snd_soc_dapm_sync(&codec->dapm);
|
||||
}
|
||||
|
||||
static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int base = dai->driver->base;
|
||||
unsigned int reg;
|
||||
|
||||
if (tristate)
|
||||
reg = ARIZONA_AIF1_TRI;
|
||||
else
|
||||
reg = 0;
|
||||
|
||||
return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
|
||||
ARIZONA_AIF1_TRI, reg);
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops arizona_dai_ops = {
|
||||
.startup = arizona_startup,
|
||||
.set_fmt = arizona_set_fmt,
|
||||
.hw_params = arizona_hw_params,
|
||||
.set_sysclk = arizona_dai_set_sysclk,
|
||||
.set_tristate = arizona_set_tristate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_dai_ops);
|
||||
|
||||
@@ -807,17 +931,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_dai);
|
||||
|
||||
static irqreturn_t arizona_fll_lock(int irq, void *data)
|
||||
{
|
||||
struct arizona_fll *fll = data;
|
||||
|
||||
arizona_fll_dbg(fll, "Lock status changed\n");
|
||||
|
||||
complete(&fll->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
|
||||
{
|
||||
struct arizona_fll *fll = data;
|
||||
@@ -910,7 +1023,7 @@ static int arizona_calc_fll(struct arizona_fll *fll,
|
||||
|
||||
cfg->n = target / (ratio * Fref);
|
||||
|
||||
if (target % Fref) {
|
||||
if (target % (ratio * Fref)) {
|
||||
gcd_fll = gcd(target, ratio * Fref);
|
||||
arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
|
||||
|
||||
@@ -922,6 +1035,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
|
||||
cfg->lambda = 0;
|
||||
}
|
||||
|
||||
/* Round down to 16bit range with cost of accuracy lost.
|
||||
* Denominator must be bigger than numerator so we only
|
||||
* take care of it.
|
||||
*/
|
||||
while (cfg->lambda >= (1 << 16)) {
|
||||
cfg->theta >>= 1;
|
||||
cfg->lambda >>= 1;
|
||||
}
|
||||
|
||||
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
|
||||
cfg->n, cfg->theta, cfg->lambda);
|
||||
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
|
||||
@@ -1057,7 +1179,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
|
||||
{
|
||||
int ret;
|
||||
|
||||
init_completion(&fll->lock);
|
||||
init_completion(&fll->ok);
|
||||
|
||||
fll->id = id;
|
||||
@@ -1068,13 +1189,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
|
||||
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
|
||||
"FLL%d clock OK", id);
|
||||
|
||||
ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
|
||||
arizona_fll_lock, fll);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
|
||||
id, ret);
|
||||
}
|
||||
|
||||
ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
|
||||
arizona_fll_clock_ok, fll);
|
||||
if (ret != 0) {
|
||||
@@ -1089,6 +1203,40 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_fll);
|
||||
|
||||
/**
|
||||
* arizona_set_output_mode - Set the mode of the specified output
|
||||
*
|
||||
* @codec: Device to configure
|
||||
* @output: Output number
|
||||
* @diff: True to set the output to differential mode
|
||||
*
|
||||
* Some systems use external analogue switches to connect more
|
||||
* analogue devices to the CODEC than are supported by the device. In
|
||||
* some systems this requires changing the switched output from single
|
||||
* ended to differential mode dynamically at runtime, an operation
|
||||
* supported using this function.
|
||||
*
|
||||
* Most systems have a single static configuration and should use
|
||||
* platform data instead.
|
||||
*/
|
||||
int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
|
||||
{
|
||||
unsigned int reg, val;
|
||||
|
||||
if (output < 1 || output > 6)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
|
||||
|
||||
if (diff)
|
||||
val = ARIZONA_OUT1_MONO;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_set_output_mode);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -66,7 +66,7 @@ struct arizona_priv {
|
||||
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
|
||||
};
|
||||
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 75
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 99
|
||||
|
||||
extern const unsigned int arizona_mixer_tlv[];
|
||||
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
|
||||
@@ -176,6 +176,8 @@ extern const struct soc_enum arizona_lhpf2_mode;
|
||||
extern const struct soc_enum arizona_lhpf3_mode;
|
||||
extern const struct soc_enum arizona_lhpf4_mode;
|
||||
|
||||
extern const struct soc_enum arizona_ng_hold;
|
||||
|
||||
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
@@ -195,7 +197,6 @@ struct arizona_fll {
|
||||
int id;
|
||||
unsigned int base;
|
||||
unsigned int vco_mult;
|
||||
struct completion lock;
|
||||
struct completion ok;
|
||||
unsigned int fref;
|
||||
unsigned int fout;
|
||||
@@ -211,4 +212,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
|
||||
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
|
||||
|
||||
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
||||
bool diff);
|
||||
|
||||
#endif
|
||||
|
@@ -167,6 +167,8 @@ struct cs4271_private {
|
||||
int gpio_nreset;
|
||||
/* GPIO that disable serial bus, if any */
|
||||
int gpio_disable;
|
||||
/* enable soft reset workaround */
|
||||
bool enable_soft_reset;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -325,6 +327,33 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
|
||||
int i, ret;
|
||||
unsigned int ratio, val;
|
||||
|
||||
if (cs4271->enable_soft_reset) {
|
||||
/*
|
||||
* Put the codec in soft reset and back again in case it's not
|
||||
* currently streaming data. This way of bringing the codec in
|
||||
* sync to the current clocks is not explicitly documented in
|
||||
* the data sheet, but it seems to work fine, and in contrast
|
||||
* to a read hardware reset, we don't have to sync back all
|
||||
* registers every time.
|
||||
*/
|
||||
|
||||
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
!dai->capture_active) ||
|
||||
(substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
|
||||
!dai->playback_active)) {
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN,
|
||||
CS4271_MODE2_PDN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_update_bits(codec, CS4271_MODE2,
|
||||
CS4271_MODE2_PDN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
cs4271->rate = params_rate(params);
|
||||
|
||||
/* Configure DAC */
|
||||
@@ -484,6 +513,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
|
||||
if (of_get_property(codec->dev->of_node,
|
||||
"cirrus,amutec-eq-bmutec", NULL))
|
||||
amutec_eq_bmutec = true;
|
||||
|
||||
if (of_get_property(codec->dev->of_node,
|
||||
"cirrus,enable-soft-reset", NULL))
|
||||
cs4271->enable_soft_reset = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -492,6 +525,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
|
||||
gpio_nreset = cs4271plat->gpio_nreset;
|
||||
|
||||
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
|
||||
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
|
||||
}
|
||||
|
||||
if (gpio_nreset >= 0)
|
||||
|
@@ -1038,7 +1038,7 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec)
|
||||
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
cs42l52->beep = input_allocate_device();
|
||||
cs42l52->beep = devm_input_allocate_device(codec->dev);
|
||||
if (!cs42l52->beep) {
|
||||
dev_err(codec->dev, "Failed to allocate beep device\n");
|
||||
return;
|
||||
@@ -1059,7 +1059,6 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec)
|
||||
|
||||
ret = input_register_device(cs42l52->beep);
|
||||
if (ret != 0) {
|
||||
input_free_device(cs42l52->beep);
|
||||
cs42l52->beep = NULL;
|
||||
dev_err(codec->dev, "Failed to register beep device\n");
|
||||
}
|
||||
@@ -1076,7 +1075,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
|
||||
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
device_remove_file(codec->dev, &dev_attr_beep);
|
||||
input_unregister_device(cs42l52->beep);
|
||||
cancel_work_sync(&cs42l52->beep_work);
|
||||
cs42l52->beep = NULL;
|
||||
|
||||
|
1599
sound/soc/codecs/da7213.c
Normal file
1599
sound/soc/codecs/da7213.c
Normal file
File diff suppressed because it is too large
Load Diff
523
sound/soc/codecs/da7213.h
Normal file
523
sound/soc/codecs/da7213.h
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* da7213.h - DA7213 ASoC Codec Driver
|
||||
*
|
||||
* Copyright (c) 2013 Dialog Semiconductor
|
||||
*
|
||||
* Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _DA7213_H
|
||||
#define _DA7213_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/da7213.h>
|
||||
|
||||
/*
|
||||
* Registers
|
||||
*/
|
||||
|
||||
/* Status Registers */
|
||||
#define DA7213_STATUS1 0x02
|
||||
#define DA7213_PLL_STATUS 0x03
|
||||
#define DA7213_AUX_L_GAIN_STATUS 0x04
|
||||
#define DA7213_AUX_R_GAIN_STATUS 0x05
|
||||
#define DA7213_MIC_1_GAIN_STATUS 0x06
|
||||
#define DA7213_MIC_2_GAIN_STATUS 0x07
|
||||
#define DA7213_MIXIN_L_GAIN_STATUS 0x08
|
||||
#define DA7213_MIXIN_R_GAIN_STATUS 0x09
|
||||
#define DA7213_ADC_L_GAIN_STATUS 0x0A
|
||||
#define DA7213_ADC_R_GAIN_STATUS 0x0B
|
||||
#define DA7213_DAC_L_GAIN_STATUS 0x0C
|
||||
#define DA7213_DAC_R_GAIN_STATUS 0x0D
|
||||
#define DA7213_HP_L_GAIN_STATUS 0x0E
|
||||
#define DA7213_HP_R_GAIN_STATUS 0x0F
|
||||
#define DA7213_LINE_GAIN_STATUS 0x10
|
||||
|
||||
/* System Initialisation Registers */
|
||||
#define DA7213_DIG_ROUTING_DAI 0x21
|
||||
#define DA7213_SR 0x22
|
||||
#define DA7213_REFERENCES 0x23
|
||||
#define DA7213_PLL_FRAC_TOP 0x24
|
||||
#define DA7213_PLL_FRAC_BOT 0x25
|
||||
#define DA7213_PLL_INTEGER 0x26
|
||||
#define DA7213_PLL_CTRL 0x27
|
||||
#define DA7213_DAI_CLK_MODE 0x28
|
||||
#define DA7213_DAI_CTRL 0x29
|
||||
#define DA7213_DIG_ROUTING_DAC 0x2A
|
||||
#define DA7213_ALC_CTRL1 0x2B
|
||||
|
||||
/* Input - Gain, Select and Filter Registers */
|
||||
#define DA7213_AUX_L_GAIN 0x30
|
||||
#define DA7213_AUX_R_GAIN 0x31
|
||||
#define DA7213_MIXIN_L_SELECT 0x32
|
||||
#define DA7213_MIXIN_R_SELECT 0x33
|
||||
#define DA7213_MIXIN_L_GAIN 0x34
|
||||
#define DA7213_MIXIN_R_GAIN 0x35
|
||||
#define DA7213_ADC_L_GAIN 0x36
|
||||
#define DA7213_ADC_R_GAIN 0x37
|
||||
#define DA7213_ADC_FILTERS1 0x38
|
||||
#define DA7213_MIC_1_GAIN 0x39
|
||||
#define DA7213_MIC_2_GAIN 0x3A
|
||||
|
||||
/* Output - Gain, Select and Filter Registers */
|
||||
#define DA7213_DAC_FILTERS5 0x40
|
||||
#define DA7213_DAC_FILTERS2 0x41
|
||||
#define DA7213_DAC_FILTERS3 0x42
|
||||
#define DA7213_DAC_FILTERS4 0x43
|
||||
#define DA7213_DAC_FILTERS1 0x44
|
||||
#define DA7213_DAC_L_GAIN 0x45
|
||||
#define DA7213_DAC_R_GAIN 0x46
|
||||
#define DA7213_CP_CTRL 0x47
|
||||
#define DA7213_HP_L_GAIN 0x48
|
||||
#define DA7213_HP_R_GAIN 0x49
|
||||
#define DA7213_LINE_GAIN 0x4A
|
||||
#define DA7213_MIXOUT_L_SELECT 0x4B
|
||||
#define DA7213_MIXOUT_R_SELECT 0x4C
|
||||
|
||||
/* System Controller Registers */
|
||||
#define DA7213_SYSTEM_MODES_INPUT 0x50
|
||||
#define DA7213_SYSTEM_MODES_OUTPUT 0x51
|
||||
|
||||
/* Control Registers */
|
||||
#define DA7213_AUX_L_CTRL 0x60
|
||||
#define DA7213_AUX_R_CTRL 0x61
|
||||
#define DA7213_MICBIAS_CTRL 0x62
|
||||
#define DA7213_MIC_1_CTRL 0x63
|
||||
#define DA7213_MIC_2_CTRL 0x64
|
||||
#define DA7213_MIXIN_L_CTRL 0x65
|
||||
#define DA7213_MIXIN_R_CTRL 0x66
|
||||
#define DA7213_ADC_L_CTRL 0x67
|
||||
#define DA7213_ADC_R_CTRL 0x68
|
||||
#define DA7213_DAC_L_CTRL 0x69
|
||||
#define DA7213_DAC_R_CTRL 0x6A
|
||||
#define DA7213_HP_L_CTRL 0x6B
|
||||
#define DA7213_HP_R_CTRL 0x6C
|
||||
#define DA7213_LINE_CTRL 0x6D
|
||||
#define DA7213_MIXOUT_L_CTRL 0x6E
|
||||
#define DA7213_MIXOUT_R_CTRL 0x6F
|
||||
|
||||
/* Configuration Registers */
|
||||
#define DA7213_LDO_CTRL 0x90
|
||||
#define DA7213_IO_CTRL 0x91
|
||||
#define DA7213_GAIN_RAMP_CTRL 0x92
|
||||
#define DA7213_MIC_CONFIG 0x93
|
||||
#define DA7213_PC_COUNT 0x94
|
||||
#define DA7213_CP_VOL_THRESHOLD1 0x95
|
||||
#define DA7213_CP_DELAY 0x96
|
||||
#define DA7213_CP_DETECTOR 0x97
|
||||
#define DA7213_DAI_OFFSET 0x98
|
||||
#define DA7213_DIG_CTRL 0x99
|
||||
#define DA7213_ALC_CTRL2 0x9A
|
||||
#define DA7213_ALC_CTRL3 0x9B
|
||||
#define DA7213_ALC_NOISE 0x9C
|
||||
#define DA7213_ALC_TARGET_MIN 0x9D
|
||||
#define DA7213_ALC_TARGET_MAX 0x9E
|
||||
#define DA7213_ALC_GAIN_LIMITS 0x9F
|
||||
#define DA7213_ALC_ANA_GAIN_LIMITS 0xA0
|
||||
#define DA7213_ALC_ANTICLIP_CTRL 0xA1
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL 0xA2
|
||||
|
||||
#define DA7213_ALC_OFFSET_AUTO_M_L 0xA3
|
||||
#define DA7213_ALC_OFFSET_AUTO_U_L 0xA4
|
||||
#define DA7213_ALC_OFFSET_MAN_M_L 0xA6
|
||||
#define DA7213_ALC_OFFSET_MAN_U_L 0xA7
|
||||
#define DA7213_ALC_OFFSET_AUTO_M_R 0xA8
|
||||
#define DA7213_ALC_OFFSET_AUTO_U_R 0xA9
|
||||
#define DA7213_ALC_OFFSET_MAN_M_R 0xAB
|
||||
#define DA7213_ALC_OFFSET_MAN_U_R 0xAC
|
||||
#define DA7213_ALC_CIC_OP_LVL_CTRL 0xAD
|
||||
#define DA7213_ALC_CIC_OP_LVL_DATA 0xAE
|
||||
#define DA7213_DAC_NG_SETUP_TIME 0xAF
|
||||
#define DA7213_DAC_NG_OFF_THRESHOLD 0xB0
|
||||
#define DA7213_DAC_NG_ON_THRESHOLD 0xB1
|
||||
#define DA7213_DAC_NG_CTRL 0xB2
|
||||
|
||||
|
||||
/*
|
||||
* Bit fields
|
||||
*/
|
||||
|
||||
/* DA7213_SR = 0x22 */
|
||||
#define DA7213_SR_8000 (0x1 << 0)
|
||||
#define DA7213_SR_11025 (0x2 << 0)
|
||||
#define DA7213_SR_12000 (0x3 << 0)
|
||||
#define DA7213_SR_16000 (0x5 << 0)
|
||||
#define DA7213_SR_22050 (0x6 << 0)
|
||||
#define DA7213_SR_24000 (0x7 << 0)
|
||||
#define DA7213_SR_32000 (0x9 << 0)
|
||||
#define DA7213_SR_44100 (0xA << 0)
|
||||
#define DA7213_SR_48000 (0xB << 0)
|
||||
#define DA7213_SR_88200 (0xE << 0)
|
||||
#define DA7213_SR_96000 (0xF << 0)
|
||||
|
||||
/* DA7213_REFERENCES = 0x23 */
|
||||
#define DA7213_BIAS_EN (0x1 << 3)
|
||||
#define DA7213_VMID_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_PLL_CTRL = 0x27 */
|
||||
#define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2)
|
||||
#define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2)
|
||||
#define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2)
|
||||
#define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2)
|
||||
#define DA7213_PLL_INDIV_MASK (0x3 << 2)
|
||||
#define DA7213_PLL_MCLK_SQR_EN (0x1 << 4)
|
||||
#define DA7213_PLL_32K_MODE (0x1 << 5)
|
||||
#define DA7213_PLL_SRM_EN (0x1 << 6)
|
||||
#define DA7213_PLL_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_DAI_CLK_MODE = 0x28 */
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_64 (0x1 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_128 (0x2 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
|
||||
#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
|
||||
#define DA7213_DAI_CLK_POL_INV (0x1 << 2)
|
||||
#define DA7213_DAI_WCLK_POL_INV (0x1 << 3)
|
||||
#define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7)
|
||||
#define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7)
|
||||
#define DA7213_DAI_CLK_EN_MASK (0x1 << 7)
|
||||
|
||||
/* DA7213_DAI_CTRL = 0x29 */
|
||||
#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0)
|
||||
#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0)
|
||||
#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0)
|
||||
#define DA7213_DAI_FORMAT_MASK (0x3 << 0)
|
||||
#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2)
|
||||
#define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2)
|
||||
#define DA7213_DAI_EN_SHIFT 7
|
||||
|
||||
/* DA7213_DIG_ROUTING_DAI = 0x21 */
|
||||
#define DA7213_DAI_L_SRC_SHIFT 0
|
||||
#define DA7213_DAI_R_SRC_SHIFT 4
|
||||
#define DA7213_DAI_SRC_MAX 4
|
||||
|
||||
/* DA7213_DIG_ROUTING_DAC = 0x2A */
|
||||
#define DA7213_DAC_L_SRC_SHIFT 0
|
||||
#define DA7213_DAC_L_MONO_SHIFT 3
|
||||
#define DA7213_DAC_R_SRC_SHIFT 4
|
||||
#define DA7213_DAC_R_MONO_SHIFT 7
|
||||
#define DA7213_DAC_SRC_MAX 4
|
||||
#define DA7213_DAC_MONO_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_CTRL1 = 0x2B */
|
||||
#define DA7213_ALC_OFFSET_EN_SHIFT 0
|
||||
#define DA7213_ALC_OFFSET_EN_MAX 0x1
|
||||
#define DA7213_ALC_OFFSET_EN (0x1 << 0)
|
||||
#define DA7213_ALC_SYNC_MODE (0x1 << 1)
|
||||
#define DA7213_ALC_CALIB_MODE_MAN (0x1 << 2)
|
||||
#define DA7213_ALC_L_EN_SHIFT 3
|
||||
#define DA7213_ALC_AUTO_CALIB_EN (0x1 << 4)
|
||||
#define DA7213_ALC_CALIB_OVERFLOW (0x1 << 5)
|
||||
#define DA7213_ALC_R_EN_SHIFT 7
|
||||
#define DA7213_ALC_EN_MAX 0x1
|
||||
|
||||
/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */
|
||||
#define DA7213_AUX_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_AUX_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */
|
||||
#define DA7213_DMIC_EN_SHIFT 7
|
||||
#define DA7213_DMIC_EN_MAX 0x1
|
||||
|
||||
/* DA7213_MIXIN_L_SELECT = 0x32 */
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT 0
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT 1
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_1 (0x1 << 1)
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT 2
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIC_2 (0x1 << 2)
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT 3
|
||||
#define DA7213_MIXIN_L_MIX_SELECT_MAX 0x1
|
||||
|
||||
/* DA7213_MIXIN_R_SELECT = 0x33 */
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT 0
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT 1
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_2 (0x1 << 1)
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT 2
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIC_1 (0x1 << 2)
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT 3
|
||||
#define DA7213_MIXIN_R_MIX_SELECT_MAX 0x1
|
||||
#define DA7213_MIC_BIAS_OUTPUT_SELECT_2 (0x1 << 6)
|
||||
|
||||
/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */
|
||||
#define DA7213_MIXIN_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_MIXIN_AMP_GAIN_MAX 0xF
|
||||
|
||||
/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */
|
||||
#define DA7213_ADC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_ADC_AMP_GAIN_MAX 0x7F
|
||||
|
||||
/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */
|
||||
#define DA7213_VOICE_HPF_CORNER_SHIFT 0
|
||||
#define DA7213_VOICE_HPF_CORNER_MAX 8
|
||||
#define DA7213_VOICE_EN_SHIFT 3
|
||||
#define DA7213_VOICE_EN_MAX 0x1
|
||||
#define DA7213_AUDIO_HPF_CORNER_SHIFT 4
|
||||
#define DA7213_AUDIO_HPF_CORNER_MAX 4
|
||||
#define DA7213_HPF_EN_SHIFT 7
|
||||
#define DA7213_HPF_EN_MAX 0x1
|
||||
|
||||
/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */
|
||||
#define DA7213_MIC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_MIC_AMP_GAIN_MAX 0x7
|
||||
|
||||
/* DA7213_DAC_FILTERS5 = 0x40 */
|
||||
#define DA7213_DAC_SOFTMUTE_EN_SHIFT 7
|
||||
#define DA7213_DAC_SOFTMUTE_EN_MAX 0x1
|
||||
#define DA7213_DAC_SOFTMUTE_RATE_SHIFT 4
|
||||
#define DA7213_DAC_SOFTMUTE_RATE_MAX 7
|
||||
|
||||
/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */
|
||||
#define DA7213_DAC_EQ_BAND_MAX 0xF
|
||||
|
||||
/* DA7213_DAC_FILTERS2 = 0x41 */
|
||||
#define DA7213_DAC_EQ_BAND1_SHIFT 0
|
||||
#define DA7213_DAC_EQ_BAND2_SHIFT 4
|
||||
|
||||
/* DA7213_DAC_FILTERS2 = 0x42 */
|
||||
#define DA7213_DAC_EQ_BAND3_SHIFT 0
|
||||
#define DA7213_DAC_EQ_BAND4_SHIFT 4
|
||||
|
||||
/* DA7213_DAC_FILTERS4 = 0x43 */
|
||||
#define DA7213_DAC_EQ_BAND5_SHIFT 0
|
||||
#define DA7213_DAC_EQ_EN_SHIFT 7
|
||||
#define DA7213_DAC_EQ_EN_MAX 0x1
|
||||
|
||||
/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */
|
||||
#define DA7213_DAC_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_DAC_AMP_GAIN_MAX 0x7F
|
||||
|
||||
/* DA7213_HP_L/R_GAIN = 0x45/0x46 */
|
||||
#define DA7213_HP_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_HP_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_CP_CTRL = 0x47 */
|
||||
#define DA7213_CP_EN_SHIFT 7
|
||||
|
||||
/* DA7213_LINE_GAIN = 0x4A */
|
||||
#define DA7213_LINE_AMP_GAIN_SHIFT 0
|
||||
#define DA7213_LINE_AMP_GAIN_MAX 0x3F
|
||||
|
||||
/* DA7213_MIXOUT_L_SELECT = 0x4B */
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT 0
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT 1
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT 2
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT 3
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT 4
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 5
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 6
|
||||
#define DA7213_MIXOUT_L_MIX_SELECT_MAX 0x1
|
||||
|
||||
/* DA7213_MIXOUT_R_SELECT = 0x4C */
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT 0
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT 1
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT 2
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT 3
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT 4
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT 5
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT 6
|
||||
#define DA7213_MIXOUT_R_MIX_SELECT_MAX 0x1
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_MUTE_EN_SHIFT 6
|
||||
#define DA7213_MUTE_EN_MAX 0x1
|
||||
#define DA7213_MUTE_EN (0x1 << 6)
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_ADC_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_DAC_L/R_CTRL = 0x69/0x6A,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_GAIN_RAMP_EN_SHIFT 5
|
||||
#define DA7213_GAIN_RAMP_EN_MAX 0x1
|
||||
#define DA7213_GAIN_RAMP_EN (0x1 << 5)
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_ZC_EN_SHIFT 4
|
||||
#define DA7213_ZC_EN_MAX 0x1
|
||||
|
||||
/*
|
||||
* DA7213_AUX_L/R_CTRL = 0x60/0x61,
|
||||
* DA7213_MIC_1/2_CTRL = 0x63/0x64,
|
||||
* DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
|
||||
* DA7213_HP_L/R_CTRL = 0x6B/0x6C,
|
||||
* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F,
|
||||
* DA7213_LINE_CTRL = 0x6D
|
||||
*/
|
||||
#define DA7213_AMP_EN_SHIFT 7
|
||||
|
||||
/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */
|
||||
#define DA7213_MIC_AMP_IN_SEL_SHIFT 2
|
||||
#define DA7213_MIC_AMP_IN_SEL_MAX 3
|
||||
|
||||
/* DA7213_MICBIAS_CTRL = 0x62 */
|
||||
#define DA7213_MICBIAS1_LEVEL_SHIFT 0
|
||||
#define DA7213_MICBIAS1_LEVEL_MASK (0x3 << 0)
|
||||
#define DA7213_MICBIAS1_EN_SHIFT 3
|
||||
#define DA7213_MICBIAS2_LEVEL_SHIFT 4
|
||||
#define DA7213_MICBIAS2_LEVEL_MASK (0x3 << 4)
|
||||
#define DA7213_MICBIAS2_EN_SHIFT 7
|
||||
|
||||
/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */
|
||||
#define DA7213_MIXIN_MIX_EN (0x1 << 3)
|
||||
|
||||
/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */
|
||||
#define DA7213_ADC_EN_SHIFT 7
|
||||
#define DA7213_ADC_EN (0x1 << 7)
|
||||
|
||||
/* DA7213_DAC_L/R_CTRL = 0x69/0x6A*/
|
||||
#define DA7213_DAC_EN_SHIFT 7
|
||||
|
||||
/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */
|
||||
#define DA7213_HP_AMP_OE (0x1 << 3)
|
||||
|
||||
/* DA7213_LINE_CTRL = 0x6D */
|
||||
#define DA7213_LINE_AMP_OE (0x1 << 3)
|
||||
|
||||
/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */
|
||||
#define DA7213_MIXOUT_MIX_EN (0x1 << 3)
|
||||
|
||||
/* DA7213_GAIN_RAMP_CTRL = 0x92 */
|
||||
#define DA7213_GAIN_RAMP_RATE_SHIFT 0
|
||||
#define DA7213_GAIN_RAMP_RATE_MAX 4
|
||||
|
||||
/* DA7213_MIC_CONFIG = 0x93 */
|
||||
#define DA7213_DMIC_DATA_SEL_SHIFT 0
|
||||
#define DA7213_DMIC_DATA_SEL_MASK (0x1 << 0)
|
||||
#define DA7213_DMIC_SAMPLEPHASE_SHIFT 1
|
||||
#define DA7213_DMIC_SAMPLEPHASE_MASK (0x1 << 1)
|
||||
#define DA7213_DMIC_CLK_RATE_SHIFT 2
|
||||
#define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2)
|
||||
|
||||
/* DA7213_DIG_CTRL = 0x99 */
|
||||
#define DA7213_DAC_L_INV_SHIFT 3
|
||||
#define DA7213_DAC_R_INV_SHIFT 7
|
||||
#define DA7213_DAC_INV_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_CTRL2 = 0x9A */
|
||||
#define DA7213_ALC_ATTACK_SHIFT 0
|
||||
#define DA7213_ALC_ATTACK_MAX 13
|
||||
#define DA7213_ALC_RELEASE_SHIFT 4
|
||||
#define DA7213_ALC_RELEASE_MAX 11
|
||||
|
||||
/* DA7213_ALC_CTRL3 = 0x9B */
|
||||
#define DA7213_ALC_HOLD_SHIFT 0
|
||||
#define DA7213_ALC_HOLD_MAX 16
|
||||
#define DA7213_ALC_INTEG_ATTACK_SHIFT 4
|
||||
#define DA7213_ALC_INTEG_RELEASE_SHIFT 6
|
||||
#define DA7213_ALC_INTEG_MAX 4
|
||||
|
||||
/*
|
||||
* DA7213_ALC_NOISE = 0x9C,
|
||||
* DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E
|
||||
*/
|
||||
#define DA7213_ALC_THRESHOLD_SHIFT 0
|
||||
#define DA7213_ALC_THRESHOLD_MAX 0x3F
|
||||
|
||||
/* DA7213_ALC_GAIN_LIMITS = 0x9F */
|
||||
#define DA7213_ALC_ATTEN_MAX_SHIFT 0
|
||||
#define DA7213_ALC_GAIN_MAX_SHIFT 4
|
||||
#define DA7213_ALC_ATTEN_GAIN_MAX_MAX 0xF
|
||||
|
||||
/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */
|
||||
#define DA7213_ALC_ANA_GAIN_MIN_SHIFT 0
|
||||
#define DA7213_ALC_ANA_GAIN_MAX_SHIFT 4
|
||||
#define DA7213_ALC_ANA_GAIN_MAX 0x7
|
||||
|
||||
/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */
|
||||
#define DA7213_ALC_ANTICLIP_EN_SHIFT 7
|
||||
#define DA7213_ALC_ANTICLIP_EN_MAX 0x1
|
||||
|
||||
/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT 0
|
||||
#define DA7213_ALC_ANTICLIP_LEVEL_MAX 0x7F
|
||||
|
||||
/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */
|
||||
#define DA7213_ALC_DATA_MIDDLE (0x2 << 0)
|
||||
#define DA7213_ALC_DATA_TOP (0x3 << 0)
|
||||
#define DA7213_ALC_CIC_OP_CHANNEL_LEFT (0x0 << 7)
|
||||
#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT (0x1 << 7)
|
||||
|
||||
/* DA7213_DAC_NG_SETUP_TIME = 0xAF */
|
||||
#define DA7213_DAC_NG_SETUP_TIME_SHIFT 0
|
||||
#define DA7213_DAC_NG_SETUP_TIME_MAX 4
|
||||
#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT 2
|
||||
#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT 3
|
||||
#define DA7213_DAC_NG_RAMP_RATE_MAX 2
|
||||
|
||||
/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */
|
||||
#define DA7213_DAC_NG_THRESHOLD_SHIFT 0
|
||||
#define DA7213_DAC_NG_THRESHOLD_MAX 0x7
|
||||
|
||||
/* DA7213_DAC_NG_CTRL = 0xB2 */
|
||||
#define DA7213_DAC_NG_EN_SHIFT 7
|
||||
#define DA7213_DAC_NG_EN_MAX 0x1
|
||||
|
||||
|
||||
/*
|
||||
* General defines
|
||||
*/
|
||||
|
||||
/* Register inversion */
|
||||
#define DA7213_NO_INVERT 0
|
||||
#define DA7213_INVERT 1
|
||||
|
||||
/* Byte related defines */
|
||||
#define DA7213_BYTE_SHIFT 8
|
||||
#define DA7213_BYTE_MASK 0xFF
|
||||
|
||||
/* ALC related */
|
||||
#define DA7213_ALC_OFFSET_15_8 0x00FF00
|
||||
#define DA7213_ALC_OFFSET_19_16 0x0F0000
|
||||
#define DA7213_ALC_AVG_ITERATIONS 5
|
||||
|
||||
/* PLL related */
|
||||
#define DA7213_SYSCLK_MCLK 0
|
||||
#define DA7213_SYSCLK_PLL 1
|
||||
#define DA7213_PLL_FREQ_OUT_90316800 90316800
|
||||
#define DA7213_PLL_FREQ_OUT_98304000 98304000
|
||||
#define DA7213_PLL_FREQ_OUT_94310400 94310400
|
||||
#define DA7213_PLL_INDIV_5_10_MHZ_VAL 2
|
||||
#define DA7213_PLL_INDIV_10_20_MHZ_VAL 4
|
||||
#define DA7213_PLL_INDIV_20_40_MHZ_VAL 8
|
||||
#define DA7213_PLL_INDIV_40_54_MHZ_VAL 16
|
||||
|
||||
enum clk_src {
|
||||
DA7213_CLKSRC_MCLK
|
||||
};
|
||||
|
||||
/* Codec private data */
|
||||
struct da7213_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int mclk_rate;
|
||||
bool master;
|
||||
bool mclk_squarer_en;
|
||||
bool srm_en;
|
||||
bool alc_calib_auto;
|
||||
bool alc_en;
|
||||
struct da7213_platform_data *pdata;
|
||||
};
|
||||
|
||||
#endif /* _DA7213_H */
|
2673
sound/soc/codecs/max98090.c
Normal file → Executable file
2673
sound/soc/codecs/max98090.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
1549
sound/soc/codecs/max98090.h
Executable file
1549
sound/soc/codecs/max98090.h
Executable file
File diff suppressed because it is too large
Load Diff
@@ -85,6 +85,9 @@ struct aic3x_priv {
|
||||
#define AIC3X_MODEL_33 1
|
||||
#define AIC3X_MODEL_3007 2
|
||||
u16 model;
|
||||
|
||||
/* Selects the micbias voltage */
|
||||
enum aic3x_micbias_voltage micbias_vg;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -195,6 +198,37 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* mic bias power on/off share the same register bits with
|
||||
* output voltage of mic bias. when power on mic bias, we
|
||||
* need reclaim it to voltage value.
|
||||
* 0x0 = Powered off
|
||||
* 0x1 = MICBIAS output is powered to 2.0V,
|
||||
* 0x2 = MICBIAS output is powered to 2.5V
|
||||
* 0x3 = MICBIAS output is connected to AVDD
|
||||
*/
|
||||
static int mic_bias_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
/* change mic bias voltage to user defined */
|
||||
snd_soc_update_bits(codec, MICBIAS_CTRL,
|
||||
MICBIAS_LEVEL_MASK,
|
||||
aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(codec, MICBIAS_CTRL,
|
||||
MICBIAS_LEVEL_MASK, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
|
||||
static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
|
||||
static const char *aic3x_left_hpcom_mux[] =
|
||||
@@ -596,12 +630,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
|
||||
AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
|
||||
|
||||
/* Mic Bias */
|
||||
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
|
||||
MICBIAS_CTRL, 6, 3, 1, 0),
|
||||
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
|
||||
MICBIAS_CTRL, 6, 3, 2, 0),
|
||||
SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
|
||||
MICBIAS_CTRL, 6, 3, 3, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
|
||||
mic_bias_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
|
||||
/* Output mixers */
|
||||
SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
|
||||
@@ -1210,13 +1241,13 @@ static struct snd_soc_dai_driver aic3x_dai = {
|
||||
.name = "tlv320aic3x-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = AIC3X_RATES,
|
||||
.formats = AIC3X_FORMATS,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = AIC3X_RATES,
|
||||
.formats = AIC3X_FORMATS,},
|
||||
@@ -1386,6 +1417,24 @@ static int aic3x_probe(struct snd_soc_codec *codec)
|
||||
if (aic3x->model == AIC3X_MODEL_3007)
|
||||
snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
|
||||
|
||||
/* set mic bias voltage */
|
||||
switch (aic3x->micbias_vg) {
|
||||
case AIC3X_MICBIAS_2_0V:
|
||||
case AIC3X_MICBIAS_2_5V:
|
||||
case AIC3X_MICBIAS_AVDDV:
|
||||
snd_soc_update_bits(codec, MICBIAS_CTRL,
|
||||
MICBIAS_LEVEL_MASK,
|
||||
(aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
|
||||
break;
|
||||
case AIC3X_MICBIAS_OFF:
|
||||
/*
|
||||
* noting to do. target won't enter here. This is just to avoid
|
||||
* compile time warning "warning: enumeration value
|
||||
* 'AIC3X_MICBIAS_OFF' not handled in switch"
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
aic3x_add_widgets(codec);
|
||||
list_add(&aic3x->list, &reset_list);
|
||||
|
||||
@@ -1461,6 +1510,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
||||
struct aic3x_setup_data *ai3x_setup;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
int ret;
|
||||
u32 value;
|
||||
|
||||
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
|
||||
if (aic3x == NULL) {
|
||||
@@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
||||
if (pdata) {
|
||||
aic3x->gpio_reset = pdata->gpio_reset;
|
||||
aic3x->setup = pdata->setup;
|
||||
aic3x->micbias_vg = pdata->micbias_vg;
|
||||
} else if (np) {
|
||||
ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
|
||||
GFP_KERNEL);
|
||||
@@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
||||
aic3x->setup = ai3x_setup;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
|
||||
switch (value) {
|
||||
case 1 :
|
||||
aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
|
||||
break;
|
||||
case 2 :
|
||||
aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
|
||||
break;
|
||||
case 3 :
|
||||
aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
|
||||
break;
|
||||
default :
|
||||
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
|
||||
dev_err(&i2c->dev, "Unsuitable MicBias voltage "
|
||||
"found in DT\n");
|
||||
}
|
||||
} else {
|
||||
aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
|
||||
}
|
||||
|
||||
} else {
|
||||
aic3x->gpio_reset = -1;
|
||||
}
|
||||
|
@@ -238,6 +238,10 @@
|
||||
/* Default input volume */
|
||||
#define DEFAULT_GAIN 0x20
|
||||
|
||||
/* MICBIAS Control Register */
|
||||
#define MICBIAS_LEVEL_SHIFT (6)
|
||||
#define MICBIAS_LEVEL_MASK (3 << 6)
|
||||
|
||||
/* headset detection / button API */
|
||||
|
||||
/* The AIC3x supports detection of stereo headsets (GND + left + right signal)
|
||||
|
@@ -1452,20 +1452,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
|
||||
.read = dac33_read_reg_cache,
|
||||
.write = dac33_write_locked,
|
||||
@@ -1476,8 +1462,6 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
|
||||
.reg_cache_default = dac33_reg,
|
||||
.probe = dac33_soc_probe,
|
||||
.remove = dac33_soc_remove,
|
||||
.suspend = dac33_soc_suspend,
|
||||
.resume = dac33_soc_resume,
|
||||
|
||||
.controls = dac33_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(dac33_snd_controls),
|
||||
|
@@ -41,6 +41,11 @@
|
||||
/* Register descriptions are here */
|
||||
#include <linux/mfd/twl4030-audio.h>
|
||||
|
||||
/* TWL4030 PMBR1 Register */
|
||||
#define TWL4030_PMBR1_REG 0x0D
|
||||
/* TWL4030 PMBR1 Register GPIO6 mux bits */
|
||||
#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
|
||||
|
||||
/* Shadow register used by the audio driver */
|
||||
#define TWL4030_REG_SW_SHADOW 0x4A
|
||||
#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
|
||||
@@ -348,19 +353,32 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
|
||||
|
||||
pdata = twl4030_get_pdata(codec);
|
||||
|
||||
if (pdata && pdata->hs_extmute &&
|
||||
gpio_is_valid(pdata->hs_extmute_gpio)) {
|
||||
int ret;
|
||||
if (pdata && pdata->hs_extmute) {
|
||||
if (gpio_is_valid(pdata->hs_extmute_gpio)) {
|
||||
int ret;
|
||||
|
||||
if (!pdata->hs_extmute_gpio)
|
||||
dev_warn(codec->dev,
|
||||
"Extmute GPIO is 0 is this correct?\n");
|
||||
if (!pdata->hs_extmute_gpio)
|
||||
dev_warn(codec->dev,
|
||||
"Extmute GPIO is 0 is this correct?\n");
|
||||
|
||||
ret = gpio_request_one(pdata->hs_extmute_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "hs_extmute");
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to get hs_extmute GPIO\n");
|
||||
pdata->hs_extmute_gpio = -1;
|
||||
ret = gpio_request_one(pdata->hs_extmute_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"hs_extmute");
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to get hs_extmute GPIO\n");
|
||||
pdata->hs_extmute_gpio = -1;
|
||||
}
|
||||
} else {
|
||||
u8 pin_mux;
|
||||
|
||||
/* Set TWL4030 GPIO6 as EXTMUTE signal */
|
||||
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
|
||||
TWL4030_PMBR1_REG);
|
||||
pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
|
||||
pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
|
||||
twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
|
||||
TWL4030_PMBR1_REG);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1306,6 +1324,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_IN("VAIFIN", "Voice Playback", 0,
|
||||
TWL4030_REG_VOICE_IF, 6, 0),
|
||||
|
||||
/* Analog bypasses */
|
||||
SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_abypassr1_control),
|
||||
@@ -1438,6 +1459,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("VAIFOUT", "Voice Capture", 0,
|
||||
TWL4030_REG_VOICE_IF, 5, 0),
|
||||
|
||||
/* Analog/Digital mic path selection.
|
||||
TX1 Left/Right: either analog Left/Right or Digimic0
|
||||
TX2 Left/Right: either analog Left/Right or Digimic1 */
|
||||
@@ -1473,10 +1497,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0,
|
||||
NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
|
||||
SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
|
||||
SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0),
|
||||
/* Microphone bias */
|
||||
SND_SOC_DAPM_SUPPLY("Mic Bias 1",
|
||||
TWL4030_REG_MICBIAS_CTL, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Mic Bias 2",
|
||||
TWL4030_REG_MICBIAS_CTL, 1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
|
||||
TWL4030_REG_MICBIAS_CTL, 2, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("VIF Enable", TWL4030_REG_VOICE_IF, 0, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
@@ -1485,17 +1514,16 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"DAC Left1", NULL, "HiFi Playback"},
|
||||
{"DAC Right2", NULL, "HiFi Playback"},
|
||||
{"DAC Left2", NULL, "HiFi Playback"},
|
||||
{"DAC Voice", NULL, "Voice Playback"},
|
||||
{"DAC Voice", NULL, "VAIFIN"},
|
||||
|
||||
/* ADC -> Stream mapping */
|
||||
{"HiFi Capture", NULL, "ADC Virtual Left1"},
|
||||
{"HiFi Capture", NULL, "ADC Virtual Right1"},
|
||||
{"HiFi Capture", NULL, "ADC Virtual Left2"},
|
||||
{"HiFi Capture", NULL, "ADC Virtual Right2"},
|
||||
{"Voice Capture", NULL, "ADC Virtual Left1"},
|
||||
{"Voice Capture", NULL, "ADC Virtual Right1"},
|
||||
{"Voice Capture", NULL, "ADC Virtual Left2"},
|
||||
{"Voice Capture", NULL, "ADC Virtual Right2"},
|
||||
{"VAIFOUT", NULL, "ADC Virtual Left2"},
|
||||
{"VAIFOUT", NULL, "ADC Virtual Right2"},
|
||||
{"VAIFOUT", NULL, "VIF Enable"},
|
||||
|
||||
{"Digital L1 Playback Mixer", NULL, "DAC Left1"},
|
||||
{"Digital R1 Playback Mixer", NULL, "DAC Right1"},
|
||||
@@ -1510,6 +1538,7 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"DAC Right1", NULL, "AIF Enable"},
|
||||
{"DAC Left2", NULL, "AIF Enable"},
|
||||
{"DAC Right1", NULL, "AIF Enable"},
|
||||
{"DAC Voice", NULL, "VIF Enable"},
|
||||
|
||||
{"Digital R2 Playback Mixer", NULL, "AIF Enable"},
|
||||
{"Digital L2 Playback Mixer", NULL, "AIF Enable"},
|
||||
@@ -2267,18 +2296,6 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int twl4030_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl4030_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl4030_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl4030_priv *twl4030;
|
||||
@@ -2316,8 +2333,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
|
||||
static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
|
||||
.probe = twl4030_soc_probe,
|
||||
.remove = twl4030_soc_remove,
|
||||
.suspend = twl4030_soc_suspend,
|
||||
.resume = twl4030_soc_resume,
|
||||
.read = twl4030_read_reg_cache,
|
||||
.write = twl4030_write,
|
||||
.set_bias_level = twl4030_set_bias_level,
|
||||
|
@@ -69,13 +69,8 @@ struct twl6040_data {
|
||||
int hs_power_mode_locked;
|
||||
unsigned int clk_in;
|
||||
unsigned int sysclk;
|
||||
u16 hs_left_step;
|
||||
u16 hs_right_step;
|
||||
u16 hf_left_step;
|
||||
u16 hf_right_step;
|
||||
struct twl6040_jack_data hs_jack;
|
||||
struct snd_soc_codec *codec;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
@@ -404,8 +399,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
|
||||
struct snd_soc_codec *codec = data;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
queue_delayed_work(priv->workqueue, &priv->hs_jack.work,
|
||||
msecs_to_jiffies(200));
|
||||
schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -1115,7 +1109,6 @@ static int twl6040_suspend(struct snd_soc_codec *codec)
|
||||
static int twl6040_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1127,83 +1120,46 @@ static int twl6040_resume(struct snd_soc_codec *codec)
|
||||
static int twl6040_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl6040_data *priv;
|
||||
struct twl6040_codec_data *pdata = dev_get_platdata(codec->dev);
|
||||
struct platform_device *pdev = container_of(codec->dev,
|
||||
struct platform_device, dev);
|
||||
int ret = 0;
|
||||
|
||||
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
|
||||
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
|
||||
priv->codec = codec;
|
||||
codec->control_data = dev_get_drvdata(codec->dev->parent);
|
||||
|
||||
if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
|
||||
priv->hs_left_step = pdata->hs_left_step;
|
||||
priv->hs_right_step = pdata->hs_right_step;
|
||||
} else {
|
||||
priv->hs_left_step = 1;
|
||||
priv->hs_right_step = 1;
|
||||
}
|
||||
|
||||
if (pdata && pdata->hf_left_step && pdata->hf_right_step) {
|
||||
priv->hf_left_step = pdata->hf_left_step;
|
||||
priv->hf_right_step = pdata->hf_right_step;
|
||||
} else {
|
||||
priv->hf_left_step = 1;
|
||||
priv->hf_right_step = 1;
|
||||
}
|
||||
|
||||
priv->plug_irq = platform_get_irq(pdev, 0);
|
||||
if (priv->plug_irq < 0) {
|
||||
dev_err(codec->dev, "invalid irq\n");
|
||||
ret = -EINVAL;
|
||||
goto work_err;
|
||||
}
|
||||
|
||||
priv->workqueue = alloc_workqueue("twl6040-codec", 0, 0);
|
||||
if (!priv->workqueue) {
|
||||
ret = -ENOMEM;
|
||||
goto work_err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
||||
ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
|
||||
0, "twl6040_irq_plug", codec);
|
||||
ret = devm_request_threaded_irq(codec->dev, priv->plug_irq, NULL,
|
||||
twl6040_audio_handler, IRQF_NO_SUSPEND,
|
||||
"twl6040_irq_plug", codec);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
|
||||
goto plugirq_err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
twl6040_init_chip(codec);
|
||||
|
||||
/* power on device */
|
||||
ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
/* Error path */
|
||||
free_irq(priv->plug_irq, codec);
|
||||
plugirq_err:
|
||||
destroy_workqueue(priv->workqueue);
|
||||
work_err:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
static int twl6040_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
free_irq(priv->plug_irq, codec);
|
||||
destroy_workqueue(priv->workqueue);
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -62,6 +63,7 @@ enum wm2000_anc_mode {
|
||||
struct wm2000_priv {
|
||||
struct i2c_client *i2c;
|
||||
struct regmap *regmap;
|
||||
struct clk *mclk;
|
||||
|
||||
struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
|
||||
|
||||
@@ -71,11 +73,12 @@ struct wm2000_priv {
|
||||
unsigned int anc_eng_ena:1;
|
||||
unsigned int spk_ena:1;
|
||||
|
||||
unsigned int mclk_div:1;
|
||||
unsigned int speech_clarity:1;
|
||||
|
||||
int anc_download_size;
|
||||
char *anc_download;
|
||||
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
|
||||
@@ -131,6 +134,7 @@ static int wm2000_poll_bit(struct i2c_client *i2c,
|
||||
static int wm2000_power_up(struct i2c_client *i2c, int analogue)
|
||||
{
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
BUG_ON(wm2000->anc_mode != ANC_OFF);
|
||||
@@ -143,7 +147,8 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!wm2000->mclk_div) {
|
||||
rate = clk_get_rate(wm2000->mclk);
|
||||
if (rate <= 13500000) {
|
||||
dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
|
||||
wm2000_write(i2c, WM2000_REG_SYS_CTL2,
|
||||
WM2000_MCLK_DIV2_ENA_CLR);
|
||||
@@ -550,6 +555,15 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Maintain clock while active */
|
||||
if (anc_transitions[i].source == ANC_OFF) {
|
||||
ret = clk_prepare_enable(wm2000->mclk);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to enable MCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) {
|
||||
if (!anc_transitions[i].step[j])
|
||||
break;
|
||||
@@ -559,7 +573,10 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (anc_transitions[i].dest == ANC_OFF)
|
||||
clk_disable_unprepare(wm2000->mclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
|
||||
@@ -599,13 +616,20 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
|
||||
int anc_active = ucontrol->value.enumerated.item[0];
|
||||
int ret;
|
||||
|
||||
if (anc_active > 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wm2000->lock);
|
||||
|
||||
wm2000->anc_active = anc_active;
|
||||
|
||||
return wm2000_anc_set_mode(wm2000);
|
||||
ret = wm2000_anc_set_mode(wm2000);
|
||||
|
||||
mutex_unlock(&wm2000->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
|
||||
@@ -625,16 +649,24 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
|
||||
int val = ucontrol->value.enumerated.item[0];
|
||||
int ret;
|
||||
|
||||
if (val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wm2000->lock);
|
||||
|
||||
wm2000->spk_ena = val;
|
||||
|
||||
return wm2000_anc_set_mode(wm2000);
|
||||
ret = wm2000_anc_set_mode(wm2000);
|
||||
|
||||
mutex_unlock(&wm2000->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new wm2000_controls[] = {
|
||||
SOC_SINGLE("ANC Volume", WM2000_REG_ANC_GAIN_CTRL, 0, 255, 0),
|
||||
SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0,
|
||||
wm2000_anc_mode_get,
|
||||
wm2000_anc_mode_put),
|
||||
@@ -648,6 +680,9 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wm2000->lock);
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
||||
wm2000->anc_eng_ena = 1;
|
||||
@@ -655,7 +690,11 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
|
||||
if (SND_SOC_DAPM_EVENT_OFF(event))
|
||||
wm2000->anc_eng_ena = 0;
|
||||
|
||||
return wm2000_anc_set_mode(wm2000);
|
||||
ret = wm2000_anc_set_mode(wm2000);
|
||||
|
||||
mutex_unlock(&wm2000->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
|
||||
@@ -702,6 +741,9 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case WM2000_REG_SYS_START:
|
||||
case WM2000_REG_ANC_GAIN_CTRL:
|
||||
case WM2000_REG_MSE_TH1:
|
||||
case WM2000_REG_MSE_TH2:
|
||||
case WM2000_REG_SPEECH_CLARITY:
|
||||
case WM2000_REG_SYS_WATCHDOG:
|
||||
case WM2000_REG_ANA_VMID_PD_TIME:
|
||||
@@ -737,6 +779,8 @@ static int wm2000_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
|
||||
|
||||
snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP);
|
||||
|
||||
/* This will trigger a transition to standby mode by default */
|
||||
wm2000_anc_set_mode(wm2000);
|
||||
|
||||
@@ -782,6 +826,8 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&wm2000->lock);
|
||||
|
||||
dev_set_drvdata(&i2c->dev, wm2000);
|
||||
|
||||
wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
|
||||
@@ -823,10 +869,16 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
|
||||
reg = wm2000_read(i2c, WM2000_REG_REVISON);
|
||||
dev_info(&i2c->dev, "revision %c\n", reg + 'A');
|
||||
|
||||
wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK");
|
||||
if (IS_ERR(wm2000->mclk)) {
|
||||
ret = PTR_ERR(wm2000->mclk);
|
||||
dev_err(&i2c->dev, "Failed to get MCLK: %d\n", ret);
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
filename = "wm2000_anc.bin";
|
||||
pdata = dev_get_platdata(&i2c->dev);
|
||||
if (pdata) {
|
||||
wm2000->mclk_div = pdata->mclkdiv2;
|
||||
wm2000->speech_clarity = !pdata->speech_enh_disable;
|
||||
|
||||
if (pdata->download_file)
|
||||
|
@@ -10,6 +10,9 @@
|
||||
#define _WM2000_H
|
||||
|
||||
#define WM2000_REG_SYS_START 0x8000
|
||||
#define WM2000_REG_ANC_GAIN_CTRL 0x8fa2
|
||||
#define WM2000_REG_MSE_TH2 0x8fdf
|
||||
#define WM2000_REG_MSE_TH1 0x8fe0
|
||||
#define WM2000_REG_SPEECH_CLARITY 0x8fef
|
||||
#define WM2000_REG_SYS_WATCHDOG 0x8ff6
|
||||
#define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7
|
||||
|
@@ -1109,6 +1109,16 @@ static int wm2200_mixer_values[] = {
|
||||
static WM2200_MUX_CTL_DECL(name##_aux5); \
|
||||
static WM2200_MUX_CTL_DECL(name##_aux6);
|
||||
|
||||
static const char *wm2200_rxanc_input_sel_texts[] = {
|
||||
"None", "IN1", "IN2", "IN3",
|
||||
};
|
||||
|
||||
static const struct soc_enum wm2200_rxanc_input_sel =
|
||||
SOC_ENUM_SINGLE(WM2200_RXANC_SRC,
|
||||
WM2200_IN_RXANC_SEL_SHIFT,
|
||||
ARRAY_SIZE(wm2200_rxanc_input_sel_texts),
|
||||
wm2200_rxanc_input_sel_texts);
|
||||
|
||||
static const struct snd_kcontrol_new wm2200_snd_controls[] = {
|
||||
SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
|
||||
WM2200_IN1_OSR_SHIFT, 1, 0),
|
||||
@@ -1126,9 +1136,9 @@ SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
|
||||
|
||||
SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
|
||||
WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
|
||||
SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L,
|
||||
WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
|
||||
SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L,
|
||||
WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
|
||||
|
||||
SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
|
||||
@@ -1141,6 +1151,12 @@ SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
|
||||
WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
|
||||
SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA),
|
||||
SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA),
|
||||
|
||||
SND_SOC_BYTES("LHPF1 Coefficeints", WM2200_HPLPF1_2, 1),
|
||||
SND_SOC_BYTES("LHPF2 Coefficeints", WM2200_HPLPF2_2, 1),
|
||||
|
||||
SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
|
||||
WM2200_OUT1_OSR_SHIFT, 1, 0),
|
||||
SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
|
||||
@@ -1162,6 +1178,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
|
||||
digital_tlv),
|
||||
SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
|
||||
WM2200_SPK1R_MUTE_SHIFT, 1, 1),
|
||||
SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel),
|
||||
};
|
||||
|
||||
WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
|
||||
@@ -1548,6 +1565,10 @@ static int wm2200_probe(struct snd_soc_codec *codec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2182,6 +2203,7 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
|
||||
struct wm2200_priv *wm2200;
|
||||
unsigned int reg;
|
||||
int ret, i;
|
||||
int val;
|
||||
|
||||
wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
|
||||
GFP_KERNEL);
|
||||
@@ -2205,6 +2227,9 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
|
||||
wm2200->dsp[i].num = i + 1;
|
||||
wm2200->dsp[i].dev = &i2c->dev;
|
||||
wm2200->dsp[i].regmap = wm2200->regmap;
|
||||
wm2200->dsp[i].sysclk_reg = WM2200_CLOCKING_3;
|
||||
wm2200->dsp[i].sysclk_mask = WM2200_SYSCLK_FREQ_MASK;
|
||||
wm2200->dsp[i].sysclk_shift = WM2200_SYSCLK_FREQ_SHIFT;
|
||||
}
|
||||
|
||||
wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1;
|
||||
@@ -2215,6 +2240,9 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
|
||||
wm2200->dsp[1].mem = wm2200_dsp2_regions;
|
||||
wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm2200->dsp); i++)
|
||||
wm_adsp1_init(&wm2200->dsp[i]);
|
||||
|
||||
if (pdata)
|
||||
wm2200->pdata = *pdata;
|
||||
|
||||
@@ -2326,6 +2354,36 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
|
||||
regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < WM2200_MAX_MICBIAS; i++) {
|
||||
if (!wm2200->pdata.micbias[i].mb_lvl &&
|
||||
!wm2200->pdata.micbias[i].bypass)
|
||||
continue;
|
||||
|
||||
/* Apply default for bypass mode */
|
||||
if (!wm2200->pdata.micbias[i].mb_lvl)
|
||||
wm2200->pdata.micbias[i].mb_lvl
|
||||
= WM2200_MBIAS_LVL_1V5;
|
||||
|
||||
val = (wm2200->pdata.micbias[i].mb_lvl -1)
|
||||
<< WM2200_MICB1_LVL_SHIFT;
|
||||
|
||||
if (wm2200->pdata.micbias[i].discharge)
|
||||
val |= WM2200_MICB1_DISCH;
|
||||
|
||||
if (wm2200->pdata.micbias[i].fast_start)
|
||||
val |= WM2200_MICB1_RATE;
|
||||
|
||||
if (wm2200->pdata.micbias[i].bypass)
|
||||
val |= WM2200_MICB1_MODE;
|
||||
|
||||
regmap_update_bits(wm2200->regmap,
|
||||
WM2200_MIC_BIAS_CTRL_1 + i,
|
||||
WM2200_MICB1_LVL_MASK |
|
||||
WM2200_MICB1_DISCH |
|
||||
WM2200_MICB1_MODE |
|
||||
WM2200_MICB1_RATE, val);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
|
||||
regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
|
||||
WM2200_IN1_MODE_MASK |
|
||||
|
@@ -563,6 +563,19 @@ SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
|
||||
SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
|
||||
WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
|
||||
|
||||
SND_SOC_BYTES_MASK("EQ1 Coefficients", WM5100_EQ1_1, 20, WM5100_EQ1_ENA),
|
||||
SND_SOC_BYTES_MASK("EQ2 Coefficients", WM5100_EQ2_1, 20, WM5100_EQ2_ENA),
|
||||
SND_SOC_BYTES_MASK("EQ3 Coefficients", WM5100_EQ3_1, 20, WM5100_EQ3_ENA),
|
||||
SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
|
||||
|
||||
SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
|
||||
WM5100_DRCL_ENA | WM5100_DRCR_ENA),
|
||||
|
||||
SND_SOC_BYTES("LHPF1 Coefficeints", WM5100_HPLPF1_2, 1),
|
||||
SND_SOC_BYTES("LHPF2 Coefficeints", WM5100_HPLPF2_2, 1),
|
||||
SND_SOC_BYTES("LHPF3 Coefficeints", WM5100_HPLPF3_2, 1),
|
||||
SND_SOC_BYTES("LHPF4 Coefficeints", WM5100_HPLPF4_2, 1),
|
||||
|
||||
SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
|
||||
WM5100_OUT1_OSR_SHIFT, 1, 0),
|
||||
SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,
|
||||
|
@@ -45,6 +45,7 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
|
||||
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, 0, 600, 0);
|
||||
static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
|
||||
|
||||
static const struct wm_adsp_region wm5102_dsp1_regions[] = {
|
||||
{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
|
||||
@@ -603,6 +604,17 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM5102_NG_SRC(name, base) \
|
||||
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \
|
||||
SOC_SINGLE(name " NG EPOUT Switch", base, 4, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
|
||||
|
||||
static const struct snd_kcontrol_new wm5102_snd_controls[] = {
|
||||
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
|
||||
ARIZONA_IN1_OSR_SHIFT, 1, 0),
|
||||
@@ -611,32 +623,31 @@ SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
|
||||
SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
|
||||
ARIZONA_IN3_OSR_SHIFT, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
|
||||
ARIZONA_IN1R_CONTROL,
|
||||
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
|
||||
ARIZONA_IN2R_CONTROL,
|
||||
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
|
||||
ARIZONA_IN3R_CONTROL,
|
||||
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
|
||||
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
|
||||
ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
|
||||
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
|
||||
ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
|
||||
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
|
||||
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
|
||||
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
|
||||
|
||||
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
|
||||
ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
|
||||
ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
|
||||
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
|
||||
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
|
||||
@@ -774,6 +785,22 @@ SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
|
||||
SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
|
||||
ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
|
||||
|
||||
SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
|
||||
ARIZONA_NGATE_ENA_SHIFT, 1, 0),
|
||||
SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
|
||||
ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
|
||||
SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
|
||||
|
||||
WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
|
||||
WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
|
||||
WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
|
||||
WM5102_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
|
||||
WM5102_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
|
||||
WM5102_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
|
||||
WM5102_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
|
||||
WM5102_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
|
||||
WM5102_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
|
||||
@@ -880,6 +907,18 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
|
||||
|
||||
ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
|
||||
|
||||
ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
|
||||
|
||||
ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
|
||||
|
||||
ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
|
||||
|
||||
ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
|
||||
|
||||
@@ -1002,6 +1041,26 @@ 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),
|
||||
|
||||
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
|
||||
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
|
||||
ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
|
||||
ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
|
||||
ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
|
||||
ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
|
||||
ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
|
||||
ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
|
||||
ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
|
||||
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
|
||||
@@ -1138,6 +1197,18 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
|
||||
ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
|
||||
ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
|
||||
|
||||
ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
|
||||
ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
|
||||
|
||||
ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
|
||||
ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
|
||||
|
||||
ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
|
||||
ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
|
||||
|
||||
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
|
||||
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
|
||||
|
||||
WM_ADSP2("DSP1", 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
|
||||
@@ -1195,6 +1266,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
|
||||
{ name, "ASRC1R", "ASRC1R" }, \
|
||||
{ name, "ASRC2L", "ASRC2L" }, \
|
||||
{ name, "ASRC2R", "ASRC2R" }, \
|
||||
{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
|
||||
{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
|
||||
{ name, "ISRC1INT1", "ISRC1INT1" }, \
|
||||
{ name, "ISRC1INT2", "ISRC1INT2" }, \
|
||||
{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
|
||||
{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
|
||||
{ name, "ISRC2INT1", "ISRC2INT1" }, \
|
||||
{ name, "ISRC2INT2", "ISRC2INT2" }, \
|
||||
{ name, "DSP1.1", "DSP1" }, \
|
||||
{ name, "DSP1.2", "DSP1" }, \
|
||||
{ name, "DSP1.3", "DSP1" }, \
|
||||
@@ -1291,6 +1370,18 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
|
||||
{ "ASRC2L", NULL, "ASRC2L Input" },
|
||||
{ "ASRC2R", NULL, "ASRC2R Input" },
|
||||
|
||||
{ "ISRC1DEC1", NULL, "ISRC1DEC1 Input" },
|
||||
{ "ISRC1DEC2", NULL, "ISRC1DEC2 Input" },
|
||||
|
||||
{ "ISRC1INT1", NULL, "ISRC1INT1 Input" },
|
||||
{ "ISRC1INT2", NULL, "ISRC1INT2 Input" },
|
||||
|
||||
{ "ISRC2DEC1", NULL, "ISRC2DEC1 Input" },
|
||||
{ "ISRC2DEC2", NULL, "ISRC2DEC2 Input" },
|
||||
|
||||
{ "ISRC2INT1", NULL, "ISRC2INT1 Input" },
|
||||
{ "ISRC2INT2", NULL, "ISRC2INT2 Input" },
|
||||
|
||||
ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
|
||||
ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
|
||||
ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
|
||||
@@ -1338,6 +1429,18 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
|
||||
ARIZONA_MUX_ROUTES("ASRC2L"),
|
||||
ARIZONA_MUX_ROUTES("ASRC2R"),
|
||||
|
||||
ARIZONA_MUX_ROUTES("ISRC1INT1"),
|
||||
ARIZONA_MUX_ROUTES("ISRC1INT2"),
|
||||
|
||||
ARIZONA_MUX_ROUTES("ISRC1DEC1"),
|
||||
ARIZONA_MUX_ROUTES("ISRC1DEC2"),
|
||||
|
||||
ARIZONA_MUX_ROUTES("ISRC2INT1"),
|
||||
ARIZONA_MUX_ROUTES("ISRC2INT2"),
|
||||
|
||||
ARIZONA_MUX_ROUTES("ISRC2DEC1"),
|
||||
ARIZONA_MUX_ROUTES("ISRC2DEC2"),
|
||||
|
||||
ARIZONA_DSP_ROUTES("DSP1"),
|
||||
|
||||
{ "AEC Loopback", "HPOUT1L", "OUT1L" },
|
||||
@@ -1467,6 +1570,10 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
|
||||
|
||||
priv->core.arizona->dapm = &codec->dapm;
|
||||
|
@@ -41,6 +41,21 @@ static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
|
||||
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, 0, 600, 0);
|
||||
static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
|
||||
|
||||
#define WM5110_NG_SRC(name, base) \
|
||||
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT3L Switch", base, 4, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT3R Switch", base, 5, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKOUTR Switch", base, 7, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
|
||||
SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
|
||||
|
||||
static const struct snd_kcontrol_new wm5110_snd_controls[] = {
|
||||
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
|
||||
@@ -52,37 +67,35 @@ SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
|
||||
SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL,
|
||||
ARIZONA_IN4_OSR_SHIFT, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL,
|
||||
ARIZONA_IN1R_CONTROL,
|
||||
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
|
||||
ARIZONA_IN2R_CONTROL,
|
||||
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL,
|
||||
ARIZONA_IN3R_CONTROL,
|
||||
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
|
||||
ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
|
||||
ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
|
||||
ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
|
||||
ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
|
||||
ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
|
||||
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
|
||||
|
||||
SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1),
|
||||
SOC_DOUBLE_R("IN4 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_MUTE_SHIFT, 1, 1),
|
||||
|
||||
SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
|
||||
ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
|
||||
ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN4L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
|
||||
ARIZONA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
|
||||
ARIZONA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
|
||||
|
||||
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
|
||||
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
|
||||
@@ -263,6 +276,25 @@ SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
|
||||
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
|
||||
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
|
||||
|
||||
SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
|
||||
ARIZONA_NGATE_ENA_SHIFT, 1, 0),
|
||||
SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
|
||||
ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
|
||||
SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
|
||||
|
||||
WM5110_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
|
||||
WM5110_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
|
||||
WM5110_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
|
||||
WM5110_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
|
||||
WM5110_NG_SRC("HPOUT3L", ARIZONA_NOISE_GATE_SELECT_3L),
|
||||
WM5110_NG_SRC("HPOUT3R", ARIZONA_NOISE_GATE_SELECT_3R),
|
||||
WM5110_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
|
||||
WM5110_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
|
||||
WM5110_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
|
||||
WM5110_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
|
||||
WM5110_NG_SRC("SPKDAT2L", ARIZONA_NOISE_GATE_SELECT_6L),
|
||||
WM5110_NG_SRC("SPKDAT2R", ARIZONA_NOISE_GATE_SELECT_6R),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
|
||||
|
@@ -283,18 +283,16 @@ static int pga_event(struct snd_soc_dapm_widget *w,
|
||||
out->ramp = WM8350_RAMP_UP;
|
||||
out->active = 1;
|
||||
|
||||
if (!delayed_work_pending(&codec->dapm.delayed_work))
|
||||
schedule_delayed_work(&codec->dapm.delayed_work,
|
||||
msecs_to_jiffies(1));
|
||||
schedule_delayed_work(&codec->dapm.delayed_work,
|
||||
msecs_to_jiffies(1));
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
out->ramp = WM8350_RAMP_DOWN;
|
||||
out->active = 0;
|
||||
|
||||
if (!delayed_work_pending(&codec->dapm.delayed_work))
|
||||
schedule_delayed_work(&codec->dapm.delayed_work,
|
||||
msecs_to_jiffies(1));
|
||||
schedule_delayed_work(&codec->dapm.delayed_work,
|
||||
msecs_to_jiffies(1));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -395,9 +395,6 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
/* power down the PLL before reprogramming it */
|
||||
snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
|
||||
|
||||
if (!freq_in || !freq_out)
|
||||
return 0;
|
||||
|
||||
/* set PLLN and PRESCALE */
|
||||
snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
|
||||
pll_div.n | (pll_div.prescale << 4));
|
||||
|
@@ -2873,22 +2873,20 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (fll1 & WM8962_FLL_ENA) {
|
||||
/* This should be a massive overestimate but go even
|
||||
* higher if we'll error out
|
||||
*/
|
||||
if (wm8962->irq)
|
||||
timeout = msecs_to_jiffies(5);
|
||||
else
|
||||
timeout = msecs_to_jiffies(1);
|
||||
/* This should be a massive overestimate but go even
|
||||
* higher if we'll error out
|
||||
*/
|
||||
if (wm8962->irq)
|
||||
timeout = msecs_to_jiffies(5);
|
||||
else
|
||||
timeout = msecs_to_jiffies(1);
|
||||
|
||||
timeout = wait_for_completion_timeout(&wm8962->fll_lock,
|
||||
timeout);
|
||||
timeout = wait_for_completion_timeout(&wm8962->fll_lock,
|
||||
timeout);
|
||||
|
||||
if (timeout == 0 && wm8962->irq) {
|
||||
dev_err(codec->dev, "FLL lock timed out");
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
if (timeout == 0 && wm8962->irq) {
|
||||
dev_err(codec->dev, "FLL lock timed out");
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
wm8962->fll_fref = Fref;
|
||||
@@ -3189,7 +3187,7 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
|
||||
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
wm8962->beep = input_allocate_device();
|
||||
wm8962->beep = devm_input_allocate_device(codec->dev);
|
||||
if (!wm8962->beep) {
|
||||
dev_err(codec->dev, "Failed to allocate beep device\n");
|
||||
return;
|
||||
@@ -3210,7 +3208,6 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
|
||||
|
||||
ret = input_register_device(wm8962->beep);
|
||||
if (ret != 0) {
|
||||
input_free_device(wm8962->beep);
|
||||
wm8962->beep = NULL;
|
||||
dev_err(codec->dev, "Failed to register beep device\n");
|
||||
}
|
||||
@@ -3227,7 +3224,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
|
||||
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
device_remove_file(codec->dev, &dev_attr_beep);
|
||||
input_unregister_device(wm8962->beep);
|
||||
cancel_work_sync(&wm8962->beep_work);
|
||||
wm8962->beep = NULL;
|
||||
|
||||
@@ -3758,10 +3754,17 @@ static const struct i2c_device_id wm8962_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
|
||||
|
||||
static const struct of_device_id wm8962_of_match[] = {
|
||||
{ .compatible = "wlf,wm8962", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8962_of_match);
|
||||
|
||||
static struct i2c_driver wm8962_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8962",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8962_of_match,
|
||||
.pm = &wm8962_pm,
|
||||
},
|
||||
.probe = wm8962_i2c_probe,
|
||||
|
@@ -851,30 +851,33 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
struct pll_div pll_div;
|
||||
|
||||
codec = dai->codec;
|
||||
if (freq_in && freq_out) {
|
||||
if (!freq_in || !freq_out) {
|
||||
/* disable the PLL */
|
||||
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
|
||||
WM8983_PLLEN_MASK, 0);
|
||||
return 0;
|
||||
} else {
|
||||
ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable the PLL before re-programming it */
|
||||
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
|
||||
WM8983_PLLEN_MASK, 0);
|
||||
|
||||
/* set PLLN and PRESCALE */
|
||||
snd_soc_write(codec, WM8983_PLL_N,
|
||||
(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
|
||||
| pll_div.n);
|
||||
/* set PLLK */
|
||||
snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
|
||||
snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
|
||||
snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
|
||||
/* enable the PLL */
|
||||
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
|
||||
WM8983_PLLEN_MASK, WM8983_PLLEN);
|
||||
}
|
||||
|
||||
/* disable the PLL before re-programming it */
|
||||
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
|
||||
WM8983_PLLEN_MASK, 0);
|
||||
|
||||
if (!freq_in || !freq_out)
|
||||
return 0;
|
||||
|
||||
/* set PLLN and PRESCALE */
|
||||
snd_soc_write(codec, WM8983_PLL_N,
|
||||
(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
|
||||
| pll_div.n);
|
||||
/* set PLLK */
|
||||
snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
|
||||
snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
|
||||
snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
|
||||
/* enable the PLL */
|
||||
snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
|
||||
WM8983_PLLEN_MASK, WM8983_PLLEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -830,33 +830,30 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
struct pll_div pll_div;
|
||||
|
||||
codec = dai->codec;
|
||||
if (freq_in && freq_out) {
|
||||
if (!freq_in || !freq_out) {
|
||||
/* disable the PLL */
|
||||
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
|
||||
WM8985_PLLEN_MASK, 0);
|
||||
} else {
|
||||
ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* set PLLN and PRESCALE */
|
||||
snd_soc_write(codec, WM8985_PLL_N,
|
||||
(pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
|
||||
| pll_div.n);
|
||||
/* set PLLK */
|
||||
snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
|
||||
snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
|
||||
snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
|
||||
/* set the source of the clock to be the PLL */
|
||||
snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
|
||||
WM8985_CLKSEL_MASK, WM8985_CLKSEL);
|
||||
/* enable the PLL */
|
||||
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
|
||||
WM8985_PLLEN_MASK, WM8985_PLLEN);
|
||||
}
|
||||
|
||||
/* disable the PLL before reprogramming it */
|
||||
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
|
||||
WM8985_PLLEN_MASK, 0);
|
||||
|
||||
if (!freq_in || !freq_out)
|
||||
return 0;
|
||||
|
||||
/* set PLLN and PRESCALE */
|
||||
snd_soc_write(codec, WM8985_PLL_N,
|
||||
(pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
|
||||
| pll_div.n);
|
||||
/* set PLLK */
|
||||
snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
|
||||
snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
|
||||
snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
|
||||
/* set the source of the clock to be the PLL */
|
||||
snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
|
||||
WM8985_CLKSEL_MASK, WM8985_CLKSEL);
|
||||
/* enable the PLL */
|
||||
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
|
||||
WM8985_PLLEN_MASK, WM8985_PLLEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -3737,7 +3737,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = data;
|
||||
struct snd_soc_codec *codec = wm8994->hubs.codec;
|
||||
int reg, count;
|
||||
int reg, count, ret;
|
||||
|
||||
/*
|
||||
* Jack detection may have detected a removal simulataneously
|
||||
@@ -3783,11 +3783,11 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
|
||||
|
||||
/* Avoid a transient report when the accessory is being removed */
|
||||
if (wm8994->jackdet) {
|
||||
reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
|
||||
if (reg < 0) {
|
||||
ret = snd_soc_read(codec, WM1811_JACKDET_CTRL);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to read jack status: %d\n",
|
||||
reg);
|
||||
} else if (!(reg & WM1811_JACKDET_LVL)) {
|
||||
ret);
|
||||
} else if (!(ret & WM1811_JACKDET_LVL)) {
|
||||
dev_dbg(codec->dev, "Ignoring removed jack\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -103,9 +104,19 @@
|
||||
#define ADSP1_START_SHIFT 0 /* DSP1_START */
|
||||
#define ADSP1_START_WIDTH 1 /* DSP1_START */
|
||||
|
||||
#define ADSP2_CONTROL 0
|
||||
#define ADSP2_CLOCKING 1
|
||||
#define ADSP2_STATUS1 4
|
||||
/*
|
||||
* ADSP1 Control 31
|
||||
*/
|
||||
#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
|
||||
#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
|
||||
#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
|
||||
|
||||
#define ADSP2_CONTROL 0x0
|
||||
#define ADSP2_CLOCKING 0x1
|
||||
#define ADSP2_STATUS1 0x4
|
||||
#define ADSP2_WDMA_CONFIG_1 0x30
|
||||
#define ADSP2_WDMA_CONFIG_2 0x31
|
||||
#define ADSP2_RDMA_CONFIG_1 0x34
|
||||
|
||||
/*
|
||||
* ADSP2 Control
|
||||
@@ -143,6 +154,109 @@
|
||||
#define ADSP2_RAM_RDY_SHIFT 0
|
||||
#define ADSP2_RAM_RDY_WIDTH 1
|
||||
|
||||
struct wm_adsp_buf {
|
||||
struct list_head list;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
|
||||
struct list_head *list)
|
||||
{
|
||||
struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
||||
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf->buf) {
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (list)
|
||||
list_add_tail(&buf->list, list);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void wm_adsp_buf_free(struct list_head *list)
|
||||
{
|
||||
while (!list_empty(list)) {
|
||||
struct wm_adsp_buf *buf = list_first_entry(list,
|
||||
struct wm_adsp_buf,
|
||||
list);
|
||||
list_del(&buf->list);
|
||||
kfree(buf->buf);
|
||||
kfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
#define WM_ADSP_NUM_FW 4
|
||||
|
||||
static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
|
||||
"MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char *file;
|
||||
} wm_adsp_fw[WM_ADSP_NUM_FW] = {
|
||||
{ .file = "mbc-vss" },
|
||||
{ .file = "tx" },
|
||||
{ .file = "tx-spk" },
|
||||
{ .file = "rx-anc" },
|
||||
};
|
||||
|
||||
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
|
||||
return 0;
|
||||
|
||||
if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
|
||||
return -EINVAL;
|
||||
|
||||
if (adsp[e->shift_l].running)
|
||||
return -EBUSY;
|
||||
|
||||
adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct soc_enum wm_adsp_fw_enum[] = {
|
||||
SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
};
|
||||
|
||||
const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
|
||||
SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
|
||||
|
||||
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
|
||||
int type)
|
||||
@@ -156,8 +270,29 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
|
||||
unsigned int offset)
|
||||
{
|
||||
switch (region->type) {
|
||||
case WMFW_ADSP1_PM:
|
||||
return region->base + (offset * 3);
|
||||
case WMFW_ADSP1_DM:
|
||||
return region->base + (offset * 2);
|
||||
case WMFW_ADSP2_XM:
|
||||
return region->base + (offset * 2);
|
||||
case WMFW_ADSP2_YM:
|
||||
return region->base + (offset * 2);
|
||||
case WMFW_ADSP1_ZM:
|
||||
return region->base + (offset * 2);
|
||||
default:
|
||||
WARN_ON(NULL != "Unknown memory region type");
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
{
|
||||
LIST_HEAD(buf_list);
|
||||
const struct firmware *firmware;
|
||||
struct regmap *regmap = dsp->regmap;
|
||||
unsigned int pos = 0;
|
||||
@@ -169,7 +304,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
const struct wm_adsp_region *mem;
|
||||
const char *region_name;
|
||||
char *file, *text;
|
||||
void *buf;
|
||||
struct wm_adsp_buf *buf;
|
||||
unsigned int reg;
|
||||
int regions = 0;
|
||||
int ret, offset, type, sizes;
|
||||
@@ -178,7 +313,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
if (file == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
|
||||
wm_adsp_fw[dsp->fw].file);
|
||||
file[PAGE_SIZE - 1] = '\0';
|
||||
|
||||
ret = request_firmware(&firmware, file, dsp->dev);
|
||||
@@ -283,27 +419,27 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
case WMFW_ADSP1_PM:
|
||||
BUG_ON(!mem);
|
||||
region_name = "PM";
|
||||
reg = mem->base + (offset * 3);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP1_DM:
|
||||
BUG_ON(!mem);
|
||||
region_name = "DM";
|
||||
reg = mem->base + (offset * 2);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP2_XM:
|
||||
BUG_ON(!mem);
|
||||
region_name = "XM";
|
||||
reg = mem->base + (offset * 2);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP2_YM:
|
||||
BUG_ON(!mem);
|
||||
region_name = "YM";
|
||||
reg = mem->base + (offset * 2);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
case WMFW_ADSP1_ZM:
|
||||
BUG_ON(!mem);
|
||||
region_name = "ZM";
|
||||
reg = mem->base + (offset * 2);
|
||||
reg = wm_adsp_region_to_reg(mem, offset);
|
||||
break;
|
||||
default:
|
||||
adsp_warn(dsp,
|
||||
@@ -323,18 +459,16 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
}
|
||||
|
||||
if (reg) {
|
||||
buf = kmemdup(region->data, le32_to_cpu(region->len),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
buf = wm_adsp_buf_alloc(region->data,
|
||||
le32_to_cpu(region->len),
|
||||
&buf_list);
|
||||
if (!buf) {
|
||||
adsp_err(dsp, "Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = regmap_raw_write(regmap, reg, buf,
|
||||
le32_to_cpu(region->len));
|
||||
|
||||
kfree(buf);
|
||||
|
||||
ret = regmap_raw_write_async(regmap, reg, buf->buf,
|
||||
le32_to_cpu(region->len));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp,
|
||||
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
|
||||
@@ -348,12 +482,20 @@ static int wm_adsp_load(struct wm_adsp *dsp)
|
||||
pos += le32_to_cpu(region->len) + sizeof(*region);
|
||||
regions++;
|
||||
}
|
||||
|
||||
|
||||
ret = regmap_async_complete(regmap);
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to complete async write: %d\n", ret);
|
||||
goto out_fw;
|
||||
}
|
||||
|
||||
if (pos > firmware->size)
|
||||
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
|
||||
file, regions, pos - firmware->size);
|
||||
|
||||
out_fw:
|
||||
regmap_async_complete(regmap);
|
||||
wm_adsp_buf_free(&buf_list);
|
||||
release_firmware(firmware);
|
||||
out:
|
||||
kfree(file);
|
||||
@@ -361,22 +503,222 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_adsp_setup_algs(struct wm_adsp *dsp)
|
||||
{
|
||||
struct regmap *regmap = dsp->regmap;
|
||||
struct wmfw_adsp1_id_hdr adsp1_id;
|
||||
struct wmfw_adsp2_id_hdr adsp2_id;
|
||||
struct wmfw_adsp1_alg_hdr *adsp1_alg;
|
||||
struct wmfw_adsp2_alg_hdr *adsp2_alg;
|
||||
void *alg, *buf;
|
||||
struct wm_adsp_alg_region *region;
|
||||
const struct wm_adsp_region *mem;
|
||||
unsigned int pos, term;
|
||||
size_t algs, buf_size;
|
||||
__be32 val;
|
||||
int i, ret;
|
||||
|
||||
switch (dsp->type) {
|
||||
case WMFW_ADSP1:
|
||||
mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
|
||||
break;
|
||||
case WMFW_ADSP2:
|
||||
mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
|
||||
break;
|
||||
default:
|
||||
mem = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
BUG_ON(mem != NULL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dsp->type) {
|
||||
case WMFW_ADSP1:
|
||||
ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
|
||||
sizeof(adsp1_id));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm info: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf = &adsp1_id;
|
||||
buf_size = sizeof(adsp1_id);
|
||||
|
||||
algs = be32_to_cpu(adsp1_id.algs);
|
||||
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
|
||||
be32_to_cpu(adsp1_id.fw.id),
|
||||
(be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp1_id.fw.ver) & 0xff,
|
||||
algs);
|
||||
|
||||
pos = sizeof(adsp1_id) / 2;
|
||||
term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
|
||||
break;
|
||||
|
||||
case WMFW_ADSP2:
|
||||
ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
|
||||
sizeof(adsp2_id));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm info: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf = &adsp2_id;
|
||||
buf_size = sizeof(adsp2_id);
|
||||
|
||||
algs = be32_to_cpu(adsp2_id.algs);
|
||||
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
|
||||
be32_to_cpu(adsp2_id.fw.id),
|
||||
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
|
||||
algs);
|
||||
|
||||
pos = sizeof(adsp2_id) / 2;
|
||||
term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG_ON(NULL == "Unknown DSP type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (algs == 0) {
|
||||
adsp_err(dsp, "No algorithms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (algs > 1024) {
|
||||
adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
|
||||
print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
|
||||
buf, buf_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read the terminator first to validate the length */
|
||||
ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm list end: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (be32_to_cpu(val) != 0xbedead)
|
||||
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
|
||||
term, be32_to_cpu(val));
|
||||
|
||||
alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
|
||||
if (!alg)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read algorithm list: %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
adsp1_alg = alg;
|
||||
adsp2_alg = alg;
|
||||
|
||||
for (i = 0; i < algs; i++) {
|
||||
switch (dsp->type) {
|
||||
case WMFW_ADSP1:
|
||||
adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
|
||||
i, be32_to_cpu(adsp1_alg[i].alg.id),
|
||||
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
|
||||
be32_to_cpu(adsp1_alg[i].dm),
|
||||
be32_to_cpu(adsp1_alg[i].zm));
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP1_DM;
|
||||
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
|
||||
region->base = be32_to_cpu(adsp1_alg[i].dm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP1_ZM;
|
||||
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
|
||||
region->base = be32_to_cpu(adsp1_alg[i].zm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
break;
|
||||
|
||||
case WMFW_ADSP2:
|
||||
adsp_info(dsp,
|
||||
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
|
||||
i, be32_to_cpu(adsp2_alg[i].alg.id),
|
||||
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
|
||||
be32_to_cpu(adsp2_alg[i].xm),
|
||||
be32_to_cpu(adsp2_alg[i].ym),
|
||||
be32_to_cpu(adsp2_alg[i].zm));
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_XM;
|
||||
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
|
||||
region->base = be32_to_cpu(adsp2_alg[i].xm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_YM;
|
||||
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
|
||||
region->base = be32_to_cpu(adsp2_alg[i].ym);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_ZM;
|
||||
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
|
||||
region->base = be32_to_cpu(adsp2_alg[i].zm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(alg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
{
|
||||
LIST_HEAD(buf_list);
|
||||
struct regmap *regmap = dsp->regmap;
|
||||
struct wmfw_coeff_hdr *hdr;
|
||||
struct wmfw_coeff_item *blk;
|
||||
const struct firmware *firmware;
|
||||
const struct wm_adsp_region *mem;
|
||||
struct wm_adsp_alg_region *alg_region;
|
||||
const char *region_name;
|
||||
int ret, pos, blocks, type, offset, reg;
|
||||
char *file;
|
||||
void *buf;
|
||||
struct wm_adsp_buf *buf;
|
||||
int tmp;
|
||||
|
||||
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (file == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
|
||||
snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
|
||||
wm_adsp_fw[dsp->fw].file);
|
||||
file[PAGE_SIZE - 1] = '\0';
|
||||
|
||||
ret = request_firmware(&firmware, file, dsp->dev);
|
||||
@@ -399,6 +741,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
goto out_fw;
|
||||
}
|
||||
|
||||
switch (be32_to_cpu(hdr->rev) & 0xff) {
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
|
||||
file, be32_to_cpu(hdr->rev) & 0xff);
|
||||
ret = -EINVAL;
|
||||
goto out_fw;
|
||||
}
|
||||
|
||||
adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
|
||||
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
|
||||
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
|
||||
@@ -411,8 +763,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
pos - firmware->size > sizeof(*blk)) {
|
||||
blk = (void*)(&firmware->data[pos]);
|
||||
|
||||
type = be32_to_cpu(blk->type) & 0xff;
|
||||
offset = le32_to_cpu(blk->offset) & 0xffffff;
|
||||
type = le16_to_cpu(blk->type);
|
||||
offset = le16_to_cpu(blk->offset);
|
||||
|
||||
adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
|
||||
file, blocks, le32_to_cpu(blk->id),
|
||||
@@ -425,52 +777,105 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
reg = 0;
|
||||
region_name = "Unknown";
|
||||
switch (type) {
|
||||
case WMFW_NAME_TEXT:
|
||||
case WMFW_INFO_TEXT:
|
||||
case (WMFW_NAME_TEXT << 8):
|
||||
case (WMFW_INFO_TEXT << 8):
|
||||
break;
|
||||
case WMFW_ABSOLUTE:
|
||||
case (WMFW_ABSOLUTE << 8):
|
||||
region_name = "register";
|
||||
reg = offset;
|
||||
break;
|
||||
|
||||
case WMFW_ADSP1_DM:
|
||||
case WMFW_ADSP1_ZM:
|
||||
case WMFW_ADSP2_XM:
|
||||
case WMFW_ADSP2_YM:
|
||||
adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
|
||||
file, blocks, le32_to_cpu(blk->len),
|
||||
type, le32_to_cpu(blk->id));
|
||||
|
||||
mem = wm_adsp_find_region(dsp, type);
|
||||
if (!mem) {
|
||||
adsp_err(dsp, "No base for region %x\n", type);
|
||||
break;
|
||||
}
|
||||
|
||||
reg = 0;
|
||||
list_for_each_entry(alg_region,
|
||||
&dsp->alg_regions, list) {
|
||||
if (le32_to_cpu(blk->id) == alg_region->alg &&
|
||||
type == alg_region->type) {
|
||||
reg = alg_region->base;
|
||||
reg = wm_adsp_region_to_reg(mem,
|
||||
reg);
|
||||
reg += offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (reg == 0)
|
||||
adsp_err(dsp, "No %x for algorithm %x\n",
|
||||
type, le32_to_cpu(blk->id));
|
||||
break;
|
||||
|
||||
default:
|
||||
adsp_err(dsp, "Unknown region type %x\n", type);
|
||||
adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
|
||||
file, blocks, type, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reg) {
|
||||
buf = kmemdup(blk->data, le32_to_cpu(blk->len),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
buf = wm_adsp_buf_alloc(blk->data,
|
||||
le32_to_cpu(blk->len),
|
||||
&buf_list);
|
||||
if (!buf) {
|
||||
adsp_err(dsp, "Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = regmap_raw_write(regmap, reg, blk->data,
|
||||
le32_to_cpu(blk->len));
|
||||
adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
|
||||
file, blocks, le32_to_cpu(blk->len),
|
||||
reg);
|
||||
ret = regmap_raw_write_async(regmap, reg, buf->buf,
|
||||
le32_to_cpu(blk->len));
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp,
|
||||
"%s.%d: Failed to write to %x in %s\n",
|
||||
file, blocks, reg, region_name);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
pos += le32_to_cpu(blk->len) + sizeof(*blk);
|
||||
tmp = le32_to_cpu(blk->len) % 4;
|
||||
if (tmp)
|
||||
pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
|
||||
else
|
||||
pos += le32_to_cpu(blk->len) + sizeof(*blk);
|
||||
|
||||
blocks++;
|
||||
}
|
||||
|
||||
ret = regmap_async_complete(regmap);
|
||||
if (ret != 0)
|
||||
adsp_err(dsp, "Failed to complete async write: %d\n", ret);
|
||||
|
||||
if (pos > firmware->size)
|
||||
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
|
||||
file, blocks, pos - firmware->size);
|
||||
|
||||
out_fw:
|
||||
release_firmware(firmware);
|
||||
wm_adsp_buf_free(&buf_list);
|
||||
out:
|
||||
kfree(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wm_adsp1_init(struct wm_adsp *adsp)
|
||||
{
|
||||
INIT_LIST_HEAD(&adsp->alg_regions);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp1_init);
|
||||
|
||||
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
@@ -479,16 +884,46 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
||||
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm_adsp *dsp = &dsps[w->shift];
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
|
||||
ADSP1_SYS_ENA, ADSP1_SYS_ENA);
|
||||
|
||||
/*
|
||||
* For simplicity set the DSP clock rate to be the
|
||||
* SYSCLK rate rather than making it configurable.
|
||||
*/
|
||||
if(dsp->sysclk_reg) {
|
||||
ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = (val & dsp->sysclk_mask)
|
||||
>> dsp->sysclk_shift;
|
||||
|
||||
ret = regmap_update_bits(dsp->regmap,
|
||||
dsp->base + ADSP1_CONTROL_31,
|
||||
ADSP1_CLK_SEL_MASK, val);
|
||||
if (ret != 0) {
|
||||
adsp_err(dsp, "Failed to set clock rate: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = wm_adsp_load(dsp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
ret = wm_adsp_setup_algs(dsp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
ret = wm_adsp_load_coeff(dsp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
@@ -560,6 +995,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm_adsp *dsp = &dsps[w->shift];
|
||||
struct wm_adsp_alg_region *alg_region;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
@@ -625,6 +1061,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
ret = wm_adsp_setup_algs(dsp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
ret = wm_adsp_load_coeff(dsp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
@@ -635,13 +1075,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
ADSP2_CORE_ENA | ADSP2_START);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
dsp->running = true;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
dsp->running = false;
|
||||
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
|
||||
ADSP2_SYS_ENA | ADSP2_CORE_ENA |
|
||||
ADSP2_START, 0);
|
||||
|
||||
/* Make sure DMAs are quiesced */
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
|
||||
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
|
||||
|
||||
if (dsp->dvfs) {
|
||||
ret = regulator_set_voltage(dsp->dvfs, 1200000,
|
||||
1800000);
|
||||
@@ -656,6 +1105,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
"Failed to enable supply: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
while (!list_empty(&dsp->alg_regions)) {
|
||||
alg_region = list_first_entry(&dsp->alg_regions,
|
||||
struct wm_adsp_alg_region,
|
||||
list);
|
||||
list_del(&alg_region->list);
|
||||
kfree(alg_region);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -685,6 +1142,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&adsp->alg_regions);
|
||||
|
||||
if (dvfs) {
|
||||
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
|
||||
if (IS_ERR(adsp->dvfs)) {
|
||||
|
@@ -25,6 +25,13 @@ struct wm_adsp_region {
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
struct wm_adsp_alg_region {
|
||||
struct list_head list;
|
||||
unsigned int alg;
|
||||
int type;
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
struct wm_adsp {
|
||||
const char *part;
|
||||
int num;
|
||||
@@ -33,10 +40,18 @@ struct wm_adsp {
|
||||
struct regmap *regmap;
|
||||
|
||||
int base;
|
||||
int sysclk_reg;
|
||||
int sysclk_mask;
|
||||
int sysclk_shift;
|
||||
|
||||
struct list_head alg_regions;
|
||||
|
||||
const struct wm_adsp_region *mem;
|
||||
int num_mems;
|
||||
|
||||
int fw;
|
||||
bool running;
|
||||
|
||||
struct regulator *dvfs;
|
||||
};
|
||||
|
||||
@@ -50,6 +65,9 @@ struct wm_adsp {
|
||||
.shift = num, .event = wm_adsp2_event, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
|
||||
|
||||
extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
|
||||
|
||||
int wm_adsp1_init(struct wm_adsp *adsp);
|
||||
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
|
||||
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
@@ -93,15 +93,20 @@ struct wmfw_adsp2_alg_hdr {
|
||||
struct wmfw_coeff_hdr {
|
||||
u8 magic[4];
|
||||
__le32 len;
|
||||
__le32 ver;
|
||||
union {
|
||||
__be32 rev;
|
||||
__le32 ver;
|
||||
};
|
||||
union {
|
||||
__be32 core;
|
||||
__le32 core_ver;
|
||||
};
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
struct wmfw_coeff_item {
|
||||
union {
|
||||
__be32 type;
|
||||
__le32 offset;
|
||||
};
|
||||
__le16 offset;
|
||||
__le16 type;
|
||||
__le32 id;
|
||||
__le32 ver;
|
||||
__le32 sr;
|
||||
|
Reference in New Issue
Block a user