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