1/* 2 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include <linux/io.h> 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/of.h> 18#include <linux/time.h> 19#include <linux/delay.h> 20#include <linux/clk.h> 21#include <linux/slab.h> 22#include <linux/platform_device.h> 23#include <linux/phy/phy.h> 24 25/* PHY registers */ 26#define UNIPHY_PLL_REFCLK_CFG 0x000 27#define UNIPHY_PLL_PWRGEN_CFG 0x014 28#define UNIPHY_PLL_GLB_CFG 0x020 29#define UNIPHY_PLL_SDM_CFG0 0x038 30#define UNIPHY_PLL_SDM_CFG1 0x03C 31#define UNIPHY_PLL_SDM_CFG2 0x040 32#define UNIPHY_PLL_SDM_CFG3 0x044 33#define UNIPHY_PLL_SDM_CFG4 0x048 34#define UNIPHY_PLL_SSC_CFG0 0x04C 35#define UNIPHY_PLL_SSC_CFG1 0x050 36#define UNIPHY_PLL_SSC_CFG2 0x054 37#define UNIPHY_PLL_SSC_CFG3 0x058 38#define UNIPHY_PLL_LKDET_CFG0 0x05C 39#define UNIPHY_PLL_LKDET_CFG1 0x060 40#define UNIPHY_PLL_LKDET_CFG2 0x064 41#define UNIPHY_PLL_CAL_CFG0 0x06C 42#define UNIPHY_PLL_CAL_CFG8 0x08C 43#define UNIPHY_PLL_CAL_CFG9 0x090 44#define UNIPHY_PLL_CAL_CFG10 0x094 45#define UNIPHY_PLL_CAL_CFG11 0x098 46#define UNIPHY_PLL_STATUS 0x0C0 47 48#define SATA_PHY_SER_CTRL 0x100 49#define SATA_PHY_TX_DRIV_CTRL0 0x104 50#define SATA_PHY_TX_DRIV_CTRL1 0x108 51#define SATA_PHY_TX_IMCAL0 0x11C 52#define SATA_PHY_TX_IMCAL2 0x124 53#define SATA_PHY_RX_IMCAL0 0x128 54#define SATA_PHY_EQUAL 0x13C 55#define SATA_PHY_OOB_TERM 0x144 56#define SATA_PHY_CDR_CTRL0 0x148 57#define SATA_PHY_CDR_CTRL1 0x14C 58#define SATA_PHY_CDR_CTRL2 0x150 59#define SATA_PHY_CDR_CTRL3 0x154 60#define SATA_PHY_PI_CTRL0 0x168 61#define SATA_PHY_POW_DWN_CTRL0 0x180 62#define SATA_PHY_POW_DWN_CTRL1 0x184 63#define SATA_PHY_TX_DATA_CTRL 0x188 64#define SATA_PHY_ALIGNP 0x1A4 65#define SATA_PHY_TX_IMCAL_STAT 0x1E4 66#define SATA_PHY_RX_IMCAL_STAT 0x1E8 67 68#define UNIPHY_PLL_LOCK BIT(0) 69#define SATA_PHY_TX_CAL BIT(0) 70#define SATA_PHY_RX_CAL BIT(0) 71 72/* default timeout set to 1 sec */ 73#define TIMEOUT_MS 10000 74#define DELAY_INTERVAL_US 100 75 76struct qcom_apq8064_sata_phy { 77 void __iomem *mmio; 78 struct clk *cfg_clk; 79 struct device *dev; 80}; 81 82/* Helper function to do poll and timeout */ 83static int read_poll_timeout(void __iomem *addr, u32 mask) 84{ 85 unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); 86 87 do { 88 if (readl_relaxed(addr) & mask) 89 return 0; 90 91 usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); 92 } while (!time_after(jiffies, timeout)); 93 94 return (readl_relaxed(addr) & mask) ? 0 : -ETIMEDOUT; 95} 96 97static int qcom_apq8064_sata_phy_init(struct phy *generic_phy) 98{ 99 struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); 100 void __iomem *base = phy->mmio; 101 int ret = 0; 102 103 /* SATA phy initialization */ 104 writel_relaxed(0x01, base + SATA_PHY_SER_CTRL); 105 writel_relaxed(0xB1, base + SATA_PHY_POW_DWN_CTRL0); 106 /* Make sure the power down happens before power up */ 107 mb(); 108 usleep_range(10, 60); 109 110 writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); 111 writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); 112 writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); 113 writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); 114 writel_relaxed(0x02, base + SATA_PHY_TX_IMCAL2); 115 116 /* Write UNIPHYPLL registers to configure PLL */ 117 writel_relaxed(0x04, base + UNIPHY_PLL_REFCLK_CFG); 118 writel_relaxed(0x00, base + UNIPHY_PLL_PWRGEN_CFG); 119 120 writel_relaxed(0x0A, base + UNIPHY_PLL_CAL_CFG0); 121 writel_relaxed(0xF3, base + UNIPHY_PLL_CAL_CFG8); 122 writel_relaxed(0x01, base + UNIPHY_PLL_CAL_CFG9); 123 writel_relaxed(0xED, base + UNIPHY_PLL_CAL_CFG10); 124 writel_relaxed(0x02, base + UNIPHY_PLL_CAL_CFG11); 125 126 writel_relaxed(0x36, base + UNIPHY_PLL_SDM_CFG0); 127 writel_relaxed(0x0D, base + UNIPHY_PLL_SDM_CFG1); 128 writel_relaxed(0xA3, base + UNIPHY_PLL_SDM_CFG2); 129 writel_relaxed(0xF0, base + UNIPHY_PLL_SDM_CFG3); 130 writel_relaxed(0x00, base + UNIPHY_PLL_SDM_CFG4); 131 132 writel_relaxed(0x19, base + UNIPHY_PLL_SSC_CFG0); 133 writel_relaxed(0xE1, base + UNIPHY_PLL_SSC_CFG1); 134 writel_relaxed(0x00, base + UNIPHY_PLL_SSC_CFG2); 135 writel_relaxed(0x11, base + UNIPHY_PLL_SSC_CFG3); 136 137 writel_relaxed(0x04, base + UNIPHY_PLL_LKDET_CFG0); 138 writel_relaxed(0xFF, base + UNIPHY_PLL_LKDET_CFG1); 139 140 writel_relaxed(0x02, base + UNIPHY_PLL_GLB_CFG); 141 /* make sure global config LDO power down happens before power up */ 142 mb(); 143 144 writel_relaxed(0x03, base + UNIPHY_PLL_GLB_CFG); 145 writel_relaxed(0x05, base + UNIPHY_PLL_LKDET_CFG2); 146 147 /* PLL Lock wait */ 148 ret = read_poll_timeout(base + UNIPHY_PLL_STATUS, UNIPHY_PLL_LOCK); 149 if (ret) { 150 dev_err(phy->dev, "poll timeout UNIPHY_PLL_STATUS\n"); 151 return ret; 152 } 153 154 /* TX Calibration */ 155 ret = read_poll_timeout(base + SATA_PHY_TX_IMCAL_STAT, SATA_PHY_TX_CAL); 156 if (ret) { 157 dev_err(phy->dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n"); 158 return ret; 159 } 160 161 /* RX Calibration */ 162 ret = read_poll_timeout(base + SATA_PHY_RX_IMCAL_STAT, SATA_PHY_RX_CAL); 163 if (ret) { 164 dev_err(phy->dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n"); 165 return ret; 166 } 167 168 /* SATA phy calibrated succesfully, power up to functional mode */ 169 writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); 170 writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); 171 writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); 172 173 writel_relaxed(0x00, base + SATA_PHY_POW_DWN_CTRL1); 174 writel_relaxed(0x59, base + SATA_PHY_CDR_CTRL0); 175 writel_relaxed(0x04, base + SATA_PHY_CDR_CTRL1); 176 writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL2); 177 writel_relaxed(0x00, base + SATA_PHY_PI_CTRL0); 178 writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL3); 179 writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); 180 181 writel_relaxed(0x11, base + SATA_PHY_TX_DATA_CTRL); 182 writel_relaxed(0x43, base + SATA_PHY_ALIGNP); 183 writel_relaxed(0x04, base + SATA_PHY_OOB_TERM); 184 185 writel_relaxed(0x01, base + SATA_PHY_EQUAL); 186 writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL0); 187 writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL1); 188 189 return 0; 190} 191 192static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) 193{ 194 struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); 195 void __iomem *base = phy->mmio; 196 197 /* Power down PHY */ 198 writel_relaxed(0xF8, base + SATA_PHY_POW_DWN_CTRL0); 199 writel_relaxed(0xFE, base + SATA_PHY_POW_DWN_CTRL1); 200 201 /* Power down PLL block */ 202 writel_relaxed(0x00, base + UNIPHY_PLL_GLB_CFG); 203 204 return 0; 205} 206 207static struct phy_ops qcom_apq8064_sata_phy_ops = { 208 .init = qcom_apq8064_sata_phy_init, 209 .exit = qcom_apq8064_sata_phy_exit, 210 .owner = THIS_MODULE, 211}; 212 213static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) 214{ 215 struct qcom_apq8064_sata_phy *phy; 216 struct device *dev = &pdev->dev; 217 struct resource *res; 218 struct phy_provider *phy_provider; 219 struct phy *generic_phy; 220 int ret; 221 222 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 223 if (!phy) 224 return -ENOMEM; 225 226 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 227 phy->mmio = devm_ioremap_resource(dev, res); 228 if (IS_ERR(phy->mmio)) 229 return PTR_ERR(phy->mmio); 230 231 generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops); 232 if (IS_ERR(generic_phy)) { 233 dev_err(dev, "%s: failed to create phy\n", __func__); 234 return PTR_ERR(generic_phy); 235 } 236 237 phy->dev = dev; 238 phy_set_drvdata(generic_phy, phy); 239 platform_set_drvdata(pdev, phy); 240 241 phy->cfg_clk = devm_clk_get(dev, "cfg"); 242 if (IS_ERR(phy->cfg_clk)) { 243 dev_err(dev, "Failed to get sata cfg clock\n"); 244 return PTR_ERR(phy->cfg_clk); 245 } 246 247 ret = clk_prepare_enable(phy->cfg_clk); 248 if (ret) 249 return ret; 250 251 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 252 if (IS_ERR(phy_provider)) { 253 clk_disable_unprepare(phy->cfg_clk); 254 dev_err(dev, "%s: failed to register phy\n", __func__); 255 return PTR_ERR(phy_provider); 256 } 257 258 return 0; 259} 260 261static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev) 262{ 263 struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev); 264 265 clk_disable_unprepare(phy->cfg_clk); 266 267 return 0; 268} 269 270static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { 271 { .compatible = "qcom,apq8064-sata-phy" }, 272 { }, 273}; 274MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); 275 276static struct platform_driver qcom_apq8064_sata_phy_driver = { 277 .probe = qcom_apq8064_sata_phy_probe, 278 .remove = qcom_apq8064_sata_phy_remove, 279 .driver = { 280 .name = "qcom-apq8064-sata-phy", 281 .of_match_table = qcom_apq8064_sata_phy_of_match, 282 } 283}; 284module_platform_driver(qcom_apq8064_sata_phy_driver); 285 286MODULE_DESCRIPTION("QCOM apq8064 SATA PHY driver"); 287MODULE_LICENSE("GPL v2"); 288