110 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Atheros AR71XX/9XXX USB PHY driver4 *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 prefix17 * 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