diff options
author | Manoj Gangwal <mgangwal@nvidia.com> | 2013-09-03 12:33:50 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:45:26 -0700 |
commit | d446741dfa2703c571fb7de070b6cf4cb23c83d3 (patch) | |
tree | 1207e75b5283dba790b5399dd48641c0bc016083 /sound | |
parent | dc6ec03b4a15fe1f29eba6798b6ffae1e88ac2d0 (diff) |
asoc: tegra: Add support for K3.10 audio
1) Add support for K3.10 audio
2) Register dai as a component
Bug 1310452
Change-Id: I4c09f6b84632ab4adc0748fca807254dba3d19c5
Signed-off-by: Manoj Gangwal <mgangwal@nvidia.com>
Reviewed-on: http://git-master/r/269377
Reviewed-by: Eric Miao <emiao@nvidia.com>
Tested-by: Eric Miao <emiao@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra30_ahub.c | 267 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_ahub.h | 7 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_dam.c | 697 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_dam.h | 15 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.c | 793 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_i2s.h | 35 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_spdif.c | 22 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_asoc_utils.c | 94 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_asoc_utils.h | 10 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 51 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm.h | 12 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5639.c | 12 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5640.c | 26 |
13 files changed, 1124 insertions, 917 deletions
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index b8c5e695b3be..d57280e23318 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -102,6 +102,19 @@ void tegra30_ahub_clock_set_rate(int rate) { clk_set_rate(ahub->clk_d_audio, rate); } +EXPORT_SYMBOL_GPL(tegra30_ahub_clock_set_rate); + +void tegra30_ahub_enable_clocks(void) +{ + pm_runtime_get_sync(ahub->dev); +} +EXPORT_SYMBOL_GPL(tegra30_ahub_enable_clocks); + +void tegra30_ahub_disable_clocks(void) +{ + pm_runtime_put(ahub->dev); +} +EXPORT_SYMBOL_GPL(tegra30_ahub_disable_clocks); static int tegra30_ahub_soft_reset_rx_channel(int channel) { @@ -149,8 +162,11 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK); - val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT); + val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); + val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; tegra30_apbif_write(reg, val); reg = TEGRA30_AHUB_CIF_RX_CTRL + @@ -158,6 +174,8 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; tegra30_apbif_write(reg, val); @@ -174,6 +192,7 @@ int tegra30_ahub_rx_fifo_is_enabled(int i2s_id) val &= mask; return val; } +EXPORT_SYMBOL_GPL(tegra30_ahub_rx_fifo_is_enabled); int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) { @@ -185,6 +204,7 @@ int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) return val; } +EXPORT_SYMBOL_GPL(tegra30_ahub_tx_fifo_is_enabled); int tegra30_ahub_rx_fifo_is_empty(int i2s_id) @@ -220,6 +240,7 @@ int tegra30_ahub_dam_ch0_is_enabled(int dam_id) return val; } +EXPORT_SYMBOL_GPL(tegra30_ahub_dam_ch0_is_enabled); int tegra30_ahub_dam_ch1_is_enabled(int dam_id) { @@ -232,6 +253,7 @@ int tegra30_ahub_dam_ch1_is_enabled(int dam_id) return val; } +EXPORT_SYMBOL_GPL(tegra30_ahub_dam_ch1_is_enabled); int tegra30_ahub_dam_tx_is_enabled(int dam_id) { @@ -244,6 +266,7 @@ int tegra30_ahub_dam_tx_is_enabled(int dam_id) return val; } +EXPORT_SYMBOL_GPL(tegra30_ahub_dam_tx_is_enabled); int tegra30_ahub_dam_ch0_is_empty(int dam_id) @@ -304,6 +327,7 @@ int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, return 0; } +EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_fifo_pack_mode); int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, unsigned int pack_mode) @@ -326,6 +350,7 @@ int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, return 0; } +EXPORT_SYMBOL_GPL(tegra30_ahub_set_tx_fifo_pack_mode); int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) { @@ -391,8 +416,11 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK); - val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT); + val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); + val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; tegra30_apbif_write(reg, val); reg = TEGRA30_AHUB_CIF_TX_CTRL + @@ -400,6 +428,8 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; tegra30_apbif_write(reg, val); @@ -474,6 +504,107 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); +int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_ch, + unsigned int client_ch) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); + val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); + tegra30_apbif_write(reg, val); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_channels); + +int tegra30_ahub_set_rx_cif_stereo_conv(enum tegra30_ahub_rxcif rxcif) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK; + val |= TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG; + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, + unsigned int audio_ch, + unsigned int client_ch) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + unsigned int reg, val; + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); + val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); + + tegra30_apbif_write(reg, val); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_set_tx_cif_channels); + +int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + tegra30_apbif_write(reg, val); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_bits); + +int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + unsigned int reg, val; + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + tegra30_apbif_write(reg, val); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_set_tx_cif_bits); + static const char * const configlink_clocks[] = { "i2s0", "i2s1", @@ -483,7 +614,10 @@ static const char * const configlink_clocks[] = { "dam0", "dam1", "dam2", +/*No SPDIF in 14x*/ +#ifndef CONFIG_ARCH_TEGRA_14x_SOC "spdif_in", +#endif }; struct of_dev_auxdata ahub_auxdata[] = { @@ -625,104 +759,6 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, - unsigned int audio_ch, - unsigned int client_ch) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - unsigned int reg, val; - - reg = TEGRA30_AHUB_CIF_RX_CTRL + - (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); - val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); - tegra30_apbif_write(reg, val); - - return 0; -} - -int tegra30_ahub_set_rx_cif_stereo_conv(enum tegra30_ahub_rxcif rxcif) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - unsigned int reg, val; - - tegra30_ahub_enable_clocks(); - - reg = TEGRA30_AHUB_CIF_RX_CTRL + - (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK; - val |= TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG; - tegra30_apbif_write(reg, val); - - tegra30_ahub_disable_clocks(); - - return 0; -} - -int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, - unsigned int audio_ch, - unsigned int client_ch) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - unsigned int reg, val; - - reg = TEGRA30_AHUB_CIF_TX_CTRL + - (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); - val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); - - tegra30_apbif_write(reg, val); - - return 0; -} - -int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, - unsigned int audio_bits, - unsigned int client_bits) -{ - int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; - unsigned int reg, val; - - reg = TEGRA30_AHUB_CIF_RX_CTRL + - (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); - val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - tegra30_apbif_write(reg, val); - - return 0; -} - -int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, - unsigned int audio_bits, - unsigned int client_bits) -{ - int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; - unsigned int reg, val; - - reg = TEGRA30_AHUB_CIF_TX_CTRL + - (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); - val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - - tegra30_apbif_write(reg, val); - - return 0; -} - - static int tegra30_ahub_probe(struct platform_device *pdev) { struct clk *clk; @@ -730,8 +766,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev) struct resource *res0, *res1, *region; u32 of_dma[2]; void __iomem *regs_apbif, *regs_ahub; - int ret = 0; int clkm_rate; + int ret = 0; if (ahub) return -ENODEV; @@ -784,15 +820,19 @@ 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; + if (!(pdev->dev.of_node)) + ahub->dma_sel = 1; + else { + 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]; } - ahub->dma_sel = of_dma[1]; res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res0) { @@ -866,8 +906,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev) goto err_pm_disable; } - of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata, - &pdev->dev); + if (pdev->dev.of_node) + of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata, + &pdev->dev); return 0; diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index c28faf64ae86..142d5b0def91 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -234,7 +234,7 @@ defined(CONFIG_ARCH_TEGRA_14x_SOC)) #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT 16 #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US 0xfff #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT) -#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT 4 +#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT 5 #define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US 0xfff #define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT) #define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN (1 << 2) @@ -245,7 +245,7 @@ defined(CONFIG_ARCH_TEGRA_14x_SOC)) #define TEGRA30_AHUB_MISC_CTRL 0x84 #define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE (1 << 31) -#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN (1 << 8) +#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN (1 << 9) #define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT 0 #define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK (0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT) @@ -524,6 +524,8 @@ enum tegra30_ahub_rxcif { TEGRA30_AHUB_AUDIO_RX_COUNT, }; +extern void tegra30_ahub_enable_clocks(void); +extern void tegra30_ahub_disable_clocks(void); extern void tegra30_ahub_clock_set_rate(int rate); extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, @@ -587,6 +589,7 @@ struct tegra30_ahub { struct regmap *regmap_ahub; DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); + struct dentry *debug; }; #endif diff --git a/sound/soc/tegra/tegra30_dam.c b/sound/soc/tegra/tegra30_dam.c index 31becc5ac1fe..724283bab305 100644 --- a/sound/soc/tegra/tegra30_dam.c +++ b/sound/soc/tegra/tegra30_dam.c @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/pm_runtime.h> #include <sound/soc.h> #include "tegra30_dam.h" #include "tegra30_ahub.h" @@ -39,6 +40,10 @@ static struct tegra30_dam_context *dams_cont_info[TEGRA30_NR_DAM_IFC]; +/* +Static Tables used by DAM driver +*/ + enum { dam_ch_in0 = 0x0, dam_ch_in1, @@ -47,7 +52,7 @@ enum { } tegra30_dam_chtype; #ifdef CONFIG_ARCH_TEGRA_3x_SOC -struct tegra30_dam_src_step_table step_table[] = { +static struct tegra30_dam_src_step_table step_table[] = { { 8000, 44100, 80 }, { 8000, 48000, 1 }, { 16000, 44100, 160 }, @@ -57,10 +62,8 @@ struct tegra30_dam_src_step_table step_table[] = { { 44100, 16000, 441 }, { 48000, 16000, 0 }, }; -#endif - -#ifndef CONFIG_ARCH_TEGRA_3x_SOC -int coefRam16To44[64] = { +#else +static int coefRam16To44[64] = { 0x156105, // IIR Filter + interpolation 0x0000d649, 0x00e87afb, 0xff5f69d0, 0x003df3cf, @@ -96,7 +99,7 @@ int coefRam16To44[64] = { 0,0,0,0,0,0 }; -int coefRam8To48[64] = { +static int coefRam8To48[64] = { 0x156105, // interpolation + FIlter 0x0000d649, 0x00e87afb, 0xff5f69d0, 0x003df3cf, @@ -120,7 +123,7 @@ int coefRam8To48[64] = { 0 }; -int coefRam16To48[64] = { +static int coefRam16To48[64] = { 0x00a105, // interpolation + Filter 1924, 13390190,-13855175,5952947, @@ -146,7 +149,7 @@ int coefRam16To48[64] = { 0,0 }; -int coefRam44To16[64] = { +static int coefRam44To16[64] = { 0x126104, // IIR Filter + interp0lation 2802, 5762750,-14772125,6628868, @@ -180,7 +183,7 @@ int coefRam44To16[64] = { 0,0,0,0 }; -int coefRam44To8[64] = { +static int coefRam44To8[64] = { 0x120104, // IIR Filter 2802, 5762750,-14772125,6628868, @@ -214,7 +217,7 @@ int coefRam44To8[64] = { 0,0 }; -int coefRam48To16[64] = { +static int coefRam48To16[64] = { 0x009105, // IIR FIlter + Decimation 1924, 13390190,-13855175,5952947, @@ -232,7 +235,7 @@ int coefRam48To16[64] = { 0,0,0,0,0,0,0,0 }; -int coefRam48To8[64] = { +static int coefRam48To8[64] = { 0x0c9102, //IIR Filter + decimation 0x00000e00, 0x00e2e000,0xff6e1a00,0x002aaa00, @@ -256,7 +259,7 @@ int coefRam48To8[64] = { 0 }; -int coefRam8To44[64] = { +static int coefRam8To44[64] = { 0x0156105, // IIR filter +interpllation 0x0000d649, 0x00e87afb, 0xff5f69d0, 0x003df3cf, @@ -289,7 +292,7 @@ int coefRam8To44[64] = { 0,0,0,0,0,0 }; -int coefRam8To16[64] = { +static int coefRam8To16[64] = { 0x00006105, // interpolation + IIR Filter 0x0000d649, // input gain 0x00e87afb, 0xff5f69d0, 0x003df3cf, @@ -301,7 +304,7 @@ int coefRam8To16[64] = { 0x00000002, // ouptut gain }; -int coefRam16To8[64] = { +static int coefRam16To8[64] = { 0x00005105, //IIR Filter + Decimator 0x0000d649, //input gain 0x00e87afb, 0xff5f69d0, 0x003df3cf, @@ -314,86 +317,111 @@ int coefRam16To8[64] = { }; #endif -static void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, - int fsout); -static void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, - int fsin); -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -static int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, - int insample, int outsample); -static void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step); -#endif +/* +Internally used helper (static) function prototypes +*/ static inline void tegra30_dam_writel(struct tegra30_dam_context *dam, - u32 val, u32 reg) -{ -#ifdef CONFIG_PM - dam->reg_cache[reg >> 2] = val; + u32 val, u32 reg); +static inline u32 tegra30_dam_readl(struct tegra30_dam_context *dam, + u32 reg); +static void tegra30_dam_set_output_samplerate( + struct tegra30_dam_context *dam, int fsout); +static void tegra30_dam_set_input_samplerate( + struct tegra30_dam_context *dam, int fsin); +static int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, + int insample, int outsample); +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, + int step); +#else +static void tegra30_dam_write_coeff_ram(struct tegra30_dam_context *dam, + int fsin, int fsout); +static void tegra30_dam_set_farrow_param( + struct tegra30_dam_context *dam, int fsin, int fsout); +static void tegra30_dam_set_biquad_fixed_coef( + struct tegra30_dam_context *dam); +static void tegra30_dam_enable_coeff_ram( + struct tegra30_dam_context *dam); +static void tegra30_dam_set_filter_stages( + struct tegra30_dam_context *dam, int fsin, int fsout); #endif - __raw_writel(val, dam->damregs + reg); -} -static inline u32 tegra30_dam_readl(struct tegra30_dam_context *dam, u32 reg) -{ - u32 val = __raw_readl(dam->damregs + reg); - return val; -} +/* +Regmap and Runtime PM callback function +*/ -#ifdef CONFIG_PM -int tegra30_dam_resume(int ifc) +static bool tegra30_dam_wr_rd_reg(struct device *dev, unsigned int reg) { - int i = 0; - struct tegra30_dam_context *dam; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return -EINVAL; - - dam = dams_cont_info[ifc]; - - if (dam->in_use) { - tegra30_dam_enable_clock(ifc); - - for (i = 0; i <= TEGRA30_DAM_CTRL_REGINDEX; i++) { - if ((i == TEGRA30_DAM_CTRL_RSVD_6) || - (i == TEGRA30_DAM_CTRL_RSVD_10)) - continue; - - tegra30_dam_writel(dam, dam->reg_cache[i], - (i << 2)); - } - - tegra30_dam_disable_clock(ifc); - } - - return 0; + switch (reg) { + case TEGRA30_DAM_CTRL: + case TEGRA30_DAM_CLIP: + case TEGRA30_DAM_CLIP_THRESHOLD: + case TEGRA30_DAM_AUDIOCIF_OUT_CTRL: + case TEGRA30_DAM_CH0_CTRL: + case TEGRA30_DAM_CH0_CONV: + case TEGRA30_DAM_AUDIOCIF_CH0_CTRL: + case TEGRA30_DAM_CH1_CTRL: + case TEGRA30_DAM_CH1_CONV: + case TEGRA30_DAM_AUDIOCIF_CH1_CTRL: +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + case TEGRA30_DAM_CH0_BIQUAD_FIXED_COEF_0: + case TEGRA30_DAM_FARROW_PARAM_0: + case TEGRA30_DAM_AUDIORAMCTL_DAM_CTRL_0: + case TEGRA30_DAM_AUDIORAMCTL_DAM_DATA_0: +#endif + return true; + default: + return false; + }; } + +static const struct regmap_config tegra30_dam_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + .max_register = TEGRA30_DAM_AUDIORAMCTL_DAM_DATA_0, +#else + .max_register = TEGRA30_DAM_AUDIOCIF_CH1_CTRL, #endif + .writeable_reg = tegra30_dam_wr_rd_reg, + .readable_reg = tegra30_dam_wr_rd_reg, + .cache_type = REGCACHE_RBTREE, +}; -void tegra30_dam_disable_clock(int ifc) +static int tegra30_dam_runtime_suspend(struct device *dev) { - struct tegra30_dam_context *dam; + struct tegra30_dam_context *dam = dev_get_drvdata(dev); - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; + tegra30_ahub_disable_clocks(); + regcache_cache_only(dam->regmap, true); + clk_disable_unprepare(dam->dam_clk); - dam = dams_cont_info[ifc]; - clk_disable(dam->dam_clk); + return 0; } -int tegra30_dam_enable_clock(int ifc) +static int tegra30_dam_runtime_resume(struct device *dev) { - struct tegra30_dam_context *dam; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return -EINVAL; + struct tegra30_dam_context *dam = dev_get_drvdata(dev); + int ret; - dam = dams_cont_info[ifc]; - clk_enable(dam->dam_clk); + tegra30_ahub_enable_clocks(); + ret = clk_prepare_enable(dam->dam_clk); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + regcache_cache_only(dam->regmap, false); return 0; } +/* +DebugFs callback functions +*/ + #ifdef CONFIG_DEBUG_FS static int tegra30_dam_show(struct seq_file *s, void *unused) { @@ -469,110 +497,24 @@ static inline void tegra30_dam_debug_remove(struct tegra30_dam_context *dam) } #endif -int tegra30_dam_allocate_controller() -{ - int i = 0; - struct tegra30_dam_context *dam = NULL; - - for (i = 0; i < TEGRA30_NR_DAM_IFC; i++) { - - dam = dams_cont_info[i]; - - if (!dam->in_use) { - dam->in_use = true; - return i; - } - } - - return -ENOENT; -} - -int tegra30_dam_allocate_channel(int ifc, int chid) -{ - struct tegra30_dam_context *dam = NULL; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC) || - (chid < dam_ch_in0) || (chid > dam_ch_in1)) - return -EINVAL; - - dam = dams_cont_info[ifc]; - - if (!dam->ch_alloc[chid]) { - dam->ch_alloc[chid] = true; - return 0; - } - - return -ENOENT; -} - -int tegra30_dam_free_channel(int ifc, int chid) -{ - struct tegra30_dam_context *dam = NULL; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC) || - (chid < dam_ch_in0) || (chid > dam_ch_in1)) - return -EINVAL; - - dam = dams_cont_info[ifc]; - - if (dam->ch_alloc[chid]) { - dam->ch_alloc[chid] = false; - return 0; - } - - return -EINVAL; -} - -int tegra30_dam_free_controller(int ifc) +/* +Internally used helper (static) functions +*/ +static inline void tegra30_dam_writel(struct tegra30_dam_context *dam, + u32 val, u32 reg) { - struct tegra30_dam_context *dam = NULL; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return -EINVAL; - - dam = dams_cont_info[ifc]; - - if (!dam->ch_alloc[dam_ch_in0] && - !dam->ch_alloc[dam_ch_in1]) { - dam->in_use = false; - return 0; - } - - return -EINVAL; + regmap_write(dam->regmap, reg, val); } -void tegra30_dam_set_samplerate(int ifc, int chid, int samplerate) +static inline u32 tegra30_dam_readl(struct tegra30_dam_context *dam, u32 reg) { - struct tegra30_dam_context *dam; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - - dam = dams_cont_info[ifc]; + u32 val; - switch (chid) { - case dam_ch_in0: - tegra30_dam_set_input_samplerate(dam, samplerate); - dam->ch_insamplerate[dam_ch_in0] = samplerate; -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - tegra30_dam_set_step_reset(dam, samplerate, dam->outsamplerate); -#endif - break; - case dam_ch_in1: - if (samplerate != dam->outsamplerate) - return; - dam->ch_insamplerate[dam_ch_in1] = samplerate; - break; - case dam_ch_out: - tegra30_dam_set_output_samplerate(dam, samplerate); - dam->outsamplerate = samplerate; - break; - default: - break; - } + regmap_read(dam->regmap, reg, &val); + return val; } -void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, +static void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, int fsout) { u32 val; @@ -600,7 +542,8 @@ void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL); } -void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, int fsin) +static void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, + int fsin) { u32 val; @@ -627,10 +570,10 @@ void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, int fsin) tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); } -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, +static int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, int insample, int outsample) { +#ifdef CONFIG_ARCH_TEGRA_3x_SOC int step_reset = 0; int i = 0; @@ -641,11 +584,19 @@ int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, } tegra30_dam_ch0_set_step(dam, step_reset); +#else + tegra30_dam_write_coeff_ram(dam, insample, outsample); + tegra30_dam_set_farrow_param(dam, insample, outsample); + tegra30_dam_set_biquad_fixed_coef(dam); + tegra30_dam_enable_coeff_ram(dam); + tegra30_dam_set_filter_stages(dam, insample, outsample); +#endif return 0; } -void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step) +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step) { u32 val; @@ -654,95 +605,13 @@ void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step) val |= step << TEGRA30_DAM_CH0_CTRL_STEP_SHIFT; tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); } -#endif - -int tegra30_dam_set_gain(int ifc, int chid, int gain) -{ - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return -EINVAL; - - switch (chid) { - case dam_ch_in0: - tegra30_dam_writel(dams_cont_info[ifc], gain, - TEGRA30_DAM_CH0_CONV); - break; - case dam_ch_in1: - tegra30_dam_writel(dams_cont_info[ifc], gain, - TEGRA30_DAM_CH1_CONV); - break; - default: - break; - } - - return 0; -} - -int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels, - unsigned int audio_bits, unsigned int client_channels, - unsigned int client_bits) -{ - unsigned int reg; - unsigned int value = 0; - - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return -EINVAL; - -#ifndef CONFIG_ARCH_TEGRA_3x_SOC - /*ch0 takes input as mono always*/ - if ((chid == dam_ch_in0) && - ((client_channels != 1))) - return -EINVAL; - /*as per dam spec file chout is fixed to 32 bits*/ - /*so accept ch0, ch1 and chout as 32bit always*/ - if (client_bits != 32) - return -EINVAL; #else - /*ch0 takes input as mono/16bit always*/ - if ((chid == dam_ch_in0) && - ((client_channels != 1) || (client_bits != 16))) - return -EINVAL; -#endif - - value |= TEGRA30_CIF_MONOCONV_COPY; - value |= TEGRA30_CIF_STEREOCONV_CH0; - value |= (audio_channels-1) << TEGRA30_AUDIO_CHANNELS_SHIFT; - value |= (((audio_bits>>2)-1)<<TEGRA30_AUDIO_BITS_SHIFT); - value |= (client_channels-1) << TEGRA30_CLIENT_CHANNELS_SHIFT; - value |= (((client_bits>>2)-1)<<TEGRA30_CLIENT_BITS_SHIFT); - - switch (chid) { - case dam_ch_out: - value |= TEGRA30_CIF_DIRECTION_TX; - reg = TEGRA30_DAM_AUDIOCIF_OUT_CTRL; - break; - case dam_ch_in0: - value |= TEGRA30_CIF_DIRECTION_RX; - reg = TEGRA30_DAM_AUDIOCIF_CH0_CTRL; - break; - case dam_ch_in1: - value |= TEGRA30_CIF_DIRECTION_RX; - reg = TEGRA30_DAM_AUDIOCIF_CH1_CTRL; - break; - default: - return -EINVAL; - } - - tegra30_dam_writel(dams_cont_info[ifc], value, reg); - - return 0; -} - -#ifndef CONFIG_ARCH_TEGRA_3x_SOC -void tegra30_dam_write_coeff_ram(int ifc, int fsin, int fsout) +static void tegra30_dam_write_coeff_ram(struct tegra30_dam_context *dam, int fsin, int fsout) { u32 val; int i, *coefRam = NULL; - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - - tegra30_dam_writel(dams_cont_info[ifc], 0x00002000, + tegra30_dam_writel(dam, 0x00002000, TEGRA30_DAM_AUDIORAMCTL_DAM_CTRL_0); switch(fsin) { @@ -782,23 +651,20 @@ void tegra30_dam_write_coeff_ram(int ifc, int fsin, int fsout) break; } - tegra30_dam_writel(dams_cont_info[ifc], 0x00005000, + tegra30_dam_writel(dam, 0x00005000, TEGRA30_DAM_AUDIORAMCTL_DAM_CTRL_0); for (i = 0; i < 64; i++) { - val = coefRam[i];
- tegra30_dam_writel(dams_cont_info[ifc], val, + val = coefRam[i]; + tegra30_dam_writel(dam, val, TEGRA30_DAM_AUDIORAMCTL_DAM_DATA_0); } } -void tegra30_dam_set_farrow_param(int ifc, int fsin, int fsout) +static void tegra30_dam_set_farrow_param(struct tegra30_dam_context *dam, int fsin, int fsout) { u32 val = TEGRA30_FARROW_PARAM_RESET; - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - switch(fsin) { case TEGRA30_AUDIO_SAMPLERATE_8000: if (fsout == TEGRA30_AUDIO_SAMPLERATE_48000) @@ -836,43 +702,34 @@ void tegra30_dam_set_farrow_param(int ifc, int fsin, int fsout) break; } - tegra30_dam_writel(dams_cont_info[ifc], val, + tegra30_dam_writel(dam, val, TEGRA30_DAM_FARROW_PARAM_0); } -void tegra30_dam_set_biquad_fixed_coef(int ifc) +static void tegra30_dam_set_biquad_fixed_coef(struct tegra30_dam_context *dam) { u32 val = TEGRA30_DAM_CH0_BIQUAD_FIXED_COEF_0_VAL; - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - - tegra30_dam_writel(dams_cont_info[ifc], val, + tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_BIQUAD_FIXED_COEF_0); } -void tegra30_dam_enable_coeff_ram(int ifc) +static void tegra30_dam_enable_coeff_ram(struct tegra30_dam_context *dam) { u32 val; - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - - val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CH0_CTRL); + val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL); val |= TEGRA30_DAM_CH0_CTRL_COEFF_RAM_ENABLE; - tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CH0_CTRL); + tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); } -void tegra30_dam_set_filter_stages(int ifc, int fsin, int fsout) +static void tegra30_dam_set_filter_stages(struct tegra30_dam_context *dam, int fsin, int fsout) { u32 val; int filt_stages = 0; - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) - return; - - val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CH0_CTRL); + val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL); switch(fsin) { case TEGRA30_AUDIO_SAMPLERATE_8000: @@ -913,23 +770,211 @@ void tegra30_dam_set_filter_stages(int ifc, int fsin, int fsout) val |= filt_stages << TEGRA30_DAM_CH0_CTRL_FILT_STAGES_SHIFT; - tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CH0_CTRL); + tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); } +#endif -void tegra30_dam_enable_stereo_mixing(int ifc) +/* +DAM Driver API's +*/ + +int tegra30_dam_allocate_controller() { - u32 val; + int i = 0; + struct tegra30_dam_context *dam = NULL; + + for (i = 0; i < TEGRA30_NR_DAM_IFC; i++) { + + dam = dams_cont_info[i]; + + if (!dam->in_use) { + dam->in_use = true; + return i; + } + } + + return -ENOENT; +} + +void tegra30_dam_disable_clock(int ifc) +{ + struct tegra30_dam_context *dam; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return; + + dam = dams_cont_info[ifc]; + pm_runtime_put(dam->dev); +} + +int tegra30_dam_enable_clock(int ifc) +{ + struct tegra30_dam_context *dam; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + + dam = dams_cont_info[ifc]; + pm_runtime_get_sync(dam->dev); - if ((ifc < 0) || (ifc >= TEGRA30_NR_DAM_IFC)) + return 0; +} + +int tegra30_dam_allocate_channel(int ifc, int chid) +{ + struct tegra30_dam_context *dam = NULL; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + + dam = dams_cont_info[ifc]; + + if (!dam->ch_alloc[chid]) { + dam->ch_alloc[chid] = true; + return 0; + } + + return -ENOENT; +} + +int tegra30_dam_free_channel(int ifc, int chid) +{ + struct tegra30_dam_context *dam = NULL; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + + dam = dams_cont_info[ifc]; + + if (dam->ch_alloc[chid]) { + dam->ch_alloc[chid] = false; + return 0; + } + + return -EINVAL; +} + +int tegra30_dam_free_controller(int ifc) +{ + struct tegra30_dam_context *dam = NULL; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + + dam = dams_cont_info[ifc]; + + if (!dam->ch_alloc[dam_ch_in0] && + !dam->ch_alloc[dam_ch_in1]) { + dam->in_use = false; + return 0; + } + + return -EINVAL; +} + +void tegra30_dam_set_samplerate(int ifc, int chid, int samplerate) +{ + struct tegra30_dam_context *dam = dams_cont_info[ifc]; + + if (ifc >= TEGRA30_NR_DAM_IFC) return; - val = tegra30_dam_readl(dams_cont_info[ifc], TEGRA30_DAM_CTRL); - val |= TEGRA30_DAM_CTRL_STEREO_MIXING_ENABLE; + switch (chid) { + case dam_ch_in0: + tegra30_dam_set_input_samplerate(dam, samplerate); + dam->ch_insamplerate[dam_ch_in0] = samplerate; + tegra30_dam_set_step_reset(dam, samplerate, dam->outsamplerate); + break; + case dam_ch_in1: + if (samplerate != dam->outsamplerate) + return; + dam->ch_insamplerate[dam_ch_in1] = samplerate; + break; + case dam_ch_out: + tegra30_dam_set_output_samplerate(dam, samplerate); + dam->outsamplerate = samplerate; + break; + default: + break; + } +} + +int tegra30_dam_set_gain(int ifc, int chid, int gain) +{ + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + + switch (chid) { + case dam_ch_in0: + tegra30_dam_writel(dams_cont_info[ifc], gain, + TEGRA30_DAM_CH0_CONV); + break; + case dam_ch_in1: + tegra30_dam_writel(dams_cont_info[ifc], gain, + TEGRA30_DAM_CH1_CONV); + break; + default: + break; + } - tegra30_dam_writel(dams_cont_info[ifc], val, TEGRA30_DAM_CTRL); + return 0; } + +int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels, + unsigned int audio_bits, unsigned int client_channels, + unsigned int client_bits) +{ + unsigned int reg; + unsigned int value = 0; + + if (ifc >= TEGRA30_NR_DAM_IFC) + return -EINVAL; + +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + /*ch0 takes input as mono always*/ + if ((chid == dam_ch_in0) && + ((client_channels != 1))) + return -EINVAL; + /*as per dam spec file chout is fixed to 32 bits*/ + /*so accept ch0, ch1 and chout as 32bit always*/ + if (client_bits != 32) + return -EINVAL; +#else + /*ch0 takes input as mono/16bit always*/ + if ((chid == dam_ch_in0) && + ((client_channels != 1) || (client_bits != 16))) + return -EINVAL; #endif + value |= TEGRA30_CIF_MONOCONV_COPY; + value |= TEGRA30_CIF_STEREOCONV_CH0; + value |= (audio_channels-1) << TEGRA30_AUDIO_CHANNELS_SHIFT; + value |= (((audio_bits>>2)-1)<<TEGRA30_AUDIO_BITS_SHIFT); + value |= (client_channels-1) << TEGRA30_CLIENT_CHANNELS_SHIFT; + value |= (((client_bits>>2)-1)<<TEGRA30_CLIENT_BITS_SHIFT); + + switch (chid) { + case dam_ch_out: + value |= TEGRA30_CIF_DIRECTION_TX; + reg = TEGRA30_DAM_AUDIOCIF_OUT_CTRL; + break; + case dam_ch_in0: + value |= TEGRA30_CIF_DIRECTION_RX; + reg = TEGRA30_DAM_AUDIOCIF_CH0_CTRL; + break; + case dam_ch_in1: + value |= TEGRA30_CIF_DIRECTION_RX; + reg = TEGRA30_DAM_AUDIOCIF_CH1_CTRL; + break; + default: + return -EINVAL; + } + + tegra30_dam_writel(dams_cont_info[ifc], value, reg); + + return 0; +} + void tegra30_dam_enable(int ifc, int on, int chid) { u32 old_val, val, enreg; @@ -1069,14 +1114,16 @@ int tegra30_dam_set_acif_stereo_conv(int ifc, int chtype, int conv) return 0; } + +/* +DAM Driver probe and remove functions +*/ + static int tegra30_dam_probe(struct platform_device *pdev) { struct resource *res, *region; struct tegra30_dam_context *dam; int ret = 0; -#ifdef CONFIG_PM - int i; -#endif int clkm_rate; u32 val32; @@ -1100,7 +1147,10 @@ static int tegra30_dam_probe(struct platform_device *pdev) ret = -ENOMEM; goto exit; } + dams_cont_info[pdev->id]->dev = &pdev->dev; + dam = dams_cont_info[pdev->id]; + dev_set_drvdata(&pdev->dev, dam); dam->dam_clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dam->dam_clk)) { @@ -1136,28 +1186,28 @@ static int tegra30_dam_probe(struct platform_device *pdev) goto err_clk_put_dam; } -#ifdef CONFIG_PM - /* cache the POR values of DAM regs*/ - tegra30_dam_enable_clock(pdev->id); - - for (i = 0; i <= TEGRA30_DAM_CTRL_REGINDEX; i++) { - if ((i == TEGRA30_DAM_CTRL_RSVD_6) || - (i == TEGRA30_DAM_CTRL_RSVD_10)) - continue; - - dam->reg_cache[i] = - tegra30_dam_readl(dam, i << 2); + dam->regmap = devm_regmap_init_mmio(&pdev->dev, dam->damregs, + &tegra30_dam_regmap_config); + if (IS_ERR(dam->regmap)) { + dev_err(&pdev->dev, "regmap init failed\n"); + ret = PTR_ERR(dam->regmap); + goto err_clk_put_dam; } + regcache_cache_only(dam->regmap, true); - tegra30_dam_disable_clock(pdev->id); -#endif - - platform_set_drvdata(pdev, dam); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = tegra30_dam_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } tegra30_dam_debug_add(dam, pdev->id); return 0; +err_pm_disable: + pm_runtime_disable(&pdev->dev); err_clk_put_dam: clk_put(dam->dam_clk); err_free: @@ -1170,6 +1220,10 @@ static int tegra30_dam_remove(struct platform_device *pdev) { struct tegra30_dam_context *dam; + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra30_dam_runtime_suspend(&pdev->dev); + dam = platform_get_drvdata(pdev); clk_put(dam->dam_clk); tegra30_dam_debug_remove(dam); @@ -1178,26 +1232,27 @@ static int tegra30_dam_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tegra30_dam_of_match[] = { + { .compatible = "nvidia,tegra30-dam",}, + {}, +}; + +static const struct dev_pm_ops tegra30_dam_pm_ops = { + SET_RUNTIME_PM_OPS(tegra30_dam_runtime_suspend, + tegra30_dam_runtime_resume, NULL) +}; + static struct platform_driver tegra30_dam_driver = { - .probe = tegra30_dam_probe, - .remove = tegra30_dam_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = tegra30_dam_of_match, + .pm = &tegra30_dam_pm_ops, }, + .probe = tegra30_dam_probe, + .remove = tegra30_dam_remove, }; - -static int __init tegra30_dam_modinit(void) -{ - return platform_driver_register(&tegra30_dam_driver); -} -module_init(tegra30_dam_modinit); - -static void __exit tegra30_dam_modexit(void) -{ - platform_driver_unregister(&tegra30_dam_driver); -} -module_exit(tegra30_dam_modexit); +module_platform_driver(tegra30_dam_driver); MODULE_AUTHOR("Nikesh Oswal <noswal@nvidia.com>"); MODULE_DESCRIPTION("Tegra 30 DAM driver"); diff --git a/sound/soc/tegra/tegra30_dam.h b/sound/soc/tegra/tegra30_dam.h index 0e9733c413c7..d23bd60f10c3 100644 --- a/sound/soc/tegra/tegra30_dam.h +++ b/sound/soc/tegra/tegra30_dam.h @@ -2,7 +2,7 @@ * tegra30_dam.h - Tegra 30 DAM driver. * * Author: Nikesh Oswal <noswal@nvidia.com> - * Copyright (C) 2011 - NVIDIA, Inc. + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -155,17 +155,16 @@ #define TEGRA30_DAM_DISABLE 0 struct tegra30_dam_context { + struct device *dev; int outsamplerate; bool ch_alloc[TEGRA30_DAM_NUM_INPUT_CHANNELS]; int ch_enable_refcnt[TEGRA30_DAM_NUM_INPUT_CHANNELS]; int ch_insamplerate[TEGRA30_DAM_NUM_INPUT_CHANNELS]; -#ifdef CONFIG_PM - int reg_cache[TEGRA30_DAM_CTRL_REGINDEX + 1]; -#endif struct clk *dam_clk; bool in_use; void __iomem *damregs; struct dentry *debug; + struct regmap *regmap; }; struct tegra30_dam_src_step_table { @@ -174,9 +173,6 @@ struct tegra30_dam_src_step_table { int stepreset; }; -#ifdef CONFIG_PM -int tegra30_dam_resume(int ifc); -#endif void tegra30_dam_disable_clock(int ifc); int tegra30_dam_enable_clock(int ifc); int tegra30_dam_allocate_controller(void); @@ -193,11 +189,6 @@ int tegra30_dam_set_acif_stereo_conv(int ifc, int chtype, int conv); void tegra30_dam_ch0_set_datasync(int ifc, int datasync); void tegra30_dam_ch1_set_datasync(int ifc, int datasync); #ifndef CONFIG_ARCH_TEGRA_3x_SOC -void tegra30_dam_write_coeff_ram(int ifc, int fsin, int fsout); -void tegra30_dam_set_farrow_param(int ifc, int fsin, int fsout); -void tegra30_dam_set_biquad_fixed_coef(int ifc); -void tegra30_dam_enable_coeff_ram(int ifc); -void tegra30_dam_set_filter_stages(int ifc, int fsin, int fsout); void tegra30_dam_enable_stereo_mixing(int ifc); #endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 0e9991e7237e..1a1ea3255a6a 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -2,13 +2,13 @@ * tegra30_i2s.c - Tegra30 I2S driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * * Based on code copyright/by: * - * Copyright (c) 2009-2013, NVIDIA Corporation. - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2009-2013, NVIDIA CORPORATION. All rights reserved. * Scott Peterson <speterson@nvidia.com> + * Manoj Gangwal <mgangwal@nvidia.com> * * Copyright (C) 2010 Google, Inc. * Iliyan Malchev <malchev@google.com> @@ -36,11 +36,12 @@ #include <linux/regmap.h> #include <linux/slab.h> #include <linux/delay.h> -#include <mach/tegra_asoc_pdata.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <asm/delay.h> +#include <mach/tegra_asoc_pdata.h> #include "tegra30_ahub.h" #include "tegra30_dam.h" @@ -48,8 +49,7 @@ #define DRV_NAME "tegra30-i2s" -static struct tegra30_i2s i2scont[TEGRA30_NR_I2S_IFC]; - +static struct tegra30_i2s *i2scont[TEGRA30_NR_I2S_IFC]; #if defined(CONFIG_ARCH_TEGRA_14x_SOC) static struct tegra30_i2s bbc1cont; #endif @@ -58,6 +58,8 @@ static int tegra30_i2s_runtime_suspend(struct device *dev) { struct tegra30_i2s *i2s = dev_get_drvdata(dev); + tegra30_ahub_disable_clocks(); + regcache_cache_only(i2s->regmap, true); clk_disable_unprepare(i2s->clk_i2s); @@ -70,6 +72,8 @@ static int tegra30_i2s_runtime_resume(struct device *dev) struct tegra30_i2s *i2s = dev_get_drvdata(dev); int ret; + tegra30_ahub_enable_clocks(); + ret = clk_prepare_enable(i2s->clk_i2s); if (ret) { dev_err(dev, "clk_enable failed: %d\n", ret); @@ -98,8 +102,9 @@ int tegra30_i2s_startup(struct snd_pcm_substream *substream, i2s->playback_dma_data.width = 32; if (!i2s->is_dam_used) - tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif, - i2s->playback_fifo_cif); + tegra30_ahub_set_rx_cif_source( + i2s->playback_i2s_cif, + i2s->playback_fifo_cif); } else { i2s->capture_ref_count++; ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif, @@ -121,34 +126,65 @@ void tegra30_i2s_shutdown(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (i2s->playback_ref_count == 1) - tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); + tegra30_ahub_unset_rx_cif_source( + i2s->playback_i2s_cif); /* free the apbif dma channel*/ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); - i2s->txcif = -1; + i2s->playback_fifo_cif = -1; /* decrement the playback ref count */ i2s->playback_ref_count--; } else { if (i2s->capture_ref_count == 1) tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif); + + /* free the apbif dma channel*/ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif); + + /* decrement the capture ref count */ i2s->capture_ref_count--; } } +static int tegra30_i2s_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + i2s->i2s_bit_clk = freq; + + return 0; +} + static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int mask, val; + mask = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK | + TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_MASK; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: + val = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_DSP_A) { + val = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE | + TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_ON_HALF_BIT_CLK; + } + break; + case SND_SOC_DAIFMT_IB_NF: + val = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_DSP_A) { + val = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + } break; default: return -EINVAL; } + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL, mask, val); mask = TEGRA30_I2S_CTRL_MASTER_ENABLE; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -156,6 +192,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, val = TEGRA30_I2S_CTRL_MASTER_ENABLE; break; case SND_SOC_DAIFMT_CBM_CFM: + val = 0; break; default: return -EINVAL; @@ -163,41 +200,33 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | TEGRA30_I2S_CTRL_LRCK_MASK; - i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK; i2s->daifmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; switch (i2s->daifmt) { case SND_SOC_DAIFMT_DSP_A: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC | + TEGRA30_I2S_CTRL_LRCK_R_LOW; break; case SND_SOC_DAIFMT_DSP_B: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - val |= TEGRA30_I2S_CTRL_LRCK_R_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC | + TEGRA30_I2S_CTRL_LRCK_R_LOW; break; case SND_SOC_DAIFMT_I2S: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK | + TEGRA30_I2S_CTRL_LRCK_L_LOW; break; case SND_SOC_DAIFMT_RIGHT_J: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK | + TEGRA30_I2S_CTRL_LRCK_R_LOW; break; case SND_SOC_DAIFMT_LEFT_J: - val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK | + TEGRA30_I2S_CTRL_LRCK_R_LOW; break; default: return -EINVAL; } - pm_runtime_get_sync(dai->dev); regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); - pm_runtime_put(dai->dev); return 0; } @@ -206,61 +235,79 @@ static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s, int i2sclock, int srate) { int sym_bitclk, bitcnt; - u32 val; + unsigned int mask, val; bitcnt = (i2sclock / (2 * srate)) - 1; sym_bitclk = !(i2sclock % (2 * srate)); + mask = TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK; val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + mask |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; if (!sym_bitclk) val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; - regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_TIMING, mask, val); } static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s) { - u32 val; + unsigned int mask, val; int rx_data_offset = i2s->dsp_config.rx_data_offset; int tx_data_offset = i2s->dsp_config.tx_data_offset; - val = (rx_data_offset << - TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | - (tx_data_offset << - TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + mask = TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK | + TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK; + val = (rx_data_offset << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | + (tx_data_offset << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); - regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_OFFSET, mask, val); } static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream) { - u32 mask, val = 0; + unsigned int mask, val; int tx_mask = i2s->dsp_config.tx_mask; int rx_mask = i2s->dsp_config.rx_mask; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + mask = TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_MASK; + val = (tx_mask << TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_SHIFT); +#else mask = TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; - val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); + val = (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); +#endif } else { +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + mask = TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_MASK; + val = (rx_mask << TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_SHIFT); +#else mask = TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; - val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); + val = (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); +#endif } - +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL2, mask, val); + mask = TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + val = (i2s->dsp_config.num_slots - 1) << + TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; +#else mask |= TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; - val |= (i2s->dsp_config.num_slots - 1) - << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; - + val |= (i2s->dsp_config.num_slots - 1) << + TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; +#endif regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val); } static int tegra30_i2s_tdm_setup_clocks(struct device *dev, struct tegra30_i2s *i2s, int *i2sclock) { + unsigned int val; int ret; - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { - + regmap_read(i2s->regmap, TEGRA30_I2S_CTRL, &val); + if (val & TEGRA30_I2S_CTRL_MASTER_ENABLE) { ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); if (ret) { dev_err(dev, "Can't set parent of I2S clock\n"); @@ -273,7 +320,6 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev, return ret; } } else { - ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock); if (ret) { dev_err(dev, "Can't set I2S sync clock rate\n"); @@ -281,7 +327,7 @@ static int tegra30_i2s_tdm_setup_clocks(struct device *dev, } ret = clk_set_parent(clk_get_parent(i2s->clk_audio_2x), - i2s->clk_i2s_sync); + i2s->clk_i2s_sync); if (ret) { dev_err(dev, "Can't set parent of audio2x clock\n"); return ret; @@ -309,7 +355,7 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, { struct device *dev = substream->pcm->card->dev; struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 val; + unsigned int mask, val; int i2s_client_ch, i2s_audio_ch; int i2s_audio_bits = 0, i2s_client_bits = 0; int i2sclock, srate; @@ -318,8 +364,8 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, srate = params_rate(params); i2sclock = srate * - i2s->dsp_config.num_slots * - i2s->dsp_config.slot_width; + i2s->dsp_config.num_slots * + i2s->dsp_config.slot_width; ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock); if (ret) @@ -333,37 +379,45 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, i2s_client_ch = i2s->dsp_config.num_slots; i2s_audio_ch = i2s->dsp_config.num_slots; - i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; + mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK; switch (i2s->dsp_config.slot_width) { case 16: i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16; i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; + val = TEGRA30_I2S_CTRL_BIT_SIZE_16; break; case 32: i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32; i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; + val = TEGRA30_I2S_CTRL_BIT_SIZE_32; break; default: dev_err(dev, "unknown slot_width %d\n", i2s->dsp_config.slot_width); return -EINVAL; } + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); + mask = TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK | + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK | + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK; val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | - ((i2s_audio_ch - 1) << - TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | - ((i2s_client_ch - 1) << - TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | - (i2s_audio_bits << - TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | - (i2s_client_bits << - TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + ((i2s_audio_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((i2s_client_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (i2s_audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (i2s_client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CIF_RX_CTRL, + mask, val); tegra30_ahub_set_tx_cif_channels(i2s->playback_fifo_cif, i2s_audio_ch, @@ -375,7 +429,8 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, } else { val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CIF_TX_CTRL, + mask, val); tegra30_ahub_set_rx_cif_channels(i2s->capture_fifo_cif, i2s_audio_ch, @@ -390,10 +445,10 @@ static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, tegra30_i2s_set_data_offset(i2s); - i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; - i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) << + mask = TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; + val = (i2s->dsp_config.slot_width - 1) << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT; - tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL, mask, val); return 0; } @@ -404,14 +459,14 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, { struct device *dev = dai->dev; struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int mask, val, reg, i; + unsigned int mask, val, reg, reg_ctrl, i; int ret, sample_size, srate, i2sclock, bitcnt, sym_bitclk; int i2s_client_ch; mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_8; + val = TEGRA30_I2S_CTRL_BIT_SIZE_8; sample_size = 8; break; case SNDRV_PCM_FORMAT_S16_LE: @@ -419,36 +474,38 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, sample_size = 16; break; case SNDRV_PCM_FORMAT_S24_LE: - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_24; + val = TEGRA30_I2S_CTRL_BIT_SIZE_24; sample_size = 24; break; case SNDRV_PCM_FORMAT_S32_LE: - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; + val = TEGRA30_I2S_CTRL_BIT_SIZE_32; sample_size = 32; break; default: return -EINVAL; } - - regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); - bitcnt = sample_size; i = 0; + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); + regmap_read(i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); /* TDM mode */ - if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && + if ((reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && (i2s->dsp_config.slot_width > 2)) return tegra30_i2s_tdm_hw_params(substream, params, dai); srate = params_rate(params); - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { + if (reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { i2sclock = srate * params_channels(params) * sample_size; /* Additional "* 4" is needed for FSYNC mode */ - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) + if (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) i2sclock *= 4; + if (i2s->i2s_bit_clk != 0) + i2sclock = i2s->i2s_bit_clk; + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); if (ret) { dev_err(dev, "Can't set parent of I2S clock\n"); @@ -461,32 +518,14 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, return ret; } - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) { + if (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) { bitcnt = (i2sclock / srate) - 1; sym_bitclk = !(i2sclock % srate); -#ifndef CONFIG_ARCH_TEGRA_3x_SOC - val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL2); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val &= - ~TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_MASK; - val |= ((1 << params_channels(params)) - 1) << - TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_SHIFT; - } else { - val &= - ~TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_MASK; - val |= ((1 << params_channels(params)) - 1) << - TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_SHIFT; - } - tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL2, val); -#endif } else { bitcnt = (i2sclock / (2 * srate)) - 1; sym_bitclk = !(i2sclock % (2 * srate)); - i2s_client_ch = 2; } val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; - if (!sym_bitclk) val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; @@ -495,7 +534,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, i2sclock = srate * params_channels(params) * sample_size; /* Additional "* 2" is needed for FSYNC mode */ - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) + if (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) i2sclock *= 2; ret = clk_set_rate(i2s->clk_i2s_sync, i2sclock); @@ -522,9 +561,10 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, dev_err(dev, "Can't set parent of audio2x clock\n"); return ret; } + } - i2s_client_ch = (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) ? + i2s_client_ch = (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) ? params_channels(params) : 2; switch (sample_size) { @@ -615,7 +655,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, } } else { val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - reg = TEGRA30_I2S_CIF_TX_CTRL; + reg = TEGRA30_I2S_CIF_TX_CTRL, val; tegra30_ahub_set_rx_cif_channels(i2s->capture_fifo_cif, params_channels(params), @@ -653,7 +693,6 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, break; } } - regmap_write(i2s->regmap, reg, val); switch (i2s->daifmt) { @@ -673,46 +712,67 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } + val = (val << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | - (val << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + (val << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val); - tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + if (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) { + regmap_read(i2s->regmap, TEGRA30_I2S_SLOT_CTRL2, &val); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val &= + ~TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_MASK; + val |= ((1 << params_channels(params)) - 1) << + TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_SHIFT; + } else { + val &= + ~TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_MASK; + val |= ((1 << params_channels(params)) - 1) << + TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_SHIFT; + } + regmap_write(i2s->regmap, TEGRA30_I2S_SLOT_CTRL2, val); + } val = 0; -#ifdef CONFIG_ARCH_TEGRA_3x_SOC + mask = TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + if (reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) + val = (params_channels(params) - 1) << + TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; +#else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { mask = TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; - val |= (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); + val = (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); } else { mask = TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; - val |= (1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); + val = (1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); } - regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val); -#else - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) - val = params_channels(params) - 1; - regmap_write(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, val); #endif + regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val); + return 0; } static int tegra30_i2s_soft_reset(struct tegra30_i2s *i2s) { int dcnt = 10; + unsigned int val; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_SOFT_RESET; - tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_SOFT_RESET, TEGRA30_I2S_CTRL_SOFT_RESET); - while ((tegra30_i2s_read(i2s, TEGRA30_I2S_CTRL) & - TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + do { udelay(100); + regmap_read(i2s->regmap, TEGRA30_I2S_CTRL, &val); + } while ((val & TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--); /* Restore reg_ctrl to ensure if a concurrent playback/capture session was active it continues after SOFT_RESET */ - i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; - tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_SOFT_RESET, 0); return (dcnt < 0) ? -ETIMEDOUT : 0; } @@ -735,6 +795,7 @@ static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) if (i2s->playback_ref_count == 1) { regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, TEGRA30_I2S_CTRL_XFER_EN_TX, 0); + while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--) udelay(100); @@ -758,7 +819,7 @@ static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) { tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif); - if (!i2s->is_call_mode_rec && (i2s->capture_ref_count == 1)) + if (!i2s->is_call_mode_rec) regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, TEGRA30_I2S_CTRL_XFER_EN_RX, TEGRA30_I2S_CTRL_XFER_EN_RX); @@ -767,6 +828,7 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { int dcnt = 10; + if (!i2s->is_call_mode_rec && (i2s->capture_ref_count == 1)) { regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, TEGRA30_I2S_CTRL_XFER_EN_RX, 0); @@ -788,7 +850,7 @@ static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) dcnt--) udelay(100); } - tegra30_ahub_disable_rx_fifo(i2s->rxcif); + tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif); } } @@ -858,59 +920,42 @@ int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, return 0; } -#ifdef CONFIG_PM -int tegra30_i2s_resume(struct snd_soc_dai *cpu_dai) -{ - struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); - int ret = 0; - - //tegra30_ahub_apbif_resume(); - - if (i2s->dam_ch_refcount) - ret = tegra30_dam_resume(i2s->dam_ifc); - - return ret; -} -#else -#define tegra30_i2s_resume NULL -#endif - 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, - .set_tdm_slot = tegra30_i2s_set_tdm_slot, + .set_tdm_slot = tegra30_i2s_set_tdm_slot, + .set_sysclk = tegra30_i2s_set_dai_sysclk, }; -static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { +static struct snd_soc_dai_driver tegra30_i2s_dai_template = { .probe = tegra30_i2s_probe, - .resume = tegra30_i2s_resume, .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 16, .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 16, .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra30_i2s_dai_ops, .symmetric_rates = 1, }; +static const struct snd_soc_component_driver tegra30_i2s_component = { + .name = DRV_NAME, +}; + static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -936,6 +981,9 @@ static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg) case TEGRA30_I2S_LCOEF_2_4_0: case TEGRA30_I2S_LCOEF_2_4_1: case TEGRA30_I2S_LCOEF_2_4_2: +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + case TEGRA30_I2S_SLOT_CTRL2: +#endif return true; default: return false; @@ -959,7 +1007,11 @@ static const struct regmap_config tegra30_i2s_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, +#ifndef CONFIG_ARCH_TEGRA_3x_SOC + .max_register = TEGRA30_I2S_SLOT_CTRL2, +#else .max_register = TEGRA30_I2S_LCOEF_2_4_2, +#endif .writeable_reg = tegra30_i2s_wr_rd_reg, .readable_reg = tegra30_i2s_wr_rd_reg, .volatile_reg = tegra30_i2s_volatile_reg, @@ -973,17 +1025,17 @@ int tegra30_i2s_set_cif_channels(struct tegra30_i2s *i2s, { unsigned int val; - tegra30_i2s_enable_clocks(i2s); + pm_runtime_get_sync(i2s->dev); - val = tegra30_i2s_read(i2s, cif_reg); + regmap_read(i2s->regmap, cif_reg, &val); val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); - tegra30_i2s_write(i2s, cif_reg, val); + regmap_write(i2s->regmap, cif_reg, val); - tegra30_i2s_disable_clocks(i2s); + pm_runtime_put(i2s->dev); return 0; } @@ -995,17 +1047,17 @@ int tegra30_i2s_set_cif_bits(struct tegra30_i2s *i2s, { unsigned int val; - tegra30_i2s_enable_clocks(i2s); + pm_runtime_get_sync(i2s->dev); - val = tegra30_i2s_read(i2s, cif_reg); + regmap_read(i2s->regmap, cif_reg, &val); val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); - tegra30_i2s_write(i2s, cif_reg, val); + regmap_write(i2s->regmap, cif_reg, val); - tegra30_i2s_disable_clocks(i2s); + pm_runtime_put(i2s->dev); return 0; } @@ -1016,15 +1068,15 @@ int tegra30_i2s_set_cif_stereo_conv(struct tegra30_i2s *i2s, { unsigned int val; - tegra30_i2s_enable_clocks(i2s); + pm_runtime_get_sync(i2s->dev); - val = tegra30_i2s_read(i2s, cif_reg); + regmap_read(i2s->regmap, cif_reg, &val); val &= ~TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK; val |= conv; - tegra30_i2s_write(i2s, cif_reg, val); + regmap_write(i2s->regmap, cif_reg, val); - tegra30_i2s_disable_clocks(i2s); + pm_runtime_put(i2s->dev); return 0; } @@ -1032,20 +1084,16 @@ int tegra30_i2s_set_cif_stereo_conv(struct tegra30_i2s *i2s, static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, int i2s_mode, int channels, int rate, int bitsize, int bit_clk) { - u32 val; int i2sclock, bitcnt, ret, is_formatdsp; -#ifndef CONFIG_ARCH_TEGRA_3x_SOC - u32 i; -#endif + unsigned int mask, mask1, val, val1; is_formatdsp = (i2s_mode == TEGRA_DAIFMT_DSP_A) || (i2s_mode == TEGRA_DAIFMT_DSP_B); - if (bit_clk) { i2sclock = bit_clk; } else { - i2sclock = rate * channels * bitsize * 2; - /* additional 8 for baseband */ + i2sclock = rate * channels * bitsize * 2; + /* additional 8 for baseband */ if (is_formatdsp) i2sclock *= 8; } @@ -1082,60 +1130,58 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, } } - i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | - TEGRA30_I2S_CTRL_LRCK_MASK | - TEGRA30_I2S_CTRL_MASTER_ENABLE); - i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK; + pm_runtime_get_sync(i2s->dev); - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; + mask = (TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | + TEGRA30_I2S_CTRL_LRCK_MASK | + TEGRA30_I2S_CTRL_MASTER_ENABLE); + mask1 = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK; + val = TEGRA30_I2S_CTRL_BIT_SIZE_16; if (is_i2smaster) - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; + val |= TEGRA30_I2S_CTRL_MASTER_ENABLE; if (i2s_mode == TEGRA_DAIFMT_DSP_A) { - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; + val |= TEGRA30_I2S_CTRL_LRCK_R_LOW; + val1 = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; } else if (i2s_mode == TEGRA_DAIFMT_DSP_B) { - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; + val |= TEGRA30_I2S_CTRL_LRCK_R_LOW; + val1 = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; } else { - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; - i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; - i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; + val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; + val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; + val1 = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; } - - tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); + regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL, mask1, val1); #ifndef CONFIG_ARCH_TEGRA_3x_SOC - val = 0; - for (i = 0; i < channels; i++) - val |= (1 << i); - - val |= val << - TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_SHIFT; - val |= val << - TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_SHIFT; - tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL2, val); + regmap_read(i2s->regmap, TEGRA30_I2S_SLOT_CTRL2, &val); + val &= ~TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_MASK; + val |= ((1 << channels) - 1) << + TEGRA30_I2S_SLOT_CTRL2_TX_SLOT_ENABLES_SHIFT; + val &= ~TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_MASK; + val |= ((1 << channels) - 1) << + TEGRA30_I2S_SLOT_CTRL2_RX_SLOT_ENABLES_SHIFT; + regmap_write(i2s->regmap, TEGRA30_I2S_SLOT_CTRL2, val); val = 0; - if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) - val = channels - 1; - - tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); + mask = TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + if (is_formatdsp) + val = (channels - 1) << + TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; #else - val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); - val &= ~(TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK | - TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK); - val |= (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT | - 1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); - tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); + mask = (TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK | + TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK); + val = (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT | + 1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); #endif + regmap_update_bits(i2s->regmap, TEGRA30_I2S_SLOT_CTRL, mask, val); val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); - tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); + regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val); if (is_formatdsp) { bitcnt = (i2sclock/rate) - 1; @@ -1148,8 +1194,7 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, if (i2sclock % (2*rate)) val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; } - - tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); + regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val); /* configure the i2s cif*/ val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | @@ -1158,11 +1203,13 @@ static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16; val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); + regmap_write(i2s->regmap, TEGRA30_I2S_CIF_RX_CTRL, val); val &= ~TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK; val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; - tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); + regmap_write(i2s->regmap, TEGRA30_I2S_CIF_TX_CTRL, val); + + pm_runtime_put(i2s->dev); return 0; } @@ -1197,29 +1244,23 @@ static int configure_dam(struct tegra30_i2s *i2s, int out_channel, out_channel, out_bitsize, out_channel, out_bitsize); #endif -#ifndef CONFIG_ARCH_TEGRA_3x_SOC - if (in_rate != out_rate) { - tegra30_dam_write_coeff_ram(i2s->dam_ifc, in_rate, out_rate); - tegra30_dam_set_farrow_param(i2s->dam_ifc, in_rate, out_rate); - tegra30_dam_set_biquad_fixed_coef(i2s->dam_ifc); - tegra30_dam_enable_coeff_ram(i2s->dam_ifc); - tegra30_dam_set_filter_stages(i2s->dam_ifc, in_rate, out_rate); - } else { - tegra30_dam_enable_stereo_mixing(i2s->dam_ifc); - } -#endif - return 0; } - #if defined(CONFIG_ARCH_TEGRA_14x_SOC) int t14x_make_bt_voice_call_connections(struct codec_config *codec_info, struct ahub_bbc1_config *bb_info, int uses_voice_codec) { - struct tegra30_i2s *codec_i2s = &i2scont[codec_info->i2s_id]; - struct tegra30_i2s *bb_i2s = &bbc1cont; + struct tegra30_i2s *codec_i2s; + struct tegra30_i2s *bb_i2s; + unsigned int val; + + codec_i2s = i2scont[codec_info->i2s_id]; + bb_i2s = &bbc1cont; + + if (codec_i2s == NULL || bb_i2s == NULL) + return -ENOENT; /* increment the codec i2s playback ref count */ codec_i2s->playback_ref_count++; @@ -1227,6 +1268,8 @@ int t14x_make_bt_voice_call_connections(struct codec_config *codec_info, codec_i2s->capture_ref_count++; bb_i2s->capture_ref_count++; + pm_runtime_get_sync(codec_i2s->dev); + /* Configure codec i2s */ configure_baseband_i2s(codec_i2s, codec_info->is_i2smaster, codec_info->i2s_mode, codec_info->channels, @@ -1270,10 +1313,8 @@ int t14x_make_bt_voice_call_connections(struct codec_config *codec_info, tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE, TEGRA30_DAM_CHIN0_SRC); - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl); + val = TEGRA30_I2S_CTRL_XFER_EN_TX | TEGRA30_I2S_CTRL_XFER_EN_RX; + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, val, val); return 0; } @@ -1282,15 +1323,14 @@ int t14x_break_bt_voice_call_connections(struct codec_config *codec_info, struct ahub_bbc1_config *bb_info, int uses_voice_codec) { - struct tegra30_i2s *codec_i2s = &i2scont[codec_info->i2s_id]; + struct tegra30_i2s *codec_i2s = i2scont[codec_info->i2s_id]; struct tegra30_i2s *bb_i2s = &bbc1cont; int dcnt = 10; /* Disable Codec I2S RX (TX to ahub) */ if (codec_i2s->capture_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_RX, 0); while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1299,9 +1339,8 @@ int t14x_break_bt_voice_call_connections(struct codec_config *codec_info, /* Disable Codec I2S TX (RX from ahub) */ if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_TX, 0); while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1349,18 +1388,10 @@ int t14x_break_bt_voice_call_connections(struct codec_config *codec_info, bb_i2s->capture_ref_count--; /* Soft reset */ - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); - - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; - - while ((tegra30_i2s_read(codec_i2s, TEGRA30_I2S_CTRL) & - TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) - udelay(100); + tegra30_i2s_soft_reset(codec_i2s); /* Disable the clocks */ - tegra30_i2s_disable_clocks(codec_i2s); + pm_runtime_put(codec_i2s->dev); return 0; } @@ -1369,8 +1400,9 @@ int t14x_make_voice_call_connections(struct codec_config *codec_info, struct ahub_bbc1_config *bb_info, int uses_voice_codec) { - struct tegra30_i2s *codec_i2s = &i2scont[codec_info->i2s_id]; + struct tegra30_i2s *codec_i2s = i2scont[codec_info->i2s_id]; struct tegra30_i2s *bb_i2s = &bbc1cont; + unsigned int val; /* increment the codec i2s playback ref count */ codec_i2s->playback_ref_count++; @@ -1421,7 +1453,7 @@ int t14x_make_voice_call_connections(struct codec_config *codec_info, (codec_i2s->dam_ifc*2), TEGRA30_AHUB_TXCIF_BBC1_TX0); tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + - (codec_i2s->dam_ifc*2), codec_i2s->txcif); + (codec_i2s->dam_ifc*2), codec_i2s->playback_i2s_cif); tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_BBC1_RX0, TEGRA30_AHUB_TXCIF_I2S0_TX0 + codec_info->i2s_id); @@ -1438,10 +1470,8 @@ int t14x_make_voice_call_connections(struct codec_config *codec_info, tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE, TEGRA30_DAM_CHIN1); - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl); + val = TEGRA30_I2S_CTRL_XFER_EN_TX | TEGRA30_I2S_CTRL_XFER_EN_RX; + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, val, val); return 0; } @@ -1450,15 +1480,18 @@ int t14x_break_voice_call_connections(struct codec_config *codec_info, struct ahub_bbc1_config *bb_info, int uses_voice_codec) { - struct tegra30_i2s *codec_i2s = &i2scont[codec_info->i2s_id]; + struct tegra30_i2s *codec_i2s = i2scont[codec_info->i2s_id]; struct tegra30_i2s *bb_i2s = &bbc1cont; int dcnt = 10; + unsigned int reg_ctrl; + + if (codec_i2s == NULL || bb_i2s == NULL) + return -ENOENT; /* Disable Codec I2S RX (TX to ahub) */ if (codec_i2s->capture_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_RX, 0); while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1467,9 +1500,8 @@ int t14x_break_voice_call_connections(struct codec_config *codec_info, /* Disable Codec I2S TX (RX from ahub) */ if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_TX, 0); while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1512,33 +1544,38 @@ int t14x_break_voice_call_connections(struct codec_config *codec_info, bb_i2s->capture_ref_count--; /* Soft reset */ - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); - - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_SOFT_RESET, TEGRA30_I2S_CTRL_SOFT_RESET); - while ((tegra30_i2s_read(codec_i2s, TEGRA30_I2S_CTRL) & - TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + do { udelay(100); + regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); + } while ((reg_ctrl & TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--); + + dcnt = 10; /* Disable the clocks */ - tegra30_i2s_disable_clocks(codec_i2s); + pm_runtime_put(codec_i2s->dev); + tegra30_dam_disable_clock(codec_i2s->dam_ifc); + tegra30_dam_disable_clock(bb_i2s->dam_ifc); return 0; } #endif int tegra30_make_voice_call_connections(struct codec_config *codec_info, - struct codec_config *bb_info, - int uses_voice_codec) + struct codec_config *bb_info, int uses_voice_codec) { struct tegra30_i2s *codec_i2s; struct tegra30_i2s *bb_i2s; - int reg; + unsigned int val; + unsigned int en_flwcntrl = 0; - codec_i2s = &i2scont[codec_info->i2s_id]; - bb_i2s = &i2scont[bb_info->i2s_id]; + codec_i2s = i2scont[codec_info->i2s_id]; + bb_i2s = i2scont[bb_info->i2s_id]; + + if (codec_i2s == NULL || bb_i2s == NULL) + return -ENOENT; /* increment the codec i2s playback ref count */ codec_i2s->playback_ref_count++; @@ -1546,25 +1583,20 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, codec_i2s->capture_ref_count++; bb_i2s->capture_ref_count++; - /* Make sure i2s is disabled during the configiration */ - tegra30_i2s_enable_clocks(codec_i2s); - reg = codec_i2s->reg_ctrl; - reg &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - reg &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - reg &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl); - tegra30_i2s_disable_clocks(codec_i2s); - - tegra30_i2s_enable_clocks(bb_i2s); - reg = bb_i2s->reg_ctrl; - reg &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - reg &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - reg &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, - bb_i2s->reg_ctrl); - tegra30_i2s_disable_clocks(bb_i2s); + pm_runtime_get_sync(codec_i2s->dev); + pm_runtime_get_sync(bb_i2s->dev); + /* Make sure i2s is disabled during the configiration */ + regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, &val); + val &= ~(TEGRA30_I2S_CTRL_TX_FLOWCTL_EN | + TEGRA30_I2S_CTRL_XFER_EN_TX | + TEGRA30_I2S_CTRL_XFER_EN_RX); + regmap_write(codec_i2s->regmap, TEGRA30_I2S_CTRL, val); + regmap_read(bb_i2s->regmap, TEGRA30_I2S_CTRL, &val); + val &= ~(TEGRA30_I2S_CTRL_TX_FLOWCTL_EN | + TEGRA30_I2S_CTRL_XFER_EN_TX | + TEGRA30_I2S_CTRL_XFER_EN_RX); + regmap_write(bb_i2s->regmap, TEGRA30_I2S_CTRL, val); msleep(20); /*Configure codec i2s*/ @@ -1590,45 +1622,46 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, codec_info->i2s_id, TEGRA30_AHUB_TXCIF_I2S0_TX0 + bb_info->i2s_id); if (!(codec_info->is_i2smaster && bb_info->is_i2smaster)) { - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_FLOWCTL, + regmap_write(codec_i2s->regmap, TEGRA30_I2S_FLOWCTL, TEGRA30_I2S_FILTER_QUAD); - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_FLOWCTL, + regmap_write(bb_i2s->regmap, TEGRA30_I2S_FLOWCTL, TEGRA30_I2S_FILTER_QUAD); - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_TX_STEP, 4); - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_TX_STEP, 4); - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - bb_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; + regmap_write(codec_i2s->regmap, TEGRA30_I2S_TX_STEP, 4); + regmap_write(bb_i2s->regmap, TEGRA30_I2S_TX_STEP, 4); + en_flwcntrl = 1; } } else { - /*configure codec dam*/ configure_dam(codec_i2s, codec_info->channels, - codec_info->rate, codec_info->bitsize, bb_info->channels, - bb_info->rate, bb_info->bitsize); + codec_info->rate, codec_info->bitsize, + bb_info->channels, bb_info->rate, + bb_info->bitsize); /*configure bb dam*/ configure_dam(bb_i2s, bb_info->channels, - bb_info->rate, bb_info->bitsize, codec_info->channels, - codec_info->rate, codec_info->bitsize); + bb_info->rate, bb_info->bitsize, + codec_info->channels, codec_info->rate, + codec_info->bitsize); /*make ahub connections*/ - /*if this is the only user of i2s tx, make i2s rx connection*/ + /* if this is the only user of i2s tx then make + ahub i2s rx connection*/ if (codec_i2s->playback_ref_count == 1) { tegra30_ahub_set_rx_cif_source( - TEGRA30_AHUB_RXCIF_I2S0_RX0 + codec_info->i2s_id, - TEGRA30_AHUB_TXCIF_DAM0_TX0 + codec_i2s->dam_ifc); + TEGRA30_AHUB_RXCIF_I2S0_RX0 + codec_info->i2s_id, + TEGRA30_AHUB_TXCIF_DAM0_TX0 + codec_i2s->dam_ifc); } - tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + - bb_info->i2s_id, TEGRA30_AHUB_TXCIF_DAM0_TX0 + - bb_i2s->dam_ifc); - tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + - (codec_i2s->dam_ifc*2), TEGRA30_AHUB_TXCIF_I2S0_TX0 + - bb_info->i2s_id); - tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + - (bb_i2s->dam_ifc*2), TEGRA30_AHUB_TXCIF_I2S0_TX0 + - codec_info->i2s_id); + tegra30_ahub_set_rx_cif_source( + TEGRA30_AHUB_RXCIF_I2S0_RX0 + bb_info->i2s_id, + TEGRA30_AHUB_TXCIF_DAM0_TX0 + bb_i2s->dam_ifc); + tegra30_ahub_set_rx_cif_source( + TEGRA30_AHUB_RXCIF_DAM0_RX0 + (codec_i2s->dam_ifc*2), + TEGRA30_AHUB_TXCIF_I2S0_TX0 + bb_info->i2s_id); + tegra30_ahub_set_rx_cif_source( + TEGRA30_AHUB_RXCIF_DAM0_RX0 + (bb_i2s->dam_ifc*2), + TEGRA30_AHUB_TXCIF_I2S0_TX0 + codec_info->i2s_id); /*enable dam and i2s*/ tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE, @@ -1637,39 +1670,36 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, TEGRA30_DAM_CHIN0_SRC); } - msleep(20); - - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl); + val = TEGRA30_I2S_CTRL_XFER_EN_TX | TEGRA30_I2S_CTRL_XFER_EN_RX; + if (en_flwcntrl) + val |= TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; msleep(20); - - bb_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - bb_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, - bb_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, val, val); + msleep(20); + regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL, val, val); return 0; } int tegra30_break_voice_call_connections(struct codec_config *codec_info, - struct codec_config *bb_info, - int uses_voice_codec) + struct codec_config *bb_info, int uses_voice_codec) { struct tegra30_i2s *codec_i2s; struct tegra30_i2s *bb_i2s; int dcnt = 10; + unsigned int reg_ctrl; + + codec_i2s = i2scont[codec_info->i2s_id]; + bb_i2s = i2scont[bb_info->i2s_id]; - codec_i2s = &i2scont[codec_info->i2s_id]; - bb_i2s = &i2scont[bb_info->i2s_id]; + if (codec_i2s == NULL || bb_i2s == NULL) + return -ENOENT; /*Disable Codec I2S RX (TX to ahub)*/ if (codec_i2s->capture_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_RX, 0); while (!tegra30_ahub_rx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1677,8 +1707,8 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, dcnt = 10; /*Disable baseband I2S TX (RX from ahub)*/ - bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); + regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_TX, 0); while (!tegra30_ahub_tx_fifo_is_empty(bb_i2s->id) && dcnt--) udelay(100); @@ -1686,8 +1716,8 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, dcnt = 10; /*Disable baseband I2S RX (TX to ahub)*/ - bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); + regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_RX, 0); while (!tegra30_ahub_rx_fifo_is_empty(bb_i2s->id) && dcnt--) udelay(100); @@ -1696,9 +1726,8 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, /*Disable Codec I2S TX (RX from ahub)*/ if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; - - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_XFER_EN_TX, 0); while (!tegra30_ahub_tx_fifo_is_empty(codec_i2s->id) && dcnt--) udelay(100); @@ -1711,16 +1740,16 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + codec_info->i2s_id); } else { - /*Disable baseband DAM*/ tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE, - TEGRA30_DAM_CHIN0_SRC); + TEGRA30_DAM_CHIN0_SRC); tegra30_dam_free_channel(bb_i2s->dam_ifc, - TEGRA30_DAM_CHIN0_SRC); + TEGRA30_DAM_CHIN0_SRC); bb_i2s->dam_ch_refcount--; if (!bb_i2s->dam_ch_refcount) tegra30_dam_free_controller(bb_i2s->dam_ifc); + /*Disable Codec DAM*/ tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC); @@ -1735,19 +1764,19 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, i2s rx connection */ if (codec_i2s->playback_ref_count == 1) tegra30_ahub_unset_rx_cif_source( - TEGRA30_AHUB_RXCIF_I2S0_RX0 + codec_info->i2s_id); + TEGRA30_AHUB_RXCIF_I2S0_RX0 + + codec_info->i2s_id); tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 - + bb_info->i2s_id); + + bb_info->i2s_id); tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 - + (codec_i2s->dam_ifc*2)); + + (codec_i2s->dam_ifc*2)); tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 - + (bb_i2s->dam_ifc*2)); + + (bb_i2s->dam_ifc*2)); tegra30_dam_disable_clock(codec_i2s->dam_ifc); tegra30_dam_disable_clock(bb_i2s->dam_ifc); } - /* Decrement the codec and bb i2s playback ref count */ codec_i2s->playback_ref_count--; bb_i2s->playback_ref_count--; @@ -1755,23 +1784,25 @@ int tegra30_break_voice_call_connections(struct codec_config *codec_info, bb_i2s->capture_ref_count--; /* Soft reset */ - tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, - codec_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); - tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, - bb_i2s->reg_ctrl | TEGRA30_I2S_CTRL_SOFT_RESET); - - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_TX_FLOWCTL_EN; - codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; - bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_SOFT_RESET; - - while ((tegra30_i2s_read(codec_i2s, TEGRA30_I2S_CTRL) & - TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + regmap_update_bits(codec_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_SOFT_RESET, TEGRA30_I2S_CTRL_SOFT_RESET); + do { udelay(100); + regmap_read(codec_i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); + } while ((reg_ctrl & TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--); dcnt = 10; - while ((tegra30_i2s_read(bb_i2s, TEGRA30_I2S_CTRL) & - TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--) + + regmap_update_bits(bb_i2s->regmap, TEGRA30_I2S_CTRL, + TEGRA30_I2S_CTRL_SOFT_RESET, TEGRA30_I2S_CTRL_SOFT_RESET); + do { udelay(100); + regmap_read(bb_i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); + } while ((reg_ctrl & TEGRA30_I2S_CTRL_SOFT_RESET) && dcnt--); + dcnt = 10; + + /* Disable the clocks */ + pm_runtime_put(codec_i2s->dev); + pm_runtime_put(bb_i2s->dev); return 0; } @@ -1784,21 +1815,34 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) void __iomem *regs; int ret; - /* This needs to be updated for DT */ - return -ENODEV; - - i2s = &i2scont[pdev->id]; - dev_set_drvdata(&pdev->dev, i2s); - i2s->id = pdev->id; - - ret = of_property_read_u32_array(pdev->dev.of_node, - "nvidia,ahub-cif-ids", cif_ids, - ARRAY_SIZE(cif_ids)); - if (ret < 0) + i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_i2s), GFP_KERNEL); + if (!i2s) { + dev_err(&pdev->dev, "Can't allocate tegra30_i2s\n"); + ret = -ENOMEM; goto err; + } + dev_set_drvdata(&pdev->dev, i2s); + i2s->dev = &pdev->dev; + i2s->dai = tegra30_i2s_dai_template; + i2s->dai.name = dev_name(&pdev->dev); + + if (pdev->dev.of_node) { + ret = of_property_read_u32_array(pdev->dev.of_node, + "nvidia,ahub-cif-ids", cif_ids, + ARRAY_SIZE(cif_ids)); + if (ret < 0) + goto err; + + i2s->playback_i2s_cif = cif_ids[0]; + i2s->capture_i2s_cif = cif_ids[1]; + i2s->id = i2s->playback_i2s_cif - TEGRA30_AHUB_RXCIF_I2S0_RX0; + } else { + i2s->id = pdev->id; + i2s->playback_i2s_cif = TEGRA30_AHUB_RXCIF_I2S0_RX0 + pdev->id; + i2s->capture_i2s_cif = TEGRA30_AHUB_TXCIF_I2S0_TX0 + pdev->id; + } - i2s->playback_i2s_cif = cif_ids[0]; - i2s->capture_i2s_cif = cif_ids[1]; + i2scont[i2s->id] = i2s; i2s->clk_i2s = clk_get(&pdev->dev, "i2s"); if (IS_ERR(i2s->clk_i2s)) { @@ -1806,11 +1850,12 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = PTR_ERR(i2s->clk_i2s); goto err; } + i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); if (IS_ERR(i2s->clk_i2s_sync)) { dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); ret = PTR_ERR(i2s->clk_i2s_sync); - goto err_i2s_clk_put; + goto err_clk_put; } i2s->clk_audio_2x = clk_get(&pdev->dev, "audio_sync_2x"); @@ -1865,7 +1910,9 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_dai(&pdev->dev, NULL); + ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component, + &tegra30_i2s_dai_template, 1); + if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -1881,7 +1928,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) return 0; err_unregister_dai: - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_i2s_runtime_suspend(&pdev->dev); @@ -1893,7 +1940,7 @@ err_audio_2x_clk_put: clk_put(i2s->clk_audio_2x); err_i2s_sync_clk_put: clk_put(i2s->clk_i2s_sync); -err_i2s_clk_put: +err_clk_put: clk_put(i2s->clk_i2s); err: return ret; @@ -1908,7 +1955,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra30_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_pll_a_out0); clk_put(i2s->clk_audio_2x); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index cbe57475b232..126ee5dbd655 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -1,7 +1,7 @@ /* * tegra30_i2s.h - Definitions for Tegra30 I2S driver * - * Copyright (c) 2010-2013, NVIDIA Corporation. + * Copyright (c) 2010-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, @@ -174,9 +174,15 @@ /* Fields in TEGRA30_I2S_SLOT_CTRL */ /* Number of slots in frame, minus 1 */ +#ifndef CONFIG_ARCH_TEGRA_3x_SOC +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 0 +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 0xf +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) +#else #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) +#endif /* TDM mode slot enable bitmask */ #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 @@ -248,15 +254,25 @@ struct dsp_config_t { int tx_data_offset; }; +struct codec_config { + int i2s_id; + int rate; + int channels; + int bitsize; + int is_i2smaster; + int i2s_mode; + int bit_clk; +}; struct tegra30_i2s { - int id; struct snd_soc_dai_driver dai; + struct device *dev; int cif_id; struct clk *clk_i2s; struct clk *clk_i2s_sync; struct clk *clk_audio_2x; struct clk *clk_pll_a_out0; + int id; enum tegra30_ahub_txcif capture_i2s_cif; enum tegra30_ahub_rxcif capture_fifo_cif; struct tegra_pcm_dma_params capture_dma_data; @@ -264,12 +280,11 @@ struct tegra30_i2s { enum tegra30_ahub_txcif playback_fifo_cif; struct tegra_pcm_dma_params playback_dma_data; struct regmap *regmap; - u32 reg_ch_ctrl; + int daifmt; int dam_ifc; int dam_ch_refcount; int playback_ref_count; int capture_ref_count; - int daifmt; bool is_dam_used; #ifdef CONFIG_PM #ifdef CONFIG_ARCH_TEGRA_3x_SOC @@ -281,18 +296,8 @@ struct tegra30_i2s { int call_record_dam_ifc; int call_record_dam_ifc2; int is_call_mode_rec; - struct dsp_config_t dsp_config; -}; - -struct codec_config { - int i2s_id; - int rate; - int channels; - int bitsize; - int is_i2smaster; - int i2s_mode; - int bit_clk; + int i2s_bit_clk; }; int tegra30_make_voice_call_connections(struct codec_config *codec_info, diff --git a/sound/soc/tegra/tegra30_spdif.c b/sound/soc/tegra/tegra30_spdif.c index 0abb9d6ff269..393ea41db04b 100644 --- a/sound/soc/tegra/tegra30_spdif.c +++ b/sound/soc/tegra/tegra30_spdif.c @@ -36,7 +36,6 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/delay.h> -#include <mach/iomap.h> #include <mach/hdmi-audio.h> #include <mach/clk.h> #include <sound/core.h> @@ -62,10 +61,12 @@ static inline u32 tegra30_spdif_read(struct tegra30_spdif *spdif, u32 reg) static void tegra30_spdif_enable_clocks(struct tegra30_spdif *spdif) { clk_enable(spdif->clk_spdif_out); + tegra30_ahub_enable_clocks(); } static void tegra30_spdif_disable_clocks(struct tegra30_spdif *spdif) { + tegra30_ahub_disable_clocks(); clk_disable(spdif->clk_spdif_out); } @@ -396,11 +397,15 @@ struct snd_soc_dai_driver tegra30_spdif_dai = { .ops = &tegra30_spdif_dai_ops, }; +static const struct snd_soc_component_driver tegra30_spdif_component = { + .name = DRV_NAME, +}; + static int tegra30_spdif_platform_probe(struct platform_device *pdev) { struct tegra30_spdif *spdif; struct resource *mem, *memregion; - int ret; + int ret = 0; u32 reg_val; spdif = kzalloc(sizeof(struct tegra30_spdif), GFP_KERNEL); @@ -453,17 +458,26 @@ static int tegra30_spdif_platform_probe(struct platform_device *pdev) tegra30_spdif_disable_clocks(spdif); - ret = snd_soc_register_dai(&pdev->dev, &tegra30_spdif_dai); + ret = snd_soc_register_component(&pdev->dev, &tegra30_spdif_component, + &tegra30_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; goto err_unmap; } + ret = tegra_pcm_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); + goto err_unregister_dai; + } + tegra30_spdif_debug_add(spdif); return 0; +err_unregister_dai: + snd_soc_unregister_component(&pdev->dev); err_unmap: iounmap(spdif->regs); err_release: @@ -481,7 +495,7 @@ static int tegra30_spdif_platform_remove(struct platform_device *pdev) struct tegra30_spdif *spdif = dev_get_drvdata(&pdev->dev); struct resource *res; - snd_soc_unregister_dai(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); tegra30_spdif_debug_remove(spdif); diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index 30479f6b826c..e67a94b050a5 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -46,6 +46,7 @@ #endif #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> #include "tegra_pcm.h" #include "tegra_asoc_utils.h" @@ -211,11 +212,11 @@ static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol, rtd = &card->rtd[data->avp_device_id]; substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream || !substream->runtime) return 0; - prtd = (struct tegra_runtime_data *) - snd_dmaengine_pcm_get_data(substream); + prtd = substream->runtime->private_data; if (!prtd) return 0; @@ -223,8 +224,7 @@ static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol, chan = snd_dmaengine_pcm_get_chan(substream); ucontrol->value.integer.value[0] = -1; - ucontrol->value.integer.value[0] = - tegra_dma_get_channel_id(prtd->dma_chan); + return 0; } @@ -244,14 +244,10 @@ static int tegra_set_dma_addr(struct snd_kcontrol *kcontrol, substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - rtd = &card->rtd[data->avp_device_id]; - substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream || !substream->runtime) return 0; - prtd = (struct tegra_runtime_data *) - snd_dmaengine_pcm_get_data(substream); - + prtd = substream->runtime->private_data; if (!prtd) return 0; @@ -278,16 +274,15 @@ static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol, if (!substream || !substream->runtime) return 0; - prtd = (struct tegra_runtime_data *) - snd_dmaengine_pcm_get_data(substream); + prtd = substream->runtime->private_data; if (!prtd) return 0; ucontrol->value.integer.value[0] = 0; ucontrol->value.integer.value[0] = prtd->avp_dma_addr ? - prtd->avp_dma_addr : - substream->runtime->dma_addr; + (long)prtd->avp_dma_addr : + (long)substream->runtime->dma_addr; return 0; } @@ -385,6 +380,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, clk_disable_unprepare(data->clk_pll_a); reenable_clock = true; } + err = clk_set_rate(data->clk_pll_a, new_baseclock); if (err) { dev_err(data->dev, "Can't set pll_a rate: %d\n", err); @@ -406,7 +402,6 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, if(reenable_clock) clk_prepare_enable(data->clk_pll_a_out0); - data->set_baseclock = new_baseclock; data->set_mclk = mclk; @@ -428,7 +423,7 @@ int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data) { int err; - err = clk_enable(data->clk_cdev1); + err = clk_prepare_enable(data->clk_cdev1); if (err) { dev_err(data->dev, "Can't enable cdev1: %d\n", err); return err; @@ -440,7 +435,7 @@ EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_enable); int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data) { - clk_disable(data->clk_cdev1); + clk_disable_unprepare(data->clk_cdev1); return 0; } EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable); @@ -480,24 +475,40 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, data->dev = dev; data->card = card; + data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1"); + if (IS_ERR(data->clk_pll_p_out1)) { + dev_err(data->dev, "Can't retrieve clk pll_p_out1\n"); + ret = PTR_ERR(data->clk_pll_p_out1); + goto err; + } + if (of_machine_is_compatible("nvidia,tegra20")) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; else if (of_machine_is_compatible("nvidia,tegra30")) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; - else if (!dev->of_node) + else if (of_machine_is_compatible("nvidia,tegra114")) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA11x; + else if (of_machine_is_compatible("nvidia,tegra148")) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA14x; + else if (of_machine_is_compatible("nvidia,tegra124")) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA12x; + else if (!dev->of_node) { /* non-DT is always Tegra20 */ +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; - else +#elif defined(CONFIG_ARCH_TEGRA_3x_SOC) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; +#elif defined(CONFIG_ARCH_TEGRA_11x_SOC) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA11x; +#elif defined(CONFIG_ARCH_TEGRA_14x_SOC) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA14x; +#elif defined(CONFIG_ARCH_TEGRA_12x_SOC) + data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA12x; +#endif + } else /* DT boot, but unknown SoC */ return -EINVAL; - data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1"); - if (IS_ERR(data->clk_pll_p_out1)) { - dev_err(data->dev, "Can't retrieve clk pll_p_out1\n"); - ret = PTR_ERR(data->clk_pll_p_out1); - goto err; - } - data->clk_pll_a = clk_get_sys(NULL, "pll_a"); if (IS_ERR(data->clk_pll_a)) { dev_err(data->dev, "Can't retrieve clk pll_a\n"); @@ -530,43 +541,41 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, goto err_put_pll_a_out0; } -#if defined(CONFIG_ARCH_TEGRA_2x_SOC) - data->clk_out1 = ERR_PTR(-ENOENT); -#else - data->clk_out1 = clk_get_sys("clk_out_1", "extern1"); - if (IS_ERR(data->clk_out1)) { - dev_err(data->dev, "Can't retrieve clk out1\n"); - ret = PTR_ERR(data->clk_out1); - goto err_put_cdev1; + if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) + data->clk_out1 = ERR_PTR(-ENOENT); + else { + data->clk_out1 = clk_get_sys("clk_out_1", "extern1"); + if (IS_ERR(data->clk_out1)) { + dev_err(data->dev, "Can't retrieve clk out1\n"); + ret = PTR_ERR(data->clk_out1); + goto err_put_cdev1; + } } -#endif - ret = clk_enable(data->clk_cdev1); + ret = clk_prepare_enable(data->clk_cdev1); if (ret) { dev_err(data->dev, "Can't enable clk cdev1/extern1"); goto err_put_out1; } if (!IS_ERR(data->clk_out1)) { - ret = clk_enable(data->clk_out1); + ret = clk_prepare_enable(data->clk_out1); if (ret) { dev_err(data->dev, "Can't enable clk out1"); goto err_put_out1; } } - ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100); + ret = tegra_asoc_utils_set_rate(data, 48000, 256 * 48000); if (ret) - goto err_put_cdev1; + goto err_put_out1; return 0; err_put_out1: if (!IS_ERR(data->clk_out1)) clk_put(data->clk_out1); -#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) err_put_cdev1: -#endif clk_put(data->clk_cdev1); err_put_pll_a_out0: clk_put(data->clk_pll_a_out0); @@ -579,12 +588,14 @@ err: } EXPORT_SYMBOL_GPL(tegra_asoc_utils_init); -#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) int tegra_asoc_utils_set_parent (struct tegra_asoc_utils_data *data, int is_i2s_master) { int ret = -ENODEV; + if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) + return ret; + if (is_i2s_master) { ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0); if (ret) { @@ -605,7 +616,6 @@ int tegra_asoc_utils_set_parent (struct tegra_asoc_utils_data *data, return 0; } EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_parent); -#endif void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) { diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index f59696b6ea34..346b01a3dbc8 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -2,8 +2,7 @@ * tegra_asoc_utils.h - Definitions for Tegra DAS driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved. - * + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. @@ -37,12 +36,15 @@ struct device; enum tegra_asoc_utils_soc { TEGRA_ASOC_UTILS_SOC_TEGRA20, TEGRA_ASOC_UTILS_SOC_TEGRA30, + TEGRA_ASOC_UTILS_SOC_TEGRA11x, + TEGRA_ASOC_UTILS_SOC_TEGRA14x, + TEGRA_ASOC_UTILS_SOC_TEGRA12x, }; struct tegra_asoc_utils_data { struct device *dev; - enum tegra_asoc_utils_soc soc; struct snd_soc_card *card; + enum tegra_asoc_utils_soc soc; struct clk *clk_pll_a; struct clk *clk_pll_a_out0; struct clk *clk_cdev1; @@ -53,8 +55,8 @@ struct tegra_asoc_utils_data { int set_mclk; int lock_count; int avp_device_id; - unsigned int avp_dma_addr; int headset_plug_state; + dma_addr_t avp_dma_addr; }; int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 2b335a7073af..ada00e157edf 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -2,13 +2,14 @@ * tegra_pcm.c - Tegra PCM driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010,2012 - NVIDIA, Inc. + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * * Based on code copyright/by: * - * Copyright (c) 2009-2010, NVIDIA Corporation. + * Copyright (c) 2009-2013, NVIDIA CORPORATION. All rights reserved. * Scott Peterson <speterson@nvidia.com> * Vijay Mali <vmali@nvidia.com> + * Manoj Gangwal <mgangwal@nvidia.com> * * Copyright (C) 2010 Google, Inc. * Iliyan Malchev <malchev@google.com> @@ -66,16 +67,24 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct device *dev = rtd->platform->dev; + struct tegra_runtime_data *prtd; int ret; + prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + /* Set HW params now that initialization is complete */ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); /* Ensure period size is multiple of 8 */ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); - if (ret < 0) - goto err; + if (ret) { + dev_err(dev, "failed to set constraint %d\n", ret); + kfree(prtd); + return ret; + } ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL); if (ret) { @@ -93,7 +102,7 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, +int tegra_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -133,18 +142,19 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) +int tegra_pcm_hw_free(struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; } -static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct tegra_pcm_dma_params * dmap;a + struct tegra_pcm_dma_params * dmap; dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dmap) return 0; @@ -152,12 +162,14 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + return snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_START); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + return snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); default: @@ -188,12 +200,11 @@ static struct snd_pcm_ops tegra_pcm_ops = { .mmap = tegra_pcm_mmap, }; -static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream , size_t size) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = tegra_pcm_hardware.buffer_bytes_max; - #if TEGRA30_USE_SMMU unsigned char *vaddr; phys_addr_t paddr; @@ -226,7 +237,7 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) +void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -260,7 +271,7 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) static u64 tegra_dma_mask = DMA_BIT_MASK(32); -static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) +int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, size_t size) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -273,14 +284,16 @@ static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = tegra_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); + SNDRV_PCM_STREAM_PLAYBACK, + size); if (ret) goto err; } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = tegra_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); + SNDRV_PCM_STREAM_CAPTURE, + size); if (ret) goto err_free_play; } @@ -293,7 +306,13 @@ err: return ret; } -static void tegra_pcm_free(struct snd_pcm *pcm) +int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + return tegra_pcm_dma_allocate(rtd , + tegra_pcm_hardware.buffer_bytes_max); +} + +void tegra_pcm_free(struct snd_pcm *pcm) { tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index c7020c9b33dd..3dfc08e0d431 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -2,11 +2,11 @@ * tegra_pcm.h - Definitions for Tegra PCM driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010,2012 - NVIDIA, Inc. + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * * Based on code copyright/by: * - * Copyright (c) 2009-2010, NVIDIA Corporation. + * Copyright (c) 2009-2010, NVIDIA CORPORATION. All rights reserved. * Scott Peterson <speterson@nvidia.com> * * Copyright (C) 2010 Google, Inc. @@ -33,6 +33,8 @@ #include <linux/nvmap.h> +#define MAX_DMA_REQ_COUNT 2 + #define TEGRA30_USE_SMMU 0 struct tegra_pcm_dma_params { @@ -49,6 +51,12 @@ struct tegra_smmu_data { }; #endif +struct tegra_runtime_data { + int running; + int disable_intr; + dma_addr_t avp_dma_addr; +}; + int tegra_pcm_platform_register(struct device *dev); void tegra_pcm_platform_unregister(struct device *dev); diff --git a/sound/soc/tegra/tegra_rt5639.c b/sound/soc/tegra/tegra_rt5639.c index d569f26ff6e0..1e30a94dc621 100644 --- a/sound/soc/tegra/tegra_rt5639.c +++ b/sound/soc/tegra/tegra_rt5639.c @@ -500,10 +500,11 @@ static int tegra_rt5639_event_int_spk(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = dapm->card; struct tegra_rt5639 *machine = snd_soc_card_get_drvdata(card); struct tegra_asoc_platform_data *pdata = machine->pdata; + int ret = 0; if (machine->spk_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) - regulator_enable(machine->spk_reg); + ret = regulator_enable(machine->spk_reg); else regulator_disable(machine->spk_reg); } @@ -541,10 +542,11 @@ static int tegra_rt5639_event_int_mic(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = dapm->card; struct tegra_rt5639 *machine = snd_soc_card_get_drvdata(card); struct tegra_asoc_platform_data *pdata = machine->pdata; + int ret = 0; if (machine->dmic_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) - regulator_enable(machine->dmic_reg); + ret = regulator_enable(machine->dmic_reg); else regulator_disable(machine->dmic_reg); } @@ -906,7 +908,7 @@ static int tegra_rt5639_driver_probe(struct platform_device *pdev) if (IS_ERR(machine->codec_reg)) machine->codec_reg = 0; else - regulator_enable(machine->codec_reg); + ret = regulator_enable(machine->codec_reg); } /* @@ -917,7 +919,7 @@ static int tegra_rt5639_driver_probe(struct platform_device *pdev) if (IS_ERR(machine->digital_reg)) machine->digital_reg = 0; else - regulator_enable(machine->digital_reg); + ret = regulator_enable(machine->digital_reg); /* *analog_reg - provided the analog power for the codec and must be @@ -927,7 +929,7 @@ static int tegra_rt5639_driver_probe(struct platform_device *pdev) if (IS_ERR(machine->analog_reg)) machine->analog_reg = 0; else - regulator_enable(machine->analog_reg); + ret = regulator_enable(machine->analog_reg); /* *spk_reg - provided the speaker power and can be turned ON diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 2c1439602252..e40067ac7b86 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -40,6 +40,7 @@ #ifdef CONFIG_SWITCH #include <linux/switch.h> #endif +#include <linux/pm_runtime.h> #include <mach/tegra_asoc_pdata.h> #include <mach/gpio-tegra.h> #include <mach/tegra_rt5640_pdata.h> @@ -521,7 +522,7 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w, if (machine->spk_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) { - regulator_enable(machine->spk_reg); + ret =regulator_enable(machine->spk_reg); } else { regulator_disable(machine->spk_reg); @@ -604,10 +605,11 @@ static int tegra_rt5640_event_int_mic(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = dapm->card; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); struct tegra_asoc_platform_data *pdata = machine->pdata; + int ret =0; if (machine->dmic_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) - regulator_enable(machine->dmic_reg); + ret=regulator_enable(machine->dmic_reg); else regulator_disable(machine->dmic_reg); } @@ -872,14 +874,18 @@ void tegra_asoc_enable_clocks() { struct snd_soc_card *card = &snd_soc_tegra_rt5640; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - int reg; + unsigned int reg; + unsigned int reg_ctrl; struct tegra30_i2s *i2s = i2s_tfa; if (!i2s || !machine) return; - reg = i2s->reg_ctrl | TEGRA30_I2S_CTRL_XFER_EN_TX; - if (!(i2s->reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { + regmap_read(i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); + reg = reg_ctrl | TEGRA30_I2S_CTRL_XFER_EN_TX; + if (!(reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { tegra_asoc_utils_clk_enable(&machine->util_data); + pm_runtime_get_sync(i2s->dev); + tegra30_ahub_enable_clocks(); tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif); regmap_write(i2s->regmap, TEGRA30_I2S_CTRL, reg); } @@ -890,17 +896,21 @@ void tegra_asoc_disable_clocks() { struct snd_soc_card *card = &snd_soc_tegra_rt5640; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + unsigned int reg_ctrl; int dcnt = 10; struct tegra30_i2s *i2s = i2s_tfa; if (!i2s || !machine) return; - if (!(i2s->reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { - regmap_write(i2s->regmap, TEGRA30_I2S_CTRL, i2s->reg_ctrl); + regmap_read(i2s->regmap, TEGRA30_I2S_CTRL, ®_ctrl); + if (!(reg_ctrl & TEGRA30_I2S_CTRL_XFER_EN_TX)) { + regmap_write(i2s->regmap, TEGRA30_I2S_CTRL, reg_ctrl); while (!tegra30_ahub_tx_fifo_is_empty(i2s->id) && dcnt--) udelay(100); tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif); + tegra30_ahub_disable_clocks(); + pm_runtime_put(i2s->dev); tegra_asoc_utils_clk_disable(&machine->util_data); } } @@ -1008,7 +1018,7 @@ static int tegra_rt5640_driver_probe(struct platform_device *pdev) PTR_ERR(machine->cdc_en)); machine->cdc_en = 0; } else { - regulator_enable(machine->cdc_en); + ret = regulator_enable(machine->cdc_en); } } |