1 // SPDX-License-Identifier: GPL-2.0+
3 * Atheros AR71XX/9XXX USB PHY driver
5 * Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/phy/phy.h>
11 #include <linux/reset.h>
13 struct ath79_usb_phy
{
14 struct reset_control
*reset
;
15 /* The suspend override logic is inverted, hence the no prefix
16 * to make the code a bit easier to understand.
18 struct reset_control
*no_suspend_override
;
21 static int ath79_usb_phy_power_on(struct phy
*phy
)
23 struct ath79_usb_phy
*priv
= phy_get_drvdata(phy
);
26 if (priv
->no_suspend_override
) {
27 err
= reset_control_assert(priv
->no_suspend_override
);
32 err
= reset_control_deassert(priv
->reset
);
33 if (err
&& priv
->no_suspend_override
)
34 reset_control_deassert(priv
->no_suspend_override
);
39 static int ath79_usb_phy_power_off(struct phy
*phy
)
41 struct ath79_usb_phy
*priv
= phy_get_drvdata(phy
);
44 err
= reset_control_assert(priv
->reset
);
48 if (priv
->no_suspend_override
) {
49 err
= reset_control_deassert(priv
->no_suspend_override
);
51 reset_control_deassert(priv
->reset
);
57 static const struct phy_ops ath79_usb_phy_ops
= {
58 .power_on
= ath79_usb_phy_power_on
,
59 .power_off
= ath79_usb_phy_power_off
,
63 static int ath79_usb_phy_probe(struct platform_device
*pdev
)
65 struct ath79_usb_phy
*priv
;
68 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
72 priv
->reset
= devm_reset_control_get(&pdev
->dev
, "phy");
73 if (IS_ERR(priv
->reset
))
74 return PTR_ERR(priv
->reset
);
76 priv
->no_suspend_override
= devm_reset_control_get_optional(
77 &pdev
->dev
, "usb-suspend-override");
78 if (IS_ERR(priv
->no_suspend_override
))
79 return PTR_ERR(priv
->no_suspend_override
);
81 phy
= devm_phy_create(&pdev
->dev
, NULL
, &ath79_usb_phy_ops
);
85 phy_set_drvdata(phy
, priv
);
87 return PTR_ERR_OR_ZERO(devm_of_phy_provider_register(
88 &pdev
->dev
, of_phy_simple_xlate
));
91 static const struct of_device_id ath79_usb_phy_of_match
[] = {
92 { .compatible
= "qca,ar7100-usb-phy" },
95 MODULE_DEVICE_TABLE(of
, ath79_usb_phy_of_match
);
97 static struct platform_driver ath79_usb_phy_driver
= {
98 .probe
= ath79_usb_phy_probe
,
100 .of_match_table
= ath79_usb_phy_of_match
,
101 .name
= "ath79-usb-phy",
104 module_platform_driver(ath79_usb_phy_driver
);
106 MODULE_DESCRIPTION("ATH79 USB PHY driver");
107 MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
108 MODULE_LICENSE("GPL");