brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · f0a72b8 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.4 */5 6#include <linux/io.h>7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/of_address.h>11#include <linux/time.h>12#include <linux/delay.h>13#include <linux/clk.h>14#include <linux/slab.h>15#include <linux/platform_device.h>16#include <linux/phy/phy.h>17 18struct qcom_ipq806x_sata_phy {19	void __iomem *mmio;20	struct clk *cfg_clk;21	struct device *dev;22};23 24#define __set(v, a, b)	(((v) << (b)) & GENMASK(a, b))25 26#define SATA_PHY_P0_PARAM0		0x20027#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(x)	__set(x, 17, 12)28#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK	GENMASK(17, 12)29#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2(x)	__set(x, 11, 6)30#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK	GENMASK(11, 6)31#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1(x)	__set(x, 5, 0)32#define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK	GENMASK(5, 0)33 34#define SATA_PHY_P0_PARAM1		0x20435#define SATA_PHY_P0_PARAM1_RESERVED_BITS31_21(x)	__set(x, 31, 21)36#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(x)	__set(x, 20, 14)37#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK	GENMASK(20, 14)38#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(x)	__set(x, 13, 7)39#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK	GENMASK(13, 7)40#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(x)	__set(x, 6, 0)41#define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK	GENMASK(6, 0)42 43#define SATA_PHY_P0_PARAM2		0x20844#define SATA_PHY_P0_PARAM2_RX_EQ(x)	__set(x, 20, 18)45#define SATA_PHY_P0_PARAM2_RX_EQ_MASK	GENMASK(20, 18)46 47#define SATA_PHY_P0_PARAM3		0x20C48#define SATA_PHY_SSC_EN			0x849#define SATA_PHY_P0_PARAM4		0x21050#define SATA_PHY_REF_SSP_EN		0x251#define SATA_PHY_RESET			0x152 53static int qcom_ipq806x_sata_phy_init(struct phy *generic_phy)54{55	struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy);56	u32 reg;57 58	/* Setting SSC_EN to 1 */59	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM3);60	reg = reg | SATA_PHY_SSC_EN;61	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM3);62 63	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM0) &64			~(SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK |65			  SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK |66			  SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK);67	reg |= SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(0xf);68	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM0);69 70	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM1) &71			~(SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK |72			  SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK |73			  SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK);74	reg |= SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(0x55) |75		SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(0x55) |76		SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(0x55);77	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM1);78 79	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM2) &80		~SATA_PHY_P0_PARAM2_RX_EQ_MASK;81	reg |= SATA_PHY_P0_PARAM2_RX_EQ(0x3);82	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM2);83 84	/* Setting PHY_RESET to 1 */85	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4);86	reg = reg | SATA_PHY_RESET;87	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4);88 89	/* Setting REF_SSP_EN to 1 */90	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4);91	reg = reg | SATA_PHY_REF_SSP_EN | SATA_PHY_RESET;92	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4);93 94	/* make sure all changes complete before we let the PHY out of reset */95	mb();96 97	/* sleep for max. 50us more to combine processor wakeups */98	usleep_range(20, 20 + 50);99 100	/* Clearing PHY_RESET to 0 */101	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4);102	reg = reg & ~SATA_PHY_RESET;103	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4);104 105	return 0;106}107 108static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy)109{110	struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy);111	u32 reg;112 113	/* Setting PHY_RESET to 1 */114	reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4);115	reg = reg | SATA_PHY_RESET;116	writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4);117 118	return 0;119}120 121static const struct phy_ops qcom_ipq806x_sata_phy_ops = {122	.init		= qcom_ipq806x_sata_phy_init,123	.exit		= qcom_ipq806x_sata_phy_exit,124	.owner		= THIS_MODULE,125};126 127static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)128{129	struct qcom_ipq806x_sata_phy *phy;130	struct device *dev = &pdev->dev;131	struct phy_provider *phy_provider;132	struct phy *generic_phy;133	int ret;134 135	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);136	if (!phy)137		return -ENOMEM;138 139	phy->mmio = devm_platform_ioremap_resource(pdev, 0);140	if (IS_ERR(phy->mmio))141		return PTR_ERR(phy->mmio);142 143	generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);144	if (IS_ERR(generic_phy)) {145		dev_err(dev, "%s: failed to create phy\n", __func__);146		return PTR_ERR(generic_phy);147	}148 149	phy->dev = dev;150	phy_set_drvdata(generic_phy, phy);151	platform_set_drvdata(pdev, phy);152 153	phy->cfg_clk = devm_clk_get(dev, "cfg");154	if (IS_ERR(phy->cfg_clk)) {155		dev_err(dev, "Failed to get sata cfg clock\n");156		return PTR_ERR(phy->cfg_clk);157	}158 159	ret = clk_prepare_enable(phy->cfg_clk);160	if (ret)161		return ret;162 163	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);164	if (IS_ERR(phy_provider)) {165		clk_disable_unprepare(phy->cfg_clk);166		dev_err(dev, "%s: failed to register phy\n", __func__);167		return PTR_ERR(phy_provider);168	}169 170	return 0;171}172 173static void qcom_ipq806x_sata_phy_remove(struct platform_device *pdev)174{175	struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev);176 177	clk_disable_unprepare(phy->cfg_clk);178}179 180static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = {181	{ .compatible = "qcom,ipq806x-sata-phy" },182	{ },183};184MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match);185 186static struct platform_driver qcom_ipq806x_sata_phy_driver = {187	.probe	= qcom_ipq806x_sata_phy_probe,188	.remove_new = qcom_ipq806x_sata_phy_remove,189	.driver = {190		.name	= "qcom-ipq806x-sata-phy",191		.of_match_table	= qcom_ipq806x_sata_phy_of_match,192	}193};194module_platform_driver(qcom_ipq806x_sata_phy_driver);195 196MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver");197MODULE_LICENSE("GPL v2");198