Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Atheros AR71XX/9XXX USB PHY driver
0004  *
0005  * Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/phy/phy.h>
0011 #include <linux/reset.h>
0012 
0013 struct ath79_usb_phy {
0014     struct reset_control *reset;
0015     /* The suspend override logic is inverted, hence the no prefix
0016      * to make the code a bit easier to understand.
0017      */
0018     struct reset_control *no_suspend_override;
0019 };
0020 
0021 static int ath79_usb_phy_power_on(struct phy *phy)
0022 {
0023     struct ath79_usb_phy *priv = phy_get_drvdata(phy);
0024     int err = 0;
0025 
0026     if (priv->no_suspend_override) {
0027         err = reset_control_assert(priv->no_suspend_override);
0028         if (err)
0029             return err;
0030     }
0031 
0032     err = reset_control_deassert(priv->reset);
0033     if (err && priv->no_suspend_override)
0034         reset_control_deassert(priv->no_suspend_override);
0035 
0036     return err;
0037 }
0038 
0039 static int ath79_usb_phy_power_off(struct phy *phy)
0040 {
0041     struct ath79_usb_phy *priv = phy_get_drvdata(phy);
0042     int err = 0;
0043 
0044     err = reset_control_assert(priv->reset);
0045     if (err)
0046         return err;
0047 
0048     if (priv->no_suspend_override) {
0049         err = reset_control_deassert(priv->no_suspend_override);
0050         if (err)
0051             reset_control_deassert(priv->reset);
0052     }
0053 
0054     return err;
0055 }
0056 
0057 static const struct phy_ops ath79_usb_phy_ops = {
0058     .power_on   = ath79_usb_phy_power_on,
0059     .power_off  = ath79_usb_phy_power_off,
0060     .owner      = THIS_MODULE,
0061 };
0062 
0063 static int ath79_usb_phy_probe(struct platform_device *pdev)
0064 {
0065     struct ath79_usb_phy *priv;
0066     struct phy *phy;
0067 
0068     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0069     if (!priv)
0070         return -ENOMEM;
0071 
0072     priv->reset = devm_reset_control_get(&pdev->dev, "phy");
0073     if (IS_ERR(priv->reset))
0074         return PTR_ERR(priv->reset);
0075 
0076     priv->no_suspend_override = devm_reset_control_get_optional(
0077         &pdev->dev, "usb-suspend-override");
0078     if (IS_ERR(priv->no_suspend_override))
0079         return PTR_ERR(priv->no_suspend_override);
0080 
0081     phy = devm_phy_create(&pdev->dev, NULL, &ath79_usb_phy_ops);
0082     if (IS_ERR(phy))
0083         return PTR_ERR(phy);
0084 
0085     phy_set_drvdata(phy, priv);
0086 
0087     return PTR_ERR_OR_ZERO(devm_of_phy_provider_register(
0088                 &pdev->dev, of_phy_simple_xlate));
0089 }
0090 
0091 static const struct of_device_id ath79_usb_phy_of_match[] = {
0092     { .compatible = "qca,ar7100-usb-phy" },
0093     {}
0094 };
0095 MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match);
0096 
0097 static struct platform_driver ath79_usb_phy_driver = {
0098     .probe  = ath79_usb_phy_probe,
0099     .driver = {
0100         .of_match_table = ath79_usb_phy_of_match,
0101         .name       = "ath79-usb-phy",
0102     }
0103 };
0104 module_platform_driver(ath79_usb_phy_driver);
0105 
0106 MODULE_DESCRIPTION("ATH79 USB PHY driver");
0107 MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
0108 MODULE_LICENSE("GPL");