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