phy-qcom-usb-hs-28nm.c (9885B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2009-2018, Linux Foundation. All rights reserved. 4 * Copyright (c) 2018-2020, Linaro Limited 5 */ 6 7#include <linux/clk.h> 8#include <linux/delay.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_graph.h> 14#include <linux/phy/phy.h> 15#include <linux/platform_device.h> 16#include <linux/regulator/consumer.h> 17#include <linux/reset.h> 18#include <linux/slab.h> 19 20/* PHY register and bit definitions */ 21#define PHY_CTRL_COMMON0 0x078 22#define SIDDQ BIT(2) 23#define PHY_IRQ_CMD 0x0d0 24#define PHY_INTR_MASK0 0x0d4 25#define PHY_INTR_CLEAR0 0x0dc 26#define DPDM_MASK 0x1e 27#define DP_1_0 BIT(4) 28#define DP_0_1 BIT(3) 29#define DM_1_0 BIT(2) 30#define DM_0_1 BIT(1) 31 32enum hsphy_voltage { 33 VOL_NONE, 34 VOL_MIN, 35 VOL_MAX, 36 VOL_NUM, 37}; 38 39enum hsphy_vreg { 40 VDD, 41 VDDA_1P8, 42 VDDA_3P3, 43 VREG_NUM, 44}; 45 46struct hsphy_init_seq { 47 int offset; 48 int val; 49 int delay; 50}; 51 52struct hsphy_data { 53 const struct hsphy_init_seq *init_seq; 54 unsigned int init_seq_num; 55}; 56 57struct hsphy_priv { 58 void __iomem *base; 59 struct clk_bulk_data *clks; 60 int num_clks; 61 struct reset_control *phy_reset; 62 struct reset_control *por_reset; 63 struct regulator_bulk_data vregs[VREG_NUM]; 64 const struct hsphy_data *data; 65 enum phy_mode mode; 66}; 67 68static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode, 69 int submode) 70{ 71 struct hsphy_priv *priv = phy_get_drvdata(phy); 72 73 priv->mode = PHY_MODE_INVALID; 74 75 if (mode > 0) 76 priv->mode = mode; 77 78 return 0; 79} 80 81static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv) 82{ 83 u32 val; 84 85 /* Clear any existing interrupts before enabling the interrupts */ 86 val = readb(priv->base + PHY_INTR_CLEAR0); 87 val |= DPDM_MASK; 88 writeb(val, priv->base + PHY_INTR_CLEAR0); 89 90 writeb(0x0, priv->base + PHY_IRQ_CMD); 91 usleep_range(200, 220); 92 writeb(0x1, priv->base + PHY_IRQ_CMD); 93 94 /* Make sure the interrupts are cleared */ 95 usleep_range(200, 220); 96 97 val = readb(priv->base + PHY_INTR_MASK0); 98 switch (priv->mode) { 99 case PHY_MODE_USB_HOST_HS: 100 case PHY_MODE_USB_HOST_FS: 101 case PHY_MODE_USB_DEVICE_HS: 102 case PHY_MODE_USB_DEVICE_FS: 103 val |= DP_1_0 | DM_0_1; 104 break; 105 case PHY_MODE_USB_HOST_LS: 106 case PHY_MODE_USB_DEVICE_LS: 107 val |= DP_0_1 | DM_1_0; 108 break; 109 default: 110 /* No device connected */ 111 val |= DP_0_1 | DM_0_1; 112 break; 113 } 114 writeb(val, priv->base + PHY_INTR_MASK0); 115} 116 117static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv) 118{ 119 u32 val; 120 121 val = readb(priv->base + PHY_INTR_MASK0); 122 val &= ~DPDM_MASK; 123 writeb(val, priv->base + PHY_INTR_MASK0); 124 125 /* Clear any pending interrupts */ 126 val = readb(priv->base + PHY_INTR_CLEAR0); 127 val |= DPDM_MASK; 128 writeb(val, priv->base + PHY_INTR_CLEAR0); 129 130 writeb(0x0, priv->base + PHY_IRQ_CMD); 131 usleep_range(200, 220); 132 133 writeb(0x1, priv->base + PHY_IRQ_CMD); 134 usleep_range(200, 220); 135} 136 137static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv) 138{ 139 u32 val; 140 141 val = readb(priv->base + PHY_CTRL_COMMON0); 142 val |= SIDDQ; 143 writeb(val, priv->base + PHY_CTRL_COMMON0); 144} 145 146static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv) 147{ 148 u32 val; 149 150 val = readb(priv->base + PHY_CTRL_COMMON0); 151 val &= ~SIDDQ; 152 writeb(val, priv->base + PHY_CTRL_COMMON0); 153} 154 155static int qcom_snps_hsphy_power_on(struct phy *phy) 156{ 157 struct hsphy_priv *priv = phy_get_drvdata(phy); 158 int ret; 159 160 ret = regulator_bulk_enable(VREG_NUM, priv->vregs); 161 if (ret) 162 return ret; 163 164 qcom_snps_hsphy_disable_hv_interrupts(priv); 165 qcom_snps_hsphy_exit_retention(priv); 166 167 return 0; 168} 169 170static int qcom_snps_hsphy_power_off(struct phy *phy) 171{ 172 struct hsphy_priv *priv = phy_get_drvdata(phy); 173 174 qcom_snps_hsphy_enter_retention(priv); 175 qcom_snps_hsphy_enable_hv_interrupts(priv); 176 regulator_bulk_disable(VREG_NUM, priv->vregs); 177 178 return 0; 179} 180 181static int qcom_snps_hsphy_reset(struct hsphy_priv *priv) 182{ 183 int ret; 184 185 ret = reset_control_assert(priv->phy_reset); 186 if (ret) 187 return ret; 188 189 usleep_range(10, 15); 190 191 ret = reset_control_deassert(priv->phy_reset); 192 if (ret) 193 return ret; 194 195 usleep_range(80, 100); 196 197 return 0; 198} 199 200static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv) 201{ 202 const struct hsphy_data *data = priv->data; 203 const struct hsphy_init_seq *seq; 204 int i; 205 206 /* Device match data is optional. */ 207 if (!data) 208 return; 209 210 seq = data->init_seq; 211 212 for (i = 0; i < data->init_seq_num; i++, seq++) { 213 writeb(seq->val, priv->base + seq->offset); 214 if (seq->delay) 215 usleep_range(seq->delay, seq->delay + 10); 216 } 217} 218 219static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv) 220{ 221 int ret; 222 223 ret = reset_control_assert(priv->por_reset); 224 if (ret) 225 return ret; 226 227 /* 228 * The Femto PHY is POR reset in the following scenarios. 229 * 230 * 1. After overriding the parameter registers. 231 * 2. Low power mode exit from PHY retention. 232 * 233 * Ensure that SIDDQ is cleared before bringing the PHY 234 * out of reset. 235 */ 236 qcom_snps_hsphy_exit_retention(priv); 237 238 /* 239 * As per databook, 10 usec delay is required between 240 * PHY POR assert and de-assert. 241 */ 242 usleep_range(10, 20); 243 ret = reset_control_deassert(priv->por_reset); 244 if (ret) 245 return ret; 246 247 /* 248 * As per databook, it takes 75 usec for PHY to stabilize 249 * after the reset. 250 */ 251 usleep_range(80, 100); 252 253 return 0; 254} 255 256static int qcom_snps_hsphy_init(struct phy *phy) 257{ 258 struct hsphy_priv *priv = phy_get_drvdata(phy); 259 int ret; 260 261 ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); 262 if (ret) 263 return ret; 264 265 ret = qcom_snps_hsphy_reset(priv); 266 if (ret) 267 goto disable_clocks; 268 269 qcom_snps_hsphy_init_sequence(priv); 270 271 ret = qcom_snps_hsphy_por_reset(priv); 272 if (ret) 273 goto disable_clocks; 274 275 return 0; 276 277disable_clocks: 278 clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 279 return ret; 280} 281 282static int qcom_snps_hsphy_exit(struct phy *phy) 283{ 284 struct hsphy_priv *priv = phy_get_drvdata(phy); 285 286 clk_bulk_disable_unprepare(priv->num_clks, priv->clks); 287 288 return 0; 289} 290 291static const struct phy_ops qcom_snps_hsphy_ops = { 292 .init = qcom_snps_hsphy_init, 293 .exit = qcom_snps_hsphy_exit, 294 .power_on = qcom_snps_hsphy_power_on, 295 .power_off = qcom_snps_hsphy_power_off, 296 .set_mode = qcom_snps_hsphy_set_mode, 297 .owner = THIS_MODULE, 298}; 299 300static const char * const qcom_snps_hsphy_clks[] = { 301 "ref", 302 "ahb", 303 "sleep", 304}; 305 306static int qcom_snps_hsphy_probe(struct platform_device *pdev) 307{ 308 struct device *dev = &pdev->dev; 309 struct phy_provider *provider; 310 struct hsphy_priv *priv; 311 struct phy *phy; 312 int ret; 313 int i; 314 315 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 316 if (!priv) 317 return -ENOMEM; 318 319 priv->base = devm_platform_ioremap_resource(pdev, 0); 320 if (IS_ERR(priv->base)) 321 return PTR_ERR(priv->base); 322 323 priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks); 324 priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks), 325 GFP_KERNEL); 326 if (!priv->clks) 327 return -ENOMEM; 328 329 for (i = 0; i < priv->num_clks; i++) 330 priv->clks[i].id = qcom_snps_hsphy_clks[i]; 331 332 ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks); 333 if (ret) 334 return ret; 335 336 priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); 337 if (IS_ERR(priv->phy_reset)) 338 return PTR_ERR(priv->phy_reset); 339 340 priv->por_reset = devm_reset_control_get_exclusive(dev, "por"); 341 if (IS_ERR(priv->por_reset)) 342 return PTR_ERR(priv->por_reset); 343 344 priv->vregs[VDD].supply = "vdd"; 345 priv->vregs[VDDA_1P8].supply = "vdda1p8"; 346 priv->vregs[VDDA_3P3].supply = "vdda3p3"; 347 348 ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs); 349 if (ret) 350 return ret; 351 352 /* Get device match data */ 353 priv->data = device_get_match_data(dev); 354 355 phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops); 356 if (IS_ERR(phy)) 357 return PTR_ERR(phy); 358 359 phy_set_drvdata(phy, priv); 360 361 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 362 if (IS_ERR(provider)) 363 return PTR_ERR(provider); 364 365 ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000); 366 if (ret < 0) 367 return ret; 368 369 ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000); 370 if (ret < 0) 371 goto unset_1p8_load; 372 373 return 0; 374 375unset_1p8_load: 376 regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0); 377 378 return ret; 379} 380 381/* 382 * The macro is used to define an initialization sequence. Each tuple 383 * is meant to program 'value' into phy register at 'offset' with 'delay' 384 * in us followed. 385 */ 386#define HSPHY_INIT_CFG(o, v, d) { .offset = o, .val = v, .delay = d, } 387 388static const struct hsphy_init_seq init_seq_femtophy[] = { 389 HSPHY_INIT_CFG(0xc0, 0x01, 0), 390 HSPHY_INIT_CFG(0xe8, 0x0d, 0), 391 HSPHY_INIT_CFG(0x74, 0x12, 0), 392 HSPHY_INIT_CFG(0x98, 0x63, 0), 393 HSPHY_INIT_CFG(0x9c, 0x03, 0), 394 HSPHY_INIT_CFG(0xa0, 0x1d, 0), 395 HSPHY_INIT_CFG(0xa4, 0x03, 0), 396 HSPHY_INIT_CFG(0x8c, 0x23, 0), 397 HSPHY_INIT_CFG(0x78, 0x08, 0), 398 HSPHY_INIT_CFG(0x7c, 0xdc, 0), 399 HSPHY_INIT_CFG(0x90, 0xe0, 20), 400 HSPHY_INIT_CFG(0x74, 0x10, 0), 401 HSPHY_INIT_CFG(0x90, 0x60, 0), 402}; 403 404static const struct hsphy_init_seq init_seq_mdm9607[] = { 405 HSPHY_INIT_CFG(0x80, 0x44, 0), 406 HSPHY_INIT_CFG(0x81, 0x38, 0), 407 HSPHY_INIT_CFG(0x82, 0x24, 0), 408 HSPHY_INIT_CFG(0x83, 0x13, 0), 409}; 410 411static const struct hsphy_data hsphy_data_femtophy = { 412 .init_seq = init_seq_femtophy, 413 .init_seq_num = ARRAY_SIZE(init_seq_femtophy), 414}; 415 416static const struct hsphy_data hsphy_data_mdm9607 = { 417 .init_seq = init_seq_mdm9607, 418 .init_seq_num = ARRAY_SIZE(init_seq_mdm9607), 419}; 420 421static const struct of_device_id qcom_snps_hsphy_match[] = { 422 { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, }, 423 { .compatible = "qcom,usb-hs-28nm-mdm9607", .data = &hsphy_data_mdm9607, }, 424 { }, 425}; 426MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match); 427 428static struct platform_driver qcom_snps_hsphy_driver = { 429 .probe = qcom_snps_hsphy_probe, 430 .driver = { 431 .name = "qcom,usb-hs-28nm-phy", 432 .of_match_table = qcom_snps_hsphy_match, 433 }, 434}; 435module_platform_driver(qcom_snps_hsphy_driver); 436 437MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver"); 438MODULE_LICENSE("GPL v2");