root/drivers/phy/ti/phy-da8xx-usb.c

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

DEFINITIONS

This source file includes following definitions.
  1. da8xx_usb11_phy_power_on
  2. da8xx_usb11_phy_power_off
  3. da8xx_usb20_phy_power_on
  4. da8xx_usb20_phy_power_off
  5. da8xx_usb20_phy_set_mode
  6. da8xx_usb_phy_of_xlate
  7. da8xx_usb_phy_probe
  8. da8xx_usb_phy_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver
   4  *
   5  * Copyright (C) 2016 David Lechner <david@lechnology.com>
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/io.h>
  10 #include <linux/of.h>
  11 #include <linux/mfd/da8xx-cfgchip.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/module.h>
  14 #include <linux/phy/phy.h>
  15 #include <linux/platform_data/phy-da8xx-usb.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regmap.h>
  18 
  19 #define PHY_INIT_BITS   (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN)
  20 
  21 struct da8xx_usb_phy {
  22         struct phy_provider     *phy_provider;
  23         struct phy              *usb11_phy;
  24         struct phy              *usb20_phy;
  25         struct clk              *usb11_clk;
  26         struct clk              *usb20_clk;
  27         struct regmap           *regmap;
  28 };
  29 
  30 static int da8xx_usb11_phy_power_on(struct phy *phy)
  31 {
  32         struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
  33         int ret;
  34 
  35         ret = clk_prepare_enable(d_phy->usb11_clk);
  36         if (ret)
  37                 return ret;
  38 
  39         regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM,
  40                           CFGCHIP2_USB1SUSPENDM);
  41 
  42         return 0;
  43 }
  44 
  45 static int da8xx_usb11_phy_power_off(struct phy *phy)
  46 {
  47         struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
  48 
  49         regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0);
  50 
  51         clk_disable_unprepare(d_phy->usb11_clk);
  52 
  53         return 0;
  54 }
  55 
  56 static const struct phy_ops da8xx_usb11_phy_ops = {
  57         .power_on       = da8xx_usb11_phy_power_on,
  58         .power_off      = da8xx_usb11_phy_power_off,
  59         .owner          = THIS_MODULE,
  60 };
  61 
  62 static int da8xx_usb20_phy_power_on(struct phy *phy)
  63 {
  64         struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
  65         int ret;
  66 
  67         ret = clk_prepare_enable(d_phy->usb20_clk);
  68         if (ret)
  69                 return ret;
  70 
  71         regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0);
  72 
  73         return 0;
  74 }
  75 
  76 static int da8xx_usb20_phy_power_off(struct phy *phy)
  77 {
  78         struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
  79 
  80         regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN,
  81                           CFGCHIP2_OTGPWRDN);
  82 
  83         clk_disable_unprepare(d_phy->usb20_clk);
  84 
  85         return 0;
  86 }
  87 
  88 static int da8xx_usb20_phy_set_mode(struct phy *phy,
  89                                     enum phy_mode mode, int submode)
  90 {
  91         struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
  92         u32 val;
  93 
  94         switch (mode) {
  95         case PHY_MODE_USB_HOST:         /* Force VBUS valid, ID = 0 */
  96                 val = CFGCHIP2_OTGMODE_FORCE_HOST;
  97                 break;
  98         case PHY_MODE_USB_DEVICE:       /* Force VBUS valid, ID = 1 */
  99                 val = CFGCHIP2_OTGMODE_FORCE_DEVICE;
 100                 break;
 101         case PHY_MODE_USB_OTG:  /* Don't override the VBUS/ID comparators */
 102                 val = CFGCHIP2_OTGMODE_NO_OVERRIDE;
 103                 break;
 104         default:
 105                 return -EINVAL;
 106         }
 107 
 108         regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK,
 109                           val);
 110 
 111         return 0;
 112 }
 113 
 114 static const struct phy_ops da8xx_usb20_phy_ops = {
 115         .power_on       = da8xx_usb20_phy_power_on,
 116         .power_off      = da8xx_usb20_phy_power_off,
 117         .set_mode       = da8xx_usb20_phy_set_mode,
 118         .owner          = THIS_MODULE,
 119 };
 120 
 121 static struct phy *da8xx_usb_phy_of_xlate(struct device *dev,
 122                                          struct of_phandle_args *args)
 123 {
 124         struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
 125 
 126         if (!d_phy)
 127                 return ERR_PTR(-ENODEV);
 128 
 129         switch (args->args[0]) {
 130         case 0:
 131                 return d_phy->usb20_phy;
 132         case 1:
 133                 return d_phy->usb11_phy;
 134         default:
 135                 return ERR_PTR(-EINVAL);
 136         }
 137 }
 138 
 139 static int da8xx_usb_phy_probe(struct platform_device *pdev)
 140 {
 141         struct device           *dev = &pdev->dev;
 142         struct da8xx_usb_phy_platform_data *pdata = dev->platform_data;
 143         struct device_node      *node = dev->of_node;
 144         struct da8xx_usb_phy    *d_phy;
 145 
 146         d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL);
 147         if (!d_phy)
 148                 return -ENOMEM;
 149 
 150         if (pdata)
 151                 d_phy->regmap = pdata->cfgchip;
 152         else
 153                 d_phy->regmap = syscon_regmap_lookup_by_compatible(
 154                                                         "ti,da830-cfgchip");
 155         if (IS_ERR(d_phy->regmap)) {
 156                 dev_err(dev, "Failed to get syscon\n");
 157                 return PTR_ERR(d_phy->regmap);
 158         }
 159 
 160         d_phy->usb11_clk = devm_clk_get(dev, "usb1_clk48");
 161         if (IS_ERR(d_phy->usb11_clk)) {
 162                 dev_err(dev, "Failed to get usb1_clk48\n");
 163                 return PTR_ERR(d_phy->usb11_clk);
 164         }
 165 
 166         d_phy->usb20_clk = devm_clk_get(dev, "usb0_clk48");
 167         if (IS_ERR(d_phy->usb20_clk)) {
 168                 dev_err(dev, "Failed to get usb0_clk48\n");
 169                 return PTR_ERR(d_phy->usb20_clk);
 170         }
 171 
 172         d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops);
 173         if (IS_ERR(d_phy->usb11_phy)) {
 174                 dev_err(dev, "Failed to create usb11 phy\n");
 175                 return PTR_ERR(d_phy->usb11_phy);
 176         }
 177 
 178         d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops);
 179         if (IS_ERR(d_phy->usb20_phy)) {
 180                 dev_err(dev, "Failed to create usb20 phy\n");
 181                 return PTR_ERR(d_phy->usb20_phy);
 182         }
 183 
 184         platform_set_drvdata(pdev, d_phy);
 185         phy_set_drvdata(d_phy->usb11_phy, d_phy);
 186         phy_set_drvdata(d_phy->usb20_phy, d_phy);
 187 
 188         if (node) {
 189                 d_phy->phy_provider = devm_of_phy_provider_register(dev,
 190                                                         da8xx_usb_phy_of_xlate);
 191                 if (IS_ERR(d_phy->phy_provider)) {
 192                         dev_err(dev, "Failed to create phy provider\n");
 193                         return PTR_ERR(d_phy->phy_provider);
 194                 }
 195         } else {
 196                 int ret;
 197 
 198                 ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy",
 199                                         "ohci-da8xx");
 200                 if (ret)
 201                         dev_warn(dev, "Failed to create usb11 phy lookup\n");
 202                 ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy",
 203                                         "musb-da8xx");
 204                 if (ret)
 205                         dev_warn(dev, "Failed to create usb20 phy lookup\n");
 206         }
 207 
 208         regmap_write_bits(d_phy->regmap, CFGCHIP(2),
 209                           PHY_INIT_BITS, PHY_INIT_BITS);
 210 
 211         return 0;
 212 }
 213 
 214 static int da8xx_usb_phy_remove(struct platform_device *pdev)
 215 {
 216         struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev);
 217 
 218         if (!pdev->dev.of_node) {
 219                 phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
 220                 phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx");
 221         }
 222 
 223         return 0;
 224 }
 225 
 226 static const struct of_device_id da8xx_usb_phy_ids[] = {
 227         { .compatible = "ti,da830-usb-phy" },
 228         { }
 229 };
 230 MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids);
 231 
 232 static struct platform_driver da8xx_usb_phy_driver = {
 233         .probe  = da8xx_usb_phy_probe,
 234         .remove = da8xx_usb_phy_remove,
 235         .driver = {
 236                 .name   = "da8xx-usb-phy",
 237                 .of_match_table = da8xx_usb_phy_ids,
 238         },
 239 };
 240 
 241 module_platform_driver(da8xx_usb_phy_driver);
 242 
 243 MODULE_ALIAS("platform:da8xx-usb-phy");
 244 MODULE_AUTHOR("David Lechner <david@lechnology.com>");
 245 MODULE_DESCRIPTION("TI DA8xx USB PHY driver");
 246 MODULE_LICENSE("GPL v2");

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