aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/Kconfig12
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c17
-rw-r--r--sound/soc/tegra/tegra20_i2s.c20
-rw-r--r--sound/soc/tegra/tegra30_ahub.c138
-rw-r--r--sound/soc/tegra/tegra30_ahub.h11
-rw-r--r--sound/soc/tegra/tegra30_i2s.c97
-rw-r--r--sound/soc/tegra/tegra30_i2s.h3
-rw-r--r--sound/soc/tegra/tegra_max98090.c275
-rw-r--r--sound/soc/tegra/tegra_pcm.c20
-rw-r--r--sound/soc/tegra/tegra_pcm.h5
-rw-r--r--sound/soc/tegra/tegra_wm9712.c1
12 files changed, 461 insertions, 140 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 8fc653ca3ab4..9f9c1856f822 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,6 +1,8 @@
config SND_SOC_TEGRA
tristate "SoC Audio for the Tegra System-on-Chip"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
+ depends on COMMON_CLK
+ depends on RESET_CONTROLLER
select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
help
@@ -116,3 +118,13 @@ config SND_SOC_TEGRA_ALC5632
help
Say Y or M here if you want to add support for SoC audio on the
Toshiba AC100 netbook.
+
+config SND_SOC_TEGRA_MAX98090
+ tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
+ depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+ select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+ select SND_SOC_MAX98090
+ help
+ Say Y or M here if you want to add support for SoC audio on Tegra
+ boards using the MAX98090 codec, such as Venice2.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 21d2550a08a4..5ae588cd96c4 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -24,6 +24,7 @@ snd-soc-tegra-wm8903-objs := tegra_wm8903.o
snd-soc-tegra-wm9712-objs := tegra_wm9712.o
snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-alc5632-objs := tegra_alc5632.o
+snd-soc-tegra-max98090-objs := tegra_max98090.o
obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
+obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index ae27bcd586d2..cf5e1cfe818d 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -313,7 +313,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
{
struct tegra20_ac97 *ac97;
struct resource *mem;
- u32 of_dma[2];
void __iomem *regs;
int ret = 0;
@@ -348,14 +347,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
goto err_clk_put;
}
- 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;
- }
-
ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node,
"nvidia,codec-reset-gpio", 0);
if (gpio_is_valid(ac97->reset_gpio)) {
@@ -380,12 +371,10 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->capture_dma_data.maxburst = 4;
- ac97->capture_dma_data.slave_id = of_dma[1];
ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->playback_dma_data.maxburst = 4;
- ac97->playback_dma_data.slave_id = of_dma[1];
ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
if (ret)
@@ -404,7 +393,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
if (ret) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
- goto err_asoc_utils_fini;
+ goto err_clk_disable_unprepare;
}
ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
@@ -412,7 +401,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
- goto err_asoc_utils_fini;
+ goto err_clk_disable_unprepare;
}
ret = tegra_pcm_platform_register(&pdev->dev);
@@ -428,6 +417,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
+err_clk_disable_unprepare:
+ clk_disable_unprepare(ac97->clk_ac97);
err_asoc_utils_fini:
tegra_asoc_utils_fini(&ac97->util_data);
err_clk_put:
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 8c819f811470..42c1f6bfaf2e 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -339,9 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
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;
@@ -370,20 +368,6 @@ static 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) {
@@ -410,12 +394,10 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = 4;
- i2s->capture_dma_data.slave_id = dma_ch;
i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = 4;
- i2s->playback_dma_data.slave_id = dma_ch;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 31154338c1eb..d6f4c9940e0c 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -24,8 +24,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/slab.h>
-#include <linux/clk/tegra.h>
#include <sound/soc.h>
#include "tegra30_ahub.h"
@@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
}
int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel)
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg)
{
int channel;
u32 reg, val;
@@ -110,9 +110,11 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
__set_bit(channel, ahub->rx_usage);
*rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
+ snprintf(dmachan, dmachan_len, "rx%d", channel);
*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
(channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
- *reqsel = ahub->dma_sel + channel;
+
+ pm_runtime_get_sync(ahub->dev);
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
@@ -140,6 +142,8 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
(channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
@@ -149,12 +153,16 @@ int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
@@ -164,12 +172,16 @@ int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
@@ -185,8 +197,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel)
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg)
{
int channel;
u32 reg, val;
@@ -200,9 +212,11 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
__set_bit(channel, ahub->tx_usage);
*txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
+ snprintf(dmachan, dmachan_len, "tx%d", channel);
*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
(channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
- *reqsel = ahub->dma_sel + channel;
+
+ pm_runtime_get_sync(ahub->dev);
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
@@ -230,6 +244,8 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
(channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
@@ -239,12 +255,16 @@ int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
@@ -254,12 +274,16 @@ int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
@@ -280,10 +304,14 @@ int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_AUDIO_RX +
(channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
tegra30_audio_write(reg, 1 << txcif);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
@@ -293,35 +321,51 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_AUDIO_RX +
(channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
tegra30_audio_write(reg, 0);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
-#define CLK_LIST_MASK_TEGRA30 BIT(0)
-#define CLK_LIST_MASK_TEGRA114 BIT(1)
+#define MOD_LIST_MASK_TEGRA30 BIT(0)
+#define MOD_LIST_MASK_TEGRA114 BIT(1)
+#define MOD_LIST_MASK_TEGRA124 BIT(2)
-#define CLK_LIST_MASK_TEGRA30_OR_LATER \
- (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114)
+#define MOD_LIST_MASK_TEGRA30_OR_LATER \
+ (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \
+ MOD_LIST_MASK_TEGRA124)
+#define MOD_LIST_MASK_TEGRA114_OR_LATER \
+ (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124)
static const struct {
- const char *clk_name;
- u32 clk_list_mask;
-} configlink_clocks[] = {
- { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "amx", CLK_LIST_MASK_TEGRA114 },
- { "adx", CLK_LIST_MASK_TEGRA114 },
+ const char *rst_name;
+ u32 mod_list_mask;
+} configlink_mods[] = {
+ { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER },
+ { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER },
+ { "amx1", MOD_LIST_MASK_TEGRA124 },
+ { "adx1", MOD_LIST_MASK_TEGRA124 },
+ { "afc0", MOD_LIST_MASK_TEGRA124 },
+ { "afc1", MOD_LIST_MASK_TEGRA124 },
+ { "afc2", MOD_LIST_MASK_TEGRA124 },
+ { "afc3", MOD_LIST_MASK_TEGRA124 },
+ { "afc4", MOD_LIST_MASK_TEGRA124 },
+ { "afc5", MOD_LIST_MASK_TEGRA124 },
};
#define LAST_REG(name) \
@@ -450,17 +494,17 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
};
static struct tegra30_ahub_soc_data soc_data_tegra30 = {
- .clk_list_mask = CLK_LIST_MASK_TEGRA30,
+ .mod_list_mask = MOD_LIST_MASK_TEGRA30,
.set_audio_cif = tegra30_ahub_set_cif,
};
static struct tegra30_ahub_soc_data soc_data_tegra114 = {
- .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+ .mod_list_mask = MOD_LIST_MASK_TEGRA114,
.set_audio_cif = tegra30_ahub_set_cif,
};
static struct tegra30_ahub_soc_data soc_data_tegra124 = {
- .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+ .mod_list_mask = MOD_LIST_MASK_TEGRA124,
.set_audio_cif = tegra124_ahub_set_cif,
};
@@ -475,10 +519,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct tegra30_ahub_soc_data *soc_data;
- struct clk *clk;
+ struct reset_control *rst;
int i;
struct resource *res0, *res1, *region;
- u32 of_dma[2];
void __iomem *regs_apbif, *regs_ahub;
int ret = 0;
@@ -495,19 +538,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
* operate correctly, all devices on this bus must be out of reset.
* Ensure that here.
*/
- for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
- if (!(configlink_clocks[i].clk_list_mask &
- soc_data->clk_list_mask))
+ for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
+ if (!(configlink_mods[i].mod_list_mask &
+ soc_data->mod_list_mask))
continue;
- clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Can't get clock %s\n",
- configlink_clocks[i].clk_name);
- ret = PTR_ERR(clk);
+
+ rst = reset_control_get(&pdev->dev,
+ configlink_mods[i].rst_name);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Can't get reset %s\n",
+ configlink_mods[i].rst_name);
+ ret = PTR_ERR(rst);
goto err;
}
- tegra_periph_reset_deassert(clk);
- clk_put(clk);
+
+ ret = reset_control_deassert(rst);
+ reset_control_put(rst);
+ if (ret)
+ goto err;
}
ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
@@ -536,16 +584,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
goto err_clk_put_d_audio;
}
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev,
- "Missing property nvidia,dma-request-selector\n");
- ret = -ENODEV;
- goto err_clk_put_d_audio;
- }
- ahub->dma_sel = of_dma[1];
-
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res0) {
dev_err(&pdev->dev, "No apbif memory resource\n");
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index d67321d90faa..fd7ba75ed814 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -465,15 +465,15 @@ enum tegra30_ahub_rxcif {
};
extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel);
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg);
extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel);
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg);
extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
@@ -502,7 +502,7 @@ void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
struct tegra30_ahub_cif_conf *conf);
struct tegra30_ahub_soc_data {
- u32 clk_list_mask;
+ u32 mod_list_mask;
void (*set_audio_cif)(struct regmap *regmap,
unsigned int reg,
struct tegra30_ahub_cif_conf *conf);
@@ -524,7 +524,6 @@ struct tegra30_ahub {
struct device *dev;
struct clk *clk_d_audio;
struct clk *clk_apbif;
- int dma_sel;
resource_size_t apbif_addr;
struct regmap *regmap_apbif;
struct regmap *regmap_ahub;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 02247fee1cf7..49ad9366add8 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -73,47 +73,6 @@ static int tegra30_i2s_runtime_resume(struct device *dev)
return 0;
}
-static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
- &i2s->playback_dma_data.addr,
- &i2s->playback_dma_data.slave_id);
- i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- i2s->playback_dma_data.maxburst = 4;
- tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
- i2s->playback_fifo_cif);
- } else {
- ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
- &i2s->capture_dma_data.addr,
- &i2s->capture_dma_data.slave_id);
- i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- i2s->capture_dma_data.maxburst = 4;
- tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
- i2s->capture_i2s_cif);
- }
-
- return ret;
-}
-
-static void tegra30_i2s_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
- tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
- } else {
- tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
- tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
- }
-}
-
static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
@@ -317,8 +276,6 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
}
static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
- .startup = tegra30_i2s_startup,
- .shutdown = tegra30_i2s_shutdown,
.set_fmt = tegra30_i2s_set_fmt,
.hw_params = tegra30_i2s_hw_params,
.trigger = tegra30_i2s_trigger,
@@ -499,15 +456,51 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
goto err_pm_disable;
}
+ i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->playback_dma_data.maxburst = 4;
+ ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
+ i2s->playback_dma_chan,
+ sizeof(i2s->playback_dma_chan),
+ &i2s->playback_dma_data.addr);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not alloc TX FIFO: %d\n", ret);
+ goto err_suspend;
+ }
+ ret = tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
+ i2s->playback_fifo_cif);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret);
+ goto err_free_tx_fifo;
+ }
+
+ i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->capture_dma_data.maxburst = 4;
+ ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
+ i2s->capture_dma_chan,
+ sizeof(i2s->capture_dma_chan),
+ &i2s->capture_dma_data.addr);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not alloc RX FIFO: %d\n", ret);
+ goto err_unroute_tx_fifo;
+ }
+ ret = tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
+ i2s->capture_i2s_cif);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret);
+ goto err_free_rx_fifo;
+ }
+
ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component,
&i2s->dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
- goto err_suspend;
+ goto err_unroute_rx_fifo;
}
- ret = tegra_pcm_platform_register(&pdev->dev);
+ ret = tegra_pcm_platform_register_with_chan_names(&pdev->dev,
+ &i2s->dma_config, i2s->playback_dma_chan,
+ i2s->capture_dma_chan);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
goto err_unregister_component;
@@ -517,6 +510,14 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
+err_unroute_rx_fifo:
+ tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+err_free_rx_fifo:
+ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+err_unroute_tx_fifo:
+ tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+err_free_tx_fifo:
+ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
tegra30_i2s_runtime_suspend(&pdev->dev);
@@ -539,6 +540,12 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
tegra_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
+ tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+
+ tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
+
clk_put(i2s->clk_i2s);
return 0;
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index 4d0b0a30dbfb..774fc6ad2026 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -238,11 +238,14 @@ struct tegra30_i2s {
struct clk *clk_i2s;
enum tegra30_ahub_txcif capture_i2s_cif;
enum tegra30_ahub_rxcif capture_fifo_cif;
+ char capture_dma_chan[8];
struct snd_dmaengine_dai_dma_data capture_dma_data;
enum tegra30_ahub_rxcif playback_i2s_cif;
enum tegra30_ahub_txcif playback_fifo_cif;
+ char playback_dma_chan[8];
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
+ struct snd_dmaengine_pcm_config dma_config;
};
#endif
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
new file mode 100644
index 000000000000..0283cfb7c031
--- /dev/null
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -0,0 +1,275 @@
+/*
+ * Tegra machine ASoC driver for boards using a MAX90809 CODEC.
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-max98090"
+
+struct tegra_max98090 {
+ struct tegra_asoc_utils_data util_data;
+ int gpio_hp_det;
+};
+
+static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ mclk = 12000000;
+ break;
+ }
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops tegra_max98090_ops = {
+ .hw_params = tegra_max98090_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_max98090_hp_jack;
+
+static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = {
+ .name = "Headphone detection",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+ .invert = 1,
+};
+
+static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_max98090_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card);
+
+ if (gpio_is_valid(machine->gpio_hp_det)) {
+ snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
+ &tegra_max98090_hp_jack);
+ snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
+ ARRAY_SIZE(tegra_max98090_hp_jack_pins),
+ tegra_max98090_hp_jack_pins);
+
+ tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
+ snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
+ 1,
+ &tegra_max98090_hp_jack_gpio);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_link tegra_max98090_dai = {
+ .name = "max98090",
+ .stream_name = "max98090 PCM",
+ .codec_dai_name = "HiFi",
+ .init = tegra_max98090_asoc_init,
+ .ops = &tegra_max98090_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_max98090 = {
+ .name = "tegra-max98090",
+ .owner = THIS_MODULE,
+ .dai_link = &tegra_max98090_dai,
+ .num_links = 1,
+ .controls = tegra_max98090_controls,
+ .num_controls = ARRAY_SIZE(tegra_max98090_controls),
+ .dapm_widgets = tegra_max98090_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets),
+ .fully_routed = true,
+};
+
+static int tegra_max98090_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &snd_soc_tegra_max98090;
+ struct tegra_max98090 *machine;
+ int ret;
+
+ machine = devm_kzalloc(&pdev->dev,
+ sizeof(struct tegra_max98090), GFP_KERNEL);
+ if (!machine) {
+ dev_err(&pdev->dev, "Can't allocate tegra_max98090\n");
+ return -ENOMEM;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, machine);
+
+ machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+ if (machine->gpio_hp_det == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+ goto err;
+
+ tegra_max98090_dai.codec_of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_max98090_dai.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_max98090_dai.cpu_of_node = of_parse_phandle(np,
+ "nvidia,i2s-controller", 0);
+ if (!tegra_max98090_dai.cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_max98090_dai.platform_of_node = tegra_max98090_dai.cpu_of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_fini_utils;
+ }
+
+ return 0;
+
+err_fini_utils:
+ tegra_asoc_utils_fini(&machine->util_data);
+err:
+ return ret;
+}
+
+static int tegra_max98090_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
+ &tegra_max98090_hp_jack_gpio);
+
+ snd_soc_unregister_card(card);
+
+ tegra_asoc_utils_fini(&machine->util_data);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_max98090_of_match[] = {
+ { .compatible = "nvidia,tegra-audio-max98090", },
+ {},
+};
+
+static struct platform_driver tegra_max98090_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = tegra_max98090_of_match,
+ },
+ .probe = tegra_max98090_probe,
+ .remove = tegra_max98090_remove,
+};
+module_platform_driver(tegra_max98090_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_max98090_of_match);
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 7b2d23ba69b3..93caed500565 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -42,9 +42,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 2,
- .channels_max = 2,
.period_bytes_min = 1024,
.period_bytes_max = PAGE_SIZE,
.periods_min = 2,
@@ -61,12 +58,23 @@ static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
int tegra_pcm_platform_register(struct device *dev)
{
- return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_NO_DT |
- SND_DMAENGINE_PCM_FLAG_COMPAT);
+ return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, 0);
}
EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
+int tegra_pcm_platform_register_with_chan_names(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ char *txdmachan, char *rxdmachan)
+{
+ *config = tegra_dmaengine_pcm_config;
+ config->dma_dev = dev->parent;
+ config->chan_names[0] = txdmachan;
+ config->chan_names[1] = rxdmachan;
+
+ return snd_dmaengine_pcm_register(dev, config, 0);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register_with_chan_names);
+
void tegra_pcm_platform_unregister(struct device *dev)
{
return snd_dmaengine_pcm_unregister(dev);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 68ad901714a9..7883dec748a3 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -31,7 +31,12 @@
#ifndef __TEGRA_PCM_H__
#define __TEGRA_PCM_H__
+struct snd_dmaengine_pcm_config;
+
int tegra_pcm_platform_register(struct device *dev);
+int tegra_pcm_platform_register_with_chan_names(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ char *txdmachan, char *rxdmachan);
void tegra_pcm_platform_unregister(struct device *dev);
#endif
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 5e119630b0e0..45b57892b6a5 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -55,7 +55,6 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link tegra_wm9712_dai = {
.name = "AC97 HiFi",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "tegra20-ac97",
.codec_dai_name = "wm9712-hifi",
.codec_name = "wm9712-codec",
.init = tegra_wm9712_init,