root/drivers/phy/phy-pistachio-usb.c

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

DEFINITIONS

This source file includes following definitions.
  1. pistachio_usb_phy_power_on
  2. pistachio_usb_phy_power_off
  3. pistachio_usb_phy_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * IMG Pistachio USB PHY driver
   4  *
   5  * Copyright (C) 2015 Google, Inc.
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/delay.h>
  10 #include <linux/io.h>
  11 #include <linux/kernel.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/module.h>
  14 #include <linux/of.h>
  15 #include <linux/phy/phy.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regmap.h>
  18 
  19 #include <dt-bindings/phy/phy-pistachio-usb.h>
  20 
  21 #define USB_PHY_CONTROL1                                0x04
  22 #define USB_PHY_CONTROL1_FSEL_SHIFT                     2
  23 #define USB_PHY_CONTROL1_FSEL_MASK                      0x7
  24 
  25 #define USB_PHY_STRAP_CONTROL                           0x10
  26 #define USB_PHY_STRAP_CONTROL_REFCLK_SHIFT              4
  27 #define USB_PHY_STRAP_CONTROL_REFCLK_MASK               0x3
  28 
  29 #define USB_PHY_STATUS                                  0x14
  30 #define USB_PHY_STATUS_RX_PHY_CLK                       BIT(9)
  31 #define USB_PHY_STATUS_RX_UTMI_CLK                      BIT(8)
  32 #define USB_PHY_STATUS_VBUS_FAULT                       BIT(7)
  33 
  34 struct pistachio_usb_phy {
  35         struct device *dev;
  36         struct regmap *cr_top;
  37         struct clk *phy_clk;
  38         unsigned int refclk;
  39 };
  40 
  41 static const unsigned long fsel_rate_map[] = {
  42         9600000,
  43         10000000,
  44         12000000,
  45         19200000,
  46         20000000,
  47         24000000,
  48         0,
  49         50000000,
  50 };
  51 
  52 static int pistachio_usb_phy_power_on(struct phy *phy)
  53 {
  54         struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
  55         unsigned long timeout, rate;
  56         unsigned int i;
  57         int ret;
  58 
  59         ret = clk_prepare_enable(p_phy->phy_clk);
  60         if (ret < 0) {
  61                 dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
  62                 return ret;
  63         }
  64 
  65         regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
  66                            USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
  67                            USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
  68                            p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);
  69 
  70         rate = clk_get_rate(p_phy->phy_clk);
  71         if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
  72                 dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
  73                         rate);
  74                 ret = -EINVAL;
  75                 goto disable_clk;
  76         }
  77 
  78         for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
  79                 if (rate == fsel_rate_map[i])
  80                         break;
  81         }
  82         if (i == ARRAY_SIZE(fsel_rate_map)) {
  83                 dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
  84                 ret = -EINVAL;
  85                 goto disable_clk;
  86         }
  87 
  88         regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
  89                            USB_PHY_CONTROL1_FSEL_MASK <<
  90                            USB_PHY_CONTROL1_FSEL_SHIFT,
  91                            i << USB_PHY_CONTROL1_FSEL_SHIFT);
  92 
  93         timeout = jiffies + msecs_to_jiffies(200);
  94         while (time_before(jiffies, timeout)) {
  95                 unsigned int val;
  96 
  97                 regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
  98                 if (val & USB_PHY_STATUS_VBUS_FAULT) {
  99                         dev_err(p_phy->dev, "VBUS fault detected\n");
 100                         ret = -EIO;
 101                         goto disable_clk;
 102                 }
 103                 if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
 104                     (val & USB_PHY_STATUS_RX_UTMI_CLK))
 105                         return 0;
 106                 usleep_range(1000, 1500);
 107         }
 108 
 109         dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
 110         ret = -ETIMEDOUT;
 111 
 112 disable_clk:
 113         clk_disable_unprepare(p_phy->phy_clk);
 114         return ret;
 115 }
 116 
 117 static int pistachio_usb_phy_power_off(struct phy *phy)
 118 {
 119         struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
 120 
 121         clk_disable_unprepare(p_phy->phy_clk);
 122 
 123         return 0;
 124 }
 125 
 126 static const struct phy_ops pistachio_usb_phy_ops = {
 127         .power_on = pistachio_usb_phy_power_on,
 128         .power_off = pistachio_usb_phy_power_off,
 129         .owner = THIS_MODULE,
 130 };
 131 
 132 static int pistachio_usb_phy_probe(struct platform_device *pdev)
 133 {
 134         struct pistachio_usb_phy *p_phy;
 135         struct phy_provider *provider;
 136         struct phy *phy;
 137         int ret;
 138 
 139         p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
 140         if (!p_phy)
 141                 return -ENOMEM;
 142         p_phy->dev = &pdev->dev;
 143         platform_set_drvdata(pdev, p_phy);
 144 
 145         p_phy->cr_top = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node,
 146                                                         "img,cr-top");
 147         if (IS_ERR(p_phy->cr_top)) {
 148                 dev_err(p_phy->dev, "Failed to get CR_TOP registers: %ld\n",
 149                         PTR_ERR(p_phy->cr_top));
 150                 return PTR_ERR(p_phy->cr_top);
 151         }
 152 
 153         p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy");
 154         if (IS_ERR(p_phy->phy_clk)) {
 155                 dev_err(p_phy->dev, "Failed to get usb_phy clock: %ld\n",
 156                         PTR_ERR(p_phy->phy_clk));
 157                 return PTR_ERR(p_phy->phy_clk);
 158         }
 159 
 160         ret = of_property_read_u32(p_phy->dev->of_node, "img,refclk",
 161                                    &p_phy->refclk);
 162         if (ret < 0) {
 163                 dev_err(p_phy->dev, "No reference clock selector specified\n");
 164                 return ret;
 165         }
 166 
 167         phy = devm_phy_create(p_phy->dev, NULL, &pistachio_usb_phy_ops);
 168         if (IS_ERR(phy)) {
 169                 dev_err(p_phy->dev, "Failed to create PHY: %ld\n",
 170                         PTR_ERR(phy));
 171                 return PTR_ERR(phy);
 172         }
 173         phy_set_drvdata(phy, p_phy);
 174 
 175         provider = devm_of_phy_provider_register(p_phy->dev,
 176                                                  of_phy_simple_xlate);
 177         if (IS_ERR(provider)) {
 178                 dev_err(p_phy->dev, "Failed to register PHY provider: %ld\n",
 179                         PTR_ERR(provider));
 180                 return PTR_ERR(provider);
 181         }
 182 
 183         return 0;
 184 }
 185 
 186 static const struct of_device_id pistachio_usb_phy_of_match[] = {
 187         { .compatible = "img,pistachio-usb-phy", },
 188         { },
 189 };
 190 MODULE_DEVICE_TABLE(of, pistachio_usb_phy_of_match);
 191 
 192 static struct platform_driver pistachio_usb_phy_driver = {
 193         .probe          = pistachio_usb_phy_probe,
 194         .driver         = {
 195                 .name   = "pistachio-usb-phy",
 196                 .of_match_table = pistachio_usb_phy_of_match,
 197         },
 198 };
 199 module_platform_driver(pistachio_usb_phy_driver);
 200 
 201 MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
 202 MODULE_DESCRIPTION("IMG Pistachio USB2.0 PHY driver");
 203 MODULE_LICENSE("GPL v2");

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