1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 */ 5 6#include <linux/clk.h> 7#include <linux/delay.h> 8#include <linux/err.h> 9#include <linux/io.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/of_device.h> 14#include <linux/phy/phy.h> 15#include <linux/platform_device.h> 16#include <linux/regmap.h> 17#include <linux/regulator/consumer.h> 18#include <linux/reset.h> 19#include <linux/slab.h> 20 21#define USB2_PHY_USB_PHY_UTMI_CTRL0 (0x3c) 22#define SLEEPM BIT(0) 23#define OPMODE_MASK GENMASK(4, 3) 24#define OPMODE_NORMAL (0x00) 25#define OPMODE_NONDRIVING BIT(3) 26#define TERMSEL BIT(5) 27 28#define USB2_PHY_USB_PHY_UTMI_CTRL1 (0x40) 29#define XCVRSEL BIT(0) 30 31#define USB2_PHY_USB_PHY_UTMI_CTRL5 (0x50) 32#define POR BIT(1) 33 34#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) 35#define RETENABLEN BIT(3) 36#define FSEL_MASK GENMASK(6, 4) 37#define FSEL_DEFAULT (0x3 << 4) 38 39#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1 (0x58) 40#define VBUSVLDEXTSEL0 BIT(4) 41#define PLLBTUNE BIT(5) 42 43#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2 (0x5c) 44#define VREGBYPASS BIT(0) 45 46#define USB2_PHY_USB_PHY_HS_PHY_CTRL1 (0x60) 47#define VBUSVLDEXT0 BIT(0) 48 49#define USB2_PHY_USB_PHY_HS_PHY_CTRL2 (0x64) 50#define USB2_AUTO_RESUME BIT(0) 51#define USB2_SUSPEND_N BIT(2) 52#define USB2_SUSPEND_N_SEL BIT(3) 53 54#define USB2_PHY_USB_PHY_CFG0 (0x94) 55#define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0) 56#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1) 57 58#define USB2_PHY_USB_PHY_REFCLK_CTRL (0xa0) 59#define REFCLK_SEL_MASK GENMASK(1, 0) 60#define REFCLK_SEL_DEFAULT (0x2 << 0) 61 62static const char * const qcom_snps_hsphy_vreg_names[] = { 63 "vdda-pll", "vdda33", "vdda18", 64}; 65 66#define SNPS_HS_NUM_VREGS ARRAY_SIZE(qcom_snps_hsphy_vreg_names) 67 68/** 69 * struct qcom_snps_hsphy - snps hs phy attributes 70 * 71 * @dev: device structure 72 * 73 * @phy: generic phy 74 * @base: iomapped memory space for snps hs phy 75 * 76 * @num_clks: number of clocks 77 * @clks: array of clocks 78 * @phy_reset: phy reset control 79 * @vregs: regulator supplies bulk data 80 * @phy_initialized: if PHY has been initialized correctly 81 * @mode: contains the current mode the PHY is in 82 * @update_seq_cfg: tuning parameters for phy init 83 */ 84struct qcom_snps_hsphy { 85 struct device *dev; 86 87 struct phy *phy; 88 void __iomem *base; 89 90 int num_clks; 91 struct clk_bulk_data *clks; 92 struct reset_control *phy_reset; 93 struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS]; 94 95 bool phy_initialized; 96 enum phy_mode mode; 97}; 98 99static int qcom_snps_hsphy_clk_init(struct qcom_snps_hsphy *hsphy) 100{ 101 struct device *dev = hsphy->dev; 102 103 hsphy->num_clks = 2; 104 hsphy->clks = devm_kcalloc(dev, hsphy->num_clks, sizeof(*hsphy->clks), GFP_KERNEL); 105 if (!hsphy->clks) 106 return -ENOMEM; 107 108 /* 109 * TODO: Currently no device tree instantiation of the PHY is using the clock. 110 * This needs to be fixed in order for this code to be able to use devm_clk_bulk_get(). 111 */ 112 hsphy->clks[0].id = "cfg_ahb"; 113 hsphy->clks[0].clk = devm_clk_get_optional(dev, "cfg_ahb"); 114 if (IS_ERR(hsphy->clks[0].clk)) 115 return dev_err_probe(dev, PTR_ERR(hsphy->clks[0].clk), 116 "failed to get cfg_ahb clk\n"); 117 118 hsphy->clks[1].id = "ref"; 119 hsphy->clks[1].clk = devm_clk_get(dev, "ref"); 120 if (IS_ERR(hsphy->clks[1].clk)) 121 return dev_err_probe(dev, PTR_ERR(hsphy->clks[1].clk), 122 "failed to get ref clk\n"); 123 124 return 0; 125} 126 127static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, 128 u32 mask, u32 val) 129{ 130 u32 reg; 131 132 reg = readl_relaxed(base + offset); 133 reg &= ~mask; 134 reg |= val & mask; 135 writel_relaxed(reg, base + offset); 136 137 /* Ensure above write is completed */ 138 readl_relaxed(base + offset); 139} 140 141static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy) 142{ 143 dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n"); 144 145 if (hsphy->mode == PHY_MODE_USB_HOST) { 146 /* Enable auto-resume to meet remote wakeup timing */ 147 qcom_snps_hsphy_write_mask(hsphy->base, 148 USB2_PHY_USB_PHY_HS_PHY_CTRL2, 149 USB2_AUTO_RESUME, 150 USB2_AUTO_RESUME); 151 usleep_range(500, 1000); 152 qcom_snps_hsphy_write_mask(hsphy->base, 153 USB2_PHY_USB_PHY_HS_PHY_CTRL2, 154 0, USB2_AUTO_RESUME); 155 } 156 157 return 0; 158} 159 160static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy) 161{ 162 dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n"); 163 164 return 0; 165} 166 167static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev) 168{ 169 struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev); 170 171 if (!hsphy->phy_initialized) 172 return 0; 173 174 return qcom_snps_hsphy_suspend(hsphy); 175} 176 177static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev) 178{ 179 struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev); 180 181 if (!hsphy->phy_initialized) 182 return 0; 183 184 return qcom_snps_hsphy_resume(hsphy); 185} 186 187static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode, 188 int submode) 189{ 190 struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); 191 192 hsphy->mode = mode; 193 return 0; 194} 195 196static int qcom_snps_hsphy_init(struct phy *phy) 197{ 198 struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); 199 int ret; 200 201 dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__); 202 203 ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs); 204 if (ret) 205 return ret; 206 207 ret = clk_bulk_prepare_enable(hsphy->num_clks, hsphy->clks); 208 if (ret) { 209 dev_err(&phy->dev, "failed to enable clocks, %d\n", ret); 210 goto poweroff_phy; 211 } 212 213 ret = reset_control_assert(hsphy->phy_reset); 214 if (ret) { 215 dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret); 216 goto disable_clks; 217 } 218 219 usleep_range(100, 150); 220 221 ret = reset_control_deassert(hsphy->phy_reset); 222 if (ret) { 223 dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret); 224 goto disable_clks; 225 } 226 227 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0, 228 UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 229 UTMI_PHY_CMN_CTRL_OVERRIDE_EN); 230 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5, 231 POR, POR); 232 qcom_snps_hsphy_write_mask(hsphy->base, 233 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0, 234 FSEL_MASK, 0); 235 qcom_snps_hsphy_write_mask(hsphy->base, 236 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1, 237 PLLBTUNE, PLLBTUNE); 238 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL, 239 REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK); 240 qcom_snps_hsphy_write_mask(hsphy->base, 241 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1, 242 VBUSVLDEXTSEL0, VBUSVLDEXTSEL0); 243 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1, 244 VBUSVLDEXT0, VBUSVLDEXT0); 245 246 qcom_snps_hsphy_write_mask(hsphy->base, 247 USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2, 248 VREGBYPASS, VREGBYPASS); 249 250 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2, 251 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N, 252 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N); 253 254 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0, 255 SLEEPM, SLEEPM); 256 257 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5, 258 POR, 0); 259 260 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2, 261 USB2_SUSPEND_N_SEL, 0); 262 263 qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0, 264 UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0); 265 266 hsphy->phy_initialized = true; 267 268 return 0; 269 270disable_clks: 271 clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks); 272poweroff_phy: 273 regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs); 274 275 return ret; 276} 277 278static int qcom_snps_hsphy_exit(struct phy *phy) 279{ 280 struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); 281 282 reset_control_assert(hsphy->phy_reset); 283 clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks); 284 regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs); 285 hsphy->phy_initialized = false; 286 287 return 0; 288} 289 290static const struct phy_ops qcom_snps_hsphy_gen_ops = { 291 .init = qcom_snps_hsphy_init, 292 .exit = qcom_snps_hsphy_exit, 293 .set_mode = qcom_snps_hsphy_set_mode, 294 .owner = THIS_MODULE, 295}; 296 297static const struct of_device_id qcom_snps_hsphy_of_match_table[] = { 298 { .compatible = "qcom,sm8150-usb-hs-phy", }, 299 { .compatible = "qcom,usb-snps-hs-7nm-phy", }, 300 { .compatible = "qcom,usb-snps-femto-v2-phy", }, 301 { } 302}; 303MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table); 304 305static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = { 306 SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend, 307 qcom_snps_hsphy_runtime_resume, NULL) 308}; 309 310static int qcom_snps_hsphy_probe(struct platform_device *pdev) 311{ 312 struct device *dev = &pdev->dev; 313 struct qcom_snps_hsphy *hsphy; 314 struct phy_provider *phy_provider; 315 struct phy *generic_phy; 316 int ret, i; 317 int num; 318 319 hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL); 320 if (!hsphy) 321 return -ENOMEM; 322 323 hsphy->dev = dev; 324 325 hsphy->base = devm_platform_ioremap_resource(pdev, 0); 326 if (IS_ERR(hsphy->base)) 327 return PTR_ERR(hsphy->base); 328 329 ret = qcom_snps_hsphy_clk_init(hsphy); 330 if (ret) 331 return dev_err_probe(dev, ret, "failed to initialize clocks\n"); 332 333 hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); 334 if (IS_ERR(hsphy->phy_reset)) { 335 dev_err(dev, "failed to get phy core reset\n"); 336 return PTR_ERR(hsphy->phy_reset); 337 } 338 339 num = ARRAY_SIZE(hsphy->vregs); 340 for (i = 0; i < num; i++) 341 hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i]; 342 343 ret = devm_regulator_bulk_get(dev, num, hsphy->vregs); 344 if (ret) 345 return dev_err_probe(dev, ret, 346 "failed to get regulator supplies\n"); 347 348 pm_runtime_set_active(dev); 349 pm_runtime_enable(dev); 350 /* 351 * Prevent runtime pm from being ON by default. Users can enable 352 * it using power/control in sysfs. 353 */ 354 pm_runtime_forbid(dev); 355 356 generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops); 357 if (IS_ERR(generic_phy)) { 358 ret = PTR_ERR(generic_phy); 359 dev_err(dev, "failed to create phy, %d\n", ret); 360 return ret; 361 } 362 hsphy->phy = generic_phy; 363 364 dev_set_drvdata(dev, hsphy); 365 phy_set_drvdata(generic_phy, hsphy); 366 367 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 368 if (!IS_ERR(phy_provider)) 369 dev_dbg(dev, "Registered Qcom-SNPS HS phy\n"); 370 else 371 pm_runtime_disable(dev); 372 373 return PTR_ERR_OR_ZERO(phy_provider); 374} 375 376static struct platform_driver qcom_snps_hsphy_driver = { 377 .probe = qcom_snps_hsphy_probe, 378 .driver = { 379 .name = "qcom-snps-hs-femto-v2-phy", 380 .pm = &qcom_snps_hsphy_pm_ops, 381 .of_match_table = qcom_snps_hsphy_of_match_table, 382 }, 383}; 384 385module_platform_driver(qcom_snps_hsphy_driver); 386 387MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver"); 388MODULE_LICENSE("GPL v2"); 389