From patchwork Thu Aug 20 06:28:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 7040791 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id B494EC05AC for ; Thu, 20 Aug 2015 06:28:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 686AA20519 for ; Thu, 20 Aug 2015 06:28:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ECE112053A for ; Thu, 20 Aug 2015 06:28:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751462AbbHTG2f (ORCPT ); Thu, 20 Aug 2015 02:28:35 -0400 Received: from relmlor3.renesas.com ([210.160.252.173]:21427 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751283AbbHTG2d (ORCPT ); Thu, 20 Aug 2015 02:28:33 -0400 Received: from unknown (HELO relmlir4.idc.renesas.com) ([10.200.68.154]) by relmlie2.idc.renesas.com with ESMTP; 20 Aug 2015 15:28:32 +0900 Received: from relmlac4.idc.renesas.com (relmlac4.idc.renesas.com [10.200.69.24]) by relmlir4.idc.renesas.com (Postfix) with ESMTP id 28AF74BC47; Thu, 20 Aug 2015 15:28:32 +0900 (JST) Received: by relmlac4.idc.renesas.com (Postfix, from userid 0) id 0B018480A4; Thu, 20 Aug 2015 15:28:31 +0900 (JST) Received: from relmlac4.idc.renesas.com (localhost [127.0.0.1]) by relmlac4.idc.renesas.com (Postfix) with ESMTP id EBC32480A3; Thu, 20 Aug 2015 15:28:31 +0900 (JST) Received: from relmlii2.idc.renesas.com [10.200.68.66] by relmlac4.idc.renesas.com with ESMTP id RAB17118; Thu, 20 Aug 2015 15:28:31 +0900 X-IronPort-AV: E=Sophos;i="5.15,713,1432566000"; d="scan'";a="193894437" Received: from mail-hk1lp0119.outbound.protection.outlook.com (HELO APAC01-HK1-obe.outbound.protection.outlook.com) ([207.46.51.119]) by relmlii2.idc.renesas.com with ESMTP/TLS/AES256-SHA; 20 Aug 2015 15:28:30 +0900 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=<>; Received: from localhost (211.11.155.144) by SG2PR06MB0919.apcprd06.prod.outlook.com (10.162.204.152) with Microsoft SMTP Server (TLS) id 15.1.231.21; Thu, 20 Aug 2015 06:28:28 +0000 From: Yoshihiro Shimoda To: , , , , , CC: , , , Yoshihiro Shimoda Subject: [PATCH] phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver Date: Thu, 20 Aug 2015 15:28:18 +0900 Message-ID: <1440052098-4840-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: OS2PR01CA0031.jpnprd01.prod.outlook.com (25.164.161.141) To SG2PR06MB0919.apcprd06.prod.outlook.com (25.162.204.152) X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0919; 2:pdngpe2q67pR/39xBlNiXsM+bAEPAcKff5Pzno5+7zMkhDEF72BmpAtPwbqLARDPa8GGpSS8SqHi67NoceRj/qbL7AgrkepwalIrYK6Um6D3NxRceXg2zUGCo+m3/hbHhQxjucx1JF10An3HQNAPoGTnfM9jsGTbDiVUKeLbtdo=; 3:n1FersBavRYzoH2hk3Noi0ObsRlDzzgikSOiuiD8OUj9yadkVhE9ZSYXBPQArOoR1cOqNf86hVrLhtW2ciWSceilVbgsYYYIiSVGfrJWZI0SnVPjeLCkDn87YsI1PmWRZk5VQEzgvulvyb2z4Rbubw==; 25:bXICCWxCrdlDz/Twvr4WA5dVi8uy1VHLW/fJlaJ61Jpjp0DSJBvr7miCLBaLqDEG4jXuwhgy0lIVOIrdT74vl3CXg/Feily2jmrvOUirYiZPhhG49SLi4KrfdlzEx/bJnf5O9Z7+rZuqgTD4frp9dSO2+Pm7xoqyskKTT/eG8ekjqOs3zYcfFySc3AjfWiBbM5zWoUeFQGtz/zGoIcUl8P/flY9jZ3fbG5hzivLMLxuRX6kezQQ2WtenKP+K/p9tGxXnlRqHmRGGv3usKdakoQ== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SG2PR06MB0919; X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0919; 20:HzGs/e02/A9Xv4MlDh7DiU5pW5fQBlTMwMygawVfehOC+woNamLQfzGBMsN9YgEfwrgNqqom8iYJNyFmtfIk6pxLVyurH8vZm6eN75Jth5vhL7bIp1qRSmrGmAhsnj6MHHmuSVA3J9c+U7NWA/jw1YOqCCc0u29D/j/sKZsRai1d0kIcKZ7tIKsYL4a7eb953PYNJ2UnB1sOwA81rQRu9Fz59xH7e8B1m9iTDUMS8kACM22JaYtOCf6+orqc6mQz9GmBWbjW7S+wM4NJl5IxnsdkRBy4V8/4/Gt8vmDo77JbYablr2Nk1tJydPCjfHc8a2pkSVdTx7pHE1Nas3cOOPe6gZxPz5kUV03B6Gmn+8dYLf+hRWCdLeeANjs2GO3AVA6BBAbOk0SNPEwKcJT6kRCfE9loeN9KKOay3DrTifiKpg7yQwPiDfUltN6U743O1JV9ZyJI5Q7FCT1bXdMNkqJN/uxaVMRCrsd4OqJmxmWQNhO7NgqrFC1ObPCbUy+4; 4:Y0Fd2OWEdLO9s3KBu/qVa9NEFIBKtAp18FF87WIIqbTkKUBvnHTUyvJgEakT+DtHXZLxG0O07cPSyZpR+nRi/U1QX+ZBTuhgIEd9jwjKS40f8JErNuCyT9wu6EBOQvS3jXg2wBXWS7grHfB1LYy+E5g23T49rERnI96YDVR9oepQyU4RhTYPVmhZNcCkfkGprxFdB8g1ZqdOOPbsOfZhX4u77Ay1xv44lxCj25ckJ2jRPt3d0RJqe2hc44HIBvZvaBGxQramE/4RJhtRouiFLpf5ARPnvkQtn4dZSLgFekBghmcwT5TdyJIzAguvVvTm 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:SG2PR06MB0919; BCL:0; PCL:0; RULEID:; SRVR:SG2PR06MB0919; X-Forefront-PRVS: 0674DC6DD3 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6069001)(6009001)(199003)(189002)(122386002)(77096005)(40100003)(76506005)(68736005)(62966003)(87976001)(46102003)(42186005)(77156002)(19580405001)(575784001)(42382002)(33646002)(230783001)(78352002)(105586002)(106356001)(50226001)(4001540100001)(92566002)(50986999)(48376002)(5001860100001)(64706001)(36756003)(5001830100001)(107886002)(19580395003)(229853001)(5001770100001)(47776003)(189998001)(5003940100001)(5001920100001)(5001960100002)(97736004)(101416001)(50466002)(5007970100001)(66066001)(81156007)(2004002)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:SG2PR06MB0919; H:localhost; FPR:; SPF:None; PTR:InfoNoRecords; A:0; MX:0; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SG2PR06MB0919; 23:ib01qfWT2vW2oQ1c73NoPhraZvxjts3Zv171xwMRe?= =?us-ascii?Q?SX5HtUfT5Tk27ZSMeGBOeT4DFtUnzqN0QkMGc5kMbZhLGNyObzVgIJvvusxb?= =?us-ascii?Q?hTeiEs+owRS/c+jJHT5pHhA53jpDO8yjiWTzzTJKULK0Jal8aBv+CO8+MRSB?= =?us-ascii?Q?XyvO/+xgZ+OJSFPRNf6PbLST0nrGeAzfLtyGlc3K+xIvBaRCC0Df8Q+OzICi?= =?us-ascii?Q?G288X7eDxXA+vmh2E4DBsT5YiDxozVcibCSwGtNv4c620VF/FWnDZHnpE7sl?= =?us-ascii?Q?wbBjkmwlejMhVLScnPcSEIu5OF6MiPeRosi48ennsb7DmBYWBkyBRPrvOtsK?= =?us-ascii?Q?3a9guw9xgoolStdHmbdSQMko4hCWk+Ed9LL+x3S8wI/7c2CYXUKw5oKGhxTy?= =?us-ascii?Q?yo8UZEcKtiNaDZ8i+zM2kzhc0tXoj3PK6sxPZFq1LUQ4Br3dgqcLWehv0Ao2?= =?us-ascii?Q?Rvkh+Nn/Pba896lIqasC+TO3heXTiS5rulq6e3/G5hkMw0HEfesfcaUe0GCJ?= =?us-ascii?Q?rzoQgTD1rfUwgwrqvWnBOaHvYHe21qxD/m+5p35jkGir+YtiJun1SOqXKm12?= =?us-ascii?Q?NIomUuG9Ebh7ldWbQ0ei4p+ojslkC5wnhVDePus4bz4MGy4uOI3nhYBBpE62?= =?us-ascii?Q?M2aU70VRktpx9GxYmmMTOYI/oIwt+cWvXMtsw+G3le0imMhByouud87/6vDG?= =?us-ascii?Q?kMmvbdgAg/olG+vJbs1PZdNyS0KJx0Ih1MjT/uEkZogNGsQTLImhwQT8kcOh?= =?us-ascii?Q?BnrdJAj1F0j7O0/BxpNn7/SZnPR6kyE8OnAGfUd5JMaLs4JCthzgmdc6fb0Y?= =?us-ascii?Q?A86f2kiMuF7J8gzXhiIVT+YX2zBCRDavgwS28ypxEiJ43Rzd9SRhjTWRwfxV?= =?us-ascii?Q?OrmYItseE/28oDR8KYx9UPRiqSPC3gpSZUTMjsinGaDyXCVS1NieSaUyCRjx?= =?us-ascii?Q?0Q8r/PKCND681tCnlA3gtfo2KIj/YKAmPOpT0IhCO9WRgV8dnSK6T/NWiCzm?= =?us-ascii?Q?PrmjoVHJ6rhTws9genE/LxeEfKGdIPb+0xfLYl24VNEqAAfRXqONrwpV0VNo?= =?us-ascii?Q?c+CYDAlJ1T2S7AGC7+vQkcSOaO1k3rFltPaS/G6LpSgekoWZpqLArzkv0j5f?= =?us-ascii?Q?gSIbJPMTAErkCLHihyJNKZNc2NV8x+MDo0mzx6/jqP6G++1aj8CAFx6dv0ko?= =?us-ascii?Q?Jz/0hO2lhAydjgU9TGnDa39x5oEW0yqTousKAa7SWIApWKrZljysgOFYZODa?= =?us-ascii?Q?tBlV475cOFIZ75zwyXpSwFd50lUj5MH1bN9dbkbwrUBSVKNFAU7Hz2p88jbg?= =?us-ascii?B?dz09?= X-Microsoft-Exchange-Diagnostics: 1; SG2PR06MB0919; 5:SyYDYwLLmbtjEjCmxIVjwh+MqVn82XtQq6iu98eXS6fRhuEcXlJoKcIjHmRw0eu4WcwlDg/DE3NRRpOe7WJ1Gs7CpHGBgmyvIk1CxzVFv+c7997rZ6N2S8F1j1NSofyB9hQYK3A2BxGVyzoQ0Mit/Q==; 24:u4jcUhQ1ieH//wp7xw0Nop5j/fi/+LTvgfac6KkdYS9aHLSvMibXIblfi3XvWyB+3nvGBihzYUXj/zFo0ZzCXNPFfzcdV0p/Q1bLP9a6Du0=; 20:h6hUOhhzW0w9As+s2Q12S4OgwItBtgtllBWLqKdX+sxQBC98VbV61FUJFo9TKbWNdGWLMe/lsE7WyN4Wqd4ngVBOt4J6MZP5HSvkAcqSvb4Jwn5N9mF3fjd3SE/3cGblk9BiEXgOJm1FHNlgZuKS3cSlyuBt2g19YHrPjbCn9ZQ= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Aug 2015 06:28:28.3707 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SG2PR06MB0919 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, 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 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 --- .../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 ");