19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2be944d42SStephen Warren /* 3be944d42SStephen Warren * tegra30_ahub.c - Tegra30 AHUB driver 4be944d42SStephen Warren * 5be944d42SStephen Warren * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved. 6be944d42SStephen Warren */ 7be944d42SStephen Warren 8be944d42SStephen Warren #include <linux/clk.h> 9be944d42SStephen Warren #include <linux/device.h> 10be944d42SStephen Warren #include <linux/io.h> 11be944d42SStephen Warren #include <linux/module.h> 12be944d42SStephen Warren #include <linux/of_platform.h> 13be944d42SStephen Warren #include <linux/platform_device.h> 14be944d42SStephen Warren #include <linux/pm_runtime.h> 15be944d42SStephen Warren #include <linux/regmap.h> 165185e0acSStephen Warren #include <linux/reset.h> 17be944d42SStephen Warren #include <linux/slab.h> 18be944d42SStephen Warren #include <sound/soc.h> 19be944d42SStephen Warren #include "tegra30_ahub.h" 20be944d42SStephen Warren 21be944d42SStephen Warren #define DRV_NAME "tegra30-ahub" 22be944d42SStephen Warren 23be944d42SStephen Warren static struct tegra30_ahub *ahub; 24be944d42SStephen Warren 25be944d42SStephen Warren static inline void tegra30_apbif_write(u32 reg, u32 val) 26be944d42SStephen Warren { 27be944d42SStephen Warren regmap_write(ahub->regmap_apbif, reg, val); 28be944d42SStephen Warren } 29be944d42SStephen Warren 30be944d42SStephen Warren static inline u32 tegra30_apbif_read(u32 reg) 31be944d42SStephen Warren { 32be944d42SStephen Warren u32 val; 33bf3c6ef7SCodrut Grosu 34be944d42SStephen Warren regmap_read(ahub->regmap_apbif, reg, &val); 35be944d42SStephen Warren return val; 36be944d42SStephen Warren } 37be944d42SStephen Warren 38be944d42SStephen Warren static inline void tegra30_audio_write(u32 reg, u32 val) 39be944d42SStephen Warren { 40be944d42SStephen Warren regmap_write(ahub->regmap_ahub, reg, val); 41be944d42SStephen Warren } 42be944d42SStephen Warren 43be944d42SStephen Warren static int tegra30_ahub_runtime_suspend(struct device *dev) 44be944d42SStephen Warren { 45be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, true); 46be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, true); 47be944d42SStephen Warren 4865d2bdd3SPrashant Gaikwad clk_disable_unprepare(ahub->clk_apbif); 4965d2bdd3SPrashant Gaikwad clk_disable_unprepare(ahub->clk_d_audio); 50be944d42SStephen Warren 51be944d42SStephen Warren return 0; 52be944d42SStephen Warren } 53be944d42SStephen Warren 54be944d42SStephen Warren /* 55be944d42SStephen Warren * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data 56be944d42SStephen Warren * is read from or sent to memory. However, that's not something the rest of 57be944d42SStephen Warren * the driver supports right now, so we'll just treat the two clocks as one 58be944d42SStephen Warren * for now. 59be944d42SStephen Warren * 60be944d42SStephen Warren * These functions should not be a plain ref-count. Instead, each active stream 61be944d42SStephen Warren * contributes some requirement to the minimum clock rate, so starting or 62be944d42SStephen Warren * stopping streams should dynamically adjust the clock as required. However, 63be944d42SStephen Warren * this is not yet implemented. 64be944d42SStephen Warren */ 65be944d42SStephen Warren static int tegra30_ahub_runtime_resume(struct device *dev) 66be944d42SStephen Warren { 67be944d42SStephen Warren int ret; 68be944d42SStephen Warren 6965d2bdd3SPrashant Gaikwad ret = clk_prepare_enable(ahub->clk_d_audio); 70be944d42SStephen Warren if (ret) { 71be944d42SStephen Warren dev_err(dev, "clk_enable d_audio failed: %d\n", ret); 72be944d42SStephen Warren return ret; 73be944d42SStephen Warren } 7465d2bdd3SPrashant Gaikwad ret = clk_prepare_enable(ahub->clk_apbif); 75be944d42SStephen Warren if (ret) { 76be944d42SStephen Warren dev_err(dev, "clk_enable apbif failed: %d\n", ret); 77be944d42SStephen Warren clk_disable(ahub->clk_d_audio); 78be944d42SStephen Warren return ret; 79be944d42SStephen Warren } 80be944d42SStephen Warren 81be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, false); 82be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, false); 83be944d42SStephen Warren 84be944d42SStephen Warren return 0; 85be944d42SStephen Warren } 86be944d42SStephen Warren 87be944d42SStephen Warren int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, 885608bd3eSStephen Warren char *dmachan, int dmachan_len, 895608bd3eSStephen Warren dma_addr_t *fiforeg) 90be944d42SStephen Warren { 91be944d42SStephen Warren int channel; 92be944d42SStephen Warren u32 reg, val; 935e049fceSStephen Warren struct tegra30_ahub_cif_conf cif_conf; 94be944d42SStephen Warren 95be944d42SStephen Warren channel = find_first_zero_bit(ahub->rx_usage, 96be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_COUNT); 97be944d42SStephen Warren if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) 98be944d42SStephen Warren return -EBUSY; 99be944d42SStephen Warren 100be944d42SStephen Warren __set_bit(channel, ahub->rx_usage); 101be944d42SStephen Warren 102be944d42SStephen Warren *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel; 1035608bd3eSStephen Warren snprintf(dmachan, dmachan_len, "rx%d", channel); 104be944d42SStephen Warren *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO + 105be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE); 106be944d42SStephen Warren 107768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 108768db0b9SStephen Warren 109be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 110be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 111be944d42SStephen Warren val = tegra30_apbif_read(reg); 112be944d42SStephen Warren val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | 113be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); 114be944d42SStephen Warren val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | 115be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | 116be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; 117be944d42SStephen Warren tegra30_apbif_write(reg, val); 118be944d42SStephen Warren 1195e049fceSStephen Warren cif_conf.threshold = 0; 1205e049fceSStephen Warren cif_conf.audio_channels = 2; 1215e049fceSStephen Warren cif_conf.client_channels = 2; 1225e049fceSStephen Warren cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; 1235e049fceSStephen Warren cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; 1245e049fceSStephen Warren cif_conf.expand = 0; 1255e049fceSStephen Warren cif_conf.stereo_conv = 0; 1265e049fceSStephen Warren cif_conf.replicate = 0; 1275e049fceSStephen Warren cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; 1285e049fceSStephen Warren cif_conf.truncate = 0; 1295e049fceSStephen Warren cif_conf.mono_conv = 0; 1305e049fceSStephen Warren 131be944d42SStephen Warren reg = TEGRA30_AHUB_CIF_RX_CTRL + 132be944d42SStephen Warren (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); 1335e049fceSStephen Warren ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); 134be944d42SStephen Warren 135768db0b9SStephen Warren pm_runtime_put(ahub->dev); 136768db0b9SStephen Warren 137be944d42SStephen Warren return 0; 138be944d42SStephen Warren } 139be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo); 140be944d42SStephen Warren 141be944d42SStephen Warren int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) 142be944d42SStephen Warren { 143be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 144be944d42SStephen Warren int reg, val; 145be944d42SStephen Warren 146768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 147768db0b9SStephen Warren 148be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 149be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 150be944d42SStephen Warren val = tegra30_apbif_read(reg); 151be944d42SStephen Warren val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; 152be944d42SStephen Warren tegra30_apbif_write(reg, val); 153be944d42SStephen Warren 154768db0b9SStephen Warren pm_runtime_put(ahub->dev); 155768db0b9SStephen Warren 156be944d42SStephen Warren return 0; 157be944d42SStephen Warren } 158be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo); 159be944d42SStephen Warren 160be944d42SStephen Warren int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif) 161be944d42SStephen Warren { 162be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 163be944d42SStephen Warren int reg, val; 164be944d42SStephen Warren 165768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 166768db0b9SStephen Warren 167be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 168be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 169be944d42SStephen Warren val = tegra30_apbif_read(reg); 170be944d42SStephen Warren val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; 171be944d42SStephen Warren tegra30_apbif_write(reg, val); 172be944d42SStephen Warren 173768db0b9SStephen Warren pm_runtime_put(ahub->dev); 174768db0b9SStephen Warren 175be944d42SStephen Warren return 0; 176be944d42SStephen Warren } 177be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo); 178be944d42SStephen Warren 179be944d42SStephen Warren int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif) 180be944d42SStephen Warren { 181be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 182be944d42SStephen Warren 183be944d42SStephen Warren __clear_bit(channel, ahub->rx_usage); 184be944d42SStephen Warren 185be944d42SStephen Warren return 0; 186be944d42SStephen Warren } 187be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); 188be944d42SStephen Warren 189be944d42SStephen Warren int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, 1905608bd3eSStephen Warren char *dmachan, int dmachan_len, 1915608bd3eSStephen Warren dma_addr_t *fiforeg) 192be944d42SStephen Warren { 193be944d42SStephen Warren int channel; 194be944d42SStephen Warren u32 reg, val; 1955e049fceSStephen Warren struct tegra30_ahub_cif_conf cif_conf; 196be944d42SStephen Warren 197be944d42SStephen Warren channel = find_first_zero_bit(ahub->tx_usage, 198be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_COUNT); 199be944d42SStephen Warren if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) 200be944d42SStephen Warren return -EBUSY; 201be944d42SStephen Warren 202be944d42SStephen Warren __set_bit(channel, ahub->tx_usage); 203be944d42SStephen Warren 204be944d42SStephen Warren *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel; 2055608bd3eSStephen Warren snprintf(dmachan, dmachan_len, "tx%d", channel); 206be944d42SStephen Warren *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO + 207be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE); 208be944d42SStephen Warren 209768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 210768db0b9SStephen Warren 211be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 212be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 213be944d42SStephen Warren val = tegra30_apbif_read(reg); 214be944d42SStephen Warren val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | 215be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); 216be944d42SStephen Warren val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | 217be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | 218be944d42SStephen Warren TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; 219be944d42SStephen Warren tegra30_apbif_write(reg, val); 220be944d42SStephen Warren 2215e049fceSStephen Warren cif_conf.threshold = 0; 2225e049fceSStephen Warren cif_conf.audio_channels = 2; 2235e049fceSStephen Warren cif_conf.client_channels = 2; 2245e049fceSStephen Warren cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; 2255e049fceSStephen Warren cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; 2265e049fceSStephen Warren cif_conf.expand = 0; 2275e049fceSStephen Warren cif_conf.stereo_conv = 0; 2285e049fceSStephen Warren cif_conf.replicate = 0; 2295e049fceSStephen Warren cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; 2305e049fceSStephen Warren cif_conf.truncate = 0; 2315e049fceSStephen Warren cif_conf.mono_conv = 0; 2325e049fceSStephen Warren 233be944d42SStephen Warren reg = TEGRA30_AHUB_CIF_TX_CTRL + 234be944d42SStephen Warren (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); 2355e049fceSStephen Warren ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); 236be944d42SStephen Warren 237768db0b9SStephen Warren pm_runtime_put(ahub->dev); 238768db0b9SStephen Warren 239be944d42SStephen Warren return 0; 240be944d42SStephen Warren } 241be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo); 242be944d42SStephen Warren 243be944d42SStephen Warren int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif) 244be944d42SStephen Warren { 245be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 246be944d42SStephen Warren int reg, val; 247be944d42SStephen Warren 248768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 249768db0b9SStephen Warren 250be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 251be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 252be944d42SStephen Warren val = tegra30_apbif_read(reg); 253be944d42SStephen Warren val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; 254be944d42SStephen Warren tegra30_apbif_write(reg, val); 255be944d42SStephen Warren 256768db0b9SStephen Warren pm_runtime_put(ahub->dev); 257768db0b9SStephen Warren 258be944d42SStephen Warren return 0; 259be944d42SStephen Warren } 260be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo); 261be944d42SStephen Warren 262be944d42SStephen Warren int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif) 263be944d42SStephen Warren { 264be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 265be944d42SStephen Warren int reg, val; 266be944d42SStephen Warren 267768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 268768db0b9SStephen Warren 269be944d42SStephen Warren reg = TEGRA30_AHUB_CHANNEL_CTRL + 270be944d42SStephen Warren (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); 271be944d42SStephen Warren val = tegra30_apbif_read(reg); 272be944d42SStephen Warren val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; 273be944d42SStephen Warren tegra30_apbif_write(reg, val); 274be944d42SStephen Warren 275768db0b9SStephen Warren pm_runtime_put(ahub->dev); 276768db0b9SStephen Warren 277be944d42SStephen Warren return 0; 278be944d42SStephen Warren } 279be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo); 280be944d42SStephen Warren 281be944d42SStephen Warren int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif) 282be944d42SStephen Warren { 283be944d42SStephen Warren int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; 284be944d42SStephen Warren 285be944d42SStephen Warren __clear_bit(channel, ahub->tx_usage); 286be944d42SStephen Warren 287be944d42SStephen Warren return 0; 288be944d42SStephen Warren } 289be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo); 290be944d42SStephen Warren 291be944d42SStephen Warren int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, 292be944d42SStephen Warren enum tegra30_ahub_txcif txcif) 293be944d42SStephen Warren { 294be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 295be944d42SStephen Warren int reg; 296be944d42SStephen Warren 297768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 298768db0b9SStephen Warren 299be944d42SStephen Warren reg = TEGRA30_AHUB_AUDIO_RX + 300be944d42SStephen Warren (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); 301be944d42SStephen Warren tegra30_audio_write(reg, 1 << txcif); 302be944d42SStephen Warren 303768db0b9SStephen Warren pm_runtime_put(ahub->dev); 304768db0b9SStephen Warren 305be944d42SStephen Warren return 0; 306be944d42SStephen Warren } 307be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source); 308be944d42SStephen Warren 309be944d42SStephen Warren int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) 310be944d42SStephen Warren { 311be944d42SStephen Warren int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; 312be944d42SStephen Warren int reg; 313be944d42SStephen Warren 314768db0b9SStephen Warren pm_runtime_get_sync(ahub->dev); 315768db0b9SStephen Warren 316be944d42SStephen Warren reg = TEGRA30_AHUB_AUDIO_RX + 317be944d42SStephen Warren (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); 318be944d42SStephen Warren tegra30_audio_write(reg, 0); 319be944d42SStephen Warren 320768db0b9SStephen Warren pm_runtime_put(ahub->dev); 321768db0b9SStephen Warren 322be944d42SStephen Warren return 0; 323be944d42SStephen Warren } 324be944d42SStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); 325be944d42SStephen Warren 3265185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA30 BIT(0) 3275185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA114 BIT(1) 328f1d6ff79SStephen Warren #define MOD_LIST_MASK_TEGRA124 BIT(2) 32995d36075SStephen Warren 3305185e0acSStephen Warren #define MOD_LIST_MASK_TEGRA30_OR_LATER \ 331f1d6ff79SStephen Warren (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \ 332f1d6ff79SStephen Warren MOD_LIST_MASK_TEGRA124) 333f1d6ff79SStephen Warren #define MOD_LIST_MASK_TEGRA114_OR_LATER \ 334f1d6ff79SStephen Warren (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124) 33595d36075SStephen Warren 33695d36075SStephen Warren static const struct { 3375185e0acSStephen Warren const char *rst_name; 3385185e0acSStephen Warren u32 mod_list_mask; 3395185e0acSStephen Warren } configlink_mods[] = { 3405185e0acSStephen Warren { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3415185e0acSStephen Warren { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3425185e0acSStephen Warren { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3435185e0acSStephen Warren { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3445185e0acSStephen Warren { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3455185e0acSStephen Warren { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3465185e0acSStephen Warren { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3475185e0acSStephen Warren { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER }, 3485185e0acSStephen Warren { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER }, 349f1d6ff79SStephen Warren { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER }, 350f1d6ff79SStephen Warren { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER }, 351f1d6ff79SStephen Warren { "amx1", MOD_LIST_MASK_TEGRA124 }, 352f1d6ff79SStephen Warren { "adx1", MOD_LIST_MASK_TEGRA124 }, 353f1d6ff79SStephen Warren { "afc0", MOD_LIST_MASK_TEGRA124 }, 354f1d6ff79SStephen Warren { "afc1", MOD_LIST_MASK_TEGRA124 }, 355f1d6ff79SStephen Warren { "afc2", MOD_LIST_MASK_TEGRA124 }, 356f1d6ff79SStephen Warren { "afc3", MOD_LIST_MASK_TEGRA124 }, 357f1d6ff79SStephen Warren { "afc4", MOD_LIST_MASK_TEGRA124 }, 358f1d6ff79SStephen Warren { "afc5", MOD_LIST_MASK_TEGRA124 }, 359be944d42SStephen Warren }; 360be944d42SStephen Warren 361be944d42SStephen Warren #define LAST_REG(name) \ 362be944d42SStephen Warren (TEGRA30_AHUB_##name + \ 363be944d42SStephen Warren (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4) 364be944d42SStephen Warren 365be944d42SStephen Warren #define REG_IN_ARRAY(reg, name) \ 366be944d42SStephen Warren ((reg >= TEGRA30_AHUB_##name) && \ 367be944d42SStephen Warren (reg <= LAST_REG(name) && \ 368be944d42SStephen Warren (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE)))) 369be944d42SStephen Warren 370be944d42SStephen Warren static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg) 371be944d42SStephen Warren { 372be944d42SStephen Warren switch (reg) { 373be944d42SStephen Warren case TEGRA30_AHUB_CONFIG_LINK_CTRL: 374be944d42SStephen Warren case TEGRA30_AHUB_MISC_CTRL: 375be944d42SStephen Warren case TEGRA30_AHUB_APBDMA_LIVE_STATUS: 376be944d42SStephen Warren case TEGRA30_AHUB_I2S_LIVE_STATUS: 377be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_LIVE_STATUS: 378be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_MASK: 379be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_MASK: 380be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_MASK: 381be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_MASK: 382be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_STATUS: 383be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_STATUS: 384be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_STATUS: 385be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_STATUS: 386be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SOURCE: 387be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SOURCE: 388be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SOURCE: 389be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SOURCE: 390be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SET: 391be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SET: 392be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SET: 393be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SET: 394be944d42SStephen Warren return true; 395be944d42SStephen Warren default: 396be944d42SStephen Warren break; 3971d198f26SJoe Perches } 398be944d42SStephen Warren 399be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_CTRL) || 400be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_CLEAR) || 401be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_STATUS) || 402be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 403be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO) || 404be944d42SStephen Warren REG_IN_ARRAY(reg, CIF_TX_CTRL) || 405be944d42SStephen Warren REG_IN_ARRAY(reg, CIF_RX_CTRL) || 406be944d42SStephen Warren REG_IN_ARRAY(reg, DAM_LIVE_STATUS)) 407be944d42SStephen Warren return true; 408be944d42SStephen Warren 409be944d42SStephen Warren return false; 410be944d42SStephen Warren } 411be944d42SStephen Warren 412be944d42SStephen Warren static bool tegra30_ahub_apbif_volatile_reg(struct device *dev, 413be944d42SStephen Warren unsigned int reg) 414be944d42SStephen Warren { 415be944d42SStephen Warren switch (reg) { 416be944d42SStephen Warren case TEGRA30_AHUB_CONFIG_LINK_CTRL: 417be944d42SStephen Warren case TEGRA30_AHUB_MISC_CTRL: 418be944d42SStephen Warren case TEGRA30_AHUB_APBDMA_LIVE_STATUS: 419be944d42SStephen Warren case TEGRA30_AHUB_I2S_LIVE_STATUS: 420be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_LIVE_STATUS: 421be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_STATUS: 422be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_STATUS: 423be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_STATUS: 424be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_STATUS: 425be944d42SStephen Warren case TEGRA30_AHUB_I2S_INT_SET: 426be944d42SStephen Warren case TEGRA30_AHUB_DAM_INT_SET: 427be944d42SStephen Warren case TEGRA30_AHUB_SPDIF_INT_SET: 428be944d42SStephen Warren case TEGRA30_AHUB_APBIF_INT_SET: 429be944d42SStephen Warren return true; 430be944d42SStephen Warren default: 431be944d42SStephen Warren break; 4321d198f26SJoe Perches } 433be944d42SStephen Warren 434be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) || 435be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_STATUS) || 436be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 437be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO) || 438be944d42SStephen Warren REG_IN_ARRAY(reg, DAM_LIVE_STATUS)) 439be944d42SStephen Warren return true; 440be944d42SStephen Warren 441be944d42SStephen Warren return false; 442be944d42SStephen Warren } 443be944d42SStephen Warren 444be944d42SStephen Warren static bool tegra30_ahub_apbif_precious_reg(struct device *dev, 445be944d42SStephen Warren unsigned int reg) 446be944d42SStephen Warren { 447be944d42SStephen Warren if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) || 448be944d42SStephen Warren REG_IN_ARRAY(reg, CHANNEL_RXFIFO)) 449be944d42SStephen Warren return true; 450be944d42SStephen Warren 451be944d42SStephen Warren return false; 452be944d42SStephen Warren } 453be944d42SStephen Warren 454be944d42SStephen Warren static const struct regmap_config tegra30_ahub_apbif_regmap_config = { 455be944d42SStephen Warren .name = "apbif", 456be944d42SStephen Warren .reg_bits = 32, 457be944d42SStephen Warren .val_bits = 32, 458be944d42SStephen Warren .reg_stride = 4, 459be944d42SStephen Warren .max_register = TEGRA30_AHUB_APBIF_INT_SET, 460be944d42SStephen Warren .writeable_reg = tegra30_ahub_apbif_wr_rd_reg, 461be944d42SStephen Warren .readable_reg = tegra30_ahub_apbif_wr_rd_reg, 462be944d42SStephen Warren .volatile_reg = tegra30_ahub_apbif_volatile_reg, 463be944d42SStephen Warren .precious_reg = tegra30_ahub_apbif_precious_reg, 464591d14f0SDylan Reid .cache_type = REGCACHE_FLAT, 465be944d42SStephen Warren }; 466be944d42SStephen Warren 467be944d42SStephen Warren static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg) 468be944d42SStephen Warren { 469be944d42SStephen Warren if (REG_IN_ARRAY(reg, AUDIO_RX)) 470be944d42SStephen Warren return true; 471be944d42SStephen Warren 472be944d42SStephen Warren return false; 473be944d42SStephen Warren } 474be944d42SStephen Warren 475be944d42SStephen Warren static const struct regmap_config tegra30_ahub_ahub_regmap_config = { 476be944d42SStephen Warren .name = "ahub", 477be944d42SStephen Warren .reg_bits = 32, 478be944d42SStephen Warren .val_bits = 32, 479be944d42SStephen Warren .reg_stride = 4, 480be944d42SStephen Warren .max_register = LAST_REG(AUDIO_RX), 481be944d42SStephen Warren .writeable_reg = tegra30_ahub_ahub_wr_rd_reg, 482be944d42SStephen Warren .readable_reg = tegra30_ahub_ahub_wr_rd_reg, 483591d14f0SDylan Reid .cache_type = REGCACHE_FLAT, 484be944d42SStephen Warren }; 485be944d42SStephen Warren 48695d36075SStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra30 = { 4875185e0acSStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA30, 4885e049fceSStephen Warren .set_audio_cif = tegra30_ahub_set_cif, 48995d36075SStephen Warren }; 49095d36075SStephen Warren 49195d36075SStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra114 = { 4925185e0acSStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA114, 4935e049fceSStephen Warren .set_audio_cif = tegra30_ahub_set_cif, 4945e049fceSStephen Warren }; 4955e049fceSStephen Warren 4965e049fceSStephen Warren static struct tegra30_ahub_soc_data soc_data_tegra124 = { 497f1d6ff79SStephen Warren .mod_list_mask = MOD_LIST_MASK_TEGRA124, 4985e049fceSStephen Warren .set_audio_cif = tegra124_ahub_set_cif, 49995d36075SStephen Warren }; 50095d36075SStephen Warren 50195d36075SStephen Warren static const struct of_device_id tegra30_ahub_of_match[] = { 5025e049fceSStephen Warren { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 }, 50395d36075SStephen Warren { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 }, 50495d36075SStephen Warren { .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 }, 50595d36075SStephen Warren {}, 50695d36075SStephen Warren }; 50795d36075SStephen Warren 5084652a0d0SBill Pemberton static int tegra30_ahub_probe(struct platform_device *pdev) 509be944d42SStephen Warren { 51095d36075SStephen Warren const struct of_device_id *match; 51195d36075SStephen Warren const struct tegra30_ahub_soc_data *soc_data; 5125185e0acSStephen Warren struct reset_control *rst; 513be944d42SStephen Warren int i; 514a813d0e8SYueHaibing struct resource *res0; 515be944d42SStephen Warren void __iomem *regs_apbif, *regs_ahub; 516be944d42SStephen Warren int ret = 0; 517be944d42SStephen Warren 518be944d42SStephen Warren if (ahub) 519be944d42SStephen Warren return -ENODEV; 520be944d42SStephen Warren 52195d36075SStephen Warren match = of_match_device(tegra30_ahub_of_match, &pdev->dev); 52295d36075SStephen Warren if (!match) 52395d36075SStephen Warren return -EINVAL; 52495d36075SStephen Warren soc_data = match->data; 52595d36075SStephen Warren 526be944d42SStephen Warren /* 527be944d42SStephen Warren * The AHUB hosts a register bus: the "configlink". For this to 528be944d42SStephen Warren * operate correctly, all devices on this bus must be out of reset. 529be944d42SStephen Warren * Ensure that here. 530be944d42SStephen Warren */ 5315185e0acSStephen Warren for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) { 5325185e0acSStephen Warren if (!(configlink_mods[i].mod_list_mask & 5335185e0acSStephen Warren soc_data->mod_list_mask)) 53495d36075SStephen Warren continue; 5355185e0acSStephen Warren 536181e8ce6SPhilipp Zabel rst = reset_control_get_exclusive(&pdev->dev, 5375185e0acSStephen Warren configlink_mods[i].rst_name); 5385185e0acSStephen Warren if (IS_ERR(rst)) { 5395185e0acSStephen Warren dev_err(&pdev->dev, "Can't get reset %s\n", 5405185e0acSStephen Warren configlink_mods[i].rst_name); 5415185e0acSStephen Warren ret = PTR_ERR(rst); 5428833c01aSVaishali Thakkar return ret; 543be944d42SStephen Warren } 5445185e0acSStephen Warren 5455185e0acSStephen Warren ret = reset_control_deassert(rst); 5465185e0acSStephen Warren reset_control_put(rst); 5475185e0acSStephen Warren if (ret) 5488833c01aSVaishali Thakkar return ret; 549be944d42SStephen Warren } 550be944d42SStephen Warren 551be944d42SStephen Warren ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), 552be944d42SStephen Warren GFP_KERNEL); 553e2c187a6SCodrut Grosu if (!ahub) 5548833c01aSVaishali Thakkar return -ENOMEM; 555be944d42SStephen Warren dev_set_drvdata(&pdev->dev, ahub); 556be944d42SStephen Warren 5575e049fceSStephen Warren ahub->soc_data = soc_data; 558be944d42SStephen Warren ahub->dev = &pdev->dev; 559be944d42SStephen Warren 5608833c01aSVaishali Thakkar ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio"); 561be944d42SStephen Warren if (IS_ERR(ahub->clk_d_audio)) { 562be944d42SStephen Warren dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n"); 563be944d42SStephen Warren ret = PTR_ERR(ahub->clk_d_audio); 5648833c01aSVaishali Thakkar return ret; 565be944d42SStephen Warren } 566be944d42SStephen Warren 5678833c01aSVaishali Thakkar ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif"); 568be944d42SStephen Warren if (IS_ERR(ahub->clk_apbif)) { 569be944d42SStephen Warren dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n"); 570be944d42SStephen Warren ret = PTR_ERR(ahub->clk_apbif); 5718833c01aSVaishali Thakkar return ret; 572be944d42SStephen Warren } 573be944d42SStephen Warren 574be944d42SStephen Warren res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 575f57ddcdfSAxel Lin regs_apbif = devm_ioremap_resource(&pdev->dev, res0); 576f57ddcdfSAxel Lin if (IS_ERR(regs_apbif)) 577f57ddcdfSAxel Lin return PTR_ERR(regs_apbif); 578be944d42SStephen Warren 579be944d42SStephen Warren ahub->apbif_addr = res0->start; 580be944d42SStephen Warren 581be944d42SStephen Warren ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, 582be944d42SStephen Warren &tegra30_ahub_apbif_regmap_config); 583be944d42SStephen Warren if (IS_ERR(ahub->regmap_apbif)) { 584be944d42SStephen Warren dev_err(&pdev->dev, "apbif regmap init failed\n"); 585be944d42SStephen Warren ret = PTR_ERR(ahub->regmap_apbif); 5868833c01aSVaishali Thakkar return ret; 587be944d42SStephen Warren } 588be944d42SStephen Warren regcache_cache_only(ahub->regmap_apbif, true); 589be944d42SStephen Warren 590a813d0e8SYueHaibing regs_ahub = devm_platform_ioremap_resource(pdev, 1); 591f57ddcdfSAxel Lin if (IS_ERR(regs_ahub)) 592f57ddcdfSAxel Lin return PTR_ERR(regs_ahub); 593be944d42SStephen Warren 594be944d42SStephen Warren ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, 595be944d42SStephen Warren &tegra30_ahub_ahub_regmap_config); 596be944d42SStephen Warren if (IS_ERR(ahub->regmap_ahub)) { 597be944d42SStephen Warren dev_err(&pdev->dev, "ahub regmap init failed\n"); 598be944d42SStephen Warren ret = PTR_ERR(ahub->regmap_ahub); 5998833c01aSVaishali Thakkar return ret; 600be944d42SStephen Warren } 601be944d42SStephen Warren regcache_cache_only(ahub->regmap_ahub, true); 602be944d42SStephen Warren 603be944d42SStephen Warren pm_runtime_enable(&pdev->dev); 604be944d42SStephen Warren if (!pm_runtime_enabled(&pdev->dev)) { 605be944d42SStephen Warren ret = tegra30_ahub_runtime_resume(&pdev->dev); 606be944d42SStephen Warren if (ret) 607be944d42SStephen Warren goto err_pm_disable; 608be944d42SStephen Warren } 609be944d42SStephen Warren 61079cf5918SPrashant Gaikwad of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 611be944d42SStephen Warren 612be944d42SStephen Warren return 0; 613be944d42SStephen Warren 614be944d42SStephen Warren err_pm_disable: 615be944d42SStephen Warren pm_runtime_disable(&pdev->dev); 6168833c01aSVaishali Thakkar 617be944d42SStephen Warren return ret; 618be944d42SStephen Warren } 619be944d42SStephen Warren 6204652a0d0SBill Pemberton static int tegra30_ahub_remove(struct platform_device *pdev) 621be944d42SStephen Warren { 622be944d42SStephen Warren if (!ahub) 623be944d42SStephen Warren return -ENODEV; 624be944d42SStephen Warren 625be944d42SStephen Warren pm_runtime_disable(&pdev->dev); 626be944d42SStephen Warren if (!pm_runtime_status_suspended(&pdev->dev)) 627be944d42SStephen Warren tegra30_ahub_runtime_suspend(&pdev->dev); 628be944d42SStephen Warren 629be944d42SStephen Warren return 0; 630be944d42SStephen Warren } 631be944d42SStephen Warren 6322f41a3f4SStephen Warren #ifdef CONFIG_PM_SLEEP 6332f41a3f4SStephen Warren static int tegra30_ahub_suspend(struct device *dev) 6342f41a3f4SStephen Warren { 6352f41a3f4SStephen Warren regcache_mark_dirty(ahub->regmap_ahub); 6362f41a3f4SStephen Warren regcache_mark_dirty(ahub->regmap_apbif); 6372f41a3f4SStephen Warren 6382f41a3f4SStephen Warren return 0; 6392f41a3f4SStephen Warren } 6402f41a3f4SStephen Warren 6412f41a3f4SStephen Warren static int tegra30_ahub_resume(struct device *dev) 6422f41a3f4SStephen Warren { 6432f41a3f4SStephen Warren int ret; 6442f41a3f4SStephen Warren 645249e66c3SStephen Warren ret = pm_runtime_get_sync(dev); 646*deca1953SQiushi Wu if (ret < 0) { 647*deca1953SQiushi Wu pm_runtime_put(dev); 648249e66c3SStephen Warren return ret; 649*deca1953SQiushi Wu } 6502f41a3f4SStephen Warren ret = regcache_sync(ahub->regmap_ahub); 6512f41a3f4SStephen Warren ret |= regcache_sync(ahub->regmap_apbif); 652249e66c3SStephen Warren pm_runtime_put(dev); 6532f41a3f4SStephen Warren 6542f41a3f4SStephen Warren return ret; 6552f41a3f4SStephen Warren } 6562f41a3f4SStephen Warren #endif 6572f41a3f4SStephen Warren 658f6e65744SBill Pemberton static const struct dev_pm_ops tegra30_ahub_pm_ops = { 659be944d42SStephen Warren SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, 660be944d42SStephen Warren tegra30_ahub_runtime_resume, NULL) 6612f41a3f4SStephen Warren SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume) 662be944d42SStephen Warren }; 663be944d42SStephen Warren 664be944d42SStephen Warren static struct platform_driver tegra30_ahub_driver = { 665be944d42SStephen Warren .probe = tegra30_ahub_probe, 6664652a0d0SBill Pemberton .remove = tegra30_ahub_remove, 667be944d42SStephen Warren .driver = { 668be944d42SStephen Warren .name = DRV_NAME, 669be944d42SStephen Warren .of_match_table = tegra30_ahub_of_match, 670be944d42SStephen Warren .pm = &tegra30_ahub_pm_ops, 671be944d42SStephen Warren }, 672be944d42SStephen Warren }; 673be944d42SStephen Warren module_platform_driver(tegra30_ahub_driver); 674be944d42SStephen Warren 6755e049fceSStephen Warren void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, 6765e049fceSStephen Warren struct tegra30_ahub_cif_conf *conf) 6775e049fceSStephen Warren { 6785e049fceSStephen Warren unsigned int value; 6795e049fceSStephen Warren 6805e049fceSStephen Warren value = (conf->threshold << 6815e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 6825e049fceSStephen Warren ((conf->audio_channels - 1) << 6835e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 6845e049fceSStephen Warren ((conf->client_channels - 1) << 6855e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 6865e049fceSStephen Warren (conf->audio_bits << 6875e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 6885e049fceSStephen Warren (conf->client_bits << 6895e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 6905e049fceSStephen Warren (conf->expand << 6915e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 6925e049fceSStephen Warren (conf->stereo_conv << 6935e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 6945e049fceSStephen Warren (conf->replicate << 6955e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 6965e049fceSStephen Warren (conf->direction << 6975e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 6985e049fceSStephen Warren (conf->truncate << 6995e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 7005e049fceSStephen Warren (conf->mono_conv << 7015e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 7025e049fceSStephen Warren 7035e049fceSStephen Warren regmap_write(regmap, reg, value); 7045e049fceSStephen Warren } 7055e049fceSStephen Warren EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif); 7065e049fceSStephen Warren 7075e049fceSStephen Warren void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, 7085e049fceSStephen Warren struct tegra30_ahub_cif_conf *conf) 7095e049fceSStephen Warren { 7105e049fceSStephen Warren unsigned int value; 7115e049fceSStephen Warren 7125e049fceSStephen Warren value = (conf->threshold << 7135e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | 7145e049fceSStephen Warren ((conf->audio_channels - 1) << 7155e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | 7165e049fceSStephen Warren ((conf->client_channels - 1) << 7175e049fceSStephen Warren TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | 7185e049fceSStephen Warren (conf->audio_bits << 7195e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | 7205e049fceSStephen Warren (conf->client_bits << 7215e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | 7225e049fceSStephen Warren (conf->expand << 7235e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | 7245e049fceSStephen Warren (conf->stereo_conv << 7255e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | 7265e049fceSStephen Warren (conf->replicate << 7275e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) | 7285e049fceSStephen Warren (conf->direction << 7295e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | 7305e049fceSStephen Warren (conf->truncate << 7315e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | 7325e049fceSStephen Warren (conf->mono_conv << 7335e049fceSStephen Warren TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT); 7345e049fceSStephen Warren 7355e049fceSStephen Warren regmap_write(regmap, reg, value); 7365e049fceSStephen Warren } 7375e049fceSStephen Warren EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif); 7385e049fceSStephen Warren 739be944d42SStephen Warren MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 740be944d42SStephen Warren MODULE_DESCRIPTION("Tegra30 AHUB driver"); 741be944d42SStephen Warren MODULE_LICENSE("GPL v2"); 742be944d42SStephen Warren MODULE_ALIAS("platform:" DRV_NAME); 74369c5b753SStephen Warren MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match); 744