Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "This contains pretty many small commits covering fairly large range of
  files in sound/ directory.  Partly because of additional API support
  and partly because of constantly developed ASoC and ARM stuff.

  Some highlights:

   - Introduced the helper function and documentation for exposing the
     channel map via control API, as discussed in Plumbers; most of PCI
     drivers are covered, will follow more drivers later

   - Most of drivers have been replaced with the new PM callbacks (if
     the bus is supported)

   - HD-audio controller got the support of runtime PM and the support
     of D3 clock-stop.  Also changing the power_save option in sysfs
     kicks off immediately to enable / disable the power-save mode.

   - Another significant code change in HD-audio is the rewrite of
     firmware loading code.  Other than that, most of changes in
     HD-audio are continued cleanups and standardization for the generic
     auto parser and bug fixes (HBR, device-specific fixups), in
     addition to the support of channel-map API.

   - Addition of ASoC bindings for the compressed API, used by the
     mid-x86 drivers.

   - Lots of cleanups and API refreshes for ASoC codec drivers and
     DaVinci.

   - Conversion of OMAP to dmaengine.

   - New machine driver for Wolfson Microelectronics Bells.

   - New CODEC driver for Wolfson Microelectronics WM0010.

   - Enhancements to the ux500 and wm2000 drivers

   - A new driver for DA9055 and the support for regulator bypass mode."

Fix up various arm soc header file reorg conflicts.

* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits)
  ALSA: hda - Add new codec ALC283 ALC290 support
  ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls
  ALSA: hda - fix indices on boost volume on Conexant
  ALSA: aloop - add locking to timer access
  ALSA: hda - Fix hang caused by race during suspend.
  sound: Remove unnecessary semicolon
  ALSA: hda/realtek - Fix detection of ALC271X codec
  ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310
  ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event
  ALSA: hda - make a generic unsol event handler
  ASoC: codecs: Add DA9055 codec driver
  ASoC: eukrea-tlv320: Convert it to platform driver
  ALSA: ASoC: add DT bindings for CS4271
  ASoC: wm_hubs: Ensure volume updates are handled during class W startup
  ASoC: wm5110: Adding missing volume update bits
  ASoC: wm5110: Add OUT3R support
  ASoC: wm5110: Add AEC loopback support
  ASoC: wm5110: Rename EPOUT to HPOUT3
  ASoC: arizona: Add more clock rates
  ASoC: arizona: Add more DSP options for mixer input muxes
  ...
此提交包含在:
Linus Torvalds
2012-10-09 07:07:14 +09:00
當前提交 f5a246eab9
共有 363 個檔案被更改,包括 10812 行新增4232 行删除

查看文件

@@ -25,13 +25,14 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/omap-dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
#include <plat/cpu.h>
#include <plat/dma.h>
#include "omap-pcm.h"
static const struct snd_pcm_hardware omap_pcm_hardware = {
@@ -50,61 +51,34 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
.buffer_bytes_max = 128 * 1024,
};
struct omap_runtime_data {
spinlock_t lock;
struct omap_pcm_dma_data *dma_data;
int dma_ch;
int period_index;
};
static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
static int omap_pcm_get_dma_buswidth(int num_bits)
{
struct snd_pcm_substream *substream = data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
unsigned long flags;
int buswidth;
if ((cpu_is_omap1510())) {
/*
* OMAP1510 doesn't fully support DMA progress counter
* and there is no software emulation implemented yet,
* so have to maintain our own progress counters
* that can be used by omap_pcm_pointer() instead.
*/
spin_lock_irqsave(&prtd->lock, flags);
if ((stat == OMAP_DMA_LAST_IRQ) &&
(prtd->period_index == runtime->periods - 1)) {
/* we are in sync, do nothing */
spin_unlock_irqrestore(&prtd->lock, flags);
return;
}
if (prtd->period_index >= 0) {
if (stat & OMAP_DMA_BLOCK_IRQ) {
/* end of buffer reached, loop back */
prtd->period_index = 0;
} else if (stat & OMAP_DMA_LAST_IRQ) {
/* update the counter for the last period */
prtd->period_index = runtime->periods - 1;
} else if (++prtd->period_index >= runtime->periods) {
/* end of buffer missed? loop back */
prtd->period_index = 0;
}
}
spin_unlock_irqrestore(&prtd->lock, flags);
switch (num_bits) {
case 16:
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case 32:
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
break;
default:
buswidth = -EINVAL;
break;
}
snd_pcm_period_elapsed(substream);
return buswidth;
}
/* this may get called several times by oss emulation */
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data;
struct dma_slave_config config;
struct dma_chan *chan;
int err = 0;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -117,162 +91,78 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
if (prtd->dma_data)
return 0;
prtd->dma_data = dma_data;
err = omap_request_dma(dma_data->dma_req, dma_data->name,
omap_pcm_dma_irq, substream, &prtd->dma_ch);
if (!err) {
/*
* Link channel with itself so DMA doesn't need any
* reprogramming while looping the buffer
*/
omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
chan = snd_dmaengine_pcm_get_chan(substream);
if (!chan)
return -EINVAL;
/* fills in addr_width and direction */
err = snd_hwparams_to_dma_slave_config(substream, params, &config);
if (err)
return err;
/* Override the *_dma addr_width if requested by the DAI driver */
if (dma_data->data_type) {
int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
config.dst_addr_width = buswidth;
else
config.src_addr_width = buswidth;
}
return err;
config.src_addr = dma_data->port_addr;
config.dst_addr = dma_data->port_addr;
config.src_maxburst = dma_data->packet_size;
config.dst_maxburst = dma_data->packet_size;
return dmaengine_slave_config(chan, &config);
}
static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
if (prtd->dma_data == NULL)
return 0;
omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
omap_free_dma(prtd->dma_ch);
prtd->dma_data = NULL;
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
static int omap_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data = prtd->dma_data;
struct omap_dma_channel_params dma_params;
int bytes;
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
if (!prtd->dma_data)
return 0;
memset(&dma_params, 0, sizeof(dma_params));
dma_params.data_type = dma_data->data_type;
dma_params.trigger = dma_data->dma_req;
dma_params.sync_mode = dma_data->sync_mode;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_params.src_amode = OMAP_DMA_AMODE_POST_INC;
dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC;
dma_params.src_start = runtime->dma_addr;
dma_params.dst_start = dma_data->port_addr;
dma_params.dst_port = OMAP_DMA_PORT_MPUI;
dma_params.dst_fi = dma_data->packet_size;
} else {
dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
dma_params.src_start = dma_data->port_addr;
dma_params.dst_start = runtime->dma_addr;
dma_params.src_port = OMAP_DMA_PORT_MPUI;
dma_params.src_fi = dma_data->packet_size;
}
/*
* Set DMA transfer frame size equal to ALSA period size and frame
* count as no. of ALSA periods. Then with DMA frame interrupt enabled,
* we can transfer the whole ALSA buffer with single DMA transfer but
* still can get an interrupt at each period bounary
*/
bytes = snd_pcm_lib_period_bytes(substream);
dma_params.elem_count = bytes >> dma_data->data_type;
dma_params.frame_count = runtime->periods;
omap_set_dma_params(prtd->dma_ch, &dma_params);
if ((cpu_is_omap1510()))
omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
else if (!substream->runtime->no_period_wakeup)
omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
else {
/*
* No period wakeup:
* we need to disable BLOCK_IRQ, which is enabled by the omap
* dma core at request dma time.
*/
omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
}
if (!(cpu_class_is_omap1())) {
omap_set_dma_src_burst_mode(prtd->dma_ch,
OMAP_DMA_DATA_BURST_16);
omap_set_dma_dest_burst_mode(prtd->dma_ch,
OMAP_DMA_DATA_BURST_16);
}
return 0;
}
static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data = prtd->dma_data;
unsigned long flags;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_pcm_dma_data *dma_data;
int ret = 0;
spin_lock_irqsave(&prtd->lock, flags);
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
prtd->period_index = 0;
/* Configure McBSP internal buffer usage */
if (dma_data->set_threshold)
dma_data->set_threshold(substream);
omap_start_dma(prtd->dma_ch);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
prtd->period_index = -1;
omap_stop_dma(prtd->dma_ch);
break;
default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&prtd->lock, flags);
if (ret == 0)
ret = snd_dmaengine_pcm_trigger(substream, cmd);
return ret;
}
static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd = runtime->private_data;
dma_addr_t ptr;
snd_pcm_uframes_t offset;
if (cpu_is_omap1510()) {
offset = prtd->period_index * runtime->period_size;
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ptr = omap_get_dma_dst_pos(prtd->dma_ch);
offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
} else {
ptr = omap_get_dma_src_pos(prtd->dma_ch);
offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
}
if (offset >= runtime->buffer_size)
offset = 0;
if (cpu_is_omap1510())
offset = snd_dmaengine_pcm_pointer_no_residue(substream);
else
offset = snd_dmaengine_pcm_pointer(substream);
return offset;
}
@@ -280,7 +170,8 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
static int omap_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct omap_runtime_data *prtd;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_pcm_dma_data *dma_data;
int ret;
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
@@ -289,25 +180,17 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
return ret;
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
if (prtd == NULL) {
ret = -ENOMEM;
goto out;
}
spin_lock_init(&prtd->lock);
runtime->private_data = prtd;
out:
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
&dma_data->dma_req);
return ret;
}
static int omap_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
kfree(runtime->private_data);
snd_dmaengine_pcm_close(substream);
return 0;
}
@@ -328,7 +211,6 @@ static struct snd_pcm_ops omap_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = omap_pcm_hw_params,
.hw_free = omap_pcm_hw_free,
.prepare = omap_pcm_prepare,
.trigger = omap_pcm_trigger,
.pointer = omap_pcm_pointer,
.mmap = omap_pcm_mmap,