Selaa lähdekoodia

Merge tag 'renesas-phy-rcar-usb-for-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas into next/soc

From Simon Horman:
Renesas USB updates for v3.11

These updates are by Sergei Shtylyov to clean-up USB support
present for R8A7779/Marzen and then extend USB support coverage to
R8A7778/BOCK-W.

* tag 'renesas-phy-rcar-usb-for-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas:
  ARM: shmobile: BOCK-W: add USB support
  ARM: shmobile: r8a7778: add USB support
  phy-rcar-usb: add R8A7778 support
  phy-rcar-usb: handle platform data
  ARM: shmobile: Marzen: pass platform data to USB PHY device
  phy-rcar-usb: add platform data
  phy-rcar-usb: correct base address
  ARM: shmobile: r8a7779: remove USB PHY 2nd memory resource
  phy-rcar-usb: remove EHCI internal buffer setup
  ARM: shmobile: r8a7779: setup EHCI internal buffer
  ehci-platform: add pre_setup() method to platform data
  ARM: shmobile: Marzen: move USB EHCI, OHCI, and PHY devices to R8A7779 code

Conflicts:
	arch/arm/mach-shmobile/board-marzen.c
	arch/arm/mach-shmobile/setup-r8a7778.c

Signed-off-by: Olof Johansson <olof@lixom.net>
Olof Johansson 12 vuotta sitten
vanhempi
commit
a114926964

+ 2 - 0
arch/arm/mach-shmobile/Kconfig

@@ -41,6 +41,8 @@ config ARCH_R8A7778
 	select CPU_V7
 	select SH_CLK_CPG
 	select ARM_GIC
+	select USB_ARCH_HAS_EHCI
+	select USB_ARCH_HAS_OHCI
 
 config ARCH_R8A7779
 	bool "R-Car H1 (R8A77790)"

+ 8 - 0
arch/arm/mach-shmobile/board-bockw.c

@@ -38,12 +38,18 @@ static struct resource smsc911x_resources[] = {
 	DEFINE_RES_IRQ(irq_pin(0)), /* IRQ 0 */
 };
 
+static struct rcar_phy_platform_data usb_phy_platform_data __initdata;
+
 static const struct pinctrl_map bockw_pinctrl_map[] = {
 	/* SCIF0 */
 	PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
 				  "scif0_data_a", "scif0"),
 	PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
 				  "scif0_ctrl", "scif0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("ehci-platform", "pfc-r8a7778",
+				  "usb0", "usb0"),
+	PIN_MAP_MUX_GROUP_DEFAULT("ehci-platform", "pfc-r8a7778",
+				  "usb1", "usb1"),
 };
 
 #define IRQ0MR	0x30
@@ -54,6 +60,7 @@ static void __init bockw_init(void)
 	r8a7778_clock_init();
 	r8a7778_init_irq_extpin(1);
 	r8a7778_add_standard_devices();
+	r8a7778_add_usb_phy_device(&usb_phy_platform_data);
 
 	pinctrl_register_mappings(bockw_pinctrl_map,
 				  ARRAY_SIZE(bockw_pinctrl_map));
@@ -91,4 +98,5 @@ DT_MACHINE_START(BOCKW_DT, "bockw")
 	.init_machine	= bockw_init,
 	.init_time	= shmobile_timer_init,
 	.dt_compat	= bockw_boards_compat_dt,
+	.init_late      = r8a7778_init_late,
 MACHINE_END

+ 4 - 177
arch/arm/mach-shmobile/board-marzen.c

@@ -37,10 +37,6 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/mfd/tmio.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ehci_pdriver.h>
-#include <linux/usb/ohci_pdriver.h>
-#include <linux/pm_runtime.h>
 #include <mach/hardware.h>
 #include <mach/r8a7779.h>
 #include <mach/common.h>
@@ -61,6 +57,8 @@ static struct regulator_consumer_supply dummy_supplies[] = {
 	REGULATOR_SUPPLY("vdd33a", "smsc911x"),
 };
 
+static struct rcar_phy_platform_data usb_phy_platform_data __initdata;
+
 /* SMSC LAN89218 */
 static struct resource smsc911x_resources[] = {
 	[0] = {
@@ -150,26 +148,6 @@ static struct platform_device hspi_device = {
 	.num_resources	= ARRAY_SIZE(hspi_resources),
 };
 
-/* USB PHY */
-static struct resource usb_phy_resources[] = {
-	[0] = {
-		.start		= 0xffe70000,
-		.end		= 0xffe70900 - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= 0xfff70000,
-		.end		= 0xfff70900 - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device usb_phy_device = {
-	.name		= "rcar_usb_phy",
-	.resource	= usb_phy_resources,
-	.num_resources	= ARRAY_SIZE(usb_phy_resources),
-};
-
 /* LEDS */
 static struct gpio_led marzen_leds[] = {
 	{
@@ -205,161 +183,9 @@ static struct platform_device *marzen_devices[] __initdata = {
 	&sdhi0_device,
 	&thermal_device,
 	&hspi_device,
-	&usb_phy_device,
 	&leds_device,
 };
 
-/* USB */
-static struct usb_phy *phy;
-static int usb_power_on(struct platform_device *pdev)
-{
-	if (IS_ERR(phy))
-		return PTR_ERR(phy);
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	usb_phy_init(phy);
-
-	return 0;
-}
-
-static void usb_power_off(struct platform_device *pdev)
-{
-	if (IS_ERR(phy))
-		return;
-
-	usb_phy_shutdown(phy);
-
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-}
-
-static struct usb_ehci_pdata ehcix_pdata = {
-	.power_on	= usb_power_on,
-	.power_off	= usb_power_off,
-	.power_suspend	= usb_power_off,
-};
-
-static struct resource ehci0_resources[] = {
-	[0] = {
-		.start	= 0xffe70000,
-		.end	= 0xffe70400 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= gic_iid(0x4c),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device ehci0_device = {
-	.name	= "ehci-platform",
-	.id	= 0,
-	.dev	= {
-		.dma_mask		= &ehci0_device.dev.coherent_dma_mask,
-		.coherent_dma_mask	= 0xffffffff,
-		.platform_data		= &ehcix_pdata,
-	},
-	.num_resources	= ARRAY_SIZE(ehci0_resources),
-	.resource	= ehci0_resources,
-};
-
-static struct resource ehci1_resources[] = {
-	[0] = {
-		.start	= 0xfff70000,
-		.end	= 0xfff70400 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= gic_iid(0x4d),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device ehci1_device = {
-	.name	= "ehci-platform",
-	.id	= 1,
-	.dev	= {
-		.dma_mask		= &ehci1_device.dev.coherent_dma_mask,
-		.coherent_dma_mask	= 0xffffffff,
-		.platform_data		= &ehcix_pdata,
-	},
-	.num_resources	= ARRAY_SIZE(ehci1_resources),
-	.resource	= ehci1_resources,
-};
-
-static struct usb_ohci_pdata ohcix_pdata = {
-	.power_on	= usb_power_on,
-	.power_off	= usb_power_off,
-	.power_suspend	= usb_power_off,
-};
-
-static struct resource ohci0_resources[] = {
-	[0] = {
-		.start	= 0xffe70400,
-		.end	= 0xffe70800 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= gic_iid(0x4c),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device ohci0_device = {
-	.name	= "ohci-platform",
-	.id	= 0,
-	.dev	= {
-		.dma_mask		= &ohci0_device.dev.coherent_dma_mask,
-		.coherent_dma_mask	= 0xffffffff,
-		.platform_data		= &ohcix_pdata,
-	},
-	.num_resources	= ARRAY_SIZE(ohci0_resources),
-	.resource	= ohci0_resources,
-};
-
-static struct resource ohci1_resources[] = {
-	[0] = {
-		.start	= 0xfff70400,
-		.end	= 0xfff70800 - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= gic_iid(0x4d),
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device ohci1_device = {
-	.name	= "ohci-platform",
-	.id	= 1,
-	.dev	= {
-		.dma_mask		= &ohci1_device.dev.coherent_dma_mask,
-		.coherent_dma_mask	= 0xffffffff,
-		.platform_data		= &ohcix_pdata,
-	},
-	.num_resources	= ARRAY_SIZE(ohci1_resources),
-	.resource	= ohci1_resources,
-};
-
-static struct platform_device *marzen_late_devices[] __initdata = {
-	&ehci0_device,
-	&ehci1_device,
-	&ohci0_device,
-	&ohci1_device,
-};
-
-void __init marzen_init_late(void)
-{
-	/* get usb phy */
-	phy = usb_get_phy(USB_PHY_TYPE_USB2);
-
-	shmobile_init_late();
-	platform_add_devices(marzen_late_devices,
-			     ARRAY_SIZE(marzen_late_devices));
-}
-
 static const struct pinctrl_map marzen_pinctrl_map[] = {
 	/* HSPI0 */
 	PIN_MAP_MUX_GROUP_DEFAULT("sh-hspi.0", "pfc-r8a7779",
@@ -407,6 +233,7 @@ static void __init marzen_init(void)
 	r8a7779_pinmux_init();
 
 	r8a7779_add_standard_devices();
+	r8a7779_add_usb_phy_device(&usb_phy_platform_data);
 	platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
 }
 
@@ -417,6 +244,6 @@ MACHINE_START(MARZEN, "marzen")
 	.nr_irqs	= NR_IRQS_LEGACY,
 	.init_irq	= r8a7779_init_irq,
 	.init_machine	= marzen_init,
-	.init_late	= marzen_init_late,
+	.init_late	= r8a7779_init_late,
 	.init_time	= r8a7779_earlytimer_init,
 MACHINE_END

+ 4 - 0
arch/arm/mach-shmobile/clock-r8a7778.c

@@ -105,6 +105,7 @@ static struct clk *main_clks[] = {
 enum {
 	MSTP323, MSTP322, MSTP321,
 	MSTP114,
+	MSTP100,
 	MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
 	MSTP016, MSTP015,
 	MSTP_NR };
@@ -114,6 +115,7 @@ static struct clk mstp_clks[MSTP_NR] = {
 	[MSTP322] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 22, 0), /* SDHI1 */
 	[MSTP321] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 21, 0), /* SDHI2 */
 	[MSTP114] = SH_CLK_MSTP32(&p_clk, MSTPCR1, 14, 0), /* Ether */
+	[MSTP100] = SH_CLK_MSTP32(&p_clk, MSTPCR1,  0, 0), /* USB0/1 */
 	[MSTP026] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 26, 0), /* SCIF0 */
 	[MSTP025] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 25, 0), /* SCIF1 */
 	[MSTP024] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 24, 0), /* SCIF2 */
@@ -130,6 +132,8 @@ static struct clk_lookup lookups[] = {
 	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
 	CLKDEV_DEV_ID("sh-eth",	&mstp_clks[MSTP114]), /* Ether */
+	CLKDEV_DEV_ID("ehci-platform", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */
+	CLKDEV_DEV_ID("ohci-platform", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */
 	CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP026]), /* SCIF0 */
 	CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP025]), /* SCIF1 */
 	CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP024]), /* SCIF2 */

+ 3 - 0
arch/arm/mach-shmobile/include/mach/r8a7778.h

@@ -20,10 +20,13 @@
 
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/sh_eth.h>
+#include <linux/platform_data/usb-rcar-phy.h>
 
 extern void r8a7778_add_standard_devices(void);
 extern void r8a7778_add_standard_devices_dt(void);
 extern void r8a7778_add_ether_device(struct sh_eth_plat_data *pdata);
+extern void r8a7778_add_usb_phy_device(struct rcar_phy_platform_data *pdata);
+extern void r8a7778_init_late(void);
 extern void r8a7778_init_delay(void);
 extern void r8a7778_init_irq(void);
 extern void r8a7778_init_irq_dt(void);

+ 3 - 0
arch/arm/mach-shmobile/include/mach/r8a7779.h

@@ -4,6 +4,7 @@
 #include <linux/sh_clk.h>
 #include <linux/pm_domain.h>
 #include <linux/sh_eth.h>
+#include <linux/platform_data/usb-rcar-phy.h>
 
 struct platform_device;
 
@@ -33,6 +34,8 @@ extern void r8a7779_add_early_devices(void);
 extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_add_standard_devices_dt(void);
 extern void r8a7779_add_ether_device(struct sh_eth_plat_data *pdata);
+extern void r8a7779_add_usb_phy_device(struct rcar_phy_platform_data *pdata);
+extern void r8a7779_init_late(void);
 extern void r8a7779_clock_init(void);
 extern void r8a7779_pinmux_init(void);
 extern void r8a7779_pm_init(void);

+ 108 - 0
arch/arm/mach-shmobile/setup-r8a7778.c

@@ -30,6 +30,12 @@
 #include <linux/irqchip.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+#include <linux/dma-mapping.h>
 #include <mach/irqs.h>
 #include <mach/r8a7778.h>
 #include <mach/common.h>
@@ -89,6 +95,99 @@ static struct sh_timer_config sh_tmu1_platform_data = {
 		&sh_tmu##idx##_platform_data,		\
 		sizeof(sh_tmu##idx##_platform_data))
 
+/* USB PHY */
+static struct resource usb_phy_resources[] __initdata = {
+	DEFINE_RES_MEM(0xffe70800, 0x100),
+	DEFINE_RES_MEM(0xffe76000, 0x100),
+};
+
+void __init r8a7778_add_usb_phy_device(struct rcar_phy_platform_data *pdata)
+{
+	platform_device_register_resndata(&platform_bus, "rcar_usb_phy", -1,
+					  usb_phy_resources,
+					  ARRAY_SIZE(usb_phy_resources),
+					  pdata, sizeof(*pdata));
+}
+
+/* USB */
+static struct usb_phy *phy;
+
+static int usb_power_on(struct platform_device *pdev)
+{
+	if (IS_ERR(phy))
+		return PTR_ERR(phy);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	usb_phy_init(phy);
+
+	return 0;
+}
+
+static void usb_power_off(struct platform_device *pdev)
+{
+	if (IS_ERR(phy))
+		return;
+
+	usb_phy_shutdown(phy);
+
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static int ehci_init_internal_buffer(struct usb_hcd *hcd)
+{
+	/*
+	 * Below are recommended values from the datasheet;
+	 * see [USB :: Setting of EHCI Internal Buffer].
+	 */
+	/* EHCI IP internal buffer setting */
+	iowrite32(0x00ff0040, hcd->regs + 0x0094);
+	/* EHCI IP internal buffer enable */
+	iowrite32(0x00000001, hcd->regs + 0x009C);
+
+	return 0;
+}
+
+static struct usb_ehci_pdata ehci_pdata __initdata = {
+	.power_on	= usb_power_on,
+	.power_off	= usb_power_off,
+	.power_suspend	= usb_power_off,
+	.pre_setup	= ehci_init_internal_buffer,
+};
+
+static struct resource ehci_resources[] __initdata = {
+	DEFINE_RES_MEM(0xffe70000, 0x400),
+	DEFINE_RES_IRQ(gic_iid(0x4c)),
+};
+
+static struct usb_ohci_pdata ohci_pdata __initdata = {
+	.power_on	= usb_power_on,
+	.power_off	= usb_power_off,
+	.power_suspend	= usb_power_off,
+};
+
+static struct resource ohci_resources[] __initdata = {
+	DEFINE_RES_MEM(0xffe70400, 0x400),
+	DEFINE_RES_IRQ(gic_iid(0x4c)),
+};
+
+#define USB_PLATFORM_INFO(hci)					\
+static struct platform_device_info hci##_info __initdata = {	\
+	.parent		= &platform_bus,			\
+	.name		= #hci "-platform",			\
+	.id		= -1,					\
+	.res		= hci##_resources,			\
+	.num_res	= ARRAY_SIZE(hci##_resources),		\
+	.data		= &hci##_pdata,				\
+	.size_data	= sizeof(hci##_pdata),			\
+	.dma_mask	= DMA_BIT_MASK(32),			\
+}
+
+USB_PLATFORM_INFO(ehci);
+USB_PLATFORM_INFO(ohci);
+
 /* Ether */
 static struct resource ether_resources[] = {
 	DEFINE_RES_MEM(0xfde00000, 0x400),
@@ -197,6 +296,14 @@ void __init r8a7778_add_standard_devices(void)
 	r8a7778_register_tmu(1);
 }
 
+void __init r8a7778_init_late(void)
+{
+	phy = usb_get_phy(USB_PHY_TYPE_USB2);
+
+	platform_device_register_full(&ehci_info);
+	platform_device_register_full(&ohci_info);
+}
+
 static struct renesas_intc_irqpin_config irqpin_platform_data = {
 	.irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
 	.sense_bitfield_width = 2,
@@ -310,6 +417,7 @@ DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)")
 	.init_machine	= r8a7778_add_standard_devices_dt,
 	.init_time	= shmobile_timer_init,
 	.dt_compat	= r8a7778_compat_dt,
+	.init_late      = r8a7778_init_late,
 MACHINE_END
 
 #endif /* CONFIG_USE_OF */

+ 193 - 3
arch/arm/mach-shmobile/setup-r8a7779.c

@@ -32,6 +32,11 @@
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+#include <linux/pm_runtime.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/r8a7779.h>
@@ -383,6 +388,165 @@ static struct platform_device sata_device = {
 	},
 };
 
+/* USB PHY */
+static struct resource usb_phy_resources[] __initdata = {
+	[0] = {
+		.start		= 0xffe70800,
+		.end		= 0xffe70900 - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+/* USB */
+static struct usb_phy *phy;
+
+static int usb_power_on(struct platform_device *pdev)
+{
+	if (IS_ERR(phy))
+		return PTR_ERR(phy);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
+	usb_phy_init(phy);
+
+	return 0;
+}
+
+static void usb_power_off(struct platform_device *pdev)
+{
+	if (IS_ERR(phy))
+		return;
+
+	usb_phy_shutdown(phy);
+
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+}
+
+static int ehci_init_internal_buffer(struct usb_hcd *hcd)
+{
+	/*
+	 * Below are recommended values from the datasheet;
+	 * see [USB :: Setting of EHCI Internal Buffer].
+	 */
+	/* EHCI IP internal buffer setting */
+	iowrite32(0x00ff0040, hcd->regs + 0x0094);
+	/* EHCI IP internal buffer enable */
+	iowrite32(0x00000001, hcd->regs + 0x009C);
+
+	return 0;
+}
+
+static struct usb_ehci_pdata ehcix_pdata = {
+	.power_on	= usb_power_on,
+	.power_off	= usb_power_off,
+	.power_suspend	= usb_power_off,
+	.pre_setup	= ehci_init_internal_buffer,
+};
+
+static struct resource ehci0_resources[] = {
+	[0] = {
+		.start	= 0xffe70000,
+		.end	= 0xffe70400 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gic_iid(0x4c),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ehci0_device = {
+	.name	= "ehci-platform",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ehci0_device.dev.coherent_dma_mask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &ehcix_pdata,
+	},
+	.num_resources	= ARRAY_SIZE(ehci0_resources),
+	.resource	= ehci0_resources,
+};
+
+static struct resource ehci1_resources[] = {
+	[0] = {
+		.start	= 0xfff70000,
+		.end	= 0xfff70400 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gic_iid(0x4d),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ehci1_device = {
+	.name	= "ehci-platform",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ehci1_device.dev.coherent_dma_mask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &ehcix_pdata,
+	},
+	.num_resources	= ARRAY_SIZE(ehci1_resources),
+	.resource	= ehci1_resources,
+};
+
+static struct usb_ohci_pdata ohcix_pdata = {
+	.power_on	= usb_power_on,
+	.power_off	= usb_power_off,
+	.power_suspend	= usb_power_off,
+};
+
+static struct resource ohci0_resources[] = {
+	[0] = {
+		.start	= 0xffe70400,
+		.end	= 0xffe70800 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gic_iid(0x4c),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ohci0_device = {
+	.name	= "ohci-platform",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ohci0_device.dev.coherent_dma_mask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &ohcix_pdata,
+	},
+	.num_resources	= ARRAY_SIZE(ohci0_resources),
+	.resource	= ohci0_resources,
+};
+
+static struct resource ohci1_resources[] = {
+	[0] = {
+		.start	= 0xfff70400,
+		.end	= 0xfff70800 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= gic_iid(0x4d),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ohci1_device = {
+	.name	= "ohci-platform",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ohci1_device.dev.coherent_dma_mask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &ohcix_pdata,
+	},
+	.num_resources	= ARRAY_SIZE(ohci1_resources),
+	.resource	= ohci1_resources,
+};
+
 /* Ether */
 static struct resource ether_resources[] = {
 	{
@@ -406,7 +570,7 @@ static struct platform_device *r8a7779_devices_dt[] __initdata = {
 	&tmu01_device,
 };
 
-static struct platform_device *r8a7779_late_devices[] __initdata = {
+static struct platform_device *r8a7779_standard_devices[] __initdata = {
 	&i2c0_device,
 	&i2c1_device,
 	&i2c2_device,
@@ -426,8 +590,8 @@ void __init r8a7779_add_standard_devices(void)
 
 	platform_add_devices(r8a7779_devices_dt,
 			    ARRAY_SIZE(r8a7779_devices_dt));
-	platform_add_devices(r8a7779_late_devices,
-			    ARRAY_SIZE(r8a7779_late_devices));
+	platform_add_devices(r8a7779_standard_devices,
+			    ARRAY_SIZE(r8a7779_standard_devices));
 }
 
 void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata)
@@ -438,6 +602,14 @@ void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata)
 					  pdata, sizeof(*pdata));
 }
 
+void __init r8a7779_add_usb_phy_device(struct rcar_phy_platform_data *pdata)
+{
+	platform_device_register_resndata(&platform_bus, "rcar_usb_phy", -1,
+					  usb_phy_resources,
+					  ARRAY_SIZE(usb_phy_resources),
+					  pdata, sizeof(*pdata));
+}
+
 /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
 void __init __weak r8a7779_register_twd(void) { }
 
@@ -470,6 +642,23 @@ void __init r8a7779_add_early_devices(void)
 	 */
 }
 
+static struct platform_device *r8a7779_late_devices[] __initdata = {
+	&ehci0_device,
+	&ehci1_device,
+	&ohci0_device,
+	&ohci1_device,
+};
+
+void __init r8a7779_init_late(void)
+{
+	/* get USB PHY */
+	phy = usb_get_phy(USB_PHY_TYPE_USB2);
+
+	shmobile_init_late();
+	platform_add_devices(r8a7779_late_devices,
+			     ARRAY_SIZE(r8a7779_late_devices));
+}
+
 #ifdef CONFIG_USE_OF
 void __init r8a7779_init_delay(void)
 {
@@ -503,6 +692,7 @@ DT_MACHINE_START(R8A7779_DT, "Generic R8A7779 (Flattened Device Tree)")
 	.init_irq	= r8a7779_init_irq_dt,
 	.init_machine	= r8a7779_add_standard_devices_dt,
 	.init_time	= shmobile_timer_init,
+	.init_late	= r8a7779_init_late,
 	.dt_compat	= r8a7779_compat_dt,
 MACHINE_END
 #endif /* CONFIG_USE_OF */

+ 6 - 0
drivers/usb/host/ehci-platform.c

@@ -48,6 +48,12 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
 	ehci->big_endian_desc = pdata->big_endian_desc;
 	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
+	if (pdata->pre_setup) {
+		retval = pdata->pre_setup(hcd);
+		if (retval < 0)
+			return retval;
+	}
+
 	ehci->caps = hcd->regs + pdata->caps_offset;
 	retval = ehci_setup(hcd);
 	if (retval)

+ 5 - 5
drivers/usb/phy/Kconfig

@@ -180,15 +180,15 @@ config USB_MXS_PHY
 	  MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
 
 config USB_RCAR_PHY
-	tristate "Renesas R-Car USB phy support"
+	tristate "Renesas R-Car USB PHY support"
 	depends on USB || USB_GADGET
 	help
-	  Say Y here to add support for the Renesas R-Car USB phy driver.
-	  This chip is typically used as USB phy for USB host, gadget.
-	  This driver supports: R8A7779
+	  Say Y here to add support for the Renesas R-Car USB common PHY driver.
+	  This chip is typically used as USB PHY for USB host, gadget.
+	  This driver supports R8A7778 and R8A7779.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called rcar-phy.
+	  module will be called phy-rcar-usb.
 
 config USB_ULPI
 	bool "Generic ULPI Transceiver Driver"

+ 82 - 46
drivers/usb/phy/phy-rcar-usb.c

@@ -1,8 +1,9 @@
 /*
  * Renesas R-Car USB phy driver
  *
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012-2013 Renesas Solutions Corp.
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Copyright (C) 2013 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
@@ -15,17 +16,41 @@
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
-
-/* USBH common register */
-#define USBPCTRL0	0x0800
-#define USBPCTRL1	0x0804
-#define USBST		0x0808
-#define USBEH0		0x080C
-#define USBOH0		0x081C
-#define USBCTL0		0x0858
-#define EIIBC1		0x0094
-#define EIIBC2		0x009C
-
+#include <linux/platform_data/usb-rcar-phy.h>
+
+/* REGS block */
+#define USBPCTRL0	0x00
+#define USBPCTRL1	0x04
+#define USBST		0x08
+#define USBEH0		0x0C
+#define USBOH0		0x1C
+#define USBCTL0		0x58
+
+/* High-speed signal quality characteristic control registers (R8A7778 only) */
+#define HSQCTL1		0x24
+#define HSQCTL2		0x28
+
+/* USBPCTRL0 */
+#define OVC2		(1 << 10) /* (R8A7779 only)			*/
+				/* Switches the OVC input pin for port 2: */
+				/* 1: USB_OVC2, 0: OVC2			*/
+#define OVC1_VBUS1	(1 << 9) /* Switches the OVC input pin for port 1: */
+				/* 1: USB_OVC1, 0: OVC1/VBUS1		*/
+				/* Function mode: set to 0		*/
+#define OVC0		(1 << 8) /* Switches the OVC input pin for port 0: */
+				/* 1: USB_OVC0 pin, 0: OVC0		*/
+#define OVC2_ACT 	(1 << 6) /* (R8A7779 only)			*/
+				/* Host mode: OVC2 polarity:		*/
+				/* 1: active-high, 0: active-low	*/
+#define PENC		(1 << 4) /* Function mode: output level of PENC1 pin: */
+				/* 1: high, 0: low			*/
+#define OVC0_ACT 	(1 << 3) /* Host mode: OVC0 polarity:		*/
+				/* 1: active-high, 0: active-low	*/
+#define OVC1_ACT	(1 << 1) /* Host mode: OVC1 polarity:		*/
+				/* 1: active-high, 0: active-low	*/
+				/* Function mode: be sure to set to 1	*/
+#define PORT1		(1 << 0) /* Selects port 1 mode:		*/
+				/* 1: function, 0: host			*/
 /* USBPCTRL1 */
 #define PHY_RST		(1 << 2)
 #define PLL_ENB		(1 << 1)
@@ -58,8 +83,10 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
 {
 	struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
 	struct device *dev = phy->dev;
+	struct rcar_phy_platform_data *pdata = dev->platform_data;
 	void __iomem *reg0 = priv->reg0;
 	void __iomem *reg1 = priv->reg1;
+	static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
 	int i;
 	u32 val;
 	unsigned long flags;
@@ -77,7 +104,16 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
 		/* (2) start USB-PHY internal PLL */
 		iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1));
 
-		/* (3) USB module status check */
+		/* (3) set USB-PHY in accord with the conditions of usage */
+		if (reg1) {
+			u32 hsqctl1 = pdata->ferrite_bead ? 0x41 : 0;
+			u32 hsqctl2 = pdata->ferrite_bead ? 0x0d : 7;
+
+			iowrite32(hsqctl1, reg1 + HSQCTL1);
+			iowrite32(hsqctl2, reg1 + HSQCTL2);
+		}
+
+		/* (4) USB module status check */
 		for (i = 0; i < 1024; i++) {
 			udelay(10);
 			val = ioread32(reg0 + USBST);
@@ -90,24 +126,24 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
 			goto phy_init_end;
 		}
 
-		/* (4) USB-PHY reset clear */
+		/* (5) USB-PHY reset clear */
 		iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
 
-		/* set platform specific port settings */
-		iowrite32(0x00000000, (reg0 + USBPCTRL0));
-
-		/*
-		 * EHCI IP internal buffer setting
-		 * EHCI IP internal buffer enable
-		 *
-		 * These are recommended value of a datasheet
-		 * see [USB :: EHCI internal buffer setting]
-		 */
-		iowrite32(0x00ff0040, (reg0 + EIIBC1));
-		iowrite32(0x00ff0040, (reg1 + EIIBC1));
-
-		iowrite32(0x00000001, (reg0 + EIIBC2));
-		iowrite32(0x00000001, (reg1 + EIIBC2));
+		/* Board specific port settings */
+		val = 0;
+		if (pdata->port1_func)
+			val |= PORT1;
+		if (pdata->penc1)
+			val |= PENC;
+		for (i = 0; i < 3; i++) {
+			/* OVCn bits follow each other in the right order */
+			if (pdata->ovc_pin[i].select_3_3v)
+				val |= OVC0 << i;
+			/* OVCn_ACT bits are spaced by irregular intervals */
+			if (pdata->ovc_pin[i].active_high)
+				val |= ovcn_act[i];
+		}
+		iowrite32(val, (reg0 + USBPCTRL0));
 
 		/*
 		 * Bus alignment settings
@@ -134,10 +170,8 @@ static void rcar_usb_phy_shutdown(struct usb_phy *phy)
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if (priv->counter-- == 1) { /* last user */
-		iowrite32(0x00000000, (reg0 + USBPCTRL0));
+	if (priv->counter-- == 1)	/* last user */
 		iowrite32(0x00000000, (reg0 + USBPCTRL1));
-	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -147,27 +181,29 @@ static int rcar_usb_phy_probe(struct platform_device *pdev)
 	struct rcar_usb_phy_priv *priv;
 	struct resource *res0, *res1;
 	struct device *dev = &pdev->dev;
-	void __iomem *reg0, *reg1;
+	void __iomem *reg0, *reg1 = NULL;
 	int ret;
 
+	if (!pdev->dev.platform_data) {
+		dev_err(dev, "No platform data\n");
+		return -EINVAL;
+	}
+
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res0 || !res1) {
+	if (!res0) {
 		dev_err(dev, "Not enough platform resources\n");
 		return -EINVAL;
 	}
 
-	/*
-	 * CAUTION
-	 *
-	 * Because this phy address is also mapped under OHCI/EHCI address area,
-	 * this driver can't use devm_request_and_ioremap(dev, res) here
-	 */
-	reg0 = devm_ioremap_nocache(dev, res0->start, resource_size(res0));
-	reg1 = devm_ioremap_nocache(dev, res1->start, resource_size(res1));
-	if (!reg0 || !reg1) {
-		dev_err(dev, "ioremap error\n");
-		return -ENOMEM;
+	reg0 = devm_ioremap_resource(dev, res0);
+	if (IS_ERR(reg0))
+		return PTR_ERR(reg0);
+
+	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res1) {
+		reg1 = devm_ioremap_resource(dev, res1);
+		if (IS_ERR(reg1))
+			return PTR_ERR(reg1);
 	}
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);

+ 28 - 0
include/linux/platform_data/usb-rcar-phy.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef __USB_RCAR_PHY_H
+#define __USB_RCAR_PHY_H
+
+#include <linux/types.h>
+
+struct rcar_phy_platform_data {
+	bool ferrite_bead:1;	/* (R8A7778 only)			*/
+
+	bool port1_func:1;	/* true: port 1 used by function, false: host */
+	unsigned penc1:1;	/* Output of the PENC1 pin in function mode */
+	struct {		/* Overcurrent pin control for ports 0..2 */
+		bool select_3_3v:1; /* true: USB_OVCn pin, false: OVCn pin */
+				/* Set to false on port 1 in function mode */
+		bool active_high:1; /* true: active  high, false: active low */
+				/* Set to true  on port 1 in function mode */
+	} ovc_pin[3];		/* (R8A7778 only has 2 ports)		*/
+};
+
+#endif /* __USB_RCAR_PHY_H */

+ 4 - 0
include/linux/usb/ehci_pdriver.h

@@ -19,6 +19,9 @@
 #ifndef __USB_CORE_EHCI_PDRIVER_H
 #define __USB_CORE_EHCI_PDRIVER_H
 
+struct platform_device;
+struct usb_hcd;
+
 /**
  * struct usb_ehci_pdata - platform_data for generic ehci driver
  *
@@ -50,6 +53,7 @@ struct usb_ehci_pdata {
 	/* Turn on only VBUS suspend power and hotplug detection,
 	 * turn off everything else */
 	void (*power_suspend)(struct platform_device *pdev);
+	int (*pre_setup)(struct usb_hcd *hcd);
 };
 
 #endif /* __USB_CORE_EHCI_PDRIVER_H */