1be944d42SStephen Warren /* 2be944d42SStephen Warren * tegra30_ahub.c - Tegra30 AHUB driver 3be944d42SStephen Warren * 4be944d42SStephen Warren * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved. 5be944d42SStephen Warren * 6be944d42SStephen Warren * This program is free software; you can redistribute it and/or modify it 7be944d42SStephen Warren * under the terms and conditions of the GNU General Public License, 8be944d42SStephen Warren * version 2, as published by the Free Software Foundation. 9be944d42SStephen Warren * 10be944d42SStephen Warren * This program is distributed in the hope it will be useful, but WITHOUT 11be944d42SStephen Warren * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12be944d42SStephen Warren * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13be944d42SStephen Warren * more details. 14be944d42SStephen Warren * 15be944d42SStephen Warren * You should have received a copy of the GNU General Public License 16be944d42SStephen Warren * along with this program. If not, see <http://www.gnu.org/licenses/>. 17be944d42SStephen Warren */ 18be944d42SStephen Warren 19be944d42SStephen Warren #include <linux/clk.h> 20be944d42SStephen Warren #include <linux/device.h> 21be944d42SStephen Warren #include <linux/io.h> 22be944d42SStephen Warren #include <linux/module.h> 23be944d42SStephen Warren #include <linux/of_platform.h> 24be944d42SStephen Warren #include <linux/platform_device.h> 25be944d42SStephen Warren #include <linux/pm_runtime.h> 26be944d42SStephen Warren #include <linux/regmap.h> 275185e0acSStephen Warren #include <linux/reset.h> 28be944d42SStephen Warren #include <linux/slab.h> 29be944d42SStephen Warren #include <sound/soc.h> 30be944d42SStephen Warren #include "tegra30_ahub.h" 31be944d42SStephen Warren 32be944d42SStephen Warren #define DRV_NAME "tegra30-ahub" 33be944d42SStephen Warren 34be944d42SStephen Warren static struct tegra30_ahub *ahub; 35be944d42SStephen Warren 36be944d42SStephen Warren static inline void tegra30_apbif_write(u32 reg, u32 val) 37be944d42SStephen Warren { 38be944d42SStephen Warren regmap_write(ahub->regmap_apbif, reg, val); 39be944d42SStephen Warren } 40be944d42SStephen Warren 41be944d42SStephen Warren static inline u32 tegra30_apbif_read(u32 reg) 42be944d42SStephen Warren { 43be944d42SStephen Warren u32 val; 44be944d42SStephen Warren regmap_read(ahub->regmap_apbif, reg, &val); 45be944d42SStephen Warren return val; 46be944d42SStephen Warren } 47be944d42SStephen Warren 48be944d42SStephen Warren static inline void tegra30_audio_write(u32 reg, u32 val) 49be944d42SStephen Warren { 50be944d42SStephen Warren regmap_write(ahub->regmap_ahub, reg, val); 51be944d42SStephen Warren } 52be944d42SStephen Warren 53be944d42SStephen Warren static int tegra30_ahub_runtime_suspend(struct device *dev) 54be944d42SStephen Warren { 55be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, true); 56be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, true); 57be944d42SStephen Warren 5865d2bdd3SPrashant Gaikwad clk_disable_unprepare(ahub->clk_apbif); 5965d2bdd3SPrashant Gaikwad clk_disable_unprepare(ahub->clk_d_audio); 60be944d42SStephen Warren 61be944d42SStephen Warren return 0; 62be944d42SStephen Warren } 63be944d42SStephen Warren 64be944d42SStephen Warren /* 65be944d42SStephen Warren * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data 66be944d42SStephen Warren * is read from or sent to memory. However, that's not something the rest of 67be944d42SStephen Warren * the driver supports right now, so we'll just treat the two clocks as one 68be944d42SStephen Warren * for now. 69be944d42SStephen Warren * 70be944d42SStephen Warren * These functions should not be a plain ref-count. Instead, each active stream 71be944d42SStephen Warren * contributes some requirement to the minimum clock rate, so starting or 72be944d42SStephen Warren * stopping streams should dynamically adjust the clock as required. However, 73be944d42SStephen Warren * this is not yet implemented. 74be944d42SStephen Warren */ 75be944d42SStephen Warren static int tegra30_ahub_runtime_resume(struct device *dev) 76be944d42SStephen Warren { 77be944d42SStephen Warren int ret; 78be944d42SStephen Warren 7965d2bdd3SPrashant Gaikwad ret = clk_prepare_enable(ahub->clk_d_audio); 80be944d42SStephen Warren if (ret) { 81be944d42SStephen Warren dev_err(dev, "clk_enable d_audio failed: %d\n", ret); 82be944d42SStephen Warren return ret; 83be944d42SStephen Warren } 8465d2bdd3SPrashant Gaikwad ret = clk_prepare_enable(ahub->clk_apbif); 85be944d42SStephen Warren if (ret) { 86be944d42SStephen Warren dev_err(dev, "clk_enable apbif failed: %d\n", ret); 87be944d42SStephen Warren clk_disable(ahub->clk_d_audio); 88be944d42SStephen Warren return ret; 89be944d42SStephen Warren } 90be944d42SStephen Warren 91be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, false); 92be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, false); 93be944d42SStephen Warren 94be944d42SStephen Warren return 0; 95be944d42SStephen Warren } 96be944d42SStephen Warren 97be944d42SStephen Warren int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, 985608bd3eSStephen Warren char *dmachan, int dmachan_len, 995608bd3eSStephen Warren dma_addr_t *fiforeg) 100be944d42SStephen Warren { 101be944d42SStephen Warren int channel; 102be944d42SStephen Warren u32 reg, val; 1035e049fceSStephen Warren struct tegra30_ahub_cif_conf cif_conf; 104be944d42SStephen Warren 105be944d42SStephen Warren channel = find_first_zero_bit(ahub->rx_usage, 106be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_COUNT); 107be944d42SStephen Warren if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) 108be944d42SStephen Warren return -EBUSY; 109be944d42SStephen Warren 110be944d42SStephen Warren __set_bit(channel, ahub->rx_usage); 111be944d42SStephen Warren 112be944d42SStephen Warren *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel; 1135608bd3eSStephen Warren snprintf(dmachan, dmachan_len, "rx%d", channel); 114be944d42SStephen Warren *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO + 115be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE); 116be944d42SStephen Warren 117768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 118768db0b9SStephen Warren 119be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 120be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 121be944d42SStephen Warren val = tegra30_apbif_read(reg); 122be944d42SStephen Warren val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | 123be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); 124be944d42SStephen Warren val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | 125be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | 126be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; 127be944d42SStephen Warren tegra30_apbif_write(reg, val); 128be944d42SStephen Warren 1295e049fceSStephen Warren cif_conf.threshold = 0; 1305e049fceSStephen Warren cif_conf.audio_channels = 2; 1315e049fceSStephen Warren cif_conf.client_channels = 2; 1325e049fceSStephen Warren cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; 1335e049fceSStephen Warren cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; 1345e049fceSStephen Warren cif_conf.expand = 0; 1355e049fceSStephen Warren cif_conf.stereo_conv = 0; 1365e049fceSStephen Warren cif_conf.replicate = 0; 1375e049fceSStephen Warren cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; 1385e049fceSStephen Warren cif_conf.truncate = 0; 1395e049fceSStephen Warren cif_conf.mono_conv = 0; 1405e049fceSStephen Warren 141be944d42SStephen Warren reg = TEGRA30_AHUB_CIF_RX_CTRL + 142be944d42SStephen Warren (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); 1435e049fceSStephen Warren ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); 144be944d42SStephen Warren 145768db0b9SStephen Warren pm_runtime_put(ahub->dev); 146768db0b9SStephen Warren 147be944d42SStephen Warren return 0; 148be944d42SStephen Warren } 149be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo); 150be944d42SStephen Warren 151be944d42SStephen Warren int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) 152be944d42SStephen Warren { 153be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 154be944d42SStephen Warren int reg, val; 155be944d42SStephen Warren 156768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 157768db0b9SStephen Warren 158be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 159be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 160be944d42SStephen Warren val = tegra30_apbif_read(reg); 161be944d42SStephen Warren val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; 162be944d42SStephen Warren tegra30_apbif_write(reg, val); 163be944d42SStephen Warren 164768db0b9SStephen Warren pm_runtime_put(ahub->dev); 165768db0b9SStephen Warren 166be944d42SStephen Warren return 0; 167be944d42SStephen Warren } 168be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo); 169be944d42SStephen Warren 170be944d42SStephen Warren int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif) 171be944d42SStephen Warren { 172be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 173be944d42SStephen Warren int reg, val; 174be944d42SStephen Warren 175768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 176768db0b9SStephen Warren 177be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 178be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 179be944d42SStephen Warren val = tegra30_apbif_read(reg); 180be944d42SStephen Warren val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; 181be944d42SStephen Warren tegra30_apbif_write(reg, val); 182be944d42SStephen Warren 183768db0b9SStephen Warren pm_runtime_put(ahub->dev); 184768db0b9SStephen Warren 185be944d42SStephen Warren return 0; 186be944d42SStephen Warren } 187be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo); 188be944d42SStephen Warren 189be944d42SStephen Warren int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif) 190be944d42SStephen Warren { 191be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 192be944d42SStephen Warren 193be944d42SStephen Warren __clear_bit(channel, ahub->rx_usage); 194be944d42SStephen Warren 195be944d42SStephen Warren return 0; 196be944d42SStephen Warren } 197be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); 198be944d42SStephen Warren 199be944d42SStephen Warren int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, 2005608bd3eSStephen Warren char *dmachan, int dmachan_len, 2015608bd3eSStephen Warren dma_addr_t *fiforeg) 202be944d42SStephen Warren { 203be944d42SStephen Warren int channel; 204be944d42SStephen Warren u32 reg, val; 2055e049fceSStephen Warren struct tegra30_ahub_cif_conf cif_conf; 206be944d42SStephen Warren 207be944d42SStephen Warren channel = find_first_zero_bit(ahub->tx_usage, 208be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_COUNT); 209be944d42SStephen Warren if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) 210be944d42SStephen Warren return -EBUSY; 211be944d42SStephen Warren 212be944d42SStephen Warren __set_bit(channel, ahub->tx_usage); 213be944d42SStephen Warren 214be944d42SStephen Warren *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel; 2155608bd3eSStephen Warren snprintf(dmachan, dmachan_len, "tx%d", channel); 216be944d42SStephen Warren *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO + 217be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE); 218be944d42SStephen Warren 219768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 220768db0b9SStephen Warren 221be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 222be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 223be944d42SStephen Warren val = tegra30_apbif_read(reg); 224be944d42SStephen Warren val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | 225be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); 226be944d42SStephen Warren val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | 227be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | 228be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; 229be944d42SStephen Warren tegra30_apbif_write(reg, val); 230be944d42SStephen Warren 2315e049fceSStephen Warren cif_conf.threshold = 0; 2325e049fceSStephen Warren cif_conf.audio_channels = 2; 2335e049fceSStephen Warren cif_conf.client_channels = 2; 2345e049fceSStephen Warren cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; 2355e049fceSStephen Warren cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; 2365e049fceSStephen Warren cif_conf.expand = 0; 2375e049fceSStephen Warren cif_conf.stereo_conv = 0; 2385e049fceSStephen Warren cif_conf.replicate = 0; 2395e049fceSStephen Warren cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; 2405e049fceSStephen Warren cif_conf.truncate = 0; 2415e049fceSStephen Warren cif_conf.mono_conv = 0; 2425e049fceSStephen Warren 243be944d42SStephen Warren reg = TEGRA30_AHUB_CIF_TX_CTRL + 244be944d42SStephen Warren (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); 2455e049fceSStephen Warren ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); 246be944d42SStephen Warren 247768db0b9SStephen Warren pm_runtime_put(ahub->dev); 248768db0b9SStephen Warren 249be944d42SStephen Warren return 0; 250be944d42SStephen Warren } 251be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo); 252be944d42SStephen Warren 253be944d42SStephen Warren int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif) 254be944d42SStephen Warren { 255be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 256be944d42SStephen Warren int reg, val; 257be944d42SStephen Warren 258768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 259768db0b9SStephen Warren 260be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 261be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 262be944d42SStephen Warren val = tegra30_apbif_read(reg); 263be944d42SStephen Warren val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; 264be944d42SStephen Warren tegra30_apbif_write(reg, val); 265be944d42SStephen Warren 266768db0b9SStephen Warren pm_runtime_put(ahub->dev); 267768db0b9SStephen Warren 268be944d42SStephen Warren return 0; 269be944d42SStephen Warren } 270be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo); 271be944d42SStephen Warren 272be944d42SStephen Warren int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif) 273be944d42SStephen Warren { 274be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 275be944d42SStephen Warren int reg, val; 276be944d42SStephen Warren 277768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 278768db0b9SStephen Warren 279be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 280be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 281be944d42SStephen Warren val = tegra30_apbif_read(reg); 282be944d42SStephen Warren val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; 283be944d42SStephen Warren tegra30_apbif_write(reg, val); 284be944d42SStephen Warren 285768db0b9SStephen Warren pm_runtime_put(ahub->dev); 286768db0b9SStephen Warren 287be944d42SStephen Warren return 0; 288be944d42SStephen Warren } 289be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo); 290be944d42SStephen Warren 291be944d42SStephen Warren int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif) 292be944d42SStephen Warren { 293be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 294be944d42SStephen Warren 295be944d42SStephen Warren __clear_bit(channel, ahub->tx_usage); 296be944d42SStephen Warren 297be944d42SStephen Warren return 0; 298be944d42SStephen Warren } 299be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo); 300be944d42SStephen Warren 301be944d42SStephen Warren int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, 302be944d42SStephen Warren enum tegra30_ahub_txcif txcif) 303be944d42SStephen Warren { 304be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 305be944d42SStephen Warren int reg; 306be944d42SStephen Warren 307768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 308768db0b9SStephen Warren 309be944d42SStephen Warren reg = TEGRA30_AHUB_AUDIO_RX + 310be944d42SStephen Warren (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); 311be944d42SStephen Warren tegra30_audio_write(reg, 1 << txcif); 312be944d42SStephen Warren 313768db0b9SStephen Warren pm_runtime_put(ahub->dev); 314768db0b9SStephen Warren 315be944d42SStephen Warren return 0; 316be944d42SStephen Warren } 317be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source); 318be944d42SStephen Warren 319be944d42SStephen Warren int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) 320be944d42SStephen Warren { 321be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 322be944d42SStephen Warren int reg; 323be944d42SStephen Warren 324768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 325768db0b9SStephen Warren 326be944d42SStephen Warren reg = TEGRA30_AHUB_AUDIO_RX + 327be944d42SStephen Warren (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); 328be944d42SStephen Warren tegra30_audio_write(reg, 0); 329be944d42SStephen Warren 330768db0b9SStephen Warren pm_runtime_put(ahub->dev); 331768db0b9SStephen Warren 332be944d42SStephen Warren return 0; 333be944d42SStephen Warren } 334be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); 335be944d42SStephen Warren 3365185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA30 BIT(0) 3375185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA114 BIT(1) 338f1d6ff79SStephen Warren #define MOD_LIST_MASK_TEGRA124 BIT(2) 33995d36075SStephen Warren 3405185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA30_OR_LATER \ 341f1d6ff79SStephen Warren (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \ 342f1d6ff79SStephen Warren MOD_LIST_MASK_TEGRA124) 343f1d6ff79SStephen Warren #define MOD_LIST_MASK_TEGRA114_OR_LATER \ 344f1d6ff79SStephen Warren (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124) 34595d36075SStephen Warren 34695d36075SStephen Warren static const struct { 3475185e0acSStephen Warren const char *rst_name; 3485185e0acSStephen Warren u32 mod_list_mask; 3495185e0acSStephen Warren } configlink_mods[] = { 3505185e0acSStephen Warren { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3515185e0acSStephen Warren { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3525185e0acSStephen Warren { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3535185e0acSStephen Warren { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3545185e0acSStephen Warren { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3555185e0acSStephen Warren { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3565185e0acSStephen Warren { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3575185e0acSStephen Warren { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3585185e0acSStephen Warren { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER }, 359f1d6ff79SStephen Warren { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER }, 360f1d6ff79SStephen Warren { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER }, 361f1d6ff79SStephen Warren { "amx1", MOD_LIST_MASK_TEGRA124 }, 362f1d6ff79SStephen Warren { "adx1", MOD_LIST_MASK_TEGRA124 }, 363f1d6ff79SStephen Warren { "afc0", MOD_LIST_MASK_TEGRA124 }, 364f1d6ff79SStephen Warren { "afc1", MOD_LIST_MASK_TEGRA124 }, 365f1d6ff79SStephen Warren { "afc2", MOD_LIST_MASK_TEGRA124 }, 366f1d6ff79SStephen Warren { "afc3", MOD_LIST_MASK_TEGRA124 }, 367f1d6ff79SStephen Warren { "afc4", MOD_LIST_MASK_TEGRA124 }, 368f1d6ff79SStephen Warren { "afc5", MOD_LIST_MASK_TEGRA124 }, 369be944d42SStephen Warren }; 370be944d42SStephen Warren 371be944d42SStephen Warren #define LAST_REG(name) \ 372be944d42SStephen Warren (TEGRA30_AHUB_##name + \ 373be944d42SStephen Warren (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4) 374be944d42SStephen Warren 375be944d42SStephen Warren #define REG_IN_ARRAY(reg, name) \ 376be944d42SStephen Warren ((reg >= TEGRA30_AHUB_##name) && \ 377be944d42SStephen Warren (reg <= LAST_REG(name) && \ 378be944d42SStephen Warren (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE)))) 379be944d42SStephen Warren 380be944d42SStephen Warren static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg) 381be944d42SStephen Warren { 382be944d42SStephen Warren switch (reg) { 383be944d42SStephen Warren case TEGRA30_AHUB_CONFIG_LINK_CTRL: 384be944d42SStephen Warren case TEGRA30_AHUB_MISC_CTRL: 385be944d42SStephen Warren case TEGRA30_AHUB_APBDMA_LIVE_STATUS: 386be944d42SStephen Warren case TEGRA30_AHUB_I2S_LIVE_STATUS: 387be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_LIVE_STATUS: 388be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_MASK: 389be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_MASK: 390be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_MASK: 391be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_MASK: 392be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_STATUS: 393be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_STATUS: 394be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_STATUS: 395be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_STATUS: 396be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SOURCE: 397be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SOURCE: 398be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SOURCE: 399be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SOURCE: 400be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SET: 401be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SET: 402be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SET: 403be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SET: 404be944d42SStephen Warren return true; 405be944d42SStephen Warren default: 406be944d42SStephen Warren break; 4071d198f26SJoe Perches } 408be944d42SStephen Warren 409be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_CTRL) || 410be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_CLEAR) || 411be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_STATUS) || 412be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 413be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO) || 414be944d42SStephen Warren REG_IN_ARRAY(reg, CIF_TX_CTRL) || 415be944d42SStephen Warren REG_IN_ARRAY(reg, CIF_RX_CTRL) || 416be944d42SStephen Warren REG_IN_ARRAY(reg, DAM_LIVE_STATUS)) 417be944d42SStephen Warren return true; 418be944d42SStephen Warren 419be944d42SStephen Warren return false; 420be944d42SStephen Warren } 421be944d42SStephen Warren 422be944d42SStephen Warren static bool tegra30_ahub_apbif_volatile_reg(struct device *dev, 423be944d42SStephen Warren unsigned int reg) 424be944d42SStephen Warren { 425be944d42SStephen Warren switch (reg) { 426be944d42SStephen Warren case TEGRA30_AHUB_CONFIG_LINK_CTRL: 427be944d42SStephen Warren case TEGRA30_AHUB_MISC_CTRL: 428be944d42SStephen Warren case TEGRA30_AHUB_APBDMA_LIVE_STATUS: 429be944d42SStephen Warren case TEGRA30_AHUB_I2S_LIVE_STATUS: 430be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_LIVE_STATUS: 431be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_STATUS: 432be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_STATUS: 433be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_STATUS: 434be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_STATUS: 435be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SET: 436be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SET: 437be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SET: 438be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SET: 439be944d42SStephen Warren return true; 440be944d42SStephen Warren default: 441be944d42SStephen Warren break; 4421d198f26SJoe Perches } 443be944d42SStephen Warren 444be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) || 445be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_STATUS) || 446be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 447be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO) || 448be944d42SStephen Warren REG_IN_ARRAY(reg, DAM_LIVE_STATUS)) 449be944d42SStephen Warren return true; 450be944d42SStephen Warren 451be944d42SStephen Warren return false; 452be944d42SStephen Warren } 453be944d42SStephen Warren 454be944d42SStephen Warren static bool tegra30_ahub_apbif_precious_reg(struct device *dev, 455be944d42SStephen Warren unsigned int reg) 456be944d42SStephen Warren { 457be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 458be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO)) 459be944d42SStephen Warren return true; 460be944d42SStephen Warren 461be944d42SStephen Warren return false; 462be944d42SStephen Warren } 463be944d42SStephen Warren 464be944d42SStephen Warren static const struct regmap_config tegra30_ahub_apbif_regmap_config = { 465be944d42SStephen Warren .name = "apbif", 466be944d42SStephen Warren .reg_bits = 32, 467be944d42SStephen Warren .val_bits = 32, 468be944d42SStephen Warren .reg_stride = 4, 469be944d42SStephen Warren .max_register = TEGRA30_AHUB_APBIF_INT_SET, 470be944d42SStephen Warren .writeable_reg = tegra30_ahub_apbif_wr_rd_reg, 471be944d42SStephen Warren .readable_reg = tegra30_ahub_apbif_wr_rd_reg, 472be944d42SStephen Warren .volatile_reg = tegra30_ahub_apbif_volatile_reg, 473be944d42SStephen Warren .precious_reg = tegra30_ahub_apbif_precious_reg, 474591d14f0SDylan Reid .cache_type = REGCACHE_FLAT, 475be944d42SStephen Warren }; 476be944d42SStephen Warren 477be944d42SStephen Warren static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg) 478be944d42SStephen Warren { 479be944d42SStephen Warren if (REG_IN_ARRAY(reg, AUDIO_RX)) 480be944d42SStephen Warren return true; 481be944d42SStephen Warren 482be944d42SStephen Warren return false; 483be944d42SStephen Warren } 484be944d42SStephen Warren 485be944d42SStephen Warren static const struct regmap_config tegra30_ahub_ahub_regmap_config = { 486be944d42SStephen Warren .name = "ahub", 487be944d42SStephen Warren .reg_bits = 32, 488be944d42SStephen Warren .val_bits = 32, 489be944d42SStephen Warren .reg_stride = 4, 490be944d42SStephen Warren .max_register = LAST_REG(AUDIO_RX), 491be944d42SStephen Warren .writeable_reg = tegra30_ahub_ahub_wr_rd_reg, 492be944d42SStephen Warren .readable_reg = tegra30_ahub_ahub_wr_rd_reg, 493591d14f0SDylan Reid .cache_type = REGCACHE_FLAT, 494be944d42SStephen Warren }; 495be944d42SStephen Warren 49695d36075SStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra30 = { 4975185e0acSStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA30, 4985e049fceSStephen Warren .set_audio_cif = tegra30_ahub_set_cif, 49995d36075SStephen Warren }; 50095d36075SStephen Warren 50195d36075SStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra114 = { 5025185e0acSStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA114, 5035e049fceSStephen Warren .set_audio_cif = tegra30_ahub_set_cif, 5045e049fceSStephen Warren }; 5055e049fceSStephen Warren 5065e049fceSStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra124 = { 507f1d6ff79SStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA124, 5085e049fceSStephen Warren .set_audio_cif = tegra124_ahub_set_cif, 50995d36075SStephen Warren }; 51095d36075SStephen Warren 51195d36075SStephen Warren static const struct of_device_id tegra30_ahub_of_match[] = { 5125e049fceSStephen Warren { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 }, 51395d36075SStephen Warren { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 }, 51495d36075SStephen Warren { .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 }, 51595d36075SStephen Warren {}, 51695d36075SStephen Warren }; 51795d36075SStephen Warren 5184652a0d0SBill Pemberton static int tegra30_ahub_probe(struct platform_device *pdev) 519be944d42SStephen Warren { 52095d36075SStephen Warren const struct of_device_id *match; 52195d36075SStephen Warren const struct tegra30_ahub_soc_data *soc_data; 5225185e0acSStephen Warren struct reset_control *rst; 523be944d42SStephen Warren int i; 524be944d42SStephen Warren struct resource *res0, *res1, *region; 525be944d42SStephen Warren void __iomem *regs_apbif, *regs_ahub; 526be944d42SStephen Warren int ret = 0; 527be944d42SStephen Warren 528be944d42SStephen Warren if (ahub) 529be944d42SStephen Warren return -ENODEV; 530be944d42SStephen Warren 53195d36075SStephen Warren match = of_match_device(tegra30_ahub_of_match, &pdev->dev); 53295d36075SStephen Warren if (!match) 53395d36075SStephen Warren return -EINVAL; 53495d36075SStephen Warren soc_data = match->data; 53595d36075SStephen Warren 536be944d42SStephen Warren /* 537be944d42SStephen Warren * The AHUB hosts a register bus: the "configlink". For this to 538be944d42SStephen Warren * operate correctly, all devices on this bus must be out of reset. 539be944d42SStephen Warren * Ensure that here. 540be944d42SStephen Warren */ 5415185e0acSStephen Warren for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) { 5425185e0acSStephen Warren if (!(configlink_mods[i].mod_list_mask & 5435185e0acSStephen Warren soc_data->mod_list_mask)) 54495d36075SStephen Warren continue; 5455185e0acSStephen Warren 5465185e0acSStephen Warren rst = reset_control_get(&pdev->dev, 5475185e0acSStephen Warren configlink_mods[i].rst_name); 5485185e0acSStephen Warren if (IS_ERR(rst)) { 5495185e0acSStephen Warren dev_err(&pdev->dev, "Can't get reset %s\n", 5505185e0acSStephen Warren configlink_mods[i].rst_name); 5515185e0acSStephen Warren ret = PTR_ERR(rst); 552be944d42SStephen Warren goto err; 553be944d42SStephen Warren } 5545185e0acSStephen Warren 5555185e0acSStephen Warren ret = reset_control_deassert(rst); 5565185e0acSStephen Warren reset_control_put(rst); 5575185e0acSStephen Warren if (ret) 5585185e0acSStephen Warren goto err; 559be944d42SStephen Warren } 560be944d42SStephen Warren 561be944d42SStephen Warren ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), 562be944d42SStephen Warren GFP_KERNEL); 563be944d42SStephen Warren if (!ahub) { 564be944d42SStephen Warren dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n"); 565be944d42SStephen Warren ret = -ENOMEM; 566be944d42SStephen Warren goto err; 567be944d42SStephen Warren } 568be944d42SStephen Warren dev_set_drvdata(&pdev->dev, ahub); 569be944d42SStephen Warren 5705e049fceSStephen Warren ahub->soc_data = soc_data; 571be944d42SStephen Warren ahub->dev = &pdev->dev; 572be944d42SStephen Warren 573be944d42SStephen Warren ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio"); 574be944d42SStephen Warren if (IS_ERR(ahub->clk_d_audio)) { 575be944d42SStephen Warren dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n"); 576be944d42SStephen Warren ret = PTR_ERR(ahub->clk_d_audio); 577be944d42SStephen Warren goto err; 578be944d42SStephen Warren } 579be944d42SStephen Warren 580be944d42SStephen Warren ahub->clk_apbif = clk_get(&pdev->dev, "apbif"); 581be944d42SStephen Warren if (IS_ERR(ahub->clk_apbif)) { 582be944d42SStephen Warren dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n"); 583be944d42SStephen Warren ret = PTR_ERR(ahub->clk_apbif); 584be944d42SStephen Warren goto err_clk_put_d_audio; 585be944d42SStephen Warren } 586be944d42SStephen Warren 587be944d42SStephen Warren res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 588be944d42SStephen Warren if (!res0) { 589be944d42SStephen Warren dev_err(&pdev->dev, "No apbif memory resource\n"); 590be944d42SStephen Warren ret = -ENODEV; 591be944d42SStephen Warren goto err_clk_put_apbif; 592be944d42SStephen Warren } 593be944d42SStephen Warren 594be944d42SStephen Warren region = devm_request_mem_region(&pdev->dev, res0->start, 595be944d42SStephen Warren resource_size(res0), DRV_NAME); 596be944d42SStephen Warren if (!region) { 597be944d42SStephen Warren dev_err(&pdev->dev, "request region apbif failed\n"); 598be944d42SStephen Warren ret = -EBUSY; 599be944d42SStephen Warren goto err_clk_put_apbif; 600be944d42SStephen Warren } 601be944d42SStephen Warren ahub->apbif_addr = res0->start; 602be944d42SStephen Warren 603be944d42SStephen Warren regs_apbif = devm_ioremap(&pdev->dev, res0->start, 604be944d42SStephen Warren resource_size(res0)); 605be944d42SStephen Warren if (!regs_apbif) { 606be944d42SStephen Warren dev_err(&pdev->dev, "ioremap apbif failed\n"); 607be944d42SStephen Warren ret = -ENOMEM; 608be944d42SStephen Warren goto err_clk_put_apbif; 609be944d42SStephen Warren } 610be944d42SStephen Warren 611be944d42SStephen Warren ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, 612be944d42SStephen Warren &tegra30_ahub_apbif_regmap_config); 613be944d42SStephen Warren if (IS_ERR(ahub->regmap_apbif)) { 614be944d42SStephen Warren dev_err(&pdev->dev, "apbif regmap init failed\n"); 615be944d42SStephen Warren ret = PTR_ERR(ahub->regmap_apbif); 616be944d42SStephen Warren goto err_clk_put_apbif; 617be944d42SStephen Warren } 618be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, true); 619be944d42SStephen Warren 620be944d42SStephen Warren res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 621be944d42SStephen Warren if (!res1) { 622be944d42SStephen Warren dev_err(&pdev->dev, "No ahub memory resource\n"); 623be944d42SStephen Warren ret = -ENODEV; 624be944d42SStephen Warren goto err_clk_put_apbif; 625be944d42SStephen Warren } 626be944d42SStephen Warren 627be944d42SStephen Warren region = devm_request_mem_region(&pdev->dev, res1->start, 628be944d42SStephen Warren resource_size(res1), DRV_NAME); 629be944d42SStephen Warren if (!region) { 630be944d42SStephen Warren dev_err(&pdev->dev, "request region ahub failed\n"); 631be944d42SStephen Warren ret = -EBUSY; 632be944d42SStephen Warren goto err_clk_put_apbif; 633be944d42SStephen Warren } 634be944d42SStephen Warren 635be944d42SStephen Warren regs_ahub = devm_ioremap(&pdev->dev, res1->start, 636be944d42SStephen Warren resource_size(res1)); 637be944d42SStephen Warren if (!regs_ahub) { 638be944d42SStephen Warren dev_err(&pdev->dev, "ioremap ahub failed\n"); 639be944d42SStephen Warren ret = -ENOMEM; 640be944d42SStephen Warren goto err_clk_put_apbif; 641be944d42SStephen Warren } 642be944d42SStephen Warren 643be944d42SStephen Warren ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, 644be944d42SStephen Warren &tegra30_ahub_ahub_regmap_config); 645be944d42SStephen Warren if (IS_ERR(ahub->regmap_ahub)) { 646be944d42SStephen Warren dev_err(&pdev->dev, "ahub regmap init failed\n"); 647be944d42SStephen Warren ret = PTR_ERR(ahub->regmap_ahub); 648be944d42SStephen Warren goto err_clk_put_apbif; 649be944d42SStephen Warren } 650be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, true); 651be944d42SStephen Warren 652be944d42SStephen Warren pm_runtime_enable(&pdev->dev); 653be944d42SStephen Warren if (!pm_runtime_enabled(&pdev->dev)) { 654be944d42SStephen Warren ret = tegra30_ahub_runtime_resume(&pdev->dev); 655be944d42SStephen Warren if (ret) 656be944d42SStephen Warren goto err_pm_disable; 657be944d42SStephen Warren } 658be944d42SStephen Warren 65979cf5918SPrashant Gaikwad of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 660be944d42SStephen Warren 661be944d42SStephen Warren return 0; 662be944d42SStephen Warren 663be944d42SStephen Warren err_pm_disable: 664be944d42SStephen Warren pm_runtime_disable(&pdev->dev); 665be944d42SStephen Warren err_clk_put_apbif: 666be944d42SStephen Warren clk_put(ahub->clk_apbif); 667be944d42SStephen Warren err_clk_put_d_audio: 668be944d42SStephen Warren clk_put(ahub->clk_d_audio); 669ecb2c174SSachin Kamat ahub = NULL; 670be944d42SStephen Warren err: 671be944d42SStephen Warren return ret; 672be944d42SStephen Warren } 673be944d42SStephen Warren 6744652a0d0SBill Pemberton static int tegra30_ahub_remove(struct platform_device *pdev) 675be944d42SStephen Warren { 676be944d42SStephen Warren if (!ahub) 677be944d42SStephen Warren return -ENODEV; 678be944d42SStephen Warren 679be944d42SStephen Warren pm_runtime_disable(&pdev->dev); 680be944d42SStephen Warren if (!pm_runtime_status_suspended(&pdev->dev)) 681be944d42SStephen Warren tegra30_ahub_runtime_suspend(&pdev->dev); 682be944d42SStephen Warren 683be944d42SStephen Warren clk_put(ahub->clk_apbif); 684be944d42SStephen Warren clk_put(ahub->clk_d_audio); 685be944d42SStephen Warren 686ecb2c174SSachin Kamat ahub = NULL; 687be944d42SStephen Warren 688be944d42SStephen Warren return 0; 689be944d42SStephen Warren } 690be944d42SStephen Warren 6912f41a3f4SStephen Warren #ifdef CONFIG_PM_SLEEP 6922f41a3f4SStephen Warren static int tegra30_ahub_suspend(struct device *dev) 6932f41a3f4SStephen Warren { 6942f41a3f4SStephen Warren regcache_mark_dirty(ahub->regmap_ahub); 6952f41a3f4SStephen Warren regcache_mark_dirty(ahub->regmap_apbif); 6962f41a3f4SStephen Warren 6972f41a3f4SStephen Warren return 0; 6982f41a3f4SStephen Warren } 6992f41a3f4SStephen Warren 7002f41a3f4SStephen Warren static int tegra30_ahub_resume(struct device *dev) 7012f41a3f4SStephen Warren { 7022f41a3f4SStephen Warren int ret; 7032f41a3f4SStephen Warren 704249e66c3SStephen Warren ret = pm_runtime_get_sync(dev); 705249e66c3SStephen Warren if (ret < 0) 706249e66c3SStephen Warren return ret; 7072f41a3f4SStephen Warren ret = regcache_sync(ahub->regmap_ahub); 7082f41a3f4SStephen Warren ret |= regcache_sync(ahub->regmap_apbif); 709249e66c3SStephen Warren pm_runtime_put(dev); 7102f41a3f4SStephen Warren 7112f41a3f4SStephen Warren return ret; 7122f41a3f4SStephen Warren } 7132f41a3f4SStephen Warren #endif 7142f41a3f4SStephen Warren 715f6e65744SBill Pemberton static const struct dev_pm_ops tegra30_ahub_pm_ops = { 716be944d42SStephen Warren SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, 717be944d42SStephen Warren tegra30_ahub_runtime_resume, NULL) 7182f41a3f4SStephen Warren SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume) 719be944d42SStephen Warren }; 720be944d42SStephen Warren 721be944d42SStephen Warren static struct platform_driver tegra30_ahub_driver = { 722be944d42SStephen Warren .probe = tegra30_ahub_probe, 7234652a0d0SBill Pemberton .remove = tegra30_ahub_remove, 724be944d42SStephen Warren .driver = { 725be944d42SStephen Warren .name = DRV_NAME, 726be944d42SStephen Warren .owner = THIS_MODULE, 727be944d42SStephen Warren .of_match_table = tegra30_ahub_of_match, 728be944d42SStephen Warren .pm = &tegra30_ahub_pm_ops, 729be944d42SStephen Warren }, 730be944d42SStephen Warren }; 731be944d42SStephen Warren module_platform_driver(tegra30_ahub_driver); 732be944d42SStephen Warren 7335e049fceSStephen Warren void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, 7345e049fceSStephen Warren struct tegra30_ahub_cif_conf *conf) 7355e049fceSStephen Warren { 7365e049fceSStephen Warren unsigned int value; 7375e049fceSStephen Warren 7385e049fceSStephen Warren value = (conf->threshold << 7395e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 7405e049fceSStephen Warren ((conf->audio_channels - 1) << 7415e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 7425e049fceSStephen Warren ((conf->client_channels - 1) << 7435e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 7445e049fceSStephen Warren (conf->audio_bits << 7455e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 7465e049fceSStephen Warren (conf->client_bits << 7475e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 7485e049fceSStephen Warren (conf->expand << 7495e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 7505e049fceSStephen Warren (conf->stereo_conv << 7515e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 7525e049fceSStephen Warren (conf->replicate << 7535e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 7545e049fceSStephen Warren (conf->direction << 7555e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 7565e049fceSStephen Warren (conf->truncate << 7575e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 7585e049fceSStephen Warren (conf->mono_conv << 7595e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 7605e049fceSStephen Warren 7615e049fceSStephen Warren regmap_write(regmap, reg, value); 7625e049fceSStephen Warren } 7635e049fceSStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif); 7645e049fceSStephen Warren 7655e049fceSStephen Warren void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, 7665e049fceSStephen Warren struct tegra30_ahub_cif_conf *conf) 7675e049fceSStephen Warren { 7685e049fceSStephen Warren unsigned int value; 7695e049fceSStephen Warren 7705e049fceSStephen Warren value = (conf->threshold << 7715e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 7725e049fceSStephen Warren ((conf->audio_channels - 1) << 7735e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 7745e049fceSStephen Warren ((conf->client_channels - 1) << 7755e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 7765e049fceSStephen Warren (conf->audio_bits << 7775e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 7785e049fceSStephen Warren (conf->client_bits << 7795e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 7805e049fceSStephen Warren (conf->expand << 7815e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 7825e049fceSStephen Warren (conf->stereo_conv << 7835e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 7845e049fceSStephen Warren (conf->replicate << 7855e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 7865e049fceSStephen Warren (conf->direction << 7875e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 7885e049fceSStephen Warren (conf->truncate << 7895e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 7905e049fceSStephen Warren (conf->mono_conv << 7915e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 7925e049fceSStephen Warren 7935e049fceSStephen Warren regmap_write(regmap, reg, value); 7945e049fceSStephen Warren } 7955e049fceSStephen Warren EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif); 7965e049fceSStephen Warren 797be944d42SStephen Warren MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 798be944d42SStephen Warren MODULE_DESCRIPTION("Tegra30 AHUB driver"); 799be944d42SStephen Warren MODULE_LICENSE("GPL v2"); 800be944d42SStephen Warren MODULE_ALIAS("platform:" DRV_NAME); 80169c5b753SStephen Warren MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match); 802