162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ST SPEAr1310-miphy driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 ST Microelectronics
662306a36Sopenharmony_ci * Pratyush Anand <pratyush.anand@gmail.com>
762306a36Sopenharmony_ci * Mohit Kumar <mohit.kumar.dhaka@gmail.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/phy/phy.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* SPEAr1310 Registers */
2262306a36Sopenharmony_ci#define SPEAR1310_PCIE_SATA_CFG			0x3A4
2362306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA2_SEL_PCIE		(0 << 31)
2462306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA1_SEL_PCIE		(0 << 30)
2562306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA0_SEL_PCIE		(0 << 29)
2662306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA2_SEL_SATA		BIT(31)
2762306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA1_SEL_SATA		BIT(30)
2862306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA0_SEL_SATA		BIT(29)
2962306a36Sopenharmony_ci	#define SPEAR1310_SATA2_CFG_TX_CLK_EN		BIT(27)
3062306a36Sopenharmony_ci	#define SPEAR1310_SATA2_CFG_RX_CLK_EN		BIT(26)
3162306a36Sopenharmony_ci	#define SPEAR1310_SATA2_CFG_POWERUP_RESET	BIT(25)
3262306a36Sopenharmony_ci	#define SPEAR1310_SATA2_CFG_PM_CLK_EN		BIT(24)
3362306a36Sopenharmony_ci	#define SPEAR1310_SATA1_CFG_TX_CLK_EN		BIT(23)
3462306a36Sopenharmony_ci	#define SPEAR1310_SATA1_CFG_RX_CLK_EN		BIT(22)
3562306a36Sopenharmony_ci	#define SPEAR1310_SATA1_CFG_POWERUP_RESET	BIT(21)
3662306a36Sopenharmony_ci	#define SPEAR1310_SATA1_CFG_PM_CLK_EN		BIT(20)
3762306a36Sopenharmony_ci	#define SPEAR1310_SATA0_CFG_TX_CLK_EN		BIT(19)
3862306a36Sopenharmony_ci	#define SPEAR1310_SATA0_CFG_RX_CLK_EN		BIT(18)
3962306a36Sopenharmony_ci	#define SPEAR1310_SATA0_CFG_POWERUP_RESET	BIT(17)
4062306a36Sopenharmony_ci	#define SPEAR1310_SATA0_CFG_PM_CLK_EN		BIT(16)
4162306a36Sopenharmony_ci	#define SPEAR1310_PCIE2_CFG_DEVICE_PRESENT	BIT(11)
4262306a36Sopenharmony_ci	#define SPEAR1310_PCIE2_CFG_POWERUP_RESET	BIT(10)
4362306a36Sopenharmony_ci	#define SPEAR1310_PCIE2_CFG_CORE_CLK_EN		BIT(9)
4462306a36Sopenharmony_ci	#define SPEAR1310_PCIE2_CFG_AUX_CLK_EN		BIT(8)
4562306a36Sopenharmony_ci	#define SPEAR1310_PCIE1_CFG_DEVICE_PRESENT	BIT(7)
4662306a36Sopenharmony_ci	#define SPEAR1310_PCIE1_CFG_POWERUP_RESET	BIT(6)
4762306a36Sopenharmony_ci	#define SPEAR1310_PCIE1_CFG_CORE_CLK_EN		BIT(5)
4862306a36Sopenharmony_ci	#define SPEAR1310_PCIE1_CFG_AUX_CLK_EN		BIT(4)
4962306a36Sopenharmony_ci	#define SPEAR1310_PCIE0_CFG_DEVICE_PRESENT	BIT(3)
5062306a36Sopenharmony_ci	#define SPEAR1310_PCIE0_CFG_POWERUP_RESET	BIT(2)
5162306a36Sopenharmony_ci	#define SPEAR1310_PCIE0_CFG_CORE_CLK_EN		BIT(1)
5262306a36Sopenharmony_ci	#define SPEAR1310_PCIE0_CFG_AUX_CLK_EN		BIT(0)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	#define SPEAR1310_PCIE_CFG_MASK(x) ((0xF << (x * 4)) | BIT((x + 29)))
5562306a36Sopenharmony_ci	#define SPEAR1310_SATA_CFG_MASK(x) ((0xF << (x * 4 + 16)) | \
5662306a36Sopenharmony_ci			BIT((x + 29)))
5762306a36Sopenharmony_ci	#define SPEAR1310_PCIE_CFG_VAL(x) \
5862306a36Sopenharmony_ci			(SPEAR1310_PCIE_SATA##x##_SEL_PCIE | \
5962306a36Sopenharmony_ci			SPEAR1310_PCIE##x##_CFG_AUX_CLK_EN | \
6062306a36Sopenharmony_ci			SPEAR1310_PCIE##x##_CFG_CORE_CLK_EN | \
6162306a36Sopenharmony_ci			SPEAR1310_PCIE##x##_CFG_POWERUP_RESET | \
6262306a36Sopenharmony_ci			SPEAR1310_PCIE##x##_CFG_DEVICE_PRESENT)
6362306a36Sopenharmony_ci	#define SPEAR1310_SATA_CFG_VAL(x) \
6462306a36Sopenharmony_ci			(SPEAR1310_PCIE_SATA##x##_SEL_SATA | \
6562306a36Sopenharmony_ci			SPEAR1310_SATA##x##_CFG_PM_CLK_EN | \
6662306a36Sopenharmony_ci			SPEAR1310_SATA##x##_CFG_POWERUP_RESET | \
6762306a36Sopenharmony_ci			SPEAR1310_SATA##x##_CFG_RX_CLK_EN | \
6862306a36Sopenharmony_ci			SPEAR1310_SATA##x##_CFG_TX_CLK_EN)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define SPEAR1310_PCIE_MIPHY_CFG_1		0x3A8
7162306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT	BIT(31)
7262306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2	BIT(28)
7362306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(x)	(x << 16)
7462306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT	BIT(15)
7562306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2	BIT(12)
7662306a36Sopenharmony_ci	#define SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(x)	(x << 0)
7762306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_MASK (0xFFFF)
7862306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK (0xFFFF << 16)
7962306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA \
8062306a36Sopenharmony_ci			(SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
8162306a36Sopenharmony_ci			SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 | \
8262306a36Sopenharmony_ci			SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(60) | \
8362306a36Sopenharmony_ci			SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
8462306a36Sopenharmony_ci			SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 | \
8562306a36Sopenharmony_ci			SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(60))
8662306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
8762306a36Sopenharmony_ci			(SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(120))
8862306a36Sopenharmony_ci	#define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE \
8962306a36Sopenharmony_ci			(SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
9062306a36Sopenharmony_ci			SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(25) | \
9162306a36Sopenharmony_ci			SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
9262306a36Sopenharmony_ci			SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(25))
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define SPEAR1310_PCIE_MIPHY_CFG_2		0x3AC
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cienum spear1310_miphy_mode {
9762306a36Sopenharmony_ci	SATA,
9862306a36Sopenharmony_ci	PCIE,
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistruct spear1310_miphy_priv {
10262306a36Sopenharmony_ci	/* instance id of this phy */
10362306a36Sopenharmony_ci	u32				id;
10462306a36Sopenharmony_ci	/* phy mode: 0 for SATA 1 for PCIe */
10562306a36Sopenharmony_ci	enum spear1310_miphy_mode	mode;
10662306a36Sopenharmony_ci	/* regmap for any soc specific misc registers */
10762306a36Sopenharmony_ci	struct regmap			*misc;
10862306a36Sopenharmony_ci	/* phy struct pointer */
10962306a36Sopenharmony_ci	struct phy			*phy;
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int spear1310_miphy_pcie_init(struct spear1310_miphy_priv *priv)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	u32 val;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
11762306a36Sopenharmony_ci			   SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK,
11862306a36Sopenharmony_ci			   SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	switch (priv->id) {
12162306a36Sopenharmony_ci	case 0:
12262306a36Sopenharmony_ci		val = SPEAR1310_PCIE_CFG_VAL(0);
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	case 1:
12562306a36Sopenharmony_ci		val = SPEAR1310_PCIE_CFG_VAL(1);
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case 2:
12862306a36Sopenharmony_ci		val = SPEAR1310_PCIE_CFG_VAL(2);
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	default:
13162306a36Sopenharmony_ci		return -EINVAL;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
13562306a36Sopenharmony_ci			   SPEAR1310_PCIE_CFG_MASK(priv->id), val);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int spear1310_miphy_pcie_exit(struct spear1310_miphy_priv *priv)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
14362306a36Sopenharmony_ci			   SPEAR1310_PCIE_CFG_MASK(priv->id), 0);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
14662306a36Sopenharmony_ci			   SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 0);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int spear1310_miphy_init(struct phy *phy)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
15462306a36Sopenharmony_ci	int ret = 0;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (priv->mode == PCIE)
15762306a36Sopenharmony_ci		ret = spear1310_miphy_pcie_init(priv);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return ret;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int spear1310_miphy_exit(struct phy *phy)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
16562306a36Sopenharmony_ci	int ret = 0;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (priv->mode == PCIE)
16862306a36Sopenharmony_ci		ret = spear1310_miphy_pcie_exit(priv);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return ret;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic const struct of_device_id spear1310_miphy_of_match[] = {
17462306a36Sopenharmony_ci	{ .compatible = "st,spear1310-miphy" },
17562306a36Sopenharmony_ci	{ },
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spear1310_miphy_of_match);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct phy_ops spear1310_miphy_ops = {
18062306a36Sopenharmony_ci	.init = spear1310_miphy_init,
18162306a36Sopenharmony_ci	.exit = spear1310_miphy_exit,
18262306a36Sopenharmony_ci	.owner = THIS_MODULE,
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic struct phy *spear1310_miphy_xlate(struct device *dev,
18662306a36Sopenharmony_ci					 struct of_phandle_args *args)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct spear1310_miphy_priv *priv = dev_get_drvdata(dev);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (args->args_count < 1) {
19162306a36Sopenharmony_ci		dev_err(dev, "DT did not pass correct no of args\n");
19262306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	priv->mode = args->args[0];
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (priv->mode != SATA && priv->mode != PCIE) {
19862306a36Sopenharmony_ci		dev_err(dev, "DT did not pass correct phy mode\n");
19962306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return priv->phy;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int spear1310_miphy_probe(struct platform_device *pdev)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
20862306a36Sopenharmony_ci	struct spear1310_miphy_priv *priv;
20962306a36Sopenharmony_ci	struct phy_provider *phy_provider;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
21262306a36Sopenharmony_ci	if (!priv)
21362306a36Sopenharmony_ci		return -ENOMEM;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	priv->misc =
21662306a36Sopenharmony_ci		syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
21762306a36Sopenharmony_ci	if (IS_ERR(priv->misc)) {
21862306a36Sopenharmony_ci		dev_err(dev, "failed to find misc regmap\n");
21962306a36Sopenharmony_ci		return PTR_ERR(priv->misc);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node, "phy-id", &priv->id)) {
22362306a36Sopenharmony_ci		dev_err(dev, "failed to find phy id\n");
22462306a36Sopenharmony_ci		return -EINVAL;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops);
22862306a36Sopenharmony_ci	if (IS_ERR(priv->phy)) {
22962306a36Sopenharmony_ci		dev_err(dev, "failed to create SATA PCIe PHY\n");
23062306a36Sopenharmony_ci		return PTR_ERR(priv->phy);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	dev_set_drvdata(dev, priv);
23462306a36Sopenharmony_ci	phy_set_drvdata(priv->phy, priv);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	phy_provider =
23762306a36Sopenharmony_ci		devm_of_phy_provider_register(dev, spear1310_miphy_xlate);
23862306a36Sopenharmony_ci	if (IS_ERR(phy_provider)) {
23962306a36Sopenharmony_ci		dev_err(dev, "failed to register phy provider\n");
24062306a36Sopenharmony_ci		return PTR_ERR(phy_provider);
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic struct platform_driver spear1310_miphy_driver = {
24762306a36Sopenharmony_ci	.probe		= spear1310_miphy_probe,
24862306a36Sopenharmony_ci	.driver = {
24962306a36Sopenharmony_ci		.name = "spear1310-miphy",
25062306a36Sopenharmony_ci		.of_match_table = spear1310_miphy_of_match,
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cimodule_platform_driver(spear1310_miphy_driver);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciMODULE_DESCRIPTION("ST SPEAR1310-MIPHY driver");
25762306a36Sopenharmony_ciMODULE_AUTHOR("Pratyush Anand <pratyush.anand@gmail.com>");
25862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
259