^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) * tegra20_ac97.c - Tegra20 AC97 platform driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012 Lucas Stach <dev@lynxeye.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Partly based on code copyright/by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 2011,2012 Toradex Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/of_gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <sound/dmaengine_pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "tegra20_ac97.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define DRV_NAME "tegra20-ac97"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static struct tegra20_ac97 *workdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void tegra20_ac97_codec_reset(struct snd_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) u32 readback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* reset line is not driven by DAC pad group, have to toggle GPIO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) gpio_set_value(workdata->reset_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) udelay(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) gpio_set_value(workdata->reset_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) udelay(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) timeout = jiffies + msecs_to_jiffies(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) } while (!time_after(jiffies, timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void tegra20_ac97_codec_warm_reset(struct snd_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u32 readback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * although sync line is driven by the DAC pad group warm reset using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * the controller cmd is not working, have to toggle sync line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * manually.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) gpio_request(workdata->sync_gpio, "codec-sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) gpio_direction_output(workdata->sync_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) udelay(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) gpio_set_value(workdata->sync_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) udelay(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) gpio_free(workdata->sync_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) timeout = jiffies + msecs_to_jiffies(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) } while (!time_after(jiffies, timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static unsigned short tegra20_ac97_codec_read(struct snd_ac97 *ac97_snd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned short reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 readback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) (((reg | 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) TEGRA20_AC97_CMD_BUSY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) timeout = jiffies + msecs_to_jiffies(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (readback & TEGRA20_AC97_STATUS1_STA_VALID1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) } while (!time_after(jiffies, timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return ((readback & TEGRA20_AC97_STATUS1_STA_DATA1_MASK) >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned short reg, unsigned short val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u32 readback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ((reg << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ((val << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) TEGRA20_AC97_CMD_CMD_DATA_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) TEGRA20_AC97_CMD_BUSY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) timeout = jiffies + msecs_to_jiffies(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) regmap_read(workdata->regmap, TEGRA20_AC97_CMD, &readback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!(readback & TEGRA20_AC97_CMD_BUSY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) } while (!time_after(jiffies, timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static struct snd_ac97_bus_ops tegra20_ac97_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .read = tegra20_ac97_codec_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .write = tegra20_ac97_codec_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .reset = tegra20_ac97_codec_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .warm_reset = tegra20_ac97_codec_warm_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) TEGRA20_AC97_CTRL_PCM_DAC_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) TEGRA20_AC97_CTRL_STM_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) TEGRA20_AC97_CTRL_PCM_DAC_EN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) TEGRA20_AC97_CTRL_STM_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static inline void tegra20_ac97_stop_playback(struct tegra20_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) TEGRA20_AC97_CTRL_PCM_DAC_EN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static inline void tegra20_ac97_start_capture(struct tegra20_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) TEGRA20_AC97_FIFO_SCR_REC_FULL_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) TEGRA20_AC97_FIFO_SCR_REC_FULL_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static inline void tegra20_ac97_stop_capture(struct tegra20_ac97 *ac97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) tegra20_ac97_start_playback(ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) tegra20_ac97_start_capture(ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) tegra20_ac97_stop_playback(ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) tegra20_ac97_stop_capture(ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .trigger = tegra20_ac97_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static int tegra20_ac97_probe(struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) dai->capture_dma_data = &ac97->capture_dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) dai->playback_dma_data = &ac97->playback_dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static struct snd_soc_dai_driver tegra20_ac97_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .name = "tegra-ac97-pcm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .probe = tegra20_ac97_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .stream_name = "PCM Playback",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .rates = SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .stream_name = "PCM Capture",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .rates = SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .ops = &tegra20_ac97_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static const struct snd_soc_component_driver tegra20_ac97_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case TEGRA20_AC97_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case TEGRA20_AC97_CMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case TEGRA20_AC97_STATUS1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case TEGRA20_AC97_FIFO1_SCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) case TEGRA20_AC97_FIFO_TX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case TEGRA20_AC97_FIFO_RX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static bool tegra20_ac97_volatile_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) case TEGRA20_AC97_STATUS1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) case TEGRA20_AC97_FIFO1_SCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case TEGRA20_AC97_FIFO_TX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) case TEGRA20_AC97_FIFO_RX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static bool tegra20_ac97_precious_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case TEGRA20_AC97_FIFO_TX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) case TEGRA20_AC97_FIFO_RX1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static const struct regmap_config tegra20_ac97_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .max_register = TEGRA20_AC97_FIFO_RX1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .writeable_reg = tegra20_ac97_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .readable_reg = tegra20_ac97_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .volatile_reg = tegra20_ac97_volatile_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .precious_reg = tegra20_ac97_precious_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .cache_type = REGCACHE_FLAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int tegra20_ac97_platform_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct tegra20_ac97 *ac97;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct resource *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (!ac97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) dev_set_drvdata(&pdev->dev, ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (IS_ERR(ac97->clk_ac97)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) ret = PTR_ERR(ac97->clk_ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) regs = devm_ioremap_resource(&pdev->dev, mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (IS_ERR(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ret = PTR_ERR(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ac97->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) &tegra20_ac97_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (IS_ERR(ac97->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) dev_err(&pdev->dev, "regmap init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ret = PTR_ERR(ac97->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) "nvidia,codec-reset-gpio", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (gpio_is_valid(ac97->reset_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ret = devm_gpio_request_one(&pdev->dev, ac97->reset_gpio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) GPIOF_OUT_INIT_HIGH, "codec-reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) dev_err(&pdev->dev, "could not get codec-reset GPIO\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) dev_err(&pdev->dev, "no codec-reset GPIO supplied\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ac97->sync_gpio = of_get_named_gpio(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) "nvidia,codec-sync-gpio", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (!gpio_is_valid(ac97->sync_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) dev_err(&pdev->dev, "no codec-sync GPIO supplied\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) ac97->capture_dma_data.maxburst = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ac97->playback_dma_data.maxburst = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) ret = clk_prepare_enable(ac97->clk_ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) goto err_clk_disable_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) &tegra20_ac97_dai, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) goto err_clk_disable_unprepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = tegra_pcm_platform_register(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) goto err_unregister_component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) workdata = ac97;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) err_unregister_component:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) snd_soc_unregister_component(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) err_clk_disable_unprepare:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) clk_disable_unprepare(ac97->clk_ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) err_clk_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) snd_soc_set_ac97_ops(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static int tegra20_ac97_platform_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) tegra_pcm_platform_unregister(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) snd_soc_unregister_component(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) clk_disable_unprepare(ac97->clk_ac97);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) snd_soc_set_ac97_ops(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static const struct of_device_id tegra20_ac97_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) { .compatible = "nvidia,tegra20-ac97", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) static struct platform_driver tegra20_ac97_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .of_match_table = tegra20_ac97_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .probe = tegra20_ac97_platform_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) .remove = tegra20_ac97_platform_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) module_platform_driver(tegra20_ac97_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) MODULE_AUTHOR("Lucas Stach");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) MODULE_ALIAS("platform:" DRV_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) MODULE_DEVICE_TABLE(of, tegra20_ac97_of_match);