aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra20_i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra20_i2s.c')
-rw-r--r--sound/soc/tegra/tegra20_i2s.c160
1 files changed, 73 insertions, 87 deletions
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 0c7af63d444..79a9932ffe6 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -41,28 +41,17 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
#include "tegra20_i2s.h"
#define DRV_NAME "tegra20-i2s"
-static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
-{
- regmap_write(i2s->regmap, reg, val);
-}
-
-static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
-{
- u32 val;
- regmap_read(i2s->regmap, reg, &val);
- return val;
-}
-
static int tegra20_i2s_runtime_suspend(struct device *dev)
{
struct tegra20_i2s *i2s = dev_get_drvdata(dev);
- clk_disable(i2s->clk_i2s);
+ clk_disable_unprepare(i2s->clk_i2s);
return 0;
}
@@ -72,7 +61,7 @@ static int tegra20_i2s_runtime_resume(struct device *dev)
struct tegra20_i2s *i2s = dev_get_drvdata(dev);
int ret;
- ret = clk_enable(i2s->clk_i2s);
+ ret = clk_prepare_enable(i2s->clk_i2s);
if (ret) {
dev_err(dev, "clk_enable failed: %d\n", ret);
return ret;
@@ -85,6 +74,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int mask = 0, val = 0;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -93,10 +83,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
- i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
break;
case SND_SOC_DAIFMT_CBM_CFM:
break;
@@ -104,33 +94,35 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
- i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
- TEGRA20_I2S_CTRL_LRCK_MASK);
+ mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+ TEGRA20_I2S_CTRL_LRCK_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+ val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
break;
case SND_SOC_DAIFMT_DSP_B:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+ val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+ val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
break;
case SND_SOC_DAIFMT_I2S:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+ val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
break;
case SND_SOC_DAIFMT_RIGHT_J:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+ val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
break;
case SND_SOC_DAIFMT_LEFT_J:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+ val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
break;
default:
return -EINVAL;
}
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
return 0;
}
@@ -138,29 +130,34 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct device *dev = substream->pcm->card->dev;
+ struct device *dev = dai->dev;
struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- u32 reg;
+ unsigned int mask, val;
int ret, sample_size, srate, i2sclock, bitcnt;
- i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+ mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+ val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
sample_size = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+ val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
sample_size = 24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+ val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
sample_size = 32;
break;
default:
return -EINVAL;
}
+ mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
+ val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
srate = params_rate(params);
/* Final "* 2" required by Tegra hardware */
@@ -175,42 +172,44 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
bitcnt = (i2sclock / (2 * srate)) - 1;
if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
return -EINVAL;
- reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+ val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
if (i2sclock % (2 * srate))
- reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+ val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
- tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+ regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
- tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
- TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
- TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+ regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
+ TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+ TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
return 0;
}
static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
{
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
- tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+ TEGRA20_I2S_CTRL_FIFO1_ENABLE,
+ TEGRA20_I2S_CTRL_FIFO1_ENABLE);
}
static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
{
- i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
- tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+ TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
}
static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
{
- i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
- tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+ TEGRA20_I2S_CTRL_FIFO2_ENABLE,
+ TEGRA20_I2S_CTRL_FIFO2_ENABLE);
}
static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
{
- i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
- tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+ regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+ TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
}
static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -261,12 +260,14 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
.probe = tegra20_i2s_probe,
.playback = {
+ .stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
+ .stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_96000,
@@ -276,6 +277,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
.symmetric_rates = 1,
};
+static const struct snd_soc_component_driver tegra20_i2s_component = {
+ .name = DRV_NAME,
+};
+
static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -292,7 +297,7 @@ static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -305,7 +310,7 @@ static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
@@ -316,7 +321,7 @@ static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra20_i2s_regmap_config = {
@@ -328,15 +333,13 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
.readable_reg = tegra20_i2s_wr_rd_reg,
.volatile_reg = tegra20_i2s_volatile_reg,
.precious_reg = tegra20_i2s_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
-static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
+static int tegra20_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra20_i2s *i2s;
- struct resource *mem, *memregion, *dmareq;
- u32 of_dma[2];
- u32 dma_ch;
+ struct resource *mem, *memregion;
void __iomem *regs;
int ret;
@@ -365,20 +368,6 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
goto err_clk_put;
}
- dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmareq) {
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
- dma_ch = of_dma[1];
- } else {
- dma_ch = dmareq->start;
- }
-
memregion = devm_request_mem_region(&pdev->dev, mem->start,
resource_size(mem), DRV_NAME);
if (!memregion) {
@@ -403,16 +392,12 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
}
i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
- i2s->capture_dma_data.wrap = 4;
- i2s->capture_dma_data.width = 32;
- i2s->capture_dma_data.req_sel = dma_ch;
+ i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->capture_dma_data.maxburst = 4;
i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
- i2s->playback_dma_data.wrap = 4;
- i2s->playback_dma_data.width = 32;
- i2s->playback_dma_data.req_sel = dma_ch;
-
- i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+ i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->playback_dma_data.maxburst = 4;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
@@ -421,7 +406,8 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
goto err_pm_disable;
}
- ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+ ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
+ &i2s->dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
@@ -431,13 +417,13 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
ret = tegra_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
- goto err_unregister_dai;
+ goto err_unregister_component;
}
return 0;
-err_unregister_dai:
- snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+ snd_soc_unregister_component(&pdev->dev);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
tegra20_i2s_runtime_suspend(&pdev->dev);
@@ -449,7 +435,7 @@ err:
return ret;
}
-static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
+static int tegra20_i2s_platform_remove(struct platform_device *pdev)
{
struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
@@ -458,19 +444,19 @@ static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
tegra20_i2s_runtime_suspend(&pdev->dev);
tegra_pcm_platform_unregister(&pdev->dev);
- snd_soc_unregister_dai(&pdev->dev);
+ snd_soc_unregister_component(&pdev->dev);
clk_put(i2s->clk_i2s);
return 0;
}
-static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
+static const struct of_device_id tegra20_i2s_of_match[] = {
{ .compatible = "nvidia,tegra20-i2s", },
{},
};
-static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = {
+static const struct dev_pm_ops tegra20_i2s_pm_ops = {
SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
tegra20_i2s_runtime_resume, NULL)
};
@@ -483,7 +469,7 @@ static struct platform_driver tegra20_i2s_driver = {
.pm = &tegra20_i2s_pm_ops,
},
.probe = tegra20_i2s_platform_probe,
- .remove = __devexit_p(tegra20_i2s_platform_remove),
+ .remove = tegra20_i2s_platform_remove,
};
module_platform_driver(tegra20_i2s_driver);