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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJRuWA6AAoJENfPZGlqN0++YFAP/ArB3kdvcKNQNjXM0BmX/Pim
 TFIOIN4NRpRFcS467PSSSObm/YJsbR+5TViISZdpo7O6hmZzUPeK2MrKNq5wmUIf
 OpX0eI8dCWCRZIAZjQcOiro1BR05UEzqyc8GjnmiVnV6TShO8x9IaFKGl+RRI4WD
 KoG3wNo1OvOuEToXhsyB6kMnpD8Ab/Xrj5xAAzLkml8gx6K/kAvdCnn+0Zhv8Nvu
 Vp0hEnCC/z6peBrFFWqXPpt0aV4iILVtxG36funGIuMB1YE0Ih5TnoJDlAPZSIO7
 RnUz6vfjczobR7Pt8wBf5wFsMuWMUt5trLgruSeeskRw+728Vc7MzFwLV8IdtlAY
 LJpnrA7bd4W6R6d9u+eiCEekA4/+6SZySsLGflwfB3yzhaDr5LIMK8YZZFlXb2Bm
 p2Gkh556bT7lrYdqiyjqjSk71qFokynSFUp61GMWbQTNbSY2azlpDfxG1Epo6kFu
 XxpAr/XjGm4mMOp8ObxjvTlb9encP1snAHBnB3CoFh/LyjcG0nLwdWySAbTGlTy2
 iabAegy7pQ+wD3Qri7WR7VYyiLogb5cF+rvVSDzS0HhtYH9OMFdb8z3NrHY+mk3Q
 OCZf9bbIk5pGhQyryDXg8G6nT9qLMsjy1SB2kj6S+Tyaox4WiLJZJiZiiwI+tGrn
 7bst42iHBVMJaWQKRcAq
 =5+Te
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Olof Johansson 2013-06-14 17:36:30 -07:00
commit a114926964
13 changed files with 448 additions and 229 deletions

View File

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

View File

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

View File

@ -37,10 +37,6 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.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/hardware.h>
#include <mach/r8a7779.h> #include <mach/r8a7779.h>
#include <mach/common.h> #include <mach/common.h>
@ -61,6 +57,8 @@ static struct regulator_consumer_supply dummy_supplies[] = {
REGULATOR_SUPPLY("vdd33a", "smsc911x"), REGULATOR_SUPPLY("vdd33a", "smsc911x"),
}; };
static struct rcar_phy_platform_data usb_phy_platform_data __initdata;
/* SMSC LAN89218 */ /* SMSC LAN89218 */
static struct resource smsc911x_resources[] = { static struct resource smsc911x_resources[] = {
[0] = { [0] = {
@ -150,26 +148,6 @@ static struct platform_device hspi_device = {
.num_resources = ARRAY_SIZE(hspi_resources), .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 */ /* LEDS */
static struct gpio_led marzen_leds[] = { static struct gpio_led marzen_leds[] = {
{ {
@ -205,161 +183,9 @@ static struct platform_device *marzen_devices[] __initdata = {
&sdhi0_device, &sdhi0_device,
&thermal_device, &thermal_device,
&hspi_device, &hspi_device,
&usb_phy_device,
&leds_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[] = { static const struct pinctrl_map marzen_pinctrl_map[] = {
/* HSPI0 */ /* HSPI0 */
PIN_MAP_MUX_GROUP_DEFAULT("sh-hspi.0", "pfc-r8a7779", PIN_MAP_MUX_GROUP_DEFAULT("sh-hspi.0", "pfc-r8a7779",
@ -407,6 +233,7 @@ static void __init marzen_init(void)
r8a7779_pinmux_init(); r8a7779_pinmux_init();
r8a7779_add_standard_devices(); r8a7779_add_standard_devices();
r8a7779_add_usb_phy_device(&usb_phy_platform_data);
platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices)); platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
} }
@ -417,6 +244,6 @@ MACHINE_START(MARZEN, "marzen")
.nr_irqs = NR_IRQS_LEGACY, .nr_irqs = NR_IRQS_LEGACY,
.init_irq = r8a7779_init_irq, .init_irq = r8a7779_init_irq,
.init_machine = marzen_init, .init_machine = marzen_init,
.init_late = marzen_init_late, .init_late = r8a7779_init_late,
.init_time = r8a7779_earlytimer_init, .init_time = r8a7779_earlytimer_init,
MACHINE_END MACHINE_END

View File

@ -105,6 +105,7 @@ static struct clk *main_clks[] = {
enum { enum {
MSTP323, MSTP322, MSTP321, MSTP323, MSTP322, MSTP321,
MSTP114, MSTP114,
MSTP100,
MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
MSTP016, MSTP015, MSTP016, MSTP015,
MSTP_NR }; MSTP_NR };
@ -114,6 +115,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP322] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 22, 0), /* SDHI1 */ [MSTP322] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 22, 0), /* SDHI1 */
[MSTP321] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 21, 0), /* SDHI2 */ [MSTP321] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 21, 0), /* SDHI2 */
[MSTP114] = SH_CLK_MSTP32(&p_clk, MSTPCR1, 14, 0), /* Ether */ [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 */ [MSTP026] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 26, 0), /* SCIF0 */
[MSTP025] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 25, 0), /* SCIF1 */ [MSTP025] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 25, 0), /* SCIF1 */
[MSTP024] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 24, 0), /* SCIF2 */ [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.1", &mstp_clks[MSTP322]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP114]), /* Ether */ 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.0", &mstp_clks[MSTP026]), /* SCIF0 */
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP025]), /* SCIF1 */ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP025]), /* SCIF1 */
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP024]), /* SCIF2 */ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP024]), /* SCIF2 */

View File

@ -20,10 +20,13 @@
#include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/sh_eth.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(void);
extern void r8a7778_add_standard_devices_dt(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_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_delay(void);
extern void r8a7778_init_irq(void); extern void r8a7778_init_irq(void);
extern void r8a7778_init_irq_dt(void); extern void r8a7778_init_irq_dt(void);

View File

@ -4,6 +4,7 @@
#include <linux/sh_clk.h> #include <linux/sh_clk.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/sh_eth.h> #include <linux/sh_eth.h>
#include <linux/platform_data/usb-rcar-phy.h>
struct platform_device; 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(void);
extern void r8a7779_add_standard_devices_dt(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_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_clock_init(void);
extern void r8a7779_pinmux_init(void); extern void r8a7779_pinmux_init(void);
extern void r8a7779_pm_init(void); extern void r8a7779_pm_init(void);

View File

@ -30,6 +30,12 @@
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/serial_sci.h> #include <linux/serial_sci.h>
#include <linux/sh_timer.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/irqs.h>
#include <mach/r8a7778.h> #include <mach/r8a7778.h>
#include <mach/common.h> #include <mach/common.h>
@ -89,6 +95,99 @@ static struct sh_timer_config sh_tmu1_platform_data = {
&sh_tmu##idx##_platform_data, \ &sh_tmu##idx##_platform_data, \
sizeof(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 */ /* Ether */
static struct resource ether_resources[] = { static struct resource ether_resources[] = {
DEFINE_RES_MEM(0xfde00000, 0x400), DEFINE_RES_MEM(0xfde00000, 0x400),
@ -197,6 +296,14 @@ void __init r8a7778_add_standard_devices(void)
r8a7778_register_tmu(1); 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 = { static struct renesas_intc_irqpin_config irqpin_platform_data = {
.irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
.sense_bitfield_width = 2, .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_machine = r8a7778_add_standard_devices_dt,
.init_time = shmobile_timer_init, .init_time = shmobile_timer_init,
.dt_compat = r8a7778_compat_dt, .dt_compat = r8a7778_compat_dt,
.init_late = r8a7778_init_late,
MACHINE_END MACHINE_END
#endif /* CONFIG_USE_OF */ #endif /* CONFIG_USE_OF */

View File

@ -32,6 +32,11 @@
#include <linux/sh_intc.h> #include <linux/sh_intc.h>
#include <linux/sh_timer.h> #include <linux/sh_timer.h>
#include <linux/dma-mapping.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/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/r8a7779.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 */ /* Ether */
static struct resource ether_resources[] = { static struct resource ether_resources[] = {
{ {
@ -406,7 +570,7 @@ static struct platform_device *r8a7779_devices_dt[] __initdata = {
&tmu01_device, &tmu01_device,
}; };
static struct platform_device *r8a7779_late_devices[] __initdata = { static struct platform_device *r8a7779_standard_devices[] __initdata = {
&i2c0_device, &i2c0_device,
&i2c1_device, &i2c1_device,
&i2c2_device, &i2c2_device,
@ -426,8 +590,8 @@ void __init r8a7779_add_standard_devices(void)
platform_add_devices(r8a7779_devices_dt, platform_add_devices(r8a7779_devices_dt,
ARRAY_SIZE(r8a7779_devices_dt)); ARRAY_SIZE(r8a7779_devices_dt));
platform_add_devices(r8a7779_late_devices, platform_add_devices(r8a7779_standard_devices,
ARRAY_SIZE(r8a7779_late_devices)); ARRAY_SIZE(r8a7779_standard_devices));
} }
void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata) 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)); 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 */ /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
void __init __weak r8a7779_register_twd(void) { } 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 #ifdef CONFIG_USE_OF
void __init r8a7779_init_delay(void) 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_irq = r8a7779_init_irq_dt,
.init_machine = r8a7779_add_standard_devices_dt, .init_machine = r8a7779_add_standard_devices_dt,
.init_time = shmobile_timer_init, .init_time = shmobile_timer_init,
.init_late = r8a7779_init_late,
.dt_compat = r8a7779_compat_dt, .dt_compat = r8a7779_compat_dt,
MACHINE_END MACHINE_END
#endif /* CONFIG_USE_OF */ #endif /* CONFIG_USE_OF */

View File

@ -48,6 +48,12 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio; 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; ehci->caps = hcd->regs + pdata->caps_offset;
retval = ehci_setup(hcd); retval = ehci_setup(hcd);
if (retval) if (retval)

View File

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

View File

@ -1,8 +1,9 @@
/* /*
* Renesas R-Car USB phy driver * 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> * 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 * 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 * it under the terms of the GNU General Public License version 2 as
@ -15,17 +16,41 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_data/usb-rcar-phy.h>
/* USBH common register */ /* REGS block */
#define USBPCTRL0 0x0800 #define USBPCTRL0 0x00
#define USBPCTRL1 0x0804 #define USBPCTRL1 0x04
#define USBST 0x0808 #define USBST 0x08
#define USBEH0 0x080C #define USBEH0 0x0C
#define USBOH0 0x081C #define USBOH0 0x1C
#define USBCTL0 0x0858 #define USBCTL0 0x58
#define EIIBC1 0x0094
#define EIIBC2 0x009C
/* 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 */ /* USBPCTRL1 */
#define PHY_RST (1 << 2) #define PHY_RST (1 << 2)
#define PLL_ENB (1 << 1) #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 rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
struct device *dev = phy->dev; struct device *dev = phy->dev;
struct rcar_phy_platform_data *pdata = dev->platform_data;
void __iomem *reg0 = priv->reg0; void __iomem *reg0 = priv->reg0;
void __iomem *reg1 = priv->reg1; void __iomem *reg1 = priv->reg1;
static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
int i; int i;
u32 val; u32 val;
unsigned long flags; unsigned long flags;
@ -77,7 +104,16 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
/* (2) start USB-PHY internal PLL */ /* (2) start USB-PHY internal PLL */
iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1)); 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++) { for (i = 0; i < 1024; i++) {
udelay(10); udelay(10);
val = ioread32(reg0 + USBST); val = ioread32(reg0 + USBST);
@ -90,24 +126,24 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
goto phy_init_end; goto phy_init_end;
} }
/* (4) USB-PHY reset clear */ /* (5) USB-PHY reset clear */
iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1)); iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
/* set platform specific port settings */ /* Board specific port settings */
iowrite32(0x00000000, (reg0 + USBPCTRL0)); val = 0;
if (pdata->port1_func)
/* val |= PORT1;
* EHCI IP internal buffer setting if (pdata->penc1)
* EHCI IP internal buffer enable val |= PENC;
* for (i = 0; i < 3; i++) {
* These are recommended value of a datasheet /* OVCn bits follow each other in the right order */
* see [USB :: EHCI internal buffer setting] if (pdata->ovc_pin[i].select_3_3v)
*/ val |= OVC0 << i;
iowrite32(0x00ff0040, (reg0 + EIIBC1)); /* OVCn_ACT bits are spaced by irregular intervals */
iowrite32(0x00ff0040, (reg1 + EIIBC1)); if (pdata->ovc_pin[i].active_high)
val |= ovcn_act[i];
iowrite32(0x00000001, (reg0 + EIIBC2)); }
iowrite32(0x00000001, (reg1 + EIIBC2)); iowrite32(val, (reg0 + USBPCTRL0));
/* /*
* Bus alignment settings * Bus alignment settings
@ -134,10 +170,8 @@ static void rcar_usb_phy_shutdown(struct usb_phy *phy)
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if (priv->counter-- == 1) { /* last user */ if (priv->counter-- == 1) /* last user */
iowrite32(0x00000000, (reg0 + USBPCTRL0));
iowrite32(0x00000000, (reg0 + USBPCTRL1)); iowrite32(0x00000000, (reg0 + USBPCTRL1));
}
spin_unlock_irqrestore(&priv->lock, flags); 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 rcar_usb_phy_priv *priv;
struct resource *res0, *res1; struct resource *res0, *res1;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
void __iomem *reg0, *reg1; void __iomem *reg0, *reg1 = NULL;
int ret; int ret;
if (!pdev->dev.platform_data) {
dev_err(dev, "No platform data\n");
return -EINVAL;
}
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res0) {
if (!res0 || !res1) {
dev_err(dev, "Not enough platform resources\n"); dev_err(dev, "Not enough platform resources\n");
return -EINVAL; return -EINVAL;
} }
/* reg0 = devm_ioremap_resource(dev, res0);
* CAUTION if (IS_ERR(reg0))
* return PTR_ERR(reg0);
* Because this phy address is also mapped under OHCI/EHCI address area,
* this driver can't use devm_request_and_ioremap(dev, res) here res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
*/ if (res1) {
reg0 = devm_ioremap_nocache(dev, res0->start, resource_size(res0)); reg1 = devm_ioremap_resource(dev, res1);
reg1 = devm_ioremap_nocache(dev, res1->start, resource_size(res1)); if (IS_ERR(reg1))
if (!reg0 || !reg1) { return PTR_ERR(reg1);
dev_err(dev, "ioremap error\n");
return -ENOMEM;
} }
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);

View File

@ -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 */

View File

@ -19,6 +19,9 @@
#ifndef __USB_CORE_EHCI_PDRIVER_H #ifndef __USB_CORE_EHCI_PDRIVER_H
#define __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 * 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 on only VBUS suspend power and hotplug detection,
* turn off everything else */ * turn off everything else */
void (*power_suspend)(struct platform_device *pdev); void (*power_suspend)(struct platform_device *pdev);
int (*pre_setup)(struct usb_hcd *hcd);
}; };
#endif /* __USB_CORE_EHCI_PDRIVER_H */ #endif /* __USB_CORE_EHCI_PDRIVER_H */