Merge branch 'for-3.0' into for-3.1
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/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..b654fcd1 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 {
@@ -113,8 +111,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,
@@ -2293,6 +2289,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 +2335,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 +2387,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 +2500,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 +2725,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/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 360a333..93078b1 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -27,12 +27,12 @@
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");
@@ -66,7 +66,7 @@
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
+ ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK2,
32768, 256 * 48000);
if (ret < 0)
return ret;
@@ -127,7 +127,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 06b7b81..d8ce34c 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
@@ -483,31 +480,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;
@@ -518,19 +570,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 */
@@ -545,58 +606,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;
@@ -607,11 +751,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;
@@ -637,6 +798,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);
}
@@ -649,10 +811,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;
@@ -662,32 +823,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..13a40fc 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;
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)) {