Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * omap-usb2.c - USB PHY, talking to USB controller on TI SoCs.
0004  *
0005  * Copyright (C) 2012-2020 Texas Instruments Incorporated - http://www.ti.com
0006  * Author: Kishon Vijay Abraham I <kishon@ti.com>
0007  */
0008 
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/mfd/syscon.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/phy/omap_control_phy.h>
0018 #include <linux/phy/omap_usb.h>
0019 #include <linux/phy/phy.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/regmap.h>
0023 #include <linux/slab.h>
0024 #include <linux/sys_soc.h>
0025 #include <linux/usb/phy_companion.h>
0026 
0027 #define USB2PHY_ANA_CONFIG1     0x4c
0028 #define USB2PHY_DISCON_BYP_LATCH    BIT(31)
0029 
0030 #define USB2PHY_CHRG_DET            0x14
0031 #define USB2PHY_CHRG_DET_USE_CHG_DET_REG    BIT(29)
0032 #define USB2PHY_CHRG_DET_DIS_CHG_DET        BIT(28)
0033 
0034 /* SoC Specific USB2_OTG register definitions */
0035 #define AM654_USB2_OTG_PD       BIT(8)
0036 #define AM654_USB2_VBUS_DET_EN      BIT(5)
0037 #define AM654_USB2_VBUSVALID_DET_EN BIT(4)
0038 
0039 #define OMAP_DEV_PHY_PD     BIT(0)
0040 #define OMAP_USB2_PHY_PD    BIT(28)
0041 
0042 #define AM437X_USB2_PHY_PD      BIT(0)
0043 #define AM437X_USB2_OTG_PD      BIT(1)
0044 #define AM437X_USB2_OTGVDET_EN      BIT(19)
0045 #define AM437X_USB2_OTGSESSEND_EN   BIT(20)
0046 
0047 /* Driver Flags */
0048 #define OMAP_USB2_HAS_START_SRP         BIT(0)
0049 #define OMAP_USB2_HAS_SET_VBUS          BIT(1)
0050 #define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT    BIT(2)
0051 #define OMAP_USB2_DISABLE_CHRG_DET      BIT(3)
0052 
0053 struct omap_usb {
0054     struct usb_phy      phy;
0055     struct phy_companion    *comparator;
0056     void __iomem        *pll_ctrl_base;
0057     void __iomem        *phy_base;
0058     struct device       *dev;
0059     struct device       *control_dev;
0060     struct clk      *wkupclk;
0061     struct clk      *optclk;
0062     u8          flags;
0063     struct regmap       *syscon_phy_power; /* ctrl. reg. acces */
0064     unsigned int        power_reg; /* power reg. index within syscon */
0065     u32         mask;
0066     u32         power_on;
0067     u32         power_off;
0068 };
0069 
0070 #define phy_to_omapusb(x)   container_of((x), struct omap_usb, phy)
0071 
0072 struct usb_phy_data {
0073     const char *label;
0074     u8 flags;
0075     u32 mask;
0076     u32 power_on;
0077     u32 power_off;
0078 };
0079 
0080 static inline u32 omap_usb_readl(void __iomem *addr, unsigned int offset)
0081 {
0082     return __raw_readl(addr + offset);
0083 }
0084 
0085 static inline void omap_usb_writel(void __iomem *addr, unsigned int offset,
0086                    u32 data)
0087 {
0088     __raw_writel(data, addr + offset);
0089 }
0090 
0091 /**
0092  * omap_usb2_set_comparator() - links the comparator present in the system with this phy
0093  *
0094  * @comparator:  the companion phy(comparator) for this phy
0095  *
0096  * The phy companion driver should call this API passing the phy_companion
0097  * filled with set_vbus and start_srp to be used by usb phy.
0098  *
0099  * For use by phy companion driver
0100  */
0101 int omap_usb2_set_comparator(struct phy_companion *comparator)
0102 {
0103     struct omap_usb *phy;
0104     struct usb_phy  *x = usb_get_phy(USB_PHY_TYPE_USB2);
0105 
0106     if (IS_ERR(x))
0107         return -ENODEV;
0108 
0109     phy = phy_to_omapusb(x);
0110     phy->comparator = comparator;
0111     return 0;
0112 }
0113 EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
0114 
0115 static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
0116 {
0117     struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
0118 
0119     if (!phy->comparator)
0120         return -ENODEV;
0121 
0122     return phy->comparator->set_vbus(phy->comparator, enabled);
0123 }
0124 
0125 static int omap_usb_start_srp(struct usb_otg *otg)
0126 {
0127     struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
0128 
0129     if (!phy->comparator)
0130         return -ENODEV;
0131 
0132     return phy->comparator->start_srp(phy->comparator);
0133 }
0134 
0135 static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
0136 {
0137     otg->host = host;
0138     if (!host)
0139         otg->state = OTG_STATE_UNDEFINED;
0140 
0141     return 0;
0142 }
0143 
0144 static int omap_usb_set_peripheral(struct usb_otg *otg,
0145                    struct usb_gadget *gadget)
0146 {
0147     otg->gadget = gadget;
0148     if (!gadget)
0149         otg->state = OTG_STATE_UNDEFINED;
0150 
0151     return 0;
0152 }
0153 
0154 static int omap_usb_phy_power(struct omap_usb *phy, int on)
0155 {
0156     u32 val;
0157     int ret;
0158 
0159     if (!phy->syscon_phy_power) {
0160         omap_control_phy_power(phy->control_dev, on);
0161         return 0;
0162     }
0163 
0164     if (on)
0165         val = phy->power_on;
0166     else
0167         val = phy->power_off;
0168 
0169     ret = regmap_update_bits(phy->syscon_phy_power, phy->power_reg,
0170                  phy->mask, val);
0171     return ret;
0172 }
0173 
0174 static int omap_usb_power_off(struct phy *x)
0175 {
0176     struct omap_usb *phy = phy_get_drvdata(x);
0177 
0178     return omap_usb_phy_power(phy, false);
0179 }
0180 
0181 static int omap_usb_power_on(struct phy *x)
0182 {
0183     struct omap_usb *phy = phy_get_drvdata(x);
0184 
0185     return omap_usb_phy_power(phy, true);
0186 }
0187 
0188 static int omap_usb2_disable_clocks(struct omap_usb *phy)
0189 {
0190     clk_disable_unprepare(phy->wkupclk);
0191     if (!IS_ERR(phy->optclk))
0192         clk_disable_unprepare(phy->optclk);
0193 
0194     return 0;
0195 }
0196 
0197 static int omap_usb2_enable_clocks(struct omap_usb *phy)
0198 {
0199     int ret;
0200 
0201     ret = clk_prepare_enable(phy->wkupclk);
0202     if (ret < 0) {
0203         dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
0204         goto err0;
0205     }
0206 
0207     if (!IS_ERR(phy->optclk)) {
0208         ret = clk_prepare_enable(phy->optclk);
0209         if (ret < 0) {
0210             dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
0211             goto err1;
0212         }
0213     }
0214 
0215     return 0;
0216 
0217 err1:
0218     clk_disable_unprepare(phy->wkupclk);
0219 
0220 err0:
0221     return ret;
0222 }
0223 
0224 static int omap_usb_init(struct phy *x)
0225 {
0226     struct omap_usb *phy = phy_get_drvdata(x);
0227     u32 val;
0228 
0229     omap_usb2_enable_clocks(phy);
0230 
0231     if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
0232         /*
0233          *
0234          * Reduce the sensitivity of internal PHY by enabling the
0235          * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
0236          * resolves issues with certain devices which can otherwise
0237          * be prone to false disconnects.
0238          *
0239          */
0240         val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
0241         val |= USB2PHY_DISCON_BYP_LATCH;
0242         omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
0243     }
0244 
0245     if (phy->flags & OMAP_USB2_DISABLE_CHRG_DET) {
0246         val = omap_usb_readl(phy->phy_base, USB2PHY_CHRG_DET);
0247         val |= USB2PHY_CHRG_DET_USE_CHG_DET_REG |
0248                USB2PHY_CHRG_DET_DIS_CHG_DET;
0249         omap_usb_writel(phy->phy_base, USB2PHY_CHRG_DET, val);
0250     }
0251 
0252     return 0;
0253 }
0254 
0255 static int omap_usb_exit(struct phy *x)
0256 {
0257     struct omap_usb *phy = phy_get_drvdata(x);
0258 
0259     return omap_usb2_disable_clocks(phy);
0260 }
0261 
0262 static const struct phy_ops ops = {
0263     .init       = omap_usb_init,
0264     .exit       = omap_usb_exit,
0265     .power_on   = omap_usb_power_on,
0266     .power_off  = omap_usb_power_off,
0267     .owner      = THIS_MODULE,
0268 };
0269 
0270 static const struct usb_phy_data omap_usb2_data = {
0271     .label = "omap_usb2",
0272     .flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
0273     .mask = OMAP_DEV_PHY_PD,
0274     .power_off = OMAP_DEV_PHY_PD,
0275 };
0276 
0277 static const struct usb_phy_data omap5_usb2_data = {
0278     .label = "omap5_usb2",
0279     .flags = 0,
0280     .mask = OMAP_DEV_PHY_PD,
0281     .power_off = OMAP_DEV_PHY_PD,
0282 };
0283 
0284 static const struct usb_phy_data dra7x_usb2_data = {
0285     .label = "dra7x_usb2",
0286     .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
0287     .mask = OMAP_DEV_PHY_PD,
0288     .power_off = OMAP_DEV_PHY_PD,
0289 };
0290 
0291 static const struct usb_phy_data dra7x_usb2_phy2_data = {
0292     .label = "dra7x_usb2_phy2",
0293     .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
0294     .mask = OMAP_USB2_PHY_PD,
0295     .power_off = OMAP_USB2_PHY_PD,
0296 };
0297 
0298 static const struct usb_phy_data am437x_usb2_data = {
0299     .label = "am437x_usb2",
0300     .flags =  0,
0301     .mask = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD |
0302         AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
0303     .power_on = AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
0304     .power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
0305 };
0306 
0307 static const struct usb_phy_data am654_usb2_data = {
0308     .label = "am654_usb2",
0309     .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
0310     .mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN |
0311         AM654_USB2_VBUSVALID_DET_EN,
0312     .power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN,
0313     .power_off = AM654_USB2_OTG_PD,
0314 };
0315 
0316 static const struct of_device_id omap_usb2_id_table[] = {
0317     {
0318         .compatible = "ti,omap-usb2",
0319         .data = &omap_usb2_data,
0320     },
0321     {
0322         .compatible = "ti,omap5-usb2",
0323         .data = &omap5_usb2_data,
0324     },
0325     {
0326         .compatible = "ti,dra7x-usb2",
0327         .data = &dra7x_usb2_data,
0328     },
0329     {
0330         .compatible = "ti,dra7x-usb2-phy2",
0331         .data = &dra7x_usb2_phy2_data,
0332     },
0333     {
0334         .compatible = "ti,am437x-usb2",
0335         .data = &am437x_usb2_data,
0336     },
0337     {
0338         .compatible = "ti,am654-usb2",
0339         .data = &am654_usb2_data,
0340     },
0341     {},
0342 };
0343 MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
0344 
0345 static void omap_usb2_init_errata(struct omap_usb *phy)
0346 {
0347     static const struct soc_device_attribute am65x_sr10_soc_devices[] = {
0348         { .family = "AM65X", .revision = "SR1.0" },
0349         { /* sentinel */ }
0350     };
0351 
0352     /*
0353      * Errata i2075: USB2PHY: USB2PHY Charger Detect is Enabled by
0354      * Default Without VBUS Presence.
0355      *
0356      * AM654x SR1.0 has a silicon bug due to which D+ is pulled high after
0357      * POR, which could cause enumeration failure with some USB hubs.
0358      * Disabling the USB2_PHY Charger Detect function will put D+
0359      * into the normal state.
0360      */
0361     if (soc_device_match(am65x_sr10_soc_devices))
0362         phy->flags |= OMAP_USB2_DISABLE_CHRG_DET;
0363 }
0364 
0365 static int omap_usb2_probe(struct platform_device *pdev)
0366 {
0367     struct omap_usb *phy;
0368     struct phy *generic_phy;
0369     struct phy_provider *phy_provider;
0370     struct usb_otg *otg;
0371     struct device_node *node = pdev->dev.of_node;
0372     struct device_node *control_node;
0373     struct platform_device *control_pdev;
0374     const struct of_device_id *of_id;
0375     struct usb_phy_data *phy_data;
0376 
0377     of_id = of_match_device(omap_usb2_id_table, &pdev->dev);
0378 
0379     if (!of_id)
0380         return -EINVAL;
0381 
0382     phy_data = (struct usb_phy_data *)of_id->data;
0383 
0384     phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
0385     if (!phy)
0386         return -ENOMEM;
0387 
0388     otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
0389     if (!otg)
0390         return -ENOMEM;
0391 
0392     phy->dev        = &pdev->dev;
0393 
0394     phy->phy.dev        = phy->dev;
0395     phy->phy.label      = phy_data->label;
0396     phy->phy.otg        = otg;
0397     phy->phy.type       = USB_PHY_TYPE_USB2;
0398     phy->mask       = phy_data->mask;
0399     phy->power_on       = phy_data->power_on;
0400     phy->power_off      = phy_data->power_off;
0401     phy->flags      = phy_data->flags;
0402 
0403     omap_usb2_init_errata(phy);
0404 
0405     phy->phy_base = devm_platform_ioremap_resource(pdev, 0);
0406     if (IS_ERR(phy->phy_base))
0407         return PTR_ERR(phy->phy_base);
0408 
0409     phy->syscon_phy_power = syscon_regmap_lookup_by_phandle(node,
0410                                 "syscon-phy-power");
0411     if (IS_ERR(phy->syscon_phy_power)) {
0412         dev_dbg(&pdev->dev,
0413             "can't get syscon-phy-power, using control device\n");
0414         phy->syscon_phy_power = NULL;
0415 
0416         control_node = of_parse_phandle(node, "ctrl-module", 0);
0417         if (!control_node) {
0418             dev_err(&pdev->dev,
0419                 "Failed to get control device phandle\n");
0420             return -EINVAL;
0421         }
0422 
0423         control_pdev = of_find_device_by_node(control_node);
0424         if (!control_pdev) {
0425             dev_err(&pdev->dev, "Failed to get control device\n");
0426             return -EINVAL;
0427         }
0428         phy->control_dev = &control_pdev->dev;
0429     } else {
0430         if (of_property_read_u32_index(node,
0431                            "syscon-phy-power", 1,
0432                            &phy->power_reg)) {
0433             dev_err(&pdev->dev,
0434                 "couldn't get power reg. offset\n");
0435             return -EINVAL;
0436         }
0437     }
0438 
0439     phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
0440     if (IS_ERR(phy->wkupclk)) {
0441         if (PTR_ERR(phy->wkupclk) == -EPROBE_DEFER)
0442             return -EPROBE_DEFER;
0443 
0444         dev_warn(&pdev->dev, "unable to get wkupclk %ld, trying old name\n",
0445              PTR_ERR(phy->wkupclk));
0446         phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
0447 
0448         if (IS_ERR(phy->wkupclk)) {
0449             if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER)
0450                 dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
0451             return PTR_ERR(phy->wkupclk);
0452         }
0453 
0454         dev_warn(&pdev->dev,
0455              "found usb_phy_cm_clk32k, please fix DTS\n");
0456     }
0457 
0458     phy->optclk = devm_clk_get(phy->dev, "refclk");
0459     if (IS_ERR(phy->optclk)) {
0460         if (PTR_ERR(phy->optclk) == -EPROBE_DEFER)
0461             return -EPROBE_DEFER;
0462 
0463         dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
0464         phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
0465 
0466         if (IS_ERR(phy->optclk)) {
0467             if (PTR_ERR(phy->optclk) != -EPROBE_DEFER) {
0468                 dev_dbg(&pdev->dev,
0469                     "unable to get usb_otg_ss_refclk960m\n");
0470             }
0471         } else {
0472             dev_warn(&pdev->dev,
0473                  "found usb_otg_ss_refclk960m, please fix DTS\n");
0474         }
0475     }
0476 
0477     otg->set_host = omap_usb_set_host;
0478     otg->set_peripheral = omap_usb_set_peripheral;
0479     if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
0480         otg->set_vbus = omap_usb_set_vbus;
0481     if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
0482         otg->start_srp = omap_usb_start_srp;
0483     otg->usb_phy = &phy->phy;
0484 
0485     platform_set_drvdata(pdev, phy);
0486     pm_runtime_enable(phy->dev);
0487 
0488     generic_phy = devm_phy_create(phy->dev, NULL, &ops);
0489     if (IS_ERR(generic_phy)) {
0490         pm_runtime_disable(phy->dev);
0491         return PTR_ERR(generic_phy);
0492     }
0493 
0494     phy_set_drvdata(generic_phy, phy);
0495     omap_usb_power_off(generic_phy);
0496 
0497     phy_provider = devm_of_phy_provider_register(phy->dev,
0498                              of_phy_simple_xlate);
0499     if (IS_ERR(phy_provider)) {
0500         pm_runtime_disable(phy->dev);
0501         return PTR_ERR(phy_provider);
0502     }
0503 
0504     usb_add_phy_dev(&phy->phy);
0505 
0506     return 0;
0507 }
0508 
0509 static int omap_usb2_remove(struct platform_device *pdev)
0510 {
0511     struct omap_usb *phy = platform_get_drvdata(pdev);
0512 
0513     usb_remove_phy(&phy->phy);
0514     pm_runtime_disable(phy->dev);
0515 
0516     return 0;
0517 }
0518 
0519 static struct platform_driver omap_usb2_driver = {
0520     .probe      = omap_usb2_probe,
0521     .remove     = omap_usb2_remove,
0522     .driver     = {
0523         .name   = "omap-usb2",
0524         .of_match_table = omap_usb2_id_table,
0525     },
0526 };
0527 
0528 module_platform_driver(omap_usb2_driver);
0529 
0530 MODULE_ALIAS("platform:omap_usb2");
0531 MODULE_AUTHOR("Texas Instruments Inc.");
0532 MODULE_DESCRIPTION("OMAP USB2 phy driver");
0533 MODULE_LICENSE("GPL v2");