162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/ata/ahci_tegra.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author:
862306a36Sopenharmony_ci *	Mikko Perttunen <mperttunen@nvidia.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/ahci_platform.h>
1262306a36Sopenharmony_ci#include <linux/errno.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1862306a36Sopenharmony_ci#include <linux/reset.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <soc/tegra/fuse.h>
2162306a36Sopenharmony_ci#include <soc/tegra/pmc.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "ahci.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DRV_NAME "tegra-ahci"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define SATA_CONFIGURATION_0				0x180
2862306a36Sopenharmony_ci#define SATA_CONFIGURATION_0_EN_FPCI			BIT(0)
2962306a36Sopenharmony_ci#define SATA_CONFIGURATION_0_CLK_OVERRIDE			BIT(31)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define SCFG_OFFSET					0x1000
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define T_SATA0_CFG_1					0x04
3462306a36Sopenharmony_ci#define T_SATA0_CFG_1_IO_SPACE				BIT(0)
3562306a36Sopenharmony_ci#define T_SATA0_CFG_1_MEMORY_SPACE			BIT(1)
3662306a36Sopenharmony_ci#define T_SATA0_CFG_1_BUS_MASTER			BIT(2)
3762306a36Sopenharmony_ci#define T_SATA0_CFG_1_SERR				BIT(8)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define T_SATA0_CFG_9					0x24
4062306a36Sopenharmony_ci#define T_SATA0_CFG_9_BASE_ADDRESS			0x40020000
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define SATA_FPCI_BAR5					0x94
4362306a36Sopenharmony_ci#define SATA_FPCI_BAR5_START_MASK			(0xfffffff << 4)
4462306a36Sopenharmony_ci#define SATA_FPCI_BAR5_START				(0x0040020 << 4)
4562306a36Sopenharmony_ci#define SATA_FPCI_BAR5_ACCESS_TYPE			(0x1)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define SATA_INTR_MASK					0x188
4862306a36Sopenharmony_ci#define SATA_INTR_MASK_IP_INT_MASK			BIT(16)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define T_SATA0_CFG_35					0x94
5162306a36Sopenharmony_ci#define T_SATA0_CFG_35_IDP_INDEX_MASK			(0x7ff << 2)
5262306a36Sopenharmony_ci#define T_SATA0_CFG_35_IDP_INDEX			(0x2a << 2)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define T_SATA0_AHCI_IDP1				0x98
5562306a36Sopenharmony_ci#define T_SATA0_AHCI_IDP1_DATA				(0x400040)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define T_SATA0_CFG_PHY_1				0x12c
5862306a36Sopenharmony_ci#define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN			BIT(23)
5962306a36Sopenharmony_ci#define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN		BIT(22)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define T_SATA0_NVOOB                                   0x114
6262306a36Sopenharmony_ci#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK          (0x3 << 24)
6362306a36Sopenharmony_ci#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE               (0x1 << 24)
6462306a36Sopenharmony_ci#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK        (0x3 << 26)
6562306a36Sopenharmony_ci#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH             (0x3 << 26)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define T_SATA_CFG_PHY_0                                0x120
6862306a36Sopenharmony_ci#define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD     BIT(11)
6962306a36Sopenharmony_ci#define T_SATA_CFG_PHY_0_MASK_SQUELCH                   BIT(24)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define T_SATA0_CFG2NVOOB_2				0x134
7262306a36Sopenharmony_ci#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK	(0x1ff << 18)
7362306a36Sopenharmony_ci#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW	(0xc << 18)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR			0x300
7662306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP	BIT(13)
7762306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP	BIT(14)
7862306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR_SALP			BIT(26)
7962306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM		BIT(17)
8062306a36Sopenharmony_ci#define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ			BIT(30)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define T_SATA0_BKDOOR_CC				0x4a4
8362306a36Sopenharmony_ci#define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK		(0xffff << 16)
8462306a36Sopenharmony_ci#define T_SATA0_BKDOOR_CC_CLASS_CODE			(0x0106 << 16)
8562306a36Sopenharmony_ci#define T_SATA0_BKDOOR_CC_PROG_IF_MASK			(0xff << 8)
8662306a36Sopenharmony_ci#define T_SATA0_BKDOOR_CC_PROG_IF			(0x01 << 8)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define T_SATA0_CFG_SATA				0x54c
8962306a36Sopenharmony_ci#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN		BIT(12)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define T_SATA0_CFG_MISC				0x550
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define T_SATA0_INDEX					0x680
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN1			0x690
9662306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK		0xff
9762306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT		0
9862306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK		(0xff << 8)
9962306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT	8
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN2			0x694
10262306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK		0xff
10362306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT		0
10462306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK		(0xff << 12)
10562306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT	12
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL2				0x69c
10862306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1		0x23
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL11				0x6d0
11162306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ		(0x2800 << 16)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL17_0			0x6e8
11462306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1	0x55010000
11562306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL18_0			0x6ec
11662306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2	0x55010000
11762306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL20_0			0x6f4
11862306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1	0x1
11962306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL21_0			0x6f8
12062306a36Sopenharmony_ci#define T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2	0x1
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* AUX Registers */
12362306a36Sopenharmony_ci#define SATA_AUX_MISC_CNTL_1_0				0x8
12462306a36Sopenharmony_ci#define SATA_AUX_MISC_CNTL_1_0_DEVSLP_OVERRIDE		BIT(17)
12562306a36Sopenharmony_ci#define SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT		BIT(13)
12662306a36Sopenharmony_ci#define SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT		BIT(15)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define SATA_AUX_RX_STAT_INT_0				0xc
12962306a36Sopenharmony_ci#define SATA_AUX_RX_STAT_INT_0_SATA_DEVSLP		BIT(7)
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define SATA_AUX_SPARE_CFG0_0				0x18
13262306a36Sopenharmony_ci#define SATA_AUX_SPARE_CFG0_0_MDAT_TIMER_AFTER_PG_VALID	BIT(14)
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define FUSE_SATA_CALIB					0x124
13562306a36Sopenharmony_ci#define FUSE_SATA_CALIB_MASK				0x3
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistruct sata_pad_calibration {
13862306a36Sopenharmony_ci	u8 gen1_tx_amp;
13962306a36Sopenharmony_ci	u8 gen1_tx_peak;
14062306a36Sopenharmony_ci	u8 gen2_tx_amp;
14162306a36Sopenharmony_ci	u8 gen2_tx_peak;
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic const struct sata_pad_calibration tegra124_pad_calibration[] = {
14562306a36Sopenharmony_ci	{0x18, 0x04, 0x18, 0x0a},
14662306a36Sopenharmony_ci	{0x0e, 0x04, 0x14, 0x0a},
14762306a36Sopenharmony_ci	{0x0e, 0x07, 0x1a, 0x0e},
14862306a36Sopenharmony_ci	{0x14, 0x0e, 0x1a, 0x0e},
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistruct tegra_ahci_ops {
15262306a36Sopenharmony_ci	int (*init)(struct ahci_host_priv *hpriv);
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistruct tegra_ahci_regs {
15662306a36Sopenharmony_ci	unsigned int nvoob_comma_cnt_mask;
15762306a36Sopenharmony_ci	unsigned int nvoob_comma_cnt_val;
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistruct tegra_ahci_soc {
16162306a36Sopenharmony_ci	const char *const		*supply_names;
16262306a36Sopenharmony_ci	u32				num_supplies;
16362306a36Sopenharmony_ci	bool				supports_devslp;
16462306a36Sopenharmony_ci	bool				has_sata_oob_rst;
16562306a36Sopenharmony_ci	const struct tegra_ahci_ops	*ops;
16662306a36Sopenharmony_ci	const struct tegra_ahci_regs	*regs;
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct tegra_ahci_priv {
17062306a36Sopenharmony_ci	struct platform_device	   *pdev;
17162306a36Sopenharmony_ci	void __iomem		   *sata_regs;
17262306a36Sopenharmony_ci	void __iomem		   *sata_aux_regs;
17362306a36Sopenharmony_ci	struct reset_control	   *sata_rst;
17462306a36Sopenharmony_ci	struct reset_control	   *sata_oob_rst;
17562306a36Sopenharmony_ci	struct reset_control	   *sata_cold_rst;
17662306a36Sopenharmony_ci	/* Needs special handling, cannot use ahci_platform */
17762306a36Sopenharmony_ci	struct clk		   *sata_clk;
17862306a36Sopenharmony_ci	struct regulator_bulk_data *supplies;
17962306a36Sopenharmony_ci	const struct tegra_ahci_soc *soc;
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void tegra_ahci_handle_quirks(struct ahci_host_priv *hpriv)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra = hpriv->plat_data;
18562306a36Sopenharmony_ci	u32 val;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (tegra->sata_aux_regs && !tegra->soc->supports_devslp) {
18862306a36Sopenharmony_ci		val = readl(tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
18962306a36Sopenharmony_ci		val &= ~SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT;
19062306a36Sopenharmony_ci		writel(val, tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int tegra124_ahci_init(struct ahci_host_priv *hpriv)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra = hpriv->plat_data;
19762306a36Sopenharmony_ci	struct sata_pad_calibration calib;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci	u32 val;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Pad calibration */
20262306a36Sopenharmony_ci	ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
20362306a36Sopenharmony_ci	if (ret)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	val = readl(tegra->sata_regs +
21162306a36Sopenharmony_ci		    SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
21262306a36Sopenharmony_ci	val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
21362306a36Sopenharmony_ci	val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
21462306a36Sopenharmony_ci	val |= calib.gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
21562306a36Sopenharmony_ci	val |= calib.gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
21662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET +
21762306a36Sopenharmony_ci	       T_SATA0_CHX_PHY_CTRL1_GEN1);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	val = readl(tegra->sata_regs +
22062306a36Sopenharmony_ci		    SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
22162306a36Sopenharmony_ci	val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
22262306a36Sopenharmony_ci	val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
22362306a36Sopenharmony_ci	val |= calib.gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
22462306a36Sopenharmony_ci	val |= calib.gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
22562306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET +
22662306a36Sopenharmony_ci	       T_SATA0_CHX_PHY_CTRL1_GEN2);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
22962306a36Sopenharmony_ci	       tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
23062306a36Sopenharmony_ci	writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
23162306a36Sopenharmony_ci	       tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra = hpriv->plat_data;
24162306a36Sopenharmony_ci	int ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ret = regulator_bulk_enable(tegra->soc->num_supplies,
24462306a36Sopenharmony_ci				    tegra->supplies);
24562306a36Sopenharmony_ci	if (ret)
24662306a36Sopenharmony_ci		return ret;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (!tegra->pdev->dev.pm_domain) {
24962306a36Sopenharmony_ci		ret = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SATA,
25062306a36Sopenharmony_ci							tegra->sata_clk,
25162306a36Sopenharmony_ci							tegra->sata_rst);
25262306a36Sopenharmony_ci		if (ret)
25362306a36Sopenharmony_ci			goto disable_regulators;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	reset_control_assert(tegra->sata_oob_rst);
25762306a36Sopenharmony_ci	reset_control_assert(tegra->sata_cold_rst);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	ret = ahci_platform_enable_resources(hpriv);
26062306a36Sopenharmony_ci	if (ret)
26162306a36Sopenharmony_ci		goto disable_power;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	reset_control_deassert(tegra->sata_cold_rst);
26462306a36Sopenharmony_ci	reset_control_deassert(tegra->sata_oob_rst);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cidisable_power:
26962306a36Sopenharmony_ci	clk_disable_unprepare(tegra->sata_clk);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!tegra->pdev->dev.pm_domain)
27262306a36Sopenharmony_ci		tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cidisable_regulators:
27562306a36Sopenharmony_ci	regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return ret;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra = hpriv->plat_data;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	ahci_platform_disable_resources(hpriv);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	reset_control_assert(tegra->sata_rst);
28762306a36Sopenharmony_ci	reset_control_assert(tegra->sata_oob_rst);
28862306a36Sopenharmony_ci	reset_control_assert(tegra->sata_cold_rst);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	clk_disable_unprepare(tegra->sata_clk);
29162306a36Sopenharmony_ci	if (!tegra->pdev->dev.pm_domain)
29262306a36Sopenharmony_ci		tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra = hpriv->plat_data;
30062306a36Sopenharmony_ci	int ret;
30162306a36Sopenharmony_ci	u32 val;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ret = tegra_ahci_power_on(hpriv);
30462306a36Sopenharmony_ci	if (ret) {
30562306a36Sopenharmony_ci		dev_err(&tegra->pdev->dev,
30662306a36Sopenharmony_ci			"failed to power on AHCI controller: %d\n", ret);
30762306a36Sopenharmony_ci		return ret;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * Program the following SATA IPFS registers to allow SW accesses to
31262306a36Sopenharmony_ci	 * SATA's MMIO register range.
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SATA_FPCI_BAR5);
31562306a36Sopenharmony_ci	val &= ~(SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE);
31662306a36Sopenharmony_ci	val |= SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE;
31762306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SATA_FPCI_BAR5);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Program the following SATA IPFS register to enable the SATA */
32062306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
32162306a36Sopenharmony_ci	val |= SATA_CONFIGURATION_0_EN_FPCI;
32262306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Electrical settings for better link stability */
32562306a36Sopenharmony_ci	val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1;
32662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0);
32762306a36Sopenharmony_ci	val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2;
32862306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0);
32962306a36Sopenharmony_ci	val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1;
33062306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20_0);
33162306a36Sopenharmony_ci	val = T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2;
33262306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21_0);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
33762306a36Sopenharmony_ci	val |= T_SATA_CFG_PHY_0_MASK_SQUELCH;
33862306a36Sopenharmony_ci	val &= ~T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD;
33962306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
34262306a36Sopenharmony_ci	val &= ~(tegra->soc->regs->nvoob_comma_cnt_mask |
34362306a36Sopenharmony_ci		 T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
34462306a36Sopenharmony_ci		 T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK);
34562306a36Sopenharmony_ci	val |= (tegra->soc->regs->nvoob_comma_cnt_val |
34662306a36Sopenharmony_ci		T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
34762306a36Sopenharmony_ci		T_SATA0_NVOOB_SQUELCH_FILTER_MODE);
34862306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/*
35162306a36Sopenharmony_ci	 * Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8ns
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
35462306a36Sopenharmony_ci	val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
35562306a36Sopenharmony_ci	val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
35662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (tegra->soc->ops && tegra->soc->ops->init)
35962306a36Sopenharmony_ci		tegra->soc->ops->init(hpriv);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/*
36262306a36Sopenharmony_ci	 * Program the following SATA configuration registers to
36362306a36Sopenharmony_ci	 * initialize SATA
36462306a36Sopenharmony_ci	 */
36562306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
36662306a36Sopenharmony_ci	val |= (T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
36762306a36Sopenharmony_ci		T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR);
36862306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
36962306a36Sopenharmony_ci	val = T_SATA0_CFG_9_BASE_ADDRESS;
37062306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Program Class Code and Programming interface for SATA */
37362306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
37462306a36Sopenharmony_ci	val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
37562306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
37862306a36Sopenharmony_ci	val &=
37962306a36Sopenharmony_ci	    ~(T_SATA0_BKDOOR_CC_CLASS_CODE_MASK |
38062306a36Sopenharmony_ci	      T_SATA0_BKDOOR_CC_PROG_IF_MASK);
38162306a36Sopenharmony_ci	val |= T_SATA0_BKDOOR_CC_CLASS_CODE | T_SATA0_BKDOOR_CC_PROG_IF;
38262306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
38562306a36Sopenharmony_ci	val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
38662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Enabling LPM capabilities through Backdoor Programming */
38962306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
39062306a36Sopenharmony_ci	val |= (T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
39162306a36Sopenharmony_ci		T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
39262306a36Sopenharmony_ci		T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
39362306a36Sopenharmony_ci		T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM);
39462306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* SATA Second Level Clock Gating configuration
39762306a36Sopenharmony_ci	 * Enabling Gating of Tx/Rx clocks and driving Pad IDDQ and Lane
39862306a36Sopenharmony_ci	 * IDDQ Signals
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
40162306a36Sopenharmony_ci	val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK;
40262306a36Sopenharmony_ci	val |= T_SATA0_CFG_35_IDP_INDEX;
40362306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	val = T_SATA0_AHCI_IDP1_DATA;
40662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
40962306a36Sopenharmony_ci	val |= (T_SATA0_CFG_PHY_1_PADS_IDDQ_EN |
41062306a36Sopenharmony_ci		T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN);
41162306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* Enabling IPFS Clock Gating */
41462306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
41562306a36Sopenharmony_ci	val &= ~SATA_CONFIGURATION_0_CLK_OVERRIDE;
41662306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	tegra_ahci_handle_quirks(hpriv);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Unmask SATA interrupts */
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	val = readl(tegra->sata_regs + SATA_INTR_MASK);
42362306a36Sopenharmony_ci	val |= SATA_INTR_MASK_IP_INT_MASK;
42462306a36Sopenharmony_ci	writel(val, tegra->sata_regs + SATA_INTR_MASK);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return 0;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic void tegra_ahci_controller_deinit(struct ahci_host_priv *hpriv)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	tegra_ahci_power_off(hpriv);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void tegra_ahci_host_stop(struct ata_host *host)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct ahci_host_priv *hpriv = host->private_data;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	tegra_ahci_controller_deinit(hpriv);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic struct ata_port_operations ahci_tegra_port_ops = {
44262306a36Sopenharmony_ci	.inherits	= &ahci_ops,
44362306a36Sopenharmony_ci	.host_stop	= tegra_ahci_host_stop,
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic const struct ata_port_info ahci_tegra_port_info = {
44762306a36Sopenharmony_ci	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
44862306a36Sopenharmony_ci	.pio_mask	= ATA_PIO4,
44962306a36Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
45062306a36Sopenharmony_ci	.port_ops	= &ahci_tegra_port_ops,
45162306a36Sopenharmony_ci};
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic const char *const tegra124_supply_names[] = {
45462306a36Sopenharmony_ci	"avdd", "hvdd", "vddio", "target-5v", "target-12v"
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic const struct tegra_ahci_ops tegra124_ahci_ops = {
45862306a36Sopenharmony_ci	.init = tegra124_ahci_init,
45962306a36Sopenharmony_ci};
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic const struct tegra_ahci_regs tegra124_ahci_regs = {
46262306a36Sopenharmony_ci	.nvoob_comma_cnt_mask = GENMASK(30, 28),
46362306a36Sopenharmony_ci	.nvoob_comma_cnt_val = (7 << 28),
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic const struct tegra_ahci_soc tegra124_ahci_soc = {
46762306a36Sopenharmony_ci	.supply_names = tegra124_supply_names,
46862306a36Sopenharmony_ci	.num_supplies = ARRAY_SIZE(tegra124_supply_names),
46962306a36Sopenharmony_ci	.supports_devslp = false,
47062306a36Sopenharmony_ci	.has_sata_oob_rst = true,
47162306a36Sopenharmony_ci	.ops = &tegra124_ahci_ops,
47262306a36Sopenharmony_ci	.regs = &tegra124_ahci_regs,
47362306a36Sopenharmony_ci};
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic const struct tegra_ahci_soc tegra210_ahci_soc = {
47662306a36Sopenharmony_ci	.supports_devslp = false,
47762306a36Sopenharmony_ci	.has_sata_oob_rst = true,
47862306a36Sopenharmony_ci	.regs = &tegra124_ahci_regs,
47962306a36Sopenharmony_ci};
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic const struct tegra_ahci_regs tegra186_ahci_regs = {
48262306a36Sopenharmony_ci	.nvoob_comma_cnt_mask = GENMASK(23, 16),
48362306a36Sopenharmony_ci	.nvoob_comma_cnt_val = (7 << 16),
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic const struct tegra_ahci_soc tegra186_ahci_soc = {
48762306a36Sopenharmony_ci	.supports_devslp = false,
48862306a36Sopenharmony_ci	.has_sata_oob_rst = false,
48962306a36Sopenharmony_ci	.regs = &tegra186_ahci_regs,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic const struct of_device_id tegra_ahci_of_match[] = {
49362306a36Sopenharmony_ci	{
49462306a36Sopenharmony_ci		.compatible = "nvidia,tegra124-ahci",
49562306a36Sopenharmony_ci		.data = &tegra124_ahci_soc
49662306a36Sopenharmony_ci	},
49762306a36Sopenharmony_ci	{
49862306a36Sopenharmony_ci		.compatible = "nvidia,tegra210-ahci",
49962306a36Sopenharmony_ci		.data = &tegra210_ahci_soc
50062306a36Sopenharmony_ci	},
50162306a36Sopenharmony_ci	{
50262306a36Sopenharmony_ci		.compatible = "nvidia,tegra186-ahci",
50362306a36Sopenharmony_ci		.data = &tegra186_ahci_soc
50462306a36Sopenharmony_ci	},
50562306a36Sopenharmony_ci	{}
50662306a36Sopenharmony_ci};
50762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic const struct scsi_host_template ahci_platform_sht = {
51062306a36Sopenharmony_ci	AHCI_SHT(DRV_NAME),
51162306a36Sopenharmony_ci};
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int tegra_ahci_probe(struct platform_device *pdev)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct ahci_host_priv *hpriv;
51662306a36Sopenharmony_ci	struct tegra_ahci_priv *tegra;
51762306a36Sopenharmony_ci	struct resource *res;
51862306a36Sopenharmony_ci	int ret;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	hpriv = ahci_platform_get_resources(pdev, 0);
52162306a36Sopenharmony_ci	if (IS_ERR(hpriv))
52262306a36Sopenharmony_ci		return PTR_ERR(hpriv);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
52562306a36Sopenharmony_ci	if (!tegra)
52662306a36Sopenharmony_ci		return -ENOMEM;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	hpriv->plat_data = tegra;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	tegra->pdev = pdev;
53162306a36Sopenharmony_ci	tegra->soc = of_device_get_match_data(&pdev->dev);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	tegra->sata_regs = devm_platform_ioremap_resource(pdev, 1);
53462306a36Sopenharmony_ci	if (IS_ERR(tegra->sata_regs))
53562306a36Sopenharmony_ci		return PTR_ERR(tegra->sata_regs);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/*
53862306a36Sopenharmony_ci	 * AUX registers is optional.
53962306a36Sopenharmony_ci	 */
54062306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
54162306a36Sopenharmony_ci	if (res) {
54262306a36Sopenharmony_ci		tegra->sata_aux_regs = devm_ioremap_resource(&pdev->dev, res);
54362306a36Sopenharmony_ci		if (IS_ERR(tegra->sata_aux_regs))
54462306a36Sopenharmony_ci			return PTR_ERR(tegra->sata_aux_regs);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata");
54862306a36Sopenharmony_ci	if (IS_ERR(tegra->sata_rst)) {
54962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get sata reset\n");
55062306a36Sopenharmony_ci		return PTR_ERR(tegra->sata_rst);
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (tegra->soc->has_sata_oob_rst) {
55462306a36Sopenharmony_ci		tegra->sata_oob_rst = devm_reset_control_get(&pdev->dev,
55562306a36Sopenharmony_ci							     "sata-oob");
55662306a36Sopenharmony_ci		if (IS_ERR(tegra->sata_oob_rst)) {
55762306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to get sata-oob reset\n");
55862306a36Sopenharmony_ci			return PTR_ERR(tegra->sata_oob_rst);
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	tegra->sata_cold_rst = devm_reset_control_get(&pdev->dev, "sata-cold");
56362306a36Sopenharmony_ci	if (IS_ERR(tegra->sata_cold_rst)) {
56462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get sata-cold reset\n");
56562306a36Sopenharmony_ci		return PTR_ERR(tegra->sata_cold_rst);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	tegra->sata_clk = devm_clk_get(&pdev->dev, "sata");
56962306a36Sopenharmony_ci	if (IS_ERR(tegra->sata_clk)) {
57062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get sata clock\n");
57162306a36Sopenharmony_ci		return PTR_ERR(tegra->sata_clk);
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	tegra->supplies = devm_kcalloc(&pdev->dev,
57562306a36Sopenharmony_ci				       tegra->soc->num_supplies,
57662306a36Sopenharmony_ci				       sizeof(*tegra->supplies), GFP_KERNEL);
57762306a36Sopenharmony_ci	if (!tegra->supplies)
57862306a36Sopenharmony_ci		return -ENOMEM;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	regulator_bulk_set_supply_names(tegra->supplies,
58162306a36Sopenharmony_ci					tegra->soc->supply_names,
58262306a36Sopenharmony_ci					tegra->soc->num_supplies);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	ret = devm_regulator_bulk_get(&pdev->dev,
58562306a36Sopenharmony_ci				      tegra->soc->num_supplies,
58662306a36Sopenharmony_ci				      tegra->supplies);
58762306a36Sopenharmony_ci	if (ret) {
58862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to get regulators\n");
58962306a36Sopenharmony_ci		return ret;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	ret = tegra_ahci_controller_init(hpriv);
59362306a36Sopenharmony_ci	if (ret)
59462306a36Sopenharmony_ci		return ret;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info,
59762306a36Sopenharmony_ci				      &ahci_platform_sht);
59862306a36Sopenharmony_ci	if (ret)
59962306a36Sopenharmony_ci		goto deinit_controller;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return 0;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cideinit_controller:
60462306a36Sopenharmony_ci	tegra_ahci_controller_deinit(hpriv);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return ret;
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic struct platform_driver tegra_ahci_driver = {
61062306a36Sopenharmony_ci	.probe = tegra_ahci_probe,
61162306a36Sopenharmony_ci	.remove_new = ata_platform_remove_one,
61262306a36Sopenharmony_ci	.driver = {
61362306a36Sopenharmony_ci		.name = DRV_NAME,
61462306a36Sopenharmony_ci		.of_match_table = tegra_ahci_of_match,
61562306a36Sopenharmony_ci	},
61662306a36Sopenharmony_ci	/* LP0 suspend support not implemented */
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_cimodule_platform_driver(tegra_ahci_driver);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ciMODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
62162306a36Sopenharmony_ciMODULE_DESCRIPTION("Tegra AHCI SATA driver");
62262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
623