aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-10 09:24:50 +0200
committerTakashi Iwai <tiwai@suse.de>2011-05-10 09:24:50 +0200
commit1209842af4db98ffd7364ec9cf7d1a59293aa74c (patch)
tree33202a5468dc66456b67764eb6a272bd7e8c5af5 /sound
parentf0a2b0cb71e652ae9f0feeea91e5320e4faf25dc (diff)
parentf3eee00da39cba3c8a4db7048458969c620ac6d8 (diff)
Merge branch 'for-2.6.40' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/ssm2602.c302
-rw-r--r--sound/soc/codecs/ssm2602.h6
-rw-r--r--sound/soc/codecs/uda134x.c2
-rw-r--r--sound/soc/codecs/wm8915.c46
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c2
-rw-r--r--sound/soc/mid-x86/sst_platform.c6
-rw-r--r--sound/soc/soc-cache.c11
-rw-r--r--sound/soc/soc-core.c38
-rw-r--r--sound/soc/soc-dapm.c373
-rw-r--r--sound/soc/tegra/Kconfig8
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/trimslice.c228
13 files changed, 737 insertions, 289 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 06b6981b8d6..19241576b6b 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -120,7 +120,7 @@
*/
#define PM860X_DAPM_OUTPUT(wname, wevent) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
- .shift = 0, .invert = 0, .kcontrols = NULL, \
+ .shift = 0, .invert = 0, .kcontrol_news = NULL, \
.num_kcontrols = 0, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 7e219497536..70099c9d63c 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -40,17 +40,25 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include "ssm2602.h"
#define SSM2602_VERSION "0.1"
+enum ssm2602_type {
+ SSM2602,
+ SSM2604,
+};
+
/* codec private data */
struct ssm2602_priv {
unsigned int sysclk;
enum snd_soc_control_type control_type;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
+
+ enum ssm2602_type type;
};
/*
@@ -60,8 +68,8 @@ struct ssm2602_priv {
* There is no point in caching the reset register
*/
static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
- 0x0017, 0x0017, 0x0079, 0x0079,
- 0x0000, 0x0000, 0x0000, 0x000a,
+ 0x0097, 0x0097, 0x0079, 0x0079,
+ 0x000a, 0x0008, 0x009f, 0x000a,
0x0000, 0x0000
};
@@ -80,172 +88,186 @@ static const struct soc_enum ssm2602_enum[] = {
SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
};
-static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+static const unsigned int ssm260x_outmix_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+ 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
+};
-SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
- 0, 127, 0),
-SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
- 7, 1, 0),
+static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
-SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
+ ssm260x_inpga_tlv),
SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
-SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
-SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
-SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
-
-SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
-
SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
-SOC_ENUM("Capture Source", ssm2602_enum[0]),
-
SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
};
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+ 0, 127, 0, ssm260x_outmix_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+ 7, 1, 0),
+SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
+ ssm260x_sidetone_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+};
+
/* Output Mixer */
-static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
-SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
};
/* Input mux */
static const struct snd_kcontrol_new ssm2602_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
-static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
-SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
- &ssm2602_output_mixer_controls[0],
- ARRAY_SIZE(ssm2602_output_mixer_controls)),
+static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, 0, 0),
+
SND_SOC_DAPM_OUTPUT("LOUT"),
-SND_SOC_DAPM_OUTPUT("LHPOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
-SND_SOC_DAPM_OUTPUT("RHPOUT"),
-SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+ ssm260x_output_mixer_controls,
+ ARRAY_SIZE(ssm260x_output_mixer_controls)),
+
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
-SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
SND_SOC_DAPM_INPUT("MICIN"),
-SND_SOC_DAPM_INPUT("RLINEIN"),
-SND_SOC_DAPM_INPUT("LLINEIN"),
};
-static const struct snd_soc_dapm_route audio_conn[] = {
- /* output mixer */
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+ ssm260x_output_mixer_controls,
+ ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
+};
+
+static const struct snd_soc_dapm_route ssm260x_routes[] = {
+ {"DAC", NULL, "Digital Core Power"},
+ {"ADC", NULL, "Digital Core Power"},
+
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+ {"ROUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+
+ {"Line Input", NULL, "LLINEIN"},
+ {"Line Input", NULL, "RLINEIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2602_routes[] = {
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
- /* outputs */
{"RHPOUT", NULL, "Output Mixer"},
- {"ROUT", NULL, "Output Mixer"},
{"LHPOUT", NULL, "Output Mixer"},
- {"LOUT", NULL, "Output Mixer"},
- /* input mux */
{"Input Mux", "Line", "Line Input"},
{"Input Mux", "Mic", "Mic Bias"},
{"ADC", NULL, "Input Mux"},
- /* inputs */
- {"Line Input", NULL, "LLINEIN"},
- {"Line Input", NULL, "RLINEIN"},
{"Mic Bias", NULL, "MICIN"},
};
-static int ssm2602_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
- ARRAY_SIZE(ssm2602_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
-
- return 0;
-}
+static const struct snd_soc_dapm_route ssm2604_routes[] = {
+ {"ADC", NULL, "Line Input"},
+};
-struct _coeff_div {
+struct ssm2602_coeff {
u32 mclk;
u32 rate;
- u16 fs;
- u8 sr:4;
- u8 bosr:1;
- u8 usb:1;
+ u8 srate;
};
-/* codec mclk clock divider coefficients */
-static const struct _coeff_div coeff_div[] = {
+#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
+
+/* codec mclk clock coefficients */
+static const struct ssm2602_coeff ssm2602_coeff_table[] = {
/* 48k */
- {12288000, 48000, 256, 0x0, 0x0, 0x0},
- {18432000, 48000, 384, 0x0, 0x1, 0x0},
- {12000000, 48000, 250, 0x0, 0x0, 0x1},
+ {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
+ {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
+ {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
/* 32k */
- {12288000, 32000, 384, 0x6, 0x0, 0x0},
- {18432000, 32000, 576, 0x6, 0x1, 0x0},
- {12000000, 32000, 375, 0x6, 0x0, 0x1},
+ {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
+ {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
+ {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
/* 8k */
- {12288000, 8000, 1536, 0x3, 0x0, 0x0},
- {18432000, 8000, 2304, 0x3, 0x1, 0x0},
- {11289600, 8000, 1408, 0xb, 0x0, 0x0},
- {16934400, 8000, 2112, 0xb, 0x1, 0x0},
- {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+ {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
+ {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
+ {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
+ {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
+ {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
/* 96k */
- {12288000, 96000, 128, 0x7, 0x0, 0x0},
- {18432000, 96000, 192, 0x7, 0x1, 0x0},
- {12000000, 96000, 125, 0x7, 0x0, 0x1},
+ {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
+ {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
+ {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
/* 44.1k */
- {11289600, 44100, 256, 0x8, 0x0, 0x0},
- {16934400, 44100, 384, 0x8, 0x1, 0x0},
- {12000000, 44100, 272, 0x8, 0x1, 0x1},
+ {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
+ {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
+ {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
/* 88.2k */
- {11289600, 88200, 128, 0xf, 0x0, 0x0},
- {16934400, 88200, 192, 0xf, 0x1, 0x0},
- {12000000, 88200, 136, 0xf, 0x1, 0x1},
+ {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
+ {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
+ {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
};
-static inline int get_coeff(int mclk, int rate)
+static inline int ssm2602_get_coeff(int mclk, int rate)
{
int i;
- for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
- if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
- return i;
+ for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
+ if (ssm2602_coeff_table[i].rate == rate &&
+ ssm2602_coeff_table[i].mclk == mclk)
+ return ssm2602_coeff_table[i].srate;
}
- return i;
+ return -EINVAL;
}
static int ssm2602_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- u16 srate;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
- int i = get_coeff(ssm2602->sysclk, params_rate(params));
+ int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
if (substream == ssm2602->slave_substream) {
dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
- /*no match is found*/
- if (i == ARRAY_SIZE(coeff_div))
- return -EINVAL;
+ if (srate < 0)
+ return srate;
- srate = (coeff_div[i].sr << 2) |
- (coeff_div[i].bosr << 1) | coeff_div[i].usb;
-
- snd_soc_write(codec, SSM2602_ACTIVE, 0);
snd_soc_write(codec, SSM2602_SRATE, srate);
/* bit size */
@@ -263,7 +285,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
break;
}
snd_soc_write(codec, SSM2602_IFACE, iface);
- snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
return 0;
}
@@ -305,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
return 0;
}
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
- /* set active */
- snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
-
- return 0;
-}
-
static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -323,16 +333,13 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- /* deactivate */
- if (!codec->active)
- snd_soc_write(codec, SSM2602_ACTIVE, 0);
-
if (ssm2602->master_substream == substream)
ssm2602->master_substream = ssm2602->slave_substream;
ssm2602->slave_substream = NULL;
}
+
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
@@ -439,7 +446,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_OFF:
/* everything off, dac mute, inactive */
- snd_soc_write(codec, SSM2602_ACTIVE, 0);
snd_soc_write(codec, SSM2602_PWR, 0xffff);
break;
@@ -457,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
static struct snd_soc_dai_ops ssm2602_dai_ops = {
.startup = ssm2602_startup,
- .prepare = ssm2602_pcm_prepare,
.hw_params = ssm2602_hw_params,
.shutdown = ssm2602_shutdown,
.digital_mute = ssm2602_mute,
@@ -499,8 +504,46 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
static int ssm2602_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret, reg;
+
+ reg = snd_soc_read(codec, SSM2602_LOUT1V);
+ snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+ reg = snd_soc_read(codec, SSM2602_ROUT1V);
+ snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+
+ ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
+ ARRAY_SIZE(ssm2602_snd_controls));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+ ARRAY_SIZE(ssm2602_dapm_widgets));
+ if (ret)
+ return ret;
+
+ return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
+ ARRAY_SIZE(ssm2602_routes));
+}
+
+static int ssm2604_probe(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+ ARRAY_SIZE(ssm2604_dapm_widgets));
+ if (ret)
+ return ret;
+
+ return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
+ ARRAY_SIZE(ssm2604_routes));
+}
+
+static int ssm260x_probe(struct snd_soc_codec *codec)
+{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- int ret = 0, reg;
+ int ret, reg;
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
@@ -516,27 +559,25 @@ static int ssm2602_probe(struct snd_soc_codec *codec)
return ret;
}
- /*power on device*/
- snd_soc_write(codec, SSM2602_ACTIVE, 0);
/* set the update bits */
reg = snd_soc_read(codec, SSM2602_LINVOL);
snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
reg = snd_soc_read(codec, SSM2602_RINVOL);
snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
- reg = snd_soc_read(codec, SSM2602_LOUT1V);
- snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
- reg = snd_soc_read(codec, SSM2602_ROUT1V);
- snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
/*select Line in as default input*/
snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST);
- snd_soc_write(codec, SSM2602_PWR, 0);
- snd_soc_add_controls(codec, ssm2602_snd_controls,
- ARRAY_SIZE(ssm2602_snd_controls));
- ssm2602_add_widgets(codec);
+ switch (ssm2602->type) {
+ case SSM2602:
+ ret = ssm2602_probe(codec);
+ break;
+ case SSM2604:
+ ret = ssm2604_probe(codec);
+ break;
+ }
- return 0;
+ return ret;
}
/* remove everything here */
@@ -547,14 +588,21 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
- .probe = ssm2602_probe,
+ .probe = ssm260x_probe,
.remove = ssm2602_remove,
.suspend = ssm2602_suspend,
.resume = ssm2602_resume,
.set_bias_level = ssm2602_set_bias_level,
- .reg_cache_size = sizeof(ssm2602_reg),
+ .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = ssm2602_reg,
+
+ .controls = ssm260x_snd_controls,
+ .num_controls = ARRAY_SIZE(ssm260x_snd_controls),
+ .dapm_widgets = ssm260x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
+ .dapm_routes = ssm260x_routes,
+ .num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
};
#if defined(CONFIG_SPI_MASTER)
@@ -569,6 +617,7 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)
spi_set_drvdata(spi, ssm2602);
ssm2602->control_type = SND_SOC_SPI;
+ ssm2602->type = SSM2602;
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
@@ -601,7 +650,7 @@ static struct spi_driver ssm2602_spi_driver = {
* low = 0x1a
* high = 0x1b
*/
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
+static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct ssm2602_priv *ssm2602;
@@ -613,6 +662,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, ssm2602);
ssm2602->control_type = SND_SOC_I2C;
+ ssm2602->type = id->driver_data;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
@@ -621,7 +671,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
return ret;
}
-static int ssm2602_i2c_remove(struct i2c_client *client)
+static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
kfree(i2c_get_clientdata(client));
@@ -629,7 +679,9 @@ static int ssm2602_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id ssm2602_i2c_id[] = {
- { "ssm2602", 0 },
+ { "ssm2602", SSM2602 },
+ { "ssm2603", SSM2602 },
+ { "ssm2604", SSM2604 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
@@ -641,7 +693,7 @@ static struct i2c_driver ssm2602_i2c_driver = {
.owner = THIS_MODULE,
},
.probe = ssm2602_i2c_probe,
- .remove = ssm2602_i2c_remove,
+ .remove = __devexit_p(ssm2602_i2c_remove),
.id_table = ssm2602_i2c_id,
};
#endif
@@ -679,6 +731,6 @@ static void __exit ssm2602_exit(void)
}
module_exit(ssm2602_exit);
-MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
MODULE_AUTHOR("Cliff Cai");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index 42a47d0f8e2..b98c6916803 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -117,11 +117,5 @@
#define SSM2602_CACHEREGNUM 10
#define SSM2602_SYSCLK 0
-#define SSM2602_DAI 0
-
-struct ssm2602_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
#endif
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 48ffd406a71..a7b8f301bad 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.reg_cache_step = 1,
.read = uda134x_read_reg_cache,
.write = uda134x_write,
-#ifdef POWER_OFF_ON_STANDBY
.set_bias_level = uda134x_set_bias_level,
-#endif
};
static int __devinit uda134x_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
index 4a3c5cc77e5..ccc9bd83279 100644
--- a/sound/soc/codecs/wm8915.c
+++ b/sound/soc/codecs/wm8915.c
@@ -991,17 +991,16 @@ SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA("ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-SND_SOC_DAPM_MUX("IN1 Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN2 Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
-/* FIXME - these need to be concentrator widgets */
SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
@@ -1172,28 +1171,33 @@ static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
{ "DMIC1L", NULL, "DMIC1" },
{ "DMIC1R", NULL, "DMIC1" },
- { "ADC", NULL, "ADCL" },
- { "ADC", NULL, "ADCR" },
+ { "IN1L Mux", "ADC", "ADCL" },
+ { "IN1L Mux", "DMIC1", "DMIC1L" },
+ { "IN1L Mux", "DMIC2", "DMIC2L" },
+
+ { "IN1R Mux", "ADC", "ADCR" },
+ { "IN1R Mux", "DMIC1", "DMIC1R" },
+ { "IN1R Mux", "DMIC2", "DMIC2R" },
- { "IN1 Mux", "ADC", "ADC" },
- { "IN1 Mux", "DMIC1", "DMIC1" },
- { "IN1 Mux", "DMIC2", "DMIC2" },
+ { "IN2L Mux", "ADC", "ADCL" },
+ { "IN2L Mux", "DMIC1", "DMIC1L" },
+ { "IN2L Mux", "DMIC2", "DMIC2L" },
- { "IN2 Mux", "ADC", "ADC" },
- { "IN2 Mux", "DMIC1", "DMIC1" },
- { "IN2 Mux", "DMIC2", "DMIC2" },
+ { "IN2R Mux", "ADC", "ADCR" },
+ { "IN2R Mux", "DMIC1", "DMIC1R" },
+ { "IN2R Mux", "DMIC2", "DMIC2R" },
- { "Left Sidetone", "IN1", "IN1 Mux" },
- { "Left Sidetone", "IN2", "IN2 Mux" },
+ { "Left Sidetone", "IN1", "IN1L Mux" },
+ { "Left Sidetone", "IN2", "IN2L Mux" },
- { "Right Sidetone", "IN1", "IN1 Mux" },
- { "Right Sidetone", "IN2", "IN2 Mux" },
+ { "Right Sidetone", "IN1", "IN1R Mux" },
+ { "Right Sidetone", "IN2", "IN2R Mux" },
- { "DSP1TXL", "IN1 Switch", "IN1 Mux" },
- { "DSP1TXR", "IN1 Switch", "IN1 Mux" },
+ { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+ { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
- { "DSP2TXL", "IN1 Switch", "IN2 Mux" },
- { "DSP2TXR", "IN1 Switch", "IN2 Mux" },
+ { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+ { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
{ "AIF1TX0", NULL, "DSP1TXL" },
{ "AIF1TX1", NULL, "DSP1TXR" },
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 419bf4f5534..cd22a54b2f1 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
uint32_t conf;
- if (!dai->active)
+ if (dai->active)
return;
conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index 9765fb81a5e..5a946b4115a 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -380,6 +380,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
static struct snd_pcm_ops sst_platform_ops = {
.open = sst_platform_open,
.close = sst_platform_close,
@@ -388,6 +393,7 @@ static struct snd_pcm_ops sst_platform_ops = {
.trigger = sst_platform_pcm_trigger,
.pointer = sst_platform_pcm_pointer,
.hw_params = sst_platform_pcm_hw_params,
+ .hw_free = sst_platform_pcm_hw_free,
};
static void sst_pcm_free(struct snd_pcm *pcm)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index a217db25670..687beec5647 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -404,12 +404,13 @@ static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int r
{
int ret;
- /* Ensure that the base register is volatile. Subsequently
- * any other register that is touched by this routine should be
- * volatile as well to ensure that we don't get out of sync with
- * the cache.
+ /* To ensure that we don't get out of sync with the cache, check
+ * whether the base register is volatile or if we've directly asked
+ * to bypass the cache. Out of bounds registers are considered
+ * volatile.
*/
- if (!snd_soc_codec_volatile_register(codec, reg)
+ if (!codec->cache_bypass
+ && !snd_soc_codec_volatile_register(codec, reg)
&& reg < codec->driver->reg_cache_size)
return -EINVAL;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a823654ef36..a477e218aa2 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -302,13 +302,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
printk(KERN_WARNING
"ASoC: Failed to create codec register debugfs file\n");
- codec->dapm.debugfs_dapm = debugfs_create_dir("dapm",
- codec->debugfs_codec_root);
- if (!codec->dapm.debugfs_dapm)
- printk(KERN_WARNING
- "Failed to create DAPM debugfs directory\n");
-
- snd_soc_dapm_debugfs_init(&codec->dapm);
+ snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
}
static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
@@ -1499,6 +1493,12 @@ static int soc_probe_codec(struct snd_soc_card *card,
if (!try_module_get(codec->dev->driver->owner))
return -ENODEV;
+ soc_init_codec_debugfs(codec);
+
+ if (driver->dapm_widgets)
+ snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
+ driver->num_dapm_widgets);
+
if (driver->probe) {
ret = driver->probe(codec);
if (ret < 0) {
@@ -1512,15 +1512,10 @@ static int soc_probe_codec(struct snd_soc_card *card,
if (driver->controls)
snd_soc_add_controls(codec, driver->controls,
driver->num_controls);
- if (driver->dapm_widgets)
- snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
- driver->num_dapm_widgets);
if (driver->dapm_routes)
snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
driver->num_dapm_routes);
- soc_init_codec_debugfs(codec);
-
/* mark codec as probed and add to card codec list */
codec->probed = 1;
list_add(&codec->card_list, &card->codec_dev_list);
@@ -1529,6 +1524,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
return 0;
err_probe:
+ soc_cleanup_codec_debugfs(codec);
module_put(codec->dev->driver->owner);
return ret;
@@ -1879,6 +1875,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
card->dapm.card = card;
list_add(&card->dapm.list, &card->dapm_list);
+#ifdef CONFIG_DEBUG_FS
+ snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
+#endif
+
#ifdef CONFIG_PM_SLEEP
/* deferred resume work */
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
@@ -1925,16 +1925,6 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
-#ifdef CONFIG_DEBUG_FS
- card->dapm.debugfs_dapm = debugfs_create_dir("dapm",
- card->debugfs_card_root);
- if (!card->dapm.debugfs_dapm)
- printk(KERN_WARNING
- "Failed to create card DAPM debugfs directory\n");
-
- snd_soc_dapm_debugfs_init(&card->dapm);
-#endif
-
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
@@ -2047,6 +2037,8 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
if (card->remove)
card->remove(card);
+ snd_soc_dapm_free(&card->dapm);
+
kfree(card->rtd);
snd_card_free(card->snd_card);
return 0;
@@ -3365,6 +3357,8 @@ int snd_soc_register_card(struct snd_soc_card *card)
if (!card->name || !card->dev)
return -EINVAL;
+ dev_set_drvdata(card->dev, card);
+
snd_soc_initialize_card_lists(card);
soc_init_card_debugfs(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 378f08adee5..456617e6378 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -187,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_mixer_named_ctl: {
int val;
struct soc_mixer_control *mc = (struct soc_mixer_control *)
- w->kcontrols[i].private_value;
+ w->kcontrol_news[i].private_value;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
@@ -204,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
}
break;
case snd_soc_dapm_mux: {
- struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+ struct soc_enum *e = (struct soc_enum *)
+ w->kcontrol_news[i].private_value;
int val, item, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
@@ -220,7 +221,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
}
break;
case snd_soc_dapm_virt_mux: {
- struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+ struct soc_enum *e = (struct soc_enum *)
+ w->kcontrol_news[i].private_value;
p->connect = 0;
/* since a virtual mux has no backing registers to
@@ -235,7 +237,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
break;
case snd_soc_dapm_value_mux: {
struct soc_enum *e = (struct soc_enum *)
- w->kcontrols[i].private_value;
+ w->kcontrol_news[i].private_value;
int val, item;
val = snd_soc_read(w->codec, e->reg);
@@ -310,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
/* search for mixer kcontrol */
for (i = 0; i < dest->num_kcontrols; i++) {
- if (!strcmp(control_name, dest->kcontrols[i].name)) {
+ if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
list_add(&path->list, &dapm->card->paths);
list_add(&path->list_sink, &dest->sources);
list_add(&path->list_source, &src->sinks);
- path->name = dest->kcontrols[i].name;
+ path->name = dest->kcontrol_news[i].name;
dapm_set_path_status(dest, path, i);
return 0;
}
@@ -322,6 +324,28 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
return -ENODEV;
}
+static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
+ const struct snd_kcontrol_new *kcontrol_new,
+ struct snd_kcontrol **kcontrol)
+{
+ struct snd_soc_dapm_widget *w;
+ int i;
+
+ *kcontrol = NULL;
+
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+ for (i = 0; i < w->num_kcontrols; i++) {
+ if (&w->kcontrol_news[i] == kcontrol_new) {
+ if (w->kcontrols)
+ *kcontrol = w->kcontrols[i];
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
/* create new dapm mixer control */
static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *w)
@@ -331,6 +355,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_path *path;
struct snd_card *card = dapm->card->snd_card;
const char *prefix;
+ struct snd_soc_dapm_widget_list *wlist;
+ size_t wlistsize;
if (dapm->codec)
prefix = dapm->codec->name_prefix;
@@ -349,23 +375,37 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
list_for_each_entry(path, &w->sources, list_sink) {
/* mixer/mux paths name must match control name */
- if (path->name != (char*)w->kcontrols[i].name)
+ if (path->name != (char *)w->kcontrol_news[i].name)
continue;
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ sizeof(struct snd_soc_dapm_widget *),
+ wlist = kzalloc(wlistsize, GFP_KERNEL);
+ if (wlist == NULL) {