root/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qcom_ipq806x_sata_phy_init
  2. qcom_ipq806x_sata_phy_exit
  3. qcom_ipq806x_sata_phy_probe
  4. qcom_ipq806x_sata_phy_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   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 
  18 struct 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              0x200
  27 #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              0x204
  35 #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              0x208
  44 #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              0x20C
  48 #define SATA_PHY_SSC_EN                 0x8
  49 #define SATA_PHY_P0_PARAM4              0x210
  50 #define SATA_PHY_REF_SSP_EN             0x2
  51 #define SATA_PHY_RESET                  0x1
  52 
  53 static 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 
 108 static 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 
 121 static 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 
 127 static 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 resource *res;
 132         struct phy_provider *phy_provider;
 133         struct phy *generic_phy;
 134         int ret;
 135 
 136         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
 137         if (!phy)
 138                 return -ENOMEM;
 139 
 140         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 141         phy->mmio = devm_ioremap_resource(dev, res);
 142         if (IS_ERR(phy->mmio))
 143                 return PTR_ERR(phy->mmio);
 144 
 145         generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);
 146         if (IS_ERR(generic_phy)) {
 147                 dev_err(dev, "%s: failed to create phy\n", __func__);
 148                 return PTR_ERR(generic_phy);
 149         }
 150 
 151         phy->dev = dev;
 152         phy_set_drvdata(generic_phy, phy);
 153         platform_set_drvdata(pdev, phy);
 154 
 155         phy->cfg_clk = devm_clk_get(dev, "cfg");
 156         if (IS_ERR(phy->cfg_clk)) {
 157                 dev_err(dev, "Failed to get sata cfg clock\n");
 158                 return PTR_ERR(phy->cfg_clk);
 159         }
 160 
 161         ret = clk_prepare_enable(phy->cfg_clk);
 162         if (ret)
 163                 return ret;
 164 
 165         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 166         if (IS_ERR(phy_provider)) {
 167                 clk_disable_unprepare(phy->cfg_clk);
 168                 dev_err(dev, "%s: failed to register phy\n", __func__);
 169                 return PTR_ERR(phy_provider);
 170         }
 171 
 172         return 0;
 173 }
 174 
 175 static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev)
 176 {
 177         struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev);
 178 
 179         clk_disable_unprepare(phy->cfg_clk);
 180 
 181         return 0;
 182 }
 183 
 184 static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = {
 185         { .compatible = "qcom,ipq806x-sata-phy" },
 186         { },
 187 };
 188 MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match);
 189 
 190 static struct platform_driver qcom_ipq806x_sata_phy_driver = {
 191         .probe  = qcom_ipq806x_sata_phy_probe,
 192         .remove = qcom_ipq806x_sata_phy_remove,
 193         .driver = {
 194                 .name   = "qcom-ipq806x-sata-phy",
 195                 .of_match_table = qcom_ipq806x_sata_phy_of_match,
 196         }
 197 };
 198 module_platform_driver(qcom_ipq806x_sata_phy_driver);
 199 
 200 MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver");
 201 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */