The ARC USB OTG Core has support for accessing ULPI tranceivers through so called ULPI viewports. As the ARC core is found on other systems aswell, this is not Freescale specific and should live under drivers/usb instead. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- arch/arm/mach-mx2/Kconfig | 1 + arch/arm/plat-mxc/Kconfig | 2 + arch/arm/plat-mxc/Makefile | 1 + arch/arm/plat-mxc/include/mach/ulpi.h | 31 +++++++++ arch/arm/plat-mxc/ulpi.c | 120 +++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-mxc/include/mach/ulpi.h create mode 100644 arch/arm/plat-mxc/ulpi.c diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig index 42a7888..a8e06d0 100644 --- a/arch/arm/mach-mx2/Kconfig +++ b/arch/arm/mach-mx2/Kconfig @@ -40,6 +40,7 @@ choice config MACH_PCM970_BASEBOARD prompt "PHYTEC PCM970 development board" bool + select MXC_ULPI help This adds board specific devices that can be found on Phytec's PCM970 evaluation board. diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 17d0e99..b5668a8 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -51,4 +51,6 @@ config MXC_PWM help Enable support for the i.MX PWM controller(s). +config MXC_ULPI + bool endif diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 0554063..3ce830a 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -8,3 +8,4 @@ obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_MXC_PWM) += pwm.o +obj-$(CONFIG_MXC_ULPI) += ulpi.o diff --git a/arch/arm/plat-mxc/include/mach/ulpi.h b/arch/arm/plat-mxc/include/mach/ulpi.h new file mode 100644 index 0000000..0397fdb --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/ulpi.h @@ -0,0 +1,31 @@ +#ifndef __MACH_ULPI_H +#define __MACH_ULPI_H + +int ulpi_set(u8 bits, int reg, void __iomem *view); +int ulpi_clear(u8 bits, int reg, void __iomem *view); +int ulpi_read(int reg, void __iomem *view); + +/* ISP 1504 register addresses */ +#define ISP1504_VID_LOW 0x00 /* Vendor ID low */ +#define ISP1504_VID_HIGH 0x01 /* Vendor ID high */ +#define ISP1504_PID_LOW 0x02 /* Product ID low */ +#define ISP1504_PID_HIGH 0x03 /* Product ID high */ +#define ISP1504_ITFCTL 0x07 /* Interface Control */ +#define ISP1504_OTGCTL 0x0A /* OTG Control */ + +/* add to above register address to access Set/Clear functions */ +#define ISP1504_REG_SET 0x01 +#define ISP1504_REG_CLEAR 0x02 + +/* 1504 OTG Control Register bits */ +#define USE_EXT_VBUS_IND (1 << 7) /* Use ext. Vbus indicator */ +#define DRV_VBUS_EXT (1 << 6) /* Drive Vbus external */ +#define DRV_VBUS (1 << 5) /* Drive Vbus */ +#define CHRG_VBUS (1 << 4) /* Charge Vbus */ +#define DISCHRG_VBUS (1 << 3) /* Discharge Vbus */ +#define DM_PULL_DOWN (1 << 2) /* enable DM Pull Down */ +#define DP_PULL_DOWN (1 << 1) /* enable DP Pull Down */ +#define ID_PULL_UP (1 << 0) /* enable ID Pull Up */ + +#endif /* __MACH_ULPI_H */ + diff --git a/arch/arm/plat-mxc/ulpi.c b/arch/arm/plat-mxc/ulpi.c new file mode 100644 index 0000000..355fda1 --- /dev/null +++ b/arch/arm/plat-mxc/ulpi.c @@ -0,0 +1,120 @@ +/* + * Copyright 2008 Sascha Hauer, Pengutronix <s.hauer@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include <mach/ulpi.h> + +/* ULPIVIEW register bits */ +#define ULPIVW_WU (1 << 31) /* Wakeup */ +#define ULPIVW_RUN (1 << 30) /* read/write run */ +#define ULPIVW_WRITE (1 << 29) /* 0 = read 1 = write */ +#define ULPIVW_SS (1 << 27) /* SyncState */ +#define ULPIVW_PORT_MASK 0x07 /* Port field */ +#define ULPIVW_PORT_SHIFT 24 +#define ULPIVW_ADDR_MASK 0xFF /* data address field */ +#define ULPIVW_ADDR_SHIFT 16 +#define ULPIVW_RDATA_MASK 0xFF /* read data field */ +#define ULPIVW_RDATA_SHIFT 8 +#define ULPIVW_WDATA_MASK 0xFF /* write data field */ +#define ULPIVW_WDATA_SHIFT 0 + +static int ulpi_poll(void __iomem *view, uint32_t bit) +{ + uint32_t data; + int timeout = 10000; + + data = __raw_readl(view); + while (data & bit) { + if (!timeout--) + return -ETIMEDOUT; + + udelay(1); + data = __raw_readl(view); + } + return (data >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK; +} + +int ulpi_read(int reg, void __iomem *view) +{ + int ret; + + /* make sure interface is running */ + if (!(__raw_readl(view) && ULPIVW_SS)) { + __raw_writel(ULPIVW_WU, view); + + /* wait for wakeup */ + ret = ulpi_poll(view, ULPIVW_WU); + if (ret < 0) + return ret; + } + + /* read the register */ + __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view); + + /* wait for completion */ + return ulpi_poll(view, ULPIVW_RUN); +} +EXPORT_SYMBOL(ulpi_read); + +int ulpi_set(u8 bits, int reg, void __iomem *view) +{ + int ret; + + /* make sure the interface is running */ + if (!(__raw_readl(view) && ULPIVW_SS)) { + __raw_writel(ULPIVW_WU, view); + /* wait for wakeup */ + ret = ulpi_poll(view, ULPIVW_WU); + if (ret < 0) + return ret; + } + + __raw_writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_SET) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + /* wait for completion */ + ret = ulpi_poll(view, ULPIVW_RUN); + if (ret < 0) + return ret; + return 0; +} +EXPORT_SYMBOL(ulpi_set); + +int ulpi_clear(u8 bits, int reg, void __iomem *view) +{ + int ret; + + __raw_writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_CLEAR) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + /* wait for completion */ + ret = ulpi_poll(view, ULPIVW_RUN); + if (ret < 0) + return ret; + return 0; +} +EXPORT_SYMBOL(ulpi_clear); + -- 1.6.2.1 -- 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