From: Alban Bedel <al...@free.fr> The ATH79 USB phy is very simple, it only have a reset. On some SoC a second reset is used to force the phy in suspend mode regardless of the USB controller status.
Signed-off-by: Alban Bedel <al...@free.fr> --- Changelog: v2: * Rebased on the simple PHY driver * Added myself as maintainer of the driver v4: * Updated the copyright date * Use the new PHY core instead of the simple PHY driver --- MAINTAINERS | 8 ++++ drivers/phy/Kconfig | 8 ++++ drivers/phy/Makefile | 1 + drivers/phy/phy-ath79-usb.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 drivers/phy/phy-ath79-usb.c diff --git a/MAINTAINERS b/MAINTAINERS index 107c10e..25f2df5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2105,6 +2105,14 @@ S: Maintained F: drivers/gpio/gpio-ath79.c F: Documentation/devicetree/bindings/gpio/gpio-ath79.txt +ATHEROS 71XX/9XXX USB PHY DRIVER +M: Alban Bedel <al...@free.fr> +W: https://github.com/AlbanBedel/linux +T: git git://github.com/AlbanBedel/linux +S: Maintained +F: drivers/phy/phy-ath79-usb.c +F: Documentation/devicetree/bindings/phy/phy-ath79-usb.txt + ATHEROS ATH GENERIC UTILITIES M: "Luis R. Rodriguez" <mcg...@do-not-panic.com> L: linux-wirel...@vger.kernel.org diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8eb7f2..129f5c7 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,6 +15,14 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config PHY_ATH79_USB + tristate "Atheros AR71XX/9XXX USB PHY driver" + depends on ATH79 || COMPILE_TEST + default y if USB_EHCI_HCD_PLATFORM + select GENERIC_PHY + help + Enable this to support the USB PHY on Atheros AR71XX/9XXX SoCs. + config PHY_BCM_NS_USB2 tristate "Broadcom Northstar USB 2.0 PHY Driver" depends on ARCH_BCM_IPROC || COMPILE_TEST diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 65eb2f4..23266779 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o diff --git a/drivers/phy/phy-ath79-usb.c b/drivers/phy/phy-ath79-usb.c new file mode 100644 index 0000000..3f20d31 --- /dev/null +++ b/drivers/phy/phy-ath79-usb.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015-2017 Alban Bedel <al...@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/phy/phy.h> +#include <linux/reset.h> + +struct ath79_usb_phy { + struct reset_control *suspend_override; +}; + +static int ath79_usb_phy_power_on(struct phy *phy) +{ + struct ath79_usb_phy *priv = phy_get_drvdata(phy); + int err = 0; + + if (priv->suspend_override) + err = reset_control_assert(priv->suspend_override); + + return err; +} + +static int ath79_usb_phy_power_off(struct phy *phy) +{ + struct ath79_usb_phy *priv = phy_get_drvdata(phy); + int err = 0; + + if (priv->suspend_override) + err = reset_control_deassert(priv->suspend_override); + + return err; +} + +static const struct phy_ops ath79_usb_phy_ops = { + .power_on = ath79_usb_phy_power_on, + .power_off = ath79_usb_phy_power_off, + .owner = THIS_MODULE, +}; + +static int ath79_usb_phy_probe(struct platform_device *pdev) +{ + struct ath79_usb_phy *priv; + struct phy *phy; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->suspend_override = devm_reset_control_get_optional( + &pdev->dev, "suspend-override"); + if (IS_ERR(priv->suspend_override)) { + if (PTR_ERR(priv->suspend_override) == -ENOENT) + priv->suspend_override = NULL; + else + return PTR_ERR(priv->suspend_override); + } + + phy = devm_phy_create(&pdev->dev, NULL, &ath79_usb_phy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + + return PTR_ERR_OR_ZERO(devm_of_phy_provider_register( + &pdev->dev, of_phy_simple_xlate)); +} + +static const struct of_device_id ath79_usb_phy_of_match[] = { + { .compatible = "qca,ar7100-usb-phy" }, + {} +}; +MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match); + +static struct platform_driver ath79_usb_phy_driver = { + .probe = ath79_usb_phy_probe, + .driver = { + .of_match_table = ath79_usb_phy_of_match, + .name = "ath79-usb-phy", + } +}; +module_platform_driver(ath79_usb_phy_driver); + +MODULE_DESCRIPTION("ATH79 USB PHY driver"); +MODULE_AUTHOR("Alban Bedel <al...@free.fr>"); +MODULE_LICENSE("GPL"); -- 2.7.4