Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Phy provider for USB 3.0 controller on HiSilicon 3660 platform
0004  *
0005  * Copyright (C) 2017-2018 Hilisicon Electronics Co., Ltd.
0006  *      http://www.huawei.com
0007  *
0008  * Authors: Yu Chen <chenyu56@huawei.com>
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/module.h>
0014 #include <linux/phy/phy.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regmap.h>
0017 
0018 #define PERI_CRG_CLK_EN4            0x40
0019 #define PERI_CRG_CLK_DIS4           0x44
0020 #define GT_CLK_USB3OTG_REF          BIT(0)
0021 #define GT_ACLK_USB3OTG             BIT(1)
0022 
0023 #define PERI_CRG_RSTEN4             0x90
0024 #define PERI_CRG_RSTDIS4            0x94
0025 #define IP_RST_USB3OTGPHY_POR           BIT(3)
0026 #define IP_RST_USB3OTG              BIT(5)
0027 
0028 #define PERI_CRG_ISODIS             0x148
0029 #define USB_REFCLK_ISO_EN           BIT(25)
0030 
0031 #define PCTRL_PERI_CTRL3            0x10
0032 #define PCTRL_PERI_CTRL3_MSK_START      16
0033 #define USB_TCXO_EN             BIT(1)
0034 
0035 #define PCTRL_PERI_CTRL24           0x64
0036 #define SC_CLK_USB3PHY_3MUX1_SEL        BIT(25)
0037 
0038 #define USBOTG3_CTRL0               0x00
0039 #define SC_USB3PHY_ABB_GT_EN            BIT(15)
0040 
0041 #define USBOTG3_CTRL2               0x08
0042 #define USBOTG3CTRL2_POWERDOWN_HSP      BIT(0)
0043 #define USBOTG3CTRL2_POWERDOWN_SSP      BIT(1)
0044 
0045 #define USBOTG3_CTRL3               0x0C
0046 #define USBOTG3_CTRL3_VBUSVLDEXT        BIT(6)
0047 #define USBOTG3_CTRL3_VBUSVLDEXTSEL     BIT(5)
0048 
0049 #define USBOTG3_CTRL4               0x10
0050 
0051 #define USBOTG3_CTRL7               0x1c
0052 #define REF_SSP_EN              BIT(16)
0053 
0054 /* This value config the default txtune parameter of the usb 2.0 phy */
0055 #define HI3660_USB_DEFAULT_PHY_PARAM        0x1c466e3
0056 
0057 struct hi3660_priv {
0058     struct device *dev;
0059     struct regmap *peri_crg;
0060     struct regmap *pctrl;
0061     struct regmap *otg_bc;
0062     u32 eye_diagram_param;
0063 };
0064 
0065 static int hi3660_phy_init(struct phy *phy)
0066 {
0067     struct hi3660_priv *priv = phy_get_drvdata(phy);
0068     u32 val, mask;
0069     int ret;
0070 
0071     /* usb refclk iso disable */
0072     ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, USB_REFCLK_ISO_EN);
0073     if (ret)
0074         goto out;
0075 
0076     /* enable usb_tcxo_en */
0077     val = USB_TCXO_EN | (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
0078     ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val);
0079     if (ret)
0080         goto out;
0081 
0082     /* assert phy */
0083     val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG;
0084     ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val);
0085     if (ret)
0086         goto out;
0087 
0088     /* enable phy ref clk */
0089     val = SC_USB3PHY_ABB_GT_EN;
0090     mask = val;
0091     ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL0, mask, val);
0092     if (ret)
0093         goto out;
0094 
0095     val = REF_SSP_EN;
0096     mask = val;
0097     ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL7, mask, val);
0098     if (ret)
0099         goto out;
0100 
0101     /* exit from IDDQ mode */
0102     mask = USBOTG3CTRL2_POWERDOWN_HSP | USBOTG3CTRL2_POWERDOWN_SSP;
0103     ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL2, mask, 0);
0104     if (ret)
0105         goto out;
0106 
0107     /* delay for exit from IDDQ mode */
0108     usleep_range(100, 120);
0109 
0110     /* deassert phy */
0111     val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG;
0112     ret = regmap_write(priv->peri_crg, PERI_CRG_RSTDIS4, val);
0113     if (ret)
0114         goto out;
0115 
0116     /* delay for phy deasserted */
0117     usleep_range(10000, 15000);
0118 
0119     /* fake vbus valid signal */
0120     val = USBOTG3_CTRL3_VBUSVLDEXT | USBOTG3_CTRL3_VBUSVLDEXTSEL;
0121     mask = val;
0122     ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL3, mask, val);
0123     if (ret)
0124         goto out;
0125 
0126     /* delay for vbus valid */
0127     usleep_range(100, 120);
0128 
0129     ret = regmap_write(priv->otg_bc, USBOTG3_CTRL4,
0130             priv->eye_diagram_param);
0131     if (ret)
0132         goto out;
0133 
0134     return 0;
0135 out:
0136     dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
0137     return ret;
0138 }
0139 
0140 static int hi3660_phy_exit(struct phy *phy)
0141 {
0142     struct hi3660_priv *priv = phy_get_drvdata(phy);
0143     u32 val;
0144     int ret;
0145 
0146     /* assert phy */
0147     val = IP_RST_USB3OTGPHY_POR;
0148     ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val);
0149     if (ret)
0150         goto out;
0151 
0152     /* disable usb_tcxo_en */
0153     val = USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START;
0154     ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val);
0155     if (ret)
0156         goto out;
0157 
0158     return 0;
0159 out:
0160     dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
0161     return ret;
0162 }
0163 
0164 static const struct phy_ops hi3660_phy_ops = {
0165     .init       = hi3660_phy_init,
0166     .exit       = hi3660_phy_exit,
0167     .owner      = THIS_MODULE,
0168 };
0169 
0170 static int hi3660_phy_probe(struct platform_device *pdev)
0171 {
0172     struct phy_provider *phy_provider;
0173     struct device *dev = &pdev->dev;
0174     struct phy *phy;
0175     struct hi3660_priv *priv;
0176 
0177     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0178     if (!priv)
0179         return -ENOMEM;
0180 
0181     priv->dev = dev;
0182     priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
0183                     "hisilicon,pericrg-syscon");
0184     if (IS_ERR(priv->peri_crg)) {
0185         dev_err(dev, "no hisilicon,pericrg-syscon\n");
0186         return PTR_ERR(priv->peri_crg);
0187     }
0188 
0189     priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
0190                     "hisilicon,pctrl-syscon");
0191     if (IS_ERR(priv->pctrl)) {
0192         dev_err(dev, "no hisilicon,pctrl-syscon\n");
0193         return PTR_ERR(priv->pctrl);
0194     }
0195 
0196     /* node of hi3660 phy is a sub-node of usb3_otg_bc */
0197     priv->otg_bc = syscon_node_to_regmap(dev->parent->of_node);
0198     if (IS_ERR(priv->otg_bc)) {
0199         dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
0200         return PTR_ERR(priv->otg_bc);
0201     }
0202 
0203     if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
0204         &(priv->eye_diagram_param)))
0205         priv->eye_diagram_param = HI3660_USB_DEFAULT_PHY_PARAM;
0206 
0207     phy = devm_phy_create(dev, NULL, &hi3660_phy_ops);
0208     if (IS_ERR(phy))
0209         return PTR_ERR(phy);
0210 
0211     phy_set_drvdata(phy, priv);
0212     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0213     return PTR_ERR_OR_ZERO(phy_provider);
0214 }
0215 
0216 static const struct of_device_id hi3660_phy_of_match[] = {
0217     {.compatible = "hisilicon,hi3660-usb-phy",},
0218     { }
0219 };
0220 MODULE_DEVICE_TABLE(of, hi3660_phy_of_match);
0221 
0222 static struct platform_driver hi3660_phy_driver = {
0223     .probe  = hi3660_phy_probe,
0224     .driver = {
0225         .name   = "hi3660-usb-phy",
0226         .of_match_table = hi3660_phy_of_match,
0227     }
0228 };
0229 module_platform_driver(hi3660_phy_driver);
0230 
0231 MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
0232 MODULE_LICENSE("GPL v2");
0233 MODULE_DESCRIPTION("Hilisicon Hi3660 USB3 PHY Driver");