summaryrefslogtreecommitdiff
path: root/sound/soc/blackfin/bf5xx-i2s.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:52:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:52:22 -0700
commit1286da8bc009cb2aee7f285e94623fc974c0c983 (patch)
tree51ec0a79c3de63fa809b831ae0cbb5b85e44482f /sound/soc/blackfin/bf5xx-i2s.c
parent9e220385c4eb8b7e66174a60ea0e15b6b296f228 (diff)
parent1ba65ae4bdbd43265c51ee4c30ff21a48124b6d8 (diff)
Merge tag 'sound-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "A relative calm release at this time with a flat diffstat. The only significant change in the ALSA core side is the support for more than 32 card instances, configurable via kconfig. Other than that, in both ASoC and other parts, mostly some improvements and fixes on the driver side. - hda: More quirks for ALC269-variants on Dell & co, VIA codec fixes - hda: Haswell HDMI audio fixes, runtime PM improvements - hda: Intel BayTrail support, ALC5505 DSP support - es1968: MediaForte M56VAP support - usb-audio: Improved support for Yamaha/Roland devices - usb-audio: M2Tech hiFace, Audio Advantage Micro II support - hdspm: wordclock fixes - ASoC: Pending fixes for WM8962 - ASoC: Cleanups and fixes for Blackfin, SGTL5000 and UX500 - ASoC: Generalisation of the Bluetooth and HDMI stub drivers - ASoC: SSM2518 and RT5640 codec drivers. - ASoC: Tegra CPUs with RT5640 machine driver - ASoC: AC'97 refactoring bug fixes - ASoC: ADAU1701 driver fixes - Clean up of *_set_drvdata() in a wide range of drivers" * tag 'sound-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (284 commits) ALSA: vmaster: Fix the regression of missing vmaster hook call ALSA: hda - Add Dell SSID to support Headset Mic recording ASoC: adau1701: remove control_data assignment ASoC: adau1701: more direct regmap usage ASoC: ac97: fixup multi-platform AC'97 module build failure ASoC: pxa2xx: fixup multi-platform AC'97 build failures ASoC: tegra20-ac97: Remove unused variable ASoC: tegra20-ac97: Remove duplicate error message ALSA: usb-audio: Add Audio Advantage Micro II ASoC: tas5086: fix Mid-Z implementation ASoC: tas5086: fix TAS5086_CLOCK_CONTROL register size ALSA: Replace the magic number 44 with const ALSA: hda - Fix the max length of control name in generic parser ALSA: hda - Guess what, it's two more Dell headset mic quirks ALSA: hda - Yet another Dell headset mic quirk ALSA: hda - Add support for ALC5505 DSP power-save mode ASoC: mfld: Remove unused variable ALSA: usb-audio: add quirks for Roland QUAD/OCTO-CAPTURE ALSA: usb-audio: claim autodetected PCM interfaces all at once ALSA: usb-audio: remove superfluous Roland quirks ...
Diffstat (limited to 'sound/soc/blackfin/bf5xx-i2s.c')
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c129
1 files changed, 109 insertions, 20 deletions
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index dd0c2a4f83a3..9a174fc47d39 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -42,6 +42,7 @@
#include <linux/gpio.h>
#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
struct bf5xx_i2s_port {
u16 tcr1;
@@ -49,6 +50,13 @@ struct bf5xx_i2s_port {
u16 tcr2;
u16 rcr2;
int configured;
+
+ unsigned int slots;
+ unsigned int tx_mask;
+ unsigned int rx_mask;
+
+ struct bf5xx_i2s_pcm_data tx_dma_data;
+ struct bf5xx_i2s_pcm_data rx_dma_data;
};
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -74,7 +82,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
ret = -EINVAL;
break;
default:
- printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
+ dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
+ __func__);
ret = -EINVAL;
break;
}
@@ -88,7 +97,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
ret = -EINVAL;
break;
default:
- printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
+ dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
+ __func__);
ret = -EINVAL;
break;
}
@@ -141,14 +151,14 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
bf5xx_i2s->rcr2, 0, 0);
if (ret) {
- pr_err("SPORT is busy!\n");
+ dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
bf5xx_i2s->tcr2, 0, 0);
if (ret) {
- pr_err("SPORT is busy!\n");
+ dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
}
@@ -162,18 +172,76 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
- pr_debug("%s enter\n", __func__);
+ dev_dbg(dai->dev, "%s enter\n", __func__);
/* No active stream, SPORT is allowed to be configured again. */
if (!dai->active)
bf5xx_i2s->configured = 0;
}
+static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+ struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+ unsigned int tx_mapped = 0, rx_mapped = 0;
+ unsigned int slot;
+ int i;
+
+ if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
+ (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
+ return -EINVAL;
+
+ for (i = 0; i < tx_num; i++) {
+ slot = tx_slot[i];
+ if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+ (!(tx_mapped & (1 << slot)))) {
+ bf5xx_i2s->tx_dma_data.map[i] = slot;
+ tx_mapped |= 1 << slot;
+ } else
+ return -EINVAL;
+ }
+ for (i = 0; i < rx_num; i++) {
+ slot = rx_slot[i];
+ if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+ (!(rx_mapped & (1 << slot)))) {
+ bf5xx_i2s->rx_dma_data.map[i] = slot;
+ rx_mapped |= 1 << slot;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int width)
+{
+ struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+ struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
+ if (slots % 8 != 0 || slots > 8)
+ return -EINVAL;
+
+ if (width != 32)
+ return -EINVAL;
+
+ bf5xx_i2s->slots = slots;
+ bf5xx_i2s->tx_mask = tx_mask;
+ bf5xx_i2s->rx_mask = rx_mask;
+
+ bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
+ bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
+
+ return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
+}
+
#ifdef CONFIG_PM
static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
{
struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
- pr_debug("%s : sport %d\n", __func__, dai->id);
+ dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
if (dai->capture_active)
sport_rx_stop(sport_handle);
@@ -188,23 +256,24 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
int ret;
- pr_debug("%s : sport %d\n", __func__, dai->id);
+ dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
bf5xx_i2s->rcr2, 0, 0);
if (ret) {
- pr_err("SPORT is busy!\n");
+ dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
bf5xx_i2s->tcr2, 0, 0);
if (ret) {
- pr_err("SPORT is busy!\n");
+ dev_err(dai->dev, "SPORT is busy!\n");
return -EBUSY;
}
- return 0;
+ return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
+ bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
}
#else
@@ -212,6 +281,23 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
#define bf5xx_i2s_resume NULL
#endif
+static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+ struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+ unsigned int i;
+
+ for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
+ bf5xx_i2s->tx_dma_data.map[i] = i;
+ bf5xx_i2s->rx_dma_data.map[i] = i;
+ }
+
+ dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
+ dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
+
+ return 0;
+}
+
#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
@@ -224,22 +310,25 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
- .shutdown = bf5xx_i2s_shutdown,
- .hw_params = bf5xx_i2s_hw_params,
- .set_fmt = bf5xx_i2s_set_dai_fmt,
+ .shutdown = bf5xx_i2s_shutdown,
+ .hw_params = bf5xx_i2s_hw_params,
+ .set_fmt = bf5xx_i2s_set_dai_fmt,
+ .set_tdm_slot = bf5xx_i2s_set_tdm_slot,
+ .set_channel_map = bf5xx_i2s_set_channel_map,
};
static struct snd_soc_dai_driver bf5xx_i2s_dai = {
+ .probe = bf5xx_i2s_dai_probe,
.suspend = bf5xx_i2s_suspend,
.resume = bf5xx_i2s_resume,
.playback = {
- .channels_min = 1,
- .channels_max = 2,
+ .channels_min = 2,
+ .channels_max = 8,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.capture = {
- .channels_min = 1,
- .channels_max = 2,
+ .channels_min = 2,
+ .channels_max = 8,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.ops = &bf5xx_i2s_dai_ops,
@@ -255,7 +344,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
int ret;
/* configure SPORT for I2S */
- sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+ sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
sizeof(struct bf5xx_i2s_port));
if (!sport_handle)
return -ENODEV;
@@ -264,7 +353,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
&bf5xx_i2s_dai, 1);
if (ret) {
- pr_err("Failed to register DAI: %d\n", ret);
+ dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
sport_done(sport_handle);
return ret;
}
@@ -276,7 +365,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
{
struct sport_device *sport_handle = platform_get_drvdata(pdev);
- pr_debug("%s enter\n", __func__);
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
snd_soc_unregister_component(&pdev->dev);
sport_done(sport_handle);