diff mbox

phy: rcar-gen3-usb2: Add R-Car Gen3 USB2 PHY driver

Message ID 1440493835-6732-1-git-send-email-yoshihiro.shimoda.uh@renesas.com
State Superseded, archived
Headers show

Commit Message

Yoshihiro Shimoda Aug. 25, 2015, 9:10 a.m. UTC
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 <yoshihiro.shimoda.uh@renesas.com>
---
 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

Comments

Yoshihiro Shimoda Sept. 18, 2015, 4:29 a.m. UTC | #1
Hi Kishon,

> Sent: Tuesday, August 25, 2015 6:11 PM
> 
> 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 <yoshihiro.shimoda.uh@renesas.com>
> ---
>  This patch is based on the latest linux-phy / next branch.
>  (commit id = cfd093bbb5fe84ec8c7bb069fe618159a8b601f5)

Would you review this patch? Since the latest linux-phy.git / next branch
is the same as the above id, this patch can be applied on the repository, I think.

Best regards,
Yoshihiro Shimoda

>  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 <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +
> +/******* 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 <yoshihiro.shimoda.uh@renesas.com>");
> --
> 1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I Sept. 18, 2015, 6:08 a.m. UTC | #2
Hi,

On Tuesday 25 August 2015 02:40 PM, Yoshihiro Shimoda wrote:
> 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.

>From the description it looks like it's a single PHY with multiple
channels. In that case you should have a singe dt node for the PHY
provider and each channel should be modelled as the child node of the
PHY provider dt node.
> 
> 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 <yoshihiro.shimoda.uh@renesas.com>
> ---
>  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";

hsusb is missing in Documentation.
> +		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

depends on OF?

Thanks
Kishon
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring (Arm) Sept. 21, 2015, 2:01 p.m. UTC | #3
On 09/18/2015 01:08 AM, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Tuesday 25 August 2015 02:40 PM, Yoshihiro Shimoda wrote:
>> 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.
> 
> From the description it looks like it's a single PHY with multiple
> channels. In that case you should have a singe dt node for the PHY
> provider and each channel should be modelled as the child node of the
> PHY provider dt node.

You only need sub-nodes if you need per channel properties. Otherwise,
#phy-cells can be 1 and the cell value can be the channel number.

>>
>> 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 <yoshihiro.shimoda.uh@renesas.com>
>> ---
>>  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.

host register block? You mean phy 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";
> 
> hsusb is missing in Documentation.

usb2 is the host controller? It is questionable that these should be
combined. Does this appear under another node? If so, don't overlap
resources in the DT.

>> +		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
> 
> depends on OF?
> 
> Thanks
> Kishon
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yoshihiro Shimoda Sept. 25, 2015, 12:41 p.m. UTC | #4
Hi Kishon,

Thank you for the review!
And I'm sorry for the delayed response.

> Sent: Friday, September 18, 2015 3:08 PM
> 
> Hi,
> 
> On Tuesday 25 August 2015 02:40 PM, Yoshihiro Shimoda wrote:
> > 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.
> 
> From the description it looks like it's a single PHY with multiple
> channels. In that case you should have a singe dt node for the PHY
> provider and each channel should be modelled as the child node of the
> PHY provider dt node.

Sorry for my lack information.
As my understanding, each EHCI/OHCI channel has a PHY because the following
things are differnce:
 - Memory map
  - ch0 = 0xee080000
  - ch1 = 0xee0a0000
  - ch2 = 0xee0c0000

 - Clock ("module stop")
  - Each channel has a specific clock ("module stop bit").

< snip >
> > --- /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";
> 
> hsusb is missing in Documentation.

I wrote the "hsusb" as Optional properties in the Documentation.
Or, Is my understanding about your comment wrong?

< snip >
> > 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
> 
> depends on OF?

Thank you for the point. I will fix it.

Best regards,
Yoshihiro Shimoda

> Thanks
> Kishon
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yoshihiro Shimoda Sept. 25, 2015, 12:42 p.m. UTC | #5
Hi Rob,

Thank you for your comment!
And, I'm sorry for the delayed response.

> Sent: Monday, September 21, 2015 11:01 PM
> 
> On 09/18/2015 01:08 AM, Kishon Vijay Abraham I wrote:
> > Hi,
> >
> > On Tuesday 25 August 2015 02:40 PM, Yoshihiro Shimoda wrote:
> >> 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.
> >
> > From the description it looks like it's a single PHY with multiple
> > channels. In that case you should have a singe dt node for the PHY
> > provider and each channel should be modelled as the child node of the
> > PHY provider dt node.
> 
> You only need sub-nodes if you need per channel properties. Otherwise,
> #phy-cells can be 1 and the cell value can be the channel number.

Thank you for the information. I got it.

< snip >
> >> 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.
> 
> host register block? You mean phy register block?

Oops, thank you for the point. I will fix it.

> >> +- 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";
> >
> > hsusb is missing in Documentation.
> 
> usb2 is the host controller? It is questionable that these should be
> combined. Does this appear under another node? If so, don't overlap
> resources in the DT.

Thank you for the point.
I don't think that this appears under another node.
However, to avoid such a situation, I should change the name somehow.

Best regards,
Yoshihiro Shimoda

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yoshihiro Shimoda Oct. 1, 2015, 10:01 a.m. UTC | #6
Hi Rob,

> Sent: Friday, September 25, 2015 9:42 PM
> 
> Hi Rob,
> 
> Thank you for your comment!
> And, I'm sorry for the delayed response.
> 
> > Sent: Monday, September 21, 2015 11:01 PM
> >
> > On 09/18/2015 01:08 AM, Kishon Vijay Abraham I wrote:
< snip >
> > >> +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";
> > >
> > > hsusb is missing in Documentation.
> >
> > usb2 is the host controller? It is questionable that these should be
> > combined. Does this appear under another node? If so, don't overlap
> > resources in the DT.
> 
> Thank you for the point.
> I don't think that this appears under another node.
> However, to avoid such a situation, I should change the name somehow.

Perhaps I misunderstood your point. So, let me comment below again:

- This "usb2" means the partial registers of USB 2.0 host block.
  That host registers can control the USB2.0 PHY.
  This "hsusb" means the partial registers of USB 2.0 peripheral block.
  That peripheral registers can control the selector (host or peripheral).
  So, these should be combined in this driver.

- These resources don't appear under another nodes.

Best regards,
Yoshihiro Shimoda

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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 <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+/******* 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 <yoshihiro.shimoda.uh@renesas.com>");