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