From patchwork Fri Oct 23 18:28:08 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 7475811 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6EDEC9F36A for ; Fri, 23 Oct 2015 18:30:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6AF552041F for ; Fri, 23 Oct 2015 18:30:45 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5B5DC2041D for ; Fri, 23 Oct 2015 18:30:44 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zph5Z-0003c8-LZ; Fri, 23 Oct 2015 18:29:17 +0000 Received: from mail-pa0-x22a.google.com ([2607:f8b0:400e:c03::22a]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zph5C-0003M5-Cp for linux-arm-kernel@lists.infradead.org; Fri, 23 Oct 2015 18:28:57 +0000 Received: by pasz6 with SMTP id z6so124686336pas.2 for ; Fri, 23 Oct 2015 11:28:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tFY4E4S7LXaKRNuisOuEC+XLRzUNDADwGwcygEDWNCY=; b=aiO41tgppvMKFaEy6QXHVCdqHQKL/2iQX53a73ZwEuevzlDkMLUucj2V7R9yyaPZPI BGPVbTcmuprPqrEQNgtZQoMezeu5Pxl9Xjd81zgq783IkMVQmCNwBW3fp98KMitokxH9 yPtFvr8ZZcBf0W7OmxmpU0MtQ22Oz0Tyo46cQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tFY4E4S7LXaKRNuisOuEC+XLRzUNDADwGwcygEDWNCY=; b=Ht5dR7G5Bzjedug3jwzoESWLvQ+15r1g+szDMECevlJywzuc74pRnoYuC8wKq2d5fh viomClocv4TqQRFfhrvGM8fapM+Yl3FE+au9/OCGs/eiwxFpkQunJi3wtHxMJG9s+DMs mK4+PuFZZ0t3BcID8p8BHkjG28KRtAVJ0XCTx0Z7nCfAC2NEp+B4f5PKQPYvRHJ0eiSK In7SKcVwSq6fM6avqifdszydPhPQfd0hh7RhbAsWQFQCDIx+Xlf1jm+taevm7hPmHeg2 TjLyPvGE2640btL5bkK2xDbICRDP8qxjQ9qDohvAgA3J8/0ykbPH5UG7TDlmdeqtceap ic2Q== X-Gm-Message-State: ALoCoQlAjEbB8cY998jgU+GxoffFPa+zOY5cY7mH2Obn39sw0tBGlhZibpkO6nn9i/jVonG4Flbv X-Received: by 10.68.161.226 with SMTP id xv2mr6402989pbb.21.1445624913635; Fri, 23 Oct 2015 11:28:33 -0700 (PDT) Received: from tictac.mtv.corp.google.com ([172.22.65.76]) by smtp.gmail.com with ESMTPSA id qv5sm20175531pbc.71.2015.10.23.11.28.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 23 Oct 2015 11:28:33 -0700 (PDT) From: Douglas Anderson To: heiko@sntech.de, kishon@ti.com, johnyoun@synopsys.com, balbi@ti.com Subject: [PATCH 1/4] phy: rockchip-usb: Support the PHY's "port reset" Date: Fri, 23 Oct 2015 11:28:08 -0700 Message-Id: <1445624891-31680-2-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 2.6.0.rc2.230.g3dd15c0 In-Reply-To: <1445624891-31680-1-git-send-email-dianders@chromium.org> References: <1445624891-31680-1-git-send-email-dianders@chromium.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151023_112854_632607_7459C1FD X-CRM114-Status: GOOD ( 21.00 ) X-Spam-Score: -2.7 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, pawel.moll@arm.com, ijc+devicetree@hellion.org.uk, gregkh@linuxfoundation.org, Douglas Anderson , linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, robh+dt@kernel.org, lyz@rock-chips.com, galak@codeaurora.org, wulf@rock-chips.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We'd like to be able to expose the USB PHYs as reset providers. They can provide one reset that is named in the TRM as a "port reset". The name in the TRM is a bit confusing since there's a bit in dwc2's "hprt0" register that's also called "port reset" and this appears to reset something different, but it's still interesting to expose this one so we can actually use it. The TRM gives a little details about the reset that's in the PHY. It says this will "reset the port transmit and receive logic without disabling the clocks within the PHY." It goes on to say that the "transmit and receive finite state machines are reset and the line_state logic combinatorially reflects the state of the single-ended receivers." It's expected that will add code to dwc2 in a future patch that will let dwc2 access this reset. This reset seems to have the ability to unwedge the dwc2 "host" port when a remote wakeup happens. It may have other redeeming qualities as well. Signed-off-by: Douglas Anderson --- .../devicetree/bindings/phy/rockchip-usb-phy.txt | 6 ++ drivers/phy/phy-rockchip-usb.c | 74 ++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt index 826454a..746c035 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt @@ -21,6 +21,11 @@ required properties: Optional Properties: - clocks : phandle + clock specifier for the phy clocks - clock-names: string, clock name, must be "phyclk" +- #reset-cells: adding this property allows the phy to be + specified as a reset source. Asserting this reset will + assert the PHY's "port reset" bit. Always set reset-cells + to 0. Each PHY only has one reset to provide so no ID is + needed. Example: @@ -32,6 +37,7 @@ usbphy: phy { usbphy0: usb-phy0 { #phy-cells = <0>; + #reset-cells = <0>; reg = <0x320>; }; }; diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index 91d6f34..0e17677 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -36,11 +38,72 @@ #define SIDDQ_ON BIT(13) #define SIDDQ_OFF (0 << 13) +#define PORT_RESET_WRITE_ENA BIT(12 + 16) +#define PORT_RESET_ON BIT(12) +#define PORT_RESET_OFF (0 << 12) + struct rockchip_usb_phy { unsigned int reg_offset; struct regmap *reg_base; struct clk *clk; struct phy *phy; + struct reset_controller_dev rcdev; +}; + +static int rockchip_usb_phy_port_reset_on(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + struct rockchip_usb_phy *phy = + container_of(rcdev, struct rockchip_usb_phy, rcdev); + + ret = regmap_write(phy->reg_base, phy->reg_offset, + PORT_RESET_WRITE_ENA | PORT_RESET_ON); + + /* + * The TRM says nothing about how long we need to reset for, but + * it seems to work with very little delay. + */ + udelay(1); + + return ret; +} + +static int rockchip_usb_phy_port_reset_off(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + struct rockchip_usb_phy *phy = + container_of(rcdev, struct rockchip_usb_phy, rcdev); + + ret = regmap_write(phy->reg_base, phy->reg_offset, + PORT_RESET_WRITE_ENA | PORT_RESET_OFF); + + /* + * TRM says we should wait 11 PHYCLOCK cycles after deasserting reset + * but doesn't say what PHYCLOCK is. Even if it was as slow as 12MHz + * that would only be 917 ns though, so we'll delay 1us which should be + * total overkill but shouldn't hurt. + */ + udelay(1); + + return ret; +} + +static int rockchip_usb_phy_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) + return -EINVAL; + + return 0; +} + +static struct reset_control_ops rockchip_usb_phy_port_reset_ops = { + .assert = rockchip_usb_phy_port_reset_on, + .deassert = rockchip_usb_phy_port_reset_off, }; static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, @@ -135,6 +198,17 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev) err = rockchip_usb_phy_power(rk_phy, 1); if (err) return err; + + rk_phy->rcdev.owner = THIS_MODULE; + rk_phy->rcdev.nr_resets = 1; + rk_phy->rcdev.ops = &rockchip_usb_phy_port_reset_ops; + rk_phy->rcdev.of_node = child; + rk_phy->rcdev.of_xlate = rockchip_usb_phy_reset_xlate; + + err = reset_controller_register(&rk_phy->rcdev); + if (err) + dev_warn(dev, "Register reset failed (%d); skipping\n", + err); } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);