On Tue, 21 Apr 2009, Sascha Hauer wrote: > Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > --- > arch/arm/mach-mx3/Kconfig | 1 + > arch/arm/mach-mx3/pcm037.c | 135 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 136 insertions(+), 0 deletions(-) > > diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig > index 194b842..4bb7d69 100644 > --- a/arch/arm/mach-mx3/Kconfig > +++ b/arch/arm/mach-mx3/Kconfig > @@ -30,6 +30,7 @@ config MACH_MX31ADS_WM1133_EV1 > config MACH_PCM037 > bool "Support Phytec pcm037 (i.MX31) platforms" > select ARCH_MX31 > + select MXC_ULPI > help > Include support for Phytec pcm037 platform. This includes > specific configurations for the board and its peripherals. > diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c > index b5227d8..dd16452 100644 > --- a/arch/arm/mach-mx3/pcm037.c > +++ b/arch/arm/mach-mx3/pcm037.c > @@ -28,6 +28,7 @@ > #include <linux/interrupt.h> > #include <linux/i2c.h> > #include <linux/i2c/at24.h> > +#include <linux/delay.h> > > #include <mach/hardware.h> > #include <asm/mach-types.h> > @@ -43,6 +44,8 @@ > #ifdef CONFIG_I2C_IMX > #include <mach/i2c.h> > #endif > +#include <mach/mxc_ehci.h> > +#include <mach/ulpi.h> > > #include "devices.h" > > @@ -210,6 +213,136 @@ static int uart2_pins[] = { > MX31_PIN_CSPI3_MISO__TXD3 > }; > > +static int isp1504_set_vbus_power(void __iomem *view, int on) > +{ > + int vid, pid, ret = 0; > + > + vid = (ulpi_read(ISP1504_VID_HIGH, view) << 8) | > + ulpi_read(ISP1504_VID_LOW, view); > + pid = (ulpi_read(ISP1504_PID_HIGH, view) << 8) | > + ulpi_read(ISP1504_PID_LOW, view); > + > + pr_info("ULPI Vendor ID 0x%x Product ID 0x%x\n", vid, pid); > + if (vid != 0x4cc || pid != 0x1504) { > + pr_err("No ISP1504 found\n"); > + return -1; > + } > + > + if (on) { > + ret = ulpi_set(DRV_VBUS_EXT | /* enable external Vbus */ > + DRV_VBUS | /* enable internal Vbus */ > + USE_EXT_VBUS_IND | /* use external indicator */ > + CHRG_VBUS, /* charge Vbus */ > + ISP1504_OTGCTL, view); > + } else { > + ret = ulpi_clear(DRV_VBUS_EXT | /* disable external Vbus */ > + DRV_VBUS, /* disable internal Vbus */ > + ISP1504_OTGCTL, view); > + > + ret |= ulpi_set(USE_EXT_VBUS_IND | /* use external indicator */ > + DISCHRG_VBUS, /* discharge Vbus */ > + ISP1504_OTGCTL, view); > + } > + > + return ret; > +} > + > +static int pcm037_otg_init(struct platform_device *pdev) > +{ > + int ret; > + unsigned int tmp; > + > + tmp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x600); > + tmp &= ~((3 << 21) | 1); > + tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 11) | (1 << 20); > + writel(tmp, IO_ADDRESS(OTG_BASE_ADDR) + 0x600); > + > + tmp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x184); > + tmp &= ~(3 << 30); > + tmp |= 2 << 30; > + writel(tmp, IO_ADDRESS(OTG_BASE_ADDR) + 0x184); ...some would say "no way! use macros!", I would be happy, if you commented these. Or do both to make us all happy:-) Have you also tested this in pure device mode? CanI pull these from some tree or at least to which tree / branch can I apply this series? > + > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA0__USBOTG_DATA0); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA1__USBOTG_DATA1); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA2__USBOTG_DATA2); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA3__USBOTG_DATA3); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA4__USBOTG_DATA4); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA5__USBOTG_DATA5); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA6__USBOTG_DATA6); > + mxc_iomux_mode(MX31_PIN_USBOTG_DATA7__USBOTG_DATA7); > + mxc_iomux_mode(MX31_PIN_USBOTG_CLK__USBOTG_CLK); > + mxc_iomux_mode(MX31_PIN_USBOTG_DIR__USBOTG_DIR); > + mxc_iomux_mode(MX31_PIN_USBOTG_NXT__USBOTG_NXT); > + mxc_iomux_mode(MX31_PIN_USBOTG_STP__USBOTG_STP); > + > + mdelay(10); > + > + ret = isp1504_set_vbus_power(IO_ADDRESS(OTG_BASE_ADDR + 0x170), 1); > + > + return 0; > +} > + > +struct mxc_usbh_platform_data otg_pdata = { > + .init = pcm037_otg_init, > +}; > + > +static int pcm037_usbh2_init(struct platform_device *pdev) > +{ > + int ret; > + unsigned int tmp; > + > + tmp = readl(IO_ADDRESS(IOMUXC_BASE_ADDR + 0x8)); > + tmp |= 1 << 11; > + writel(tmp, IO_ADDRESS(IOMUXC_BASE_ADDR + 0x8)); Hm, isn't this what the mxc_iomux_set_gpr() function is for? > + > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC)); > + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC)); > + > +#define H2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) > + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, H2_PAD_CFG); > + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, H2_PAD_CFG); > + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, H2_PAD_CFG); > + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, H2_PAD_CFG); > + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, H2_PAD_CFG); /* USBH2_DATA0 */ > + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, H2_PAD_CFG); /* USBH2_DATA1 */ > + mxc_iomux_set_pad(MX31_PIN_SRXD6, H2_PAD_CFG); /* USBH2_DATA2 */ > + mxc_iomux_set_pad(MX31_PIN_STXD6, H2_PAD_CFG); /* USBH2_DATA3 */ > + mxc_iomux_set_pad(MX31_PIN_SFS3, H2_PAD_CFG); /* USBH2_DATA4 */ > + mxc_iomux_set_pad(MX31_PIN_SCK3, H2_PAD_CFG); /* USBH2_DATA5 */ > + mxc_iomux_set_pad(MX31_PIN_SRXD3, H2_PAD_CFG); /* USBH2_DATA6 */ > + mxc_iomux_set_pad(MX31_PIN_STXD3, H2_PAD_CFG); /* USBH2_DATA7 */ > + > + tmp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x600); > + tmp &= ~((3 << 21) | 1); > + tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20); > + writel(tmp, IO_ADDRESS(OTG_BASE_ADDR) + 0x600); > + > + tmp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x584); > + tmp &= ~(3 << 30); > + tmp |= 2 << 30; > + writel(tmp, IO_ADDRESS(OTG_BASE_ADDR) + 0x584); Comments here too please. Thanks Guennadi > + > + mdelay(10); > + > + ret = isp1504_set_vbus_power(IO_ADDRESS(OTG_BASE_ADDR + 0x570), 1); > + > + return 0; > +} > + > +struct mxc_usbh_platform_data usbh2_pdata = { > + .init = pcm037_usbh2_init, > +}; > + > /* > * Board specific initialization. > */ > @@ -239,6 +372,8 @@ static void __init mxc_board_init(void) > #endif > mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info); > mxc_register_device(&mxcsdhc_device0, &sdhc_pdata); > + mxc_register_device(&mxc_otg, &otg_pdata); > + mxc_register_device(&mxc_usbh2, &usbh2_pdata); > } > > static void __init pcm037_timer_init(void) > -- > 1.6.2.1 > --- Guennadi Liakhovetski, Ph.D. Freelance Open-Source Software Developer http://www.open-technology.de/ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html