root/drivers/phy/hisilicon/phy-hisi-inno-usb2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hisi_inno_phy_write_reg
  2. hisi_inno_phy_setup
  3. hisi_inno_phy_init
  4. hisi_inno_phy_exit
  5. hisi_inno_phy_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * HiSilicon INNO USB2 PHY Driver.
   4  *
   5  * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/delay.h>
  10 #include <linux/io.h>
  11 #include <linux/module.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/phy/phy.h>
  14 #include <linux/reset.h>
  15 
  16 #define INNO_PHY_PORT_NUM       2
  17 #define REF_CLK_STABLE_TIME     100     /* unit:us */
  18 #define UTMI_CLK_STABLE_TIME    200     /* unit:us */
  19 #define TEST_CLK_STABLE_TIME    2       /* unit:ms */
  20 #define PHY_CLK_STABLE_TIME     2       /* unit:ms */
  21 #define UTMI_RST_COMPLETE_TIME  2       /* unit:ms */
  22 #define POR_RST_COMPLETE_TIME   300     /* unit:us */
  23 #define PHY_TEST_DATA           GENMASK(7, 0)
  24 #define PHY_TEST_ADDR           GENMASK(15, 8)
  25 #define PHY_TEST_PORT           GENMASK(18, 16)
  26 #define PHY_TEST_WREN           BIT(21)
  27 #define PHY_TEST_CLK            BIT(22) /* rising edge active */
  28 #define PHY_TEST_RST            BIT(23) /* low active */
  29 #define PHY_CLK_ENABLE          BIT(2)
  30 
  31 struct hisi_inno_phy_port {
  32         struct reset_control *utmi_rst;
  33         struct hisi_inno_phy_priv *priv;
  34 };
  35 
  36 struct hisi_inno_phy_priv {
  37         void __iomem *mmio;
  38         struct clk *ref_clk;
  39         struct reset_control *por_rst;
  40         struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM];
  41 };
  42 
  43 static void hisi_inno_phy_write_reg(struct hisi_inno_phy_priv *priv,
  44                                     u8 port, u32 addr, u32 data)
  45 {
  46         void __iomem *reg = priv->mmio;
  47         u32 val;
  48 
  49         val = (data & PHY_TEST_DATA) |
  50               ((addr << 8) & PHY_TEST_ADDR) |
  51               ((port << 16) & PHY_TEST_PORT) |
  52               PHY_TEST_WREN | PHY_TEST_RST;
  53         writel(val, reg);
  54 
  55         val |= PHY_TEST_CLK;
  56         writel(val, reg);
  57 
  58         val &= ~PHY_TEST_CLK;
  59         writel(val, reg);
  60 }
  61 
  62 static void hisi_inno_phy_setup(struct hisi_inno_phy_priv *priv)
  63 {
  64         /* The phy clk is controlled by the port0 register 0x06. */
  65         hisi_inno_phy_write_reg(priv, 0, 0x06, PHY_CLK_ENABLE);
  66         msleep(PHY_CLK_STABLE_TIME);
  67 }
  68 
  69 static int hisi_inno_phy_init(struct phy *phy)
  70 {
  71         struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
  72         struct hisi_inno_phy_priv *priv = port->priv;
  73         int ret;
  74 
  75         ret = clk_prepare_enable(priv->ref_clk);
  76         if (ret)
  77                 return ret;
  78         udelay(REF_CLK_STABLE_TIME);
  79 
  80         reset_control_deassert(priv->por_rst);
  81         udelay(POR_RST_COMPLETE_TIME);
  82 
  83         /* Set up phy registers */
  84         hisi_inno_phy_setup(priv);
  85 
  86         reset_control_deassert(port->utmi_rst);
  87         udelay(UTMI_RST_COMPLETE_TIME);
  88 
  89         return 0;
  90 }
  91 
  92 static int hisi_inno_phy_exit(struct phy *phy)
  93 {
  94         struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
  95         struct hisi_inno_phy_priv *priv = port->priv;
  96 
  97         reset_control_assert(port->utmi_rst);
  98         reset_control_assert(priv->por_rst);
  99         clk_disable_unprepare(priv->ref_clk);
 100 
 101         return 0;
 102 }
 103 
 104 static const struct phy_ops hisi_inno_phy_ops = {
 105         .init = hisi_inno_phy_init,
 106         .exit = hisi_inno_phy_exit,
 107         .owner = THIS_MODULE,
 108 };
 109 
 110 static int hisi_inno_phy_probe(struct platform_device *pdev)
 111 {
 112         struct device *dev = &pdev->dev;
 113         struct device_node *np = dev->of_node;
 114         struct hisi_inno_phy_priv *priv;
 115         struct phy_provider *provider;
 116         struct device_node *child;
 117         struct resource *res;
 118         int i = 0;
 119         int ret;
 120 
 121         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 122         if (!priv)
 123                 return -ENOMEM;
 124 
 125         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 126         priv->mmio = devm_ioremap_resource(dev, res);
 127         if (IS_ERR(priv->mmio)) {
 128                 ret = PTR_ERR(priv->mmio);
 129                 return ret;
 130         }
 131 
 132         priv->ref_clk = devm_clk_get(dev, NULL);
 133         if (IS_ERR(priv->ref_clk))
 134                 return PTR_ERR(priv->ref_clk);
 135 
 136         priv->por_rst = devm_reset_control_get_exclusive(dev, NULL);
 137         if (IS_ERR(priv->por_rst))
 138                 return PTR_ERR(priv->por_rst);
 139 
 140         for_each_child_of_node(np, child) {
 141                 struct reset_control *rst;
 142                 struct phy *phy;
 143 
 144                 rst = of_reset_control_get_exclusive(child, NULL);
 145                 if (IS_ERR(rst))
 146                         return PTR_ERR(rst);
 147                 priv->ports[i].utmi_rst = rst;
 148                 priv->ports[i].priv = priv;
 149 
 150                 phy = devm_phy_create(dev, child, &hisi_inno_phy_ops);
 151                 if (IS_ERR(phy))
 152                         return PTR_ERR(phy);
 153 
 154                 phy_set_bus_width(phy, 8);
 155                 phy_set_drvdata(phy, &priv->ports[i]);
 156                 i++;
 157 
 158                 if (i > INNO_PHY_PORT_NUM) {
 159                         dev_warn(dev, "Support %d ports in maximum\n", i);
 160                         break;
 161                 }
 162         }
 163 
 164         provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 165         return PTR_ERR_OR_ZERO(provider);
 166 }
 167 
 168 static const struct of_device_id hisi_inno_phy_of_match[] = {
 169         { .compatible = "hisilicon,inno-usb2-phy", },
 170         { .compatible = "hisilicon,hi3798cv200-usb2-phy", },
 171         { },
 172 };
 173 MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match);
 174 
 175 static struct platform_driver hisi_inno_phy_driver = {
 176         .probe  = hisi_inno_phy_probe,
 177         .driver = {
 178                 .name   = "hisi-inno-phy",
 179                 .of_match_table = hisi_inno_phy_of_match,
 180         }
 181 };
 182 module_platform_driver(hisi_inno_phy_driver);
 183 
 184 MODULE_DESCRIPTION("HiSilicon INNO USB2 PHY Driver");
 185 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */