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