^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * tegra30_ahub.c - Tegra30 AHUB driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "tegra30_ahub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define DRV_NAME "tegra30-ahub"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static struct tegra30_ahub *ahub;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static inline void tegra30_apbif_write(u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) regmap_write(ahub->regmap_apbif, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static inline u32 tegra30_apbif_read(u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) regmap_read(ahub->regmap_apbif, reg, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static inline void tegra30_audio_write(u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) regmap_write(ahub->regmap_ahub, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int tegra30_ahub_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) regcache_cache_only(ahub->regmap_apbif, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) regcache_cache_only(ahub->regmap_ahub, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) clk_disable_unprepare(ahub->clk_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) clk_disable_unprepare(ahub->clk_d_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * is read from or sent to memory. However, that's not something the rest of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * the driver supports right now, so we'll just treat the two clocks as one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * These functions should not be a plain ref-count. Instead, each active stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * contributes some requirement to the minimum clock rate, so starting or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * stopping streams should dynamically adjust the clock as required. However,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * this is not yet implemented.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int tegra30_ahub_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ret = clk_prepare_enable(ahub->clk_d_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ret = clk_prepare_enable(ahub->clk_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) dev_err(dev, "clk_enable apbif failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) clk_disable(ahub->clk_d_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) regcache_cache_only(ahub->regmap_apbif, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) regcache_cache_only(ahub->regmap_ahub, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) char *dmachan, int dmachan_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dma_addr_t *fiforeg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct tegra30_ahub_cif_conf cif_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) channel = find_first_zero_bit(ahub->rx_usage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) __set_bit(channel, ahub->rx_usage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) snprintf(dmachan, dmachan_len, "rx%d", channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) cif_conf.threshold = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) cif_conf.audio_channels = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) cif_conf.client_channels = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) cif_conf.expand = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) cif_conf.stereo_conv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) cif_conf.replicate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) cif_conf.truncate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) cif_conf.mono_conv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) reg = TEGRA30_AHUB_CIF_RX_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) __clear_bit(channel, ahub->rx_usage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) char *dmachan, int dmachan_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) dma_addr_t *fiforeg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) int channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u32 reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct tegra30_ahub_cif_conf cif_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) channel = find_first_zero_bit(ahub->tx_usage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) __set_bit(channel, ahub->tx_usage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) snprintf(dmachan, dmachan_len, "tx%d", channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) cif_conf.threshold = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) cif_conf.audio_channels = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) cif_conf.client_channels = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) cif_conf.expand = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) cif_conf.stereo_conv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) cif_conf.replicate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) cif_conf.truncate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cif_conf.mono_conv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) reg = TEGRA30_AHUB_CIF_TX_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) int reg, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) reg = TEGRA30_AHUB_CHANNEL_CTRL +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) val = tegra30_apbif_read(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) tegra30_apbif_write(reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) __clear_bit(channel, ahub->tx_usage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) enum tegra30_ahub_txcif txcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) reg = TEGRA30_AHUB_AUDIO_RX +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) tegra30_audio_write(reg, 1 << txcif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) pm_runtime_get_sync(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) reg = TEGRA30_AHUB_AUDIO_RX +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) tegra30_audio_write(reg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) pm_runtime_put(ahub->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) #define MOD_LIST_MASK_TEGRA30 BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) #define MOD_LIST_MASK_TEGRA114 BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) #define MOD_LIST_MASK_TEGRA124 BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) #define MOD_LIST_MASK_TEGRA30_OR_LATER \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) MOD_LIST_MASK_TEGRA124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) #define MOD_LIST_MASK_TEGRA114_OR_LATER \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) const char *rst_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) u32 mod_list_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } configlink_mods[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) { "amx1", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) { "adx1", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) { "afc0", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) { "afc1", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) { "afc2", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) { "afc3", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) { "afc4", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) { "afc5", MOD_LIST_MASK_TEGRA124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) #define LAST_REG(name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) (TEGRA30_AHUB_##name + \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) #define REG_IN_ARRAY(reg, name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) ((reg >= TEGRA30_AHUB_##name) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) (reg <= LAST_REG(name) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) case TEGRA30_AHUB_CONFIG_LINK_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case TEGRA30_AHUB_MISC_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) case TEGRA30_AHUB_I2S_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) case TEGRA30_AHUB_I2S_INT_MASK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) case TEGRA30_AHUB_DAM_INT_MASK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) case TEGRA30_AHUB_SPDIF_INT_MASK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) case TEGRA30_AHUB_APBIF_INT_MASK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) case TEGRA30_AHUB_I2S_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) case TEGRA30_AHUB_DAM_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) case TEGRA30_AHUB_SPDIF_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) case TEGRA30_AHUB_APBIF_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) case TEGRA30_AHUB_I2S_INT_SOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) case TEGRA30_AHUB_DAM_INT_SOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) case TEGRA30_AHUB_SPDIF_INT_SOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) case TEGRA30_AHUB_APBIF_INT_SOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) case TEGRA30_AHUB_I2S_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) case TEGRA30_AHUB_DAM_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) case TEGRA30_AHUB_SPDIF_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) case TEGRA30_AHUB_APBIF_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) case TEGRA30_AHUB_CONFIG_LINK_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) case TEGRA30_AHUB_MISC_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) case TEGRA30_AHUB_I2S_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) case TEGRA30_AHUB_I2S_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) case TEGRA30_AHUB_DAM_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case TEGRA30_AHUB_SPDIF_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) case TEGRA30_AHUB_APBIF_INT_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) case TEGRA30_AHUB_I2S_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) case TEGRA30_AHUB_DAM_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) case TEGRA30_AHUB_SPDIF_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) case TEGRA30_AHUB_APBIF_INT_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) .name = "apbif",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) .max_register = TEGRA30_AHUB_APBIF_INT_SET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) .volatile_reg = tegra30_ahub_apbif_volatile_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) .precious_reg = tegra30_ahub_apbif_precious_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) .cache_type = REGCACHE_FLAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (REG_IN_ARRAY(reg, AUDIO_RX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) .name = "ahub",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) .max_register = LAST_REG(AUDIO_RX),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) .cache_type = REGCACHE_FLAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static struct tegra30_ahub_soc_data soc_data_tegra30 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) .mod_list_mask = MOD_LIST_MASK_TEGRA30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .set_audio_cif = tegra30_ahub_set_cif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static struct tegra30_ahub_soc_data soc_data_tegra114 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) .mod_list_mask = MOD_LIST_MASK_TEGRA114,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) .set_audio_cif = tegra30_ahub_set_cif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static struct tegra30_ahub_soc_data soc_data_tegra124 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .mod_list_mask = MOD_LIST_MASK_TEGRA124,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .set_audio_cif = tegra124_ahub_set_cif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static const struct of_device_id tegra30_ahub_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) { .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static int tegra30_ahub_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) const struct tegra30_ahub_soc_data *soc_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct reset_control *rst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) struct resource *res0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) void __iomem *regs_apbif, *regs_ahub;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (ahub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (!match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) soc_data = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * The AHUB hosts a register bus: the "configlink". For this to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * operate correctly, all devices on this bus must be out of reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * Ensure that here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (!(configlink_mods[i].mod_list_mask &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) soc_data->mod_list_mask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) rst = reset_control_get_exclusive(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) configlink_mods[i].rst_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (IS_ERR(rst)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) dev_err(&pdev->dev, "Can't get reset %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) configlink_mods[i].rst_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) ret = PTR_ERR(rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) ret = reset_control_deassert(rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) reset_control_put(rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (!ahub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) dev_set_drvdata(&pdev->dev, ahub);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) ahub->soc_data = soc_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) ahub->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (IS_ERR(ahub->clk_d_audio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) ret = PTR_ERR(ahub->clk_d_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (IS_ERR(ahub->clk_apbif)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) ret = PTR_ERR(ahub->clk_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) regs_apbif = devm_ioremap_resource(&pdev->dev, res0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (IS_ERR(regs_apbif))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return PTR_ERR(regs_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) ahub->apbif_addr = res0->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) &tegra30_ahub_apbif_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (IS_ERR(ahub->regmap_apbif)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) dev_err(&pdev->dev, "apbif regmap init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) ret = PTR_ERR(ahub->regmap_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) regcache_cache_only(ahub->regmap_apbif, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) regs_ahub = devm_platform_ioremap_resource(pdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (IS_ERR(regs_ahub))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return PTR_ERR(regs_ahub);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) &tegra30_ahub_ahub_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (IS_ERR(ahub->regmap_ahub)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) dev_err(&pdev->dev, "ahub regmap init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) ret = PTR_ERR(ahub->regmap_ahub);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) regcache_cache_only(ahub->regmap_ahub, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (!pm_runtime_enabled(&pdev->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) ret = tegra30_ahub_runtime_resume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) goto err_pm_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) err_pm_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static int tegra30_ahub_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (!ahub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) if (!pm_runtime_status_suspended(&pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) tegra30_ahub_runtime_suspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) static int tegra30_ahub_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) regcache_mark_dirty(ahub->regmap_ahub);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) regcache_mark_dirty(ahub->regmap_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int tegra30_ahub_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) ret = pm_runtime_get_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) pm_runtime_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) ret = regcache_sync(ahub->regmap_ahub);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) ret |= regcache_sync(ahub->regmap_apbif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) pm_runtime_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) static const struct dev_pm_ops tegra30_ahub_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) tegra30_ahub_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) static struct platform_driver tegra30_ahub_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) .probe = tegra30_ahub_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) .remove = tegra30_ahub_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) .of_match_table = tegra30_ahub_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) .pm = &tegra30_ahub_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) module_platform_driver(tegra30_ahub_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct tegra30_ahub_cif_conf *conf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) unsigned int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) value = (conf->threshold <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) ((conf->audio_channels - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) ((conf->client_channels - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) (conf->audio_bits <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) (conf->client_bits <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) (conf->expand <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) (conf->stereo_conv <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) (conf->replicate <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) (conf->direction <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) (conf->truncate <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) (conf->mono_conv <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) regmap_write(regmap, reg, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) struct tegra30_ahub_cif_conf *conf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) unsigned int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) value = (conf->threshold <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) ((conf->audio_channels - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) ((conf->client_channels - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) (conf->audio_bits <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) (conf->client_bits <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) (conf->expand <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) (conf->stereo_conv <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) (conf->replicate <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) (conf->direction <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) (conf->truncate <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) (conf->mono_conv <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) regmap_write(regmap, reg, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) MODULE_DESCRIPTION("Tegra30 AHUB driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) MODULE_ALIAS("platform:" DRV_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) MODULE_DEVICE_TABLE(of, tegra30_ahub_of_match);