1*6076967aSJorge Ramirez-Ortiz // SPDX-License-Identifier: GPL-2.0 2*6076967aSJorge Ramirez-Ortiz /* 3*6076967aSJorge Ramirez-Ortiz * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. 4*6076967aSJorge Ramirez-Ortiz * Copyright (c) 2018-2020, Linaro Limited 5*6076967aSJorge Ramirez-Ortiz */ 6*6076967aSJorge Ramirez-Ortiz 7*6076967aSJorge Ramirez-Ortiz #include <linux/clk.h> 8*6076967aSJorge Ramirez-Ortiz #include <linux/delay.h> 9*6076967aSJorge Ramirez-Ortiz #include <linux/err.h> 10*6076967aSJorge Ramirez-Ortiz #include <linux/io.h> 11*6076967aSJorge Ramirez-Ortiz #include <linux/kernel.h> 12*6076967aSJorge Ramirez-Ortiz #include <linux/module.h> 13*6076967aSJorge Ramirez-Ortiz #include <linux/of.h> 14*6076967aSJorge Ramirez-Ortiz #include <linux/phy/phy.h> 15*6076967aSJorge Ramirez-Ortiz #include <linux/platform_device.h> 16*6076967aSJorge Ramirez-Ortiz #include <linux/regulator/consumer.h> 17*6076967aSJorge Ramirez-Ortiz #include <linux/reset.h> 18*6076967aSJorge Ramirez-Ortiz #include <linux/slab.h> 19*6076967aSJorge Ramirez-Ortiz 20*6076967aSJorge Ramirez-Ortiz #define PHY_CTRL0 0x6C 21*6076967aSJorge Ramirez-Ortiz #define PHY_CTRL1 0x70 22*6076967aSJorge Ramirez-Ortiz #define PHY_CTRL2 0x74 23*6076967aSJorge Ramirez-Ortiz #define PHY_CTRL4 0x7C 24*6076967aSJorge Ramirez-Ortiz 25*6076967aSJorge Ramirez-Ortiz /* PHY_CTRL bits */ 26*6076967aSJorge Ramirez-Ortiz #define REF_PHY_EN BIT(0) 27*6076967aSJorge Ramirez-Ortiz #define LANE0_PWR_ON BIT(2) 28*6076967aSJorge Ramirez-Ortiz #define SWI_PCS_CLK_SEL BIT(4) 29*6076967aSJorge Ramirez-Ortiz #define TST_PWR_DOWN BIT(4) 30*6076967aSJorge Ramirez-Ortiz #define PHY_RESET BIT(7) 31*6076967aSJorge Ramirez-Ortiz 32*6076967aSJorge Ramirez-Ortiz #define NUM_BULK_CLKS 3 33*6076967aSJorge Ramirez-Ortiz #define NUM_BULK_REGS 2 34*6076967aSJorge Ramirez-Ortiz 35*6076967aSJorge Ramirez-Ortiz struct ssphy_priv { 36*6076967aSJorge Ramirez-Ortiz void __iomem *base; 37*6076967aSJorge Ramirez-Ortiz struct device *dev; 38*6076967aSJorge Ramirez-Ortiz struct reset_control *reset_com; 39*6076967aSJorge Ramirez-Ortiz struct reset_control *reset_phy; 40*6076967aSJorge Ramirez-Ortiz struct regulator_bulk_data regs[NUM_BULK_REGS]; 41*6076967aSJorge Ramirez-Ortiz struct clk_bulk_data clks[NUM_BULK_CLKS]; 42*6076967aSJorge Ramirez-Ortiz enum phy_mode mode; 43*6076967aSJorge Ramirez-Ortiz }; 44*6076967aSJorge Ramirez-Ortiz 45*6076967aSJorge Ramirez-Ortiz static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val) 46*6076967aSJorge Ramirez-Ortiz { 47*6076967aSJorge Ramirez-Ortiz writel((readl(addr) & ~mask) | val, addr); 48*6076967aSJorge Ramirez-Ortiz } 49*6076967aSJorge Ramirez-Ortiz 50*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_do_reset(struct ssphy_priv *priv) 51*6076967aSJorge Ramirez-Ortiz { 52*6076967aSJorge Ramirez-Ortiz int ret; 53*6076967aSJorge Ramirez-Ortiz 54*6076967aSJorge Ramirez-Ortiz if (!priv->reset_com) { 55*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 56*6076967aSJorge Ramirez-Ortiz PHY_RESET); 57*6076967aSJorge Ramirez-Ortiz usleep_range(10, 20); 58*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0); 59*6076967aSJorge Ramirez-Ortiz } else { 60*6076967aSJorge Ramirez-Ortiz ret = reset_control_assert(priv->reset_com); 61*6076967aSJorge Ramirez-Ortiz if (ret) { 62*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to assert reset com\n"); 63*6076967aSJorge Ramirez-Ortiz return ret; 64*6076967aSJorge Ramirez-Ortiz } 65*6076967aSJorge Ramirez-Ortiz 66*6076967aSJorge Ramirez-Ortiz ret = reset_control_assert(priv->reset_phy); 67*6076967aSJorge Ramirez-Ortiz if (ret) { 68*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to assert reset phy\n"); 69*6076967aSJorge Ramirez-Ortiz return ret; 70*6076967aSJorge Ramirez-Ortiz } 71*6076967aSJorge Ramirez-Ortiz 72*6076967aSJorge Ramirez-Ortiz usleep_range(10, 20); 73*6076967aSJorge Ramirez-Ortiz 74*6076967aSJorge Ramirez-Ortiz ret = reset_control_deassert(priv->reset_com); 75*6076967aSJorge Ramirez-Ortiz if (ret) { 76*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to deassert reset com\n"); 77*6076967aSJorge Ramirez-Ortiz return ret; 78*6076967aSJorge Ramirez-Ortiz } 79*6076967aSJorge Ramirez-Ortiz 80*6076967aSJorge Ramirez-Ortiz ret = reset_control_deassert(priv->reset_phy); 81*6076967aSJorge Ramirez-Ortiz if (ret) { 82*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to deassert reset phy\n"); 83*6076967aSJorge Ramirez-Ortiz return ret; 84*6076967aSJorge Ramirez-Ortiz } 85*6076967aSJorge Ramirez-Ortiz } 86*6076967aSJorge Ramirez-Ortiz 87*6076967aSJorge Ramirez-Ortiz return 0; 88*6076967aSJorge Ramirez-Ortiz } 89*6076967aSJorge Ramirez-Ortiz 90*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_power_on(struct phy *phy) 91*6076967aSJorge Ramirez-Ortiz { 92*6076967aSJorge Ramirez-Ortiz struct ssphy_priv *priv = phy_get_drvdata(phy); 93*6076967aSJorge Ramirez-Ortiz int ret; 94*6076967aSJorge Ramirez-Ortiz 95*6076967aSJorge Ramirez-Ortiz ret = regulator_bulk_enable(NUM_BULK_REGS, priv->regs); 96*6076967aSJorge Ramirez-Ortiz if (ret) 97*6076967aSJorge Ramirez-Ortiz return ret; 98*6076967aSJorge Ramirez-Ortiz 99*6076967aSJorge Ramirez-Ortiz ret = clk_bulk_prepare_enable(NUM_BULK_CLKS, priv->clks); 100*6076967aSJorge Ramirez-Ortiz if (ret) 101*6076967aSJorge Ramirez-Ortiz goto err_disable_regulator; 102*6076967aSJorge Ramirez-Ortiz 103*6076967aSJorge Ramirez-Ortiz ret = qcom_ssphy_do_reset(priv); 104*6076967aSJorge Ramirez-Ortiz if (ret) 105*6076967aSJorge Ramirez-Ortiz goto err_disable_clock; 106*6076967aSJorge Ramirez-Ortiz 107*6076967aSJorge Ramirez-Ortiz writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0); 108*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON); 109*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN); 110*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0); 111*6076967aSJorge Ramirez-Ortiz 112*6076967aSJorge Ramirez-Ortiz return 0; 113*6076967aSJorge Ramirez-Ortiz err_disable_clock: 114*6076967aSJorge Ramirez-Ortiz clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks); 115*6076967aSJorge Ramirez-Ortiz err_disable_regulator: 116*6076967aSJorge Ramirez-Ortiz regulator_bulk_disable(NUM_BULK_REGS, priv->regs); 117*6076967aSJorge Ramirez-Ortiz 118*6076967aSJorge Ramirez-Ortiz return ret; 119*6076967aSJorge Ramirez-Ortiz } 120*6076967aSJorge Ramirez-Ortiz 121*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_power_off(struct phy *phy) 122*6076967aSJorge Ramirez-Ortiz { 123*6076967aSJorge Ramirez-Ortiz struct ssphy_priv *priv = phy_get_drvdata(phy); 124*6076967aSJorge Ramirez-Ortiz 125*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0); 126*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0); 127*6076967aSJorge Ramirez-Ortiz qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN); 128*6076967aSJorge Ramirez-Ortiz 129*6076967aSJorge Ramirez-Ortiz clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks); 130*6076967aSJorge Ramirez-Ortiz regulator_bulk_disable(NUM_BULK_REGS, priv->regs); 131*6076967aSJorge Ramirez-Ortiz 132*6076967aSJorge Ramirez-Ortiz return 0; 133*6076967aSJorge Ramirez-Ortiz } 134*6076967aSJorge Ramirez-Ortiz 135*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_init_clock(struct ssphy_priv *priv) 136*6076967aSJorge Ramirez-Ortiz { 137*6076967aSJorge Ramirez-Ortiz priv->clks[0].id = "ref"; 138*6076967aSJorge Ramirez-Ortiz priv->clks[1].id = "ahb"; 139*6076967aSJorge Ramirez-Ortiz priv->clks[2].id = "pipe"; 140*6076967aSJorge Ramirez-Ortiz 141*6076967aSJorge Ramirez-Ortiz return devm_clk_bulk_get(priv->dev, NUM_BULK_CLKS, priv->clks); 142*6076967aSJorge Ramirez-Ortiz } 143*6076967aSJorge Ramirez-Ortiz 144*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_init_regulator(struct ssphy_priv *priv) 145*6076967aSJorge Ramirez-Ortiz { 146*6076967aSJorge Ramirez-Ortiz int ret; 147*6076967aSJorge Ramirez-Ortiz 148*6076967aSJorge Ramirez-Ortiz priv->regs[0].supply = "vdd"; 149*6076967aSJorge Ramirez-Ortiz priv->regs[1].supply = "vdda1p8"; 150*6076967aSJorge Ramirez-Ortiz ret = devm_regulator_bulk_get(priv->dev, NUM_BULK_REGS, priv->regs); 151*6076967aSJorge Ramirez-Ortiz if (ret) { 152*6076967aSJorge Ramirez-Ortiz if (ret != -EPROBE_DEFER) 153*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to get regulators\n"); 154*6076967aSJorge Ramirez-Ortiz return ret; 155*6076967aSJorge Ramirez-Ortiz } 156*6076967aSJorge Ramirez-Ortiz 157*6076967aSJorge Ramirez-Ortiz return ret; 158*6076967aSJorge Ramirez-Ortiz } 159*6076967aSJorge Ramirez-Ortiz 160*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_init_reset(struct ssphy_priv *priv) 161*6076967aSJorge Ramirez-Ortiz { 162*6076967aSJorge Ramirez-Ortiz priv->reset_com = devm_reset_control_get_optional_exclusive(priv->dev, "com"); 163*6076967aSJorge Ramirez-Ortiz if (IS_ERR(priv->reset_com)) { 164*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to get reset control com\n"); 165*6076967aSJorge Ramirez-Ortiz return PTR_ERR(priv->reset_com); 166*6076967aSJorge Ramirez-Ortiz } 167*6076967aSJorge Ramirez-Ortiz 168*6076967aSJorge Ramirez-Ortiz if (priv->reset_com) { 169*6076967aSJorge Ramirez-Ortiz /* if reset_com is present, reset_phy is no longer optional */ 170*6076967aSJorge Ramirez-Ortiz priv->reset_phy = devm_reset_control_get_exclusive(priv->dev, "phy"); 171*6076967aSJorge Ramirez-Ortiz if (IS_ERR(priv->reset_phy)) { 172*6076967aSJorge Ramirez-Ortiz dev_err(priv->dev, "Failed to get reset control phy\n"); 173*6076967aSJorge Ramirez-Ortiz return PTR_ERR(priv->reset_phy); 174*6076967aSJorge Ramirez-Ortiz } 175*6076967aSJorge Ramirez-Ortiz } 176*6076967aSJorge Ramirez-Ortiz 177*6076967aSJorge Ramirez-Ortiz return 0; 178*6076967aSJorge Ramirez-Ortiz } 179*6076967aSJorge Ramirez-Ortiz 180*6076967aSJorge Ramirez-Ortiz static const struct phy_ops qcom_ssphy_ops = { 181*6076967aSJorge Ramirez-Ortiz .power_off = qcom_ssphy_power_off, 182*6076967aSJorge Ramirez-Ortiz .power_on = qcom_ssphy_power_on, 183*6076967aSJorge Ramirez-Ortiz .owner = THIS_MODULE, 184*6076967aSJorge Ramirez-Ortiz }; 185*6076967aSJorge Ramirez-Ortiz 186*6076967aSJorge Ramirez-Ortiz static int qcom_ssphy_probe(struct platform_device *pdev) 187*6076967aSJorge Ramirez-Ortiz { 188*6076967aSJorge Ramirez-Ortiz struct device *dev = &pdev->dev; 189*6076967aSJorge Ramirez-Ortiz struct phy_provider *provider; 190*6076967aSJorge Ramirez-Ortiz struct ssphy_priv *priv; 191*6076967aSJorge Ramirez-Ortiz struct phy *phy; 192*6076967aSJorge Ramirez-Ortiz int ret; 193*6076967aSJorge Ramirez-Ortiz 194*6076967aSJorge Ramirez-Ortiz priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL); 195*6076967aSJorge Ramirez-Ortiz if (!priv) 196*6076967aSJorge Ramirez-Ortiz return -ENOMEM; 197*6076967aSJorge Ramirez-Ortiz 198*6076967aSJorge Ramirez-Ortiz priv->dev = dev; 199*6076967aSJorge Ramirez-Ortiz priv->mode = PHY_MODE_INVALID; 200*6076967aSJorge Ramirez-Ortiz 201*6076967aSJorge Ramirez-Ortiz priv->base = devm_platform_ioremap_resource(pdev, 0); 202*6076967aSJorge Ramirez-Ortiz if (IS_ERR(priv->base)) 203*6076967aSJorge Ramirez-Ortiz return PTR_ERR(priv->base); 204*6076967aSJorge Ramirez-Ortiz 205*6076967aSJorge Ramirez-Ortiz ret = qcom_ssphy_init_clock(priv); 206*6076967aSJorge Ramirez-Ortiz if (ret) 207*6076967aSJorge Ramirez-Ortiz return ret; 208*6076967aSJorge Ramirez-Ortiz 209*6076967aSJorge Ramirez-Ortiz ret = qcom_ssphy_init_reset(priv); 210*6076967aSJorge Ramirez-Ortiz if (ret) 211*6076967aSJorge Ramirez-Ortiz return ret; 212*6076967aSJorge Ramirez-Ortiz 213*6076967aSJorge Ramirez-Ortiz ret = qcom_ssphy_init_regulator(priv); 214*6076967aSJorge Ramirez-Ortiz if (ret) 215*6076967aSJorge Ramirez-Ortiz return ret; 216*6076967aSJorge Ramirez-Ortiz 217*6076967aSJorge Ramirez-Ortiz phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops); 218*6076967aSJorge Ramirez-Ortiz if (IS_ERR(phy)) { 219*6076967aSJorge Ramirez-Ortiz dev_err(dev, "Failed to create the SS phy\n"); 220*6076967aSJorge Ramirez-Ortiz return PTR_ERR(phy); 221*6076967aSJorge Ramirez-Ortiz } 222*6076967aSJorge Ramirez-Ortiz 223*6076967aSJorge Ramirez-Ortiz phy_set_drvdata(phy, priv); 224*6076967aSJorge Ramirez-Ortiz 225*6076967aSJorge Ramirez-Ortiz provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 226*6076967aSJorge Ramirez-Ortiz 227*6076967aSJorge Ramirez-Ortiz return PTR_ERR_OR_ZERO(provider); 228*6076967aSJorge Ramirez-Ortiz } 229*6076967aSJorge Ramirez-Ortiz 230*6076967aSJorge Ramirez-Ortiz static const struct of_device_id qcom_ssphy_match[] = { 231*6076967aSJorge Ramirez-Ortiz { .compatible = "qcom,usb-ss-28nm-phy", }, 232*6076967aSJorge Ramirez-Ortiz { }, 233*6076967aSJorge Ramirez-Ortiz }; 234*6076967aSJorge Ramirez-Ortiz MODULE_DEVICE_TABLE(of, qcom_ssphy_match); 235*6076967aSJorge Ramirez-Ortiz 236*6076967aSJorge Ramirez-Ortiz static struct platform_driver qcom_ssphy_driver = { 237*6076967aSJorge Ramirez-Ortiz .probe = qcom_ssphy_probe, 238*6076967aSJorge Ramirez-Ortiz .driver = { 239*6076967aSJorge Ramirez-Ortiz .name = "qcom-usb-ssphy", 240*6076967aSJorge Ramirez-Ortiz .of_match_table = qcom_ssphy_match, 241*6076967aSJorge Ramirez-Ortiz }, 242*6076967aSJorge Ramirez-Ortiz }; 243*6076967aSJorge Ramirez-Ortiz module_platform_driver(qcom_ssphy_driver); 244*6076967aSJorge Ramirez-Ortiz 245*6076967aSJorge Ramirez-Ortiz MODULE_DESCRIPTION("Qualcomm SuperSpeed USB PHY driver"); 246*6076967aSJorge Ramirez-Ortiz MODULE_LICENSE("GPL v2"); 247