diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 13:00:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 13:00:13 -0700 |
commit | b2094ef840697bc8ca5d17a83b7e30fad5f1e9fa (patch) | |
tree | 64e5f7253b6a85b6d5d36f95c0d3c67c1798918d /sound/soc/omap/omap-mcbsp.c | |
parent | 424a6f6ef990b7e9f56f6627bfc6c46b493faeb4 (diff) | |
parent | 6681bc0deba495fad0d6fb349e40524abd1b1732 (diff) |
Merge tag 'sound-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull updates of sound stuff from Takashi Iwai:
"Here is the first big update chunk of sound stuff for 3.4-rc1.
In the common sound infrastructure, there are a few changes for
dynamic PCM support (used in ASoC) and a few clean-ups. Majority of
changes are found, as usual, in HD-audio and ASoC.
Some highlights of HD-audio changes:
- All the long-standing static quirk codes for Realtek codec were
finally removed by fixing and extending the Realtek auto-parser.
- The mute-LED control is standardized over all HD-audio codec
drivers using the extended vmaster hook.
- The vmaster slave mixer elements are initialized to 0dB as default
so that the user won't be annoyed by the silent output after
updates, e.g. due to the additions of new elements.
- Other many fix-ups for the misc HD-audio devices.
In the ASoC side, this is a very active release, including a quite a
few framework enhancements. Some highlights:
- Support for widgets not associated with a CODEC, an important part
of the dynamic PCM framework.
- A library factoring out the common code shared by dmaengine based
DMA drivers contributed by Lars-Peter Clausen. This will save a
lot of code and make it much easier to deploy enhancements to
dmaengine.
- Support for binary controls, used for providing runtime
configuration of algorithm coefficients.
- A new DAPM widget type for regulator supplies allowing drivers for
devices that can power down unused supplies while active to do
without any per-driver code.
- DAPM widgets for DAIs, initially giving a speed boost for playback
startup and shutdown and also the basis for CODEC<->CODEC DAI link
support.
- Support for specifying the number of significant bits on audio
interfaces, useful for allowing applications to know how much
effort to put into generating data for a larger sample format.
- Conversion of the FSI driver used on some SH processors to
DMAEngine.
- Conversion of EP93xx drivers to DMAEngine.
- New CODEC drivers for Maxim MAX9768 and Wolfson Microelectronics
WM2200.
- Move audmux driver from arc/arm to sound/soc
- McBSP move from arch/ to sound/ and updates
Also, a few small updates and fixes for other drivers like au88x0,
ymfpci, USB 6fire, USB usx2yaudio are included."
* tag 'sound-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (446 commits)
ASoC: wm8994: Provide VMID mode control and fix default sequence
ASoC: wm8994: Add missing break in resume
ASoC: wm_hubs: Don't actively manage LINEOUT_VMID_BUF
ASoC: pxa-ssp: atomically set stream active masks
ASoC: fsl: p1022ds: tell the WM8776 codec driver that it's the master
ASoC: Samsung: Added to support mono recording
ALSA: hda - Fix build with CONFIG_PM=n
ALSA: au88x0 - Avoid possible Oops at unbinding
ALSA: usb-audio - Fix build error by consitification of rate list
ASoC: core: Fix obscure leak of runtime array
ALSA: pcm - Avoid GFP_ATOMIC in snd_pcm_link()
ALSA: pcm: Constify the list in snd_pcm_hw_constraint_list
ASoC: wm8996: Add 44.1kHz support
ALSA: hda - Fix build of patch_sigmatel.c without CONFIG_SND_HDA_POWER_SAVE
ASoC: mx27vis-aic32x4: Convert it to platform driver
ALSA: hda - fix printing of high HDMI sample rates
ALSA: ymfpci - Fix legacy registers on S3/S4 resume
ALSA: control - Fixe a trailing white space error
ALSA: hda - Add expose_enum_ctl flag to snd_hda_add_vmaster_hook()
ALSA: hda - Add "Mute-LED Mode" enum control
...
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 321 |
1 files changed, 173 insertions, 148 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 017371913ec3..6912ac7cb625 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -33,6 +34,7 @@ #include <plat/dma.h> #include <plat/mcbsp.h> +#include "mcbsp.h" #include "omap-mcbsp.h" #include "omap-pcm.h" @@ -46,42 +48,31 @@ .private_value = (unsigned long) &(struct soc_mixer_control) \ {.min = xmin, .max = xmax} } -struct omap_mcbsp_data { - unsigned int bus_id; - struct omap_mcbsp_reg_cfg regs; - unsigned int fmt; - /* - * Flags indicating is the bus already activated and configured by - * another substream - */ - int active; - int configured; - unsigned int in_freq; - int clk_div; - int wlen; +enum { + OMAP_MCBSP_WORD_8 = 0, + OMAP_MCBSP_WORD_12, + OMAP_MCBSP_WORD_16, + OMAP_MCBSP_WORD_20, + OMAP_MCBSP_WORD_24, + OMAP_MCBSP_WORD_32, }; -static struct omap_mcbsp_data mcbsp_data[NUM_LINKS]; - /* * Stream DMA parameters. DMA request line and port address are set runtime * since they are different between OMAP1 and later OMAPs */ -static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2]; - static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); struct omap_pcm_dma_data *dma_data; - int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); int words; dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ - if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) /* * Configure McBSP threshold based on either: * packet_size, when the sDMA is in packet mode, or @@ -91,15 +82,15 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) words = dma_data->packet_size; else words = snd_pcm_lib_period_bytes(substream) / - (mcbsp_data->wlen / 8); + (mcbsp->wlen / 8); else words = 1; /* Configure McBSP internal buffer usage */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words); + omap_mcbsp_set_tx_threshold(mcbsp, words); else - omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); + omap_mcbsp_set_rx_threshold(mcbsp, words); } static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, @@ -109,12 +100,12 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct omap_mcbsp_data *mcbsp_data = rule->private; + struct omap_mcbsp *mcbsp = rule->private; struct snd_interval frames; int size; snd_interval_any(&frames); - size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id); + size = mcbsp->pdata->buffer_size; frames.min = size / channels->min; frames.integer = 1; @@ -124,12 +115,11 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - int bus_id = mcbsp_data->bus_id; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); int err = 0; if (!cpu_dai->active) - err = omap_mcbsp_request(bus_id); + err = omap_mcbsp_request(mcbsp); /* * OMAP3 McBSP FIFO is word structured. @@ -146,16 +136,16 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) */ - if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + if (mcbsp->pdata->buffer_size) { /* * Rule for the buffer size. We should not allow * smaller buffer than the FIFO size to avoid underruns */ snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, omap_mcbsp_hwrule_min_buffersize, - mcbsp_data, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); + mcbsp, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, @@ -168,33 +158,33 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); if (!cpu_dai->active) { - omap_mcbsp_free(mcbsp_data->bus_id); - mcbsp_data->configured = 0; + omap_mcbsp_free(mcbsp); + mcbsp->configured = 0; } } static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - mcbsp_data->active++; - omap_mcbsp_start(mcbsp_data->bus_id, play, !play); + mcbsp->active++; + omap_mcbsp_start(mcbsp, play, !play); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); - mcbsp_data->active--; + omap_mcbsp_stop(mcbsp, play, !play); + mcbsp->active--; break; default: err = -EINVAL; @@ -209,14 +199,14 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay( { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); u16 fifo_use; snd_pcm_sframes_t delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id); + fifo_use = omap_mcbsp_get_tx_delay(mcbsp); else - fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id); + fifo_use = omap_mcbsp_get_rx_delay(mcbsp); /* * Divide the used locations with the channel count to get the @@ -232,19 +222,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; struct omap_pcm_dma_data *dma_data; - int dma, bus_id = mcbsp_data->bus_id; int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; int pkt_size = 0; - unsigned long port; unsigned int format, div, framesize, master; - dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream]; - - dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream); - port = omap_mcbsp_dma_reg_params(bus_id, substream->stream); + dma_data = &mcbsp->dma_data[substream->stream]; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -258,20 +243,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + if (mcbsp->pdata->buffer_size) { dma_data->set_threshold = omap_mcbsp_set_threshold; /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ - if (omap_mcbsp_get_dma_op_mode(bus_id) == - MCBSP_DMA_MODE_THRESHOLD) { + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; period_words = params_period_bytes(params) / (wlen / 8); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - max_thrsh = omap_mcbsp_get_max_tx_threshold( - mcbsp_data->bus_id); + max_thrsh = mcbsp->max_tx_thres; else - max_thrsh = omap_mcbsp_get_max_rx_threshold( - mcbsp_data->bus_id); + max_thrsh = mcbsp->max_rx_thres; /* * If the period contains less or equal number of words, * we are using the original threshold mode setup: @@ -304,15 +286,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } } - dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback"; - dma_data->dma_req = dma; - dma_data->port_addr = port; dma_data->sync_mode = sync_mode; dma_data->packet_size = pkt_size; snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); - if (mcbsp_data->configured) { + if (mcbsp->configured) { /* McBSP already configured by another stream */ return 0; } @@ -321,7 +300,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); - format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; wpf = channels = params_channels(params); if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || format == SND_SOC_DAIFMT_LEFT_J)) { @@ -359,10 +338,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, /* In McBSP master modes, FRAME (i.e. sample rate) is generated * by _counting_ BCLKs. Calculate frame size in BCLKs */ - master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK; + master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; if (master == SND_SOC_DAIFMT_CBS_CFS) { - div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1; - framesize = (mcbsp_data->in_freq / div) / params_rate(params); + div = mcbsp->clk_div ? mcbsp->clk_div : 1; + framesize = (mcbsp->in_freq / div) / params_rate(params); if (framesize < wlen * channels) { printk(KERN_ERR "%s: not enough bandwidth for desired rate and " @@ -388,9 +367,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, break; } - omap_mcbsp_config(bus_id, &mcbsp_data->regs); - mcbsp_data->wlen = wlen; - mcbsp_data->configured = 1; + omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs); + mcbsp->wlen = wlen; + mcbsp->configured = 1; return 0; } @@ -402,14 +381,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; bool inv_fs = false; - if (mcbsp_data->configured) + if (mcbsp->configured) return 0; - mcbsp_data->fmt = fmt; + mcbsp->fmt = fmt; memset(regs, 0, sizeof(*regs)); /* Generic McBSP register settings */ regs->spcr2 |= XINTM(3) | FREE; @@ -504,13 +483,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; if (div_id != OMAP_MCBSP_CLKGDV) return -ENODEV; - mcbsp_data->clk_div = div; + mcbsp->clk_div = div; regs->srgr1 &= ~CLKGDV(0xff); regs->srgr1 |= CLKGDV(div - 1); @@ -521,28 +500,32 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; int err = 0; - if (mcbsp_data->active) { - if (freq == mcbsp_data->in_freq) + if (mcbsp->active) { + if (freq == mcbsp->in_freq) return 0; else return -EBUSY; } - /* The McBSP signal muxing functions are only available on McBSP1 */ - if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR || - clk_id == OMAP_MCBSP_CLKR_SRC_CLKX || - clk_id == OMAP_MCBSP_FSR_SRC_FSR || - clk_id == OMAP_MCBSP_FSR_SRC_FSX) - if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0) - return -EINVAL; - - mcbsp_data->in_freq = freq; - regs->srgr2 &= ~CLKSM; - regs->pcr0 &= ~SCLKME; + if (clk_id == OMAP_MCBSP_SYSCLK_CLK || + clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK || + clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT || + clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT || + clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) { + mcbsp->in_freq = freq; + regs->srgr2 &= ~CLKSM; + regs->pcr0 &= ~SCLKME; + } else if (cpu_class_is_omap1()) { + /* + * McBSP CLKR/FSR signal muxing functions are only available on + * OMAP2 or newer versions + */ + return -EINVAL; + } switch (clk_id) { case OMAP_MCBSP_SYSCLK_CLK: @@ -553,7 +536,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, err = -EINVAL; break; } - err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, + err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: @@ -561,7 +544,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, err = 0; break; } - err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, + err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PAD_SRC); break; @@ -573,24 +556,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_CLKR_SRC_CLKR: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR); + err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR); break; case OMAP_MCBSP_CLKR_SRC_CLKX: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX); + err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX); break; case OMAP_MCBSP_FSR_SRC_FSR: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR); + err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR); break; case OMAP_MCBSP_FSR_SRC_FSX: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX); + err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX); break; default: err = -ENODEV; @@ -610,15 +585,27 @@ static const struct snd_soc_dai_ops mcbsp_dai_ops = { .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, }; -static int mcbsp_dai_probe(struct snd_soc_dai *dai) +static int omap_mcbsp_probe(struct snd_soc_dai *dai) { - mcbsp_data[dai->id].bus_id = dai->id; - snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); + + pm_runtime_enable(mcbsp->dev); + + return 0; +} + +static int omap_mcbsp_remove(struct snd_soc_dai *dai) +{ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); + + pm_runtime_disable(mcbsp->dev); + return 0; } static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = mcbsp_dai_probe, + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, @@ -649,11 +636,13 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, return 0; } -#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \ +#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel) \ static int \ -omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ +omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ struct snd_ctl_elem_value *uc) \ { \ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ struct soc_mixer_control *mc = \ (struct soc_mixer_control *)kc->private_value; \ int max = mc->max; \ @@ -664,46 +653,44 @@ omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ return -EINVAL; \ \ /* OMAP McBSP implementation uses index values 0..4 */ \ - return omap_st_set_chgain((id)-1, channel, val); \ + return omap_st_set_chgain(mcbsp, channel, val); \ } -#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \ +#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel) \ static int \ -omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ +omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ struct snd_ctl_elem_value *uc) \ { \ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ s16 chgain; \ \ - if (omap_st_get_chgain((id)-1, channel, &chgain)) \ + if (omap_st_get_chgain(mcbsp, channel, &chgain)) \ return -EAGAIN; \ \ uc->value.integer.value[0] = chgain; \ return 0; \ } -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1) static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); u8 value = ucontrol->value.integer.value[0]; - if (value == omap_st_is_enabled(mc->reg)) + if (value == omap_st_is_enabled(mcbsp)) return 0; if (value) - omap_st_enable(mc->reg); + omap_st_enable(mcbsp); else - omap_st_disable(mc->reg); + omap_st_disable(mcbsp); return 1; } @@ -711,10 +698,10 @@ static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg); + ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp); return 0; } @@ -723,12 +710,12 @@ static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = { omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", -32768, 32767, - omap_mcbsp2_get_st_ch0_volume, - omap_mcbsp2_set_st_ch0_volume), + omap_mcbsp_get_st_ch0_volume, + omap_mcbsp_set_st_ch0_volume), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", -32768, 32767, - omap_mcbsp2_get_st_ch1_volume, - omap_mcbsp2_set_st_ch1_volume), + omap_mcbsp_get_st_ch1_volume, + omap_mcbsp_set_st_ch1_volume), }; static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { @@ -736,25 +723,30 @@ static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", -32768, 32767, - omap_mcbsp3_get_st_ch0_volume, - omap_mcbsp3_set_st_ch0_volume), + omap_mcbsp_get_st_ch0_volume, + omap_mcbsp_set_st_ch0_volume), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", -32768, 32767, - omap_mcbsp3_get_st_ch1_volume, - omap_mcbsp3_set_st_ch1_volume), + omap_mcbsp_get_st_ch1_volume, + omap_mcbsp_set_st_ch1_volume), }; -int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id) +int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd) { - if (!cpu_is_omap34xx()) + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + + if (!mcbsp->st_data) return -ENODEV; - switch (mcbsp_id) { - case 1: /* McBSP 2 */ - return snd_soc_add_controls(codec, omap_mcbsp2_st_controls, + switch (cpu_dai->id) { + case 2: /* McBSP 2 */ + return snd_soc_add_dai_controls(cpu_dai, + omap_mcbsp2_st_controls, ARRAY_SIZE(omap_mcbsp2_st_controls)); - case 2: /* McBSP 3 */ - return snd_soc_add_controls(codec, omap_mcbsp3_st_controls, + case 3: /* McBSP 3 */ + return snd_soc_add_dai_controls(cpu_dai, + omap_mcbsp3_st_controls, ARRAY_SIZE(omap_mcbsp3_st_controls)); default: break; @@ -766,18 +758,51 @@ EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct omap_mcbsp *mcbsp; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data.\n"); + return -EINVAL; + } + mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL); + if (!mcbsp) + return -ENOMEM; + + mcbsp->id = pdev->id; + mcbsp->pdata = pdata; + mcbsp->dev = &pdev->dev; + platform_set_drvdata(pdev, mcbsp); + + ret = omap_mcbsp_init(pdev); + if (!ret) + return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + + return ret; } static int __devexit asoc_mcbsp_remove(struct platform_device *pdev) { + struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); + snd_soc_unregister_dai(&pdev->dev); + + if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) + mcbsp->pdata->ops->free(mcbsp->id); + + omap_mcbsp_sysfs_remove(mcbsp); + + clk_put(mcbsp->fclk); + + platform_set_drvdata(pdev, NULL); + return 0; } static struct platform_driver asoc_mcbsp_driver = { .driver = { - .name = "omap-mcbsp-dai", + .name = "omap-mcbsp", .owner = THIS_MODULE, }, |