From patchwork Tue Aug 25 09:10:35 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 510413 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D18B21401F6 for ; Tue, 25 Aug 2015 19:11:18 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754122AbbHYJKw (ORCPT ); Tue, 25 Aug 2015 05:10:52 -0400 Received: from relmlor3.renesas.com ([210.160.252.173]:52066 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753753AbbHYJKp (ORCPT ); Tue, 25 Aug 2015 05:10:45 -0400 Received: from unknown (HELO relmlir1.idc.renesas.com) ([10.200.68.151]) by relmlie2.idc.renesas.com with ESMTP; 25 Aug 2015 18:10:42 +0900 Received: from relmlac1.idc.renesas.com (relmlac1.idc.renesas.com [10.200.69.21]) by relmlir1.idc.renesas.com (Postfix) with ESMTP id E495F605DC; Tue, 25 Aug 2015 18:10:42 +0900 (JST) Received: by relmlac1.idc.renesas.com (Postfix, from userid 0) id E54CE8002E; Tue, 25 Aug 2015 18:10:42 +0900 (JST) Received: from relmlac1.idc.renesas.com (localhost [127.0.0.1]) by relmlac1.idc.renesas.com (Postfix) with ESMTP id E02058002D; Tue, 25 Aug 2015 18:10:42 +0900 (JST) Received: from relmlii1.idc.renesas.com [10.200.68.65] by relmlac1.idc.renesas.com with ESMTP id UAF02631; Tue, 25 Aug 2015 18:10:42 +0900 X-IronPort-AV: E=Sophos;i="5.15,744,1432566000"; d="scan'";a="193047773" Received: from mail-hk2apc01lp0214.outbound.protection.outlook.com (HELO APC01-HK2-obe.outbound.protection.outlook.com) ([65.55.88.214]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA; 25 Aug 2015 18:10:41 +0900 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=<>; Received: from localhost (211.11.155.144) by SG2PR06MB0918.apcprd06.prod.outlook.com (10.162.201.158) with Microsoft SMTP Server (TLS) id 15.1.243.23; Tue, 25 Aug 2015 09:10:39 +0000 From: Yoshihiro Shimoda To: , , , , , CC: , , , Yoshihiro Shimoda Subject: [PATCH] phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver Date: Tue, 25 Aug 2015 18:10:35 +0900 Message-ID: <1440493835-6732-1-git-send-email-yoshihiro.shimoda.uh@renesas.com> X-Mailer: git-send-email 1.9.4.msysgit.1 MIME-Version: 1.0 X-Originating-IP: [211.11.155.144] X-ClientProxiedBy: TY1PR01CA0008.jpnprd01.prod.outlook.com (25.161.131.146) To SG2PR06MB0918.apcprd06.prod.outlook.com (25.162.201.158) X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0918; 2:icmtUJxWgoT7h+eT5Uf4E2551W8B5bVs54SW8pRteffKfkhfr2cgK6WpdFJsBD+FgfWgK46xsmC0H/Uy+caKWT+5FczC5E7mNGKxCcKQec8jg8nIGqUKNEmiSfEoF3fvyoZ/NjOMm6clMrB2DEu4koM7kZKMXhhQwe/jFRq3VAA=; 3:VkdcLFK2rxky1DytvXPwryE4yhlXRG5GJ1W9ZmCZxk4y0JcfYuPRX8O+wpl/gtHOMwKN+20HbQ6S0aj2DcOqoNpdzUAVVya31l2m/U9kkO4vvYdj2Lh9LGiB3DdN7Q0dWLimVCZ6RnmBpHbVbfuaVw==; 25:oJyeFaIzb0mCoSdu9FFUAthBRul3q/9toolLNTCmBhAic2C+ZoQN6WkYYYNcr+3DGTke1JY9LtNLhwlWdqRkfKV5NlCpU4d04Occlg57vFXlrllkNGslPPziShPnUvlR25DNxMcdHnbeUPU4Jmg7VV3cz+h3Z5znwHEPuEzfw3UezywWpbYsrv+M73gFTkrTgkbMXMfk4ApIJMriQSeijS8X2cyV+CUHKvfX4OanJ5jmJwTHxgHtJzRW0DNLxSjXQ/3TEbuZCB6ppC70uqCbsg== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SG2PR06MB0918; X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0918; 20:1bGCrozq8TaUSM3j4ckzMC5fg6xuLIWXH02zT7J5ixh2AEHX5lCbzn4yY57K/E6AJl7gGLCu4l2k/F3NicK4R07SuLK4QNgJTHChKyyir/wFxe+G/21znf3WIjN2EONORM1HrwqQGLENUKc6BRT4ner0A/FF3BbhXvtN+4kKoKo5OjRbRB7FrAZQsiDxe2CIuiTA4uy62nO6oiRErHCqoh3EsV7qQ2ys4lJuQyh+iK4OKKLO5R0h7dIFdp9W/cnGMmeMqcJmSbuJNgETqLzqIjLDcspV/ux9FeMmoBIeX8tvocn+uLZ4vXYwa5SbwGKT5RGbt4dotPVDq1oGPRMSeLc5bGqACUZqn2FPrR33DT9W+6sqi7whqGiW5QRRTvqnwFGLU0jG01jrMiMc7Q5W+qnMSvfsJM+L8GG025GStLbMOIDXE3mxG6Hj9YO47HOXoq9AY7m45UgYTpQW6sPMHNmYuQClWMOzj2APPYMkOfG4eZdcPt/M07wjfDeegsnx; 4:bE87ZA85xXL/d0ek4ceW9WfqEp/PqLWrWgP6BXiKHSwvUgB8W3rq4AdIh24noL8LgXDozWdjwK7MUEJFOmnoJw5VHqlltRAknVbSPeylr85J58F3d4BhwIxEQw5JPvinRZJRh4gTjSI36ai3LR619J0gqfJuGZlR4/B5DJ7DZBLyLKmKD7ksFNch0coA1TpFaXZP/e+Q5kCngFqr+Fmdwfecem3+hDXkFgycYFAWukQI6CaD6wkdP26FEdWdKoLBtaOK7GiAuJ0lO48eXFWl5H6Lz9CKNDpZhIGcDJ6Sc4gJ/VQwaESi0ZxmN6MZvC93 X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(8121501046)(5005006)(3002001); SRVR:SG2PR06MB0918; BCL:0; PCL:0; RULEID:; SRVR:SG2PR06MB0918; X-Forefront-PRVS: 06793E740F X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6069001)(6009001)(189002)(199003)(64706001)(36756003)(40100003)(50466002)(76506005)(33646002)(66066001)(122386002)(48376002)(107886002)(106356001)(50986999)(47776003)(5003940100001)(105586002)(5001960100002)(81156007)(5007970100001)(42186005)(5004730100002)(5001860100001)(87976001)(50226001)(42382002)(97736004)(5001770100001)(19580405001)(230783001)(78352002)(19580395003)(46102003)(229853001)(101416001)(68736005)(62966003)(189998001)(77156002)(92566002)(77096005)(575784001)(4001540100001)(5001830100001)(2004002)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:SG2PR06MB0918; H:localhost; FPR:; SPF:None; PTR:InfoNoRecords; MX:0; A:0; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SG2PR06MB0918; 23:lOL4U2KMGHHKZsw4F55CKzZxJHUOsTY+MwdecL2AY?= =?us-ascii?Q?0eKLEEa4wic57lhR4NqyJavZKGVThrkg2KBwL2iDlfMgI7GW2L5yGwlxr//0?= =?us-ascii?Q?zRNLhCroEmWhL+oPJcT5O/tIiALjHmXTdhvP8WpQQhJF+CJfPfEMSLH2dLcx?= =?us-ascii?Q?ywJ6EuLqHLPjnVn2zG0u0zQ5sm7YVyOaEbz4lpn3Rla0BV7BG448rCiykHWL?= =?us-ascii?Q?z1YXPjRpDHBo3E7R9G0p//Wmw2bqunfWwJWXOL7V4bxVszGVLAfRl2h50jXk?= =?us-ascii?Q?w6H/Pm33Kgrz0DAePxLxPvZeOiWrp5hWB2LBF9+Heg528uYa3ml+qimHttJR?= =?us-ascii?Q?JU2frkt4OmyGMuBC7d8V0PuYdzMfuXfD9CJqcg4Txf+NgGkjlQHnj6lNEPM6?= =?us-ascii?Q?xHJHFt/LXRGEOtCBpGrO0fkboPL0n7aF+oUyTeawMtsCMxCX5WtyKhm4oVoE?= =?us-ascii?Q?LGSCKMUrh7ZQR6DSudcg6cn42VURR1N24DzA2/A7LdGWVGHDG8KIth9ps5F7?= =?us-ascii?Q?Ti6cb4IF4vQyeEDb9VMzXP6LNck3S0gJ6LkLa+h0MehyrACRsnKQnVi3sYTY?= =?us-ascii?Q?+k8pgoCO9CY2hvShrZecadbCXuhObUgCt9sibrWIC6YV8KUHxpcm2gfIlbKt?= =?us-ascii?Q?JIbtxDoPDuTNnjG959EB1q5xJa0UYQIrHExNLw3ugQF61iBC64LxA9AjuUB9?= =?us-ascii?Q?SoVqNDVUuTeAvO6zktq4al6Xqu94NhJLd14PHslCev37nRotSXmYR9097WUJ?= =?us-ascii?Q?lUkgxk0jO3PhWbRGnof5h+6VkiUMeJHTK3RLf+49OPu+TZKvhX1PxufaD0y7?= =?us-ascii?Q?/S6Y/Zgm2/kNMHP9bpz1OjTZyZctNJHtOY8OC3rxdFzDURFBKWEpthn6c1Gx?= =?us-ascii?Q?ZL8/rB1Q18xylttkPBAcNrdsjGbSUSKbHNkqmG/DoBHz4UiJXKxWbu75OJ64?= =?us-ascii?Q?eoz3URCn9JcxUXxhD/mznGUpwar6rIhwSrYCjLtU5xza5TM9q7VYsqSEIp0r?= =?us-ascii?Q?B9PXEA2mN8kGRg9QZUyQUr/SAKMYgAuRA0RrYp9Q8EPe/QULa4e9W9UuQv0Z?= =?us-ascii?Q?rEuMuz3izk+ixyTwzd4n5wu2avbdrd5s0Us/gn9BMTl7NqnNcJeOZYfBWP8B?= =?us-ascii?Q?14Vfs1LaBwZnFHI5bJjJgpJ3bXShckc31E28ooJqpZOFFlG22cpzpvisA2he?= =?us-ascii?Q?STbU+npbq66N10luFdOIWaVUv27gjdzBXE4tuXrpLLR7oUE6Wr2PgoZ8zgAK?= =?us-ascii?Q?obzlntr9wmxcirxoU4P2kG3Vd1aj2YBoACSg5Ne+7f4UwlF2E5r7krO2mo1X?= =?us-ascii?B?Zz09?= X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0918; 5:VAR7z4z1DESN86ysrVUx1BQkEGFFzXyicEhAlwk1/b/0tM3sWQxCsumT5cwh1JSosodyk9jue2eIxOhxuvKVHPLVT8fCaJ5K/c18w9rIs1omg7MH/B4n5cRX3ozvUWC8/6mQo7wX+0azKfR3cK5HlQ==; 24:/nu8M0woUJuCwX9qeguj8rNSgwNUdAmWlq/79z1fFyJFCls2W6OGC8EfNfT9b5WiZs/hlaBf3UCtxVY6W7Z9zGzsnZmdafkdh+1b7v9Fydk=; 20:S1VrPuaTwzuQyv+Po4kOiGIwB0ekOFZGSzkYkPEy6U50sHz4vcDg+R+W0NB6XiOR2lwmXl2zcHLxdYYlFbXHujPpPQxP2gN8MOn4zHTXAEK1SOPWQjRFqb+yS55O2zFLHNso7cyGqzUw1D6+kB9SaktrGbDdoMA1K+DFtz485yI= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Aug 2015 09:10:39.5360 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SG2PR06MB0918 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This patch adds support for R-Car generation 3 USB2 PHY driver. This SoC has 3 EHCI/OHCI channels, and the channel 0 is shared with the HSUSB (USB2.0 peripheral) device. So, the purpose of this driver is: 1) initializes some registers of SoC specific to use the {ehci,ohci}-platform driver. 2) detects id pin to select host or peripheral on the channel 0. For now, this driver only supports 1) above. Signed-off-by: Yoshihiro Shimoda --- This patch is based on the latest linux-phy / next branch. (commit id = cfd093bbb5fe84ec8c7bb069fe618159a8b601f5) Changes from v1: - Revise some typos. - Remove using clk API to enable/disable the clocks. (In other words, this driver expects to enable/disable the clocks by Runtime PM API by the phy-core driver.) - Remove an unnecessary header file (asm/cmpxchg.h). .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 35 +++ drivers/phy/Kconfig | 6 + drivers/phy/Makefile | 1 + drivers/phy/phy-rcar-gen3-usb2.c | 240 +++++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt create mode 100644 drivers/phy/phy-rcar-gen3-usb2.c diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt new file mode 100644 index 0000000..1d57766 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -0,0 +1,35 @@ +* Renesas R-Car generation 3 USB 2.0 PHY + +This file provides information on what the device node for the R-Car generation +3 USB 2.0 PHY contains. + +Required properties: +- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 + SoC. +- reg: offset and length of the USB2.0 host register block. +- reg-names: must be "usb2". +- clocks: clock phandle and specifier pair(s). +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Optional properties: +To use a USB channel where EHCI/OHCI and HSUSB are combined, the device tree +node should set HSUSB properties to reg and reg-names properties: +- reg: offset and length of the HSUSB register block. +- reg-names: must be "hsusb". + +Example (R-Car H3): + + usb-phy@ee080200 { + compatible = "renesas,usb2-phy-r8a7795"; + reg = <0 0xee080200 0 0x6ff>, <0 0xe6590100 0 0x100>; + reg-names = "usb2", "hsusb"; + clocks = <&mstp7_clks R8A7795_CLK_EHCI0>, + <&mstp7_clks R8A7795_CLK_HSUSB>; + }; + + usb-phy@ee0a0200 { + compatible = "renesas,usb2-phy-r8a7795"; + reg = <0 0xee0a0200 0 0x6ff>; + reg-names = "usb2"; + clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; + }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 0fe9bff..406dc43 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -116,6 +116,12 @@ config PHY_RCAR_GEN2 help Support for USB PHY found on Renesas R-Car generation 2 SoCs. +config PHY_RCAR_GEN3_USB2 + tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" + depends on GENERIC_PHY + help + Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. + config OMAP_CONTROL_PHY tristate "OMAP CONTROL PHY Driver" depends on ARCH_OMAP2PLUS || COMPILE_TEST diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index a5b18c1..97e83bc 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o +obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c new file mode 100644 index 0000000..2c2fcf9 --- /dev/null +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -0,0 +1,240 @@ +/* + * Renesas R-Car Gen3 for USB2.0 PHY driver + * + * Copyright (C) 2015 Renesas Electronics Corporation + * + * This is based on the phy-rcar-gen2 driver: + * Copyright (C) 2014 Renesas Solutions Corp. + * Copyright (C) 2014 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +/******* USB2.0 Host registers (original offset is +0x200) *******/ +#define USB2_INT_ENABLE 0x000 +#define USB2_USBCTR 0x00c +#define USB2_SPD_RSM_TIMSET 0x10c +#define USB2_OC_TIMSET 0x110 + +/* INT_ENABLE */ +#define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) +#define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) +#define USB2_INT_ENABLE_INIT (USB2_INT_ENABLE_USBH_INTB_EN | \ + USB2_INT_ENABLE_USBH_INTA_EN) + +/* USBCTR */ +#define USB2_USBCTR_DIRPD BIT(2) +#define USB2_USBCTR_PLL_RST BIT(1) + +/* SPD_RSM_TIMSET */ +#define USB2_SPD_RSM_TIMSET_INIT 0x014e029b + +/* OC_TIMSET */ +#define USB2_OC_TIMSET_INIT 0x000209ab + +/******* HSUSB registers (original offset is +0x100) *******/ +#define HSUSB_LPSTS 0x02 +#define HSUSB_UGCTRL2 0x84 + +/* Low Power Status register (LPSTS) */ +#define HSUSB_LPSTS_SUSPM 0x4000 + +/* USB General control register 2 (UGCTRL2) */ +#define HSUSB_UGCTRL2_MASK 0x00000031 /* bit[31:6] should be 0 */ +#define HSUSB_UGCTRL2_USB0SEL 0x00000030 +#define HSUSB_UGCTRL2_USB0SEL_HOST 0x00000010 +#define HSUSB_UGCTRL2_USB0SEL_HS_USB 0x00000020 +#define HSUSB_UGCTRL2_USB0SEL_OTG 0x00000030 + +struct rcar_gen3_phy_usb2_data { + void __iomem *base; + struct clk *clk; +}; + +struct rcar_gen3_phy_usb2_channel { + struct rcar_gen3_phy_usb2_data usb2; + struct rcar_gen3_phy_usb2_data hsusb; + struct phy *phy; + spinlock_t lock; +}; + +static int rcar_gen3_phy_usb2_init(struct phy *p) +{ + struct rcar_gen3_phy_usb2_channel *channel = phy_get_drvdata(p); + unsigned long flags; + void __iomem *usb2_base = channel->usb2.base; + void __iomem *hsusb_base = channel->hsusb.base; + u32 tmp; + + spin_lock_irqsave(&channel->lock, flags); + + /* Initialize USB2 part */ + writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); + writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); + writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); + + /* Initialize HSUSB part */ + if (hsusb_base) { + /* TODO: support "OTG" mode */ + tmp = readl(hsusb_base + HSUSB_UGCTRL2); + tmp = (tmp & ~HSUSB_UGCTRL2_USB0SEL) | + HSUSB_UGCTRL2_USB0SEL_HOST; + writel(tmp & HSUSB_UGCTRL2_MASK, hsusb_base + HSUSB_UGCTRL2); + } + + spin_unlock_irqrestore(&channel->lock, flags); + + return 0; +} + +static int rcar_gen3_phy_usb2_exit(struct phy *p) +{ + struct rcar_gen3_phy_usb2_channel *channel = phy_get_drvdata(p); + + writel(0, channel->usb2.base + USB2_INT_ENABLE); + + return 0; +} + +static int rcar_gen3_phy_usb2_power_on(struct phy *p) +{ + struct rcar_gen3_phy_usb2_channel *channel = phy_get_drvdata(p); + void __iomem *usb2_base = channel->usb2.base; + void __iomem *hsusb_base = channel->hsusb.base; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&channel->lock, flags); + + tmp = readl(usb2_base + USB2_USBCTR); + tmp |= USB2_USBCTR_PLL_RST; + writel(tmp, usb2_base + USB2_USBCTR); + tmp &= ~USB2_USBCTR_PLL_RST; + writel(tmp, usb2_base + USB2_USBCTR); + + /* + * TODO: To reduce power consuming, this driver should set the SUSPM + * after the PHY detects ID pin as peripheral. + */ + if (hsusb_base) { + /* Power on HSUSB PHY */ + tmp = readw(hsusb_base + HSUSB_LPSTS); + tmp |= HSUSB_LPSTS_SUSPM; + writew(tmp, hsusb_base + HSUSB_LPSTS); + } + + spin_unlock_irqrestore(&channel->lock, flags); + + return 0; +} + +static int rcar_gen3_phy_usb2_power_off(struct phy *p) +{ + struct rcar_gen3_phy_usb2_channel *channel = phy_get_drvdata(p); + void __iomem *hsusb_base = channel->hsusb.base; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&channel->lock, flags); + + if (hsusb_base) { + /* Power off HSUSB PHY */ + tmp = readw(hsusb_base + HSUSB_LPSTS); + tmp &= ~HSUSB_LPSTS_SUSPM; + writew(tmp, hsusb_base + HSUSB_LPSTS); + } + + spin_unlock_irqrestore(&channel->lock, flags); + + return 0; +} + +static struct phy_ops rcar_gen3_phy_usb2_ops = { + .init = rcar_gen3_phy_usb2_init, + .exit = rcar_gen3_phy_usb2_exit, + .power_on = rcar_gen3_phy_usb2_power_on, + .power_off = rcar_gen3_phy_usb2_power_off, + .owner = THIS_MODULE, +}; + +static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { + { .compatible = "renesas,usb2-phy-r8a7795" }, + { } +}; +MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); + +static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rcar_gen3_phy_usb2_channel *channel; + struct phy_provider *provider; + struct resource *res; + + if (!dev->of_node) { + dev_err(dev, "This driver needs device tree\n"); + return -EINVAL; + } + + channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + spin_lock_init(&channel->lock); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2"); + channel->usb2.base = devm_ioremap_resource(dev, res); + if (IS_ERR(channel->usb2.base)) + return PTR_ERR(channel->usb2.base); + + /* "hsusb" memory resource is optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsusb"); + + /* To avoid error message by devm_ioremap_resource() */ + if (res) { + channel->hsusb.base = devm_ioremap_resource(dev, res); + if (IS_ERR(channel->hsusb.base)) + channel->hsusb.base = NULL; + } + + /* devm_phy_create() will call pm_runtime_enable(dev); */ + channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops); + if (IS_ERR(channel->phy)) { + dev_err(dev, "Failed to create USB2 PHY\n"); + return PTR_ERR(channel->phy); + } + + phy_set_drvdata(channel->phy, channel); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "Failed to register PHY provider\n"); + return PTR_ERR(provider); + } + + dev_set_drvdata(dev, channel); + + return 0; +} + +static struct platform_driver rcar_gen3_phy_usb2_driver = { + .driver = { + .name = "phy_rcar_gen3_usb2", + .of_match_table = rcar_gen3_phy_usb2_match_table, + }, + .probe = rcar_gen3_phy_usb2_probe, +}; +module_platform_driver(rcar_gen3_phy_usb2_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY"); +MODULE_AUTHOR("Yoshihiro Shimoda ");