1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Atheros AR71XX/9XXX USB PHY driver 4 * 5 * Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr> 6 */ 7 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/phy/phy.h> 12 #include <linux/reset.h> 13 14 struct ath79_usb_phy { 15 struct reset_control *reset; 16 /* The suspend override logic is inverted, hence the no prefix 17 * to make the code a bit easier to understand. 18 */ 19 struct reset_control *no_suspend_override; 20 }; 21 22 static int ath79_usb_phy_power_on(struct phy *phy) 23 { 24 struct ath79_usb_phy *priv = phy_get_drvdata(phy); 25 int err = 0; 26 27 if (priv->no_suspend_override) { 28 err = reset_control_assert(priv->no_suspend_override); 29 if (err) 30 return err; 31 } 32 33 err = reset_control_deassert(priv->reset); 34 if (err && priv->no_suspend_override) 35 reset_control_deassert(priv->no_suspend_override); 36 37 return err; 38 } 39 40 static int ath79_usb_phy_power_off(struct phy *phy) 41 { 42 struct ath79_usb_phy *priv = phy_get_drvdata(phy); 43 int err = 0; 44 45 err = reset_control_assert(priv->reset); 46 if (err) 47 return err; 48 49 if (priv->no_suspend_override) { 50 err = reset_control_deassert(priv->no_suspend_override); 51 if (err) 52 reset_control_deassert(priv->reset); 53 } 54 55 return err; 56 } 57 58 static const struct phy_ops ath79_usb_phy_ops = { 59 .power_on = ath79_usb_phy_power_on, 60 .power_off = ath79_usb_phy_power_off, 61 .owner = THIS_MODULE, 62 }; 63 64 static int ath79_usb_phy_probe(struct platform_device *pdev) 65 { 66 struct ath79_usb_phy *priv; 67 struct phy *phy; 68 69 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 70 if (!priv) 71 return -ENOMEM; 72 73 priv->reset = devm_reset_control_get(&pdev->dev, "phy"); 74 if (IS_ERR(priv->reset)) 75 return PTR_ERR(priv->reset); 76 77 priv->no_suspend_override = devm_reset_control_get_optional( 78 &pdev->dev, "usb-suspend-override"); 79 if (IS_ERR(priv->no_suspend_override)) 80 return PTR_ERR(priv->no_suspend_override); 81 82 phy = devm_phy_create(&pdev->dev, NULL, &ath79_usb_phy_ops); 83 if (IS_ERR(phy)) 84 return PTR_ERR(phy); 85 86 phy_set_drvdata(phy, priv); 87 88 return PTR_ERR_OR_ZERO(devm_of_phy_provider_register( 89 &pdev->dev, of_phy_simple_xlate)); 90 } 91 92 static const struct of_device_id ath79_usb_phy_of_match[] = { 93 { .compatible = "qca,ar7100-usb-phy" }, 94 {} 95 }; 96 MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match); 97 98 static struct platform_driver ath79_usb_phy_driver = { 99 .probe = ath79_usb_phy_probe, 100 .driver = { 101 .of_match_table = ath79_usb_phy_of_match, 102 .name = "ath79-usb-phy", 103 } 104 }; 105 module_platform_driver(ath79_usb_phy_driver); 106 107 MODULE_DESCRIPTION("ATH79 USB PHY driver"); 108 MODULE_AUTHOR("Alban Bedel <albeu@free.fr>"); 109 MODULE_LICENSE("GPL"); 110