This patch extends the generic ulpi driver with support for Function and Interface control of upli phy. Signed-off-by: Igor Grinberg <grinberg@xxxxxxxxxxxxxx> Signed-off-by: Mike Rapoport <mike@xxxxxxxxxxxxxx> --- arch/arm/mach-mx2/mach-pca100.c | 10 ++++- arch/arm/mach-mx3/mach-armadillo5x0.c | 10 ++++- arch/arm/mach-mx3/mach-mx31lite.c | 5 ++- arch/arm/mach-mx3/mach-mx31moboard.c | 5 ++- arch/arm/mach-mx3/mach-pcm037.c | 10 ++++- arch/arm/mach-mx3/mach-pcm043.c | 5 ++- drivers/usb/otg/Kconfig | 2 - drivers/usb/otg/ulpi.c | 64 +++++++++++++++++++++++++++++---- include/linux/usb/ulpi.h | 25 ++++++++++++- 9 files changed, 117 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-mx2/mach-pca100.c b/arch/arm/mach-mx2/mach-pca100.c index 778fff2..0f2ece0 100644 --- a/arch/arm/mach-mx2/mach-pca100.c +++ b/arch/arm/mach-mx2/mach-pca100.c @@ -356,13 +356,19 @@ static void __init pca100_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-mx3/mach-armadillo5x0.c b/arch/arm/mach-mx3/mach-armadillo5x0.c index 5f72ec9..81904d4 100644 --- a/arch/arm/mach-mx3/mach-armadillo5x0.c +++ b/arch/arm/mach-mx3/mach-armadillo5x0.c @@ -552,9 +552,15 @@ static void __init armadillo5x0_init(void) /* USB */ #if defined(CONFIG_USB_ULPI) usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_otg_host, &usbotg_pdata); mxc_register_device(&mxc_usbh2, &usbh2_pdata); diff --git a/arch/arm/mach-mx3/mach-mx31lite.c b/arch/arm/mach-mx3/mach-mx31lite.c index 2b6d114..9413be4 100644 --- a/arch/arm/mach-mx3/mach-mx31lite.c +++ b/arch/arm/mach-mx3/mach-mx31lite.c @@ -261,7 +261,10 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) /* USB */ usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-mx3/mach-mx31moboard.c b/arch/arm/mach-mx3/mach-mx31moboard.c index fccb920..620f21a 100644 --- a/arch/arm/mach-mx3/mach-mx31moboard.c +++ b/arch/arm/mach-mx3/mach-mx31moboard.c @@ -391,7 +391,10 @@ static struct mxc_usbh_platform_data usbh2_pdata = { static int __init moboard_usbh2_init(void) { usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); return mxc_register_device(&mxc_usbh2, &usbh2_pdata); } diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-mx3/mach-pcm037.c index 2df1ec5..33471c4 100644 --- a/arch/arm/mach-mx3/mach-pcm037.c +++ b/arch/arm/mach-mx3/mach-pcm037.c @@ -657,13 +657,19 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-mx3/mach-pcm043.c index 1bf1ec2..63d8719 100644 --- a/arch/arm/mach-mx3/mach-pcm043.c +++ b/arch/arm/mach-mx3/mach-pcm043.c @@ -379,7 +379,10 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + USB_OTG_DRV_VBUS | + USB_OTG_DRV_VBUS_EXT, + ULPI_IC_DEFAULT, + ULPI_FC_DEFAULT); mxc_register_device(&mxc_otg_host, &otg_pdata); } diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 3d2d3e5..3b12895 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -49,8 +49,6 @@ config USB_ULPI Enable this to support ULPI connected USB OTG transceivers which are likely found on embedded boards. - The only chip currently supported is NXP's ISP1504 - config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c index 9010225..0e7a826 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/otg/ulpi.c @@ -34,6 +34,7 @@ #define ULPI_VID_HIGH 0x01 /* Vendor ID high */ #define ULPI_PID_LOW 0x02 /* Product ID low */ #define ULPI_PID_HIGH 0x03 /* Product ID high */ +#define ULPI_FUNCTL 0x04 /* Function Control */ #define ULPI_ITFCTL 0x07 /* Interface Control */ #define ULPI_OTGCTL 0x0A /* OTG Control */ @@ -60,25 +61,51 @@ static unsigned int ulpi_ids[] = { ULPI_ID(0x04cc, 0x1504), /* NXP ISP1504 */ }; -static int ulpi_set_flags(struct otg_transceiver *otg) +static int ulpi_set_otg_flags(struct otg_transceiver *otg) { + unsigned int otg_flags = otg->flags & 0xff; unsigned int flags = 0; - if (otg->flags & USB_OTG_PULLUP_ID) + if (otg_flags & USB_OTG_PULLUP_ID) flags |= ID_PULL_UP; - if (otg->flags & USB_OTG_PULLDOWN_DM) + if (otg_flags & USB_OTG_PULLDOWN_DM) flags |= DM_PULL_DOWN; - if (otg->flags & USB_OTG_PULLDOWN_DP) + if (otg_flags & USB_OTG_PULLDOWN_DP) flags |= DP_PULL_DOWN; - if (otg->flags & USB_OTG_EXT_VBUS_INDICATOR) + if (otg_flags & USB_OTG_EXT_VBUS_INDICATOR) flags |= USE_EXT_VBUS_IND; return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET); } +static int ulpi_set_fc_flags(struct otg_transceiver *otg) +{ + unsigned int fc_flags = (otg->flags >> 16) & 0xff; + + /* + * Bit 6 in Function Control Register is SuspendM + * 1 - Powered. + * 0 - Suspend. + */ + fc_flags |= (1 << 6); + + return otg_io_write(otg, fc_flags, ULPI_FUNCTL + ULPI_REG_SET); +} + +static inline int ulpi_set_flags(struct otg_transceiver *otg) +{ + int ret; + + ret = ulpi_set_otg_flags(otg); + if (ret) + return ret; + + return ulpi_set_fc_flags(otg); +} + static int ulpi_init(struct otg_transceiver *otg) { int i, vid, pid; @@ -98,6 +125,28 @@ static int ulpi_init(struct otg_transceiver *otg) return -ENODEV; } +static int ulpi_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + unsigned int ic_flags = (otg->flags >> 8) & 0xff; + unsigned int ic = ic_flags & ~0x7; + + if (!host) { + otg->host = NULL; + return 0; + } + + otg->host = host; + + if (ic_flags & ULPI_IC_3PIN) + ic |= ULPI_IC_3PIN; + else if (ic_flags & ULPI_IC_CARKIT) + ic |= ULPI_IC_CARKIT; + else + ic |= ULPI_IC_6PIN; + + return otg_io_write(otg, ic, ULPI_ITFCTL + ULPI_REG_SET); +} + static int ulpi_set_vbus(struct otg_transceiver *otg, bool on) { unsigned int flags = otg_io_read(otg, ULPI_OTGCTL); @@ -117,7 +166,7 @@ static int ulpi_set_vbus(struct otg_transceiver *otg, bool on) struct otg_transceiver * otg_ulpi_create(struct otg_io_access_ops *ops, - unsigned int flags) + u8 otg_flags, u8 ic_flags, u8 fc_flags) { struct otg_transceiver *otg; @@ -126,9 +175,10 @@ otg_ulpi_create(struct otg_io_access_ops *ops, return NULL; otg->label = "ULPI"; - otg->flags = flags; + otg->flags = otg_flags | (ic_flags << 8) | (fc_flags << 16); otg->io_ops = ops; otg->init = ulpi_init; + otg->set_host = ulpi_set_host; otg->set_vbus = ulpi_set_vbus; return otg; diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h index 20675c6..8318067 100644 --- a/include/linux/usb/ulpi.h +++ b/include/linux/usb/ulpi.h @@ -1,7 +1,30 @@ #ifndef __LINUX_USB_ULPI_H #define __LINUX_USB_ULPI_H +/* ULPI Function Control Register bits */ +#define ULPI_FC_HS 0 /* Enable HS tcvr */ +#define ULPI_FC_FS (0x1 << 0) /* Enable FS tcvr */ +#define ULPI_FC_LS (0x2 << 0) /* Enable LS tcvr */ +#define ULPI_FC_FS_LS (0x3 << 0) /* Enable FS tcvr for LS packets */ +#define ULPI_FC_TRM_SEL (0x1 << 2) /* Internal pullup and HS termination */ +#define ULPI_FC_NODRV (0x1 << 3) /* Non-Driving Operation */ +#define ULPI_FC_NONRZI (0x1 << 4) /* Disable bit-stuff and NRZI encode */ +#define ULPI_FC_RESET (0x1 << 5) /* Reset the UTMI core */ +#define ULPI_FC_DEFAULT 0x41 /* Function Control Register Default */ + + +/* ULPI Interface Register bits */ +#define ULPI_IC_6PIN (1 << 0) /* XCVR 6 serial pin mode */ +#define ULPI_IC_3PIN (1 << 1) /* XCVR 3 serial pin mode */ +#define ULPI_IC_CARKIT (1 << 2) /* Carkit mode */ +#define ULPI_IC_CLKSPND (1 << 3) /* Active low clock suspend */ +#define ULPI_IC_AUTORES (1 << 4) /* PHY auto transmit resume signal */ +#define ULPI_IC_VBUSINV (1 << 5) /* Invert the external VBUS indicator */ +#define ULPI_IC_INDPT (1 << 6) /* Indicator Pass Through */ +#define ULPI_IC_DISPRT (1 << 7) /* Interface Protect Disable */ +#define ULPI_IC_DEFAULT 0x0 /* Interface Control Register Default */ + struct otg_transceiver *otg_ulpi_create(struct otg_io_access_ops *ops, - unsigned int flags); + u8 fc_flags, u8 ic_flags, u8 otg_flags); #endif /* __LINUX_USB_ULPI_H */ -- 1.6.4.4 -- 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