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