Merge branch 'for-3.0' into for-3.1
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c46e7d8..7415878 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -510,7 +510,7 @@
struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
- int dev_power;
+ enum snd_soc_bias_level target_bias_level;
struct list_head list;
#ifdef CONFIG_DEBUG_FS
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f1de3e0..f55efc1 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -214,10 +214,10 @@
* @OFF: Power Off. No restrictions on transition times.
*/
enum snd_soc_bias_level {
- SND_SOC_BIAS_OFF,
- SND_SOC_BIAS_STANDBY,
- SND_SOC_BIAS_PREPARE,
- SND_SOC_BIAS_ON,
+ SND_SOC_BIAS_OFF = 0,
+ SND_SOC_BIAS_STANDBY = 1,
+ SND_SOC_BIAS_PREPARE = 2,
+ SND_SOC_BIAS_ON = 3,
};
struct snd_jack;
@@ -726,8 +726,10 @@
/* callbacks */
int (*set_bias_level)(struct snd_soc_card *,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
int (*set_bias_level_post)(struct snd_soc_card *,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
long pmdown_time;
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index d0e7532..51dde4e 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -382,7 +382,7 @@
}
if (dai->driver->capture.channels_min) {
- pr_debug("at32-pcm:"
+ pr_debug("atmel-pcm:"
"Allocating PCM capture DMA buffer\n");
ret = atmel_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
index 2597329..5e0a95e 100644
--- a/sound/soc/atmel/atmel-pcm.h
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -60,7 +60,7 @@
* This structure, shared between the PCM driver and the interface,
* contains all information required by the PCM driver to perform the
* PDC DMA operation. All fields except dma_intr_handler() are initialized
- * by the interface. The dms_intr_handler() pointer is set by the PCM
+ * by the interface. The dma_intr_handler() pointer is set by the PCM
* driver and called by the interface SSC interrupt handler if it is
* non-NULL.
*/
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index eda955b..f53dc09 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -838,10 +838,8 @@
}
ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
- if (!ssc_pdev) {
- ssc_free(ssc);
+ if (!ssc_pdev)
return -ENOMEM;
- }
/* If we can grab the SSC briefly to parent the DAI device off it */
ssc = ssc_request(ssc_id);
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 95572d2..bad3aa1 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -92,6 +92,7 @@
};
static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
static int mclk_on;
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 754c496..1e9a801 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -30,10 +30,15 @@
#include <linux/spi/spi.h>
#include "ad1836.h"
+enum ad1836_type {
+ AD1835,
+ AD1836,
+ AD1838,
+};
+
/* codec private data */
struct ad1836_priv {
- enum snd_soc_control_type control_type;
- void *control_data;
+ enum ad1836_type type;
};
/*
@@ -44,29 +49,60 @@
static const struct soc_enum ad1836_deemp_enum =
SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp);
-static const struct snd_kcontrol_new ad1836_snd_controls[] = {
- /* DAC volume control */
- SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL,
- AD1836_DAC_R1_VOL, 0, 0x3FF, 0),
- SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL,
- AD1836_DAC_R2_VOL, 0, 0x3FF, 0),
- SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL,
- AD1836_DAC_R3_VOL, 0, 0x3FF, 0),
+#define AD1836_DAC_VOLUME(x) \
+ SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
+ AD1836_DAC_R_VOL(x), 0, 0x3FF, 0)
- /* ADC switch control */
- SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE,
- AD1836_ADCR1_MUTE, 1, 1),
- SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE,
- AD1836_ADCR2_MUTE, 1, 1),
+#define AD1836_DAC_SWITCH(x) \
+ SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \
+ AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
- /* DAC switch control */
- SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE,
- AD1836_DACR1_MUTE, 1, 1),
- SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE,
- AD1836_DACR2_MUTE, 1, 1),
- SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE,
- AD1836_DACR3_MUTE, 1, 1),
+#define AD1836_ADC_SWITCH(x) \
+ SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \
+ AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
+static const struct snd_kcontrol_new ad183x_dac_controls[] = {
+ AD1836_DAC_VOLUME(1),
+ AD1836_DAC_SWITCH(1),
+ AD1836_DAC_VOLUME(2),
+ AD1836_DAC_SWITCH(2),
+ AD1836_DAC_VOLUME(3),
+ AD1836_DAC_SWITCH(3),
+ AD1836_DAC_VOLUME(4),
+ AD1836_DAC_SWITCH(4),
+};
+
+static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+};
+
+static const struct snd_soc_dapm_route ad183x_dac_routes[] = {
+ { "DAC1OUT", NULL, "DAC" },
+ { "DAC2OUT", NULL, "DAC" },
+ { "DAC3OUT", NULL, "DAC" },
+ { "DAC4OUT", NULL, "DAC" },
+};
+
+static const struct snd_kcontrol_new ad183x_adc_controls[] = {
+ AD1836_ADC_SWITCH(1),
+ AD1836_ADC_SWITCH(2),
+ AD1836_ADC_SWITCH(3),
+};
+
+static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("ADC1IN"),
+ SND_SOC_DAPM_INPUT("ADC2IN"),
+};
+
+static const struct snd_soc_dapm_route ad183x_adc_routes[] = {
+ { "ADC", NULL, "ADC1IN" },
+ { "ADC", NULL, "ADC2IN" },
+};
+
+static const struct snd_kcontrol_new ad183x_controls[] = {
/* ADC high-pass filter */
SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1,
AD1836_ADC_HIGHPASS_FILTER, 1, 0),
@@ -75,27 +111,24 @@
SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum),
};
-static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1,
AD1836_DAC_POWERDOWN, 1),
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1,
AD1836_ADC_POWERDOWN, 1, NULL, 0),
- SND_SOC_DAPM_OUTPUT("DAC1OUT"),
- SND_SOC_DAPM_OUTPUT("DAC2OUT"),
- SND_SOC_DAPM_OUTPUT("DAC3OUT"),
- SND_SOC_DAPM_INPUT("ADC1IN"),
- SND_SOC_DAPM_INPUT("ADC2IN"),
};
-static const struct snd_soc_dapm_route audio_paths[] = {
+static const struct snd_soc_dapm_route ad183x_dapm_routes[] = {
{ "DAC", NULL, "ADC_PWR" },
{ "ADC", NULL, "ADC_PWR" },
- { "DAC1OUT", "DAC1 Switch", "DAC" },
- { "DAC2OUT", "DAC2 Switch", "DAC" },
- { "DAC3OUT", "DAC3 Switch", "DAC" },
- { "ADC", "ADC1 Switch", "ADC1IN" },
- { "ADC", "ADC2 Switch", "ADC2IN" },
+};
+
+static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0);
+
+static const struct snd_kcontrol_new ad1836_controls[] = {
+ SOC_DOUBLE_TLV("ADC2 Capture Volume", AD183X_ADC_CTRL1, 3, 0, 4, 0,
+ ad1836_in_tlv),
};
/*
@@ -170,19 +203,15 @@
pm_message_t state)
{
/* reset clock control mode */
- u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
- adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
-
- return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+ return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+ AD1836_ADC_SERFMT_MASK, 0);
}
static int ad1836_soc_resume(struct snd_soc_codec *codec)
{
/* restore clock control mode */
- u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
- adc_ctrl2 |= AD1836_ADC_AUX;
-
- return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+ return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+ AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
}
#else
#define ad1836_soc_suspend NULL
@@ -194,35 +223,45 @@
.set_fmt = ad1836_set_dai_fmt,
};
-/* codec DAI instance */
-static struct snd_soc_dai_driver ad1836_dai = {
- .name = "ad1836-hifi",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 2,
- .channels_max = 6,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 2,
- .channels_max = 4,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
- },
- .ops = &ad1836_dai_ops,
+#define AD183X_DAI(_name, num_dacs, num_adcs) \
+{ \
+ .name = _name "-hifi", \
+ .playback = { \
+ .stream_name = "Playback", \
+ .channels_min = 2, \
+ .channels_max = (num_dacs) * 2, \
+ .rates = SNDRV_PCM_RATE_48000, \
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+ }, \
+ .capture = { \
+ .stream_name = "Capture", \
+ .channels_min = 2, \
+ .channels_max = (num_adcs) * 2, \
+ .rates = SNDRV_PCM_RATE_48000, \
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+ }, \
+ .ops = &ad1836_dai_ops, \
+}
+
+static struct snd_soc_dai_driver ad183x_dais[] = {
+ [AD1835] = AD183X_DAI("ad1835", 4, 1),
+ [AD1836] = AD183X_DAI("ad1836", 3, 2),
+ [AD1838] = AD183X_DAI("ad1838", 3, 1),
};
static int ad1836_probe(struct snd_soc_codec *codec)
{
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int num_dacs, num_adcs;
int ret = 0;
+ int i;
- codec->control_data = ad1836->control_data;
+ num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
+ num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
+
ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -239,21 +278,46 @@
snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
/* unmute adc channles, adc aux mode */
snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
- /* left/right diff:PGA/MUX */
- snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
/* volume */
- snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF);
- snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF);
- snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF);
- snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF);
- snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
- snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
+ for (i = 1; i <= num_dacs; ++i) {
+ snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF);
+ snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF);
+ }
- snd_soc_add_controls(codec, ad1836_snd_controls,
- ARRAY_SIZE(ad1836_snd_controls));
- snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets,
- ARRAY_SIZE(ad1836_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
+ if (ad1836->type == AD1836) {
+ /* left/right diff:PGA/MUX */
+ snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
+ ret = snd_soc_add_controls(codec, ad1836_controls,
+ ARRAY_SIZE(ad1836_controls));
+ if (ret)
+ return ret;
+ } else {
+ snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
+ }
+
+ ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
+ if (ret)
+ return ret;
return ret;
}
@@ -262,10 +326,8 @@
static int ad1836_remove(struct snd_soc_codec *codec)
{
/* reset clock control mode */
- u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
- adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
-
- return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
+ return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+ AD1836_ADC_SERFMT_MASK, 0);
}
static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
@@ -275,6 +337,13 @@
.resume = ad1836_soc_resume,
.reg_cache_size = AD1836_NUM_REGS,
.reg_word_size = sizeof(u16),
+
+ .controls = ad183x_controls,
+ .num_controls = ARRAY_SIZE(ad183x_controls),
+ .dapm_widgets = ad183x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
+ .dapm_routes = ad183x_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
};
static int __devinit ad1836_spi_probe(struct spi_device *spi)
@@ -286,12 +355,12 @@
if (ad1836 == NULL)
return -ENOMEM;
+ ad1836->type = spi_get_device_id(spi)->driver_data;
+
spi_set_drvdata(spi, ad1836);
- ad1836->control_data = spi;
- ad1836->control_type = SND_SOC_SPI;
ret = snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_ad1836, &ad1836_dai, 1);
+ &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
if (ret < 0)
kfree(ad1836);
return ret;
@@ -303,6 +372,15 @@
kfree(spi_get_drvdata(spi));
return 0;
}
+static const struct spi_device_id ad1836_ids[] = {
+ { "ad1835", AD1835 },
+ { "ad1836", AD1836 },
+ { "ad1837", AD1835 },
+ { "ad1838", AD1838 },
+ { "ad1839", AD1838 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, ad1836_ids);
static struct spi_driver ad1836_spi_driver = {
.driver = {
@@ -311,6 +389,7 @@
},
.probe = ad1836_spi_probe,
.remove = __devexit_p(ad1836_spi_remove),
+ .id_table = ad1836_ids,
};
static int __init ad1836_init(void)
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h
index 9d6a3f8..f13402f 100644
--- a/sound/soc/codecs/ad1836.h
+++ b/sound/soc/codecs/ad1836.h
@@ -28,29 +28,20 @@
#define AD1836_DAC_WORD_LEN_OFFSET 3
#define AD1836_DAC_CTRL2 1
-#define AD1836_DACL1_MUTE 0
-#define AD1836_DACR1_MUTE 1
-#define AD1836_DACL2_MUTE 2
-#define AD1836_DACR2_MUTE 3
-#define AD1836_DACL3_MUTE 4
-#define AD1836_DACR3_MUTE 5
-#define AD1836_DAC_L1_VOL 2
-#define AD1836_DAC_R1_VOL 3
-#define AD1836_DAC_L2_VOL 4
-#define AD1836_DAC_R2_VOL 5
-#define AD1836_DAC_L3_VOL 6
-#define AD1836_DAC_R3_VOL 7
+/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit
+ * for the first ADC/DAC */
+#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2)
+#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1)
+
+#define AD1836_DAC_L_VOL(x) ((x) * 2)
+#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2))
#define AD1836_ADC_CTRL1 12
#define AD1836_ADC_POWERDOWN 7
#define AD1836_ADC_HIGHPASS_FILTER 8
#define AD1836_ADC_CTRL2 13
-#define AD1836_ADCL1_MUTE 0
-#define AD1836_ADCR1_MUTE 1
-#define AD1836_ADCL2_MUTE 2
-#define AD1836_ADCR2_MUTE 3
#define AD1836_ADC_WORD_LEN_MASK 0x30
#define AD1836_ADC_WORD_OFFSET 5
#define AD1836_ADC_SERFMT_MASK (7 << 6)
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index ed96f247c..7a64e58 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -457,7 +457,7 @@
.set_sysclk = ak4641_set_dai_sysclk,
};
-struct snd_soc_dai_driver ak4641_dai[] = {
+static struct snd_soc_dai_driver ak4641_dai[] = {
{
.name = "ak4641-hifi",
.id = 1,
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 0206a17..6cc8678 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -636,10 +636,7 @@
#endif /* CONFIG_PM */
/*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
+ * ASoC codec driver structure
*/
static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
.probe = cs4270_probe,
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 4173b67..ac65a2d 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1397,8 +1397,6 @@
if (freq == max98088->sysclk)
return 0;
- max98088->sysclk = freq; /* remember current sysclk */
-
/* Setup clocks for slave mode, and using the PLL
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
* 0x02 (when master clk is 20MHz to 30MHz)..
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index e1d282d..872a5fa 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -1517,8 +1517,6 @@
if (freq == max98095->sysclk)
return 0;
- max98095->sysclk = freq; /* remember current sysclk */
-
/* Setup clocks for slave mode, and using the PLL
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
* 0x02 (when master clk is 20MHz to 40MHz)..
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
index e2ab4fa..423baa9 100644
--- a/sound/soc/codecs/wm8915.c
+++ b/sound/soc/codecs/wm8915.c
@@ -41,14 +41,12 @@
#define HPOUT2L 4
#define HPOUT2R 8
-#define WM8915_NUM_SUPPLIES 6
+#define WM8915_NUM_SUPPLIES 4
static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
- "DCVDD",
"DBVDD",
"AVDD1",
"AVDD2",
"CPVDD",
- "MICVDD",
};
struct wm8915_priv {
@@ -57,6 +55,7 @@
int ldo1ena;
int sysclk;
+ int sysclk_src;
int fll_src;
int fll_fref;
@@ -76,6 +75,7 @@
struct wm8915_pdata pdata;
int rx_rate[WM8915_AIFS];
+ int bclk_rate[WM8915_AIFS];
/* Platform dependant ReTune mobile configuration */
int num_retune_mobile_texts;
@@ -113,8 +113,6 @@
WM8915_REGULATOR_EVENT(1)
WM8915_REGULATOR_EVENT(2)
WM8915_REGULATOR_EVENT(3)
-WM8915_REGULATOR_EVENT(4)
-WM8915_REGULATOR_EVENT(5)
static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
[WM8915_SOFTWARE_RESET] = 0x8915,
@@ -1565,6 +1563,50 @@
return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
}
+static const int bclk_divs[] = {
+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static void wm8915_update_bclk(struct snd_soc_codec *codec)
+{
+ struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+ int aif, best, cur_val, bclk_rate, bclk_reg, i;
+
+ /* Don't bother if we're in a low frequency idle mode that
+ * can't support audio.
+ */
+ if (wm8915->sysclk < 64000)
+ return;
+
+ for (aif = 0; aif < WM8915_AIFS; aif++) {
+ switch (aif) {
+ case 0:
+ bclk_reg = WM8915_AIF1_BCLK;
+ break;
+ case 1:
+ bclk_reg = WM8915_AIF2_BCLK;
+ break;
+ }
+
+ bclk_rate = wm8915->bclk_rate[aif];
+
+ /* Pick a divisor for BCLK as close as we can get to ideal */
+ best = 0;
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
+ if (cur_val < 0) /* BCLK table is sorted */
+ break;
+ best = i;
+ }
+ bclk_rate = wm8915->sysclk / bclk_divs[best];
+ dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+ bclk_divs[best], bclk_rate);
+
+ snd_soc_update_bits(codec, bclk_reg,
+ WM8915_AIF1_BCLK_DIV_MASK, best);
+ }
+}
+
static int wm8915_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1717,10 +1759,6 @@
return 0;
}
-static const int bclk_divs[] = {
- 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
-};
-
static const int dsp_divs[] = {
48000, 32000, 16000, 8000
};
@@ -1731,17 +1769,11 @@
{
struct snd_soc_codec *codec = dai->codec;
struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
- int bits, i, bclk_rate, best, cur_val;
+ int bits, i, bclk_rate;
int aifdata = 0;
- int bclk = 0;
int lrclk = 0;
int dsp = 0;
- int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift;
-
- if (!wm8915->sysclk) {
- dev_err(codec->dev, "SYSCLK not configured\n");
- return -EINVAL;
- }
+ int aifdata_reg, lrclk_reg, dsp_shift;
switch (dai->id) {
case 0:
@@ -1753,7 +1785,6 @@
aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
}
- bclk_reg = WM8915_AIF1_BCLK;
dsp_shift = 0;
break;
case 1:
@@ -1765,7 +1796,6 @@
aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
}
- bclk_reg = WM8915_AIF2_BCLK;
dsp_shift = WM8915_DSP2_DIV_SHIFT;
break;
default:
@@ -1779,6 +1809,9 @@
return bclk_rate;
}
+ wm8915->bclk_rate[dai->id] = bclk_rate;
+ wm8915->rx_rate[dai->id] = params_rate(params);
+
/* Needs looking at for TDM */
bits = snd_pcm_format_width(params_format(params));
if (bits < 0)
@@ -1796,18 +1829,7 @@
}
dsp |= i << dsp_shift;
- /* Pick a divisor for BCLK as close as we can get to ideal */
- best = 0;
- for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
- cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
- if (cur_val < 0) /* BCLK table is sorted */
- break;
- best = i;
- }
- bclk_rate = wm8915->sysclk / bclk_divs[best];
- dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
- bclk_divs[best], bclk_rate);
- bclk |= best;
+ wm8915_update_bclk(codec);
lrclk = bclk_rate / params_rate(params);
dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
@@ -1817,14 +1839,11 @@
WM8915_AIF1TX_WL_MASK |
WM8915_AIF1TX_SLOT_LEN_MASK,
aifdata);
- snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk);
snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
lrclk);
snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
- wm8915->rx_rate[dai->id] = params_rate(params);
-
return 0;
}
@@ -1838,6 +1857,9 @@
int src;
int old;
+ if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src)
+ return 0;
+
/* Disable SYSCLK while we reconfigure */
old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA;
snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
@@ -1882,6 +1904,8 @@
return -EINVAL;
}
+ wm8915_update_bclk(codec);
+
snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
@@ -1889,6 +1913,8 @@
snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
WM8915_SYSCLK_ENA, old);
+ wm8915->sysclk_src = clk_id;
+
return 0;
}
@@ -2007,6 +2033,7 @@
unsigned int Fref, unsigned int Fout)
{
struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *i2c = to_i2c_client(codec->dev);
struct _fll_div fll_div;
unsigned long timeout;
int ret, reg;
@@ -2093,7 +2120,18 @@
else
timeout = msecs_to_jiffies(2);
- wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+ /* Allow substantially longer if we've actually got the IRQ */
+ if (i2c->irq)
+ timeout *= 1000;
+
+ ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+
+ if (ret == 0 && i2c->irq) {
+ dev_err(codec->dev, "Timed out waiting for FLL\n");
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
@@ -2101,7 +2139,7 @@
wm8915->fll_fout = Fout;
wm8915->fll_src = source;
- return 0;
+ return ret;
}
#ifdef CONFIG_GPIOLIB
@@ -2293,6 +2331,12 @@
SND_JACK_HEADSET | SND_JACK_BTN_0);
wm8915->jack_mic = true;
wm8915->detecting = false;
+
+ /* Increase poll rate to give better responsiveness
+ * for buttons */
+ snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+ WM8915_MICD_RATE_MASK,
+ 5 << WM8915_MICD_RATE_SHIFT);
}
/* If we detected a lower impedence during initial startup
@@ -2333,15 +2377,17 @@
SND_JACK_HEADPHONE,
SND_JACK_HEADSET |
SND_JACK_BTN_0);
+
+ /* Increase the detection rate a bit for
+ * responsiveness.
+ */
+ snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+ WM8915_MICD_RATE_MASK,
+ 7 << WM8915_MICD_RATE_SHIFT);
+
wm8915->detecting = false;
}
}
-
- /* Increase poll rate to give better responsiveness for buttons */
- if (!wm8915->detecting)
- snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
- WM8915_MICD_RATE_MASK,
- 5 << WM8915_MICD_RATE_SHIFT);
}
static irqreturn_t wm8915_irq(int irq, void *data)
@@ -2383,6 +2429,20 @@
}
}
+static irqreturn_t wm8915_edge_irq(int irq, void *data)
+{
+ irqreturn_t ret = IRQ_NONE;
+ irqreturn_t val;
+
+ do {
+ val = wm8915_irq(irq, data);
+ if (val != IRQ_NONE)
+ ret = val;
+ } while (val != IRQ_NONE);
+
+ return ret;
+}
+
static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
{
struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
@@ -2482,8 +2542,6 @@
wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
- wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
- wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
@@ -2709,8 +2767,14 @@
irq_flags |= IRQF_ONESHOT;
- ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
- irq_flags, "wm8915", codec);
+ if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+ ret = request_threaded_irq(i2c->irq, NULL,
+ wm8915_edge_irq,
+ irq_flags, "wm8915", codec);
+ else
+ ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+ irq_flags, "wm8915", codec);
+
if (ret == 0) {
/* Unmask the interrupt */
snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 9d35b8c..c9e0320 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -46,11 +46,28 @@
}
#endif
+#define DAVINCI_PCM_FMTBITS (\
+ SNDRV_PCM_FMTBIT_S8 |\
+ SNDRV_PCM_FMTBIT_U8 |\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_U16_LE |\
+ SNDRV_PCM_FMTBIT_U16_BE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_BE |\
+ SNDRV_PCM_FMTBIT_U24_LE |\
+ SNDRV_PCM_FMTBIT_U24_BE |\
+ SNDRV_PCM_FMTBIT_S32_LE |\
+ SNDRV_PCM_FMTBIT_S32_BE |\
+ SNDRV_PCM_FMTBIT_U32_LE |\
+ SNDRV_PCM_FMTBIT_U32_BE)
+
static struct snd_pcm_hardware pcm_hardware_playback = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
+ SNDRV_PCM_INFO_BATCH),
+ .formats = DAVINCI_PCM_FMTBITS,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -59,7 +76,7 @@
.rate_min = 8000,
.rate_max = 96000,
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 384,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
@@ -71,8 +88,9 @@
static struct snd_pcm_hardware pcm_hardware_capture = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE),
- .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH),
+ .formats = DAVINCI_PCM_FMTBITS,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -81,7 +99,7 @@
.rate_min = 8000,
.rate_max = 96000,
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 384,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
@@ -139,6 +157,22 @@
struct edmacc_param ram_params;
};
+static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
+{
+ struct davinci_runtime_data *prtd = substream->runtime->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ prtd->period++;
+ if (unlikely(prtd->period >= runtime->periods))
+ prtd->period = 0;
+}
+
+static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
+{
+ struct davinci_runtime_data *prtd = substream->runtime->private_data;
+
+ prtd->period = 0;
+}
/*
* Not used with ping/pong
*/
@@ -199,10 +233,6 @@
else
edma_set_transfer_params(link, acnt, fifo_level, count,
fifo_level, ABSYNC);
-
- prtd->period++;
- if (unlikely(prtd->period >= runtime->periods))
- prtd->period = 0;
}
static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
@@ -217,12 +247,13 @@
return;
if (snd_pcm_running(substream)) {
+ spin_lock(&prtd->lock);
if (prtd->ram_channel < 0) {
/* No ping/pong must fix up link dma data*/
- spin_lock(&prtd->lock);
davinci_pcm_enqueue_dma(substream);
- spin_unlock(&prtd->lock);
}
+ davinci_pcm_period_elapsed(substream);
+ spin_unlock(&prtd->lock);
snd_pcm_period_elapsed(substream);
}
}
@@ -425,7 +456,8 @@
edma_read_slot(link, &prtd->asp_params);
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
- prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
+ prtd->asp_params.opt |= TCCHEN |
+ EDMA_TCC(prtd->ram_channel & 0x3f);
edma_write_slot(link, &prtd->asp_params);
/* pong */
@@ -439,7 +471,7 @@
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
/* interrupt after every pong completion */
prtd->asp_params.opt |= TCINTEN | TCCHEN |
- EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
+ EDMA_TCC(prtd->ram_channel & 0x3f);
edma_write_slot(link, &prtd->asp_params);
/* ram */
@@ -527,6 +559,13 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ edma_start(prtd->asp_channel);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ prtd->ram_channel >= 0) {
+ /* copy 1st iram buffer */
+ edma_start(prtd->ram_channel);
+ }
+ break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
edma_resume(prtd->asp_channel);
@@ -550,6 +589,7 @@
{
struct davinci_runtime_data *prtd = substream->runtime->private_data;
+ davinci_pcm_period_reset(substream);
if (prtd->ram_channel >= 0) {
int ret = ping_pong_dma_setup(substream);
if (ret < 0)
@@ -565,21 +605,31 @@
print_buf_info(prtd->asp_link[0], "asp_link[0]");
print_buf_info(prtd->asp_link[1], "asp_link[1]");
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* copy 1st iram buffer */
- edma_start(prtd->ram_channel);
- }
- edma_start(prtd->asp_channel);
+ /*
+ * There is a phase offset of 2 periods between the position
+ * used by dma setup and the position reported in the pointer
+ * function.
+ *
+ * The phase offset, when not using ping-pong buffers, is due to
+ * the two consecutive calls to davinci_pcm_enqueue_dma() below.
+ *
+ * Whereas here, with ping-pong buffers, the phase is due to
+ * there being an entire buffer transfer complete before the
+ * first dma completion event triggers davinci_pcm_dma_irq().
+ */
+ davinci_pcm_period_elapsed(substream);
+ davinci_pcm_period_elapsed(substream);
+
return 0;
}
- prtd->period = 0;
davinci_pcm_enqueue_dma(substream);
+ davinci_pcm_period_elapsed(substream);
/* Copy self-linked parameter RAM entry into master channel */
edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
edma_write_slot(prtd->asp_channel, &prtd->asp_params);
davinci_pcm_enqueue_dma(substream);
- edma_start(prtd->asp_channel);
+ davinci_pcm_period_elapsed(substream);
return 0;
}
@@ -591,51 +641,23 @@
struct davinci_runtime_data *prtd = runtime->private_data;
unsigned int offset;
int asp_count;
- dma_addr_t asp_src, asp_dst;
+ unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+ /*
+ * There is a phase offset of 2 periods between the position used by dma
+ * setup and the position reported in the pointer function. Either +2 in
+ * the dma setup or -2 here in the pointer function (with wrapping,
+ * both) accounts for this offset -- choose the latter since it makes
+ * the first-time setup clearer.
+ */
spin_lock(&prtd->lock);
- if (prtd->ram_channel >= 0) {
- int ram_count;
- int mod_ram;
- dma_addr_t ram_src, ram_dst;
- unsigned int period_size = snd_pcm_lib_period_bytes(substream);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* reading ram before asp should be safe
- * as long as the asp transfers less than a ping size
- * of bytes between the 2 reads
- */
- edma_get_position(prtd->ram_channel,
- &ram_src, &ram_dst);
- edma_get_position(prtd->asp_channel,
- &asp_src, &asp_dst);
- asp_count = asp_src - prtd->asp_params.src;
- ram_count = ram_src - prtd->ram_params.src;
- mod_ram = ram_count % period_size;
- mod_ram -= asp_count;
- if (mod_ram < 0)
- mod_ram += period_size;
- else if (mod_ram == 0) {
- if (snd_pcm_running(substream))
- mod_ram += period_size;
- }
- ram_count -= mod_ram;
- if (ram_count < 0)
- ram_count += period_size * runtime->periods;
- } else {
- edma_get_position(prtd->ram_channel,
- &ram_src, &ram_dst);
- ram_count = ram_dst - prtd->ram_params.dst;
- }
- asp_count = ram_count;
- } else {
- edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- asp_count = asp_src - runtime->dma_addr;
- else
- asp_count = asp_dst - runtime->dma_addr;
- }
+ asp_count = prtd->period - 2;
spin_unlock(&prtd->lock);
+ if (asp_count < 0)
+ asp_count += runtime->periods;
+ asp_count *= period_size;
+
offset = bytes_to_frames(runtime, asp_count);
if (offset >= runtime->buffer_size)
offset = 0;
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index dac6732..9c0edad 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -356,7 +356,7 @@
nuc900_audio->irq_num = platform_get_irq(pdev, 0);
if (!nuc900_audio->irq_num) {
ret = -EBUSY;
- goto out2;
+ goto out3;
}
nuc900_ac97_data = nuc900_audio;
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 462cbcb..b40095a 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -427,7 +427,8 @@
/* Board specific codec bias level control */
static int ams_delta_set_bias_level(struct snd_soc_card *card,
- enum snd_soc_bias_level level)
+ struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
{
struct snd_soc_codec *codec = card->rtd->codec;
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 360a333..2515dba 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -20,24 +20,29 @@
#define WM8915_HPSEL_GPIO 214
static int speyside_set_bias_level(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_STANDBY:
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2,
32768, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2,
0, 0, 0);
if (ret < 0) {
pr_err("Failed to stop FLL\n");
return ret;
}
+ break;
default:
break;
@@ -46,6 +51,45 @@
return 0;
}
+static int speyside_set_bias_level_post(struct snd_soc_card *card,
+ struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ int ret;
+
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ WM8915_FLL_MCLK2,
+ 32768, 48000 * 256);
+ if (ret < 0) {
+ pr_err("Failed to start FLL\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ WM8915_SYSCLK_FLL,
+ 48000 * 256,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ card->dapm.bias_level = level;
+
+ return 0;
+}
+
static int speyside_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -66,16 +110,6 @@
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
- 32768, 256 * 48000);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL,
- 256 * 48000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -127,7 +161,7 @@
struct snd_soc_codec *codec = rtd->codec;
int ret;
- ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+ ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0);
if (ret < 0)
return ret;
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 4a9da6b..d2f17ce 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -118,10 +118,38 @@
/*
* FSI driver use below type name for variable
*
- * xxx_len : data length
- * xxx_width : data width
- * xxx_offset : data offset
* xxx_num : number of data
+ * xxx_pos : position of data
+ * xxx_capa : capacity of data
+ */
+
+/*
+ * period/frame/sample image
+ *
+ * ex) PCM (2ch)
+ *
+ * period pos period pos
+ * [n] [n + 1]
+ * |<-------------------- period--------------------->|
+ * ==|============================================ ... =|==
+ * | |
+ * ||<----- frame ----->|<------ frame ----->| ... |
+ * |+--------------------+--------------------+- ... |
+ * ||[ sample ][ sample ]|[ sample ][ sample ]| ... |
+ * |+--------------------+--------------------+- ... |
+ * ==|============================================ ... =|==
+ */
+
+/*
+ * FSI FIFO image
+ *
+ * | |
+ * | |
+ * | [ sample ] |
+ * | [ sample ] |
+ * | [ sample ] |
+ * | [ sample ] |
+ * --> go to codecs
*/
/*
@@ -131,12 +159,11 @@
struct fsi_stream {
struct snd_pcm_substream *substream;
- int fifo_max_num;
-
- int buff_offset;
- int buff_len;
- int period_len;
- int period_num;
+ int fifo_sample_capa; /* sample capacity of FSI FIFO */
+ int buff_sample_capa; /* sample capacity of ALSA buffer */
+ int buff_sample_pos; /* sample position of ALSA buffer */
+ int period_samples; /* sample number / 1 period */
+ int period_pos; /* current period position */
int uerr_num;
int oerr_num;
@@ -149,17 +176,14 @@
struct fsi_stream playback;
struct fsi_stream capture;
+ u32 do_fmt;
+ u32 di_fmt;
+
int chan_num:16;
int clk_master:1;
+ int spdif:1;
long rate;
-
- /* for suspend/resume */
- u32 saved_do_fmt;
- u32 saved_di_fmt;
- u32 saved_ckg1;
- u32 saved_ckg2;
- u32 saved_out_sel;
};
struct fsi_core {
@@ -180,14 +204,6 @@
struct fsi_core *core;
struct sh_fsi_platform_info *info;
spinlock_t lock;
-
- /* for suspend/resume */
- u32 saved_a_mclk;
- u32 saved_b_mclk;
- u32 saved_iemsk;
- u32 saved_imsk;
- u32 saved_clk_rst;
- u32 saved_soft_rst;
};
/*
@@ -271,6 +287,11 @@
return fsi->master->base == fsi->base;
}
+static int fsi_is_spdif(struct fsi_priv *fsi)
+{
+ return fsi->spdif;
+}
+
static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -342,28 +363,59 @@
return shift;
}
-static void fsi_stream_push(struct fsi_priv *fsi,
- int is_play,
- struct snd_pcm_substream *substream,
- u32 buffer_len,
- u32 period_len)
+static int fsi_frame2sample(struct fsi_priv *fsi, int frames)
+{
+ return frames * fsi->chan_num;
+}
+
+static int fsi_sample2frame(struct fsi_priv *fsi, int samples)
+{
+ return samples / fsi->chan_num;
+}
+
+static int fsi_stream_is_working(struct fsi_priv *fsi,
+ int is_play)
{
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct fsi_master *master = fsi_get_master(fsi);
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&master->lock, flags);
+ ret = !!io->substream;
+ spin_unlock_irqrestore(&master->lock, flags);
+
+ return ret;
+}
+
+static void fsi_stream_push(struct fsi_priv *fsi,
+ int is_play,
+ struct snd_pcm_substream *substream)
+{
+ struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct fsi_master *master = fsi_get_master(fsi);
+ unsigned long flags;
+
+ spin_lock_irqsave(&master->lock, flags);
io->substream = substream;
- io->buff_len = buffer_len;
- io->buff_offset = 0;
- io->period_len = period_len;
- io->period_num = 0;
+ io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size);
+ io->buff_sample_pos = 0;
+ io->period_samples = fsi_frame2sample(fsi, runtime->period_size);
+ io->period_pos = 0;
io->oerr_num = -1; /* ignore 1st err */
io->uerr_num = -1; /* ignore 1st err */
+ spin_unlock_irqrestore(&master->lock, flags);
}
static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
{
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+ struct fsi_master *master = fsi_get_master(fsi);
+ unsigned long flags;
+ spin_lock_irqsave(&master->lock, flags);
if (io->oerr_num > 0)
dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
@@ -372,47 +424,27 @@
dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
io->substream = NULL;
- io->buff_len = 0;
- io->buff_offset = 0;
- io->period_len = 0;
- io->period_num = 0;
+ io->buff_sample_capa = 0;
+ io->buff_sample_pos = 0;
+ io->period_samples = 0;
+ io->period_pos = 0;
io->oerr_num = 0;
io->uerr_num = 0;
+ spin_unlock_irqrestore(&master->lock, flags);
}
-static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
+static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play)
{
u32 status;
- int data_num;
+ int frames;
status = is_play ?
fsi_reg_read(fsi, DOFF_ST) :
fsi_reg_read(fsi, DIFF_ST);
- data_num = 0x1ff & (status >> 8);
- data_num *= fsi->chan_num;
+ frames = 0x1ff & (status >> 8);
- return data_num;
-}
-
-static int fsi_len2num(int len, int width)
-{
- return len / width;
-}
-
-#define fsi_num2offset(a, b) fsi_num2len(a, b)
-static int fsi_num2len(int num, int width)
-{
- return num * width;
-}
-
-static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
-{
- struct fsi_stream *io = fsi_get_stream(fsi, is_play);
- struct snd_pcm_substream *substream = io->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- return frames_to_bytes(runtime, 1) / fsi->chan_num;
+ return fsi_frame2sample(fsi, frames);
}
static void fsi_count_fifo_err(struct fsi_priv *fsi)
@@ -444,8 +476,10 @@
{
int is_play = fsi_stream_is_play(stream);
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct snd_pcm_runtime *runtime = io->substream->runtime;
- return io->substream->runtime->dma_area + io->buff_offset;
+ return runtime->dma_area +
+ samples_to_bytes(runtime, io->buff_sample_pos);
}
static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
@@ -559,37 +593,94 @@
/*
* clock function
*/
-#define fsi_module_init(m, d) __fsi_module_clk_ctrl(m, d, 1)
-#define fsi_module_kill(m, d) __fsi_module_clk_ctrl(m, d, 0)
-static void __fsi_module_clk_ctrl(struct fsi_master *master,
- struct device *dev,
- int enable)
-{
- pm_runtime_get_sync(dev);
-
- if (enable) {
- /* enable only SR */
- fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
- fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
- } else {
- /* clear all registers */
- fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
- }
-
- pm_runtime_put_sync(dev);
-}
-
-#define fsi_port_start(f) __fsi_port_clk_ctrl(f, 1)
-#define fsi_port_stop(f) __fsi_port_clk_ctrl(f, 0)
-static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
+static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
+ long rate, int enable)
{
struct fsi_master *master = fsi_get_master(fsi);
- u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
- u32 clk = fsi_is_port_a(fsi) ? CRA : CRB;
- int is_master = fsi_is_clk_master(fsi);
+ set_rate_func set_rate = fsi_get_info_set_rate(master);
+ int fsi_ver = master->core->ver;
+ int ret;
- fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
- if (is_master)
+ ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable);
+ if (ret < 0) /* error */
+ return ret;
+
+ if (!enable)
+ return 0;
+
+ if (ret > 0) {
+ u32 data = 0;
+
+ switch (ret & SH_FSI_ACKMD_MASK) {
+ default:
+ /* FALL THROUGH */
+ case SH_FSI_ACKMD_512:
+ data |= (0x0 << 12);
+ break;
+ case SH_FSI_ACKMD_256:
+ data |= (0x1 << 12);
+ break;
+ case SH_FSI_ACKMD_128:
+ data |= (0x2 << 12);
+ break;
+ case SH_FSI_ACKMD_64:
+ data |= (0x3 << 12);
+ break;
+ case SH_FSI_ACKMD_32:
+ if (fsi_ver < 2)
+ dev_err(dev, "unsupported ACKMD\n");
+ else
+ data |= (0x4 << 12);
+ break;
+ }
+
+ switch (ret & SH_FSI_BPFMD_MASK) {
+ default:
+ /* FALL THROUGH */
+ case SH_FSI_BPFMD_32:
+ data |= (0x0 << 8);
+ break;
+ case SH_FSI_BPFMD_64:
+ data |= (0x1 << 8);
+ break;
+ case SH_FSI_BPFMD_128:
+ data |= (0x2 << 8);
+ break;
+ case SH_FSI_BPFMD_256:
+ data |= (0x3 << 8);
+ break;
+ case SH_FSI_BPFMD_512:
+ data |= (0x4 << 8);
+ break;
+ case SH_FSI_BPFMD_16:
+ if (fsi_ver < 2)
+ dev_err(dev, "unsupported ACKMD\n");
+ else
+ data |= (0x7 << 8);
+ break;
+ }
+
+ fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+ udelay(10);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#define fsi_port_start(f, i) __fsi_port_clk_ctrl(f, i, 1)
+#define fsi_port_stop(f, i) __fsi_port_clk_ctrl(f, i, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable)
+{
+ struct fsi_master *master = fsi_get_master(fsi);
+ u32 clk = fsi_is_port_a(fsi) ? CRA : CRB;
+
+ if (enable)
+ fsi_irq_enable(fsi, is_play);
+ else
+ fsi_irq_disable(fsi, is_play);
+
+ if (fsi_is_clk_master(fsi))
fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
}
@@ -598,18 +689,19 @@
*/
static void fsi_fifo_init(struct fsi_priv *fsi,
int is_play,
- struct snd_soc_dai *dai)
+ struct device *dev)
{
struct fsi_master *master = fsi_get_master(fsi);
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
u32 shift, i;
+ int frame_capa;
/* get on-chip RAM capacity */
shift = fsi_master_read(master, FIFO_SZ);
shift >>= fsi_get_port_shift(fsi, is_play);
shift &= FIFO_SZ_MASK;
- io->fifo_max_num = 256 << shift;
- dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
+ frame_capa = 256 << shift;
+ dev_dbg(dev, "fifo = %d words\n", frame_capa);
/*
* The maximum number of sample data varies depending
@@ -631,9 +723,11 @@
* 8 channels: 32 ( 32 x 8 = 256)
*/
for (i = 1; i < fsi->chan_num; i <<= 1)
- io->fifo_max_num >>= 1;
- dev_dbg(dai->dev, "%d channel %d store\n",
- fsi->chan_num, io->fifo_max_num);
+ frame_capa >>= 1;
+ dev_dbg(dev, "%d channel %d store\n",
+ fsi->chan_num, frame_capa);
+
+ io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa);
/*
* set interrupt generation factor
@@ -654,10 +748,10 @@
struct snd_pcm_substream *substream = NULL;
int is_play = fsi_stream_is_play(stream);
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
- int data_residue_num;
- int data_num;
- int data_num_max;
- int ch_width;
+ int sample_residues;
+ int sample_width;
+ int samples;
+ int samples_max;
int over_period;
void (*fn)(struct fsi_priv *fsi, int size);
@@ -673,36 +767,35 @@
/* FSI FIFO has limit.
* So, this driver can not send periods data at a time
*/
- if (io->buff_offset >=
- fsi_num2offset(io->period_num + 1, io->period_len)) {
+ if (io->buff_sample_pos >=
+ io->period_samples * (io->period_pos + 1)) {
over_period = 1;
- io->period_num = (io->period_num + 1) % runtime->periods;
+ io->period_pos = (io->period_pos + 1) % runtime->periods;
- if (0 == io->period_num)
- io->buff_offset = 0;
+ if (0 == io->period_pos)
+ io->buff_sample_pos = 0;
}
- /* get 1 channel data width */
- ch_width = fsi_get_frame_width(fsi, is_play);
+ /* get 1 sample data width */
+ sample_width = samples_to_bytes(runtime, 1);
- /* get residue data number of alsa */
- data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
- ch_width);
+ /* get number of residue samples */
+ sample_residues = io->buff_sample_capa - io->buff_sample_pos;
if (is_play) {
/*
* for play-back
*
- * data_num_max : number of FSI fifo free space
- * data_num : number of ALSA residue data
+ * samples_max : number of FSI fifo free samples space
+ * samples : number of ALSA residue samples
*/
- data_num_max = io->fifo_max_num * fsi->chan_num;
- data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+ samples_max = io->fifo_sample_capa;
+ samples_max -= fsi_get_current_fifo_samples(fsi, is_play);
- data_num = data_residue_num;
+ samples = sample_residues;
- switch (ch_width) {
+ switch (sample_width) {
case 2:
fn = fsi_dma_soft_push16;
break;
@@ -716,13 +809,13 @@
/*
* for capture
*
- * data_num_max : number of ALSA free space
- * data_num : number of data in FSI fifo
+ * samples_max : number of ALSA free samples space
+ * samples : number of samples in FSI fifo
*/
- data_num_max = data_residue_num;
- data_num = fsi_get_fifo_data_num(fsi, is_play);
+ samples_max = sample_residues;
+ samples = fsi_get_current_fifo_samples(fsi, is_play);
- switch (ch_width) {
+ switch (sample_width) {
case 2:
fn = fsi_dma_soft_pop16;
break;
@@ -734,12 +827,12 @@
}
}
- data_num = min(data_num, data_num_max);
+ samples = min(samples, samples_max);
- fn(fsi, data_num);
+ fn(fsi, samples);
- /* update buff_offset */
- io->buff_offset += fsi_num2offset(data_num, ch_width);
+ /* update buff_sample_pos */
+ io->buff_sample_pos += samples;
if (over_period)
snd_pcm_period_elapsed(substream);
@@ -788,16 +881,20 @@
* dai ops
*/
-static int fsi_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int fsi_hw_startup(struct fsi_priv *fsi,
+ int is_play,
+ struct device *dev)
{
- struct fsi_priv *fsi = fsi_get_priv(substream);
u32 flags = fsi_get_info_flags(fsi);
- u32 data;
- int is_play = fsi_is_play(substream);
+ u32 data = 0;
- pm_runtime_get_sync(dai->dev);
+ pm_runtime_get_sync(dev);
+ /* clock setting */
+ if (fsi_is_clk_master(fsi))
+ data = DIMD | DOMD;
+
+ fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
/* clock inversion (CKG2) */
data = 0;
@@ -812,54 +909,70 @@
fsi_reg_write(fsi, CKG2, data);
+ /* set format */
+ fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
+ fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
+
+ /* spdif ? */
+ if (fsi_is_spdif(fsi)) {
+ fsi_spdif_clk_ctrl(fsi, 1);
+ fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+ }
+
/* irq clear */
fsi_irq_disable(fsi, is_play);
fsi_irq_clear_status(fsi);
/* fifo init */
- fsi_fifo_init(fsi, is_play, dai);
+ fsi_fifo_init(fsi, is_play, dev);
return 0;
}
+static void fsi_hw_shutdown(struct fsi_priv *fsi,
+ int is_play,
+ struct device *dev)
+{
+ if (fsi_is_clk_master(fsi))
+ fsi_set_master_clk(dev, fsi, fsi->rate, 0);
+
+ pm_runtime_put_sync(dev);
+}
+
+static int fsi_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsi_priv *fsi = fsi_get_priv(substream);
+ int is_play = fsi_is_play(substream);
+
+ return fsi_hw_startup(fsi, is_play, dai->dev);
+}
+
static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
int is_play = fsi_is_play(substream);
- struct fsi_master *master = fsi_get_master(fsi);
- set_rate_func set_rate = fsi_get_info_set_rate(master);
- fsi_irq_disable(fsi, is_play);
-
- if (fsi_is_clk_master(fsi))
- set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
-
+ fsi_hw_shutdown(fsi, is_play, dai->dev);
fsi->rate = 0;
-
- pm_runtime_put_sync(dai->dev);
}
static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
int is_play = fsi_is_play(substream);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- fsi_stream_push(fsi, is_play, substream,
- frames_to_bytes(runtime, runtime->buffer_size),
- frames_to_bytes(runtime, runtime->period_size));
+ fsi_stream_push(fsi, is_play, substream);
ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
- fsi_irq_enable(fsi, is_play);
- fsi_port_start(fsi);
+ fsi_port_start(fsi, is_play);
break;
case SNDRV_PCM_TRIGGER_STOP:
- fsi_port_stop(fsi);
- fsi_irq_disable(fsi, is_play);
+ fsi_port_stop(fsi, is_play);
fsi_stream_pop(fsi, is_play);
break;
}
@@ -884,8 +997,8 @@
return -EINVAL;
}
- fsi_reg_write(fsi, DO_FMT, data);
- fsi_reg_write(fsi, DI_FMT, data);
+ fsi->do_fmt = data;
+ fsi->di_fmt = data;
return 0;
}
@@ -900,11 +1013,10 @@
data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
fsi->chan_num = 2;
- fsi_spdif_clk_ctrl(fsi, 1);
- fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+ fsi->spdif = 1;
- fsi_reg_write(fsi, DO_FMT, data);
- fsi_reg_write(fsi, DI_FMT, data);
+ fsi->do_fmt = data;
+ fsi->di_fmt = data;
return 0;
}
@@ -915,32 +1027,24 @@
struct fsi_master *master = fsi_get_master(fsi);
set_rate_func set_rate = fsi_get_info_set_rate(master);
u32 flags = fsi_get_info_flags(fsi);
- u32 data = 0;
int ret;
- pm_runtime_get_sync(dai->dev);
-
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- data = DIMD | DOMD;
fsi->clk_master = 1;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
- ret = -EINVAL;
- goto set_fmt_exit;
+ return -EINVAL;
}
if (fsi_is_clk_master(fsi) && !set_rate) {
dev_err(dai->dev, "platform doesn't have set_rate\n");
- ret = -EINVAL;
- goto set_fmt_exit;
+ return -EINVAL;
}
- fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
-
/* set format */
switch (flags & SH_FSI_FMT_MASK) {
case SH_FSI_FMT_DAI:
@@ -953,9 +1057,6 @@
ret = -EINVAL;
}
-set_fmt_exit:
- pm_runtime_put_sync(dai->dev);
-
return ret;
}
@@ -964,79 +1065,19 @@
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- struct fsi_master *master = fsi_get_master(fsi);
- set_rate_func set_rate = fsi_get_info_set_rate(master);
- int fsi_ver = master->core->ver;
long rate = params_rate(params);
int ret;
if (!fsi_is_clk_master(fsi))
return 0;
- ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
- if (ret < 0) /* error */
+ ret = fsi_set_master_clk(dai->dev, fsi, rate, 1);
+ if (ret < 0)
return ret;
fsi->rate = rate;
- if (ret > 0) {
- u32 data = 0;
-
- switch (ret & SH_FSI_ACKMD_MASK) {
- default:
- /* FALL THROUGH */
- case SH_FSI_ACKMD_512:
- data |= (0x0 << 12);
- break;
- case SH_FSI_ACKMD_256:
- data |= (0x1 << 12);
- break;
- case SH_FSI_ACKMD_128:
- data |= (0x2 << 12);
- break;
- case SH_FSI_ACKMD_64:
- data |= (0x3 << 12);
- break;
- case SH_FSI_ACKMD_32:
- if (fsi_ver < 2)
- dev_err(dai->dev, "unsupported ACKMD\n");
- else
- data |= (0x4 << 12);
- break;
- }
-
- switch (ret & SH_FSI_BPFMD_MASK) {
- default:
- /* FALL THROUGH */
- case SH_FSI_BPFMD_32:
- data |= (0x0 << 8);
- break;
- case SH_FSI_BPFMD_64:
- data |= (0x1 << 8);
- break;
- case SH_FSI_BPFMD_128:
- data |= (0x2 << 8);
- break;
- case SH_FSI_BPFMD_256:
- data |= (0x3 << 8);
- break;
- case SH_FSI_BPFMD_512:
- data |= (0x4 << 8);
- break;
- case SH_FSI_BPFMD_16:
- if (fsi_ver < 2)
- dev_err(dai->dev, "unsupported ACKMD\n");
- else
- data |= (0x7 << 8);
- break;
- }
-
- fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
- udelay(10);
- ret = 0;
- }
return ret;
-
}
static struct snd_soc_dai_ops fsi_dai_ops = {
@@ -1097,16 +1138,14 @@
static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
struct fsi_priv *fsi = fsi_get_priv(substream);
struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
- long location;
+ int samples_pos = io->buff_sample_pos - 1;
- location = (io->buff_offset - 1);
- if (location < 0)
- location = 0;
+ if (samples_pos < 0)
+ samples_pos = 0;
- return bytes_to_frames(runtime, location);
+ return fsi_sample2frame(fsi, samples_pos);
}
static struct snd_pcm_ops fsi_pcm_ops = {
@@ -1246,8 +1285,6 @@
pm_runtime_enable(&pdev->dev);
dev_set_drvdata(&pdev->dev, master);
- fsi_module_init(master, &pdev->dev);
-
ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
id_entry->name, master);
if (ret) {
@@ -1290,8 +1327,6 @@
master = dev_get_drvdata(&pdev->dev);
- fsi_module_kill(master, &pdev->dev);
-
free_irq(master->irq, master);
pm_runtime_disable(&pdev->dev);
@@ -1305,53 +1340,43 @@
}
static void __fsi_suspend(struct fsi_priv *fsi,
- struct device *dev,
- set_rate_func set_rate)
+ int is_play,
+ struct device *dev)
{
- fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT);
- fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT);
- fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1);
- fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2);
- fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL);
+ if (!fsi_stream_is_working(fsi, is_play))
+ return;
- if (fsi_is_clk_master(fsi))
- set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+ fsi_port_stop(fsi, is_play);
+ fsi_hw_shutdown(fsi, is_play, dev);
}
static void __fsi_resume(struct fsi_priv *fsi,
- struct device *dev,
- set_rate_func set_rate)
+ int is_play,
+ struct device *dev)
{
- fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt);
- fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt);
- fsi_reg_write(fsi, CKG1, fsi->saved_ckg1);
- fsi_reg_write(fsi, CKG2, fsi->saved_ckg2);
- fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel);
+ if (!fsi_stream_is_working(fsi, is_play))
+ return;
- if (fsi_is_clk_master(fsi))
- set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
+ fsi_hw_startup(fsi, is_play, dev);
+
+ if (fsi_is_clk_master(fsi) && fsi->rate)
+ fsi_set_master_clk(dev, fsi, fsi->rate, 1);
+
+ fsi_port_start(fsi, is_play);
+
}
static int fsi_suspend(struct device *dev)
{
struct fsi_master *master = dev_get_drvdata(dev);
- set_rate_func set_rate = fsi_get_info_set_rate(master);
+ struct fsi_priv *fsia = &master->fsia;
+ struct fsi_priv *fsib = &master->fsib;
- pm_runtime_get_sync(dev);
+ __fsi_suspend(fsia, 1, dev);
+ __fsi_suspend(fsia, 0, dev);
- __fsi_suspend(&master->fsia, dev, set_rate);
- __fsi_suspend(&master->fsib, dev, set_rate);
-
- master->saved_a_mclk = fsi_core_read(master, a_mclk);
- master->saved_b_mclk = fsi_core_read(master, b_mclk);
- master->saved_iemsk = fsi_core_read(master, iemsk);
- master->saved_imsk = fsi_core_read(master, imsk);
- master->saved_clk_rst = fsi_master_read(master, CLK_RST);
- master->saved_soft_rst = fsi_master_read(master, SOFT_RST);
-
- fsi_module_kill(master, dev);
-
- pm_runtime_put_sync(dev);
+ __fsi_suspend(fsib, 1, dev);
+ __fsi_suspend(fsib, 0, dev);
return 0;
}
@@ -1359,23 +1384,14 @@
static int fsi_resume(struct device *dev)
{
struct fsi_master *master = dev_get_drvdata(dev);
- set_rate_func set_rate = fsi_get_info_set_rate(master);
+ struct fsi_priv *fsia = &master->fsia;
+ struct fsi_priv *fsib = &master->fsib;
- pm_runtime_get_sync(dev);
+ __fsi_resume(fsia, 1, dev);
+ __fsi_resume(fsia, 0, dev);
- fsi_module_init(master, dev);
-
- fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
- fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
- fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
- fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
- fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
- fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
-
- __fsi_resume(&master->fsia, dev, set_rate);
- __fsi_resume(&master->fsib, dev, set_rate);
-
- pm_runtime_put_sync(dev);
+ __fsi_resume(fsib, 1, dev);
+ __fsi_resume(fsib, 0, dev);
return 0;
}
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index c005ceb..cad70c9 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -107,12 +107,11 @@
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u8 data[2];
+ u16 data;
- data[0] = (reg << 1) | ((value >> 8) & 0x0001);
- data[1] = value & 0x00ff;
+ data = cpu_to_be16((reg << 9) | (value & 0x1ff));
- return do_hw_write(codec, reg, value, data, 2);
+ return do_hw_write(codec, reg, value, &data, 2);
}
static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
@@ -137,10 +136,10 @@
unsigned int value)
{
u8 data[3];
+ u16 val = cpu_to_be16(value);
data[0] = reg;
- data[1] = (value >> 8) & 0xff;
- data[2] = value & 0xff;
+ memcpy(&data[1], &val, sizeof(val));
return do_hw_write(codec, reg, value, data, 3);
}
@@ -243,9 +242,9 @@
unsigned int value)
{
u8 data[3];
+ u16 rval = cpu_to_be16(reg);
- data[0] = (reg >> 8) & 0xff;
- data[1] = reg & 0xff;
+ memcpy(data, &rval, sizeof(rval));
data[2] = value;
return do_hw_write(codec, reg, value, data, 3);
@@ -277,14 +276,12 @@
static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u8 data[4];
+ u16 data[2];
- data[0] = (reg >> 8) & 0xff;
- data[1] = reg & 0xff;
- data[2] = (value >> 8) & 0xff;
- data[3] = value & 0xff;
+ data[0] = cpu_to_be16(reg);
+ data[1] = cpu_to_be16(value);
- return do_hw_write(codec, reg, value, data, 4);
+ return do_hw_write(codec, reg, value, data, sizeof(data));
}
/* Primitive bulk write support for soc-cache. The data pointed to by
@@ -486,31 +483,86 @@
}
struct snd_soc_rbtree_node {
- struct rb_node node;
- unsigned int reg;
- unsigned int value;
- unsigned int defval;
+ struct rb_node node; /* the actual rbtree node holding this block */
+ unsigned int base_reg; /* base register handled by this block */
+ unsigned int word_size; /* number of bytes needed to represent the register index */
+ void *block; /* block of adjacent registers */
+ unsigned int blklen; /* number of registers available in the block */
} __attribute__ ((packed));
struct snd_soc_rbtree_ctx {
struct rb_root root;
+ struct snd_soc_rbtree_node *cached_rbnode;
};
+static inline void snd_soc_rbtree_get_base_top_reg(
+ struct snd_soc_rbtree_node *rbnode,
+ unsigned int *base, unsigned int *top)
+{
+ *base = rbnode->base_reg;
+ *top = rbnode->base_reg + rbnode->blklen - 1;
+}
+
+static unsigned int snd_soc_rbtree_get_register(
+ struct snd_soc_rbtree_node *rbnode, unsigned int idx)
+{
+ unsigned int val;
+
+ switch (rbnode->word_size) {
+ case 1: {
+ u8 *p = rbnode->block;
+ val = p[idx];
+ return val;
+ }
+ case 2: {
+ u16 *p = rbnode->block;
+ val = p[idx];
+ return val;
+ }
+ default:
+ BUG();
+ break;
+ }
+ return -1;
+}
+
+static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
+ unsigned int idx, unsigned int val)
+{
+ switch (rbnode->word_size) {
+ case 1: {
+ u8 *p = rbnode->block;
+ p[idx] = val;
+ break;
+ }
+ case 2: {
+ u16 *p = rbnode->block;
+ p[idx] = val;
+ break;
+ }
+ default:
+ BUG();
+ break;
+ }
+}
+
static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
struct rb_root *root, unsigned int reg)
{
struct rb_node *node;
struct snd_soc_rbtree_node *rbnode;
+ unsigned int base_reg, top_reg;
node = root->rb_node;
while (node) {
rbnode = container_of(node, struct snd_soc_rbtree_node, node);
- if (rbnode->reg < reg)
- node = node->rb_left;
- else if (rbnode->reg > reg)
- node = node->rb_right;
- else
+ snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ if (reg >= base_reg && reg <= top_reg)
return rbnode;
+ else if (reg > top_reg)
+ node = node->rb_right;
+ else if (reg < base_reg)
+ node = node->rb_left;
}
return NULL;
@@ -521,19 +573,28 @@
{
struct rb_node **new, *parent;
struct snd_soc_rbtree_node *rbnode_tmp;
+ unsigned int base_reg_tmp, top_reg_tmp;
+ unsigned int base_reg;
parent = NULL;
new = &root->rb_node;
while (*new) {
rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
node);
+ /* base and top registers of the current rbnode */
+ snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+ &top_reg_tmp);
+ /* base register of the rbnode to be added */
+ base_reg = rbnode->base_reg;
parent = *new;
- if (rbnode_tmp->reg < rbnode->reg)
- new = &((*new)->rb_left);
- else if (rbnode_tmp->reg > rbnode->reg)
- new = &((*new)->rb_right);
- else
+ /* if this register has already been inserted, just return */
+ if (base_reg >= base_reg_tmp &&
+ base_reg <= top_reg_tmp)
return 0;
+ else if (base_reg > top_reg_tmp)
+ new = &((*new)->rb_right);
+ else if (base_reg < base_reg_tmp)
+ new = &((*new)->rb_left);
}
/* insert the node into the rbtree */
@@ -548,58 +609,141 @@
struct snd_soc_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
struct snd_soc_rbtree_node *rbnode;
+ unsigned int regtmp;
unsigned int val;
int ret;
+ int i;
rbtree_ctx = codec->reg_cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
- if (rbnode->value == rbnode->defval)
- continue;
- WARN_ON(codec->writable_register &&
- codec->writable_register(codec, rbnode->reg));
- ret = snd_soc_cache_read(codec, rbnode->reg, &val);
- if (ret)
- return ret;
- codec->cache_bypass = 1;
- ret = snd_soc_write(codec, rbnode->reg, val);
- codec->cache_bypass = 0;
- if (ret)
- return ret;
- dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
- rbnode->reg, val);
+ for (i = 0; i < rbnode->blklen; ++i) {
+ regtmp = rbnode->base_reg + i;
+ WARN_ON(codec->writable_register &&
+ codec->writable_register(codec, regtmp));
+ val = snd_soc_rbtree_get_register(rbnode, i);
+ codec->cache_bypass = 1;
+ ret = snd_soc_write(codec, regtmp, val);
+ codec->cache_bypass = 0;
+ if (ret)
+ return ret;
+ dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+ regtmp, val);
+ }
}
return 0;
}
+static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
+ unsigned int pos, unsigned int reg,
+ unsigned int value)
+{
+ u8 *blk;
+
+ blk = krealloc(rbnode->block,
+ (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
+ if (!blk)
+ return -ENOMEM;
+
+ /* insert the register value in the correct place in the rbnode block */
+ memmove(blk + (pos + 1) * rbnode->word_size,
+ blk + pos * rbnode->word_size,
+ (rbnode->blklen - pos) * rbnode->word_size);
+
+ /* update the rbnode block, its size and the base register */
+ rbnode->block = blk;
+ rbnode->blklen++;
+ if (!pos)
+ rbnode->base_reg = reg;
+
+ snd_soc_rbtree_set_register(rbnode, pos, value);
+ return 0;
+}
+
static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
struct snd_soc_rbtree_ctx *rbtree_ctx;
- struct snd_soc_rbtree_node *rbnode;
+ struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
+ struct rb_node *node;
+ unsigned int val;
+ unsigned int reg_tmp;
+ unsigned int base_reg, top_reg;
+ unsigned int pos;
+ int i;
+ int ret;
rbtree_ctx = codec->reg_cache;
+ /* look up the required register in the cached rbnode */
+ rbnode = rbtree_ctx->cached_rbnode;
+ if (rbnode) {
+ snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ if (reg >= base_reg && reg <= top_reg) {
+ reg_tmp = reg - base_reg;
+ val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+ if (val == value)
+ return 0;
+ snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+ return 0;
+ }
+ }
+ /* if we can't locate it in the cached rbnode we'll have
+ * to traverse the rbtree looking for it.
+ */
rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
if (rbnode) {
- if (rbnode->value == value)
+ reg_tmp = reg - rbnode->base_reg;
+ val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+ if (val == value)
return 0;
- rbnode->value = value;
+ snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+ rbtree_ctx->cached_rbnode = rbnode;
} else {
/* bail out early, no need to create the rbnode yet */
if (!value)
return 0;
- /*
- * for uninitialized registers whose value is changed
- * from the default zero, create an rbnode and insert
- * it into the tree.
+ /* look for an adjacent register to the one we are about to add */
+ for (node = rb_first(&rbtree_ctx->root); node;
+ node = rb_next(node)) {
+ rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
+ for (i = 0; i < rbnode_tmp->blklen; ++i) {
+ reg_tmp = rbnode_tmp->base_reg + i;
+ if (abs(reg_tmp - reg) != 1)
+ continue;
+ /* decide where in the block to place our register */
+ if (reg_tmp + 1 == reg)
+ pos = i + 1;
+ else
+ pos = i;
+ ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
+ reg, value);
+ if (ret)
+ return ret;
+ rbtree_ctx->cached_rbnode = rbnode_tmp;
+ return 0;
+ }
+ }
+ /* we did not manage to find a place to insert it in an existing
+ * block so create a new rbnode with a single register in its block.
+ * This block will get populated further if any other adjacent
+ * registers get modified in the future.
*/
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
if (!rbnode)
return -ENOMEM;
- rbnode->reg = reg;
- rbnode->value = value;
+ rbnode->blklen = 1;
+ rbnode->base_reg = reg;
+ rbnode->word_size = codec->driver->reg_word_size;
+ rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
+ GFP_KERNEL);
+ if (!rbnode->block) {
+ kfree(rbnode);
+ return -ENOMEM;
+ }
+ snd_soc_rbtree_set_register(rbnode, 0, value);
snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
+ rbtree_ctx->cached_rbnode = rbnode;
}
return 0;
@@ -610,11 +754,28 @@
{
struct snd_soc_rbtree_ctx *rbtree_ctx;
struct snd_soc_rbtree_node *rbnode;
+ unsigned int base_reg, top_reg;
+ unsigned int reg_tmp;
rbtree_ctx = codec->reg_cache;
+ /* look up the required register in the cached rbnode */
+ rbnode = rbtree_ctx->cached_rbnode;
+ if (rbnode) {
+ snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ if (reg >= base_reg && reg <= top_reg) {
+ reg_tmp = reg - base_reg;
+ *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+ return 0;
+ }
+ }
+ /* if we can't locate it in the cached rbnode we'll have
+ * to traverse the rbtree looking for it.
+ */
rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
if (rbnode) {
- *value = rbnode->value;
+ reg_tmp = reg - rbnode->base_reg;
+ *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+ rbtree_ctx->cached_rbnode = rbnode;
} else {
/* uninitialized registers default to 0 */
*value = 0;
@@ -640,6 +801,7 @@
rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
next = rb_next(&rbtree_node->node);
rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+ kfree(rbtree_node->block);
kfree(rbtree_node);
}
@@ -652,10 +814,9 @@
static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
{
- struct snd_soc_rbtree_node *rbtree_node;
struct snd_soc_rbtree_ctx *rbtree_ctx;
- unsigned int val;
unsigned int word_size;
+ unsigned int val;
int i;
int ret;
@@ -665,32 +826,27 @@
rbtree_ctx = codec->reg_cache;
rbtree_ctx->root = RB_ROOT;
+ rbtree_ctx->cached_rbnode = NULL;
if (!codec->reg_def_copy)
return 0;
- /*
- * populate the rbtree with the initialized registers. All other
- * registers will be inserted when they are first modified.
- */
word_size = codec->driver->reg_word_size;
for (i = 0; i < codec->driver->reg_cache_size; ++i) {
- val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
+ val = snd_soc_get_cache_val(codec->reg_def_copy, i,
+ word_size);
if (!val)
continue;
- rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
- if (!rbtree_node) {
- ret = -ENOMEM;
- snd_soc_cache_exit(codec);
- break;
- }
- rbtree_node->reg = i;
- rbtree_node->value = val;
- rbtree_node->defval = val;
- snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
+ ret = snd_soc_rbtree_cache_write(codec, i, val);
+ if (ret)
+ goto err;
}
return 0;
+
+err:
+ snd_soc_cache_exit(codec);
+ return ret;
}
#ifdef CONFIG_SND_SOC_CACHE_LZO
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d75043e..c53f5d5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1256,7 +1256,7 @@
int snd_soc_resume(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
- int i;
+ int i, ac97_control = 0;
/* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
@@ -1265,14 +1265,15 @@
*/
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- if (cpu_dai->driver->ac97_control) {
- dev_dbg(dev, "Resuming AC97 immediately\n");
- soc_resume_deferred(&card->deferred_resume_work);
- } else {
- dev_dbg(dev, "Scheduling resume work\n");
- if (!schedule_work(&card->deferred_resume_work))
- dev_err(dev, "resume work item may be lost\n");
- }
+ ac97_control |= cpu_dai->driver->ac97_control;
+ }
+ if (ac97_control) {
+ dev_dbg(dev, "Resuming AC97 immediately\n");
+ soc_resume_deferred(&card->deferred_resume_work);
+ } else {
+ dev_dbg(dev, "Scheduling resume work\n");
+ if (!schedule_work(&card->deferred_resume_work))
+ dev_err(dev, "resume work item may be lost\n");
}
return 0;
@@ -2322,7 +2323,7 @@
return ret;
old = ret;
- new = (old & ~mask) | value;
+ new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
ret = snd_soc_write(codec, reg, new);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 776e6f4..34106bc 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -139,39 +139,26 @@
struct snd_soc_card *card = dapm->card;
int ret = 0;
- switch (level) {
- case SND_SOC_BIAS_ON:
- dev_dbg(dapm->dev, "Setting full bias\n");
- break;
- case SND_SOC_BIAS_PREPARE:
- dev_dbg(dapm->dev, "Setting bias prepare\n");
- break;
- case SND_SOC_BIAS_STANDBY:
- dev_dbg(dapm->dev, "Setting standby bias\n");
- break;
- case SND_SOC_BIAS_OFF:
- dev_dbg(dapm->dev, "Setting bias off\n");
- break;
- default:
- dev_err(dapm->dev, "Setting invalid bias %d\n", level);
- return -EINVAL;
- }
-
trace_snd_soc_bias_level_start(card, level);
if (card && card->set_bias_level)
- ret = card->set_bias_level(card, level);
- if (ret == 0) {
- if (dapm->codec && dapm->codec->driver->set_bias_level)
- ret = dapm->codec->driver->set_bias_level(dapm->codec, level);
+ ret = card->set_bias_level(card, dapm, level);
+ if (ret != 0)
+ goto out;
+
+ if (dapm->codec) {
+ if (dapm->codec->driver->set_bias_level)
+ ret = dapm->codec->driver->set_bias_level(dapm->codec,
+ level);
else
dapm->bias_level = level;
}
- if (ret == 0) {
- if (card && card->set_bias_level_post)
- ret = card->set_bias_level_post(card, level);
- }
+ if (ret != 0)
+ goto out;
+ if (card && card->set_bias_level_post)
+ ret = card->set_bias_level_post(card, dapm, level);
+out:
trace_snd_soc_bias_level_done(card, level);
return ret;
@@ -209,7 +196,7 @@
int val, item, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
- ;
+ ;
val = snd_soc_read(w->codec, e->reg);
item = (val >> e->shift_l) & (bitmask - 1);
@@ -1042,16 +1029,17 @@
struct snd_soc_dapm_context *d = data;
int ret;
- if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
+ /* If we're off and we're not supposed to be go into STANDBY */
+ if (d->bias_level == SND_SOC_BIAS_OFF &&
+ d->target_bias_level != SND_SOC_BIAS_OFF) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
if (ret != 0)
dev_err(d->dev,
"Failed to turn on bias: %d\n", ret);
}
- /* If we're changing to all on or all off then prepare */
- if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
- (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
+ /* Prepare for a STADDBY->ON or ON->STANDBY transition */
+ if (d->bias_level != d->target_bias_level) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
if (ret != 0)
dev_err(d->dev,
@@ -1068,7 +1056,9 @@
int ret;
/* If we just powered the last thing off drop to standby bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
+ if (d->bias_level == SND_SOC_BIAS_PREPARE &&
+ (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
+ d->target_bias_level == SND_SOC_BIAS_OFF)) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
if (ret != 0)
dev_err(d->dev, "Failed to apply standby bias: %d\n",
@@ -1076,14 +1066,16 @@
}
/* If we're in standby and can support bias off then do that */
- if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) {
+ if (d->bias_level == SND_SOC_BIAS_STANDBY &&
+ d->target_bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
if (ret != 0)
dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
}
/* If we just powered up then move to active bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
+ if (d->bias_level == SND_SOC_BIAS_PREPARE &&
+ d->target_bias_level == SND_SOC_BIAS_ON) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
if (ret != 0)
dev_err(d->dev, "Failed to apply active bias: %d\n",
@@ -1108,13 +1100,19 @@
LIST_HEAD(up_list);
LIST_HEAD(down_list);
LIST_HEAD(async_domain);
+ enum snd_soc_bias_level bias;
int power;
trace_snd_soc_dapm_start(card);
- list_for_each_entry(d, &card->dapm_list, list)
- if (d->n_widgets || d->codec == NULL)
- d->dev_power = 0;
+ list_for_each_entry(d, &card->dapm_list, list) {
+ if (d->n_widgets || d->codec == NULL) {
+ if (d->idle_bias_off)
+ d->target_bias_level = SND_SOC_BIAS_OFF;
+ else
+ d->target_bias_level = SND_SOC_BIAS_STANDBY;
+ }
+ }
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
@@ -1136,8 +1134,27 @@
power = w->power_check(w);
else
power = 1;
- if (power)
- w->dapm->dev_power = 1;
+
+ if (power) {
+ d = w->dapm;
+
+ /* Supplies and micbiases only bring
+ * the context up to STANDBY as unless
+ * something else is active and
+ * passing audio they generally don't
+ * require full power.
+ */
+ switch (w->id) {
+ case snd_soc_dapm_supply:
+ case snd_soc_dapm_micbias:
+ if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
+ d->target_bias_level = SND_SOC_BIAS_STANDBY;
+ break;
+ default:
+ d->target_bias_level = SND_SOC_BIAS_ON;
+ break;
+ }
+ }
if (w->power == power)
continue;
@@ -1161,24 +1178,19 @@
switch (event) {
case SND_SOC_DAPM_STREAM_START:
case SND_SOC_DAPM_STREAM_RESUME:
- dapm->dev_power = 1;
+ dapm->target_bias_level = SND_SOC_BIAS_ON;
break;
case SND_SOC_DAPM_STREAM_STOP:
- dapm->dev_power = !!dapm->codec->active;
+ if (dapm->codec->active)
+ dapm->target_bias_level = SND_SOC_BIAS_ON;
+ else
+ dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
break;
case SND_SOC_DAPM_STREAM_SUSPEND:
- dapm->dev_power = 0;
+ dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
break;
case SND_SOC_DAPM_STREAM_NOP:
- switch (dapm->bias_level) {
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
- dapm->dev_power = 0;
- break;
- default:
- dapm->dev_power = 1;
- break;
- }
+ dapm->target_bias_level = dapm->bias_level;
break;
default:
break;
@@ -1186,12 +1198,12 @@
}
/* Force all contexts in the card to the same bias state */
- power = 0;
+ bias = SND_SOC_BIAS_OFF;
list_for_each_entry(d, &card->dapm_list, list)
- if (d->dev_power)
- power = 1;
+ if (d->target_bias_level > bias)
+ bias = d->target_bias_level;
list_for_each_entry(d, &card->dapm_list, list)
- d->dev_power = power;
+ d->target_bias_level = bias;
/* Run all the bias changes in parallel */
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 0d6738a..a42e9ac 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -267,7 +267,7 @@
}
machine->gpio_requested |= GPIO_HP_MUTE;
- gpio_direction_output(pdata->gpio_hp_mute, 0);
+ gpio_direction_output(pdata->gpio_hp_mute, 1);
}
if (gpio_is_valid(pdata->gpio_int_mic_en)) {