From patchwork Mon Aug 24 02:27:01 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 7059751 Return-Path: X-Original-To: patchwork-linux-sh@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 147E79F344 for ; Mon, 24 Aug 2015 02:27:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6D31F206A5 for ; Mon, 24 Aug 2015 02:27:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 02AE1206A1 for ; Mon, 24 Aug 2015 02:27:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753536AbbHXC1Y (ORCPT ); Sun, 23 Aug 2015 22:27:24 -0400 Received: from relmlor2.renesas.com ([210.160.252.172]:22417 "EHLO relmlie1.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751303AbbHXC1X (ORCPT ); Sun, 23 Aug 2015 22:27:23 -0400 Received: from unknown (HELO relmlir3.idc.renesas.com) ([10.200.68.153]) by relmlie1.idc.renesas.com with ESMTP; 24 Aug 2015 11:27:22 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir3.idc.renesas.com (Postfix) with ESMTP id 5557C460AC; Mon, 24 Aug 2015 11:27:22 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 4B3EE2806E; Mon, 24 Aug 2015 11:27:22 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 457482806D; Mon, 24 Aug 2015 11:27:22 +0900 (JST) Received: from relmlii2.idc.renesas.com [10.200.68.66] by relmlac2.idc.renesas.com with ESMTP id MAF18533; Mon, 24 Aug 2015 11:27:22 +0900 X-IronPort-AV: E=Sophos;i="5.15,735,1432566000"; d="scan'";a="194128659" Received: from mail-sg2apc01lp0245.outbound.protection.outlook.com (HELO APC01-SG2-obe.outbound.protection.outlook.com) ([65.55.88.245]) by relmlii2.idc.renesas.com with ESMTP/TLS/AES256-SHA; 24 Aug 2015 11:27:21 +0900 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=kuninori.morimoto.gx@renesas.com; Received: from morimoto-PC.renesas.com (211.11.155.144) by SIXPR06MB0606.apcprd06.prod.outlook.com (10.160.237.148) with Microsoft SMTP Server (TLS) id 15.1.243.23; Mon, 24 Aug 2015 02:27:01 +0000 Message-ID: <87lhd177ce.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH 05/25 v7][RFC] phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver User-Agent: Wanderlust/2.15.9 Emacs/24.3 Mule/6.0 MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") To: Simon CC: Magnus , , YOSHIYUKI ITO , Hisao Munakata , Yusuke Goda , Yoshihiro Shimoda , TOSHIAKI KOMATSU , Gaku Inami In-Reply-To: <87si7977g4.wl%kuninori.morimoto.gx@renesas.com> References: <87si7977g4.wl%kuninori.morimoto.gx@renesas.com> Date: Mon, 24 Aug 2015 02:27:01 +0000 X-Originating-IP: [211.11.155.144] X-ClientProxiedBy: TY1PR01CA0017.jpnprd01.prod.outlook.com (25.161.131.155) To SIXPR06MB0606.apcprd06.prod.outlook.com (25.160.237.148) X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0606; 2:7L+xCRvcq+ePGL3iaOX3Cz8yDdl6v7JSUYj2pNw6SMCLe8C/kcmJvPPxDvXjlQJIgiaiejlpWUUPoY5ljx1JXtiG63m4jdNXJQGfVaVfVYb0kL/mcv8yK3FbPpX275Ha+tgiTbawkqVxRDv2YhqBFpSGMC3glRi091jzALenunc=; 3:K5gsrbyclkLcosAZEA9I6wTg3EU+1ksd0p+eJM0bEDu0yyDSYYjyzZhsAjfbaGUHOgkO1PKfckQsdp+JVr1vYTeE074MftVX9bTV4MPf1Pm2lyUWZuH70VFXPzHIafU5DPNulIX0SiOSMQQ9TQnN2A==; 25:kwruOKs5Udr/8Ho4NWgadA3qvjAKCrSw5TkK1IHUKFAKQqWhVqVKeEwi/5oyNzdSTgWL9KdMIga1ei7orD0r3PlHwmHtPtrydiL0+TJ1o2U551vSJfPkLpwp5o+0YmfvbjD0z+5IhyiHDDPJaCHzPHvcscLXhlUqdco/NTHFSc+4mph/iGkfXB+BRW12Osy9C4MdRQw5cON2jDnTYo5SIogPPGUdnX9OPl7Pjj2qZJo9Hedr7ed2mq784E7fT6s4dPyFG4PkQel+QmUlBN1lbw== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SIXPR06MB0606; X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0606; 20:9joIYzGGkr+BeTLFWDUjpK2wpNje8gxlsg/mIUVG+BwLO4gSFG2tD1MUeL5lm7/kTTLJ2GqGR+db+n0rxQYjGDAkr4E8YEr5KYwW6oAa6gu/uiFFWivoOfbwHX9ZBjXJuBVOHqOdUG0hs9HupwuF4XbCzP50gachBi5GgjZx9+x4RRAQOpsNCOT1aH4VuKLjuHg28xgCUQLzzYVPNRyajvp3cy0HkbkjBGu/r/O2ddwoae/rDOSXQWEOnR1x0kruZVZnez1g0Jol6bK9kSTgeHwAGdcmCDnp6LQnz5jsIadVZ0mSg4mldtjeh+6Zhc+knUH4R/HvpK1lxzSbNgnVmgWkBhNEGXyzN9Y42R81j1AlYO3UR3y41aetIGpJgloKHy/DFmfotoa6KPF7LT8r3GhYKZjxxMrT/TbT7Wp+kPmqwxD17NUhiu4lQHyKZlr6DX8qxk8zmufD2YjbGwejkyF/gubhpmPvge/x3qCkpBDxeBDfj1A7+5QTn36nQSV4; 4:LXsX4u3O4rfEH0TQzS9nRCUIj6rIFKgDI5WrMhOWbawT6W8JFB/GhO3tnrhlK6cAbbW1JJFAwieM+NSJkznYiLtyraCK69WFWKJO1nNELGvYTm+35BnbYD2YUFc2tvO+Ve/GdO4xv8ipXPlp6DJaEomYbXLp2HSdqz8zC/OjVE7di+atsmdN5rkb6BJ1puoduRCXHVxqs4HcD8kawnh+2I71Y9nHd9q1/qoqeDzf1+/MyhJju/qAWdIZGqJbLltn/vVZ2Whn/WGJsmKBEe+7+qTpbi/t1oLlNX5DWzFS4edu5iMJBl95mQuE3AHUf/km X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(8121501046)(3002001); SRVR:SIXPR06MB0606; BCL:0; PCL:0; RULEID:; SRVR:SIXPR06MB0606; X-Forefront-PRVS: 06780E24F8 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(979002)(6009001)(199003)(189002)(107886002)(5007970100001)(2950100001)(40100003)(19580395003)(50466002)(122386002)(5004730100002)(69596002)(53416004)(36756003)(87976001)(46102003)(19580405001)(230783001)(106356001)(575784001)(5001960100002)(105586002)(81156007)(86362001)(110136002)(4001350100001)(189998001)(42186005)(4001540100001)(229853001)(64706001)(23726002)(77156002)(5001860100001)(54356999)(5001830100001)(47776003)(83506001)(97736004)(76176999)(101416001)(77096005)(62966003)(66066001)(33646002)(46406003)(92566002)(68736005)(50986999)(2004002)(4001430100001)(969003)(989001)(999001)(1009001)(1019001); DIR:OUT; SFP:1102; SCL:1; SRVR:SIXPR06MB0606; H:morimoto-PC.renesas.com; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SIXPR06MB0606; 23:Yove0khTwVSsDNWeSX+qFQhy7HFs0AgW1OojL3ehi?= =?us-ascii?Q?/INvfWlR4ZVVmEC01iOxjwuTsX6Y44gKfMgoySjhb04PNoGLDXndwl8NZOvx?= =?us-ascii?Q?GnMKAkG4Kk7nrWgjCfX5hd5a1L6ANoAd69XQ887nj0u8mbAlWMpfpTZAEn5x?= =?us-ascii?Q?Rgm+2V1X+pbZwTbGmmYWQSqo+hzyPcRtM6l6JZywtmcPDaesZDz20U6OpB0d?= =?us-ascii?Q?m/1ykNr36RlS5zbK3JimNbR5tTWeAo3WzId8OBgBx6lySCCJTxNaQOV6m4MV?= =?us-ascii?Q?cG3cd3qEO3+0aJspgiXEWngRo8s+2gNR6P5whZP1Lhu6p9uImIaRHVG+sKMB?= =?us-ascii?Q?SD8uh2AQMIrYlLsXyvK/VgePjOc9h+osFPFUku9FzWDcL2tuciz6sYE+688A?= =?us-ascii?Q?oPout9dz9fdVI8l7HS7KzkJajYLKNRRsLGaT461v+rxg4eibq6rdkygN9758?= =?us-ascii?Q?7XpKuf8GXoq/e+l8rYxhYIWJHABqFg90D63ESE0pM3g4lz1Fo7l2fGPZUT6d?= =?us-ascii?Q?LwIEbHCwV+4RTU7PtXG12MH7Cw7E1n6FIrb3K5R4TR7Dll3e0RYEm3Y/5Spo?= =?us-ascii?Q?JDge/b9xb+tPVy3rPxploWhC7omAJucFC6A0vw03L6pCcbbqJ6v0Xk7+fz9D?= =?us-ascii?Q?EGw0DPsxB7Rah35y2ciR1/wP90+3ravNV0CZmPJn/jPMTsrvwvCeuSZ3Ns/2?= =?us-ascii?Q?UzWR1xqNai5dP+gQEitDCdD8gVxL+gUKHNahxDvi+HsqtTegozChATWRh4rQ?= =?us-ascii?Q?R+BUIMytP96uRw2k9WzMqXi+413jC5jL8MmwP5D92eb0h2ro8O67eu9v79uy?= =?us-ascii?Q?EWJFnfptNbS6DXrP6BUQb5EvjFLK5bryFCxj+qW69zJ6Z9FeYiiILBM0wUAh?= =?us-ascii?Q?lKxZB3TJDoN6t6S+CahTDLoKv0/9DObYJHt0sBlwe80RSuHkDwssEf+LQM2o?= =?us-ascii?Q?YAaGIIE0w7IMKWz9pyfh/AcDTT5ffTsx9iHKoV71b4hSXZfGiv7dCgXEn0LR?= =?us-ascii?Q?xitTbrdEuvR33h1sdGUKjnOfeYyIggWkOoLirUef5lRql5Zs6qxavzgGexyC?= =?us-ascii?Q?ZewZAMezAbD0KQwuM3ZlWKalEahXhlLWQVQwHEe01O70COtCdMFNx32cZFSW?= =?us-ascii?Q?T2G3WIowunADJVztATk1Y61gQARFu3s1jAGU/12+MmMv2lWdPyD+esvR5QSL?= =?us-ascii?Q?3oP3itYeTGJ1u6e4v9XB7mTzwiV5AlyjFDuKwBPRJHAUfhwlJE8MShPJLRWo?= =?us-ascii?Q?NuBhfuU1TxbeHhyZRcdDDa9vWuruusrLG/65k67K1IHJu8dGwwZLeTQqElMz?= =?us-ascii?Q?iBgt0U+CKoc2g53fl+d+r0AgEw4oCpZTjYNrW+6Y/KxYDsQKp+Qu51W/2xk2?= =?us-ascii?Q?aW4adtg4G4op/IBSUrBwJ4dJwPNyDlnBF/WrqMax4TLshWRQreXZBV0BKPDf?= =?us-ascii?Q?dzfTus21JEX1vlY5+iCmiEAddbondwDO57cYuqz8D8EbuUL3kvN?= X-Microsoft-Exchange-Diagnostics: 1; SIXPR06MB0606; 5:vJ5Jj1ups1wMoYhvKc7uSVixAjhmkDUhjuyv8+2p+3zUADboRlDkU081LR7QYcPD6V063Oba8w4WUB7sNvlGM094fJeC0TV22sO3d5wtDDPLn0+cGFD4/qO7149wNmRNQSZaODzqK5gIe21Ve9v5OA==; 24:WzD/qbwNEeCbGfnws+9kb3afHHFNS73adfBhJ64XMhXLrKq8vczoVo+jNntEDc9zTvzpJVi7g4+MUkbyRsBDAHPo99WvHtyv0ocTJUDFfaA=; 20:ovdvuyj6gFqXDgcc1aQxIsLJXwvoAvil1gzfvt5udyw9p7MDSazCzPc+GReZ9+33hdCELdxbByOK16KKSnbdkuzwmmh6ZxYsFZihebOiINhr9EaGVh7rYoVagu0Ixx6vsM4mBlMIaYpo2hWbmdzQz/J0hZ2ifdjbXCfa+v91Iv0= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Aug 2015 02:27:01.7437 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SIXPR06MB0606 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 From: Yoshihiro Shimoda 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 Signed-off-by: Kuninori Morimoto --- v5 -> v7 - based on v7 Gen3 SoC patch set .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 37 +++ drivers/phy/Kconfig | 6 + drivers/phy/Makefile | 1 + drivers/phy/phy-rcar-gen3-usb2.c | 262 +++++++++++++++++++++ 4 files changed, 306 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..1e8437f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -0,0 +1,37 @@ +* 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 R8A7795 SoC. +- reg: offset and length of the USB2.0 host register block. +- reg-names: must be "usb2". +- clocks: clock phandle and specifier pair. +- clock-names: string, clock input name, must be "usb2", and optional "hsusb". +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Optional proparies: +To use a USB channel which EHCI/OHCI and HSUSB are combined, the device tree +node should set HSUSB proparies to reg and reg-names proparies: +- 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>; + clock-names = "usb2", "hsusb"; + }; + + usb-phy@ee0a0200 { + compatible = "renesas,usb2-phy-r8a7795"; + reg = <0 0xee0a0200 0 0x6ff>; + reg-names = "usb2"; + clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; + clock-names = "usb2"; + }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 47da573..ee300fa 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -118,6 +118,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..e319eaf --- /dev/null +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -0,0 +1,262 @@ +/* + * 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 +#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; + + /* Since ops->init() is called once, this driver enables both clocks */ + clk_prepare_enable(channel->usb2.clk); + clk_prepare_enable(channel->hsusb.clk); + + 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); + + clk_disable_unprepare(channel->hsusb.clk); + clk_disable_unprepare(channel->usb2.clk); + + 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 peripherai. + */ + 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); + + channel->usb2.clk = devm_clk_get(dev, "usb2"); + if (IS_ERR(channel->usb2.clk)) { + dev_err(dev, "Can't get USB2 clock\n"); + return PTR_ERR(channel->usb2.clk); + } + + 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.clk = devm_clk_get(dev, "hsusb"); + if (IS_ERR(channel->hsusb.clk)) { + dev_err(dev, "Can't get HSUSB clock\n"); + return PTR_ERR(channel->hsusb.clk); + } + } else { + channel->hsusb.base = NULL; + } + } + + 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 ");