From mboxrd@z Thu Jan 1 00:00:00 1970 From: Martin Blumenstingl Subject: [PATCH usb-next v9 3/8] usb: core: add a wrapper for the USB PHYs on the HCD Date: Sun, 11 Feb 2018 22:06:46 +0100 Message-ID: <20180211210651.2046-4-martin.blumenstingl@googlemail.com> References: <20180211210651.2046-1-martin.blumenstingl@googlemail.com> Return-path: In-Reply-To: <20180211210651.2046-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> Sender: devicetree-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org To: linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, mathias.nyman-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, arnd-r2nGTMty4D4@public.gmane.org, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org, felipe.balbi-VuQAYsv1563Yd54FQh9/CA@public.gmane.org Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org, thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org, stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org, linux-ci5G2KO2hbZ+pU9mqzGVBQ@public.gmane.org, Peter.Chen-3arQi8VN3Tc@public.gmane.org, matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org, mark.rutland-5wv7dgnIgG8@public.gmane.org, robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org, narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org, linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, yixun.lan-LpR1jeaWuhtBDgjK7y7TUQ@public.gmane.org, Martin Blumenstingl , Chunfeng Yun List-Id: linux-tegra@vger.kernel.org Many SoC platforms have separate devices for the USB PHY which are registered through the generic PHY framework. These PHYs have to be enabled to make the USB controller actually work. They also have to be disabled again on shutdown/suspend. Currently (at least) the following HCI platform drivers are using custom code to obtain all PHYs via devicetree for the roothub/controller and disable/enable them when required: - ehci-platform.c has ehci_platform_power_{on,off} - xhci-mtk.c has xhci_mtk_phy_{init,exit,power_on,power_off} - ohci-platform.c has ohci_platform_power_{on,off} With this new wrapper the USB PHYs can be specified directly in the USB controller's devicetree node (just like on the drivers listed above). This allows SoCs like the Amlogic Meson GXL family to operate correctly once this is wired up correctly. These SoCs use a dwc3 controller and require all USB PHYs to be initialized (if one of the USB PHYs it not initialized then none of USB port works at all). Signed-off-by: Martin Blumenstingl Tested-by: Yixun Lan Cc: Neil Armstrong Cc: Chunfeng Yun --- drivers/usb/core/Makefile | 2 +- drivers/usb/core/phy.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/phy.h | 7 ++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/core/phy.c create mode 100644 drivers/usb/core/phy.h diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 92c9cefb4317..18e874b0441e 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -6,7 +6,7 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o +usbcore-y += phy.o port.o usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c new file mode 100644 index 000000000000..09b7c43c0ea4 --- /dev/null +++ b/drivers/usb/core/phy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * A wrapper for multiple PHYs which passes all phy_* function calls to + * multiple (actual) PHY devices. This is comes handy when initializing + * all PHYs on a HCD and to keep them all in the same state. + * + * Copyright (C) 2018 Martin Blumenstingl + */ + +#include +#include +#include +#include + +#include "phy.h" + +struct usb_phy_roothub { + struct phy *phy; + struct list_head list; +}; + +static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) +{ + struct usb_phy_roothub *roothub_entry; + + roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); + if (!roothub_entry) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&roothub_entry->list); + + return roothub_entry; +} + +static int usb_phy_roothub_add_phy(struct device *dev, int index, + struct list_head *list) +{ + struct usb_phy_roothub *roothub_entry; + struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + + if (IS_ERR_OR_NULL(phy)) { + if (!phy || PTR_ERR(phy) == -ENODEV) + return 0; + else + return PTR_ERR(phy); + } + + roothub_entry = usb_phy_roothub_alloc(dev); + if (IS_ERR(roothub_entry)) + return PTR_ERR(roothub_entry); + + roothub_entry->phy = phy; + + list_add_tail(&roothub_entry->list, list); + + return 0; +} + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) +{ + struct usb_phy_roothub *phy_roothub; + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int i, num_phys, err; + + num_phys = of_count_phandle_with_args(dev->of_node, "phys", + "#phy-cells"); + if (num_phys <= 0) + return NULL; + + phy_roothub = usb_phy_roothub_alloc(dev); + if (IS_ERR(phy_roothub)) + return phy_roothub; + + for (i = 0; i < num_phys; i++) { + err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); + if (err) + goto err_out; + } + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_init(roothub_entry->phy); + if (err) + goto err_exit_phys; + } + + return phy_roothub; + +err_exit_phys: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_exit(roothub_entry->phy); + +err_out: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_init); + +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err, ret = 0; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_exit(roothub_entry->phy); + if (err) + ret = ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_power_on(roothub_entry->phy); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on); + +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + + if (!phy_roothub) + return; + + list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list) + phy_power_off(roothub_entry->phy); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h new file mode 100644 index 000000000000..6fde59bfbff8 --- /dev/null +++ b/drivers/usb/core/phy.h @@ -0,0 +1,7 @@ +struct usb_phy_roothub; + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev); +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); -- 2.16.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [usb-next,v9,3/8] usb: core: add a wrapper for the USB PHYs on the HCD From: Martin Blumenstingl Message-Id: <20180211210651.2046-4-martin.blumenstingl@googlemail.com> Date: Sun, 11 Feb 2018 22:06:46 +0100 To: linux-usb@vger.kernel.org, mathias.nyman@intel.com, arnd@arndb.de, gregkh@linuxfoundation.org, felipe.balbi@linux.intel.com Cc: linux-omap@vger.kernel.org, linux-tegra@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, jonathanh@nvidia.com, thierry.reding@gmail.com, stern@rowland.harvard.edu, linux@prisktech.co.nz, Peter.Chen@nxp.com, matthias.bgg@gmail.com, mark.rutland@arm.com, robh+dt@kernel.org, narmstrong@baylibre.com, linux-amlogic@lists.infradead.org, yixun.lan@amlogic.com, Martin Blumenstingl , Chunfeng Yun List-ID: TWFueSBTb0MgcGxhdGZvcm1zIGhhdmUgc2VwYXJhdGUgZGV2aWNlcyBmb3IgdGhlIFVTQiBQSFkg d2hpY2ggYXJlCnJlZ2lzdGVyZWQgdGhyb3VnaCB0aGUgZ2VuZXJpYyBQSFkgZnJhbWV3b3JrLiBU aGVzZSBQSFlzIGhhdmUgdG8gYmUKZW5hYmxlZCB0byBtYWtlIHRoZSBVU0IgY29udHJvbGxlciBh Y3R1YWxseSB3b3JrLiBUaGV5IGFsc28gaGF2ZSB0byBiZQpkaXNhYmxlZCBhZ2FpbiBvbiBzaHV0 ZG93bi9zdXNwZW5kLgoKQ3VycmVudGx5IChhdCBsZWFzdCkgdGhlIGZvbGxvd2luZyBIQ0kgcGxh dGZvcm0gZHJpdmVycyBhcmUgdXNpbmcgY3VzdG9tCmNvZGUgdG8gb2J0YWluIGFsbCBQSFlzIHZp YSBkZXZpY2V0cmVlIGZvciB0aGUgcm9vdGh1Yi9jb250cm9sbGVyIGFuZApkaXNhYmxlL2VuYWJs ZSB0aGVtIHdoZW4gcmVxdWlyZWQ6Ci0gZWhjaS1wbGF0Zm9ybS5jIGhhcyBlaGNpX3BsYXRmb3Jt X3Bvd2VyX3tvbixvZmZ9Ci0geGhjaS1tdGsuYyBoYXMgeGhjaV9tdGtfcGh5X3tpbml0LGV4aXQs cG93ZXJfb24scG93ZXJfb2ZmfQotIG9oY2ktcGxhdGZvcm0uYyBoYXMgb2hjaV9wbGF0Zm9ybV9w b3dlcl97b24sb2ZmfQoKV2l0aCB0aGlzIG5ldyB3cmFwcGVyIHRoZSBVU0IgUEhZcyBjYW4gYmUg c3BlY2lmaWVkIGRpcmVjdGx5IGluIHRoZQpVU0IgY29udHJvbGxlcidzIGRldmljZXRyZWUgbm9k ZSAoanVzdCBsaWtlIG9uIHRoZSBkcml2ZXJzIGxpc3RlZAphYm92ZSkuIFRoaXMgYWxsb3dzIFNv Q3MgbGlrZSB0aGUgQW1sb2dpYyBNZXNvbiBHWEwgZmFtaWx5IHRvIG9wZXJhdGUKY29ycmVjdGx5 IG9uY2UgdGhpcyBpcyB3aXJlZCB1cCBjb3JyZWN0bHkuIFRoZXNlIFNvQ3MgdXNlIGEgZHdjMwpj b250cm9sbGVyIGFuZCByZXF1aXJlIGFsbCBVU0IgUEhZcyB0byBiZSBpbml0aWFsaXplZCAoaWYg b25lIG9mIHRoZSBVU0IKUEhZcyBpdCBub3QgaW5pdGlhbGl6ZWQgdGhlbiBub25lIG9mIFVTQiBw b3J0IHdvcmtzIGF0IGFsbCkuCgpTaWduZWQtb2ZmLWJ5OiBNYXJ0aW4gQmx1bWVuc3RpbmdsIDxt YXJ0aW4uYmx1bWVuc3RpbmdsQGdvb2dsZW1haWwuY29tPgpUZXN0ZWQtYnk6IFlpeHVuIExhbiA8 eWl4dW4ubGFuQGFtbG9naWMuY29tPgpDYzogTmVpbCBBcm1zdHJvbmcgPG5hcm1zdHJvbmdAYmF5 bGlicmUuY29tPgpDYzogQ2h1bmZlbmcgWXVuIDxjaHVuZmVuZy55dW5AbWVkaWF0ZWsuY29tPgot LS0KIGRyaXZlcnMvdXNiL2NvcmUvTWFrZWZpbGUgfCAgIDIgKy0KIGRyaXZlcnMvdXNiL2NvcmUv cGh5LmMgICAgfCAxNTggKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKwogZHJpdmVycy91c2IvY29yZS9waHkuaCAgICB8ICAgNyArKwogMyBmaWxlcyBjaGFuZ2Vk LCAxNjYgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlvbigtKQogY3JlYXRlIG1vZGUgMTAwNjQ0IGRy aXZlcnMvdXNiL2NvcmUvcGh5LmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9jb3Jl L3BoeS5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY29yZS9NYWtlZmlsZSBiL2RyaXZlcnMv dXNiL2NvcmUvTWFrZWZpbGUKaW5kZXggOTJjOWNlZmI0MzE3Li4xOGU4NzRiMDQ0MWUgMTAwNjQ0 Ci0tLSBhL2RyaXZlcnMvdXNiL2NvcmUvTWFrZWZpbGUKKysrIGIvZHJpdmVycy91c2IvY29yZS9N YWtlZmlsZQpAQCAtNiw3ICs2LDcgQEAKIHVzYmNvcmUteSA6PSB1c2IubyBodWIubyBoY2QubyB1 cmIubyBtZXNzYWdlLm8gZHJpdmVyLm8KIHVzYmNvcmUteSArPSBjb25maWcubyBmaWxlLm8gYnVm ZmVyLm8gc3lzZnMubyBlbmRwb2ludC5vCiB1c2Jjb3JlLXkgKz0gZGV2aW8ubyBub3RpZnkubyBn ZW5lcmljLm8gcXVpcmtzLm8gZGV2aWNlcy5vCi11c2Jjb3JlLXkgKz0gcG9ydC5vCit1c2Jjb3Jl LXkgKz0gcGh5Lm8gcG9ydC5vCiAKIHVzYmNvcmUtJChDT05GSUdfT0YpCQkrPSBvZi5vCiB1c2Jj b3JlLSQoQ09ORklHX1VTQl9QQ0kpCQkrPSBoY2QtcGNpLm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMv dXNiL2NvcmUvcGh5LmMgYi9kcml2ZXJzL3VzYi9jb3JlL3BoeS5jCm5ldyBmaWxlIG1vZGUgMTAw NjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uMDliN2M0M2MwZWE0Ci0tLSAvZGV2L251bGwKKysrIGIv ZHJpdmVycy91c2IvY29yZS9waHkuYwpAQCAtMCwwICsxLDE1OCBAQAorLy8gU1BEWC1MaWNlbnNl LUlkZW50aWZpZXI6IEdQTC0yLjArCisvKgorICogQSB3cmFwcGVyIGZvciBtdWx0aXBsZSBQSFlz IHdoaWNoIHBhc3NlcyBhbGwgcGh5XyogZnVuY3Rpb24gY2FsbHMgdG8KKyAqIG11bHRpcGxlIChh Y3R1YWwpIFBIWSBkZXZpY2VzLiBUaGlzIGlzIGNvbWVzIGhhbmR5IHdoZW4gaW5pdGlhbGl6aW5n CisgKiBhbGwgUEhZcyBvbiBhIEhDRCBhbmQgdG8ga2VlcCB0aGVtIGFsbCBpbiB0aGUgc2FtZSBz dGF0ZS4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTggTWFydGluIEJsdW1lbnN0aW5nbCA8bWFy dGluLmJsdW1lbnN0aW5nbEBnb29nbGVtYWlsLmNvbT4KKyAqLworCisjaW5jbHVkZSA8bGludXgv ZGV2aWNlLmg+CisjaW5jbHVkZSA8bGludXgvbGlzdC5oPgorI2luY2x1ZGUgPGxpbnV4L3BoeS9w aHkuaD4KKyNpbmNsdWRlIDxsaW51eC9vZi5oPgorCisjaW5jbHVkZSAicGh5LmgiCisKK3N0cnVj dCB1c2JfcGh5X3Jvb3RodWIgeworCXN0cnVjdCBwaHkJCSpwaHk7CisJc3RydWN0IGxpc3RfaGVh ZAlsaXN0OworfTsKKworc3RhdGljIHN0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnVzYl9waHlfcm9v dGh1Yl9hbGxvYyhzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IHVzYl9waHlfcm9vdGh1 YiAqcm9vdGh1Yl9lbnRyeTsKKworCXJvb3RodWJfZW50cnkgPSBkZXZtX2t6YWxsb2MoZGV2LCBz aXplb2YoKnJvb3RodWJfZW50cnkpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXJvb3RodWJfZW50cnkp CisJCXJldHVybiBFUlJfUFRSKC1FTk9NRU0pOworCisJSU5JVF9MSVNUX0hFQUQoJnJvb3RodWJf ZW50cnktPmxpc3QpOworCisJcmV0dXJuIHJvb3RodWJfZW50cnk7Cit9CisKK3N0YXRpYyBpbnQg dXNiX3BoeV9yb290aHViX2FkZF9waHkoc3RydWN0IGRldmljZSAqZGV2LCBpbnQgaW5kZXgsCisJ CQkJICAgc3RydWN0IGxpc3RfaGVhZCAqbGlzdCkKK3sKKwlzdHJ1Y3QgdXNiX3BoeV9yb290aHVi ICpyb290aHViX2VudHJ5OworCXN0cnVjdCBwaHkgKnBoeSA9IGRldm1fb2ZfcGh5X2dldF9ieV9p bmRleChkZXYsIGRldi0+b2Zfbm9kZSwgaW5kZXgpOworCisJaWYgKElTX0VSUl9PUl9OVUxMKHBo eSkpIHsKKwkJaWYgKCFwaHkgfHwgUFRSX0VSUihwaHkpID09IC1FTk9ERVYpCisJCQlyZXR1cm4g MDsKKwkJZWxzZQorCQkJcmV0dXJuIFBUUl9FUlIocGh5KTsKKwl9CisKKwlyb290aHViX2VudHJ5 ID0gdXNiX3BoeV9yb290aHViX2FsbG9jKGRldik7CisJaWYgKElTX0VSUihyb290aHViX2VudHJ5 KSkKKwkJcmV0dXJuIFBUUl9FUlIocm9vdGh1Yl9lbnRyeSk7CisKKwlyb290aHViX2VudHJ5LT5w aHkgPSBwaHk7CisKKwlsaXN0X2FkZF90YWlsKCZyb290aHViX2VudHJ5LT5saXN0LCBsaXN0KTsK KworCXJldHVybiAwOworfQorCitzdHJ1Y3QgdXNiX3BoeV9yb290aHViICp1c2JfcGh5X3Jvb3Ro dWJfaW5pdChzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IHVzYl9waHlfcm9vdGh1YiAq cGh5X3Jvb3RodWI7CisJc3RydWN0IHVzYl9waHlfcm9vdGh1YiAqcm9vdGh1Yl9lbnRyeTsKKwlz dHJ1Y3QgbGlzdF9oZWFkICpoZWFkOworCWludCBpLCBudW1fcGh5cywgZXJyOworCisJbnVtX3Bo eXMgPSBvZl9jb3VudF9waGFuZGxlX3dpdGhfYXJncyhkZXYtPm9mX25vZGUsICJwaHlzIiwKKwkJ CQkJICAgICAgIiNwaHktY2VsbHMiKTsKKwlpZiAobnVtX3BoeXMgPD0gMCkKKwkJcmV0dXJuIE5V TEw7CisKKwlwaHlfcm9vdGh1YiA9IHVzYl9waHlfcm9vdGh1Yl9hbGxvYyhkZXYpOworCWlmIChJ U19FUlIocGh5X3Jvb3RodWIpKQorCQlyZXR1cm4gcGh5X3Jvb3RodWI7CisKKwlmb3IgKGkgPSAw OyBpIDwgbnVtX3BoeXM7IGkrKykgeworCQllcnIgPSB1c2JfcGh5X3Jvb3RodWJfYWRkX3BoeShk ZXYsIGksICZwaHlfcm9vdGh1Yi0+bGlzdCk7CisJCWlmIChlcnIpCisJCQlnb3RvIGVycl9vdXQ7 CisJfQorCisJaGVhZCA9ICZwaHlfcm9vdGh1Yi0+bGlzdDsKKworCWxpc3RfZm9yX2VhY2hfZW50 cnkocm9vdGh1Yl9lbnRyeSwgaGVhZCwgbGlzdCkgeworCQllcnIgPSBwaHlfaW5pdChyb290aHVi X2VudHJ5LT5waHkpOworCQlpZiAoZXJyKQorCQkJZ290byBlcnJfZXhpdF9waHlzOworCX0KKwor CXJldHVybiBwaHlfcm9vdGh1YjsKKworZXJyX2V4aXRfcGh5czoKKwlsaXN0X2Zvcl9lYWNoX2Vu dHJ5X2NvbnRpbnVlX3JldmVyc2Uocm9vdGh1Yl9lbnRyeSwgaGVhZCwgbGlzdCkKKwkJcGh5X2V4 aXQocm9vdGh1Yl9lbnRyeS0+cGh5KTsKKworZXJyX291dDoKKwlyZXR1cm4gRVJSX1BUUihlcnIp OworfQorRVhQT1JUX1NZTUJPTF9HUEwodXNiX3BoeV9yb290aHViX2luaXQpOworCitpbnQgdXNi X3BoeV9yb290aHViX2V4aXQoc3RydWN0IHVzYl9waHlfcm9vdGh1YiAqcGh5X3Jvb3RodWIpCit7 CisJc3RydWN0IHVzYl9waHlfcm9vdGh1YiAqcm9vdGh1Yl9lbnRyeTsKKwlzdHJ1Y3QgbGlzdF9o ZWFkICpoZWFkOworCWludCBlcnIsIHJldCA9IDA7CisKKwlpZiAoIXBoeV9yb290aHViKQorCQly ZXR1cm4gMDsKKworCWhlYWQgPSAmcGh5X3Jvb3RodWItPmxpc3Q7CisKKwlsaXN0X2Zvcl9lYWNo X2VudHJ5KHJvb3RodWJfZW50cnksIGhlYWQsIGxpc3QpIHsKKwkJZXJyID0gcGh5X2V4aXQocm9v dGh1Yl9lbnRyeS0+cGh5KTsKKwkJaWYgKGVycikKKwkJCXJldCA9IHJldDsKKwl9CisKKwlyZXR1 cm4gcmV0OworfQorRVhQT1JUX1NZTUJPTF9HUEwodXNiX3BoeV9yb290aHViX2V4aXQpOworCitp bnQgdXNiX3BoeV9yb290aHViX3Bvd2VyX29uKHN0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnBoeV9y b290aHViKQoreworCXN0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnJvb3RodWJfZW50cnk7CisJc3Ry dWN0IGxpc3RfaGVhZCAqaGVhZDsKKwlpbnQgZXJyOworCisJaWYgKCFwaHlfcm9vdGh1YikKKwkJ cmV0dXJuIDA7CisKKwloZWFkID0gJnBoeV9yb290aHViLT5saXN0OworCisJbGlzdF9mb3JfZWFj aF9lbnRyeShyb290aHViX2VudHJ5LCBoZWFkLCBsaXN0KSB7CisJCWVyciA9IHBoeV9wb3dlcl9v bihyb290aHViX2VudHJ5LT5waHkpOworCQlpZiAoZXJyKQorCQkJZ290byBlcnJfb3V0OworCX0K KworCXJldHVybiAwOworCitlcnJfb3V0OgorCWxpc3RfZm9yX2VhY2hfZW50cnlfY29udGludWVf cmV2ZXJzZShyb290aHViX2VudHJ5LCBoZWFkLCBsaXN0KQorCQlwaHlfcG93ZXJfb2ZmKHJvb3Ro dWJfZW50cnktPnBoeSk7CisKKwlyZXR1cm4gZXJyOworfQorRVhQT1JUX1NZTUJPTF9HUEwodXNi X3BoeV9yb290aHViX3Bvd2VyX29uKTsKKwordm9pZCB1c2JfcGh5X3Jvb3RodWJfcG93ZXJfb2Zm KHN0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnBoeV9yb290aHViKQoreworCXN0cnVjdCB1c2JfcGh5 X3Jvb3RodWIgKnJvb3RodWJfZW50cnk7CisKKwlpZiAoIXBoeV9yb290aHViKQorCQlyZXR1cm47 CisKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5X3JldmVyc2Uocm9vdGh1Yl9lbnRyeSwgJnBoeV9yb290 aHViLT5saXN0LCBsaXN0KQorCQlwaHlfcG93ZXJfb2ZmKHJvb3RodWJfZW50cnktPnBoeSk7Cit9 CitFWFBPUlRfU1lNQk9MX0dQTCh1c2JfcGh5X3Jvb3RodWJfcG93ZXJfb2ZmKTsKZGlmZiAtLWdp dCBhL2RyaXZlcnMvdXNiL2NvcmUvcGh5LmggYi9kcml2ZXJzL3VzYi9jb3JlL3BoeS5oCm5ldyBm aWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uNmZkZTU5YmZiZmY4Ci0tLSAvZGV2 L251bGwKKysrIGIvZHJpdmVycy91c2IvY29yZS9waHkuaApAQCAtMCwwICsxLDcgQEAKK3N0cnVj dCB1c2JfcGh5X3Jvb3RodWI7CisKK3N0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnVzYl9waHlfcm9v dGh1Yl9pbml0KHN0cnVjdCBkZXZpY2UgKmRldik7CitpbnQgdXNiX3BoeV9yb290aHViX2V4aXQo c3RydWN0IHVzYl9waHlfcm9vdGh1YiAqcGh5X3Jvb3RodWIpOworCitpbnQgdXNiX3BoeV9yb290 aHViX3Bvd2VyX29uKHN0cnVjdCB1c2JfcGh5X3Jvb3RodWIgKnBoeV9yb290aHViKTsKK3ZvaWQg dXNiX3BoeV9yb290aHViX3Bvd2VyX29mZihzdHJ1Y3QgdXNiX3BoeV9yb290aHViICpwaHlfcm9v dGh1Yik7Cg== From mboxrd@z Thu Jan 1 00:00:00 1970 From: martin.blumenstingl@googlemail.com (Martin Blumenstingl) Date: Sun, 11 Feb 2018 22:06:46 +0100 Subject: [PATCH usb-next v9 3/8] usb: core: add a wrapper for the USB PHYs on the HCD In-Reply-To: <20180211210651.2046-1-martin.blumenstingl@googlemail.com> References: <20180211210651.2046-1-martin.blumenstingl@googlemail.com> Message-ID: <20180211210651.2046-4-martin.blumenstingl@googlemail.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Many SoC platforms have separate devices for the USB PHY which are registered through the generic PHY framework. These PHYs have to be enabled to make the USB controller actually work. They also have to be disabled again on shutdown/suspend. Currently (at least) the following HCI platform drivers are using custom code to obtain all PHYs via devicetree for the roothub/controller and disable/enable them when required: - ehci-platform.c has ehci_platform_power_{on,off} - xhci-mtk.c has xhci_mtk_phy_{init,exit,power_on,power_off} - ohci-platform.c has ohci_platform_power_{on,off} With this new wrapper the USB PHYs can be specified directly in the USB controller's devicetree node (just like on the drivers listed above). This allows SoCs like the Amlogic Meson GXL family to operate correctly once this is wired up correctly. These SoCs use a dwc3 controller and require all USB PHYs to be initialized (if one of the USB PHYs it not initialized then none of USB port works at all). Signed-off-by: Martin Blumenstingl Tested-by: Yixun Lan Cc: Neil Armstrong Cc: Chunfeng Yun --- drivers/usb/core/Makefile | 2 +- drivers/usb/core/phy.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/phy.h | 7 ++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/core/phy.c create mode 100644 drivers/usb/core/phy.h diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 92c9cefb4317..18e874b0441e 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -6,7 +6,7 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o +usbcore-y += phy.o port.o usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c new file mode 100644 index 000000000000..09b7c43c0ea4 --- /dev/null +++ b/drivers/usb/core/phy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * A wrapper for multiple PHYs which passes all phy_* function calls to + * multiple (actual) PHY devices. This is comes handy when initializing + * all PHYs on a HCD and to keep them all in the same state. + * + * Copyright (C) 2018 Martin Blumenstingl + */ + +#include +#include +#include +#include + +#include "phy.h" + +struct usb_phy_roothub { + struct phy *phy; + struct list_head list; +}; + +static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) +{ + struct usb_phy_roothub *roothub_entry; + + roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); + if (!roothub_entry) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&roothub_entry->list); + + return roothub_entry; +} + +static int usb_phy_roothub_add_phy(struct device *dev, int index, + struct list_head *list) +{ + struct usb_phy_roothub *roothub_entry; + struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + + if (IS_ERR_OR_NULL(phy)) { + if (!phy || PTR_ERR(phy) == -ENODEV) + return 0; + else + return PTR_ERR(phy); + } + + roothub_entry = usb_phy_roothub_alloc(dev); + if (IS_ERR(roothub_entry)) + return PTR_ERR(roothub_entry); + + roothub_entry->phy = phy; + + list_add_tail(&roothub_entry->list, list); + + return 0; +} + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) +{ + struct usb_phy_roothub *phy_roothub; + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int i, num_phys, err; + + num_phys = of_count_phandle_with_args(dev->of_node, "phys", + "#phy-cells"); + if (num_phys <= 0) + return NULL; + + phy_roothub = usb_phy_roothub_alloc(dev); + if (IS_ERR(phy_roothub)) + return phy_roothub; + + for (i = 0; i < num_phys; i++) { + err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); + if (err) + goto err_out; + } + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_init(roothub_entry->phy); + if (err) + goto err_exit_phys; + } + + return phy_roothub; + +err_exit_phys: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_exit(roothub_entry->phy); + +err_out: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_init); + +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err, ret = 0; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_exit(roothub_entry->phy); + if (err) + ret = ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_power_on(roothub_entry->phy); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on); + +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + + if (!phy_roothub) + return; + + list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list) + phy_power_off(roothub_entry->phy); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h new file mode 100644 index 000000000000..6fde59bfbff8 --- /dev/null +++ b/drivers/usb/core/phy.h @@ -0,0 +1,7 @@ +struct usb_phy_roothub; + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev); +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); -- 2.16.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: martin.blumenstingl@googlemail.com (Martin Blumenstingl) Date: Sun, 11 Feb 2018 22:06:46 +0100 Subject: [PATCH usb-next v9 3/8] usb: core: add a wrapper for the USB PHYs on the HCD In-Reply-To: <20180211210651.2046-1-martin.blumenstingl@googlemail.com> References: <20180211210651.2046-1-martin.blumenstingl@googlemail.com> Message-ID: <20180211210651.2046-4-martin.blumenstingl@googlemail.com> To: linus-amlogic@lists.infradead.org List-Id: linus-amlogic.lists.infradead.org Many SoC platforms have separate devices for the USB PHY which are registered through the generic PHY framework. These PHYs have to be enabled to make the USB controller actually work. They also have to be disabled again on shutdown/suspend. Currently (at least) the following HCI platform drivers are using custom code to obtain all PHYs via devicetree for the roothub/controller and disable/enable them when required: - ehci-platform.c has ehci_platform_power_{on,off} - xhci-mtk.c has xhci_mtk_phy_{init,exit,power_on,power_off} - ohci-platform.c has ohci_platform_power_{on,off} With this new wrapper the USB PHYs can be specified directly in the USB controller's devicetree node (just like on the drivers listed above). This allows SoCs like the Amlogic Meson GXL family to operate correctly once this is wired up correctly. These SoCs use a dwc3 controller and require all USB PHYs to be initialized (if one of the USB PHYs it not initialized then none of USB port works at all). Signed-off-by: Martin Blumenstingl Tested-by: Yixun Lan Cc: Neil Armstrong Cc: Chunfeng Yun --- drivers/usb/core/Makefile | 2 +- drivers/usb/core/phy.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/phy.h | 7 ++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/core/phy.c create mode 100644 drivers/usb/core/phy.h diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 92c9cefb4317..18e874b0441e 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -6,7 +6,7 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o +usbcore-y += phy.o port.o usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c new file mode 100644 index 000000000000..09b7c43c0ea4 --- /dev/null +++ b/drivers/usb/core/phy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * A wrapper for multiple PHYs which passes all phy_* function calls to + * multiple (actual) PHY devices. This is comes handy when initializing + * all PHYs on a HCD and to keep them all in the same state. + * + * Copyright (C) 2018 Martin Blumenstingl + */ + +#include +#include +#include +#include + +#include "phy.h" + +struct usb_phy_roothub { + struct phy *phy; + struct list_head list; +}; + +static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) +{ + struct usb_phy_roothub *roothub_entry; + + roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); + if (!roothub_entry) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&roothub_entry->list); + + return roothub_entry; +} + +static int usb_phy_roothub_add_phy(struct device *dev, int index, + struct list_head *list) +{ + struct usb_phy_roothub *roothub_entry; + struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + + if (IS_ERR_OR_NULL(phy)) { + if (!phy || PTR_ERR(phy) == -ENODEV) + return 0; + else + return PTR_ERR(phy); + } + + roothub_entry = usb_phy_roothub_alloc(dev); + if (IS_ERR(roothub_entry)) + return PTR_ERR(roothub_entry); + + roothub_entry->phy = phy; + + list_add_tail(&roothub_entry->list, list); + + return 0; +} + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) +{ + struct usb_phy_roothub *phy_roothub; + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int i, num_phys, err; + + num_phys = of_count_phandle_with_args(dev->of_node, "phys", + "#phy-cells"); + if (num_phys <= 0) + return NULL; + + phy_roothub = usb_phy_roothub_alloc(dev); + if (IS_ERR(phy_roothub)) + return phy_roothub; + + for (i = 0; i < num_phys; i++) { + err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); + if (err) + goto err_out; + } + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_init(roothub_entry->phy); + if (err) + goto err_exit_phys; + } + + return phy_roothub; + +err_exit_phys: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_exit(roothub_entry->phy); + +err_out: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_init); + +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err, ret = 0; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_exit(roothub_entry->phy); + if (err) + ret = ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_power_on(roothub_entry->phy); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on); + +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + + if (!phy_roothub) + return; + + list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list) + phy_power_off(roothub_entry->phy); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h new file mode 100644 index 000000000000..6fde59bfbff8 --- /dev/null +++ b/drivers/usb/core/phy.h @@ -0,0 +1,7 @@ +struct usb_phy_roothub; + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev); +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); -- 2.16.1