xref: /linux/drivers/phy/qualcomm/phy-ath79-usb.c (revision 827cb0323928952c0db9515aba9d534fb1285b3f)
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