162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Implementation of primary ALSA driver code base for NVIDIA Tegra HDA.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/clocksource.h>
962306a36Sopenharmony_ci#include <linux/completion.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/moduleparam.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/platform_device.h>
2162306a36Sopenharmony_ci#include <linux/reset.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/time.h>
2462306a36Sopenharmony_ci#include <linux/string.h>
2562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <sound/core.h>
2862306a36Sopenharmony_ci#include <sound/initval.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <sound/hda_codec.h>
3162306a36Sopenharmony_ci#include "hda_controller.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Defines for Nvidia Tegra HDA support */
3462306a36Sopenharmony_ci#define HDA_BAR0           0x8000
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define HDA_CFG_CMD        0x1004
3762306a36Sopenharmony_ci#define HDA_CFG_BAR0       0x1010
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define HDA_ENABLE_IO_SPACE       (1 << 0)
4062306a36Sopenharmony_ci#define HDA_ENABLE_MEM_SPACE      (1 << 1)
4162306a36Sopenharmony_ci#define HDA_ENABLE_BUS_MASTER     (1 << 2)
4262306a36Sopenharmony_ci#define HDA_ENABLE_SERR           (1 << 8)
4362306a36Sopenharmony_ci#define HDA_DISABLE_INTR          (1 << 10)
4462306a36Sopenharmony_ci#define HDA_BAR0_INIT_PROGRAM     0xFFFFFFFF
4562306a36Sopenharmony_ci#define HDA_BAR0_FINAL_PROGRAM    (1 << 14)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* IPFS */
4862306a36Sopenharmony_ci#define HDA_IPFS_CONFIG           0x180
4962306a36Sopenharmony_ci#define HDA_IPFS_EN_FPCI          0x1
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define HDA_IPFS_FPCI_BAR0        0x80
5262306a36Sopenharmony_ci#define HDA_FPCI_BAR0_START       0x40
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define HDA_IPFS_INTR_MASK        0x188
5562306a36Sopenharmony_ci#define HDA_IPFS_EN_INTR          (1 << 16)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* FPCI */
5862306a36Sopenharmony_ci#define FPCI_DBG_CFG_2		  0x10F4
5962306a36Sopenharmony_ci#define FPCI_GCAP_NSDO_SHIFT	  18
6062306a36Sopenharmony_ci#define FPCI_GCAP_NSDO_MASK	  (0x3 << FPCI_GCAP_NSDO_SHIFT)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* max number of SDs */
6362306a36Sopenharmony_ci#define NUM_CAPTURE_SD 1
6462306a36Sopenharmony_ci#define NUM_PLAYBACK_SD 1
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * Tegra194 does not reflect correct number of SDO lines. Below macro
6862306a36Sopenharmony_ci * is used to update the GCAP register to workaround the issue.
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_ci#define TEGRA194_NUM_SDO_LINES	  4
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct hda_tegra_soc {
7362306a36Sopenharmony_ci	bool has_hda2codec_2x_reset;
7462306a36Sopenharmony_ci	bool has_hda2hdmi;
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct hda_tegra {
7862306a36Sopenharmony_ci	struct azx chip;
7962306a36Sopenharmony_ci	struct device *dev;
8062306a36Sopenharmony_ci	struct reset_control_bulk_data resets[3];
8162306a36Sopenharmony_ci	struct clk_bulk_data clocks[3];
8262306a36Sopenharmony_ci	unsigned int nresets;
8362306a36Sopenharmony_ci	unsigned int nclocks;
8462306a36Sopenharmony_ci	void __iomem *regs;
8562306a36Sopenharmony_ci	struct work_struct probe_work;
8662306a36Sopenharmony_ci	const struct hda_tegra_soc *soc;
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#ifdef CONFIG_PM
9062306a36Sopenharmony_cistatic int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
9162306a36Sopenharmony_cimodule_param(power_save, bint, 0644);
9262306a36Sopenharmony_ciMODULE_PARM_DESC(power_save,
9362306a36Sopenharmony_ci		 "Automatic power-saving timeout (in seconds, 0 = disable).");
9462306a36Sopenharmony_ci#else
9562306a36Sopenharmony_ci#define power_save	0
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic const struct hda_controller_ops hda_tegra_ops; /* nothing special */
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void hda_tegra_init(struct hda_tegra *hda)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	u32 v;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Enable PCI access */
10562306a36Sopenharmony_ci	v = readl(hda->regs + HDA_IPFS_CONFIG);
10662306a36Sopenharmony_ci	v |= HDA_IPFS_EN_FPCI;
10762306a36Sopenharmony_ci	writel(v, hda->regs + HDA_IPFS_CONFIG);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Enable MEM/IO space and bus master */
11062306a36Sopenharmony_ci	v = readl(hda->regs + HDA_CFG_CMD);
11162306a36Sopenharmony_ci	v &= ~HDA_DISABLE_INTR;
11262306a36Sopenharmony_ci	v |= HDA_ENABLE_MEM_SPACE | HDA_ENABLE_IO_SPACE |
11362306a36Sopenharmony_ci		HDA_ENABLE_BUS_MASTER | HDA_ENABLE_SERR;
11462306a36Sopenharmony_ci	writel(v, hda->regs + HDA_CFG_CMD);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	writel(HDA_BAR0_INIT_PROGRAM, hda->regs + HDA_CFG_BAR0);
11762306a36Sopenharmony_ci	writel(HDA_BAR0_FINAL_PROGRAM, hda->regs + HDA_CFG_BAR0);
11862306a36Sopenharmony_ci	writel(HDA_FPCI_BAR0_START, hda->regs + HDA_IPFS_FPCI_BAR0);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	v = readl(hda->regs + HDA_IPFS_INTR_MASK);
12162306a36Sopenharmony_ci	v |= HDA_IPFS_EN_INTR;
12262306a36Sopenharmony_ci	writel(v, hda->regs + HDA_IPFS_INTR_MASK);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * power management
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic int __maybe_unused hda_tegra_suspend(struct device *dev)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
13162306a36Sopenharmony_ci	int rc;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	rc = pm_runtime_force_suspend(dev);
13462306a36Sopenharmony_ci	if (rc < 0)
13562306a36Sopenharmony_ci		return rc;
13662306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int __maybe_unused hda_tegra_resume(struct device *dev)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
14462306a36Sopenharmony_ci	int rc;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	rc = pm_runtime_force_resume(dev);
14762306a36Sopenharmony_ci	if (rc < 0)
14862306a36Sopenharmony_ci		return rc;
14962306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
15762306a36Sopenharmony_ci	struct azx *chip = card->private_data;
15862306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (chip && chip->running) {
16162306a36Sopenharmony_ci		/* enable controller wake up event */
16262306a36Sopenharmony_ci		azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
16362306a36Sopenharmony_ci			   STATESTS_INT_MASK);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		azx_stop_chip(chip);
16662306a36Sopenharmony_ci		azx_enter_link_reset(chip);
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return 0;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
17662306a36Sopenharmony_ci	struct azx *chip = card->private_data;
17762306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
17862306a36Sopenharmony_ci	int rc;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (!chip->running) {
18162306a36Sopenharmony_ci		rc = reset_control_bulk_assert(hda->nresets, hda->resets);
18262306a36Sopenharmony_ci		if (rc)
18362306a36Sopenharmony_ci			return rc;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
18762306a36Sopenharmony_ci	if (rc != 0)
18862306a36Sopenharmony_ci		return rc;
18962306a36Sopenharmony_ci	if (chip->running) {
19062306a36Sopenharmony_ci		hda_tegra_init(hda);
19162306a36Sopenharmony_ci		azx_init_chip(chip, 1);
19262306a36Sopenharmony_ci		/* disable controller wake up event*/
19362306a36Sopenharmony_ci		azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
19462306a36Sopenharmony_ci			   ~STATESTS_INT_MASK);
19562306a36Sopenharmony_ci	} else {
19662306a36Sopenharmony_ci		usleep_range(10, 100);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		rc = reset_control_bulk_deassert(hda->nresets, hda->resets);
19962306a36Sopenharmony_ci		if (rc)
20062306a36Sopenharmony_ci			return rc;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic const struct dev_pm_ops hda_tegra_pm = {
20762306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume)
20862306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend,
20962306a36Sopenharmony_ci			   hda_tegra_runtime_resume,
21062306a36Sopenharmony_ci			   NULL)
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int hda_tegra_dev_disconnect(struct snd_device *device)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct azx *chip = device->device_data;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	chip->bus.shutdown = 1;
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*
22262306a36Sopenharmony_ci * destructor
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_cistatic int hda_tegra_dev_free(struct snd_device *device)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct azx *chip = device->device_data;
22762306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	cancel_work_sync(&hda->probe_work);
23062306a36Sopenharmony_ci	if (azx_bus(chip)->chip_init) {
23162306a36Sopenharmony_ci		azx_stop_all_streams(chip);
23262306a36Sopenharmony_ci		azx_stop_chip(chip);
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	azx_free_stream_pages(chip);
23662306a36Sopenharmony_ci	azx_free_streams(chip);
23762306a36Sopenharmony_ci	snd_hdac_bus_exit(azx_bus(chip));
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
24562306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
24662306a36Sopenharmony_ci	struct resource *res;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	hda->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
24962306a36Sopenharmony_ci	if (IS_ERR(hda->regs))
25062306a36Sopenharmony_ci		return PTR_ERR(hda->regs);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	bus->remap_addr = hda->regs + HDA_BAR0;
25362306a36Sopenharmony_ci	bus->addr = res->start + HDA_BAR0;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	hda_tegra_init(hda);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
26362306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
26462306a36Sopenharmony_ci	struct snd_card *card = chip->card;
26562306a36Sopenharmony_ci	int err;
26662306a36Sopenharmony_ci	unsigned short gcap;
26762306a36Sopenharmony_ci	int irq_id = platform_get_irq(pdev, 0);
26862306a36Sopenharmony_ci	const char *sname, *drv_name = "tegra-hda";
26962306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (irq_id < 0)
27262306a36Sopenharmony_ci		return irq_id;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	err = hda_tegra_init_chip(chip, pdev);
27562306a36Sopenharmony_ci	if (err)
27662306a36Sopenharmony_ci		return err;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	err = devm_request_irq(chip->card->dev, irq_id, azx_interrupt,
27962306a36Sopenharmony_ci			     IRQF_SHARED, KBUILD_MODNAME, chip);
28062306a36Sopenharmony_ci	if (err) {
28162306a36Sopenharmony_ci		dev_err(chip->card->dev,
28262306a36Sopenharmony_ci			"unable to request IRQ %d, disabling device\n",
28362306a36Sopenharmony_ci			irq_id);
28462306a36Sopenharmony_ci		return err;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci	bus->irq = irq_id;
28762306a36Sopenharmony_ci	bus->dma_stop_delay = 100;
28862306a36Sopenharmony_ci	card->sync_irq = bus->irq;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/*
29162306a36Sopenharmony_ci	 * Tegra194 has 4 SDO lines and the STRIPE can be used to
29262306a36Sopenharmony_ci	 * indicate how many of the SDO lines the stream should be
29362306a36Sopenharmony_ci	 * striped. But GCAP register does not reflect the true
29462306a36Sopenharmony_ci	 * capability of HW. Below workaround helps to fix this.
29562306a36Sopenharmony_ci	 *
29662306a36Sopenharmony_ci	 * GCAP_NSDO is bits 19:18 in T_AZA_DBG_CFG_2,
29762306a36Sopenharmony_ci	 * 0 for 1 SDO, 1 for 2 SDO, 2 for 4 SDO lines.
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra194-hda")) {
30062306a36Sopenharmony_ci		u32 val;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		dev_info(card->dev, "Override SDO lines to %u\n",
30362306a36Sopenharmony_ci			 TEGRA194_NUM_SDO_LINES);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		val = readl(hda->regs + FPCI_DBG_CFG_2) & ~FPCI_GCAP_NSDO_MASK;
30662306a36Sopenharmony_ci		val |= (TEGRA194_NUM_SDO_LINES >> 1) << FPCI_GCAP_NSDO_SHIFT;
30762306a36Sopenharmony_ci		writel(val, hda->regs + FPCI_DBG_CFG_2);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	gcap = azx_readw(chip, GCAP);
31162306a36Sopenharmony_ci	dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	chip->align_buffer_size = 1;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* read number of streams from GCAP register instead of using
31662306a36Sopenharmony_ci	 * hardcoded value
31762306a36Sopenharmony_ci	 */
31862306a36Sopenharmony_ci	chip->capture_streams = (gcap >> 8) & 0x0f;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* The GCAP register on Tegra234 implies no Input Streams(ISS) support,
32162306a36Sopenharmony_ci	 * but the HW output stream descriptor programming should start with
32262306a36Sopenharmony_ci	 * offset 0x20*4 from base stream descriptor address. This will be a
32362306a36Sopenharmony_ci	 * problem while calculating the offset for output stream descriptor
32462306a36Sopenharmony_ci	 * which will be considering input stream also. So here output stream
32562306a36Sopenharmony_ci	 * starts with offset 0 which is wrong as HW register for output stream
32662306a36Sopenharmony_ci	 * offset starts with 4.
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra234-hda"))
32962306a36Sopenharmony_ci		chip->capture_streams = 4;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	chip->playback_streams = (gcap >> 12) & 0x0f;
33262306a36Sopenharmony_ci	if (!chip->playback_streams && !chip->capture_streams) {
33362306a36Sopenharmony_ci		/* gcap didn't give any info, switching to old method */
33462306a36Sopenharmony_ci		chip->playback_streams = NUM_PLAYBACK_SD;
33562306a36Sopenharmony_ci		chip->capture_streams = NUM_CAPTURE_SD;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	chip->capture_index_offset = 0;
33862306a36Sopenharmony_ci	chip->playback_index_offset = chip->capture_streams;
33962306a36Sopenharmony_ci	chip->num_streams = chip->playback_streams + chip->capture_streams;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* initialize streams */
34262306a36Sopenharmony_ci	err = azx_init_streams(chip);
34362306a36Sopenharmony_ci	if (err < 0) {
34462306a36Sopenharmony_ci		dev_err(card->dev, "failed to initialize streams: %d\n", err);
34562306a36Sopenharmony_ci		return err;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	err = azx_alloc_stream_pages(chip);
34962306a36Sopenharmony_ci	if (err < 0) {
35062306a36Sopenharmony_ci		dev_err(card->dev, "failed to allocate stream pages: %d\n",
35162306a36Sopenharmony_ci			err);
35262306a36Sopenharmony_ci		return err;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* initialize chip */
35662306a36Sopenharmony_ci	azx_init_chip(chip, 1);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/*
35962306a36Sopenharmony_ci	 * Playback (for 44.1K/48K, 2-channel, 16-bps) fails with
36062306a36Sopenharmony_ci	 * 4 SDO lines due to legacy design limitation. Following
36162306a36Sopenharmony_ci	 * is, from HD Audio Specification (Revision 1.0a), used to
36262306a36Sopenharmony_ci	 * control striping of the stream across multiple SDO lines
36362306a36Sopenharmony_ci	 * for sample rates <= 48K.
36462306a36Sopenharmony_ci	 *
36562306a36Sopenharmony_ci	 * { ((num_channels * bits_per_sample) / number of SDOs) >= 8 }
36662306a36Sopenharmony_ci	 *
36762306a36Sopenharmony_ci	 * Due to legacy design issue it is recommended that above
36862306a36Sopenharmony_ci	 * ratio must be greater than 8. Since number of SDO lines is
36962306a36Sopenharmony_ci	 * in powers of 2, next available ratio is 16 which can be
37062306a36Sopenharmony_ci	 * used as a limiting factor here.
37162306a36Sopenharmony_ci	 */
37262306a36Sopenharmony_ci	if (of_device_is_compatible(np, "nvidia,tegra30-hda"))
37362306a36Sopenharmony_ci		chip->bus.core.sdo_limit = 16;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* codec detection */
37662306a36Sopenharmony_ci	if (!bus->codec_mask) {
37762306a36Sopenharmony_ci		dev_err(card->dev, "no codecs found!\n");
37862306a36Sopenharmony_ci		return -ENODEV;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* driver name */
38262306a36Sopenharmony_ci	strscpy(card->driver, drv_name, sizeof(card->driver));
38362306a36Sopenharmony_ci	/* shortname for card */
38462306a36Sopenharmony_ci	sname = of_get_property(np, "nvidia,model", NULL);
38562306a36Sopenharmony_ci	if (!sname)
38662306a36Sopenharmony_ci		sname = drv_name;
38762306a36Sopenharmony_ci	if (strlen(sname) > sizeof(card->shortname))
38862306a36Sopenharmony_ci		dev_info(card->dev, "truncating shortname for card\n");
38962306a36Sopenharmony_ci	strscpy(card->shortname, sname, sizeof(card->shortname));
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* longname for card */
39262306a36Sopenharmony_ci	snprintf(card->longname, sizeof(card->longname),
39362306a36Sopenharmony_ci		 "%s at 0x%lx irq %i",
39462306a36Sopenharmony_ci		 card->shortname, bus->addr, bus->irq);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return 0;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * constructor
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic void hda_tegra_probe_work(struct work_struct *work);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int hda_tegra_create(struct snd_card *card,
40662306a36Sopenharmony_ci			    unsigned int driver_caps,
40762306a36Sopenharmony_ci			    struct hda_tegra *hda)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	static const struct snd_device_ops ops = {
41062306a36Sopenharmony_ci		.dev_disconnect = hda_tegra_dev_disconnect,
41162306a36Sopenharmony_ci		.dev_free = hda_tegra_dev_free,
41262306a36Sopenharmony_ci	};
41362306a36Sopenharmony_ci	struct azx *chip;
41462306a36Sopenharmony_ci	int err;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	chip = &hda->chip;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	mutex_init(&chip->open_mutex);
41962306a36Sopenharmony_ci	chip->card = card;
42062306a36Sopenharmony_ci	chip->ops = &hda_tegra_ops;
42162306a36Sopenharmony_ci	chip->driver_caps = driver_caps;
42262306a36Sopenharmony_ci	chip->driver_type = driver_caps & 0xff;
42362306a36Sopenharmony_ci	chip->dev_index = 0;
42462306a36Sopenharmony_ci	chip->jackpoll_interval = msecs_to_jiffies(5000);
42562306a36Sopenharmony_ci	INIT_LIST_HEAD(&chip->pcm_list);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	chip->codec_probe_mask = -1;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	chip->single_cmd = false;
43062306a36Sopenharmony_ci	chip->snoop = true;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	INIT_WORK(&hda->probe_work, hda_tegra_probe_work);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	err = azx_bus_init(chip, NULL);
43562306a36Sopenharmony_ci	if (err < 0)
43662306a36Sopenharmony_ci		return err;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	chip->bus.core.sync_write = 0;
43962306a36Sopenharmony_ci	chip->bus.core.needs_damn_long_delay = 1;
44062306a36Sopenharmony_ci	chip->bus.core.aligned_mmio = 1;
44162306a36Sopenharmony_ci	chip->bus.jackpoll_in_suspend = 1;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
44462306a36Sopenharmony_ci	if (err < 0) {
44562306a36Sopenharmony_ci		dev_err(card->dev, "Error creating device\n");
44662306a36Sopenharmony_ci		return err;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return 0;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const struct hda_tegra_soc tegra30_data = {
45362306a36Sopenharmony_ci	.has_hda2codec_2x_reset = true,
45462306a36Sopenharmony_ci	.has_hda2hdmi = true,
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic const struct hda_tegra_soc tegra194_data = {
45862306a36Sopenharmony_ci	.has_hda2codec_2x_reset = false,
45962306a36Sopenharmony_ci	.has_hda2hdmi = true,
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic const struct hda_tegra_soc tegra234_data = {
46362306a36Sopenharmony_ci	.has_hda2codec_2x_reset = true,
46462306a36Sopenharmony_ci	.has_hda2hdmi = false,
46562306a36Sopenharmony_ci};
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic const struct of_device_id hda_tegra_match[] = {
46862306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra30-hda", .data = &tegra30_data },
46962306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra194-hda", .data = &tegra194_data },
47062306a36Sopenharmony_ci	{ .compatible = "nvidia,tegra234-hda", .data = &tegra234_data },
47162306a36Sopenharmony_ci	{},
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, hda_tegra_match);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int hda_tegra_probe(struct platform_device *pdev)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR |
47862306a36Sopenharmony_ci					  AZX_DCAPS_PM_RUNTIME |
47962306a36Sopenharmony_ci					  AZX_DCAPS_4K_BDLE_BOUNDARY;
48062306a36Sopenharmony_ci	struct snd_card *card;
48162306a36Sopenharmony_ci	struct azx *chip;
48262306a36Sopenharmony_ci	struct hda_tegra *hda;
48362306a36Sopenharmony_ci	int err;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
48662306a36Sopenharmony_ci	if (!hda)
48762306a36Sopenharmony_ci		return -ENOMEM;
48862306a36Sopenharmony_ci	hda->dev = &pdev->dev;
48962306a36Sopenharmony_ci	chip = &hda->chip;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	hda->soc = of_device_get_match_data(&pdev->dev);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
49462306a36Sopenharmony_ci			   THIS_MODULE, 0, &card);
49562306a36Sopenharmony_ci	if (err < 0) {
49662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Error creating card!\n");
49762306a36Sopenharmony_ci		return err;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	hda->resets[hda->nresets++].id = "hda";
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/*
50362306a36Sopenharmony_ci	 * "hda2hdmi" is not applicable for Tegra234. This is because the
50462306a36Sopenharmony_ci	 * codec is separate IP and not under display SOR partition now.
50562306a36Sopenharmony_ci	 */
50662306a36Sopenharmony_ci	if (hda->soc->has_hda2hdmi)
50762306a36Sopenharmony_ci		hda->resets[hda->nresets++].id = "hda2hdmi";
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/*
51062306a36Sopenharmony_ci	 * "hda2codec_2x" reset is not present on Tegra194. Though DT would
51162306a36Sopenharmony_ci	 * be updated to reflect this, but to have backward compatibility
51262306a36Sopenharmony_ci	 * below is necessary.
51362306a36Sopenharmony_ci	 */
51462306a36Sopenharmony_ci	if (hda->soc->has_hda2codec_2x_reset)
51562306a36Sopenharmony_ci		hda->resets[hda->nresets++].id = "hda2codec_2x";
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	err = devm_reset_control_bulk_get_exclusive(&pdev->dev, hda->nresets,
51862306a36Sopenharmony_ci						    hda->resets);
51962306a36Sopenharmony_ci	if (err)
52062306a36Sopenharmony_ci		goto out_free;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	hda->clocks[hda->nclocks++].id = "hda";
52362306a36Sopenharmony_ci	if (hda->soc->has_hda2hdmi)
52462306a36Sopenharmony_ci		hda->clocks[hda->nclocks++].id = "hda2hdmi";
52562306a36Sopenharmony_ci	hda->clocks[hda->nclocks++].id = "hda2codec_2x";
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks);
52862306a36Sopenharmony_ci	if (err < 0)
52962306a36Sopenharmony_ci		goto out_free;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	err = hda_tegra_create(card, driver_flags, hda);
53262306a36Sopenharmony_ci	if (err < 0)
53362306a36Sopenharmony_ci		goto out_free;
53462306a36Sopenharmony_ci	card->private_data = chip;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, card);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	pm_runtime_enable(hda->dev);
53962306a36Sopenharmony_ci	if (!azx_has_pm_runtime(chip))
54062306a36Sopenharmony_ci		pm_runtime_forbid(hda->dev);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	schedule_work(&hda->probe_work);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return 0;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciout_free:
54762306a36Sopenharmony_ci	snd_card_free(card);
54862306a36Sopenharmony_ci	return err;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void hda_tegra_probe_work(struct work_struct *work)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct hda_tegra *hda = container_of(work, struct hda_tegra, probe_work);
55462306a36Sopenharmony_ci	struct azx *chip = &hda->chip;
55562306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(hda->dev);
55662306a36Sopenharmony_ci	int err;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	pm_runtime_get_sync(hda->dev);
55962306a36Sopenharmony_ci	err = hda_tegra_first_init(chip, pdev);
56062306a36Sopenharmony_ci	if (err < 0)
56162306a36Sopenharmony_ci		goto out_free;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* create codec instances */
56462306a36Sopenharmony_ci	err = azx_probe_codecs(chip, 8);
56562306a36Sopenharmony_ci	if (err < 0)
56662306a36Sopenharmony_ci		goto out_free;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	err = azx_codec_configure(chip);
56962306a36Sopenharmony_ci	if (err < 0)
57062306a36Sopenharmony_ci		goto out_free;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	err = snd_card_register(chip->card);
57362306a36Sopenharmony_ci	if (err < 0)
57462306a36Sopenharmony_ci		goto out_free;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	chip->running = 1;
57762306a36Sopenharmony_ci	snd_hda_set_power_save(&chip->bus, power_save * 1000);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci out_free:
58062306a36Sopenharmony_ci	pm_runtime_put(hda->dev);
58162306a36Sopenharmony_ci	return; /* no error return from async probe */
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic void hda_tegra_remove(struct platform_device *pdev)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	snd_card_free(dev_get_drvdata(&pdev->dev));
58762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic void hda_tegra_shutdown(struct platform_device *pdev)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(&pdev->dev);
59362306a36Sopenharmony_ci	struct azx *chip;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (!card)
59662306a36Sopenharmony_ci		return;
59762306a36Sopenharmony_ci	chip = card->private_data;
59862306a36Sopenharmony_ci	if (chip && chip->running)
59962306a36Sopenharmony_ci		azx_stop_chip(chip);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic struct platform_driver tegra_platform_hda = {
60362306a36Sopenharmony_ci	.driver = {
60462306a36Sopenharmony_ci		.name = "tegra-hda",
60562306a36Sopenharmony_ci		.pm = &hda_tegra_pm,
60662306a36Sopenharmony_ci		.of_match_table = hda_tegra_match,
60762306a36Sopenharmony_ci	},
60862306a36Sopenharmony_ci	.probe = hda_tegra_probe,
60962306a36Sopenharmony_ci	.remove_new = hda_tegra_remove,
61062306a36Sopenharmony_ci	.shutdown = hda_tegra_shutdown,
61162306a36Sopenharmony_ci};
61262306a36Sopenharmony_cimodule_platform_driver(tegra_platform_hda);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ciMODULE_DESCRIPTION("Tegra HDA bus driver");
61562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
616