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 14struct 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 22static 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 40static 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 58static 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 64static 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 92static const struct of_device_id ath79_usb_phy_of_match[] = { 93 { .compatible = "qca,ar7100-usb-phy" }, 94 {} 95}; 96MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match); 97 98static 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}; 105module_platform_driver(ath79_usb_phy_driver); 106 107MODULE_DESCRIPTION("ATH79 USB PHY driver"); 108MODULE_AUTHOR("Alban Bedel <albeu@free.fr>"); 109MODULE_LICENSE("GPL"); 110