From 7df5cf35de466db4d13b4fc94862248f4445a996 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 6 Nov 2012 13:48:23 +0000 Subject: am33xx: init OTG hardware and new musb gadget driver AM33xx has support for dual port MUSB OTG controller. This patch adds initialization for the controller using new MUSB gadget driver and ether gadget. Signed-off-by: Ilya Yanok --- arch/arm/cpu/armv7/am33xx/board.c | 85 +++++++++++++++++++++++++++++++++++++++ arch/arm/cpu/armv7/am33xx/clock.c | 8 ++++ 2 files changed, 93 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c index e4c123c..da5bc73 100644 --- a/arch/arm/cpu/armv7/am33xx/board.c +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -33,6 +33,11 @@ #include #include #include +#include +#include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -63,3 +68,83 @@ void setup_clocks_for_console(void) /* Not yet implemented */ return; } + +/* AM33XX has two MUSB controllers which can be host or gadget */ +#if (defined(CONFIG_MUSB_GADGET) || defined(CONFIG_MUSB_HOST)) && \ + (defined(CONFIG_AM335X_USB0) || defined(CONFIG_AM335X_USB1)) +static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; + +/* USB 2.0 PHY Control */ +#define CM_PHY_PWRDN (1 << 0) +#define CM_PHY_OTG_PWRDN (1 << 1) +#define OTGVDET_EN (1 << 19) +#define OTGSESSENDEN (1 << 20) + +static void am33xx_usb_set_phy_power(u8 on, u32 *reg_addr) +{ + if (on) { + clrsetbits_le32(reg_addr, CM_PHY_PWRDN | CM_PHY_OTG_PWRDN, + OTGVDET_EN | OTGSESSENDEN); + } else { + clrsetbits_le32(reg_addr, 0, CM_PHY_PWRDN | CM_PHY_OTG_PWRDN); + } +} + +static struct musb_hdrc_config musb_config = { + .multipoint = 1, + .dyn_fifo = 1, + .num_eps = 16, + .ram_bits = 12, +}; + +#ifdef CONFIG_AM335X_USB0 +static void am33xx_otg0_set_phy_power(u8 on) +{ + am33xx_usb_set_phy_power(on, &cdev->usb_ctrl0); +} + +struct omap_musb_board_data otg0_board_data = { + .set_phy_power = am33xx_otg0_set_phy_power, +}; + +static struct musb_hdrc_platform_data otg0_plat = { + .mode = CONFIG_AM335X_USB0_MODE, + .config = &musb_config, + .power = 50, + .platform_ops = &musb_dsps_ops, + .board_data = &otg0_board_data, +}; +#endif + +#ifdef CONFIG_AM335X_USB1 +static void am33xx_otg1_set_phy_power(u8 on) +{ + am33xx_usb_set_phy_power(on, &cdev->usb_ctrl1); +} + +struct omap_musb_board_data otg1_board_data = { + .set_phy_power = am33xx_otg1_set_phy_power, +}; + +static struct musb_hdrc_platform_data otg1_plat = { + .mode = CONFIG_AM335X_USB1_MODE, + .config = &musb_config, + .power = 50, + .platform_ops = &musb_dsps_ops, + .board_data = &otg1_board_data, +}; +#endif +#endif + +int arch_misc_init(void) +{ +#ifdef CONFIG_AM335X_USB0 + musb_register(&otg0_plat, &otg0_board_data, + (void *)AM335X_USB0_OTG_BASE); +#endif +#ifdef CONFIG_AM335X_USB1 + musb_register(&otg1_plat, &otg1_board_data, + (void *)AM335X_USB1_OTG_BASE); +#endif + return 0; +} diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c index bc2abb6..0b4cb4e 100644 --- a/arch/arm/cpu/armv7/am33xx/clock.c +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -40,6 +40,7 @@ #define CLK_MODE_MASK 0xfffffff8 #define CLK_DIV_SEL 0xFFFFFFE0 #define CPGMAC0_IDLE 0x30000 +#define DPLL_CLKDCOLDO_GATE_CTRL 0x300 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER; const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP; @@ -194,6 +195,11 @@ static void enable_per_clocks(void) writel(PRCM_MOD_EN, &cmrtc->rtcclkctrl); while (readl(&cmrtc->rtcclkctrl) != PRCM_MOD_EN) ; + + /* MUSB */ + writel(PRCM_MOD_EN, &cmper->usb0clkctrl); + while (readl(&cmper->usb0clkctrl) != PRCM_MOD_EN) + ; } static void mpu_pll_config(void) @@ -290,6 +296,8 @@ static void per_pll_config(void) while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK) ; + + writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper); } void ddr_pll_config(unsigned int ddrpll_m) -- cgit v1.1 From 08fc71711a5665f695487ea2e4bcb27f43942db7 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 6 Nov 2012 13:48:27 +0000 Subject: OMAP3: am35x: add musb functions AM35XX specific functions for integrated USB PHY/MUSB IP. Signed-off-by: Ilya Yanok --- arch/arm/cpu/armv7/omap3/Makefile | 1 + arch/arm/cpu/armv7/omap3/am35x_musb.c | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 arch/arm/cpu/armv7/omap3/am35x_musb.c (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/omap3/Makefile b/arch/arm/cpu/armv7/omap3/Makefile index ac597be..de167ee 100644 --- a/arch/arm/cpu/armv7/omap3/Makefile +++ b/arch/arm/cpu/armv7/omap3/Makefile @@ -38,6 +38,7 @@ endif COBJS-$(CONFIG_DRIVER_TI_EMAC) += emac.o COBJS-$(CONFIG_EMIF4) += emif4.o COBJS-$(CONFIG_SDRC) += sdrc.o +COBJS-$(CONFIG_USB_MUSB_AM35X) += am35x_musb.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS) $(COBJS-y) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/omap3/am35x_musb.c b/arch/arm/cpu/armv7/omap3/am35x_musb.c new file mode 100644 index 0000000..7183c4f --- /dev/null +++ b/arch/arm/cpu/armv7/omap3/am35x_musb.c @@ -0,0 +1,75 @@ +/* + * This file configures the internal USB PHY in AM35X. + * + * Copyright (C) 2012 Ilya Yanok + * + * Based on omap_phy_internal.c code from Linux by + * Hema HK + * + * 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. + * + */ + +#include +#include +#include + +void am35x_musb_reset(void) +{ + /* Reset the musb interface */ + clrsetbits_le32(&am35x_scm_general_regs->ip_sw_reset, + 0, USBOTGSS_SW_RST); + clrsetbits_le32(&am35x_scm_general_regs->ip_sw_reset, + USBOTGSS_SW_RST, 0); +} + +void am35x_musb_phy_power(u8 on) +{ + unsigned long start = get_timer(0); + + if (on) { + /* + * Start the on-chip PHY and its PLL. + */ + clrsetbits_le32(&am35x_scm_general_regs->devconf2, + CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN, + CONF2_PHY_PLLON); + + debug("Waiting for PHY clock good...\n"); + while (!(readl(&am35x_scm_general_regs->devconf2) + & CONF2_PHYCLKGD)) { + + if (get_timer(start) > CONFIG_SYS_HZ / 10) { + printf("musb PHY clock good timed out\n"); + break; + } + } + } else { + /* + * Power down the on-chip PHY. + */ + clrsetbits_le32(&am35x_scm_general_regs->devconf2, + CONF2_PHY_PLLON, + CONF2_PHYPWRDN | CONF2_OTGPWRDN); + } +} + +void am35x_musb_clear_irq(void) +{ + clrsetbits_le32(&am35x_scm_general_regs->lvl_intr_clr, + 0, USBOTGSS_INT_CLR); + readl(&am35x_scm_general_regs->lvl_intr_clr); +} + -- cgit v1.1 From fa5e2845a867a3715240ff221aaec2825b5c73df Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 30 Nov 2012 18:17:07 +0000 Subject: mxs: i2c: Implement algorithm to set up arbitrary i2c speed This algorithm computes the values of TIMING{0,1,2} registers for the MX28 I2C block. This algorithm was derived by using a scope, but the result seems correct. The resulting values programmed into the registers do not correlate with the contents in datasheet. When using the values from the datasheet, the I2C clock were completely wrong. Signed-off-by: Marek Vasut Cc: Stefano Babic Cc: Fabio Estevam Cc: Wolfgang Denk --- arch/arm/cpu/arm926ejs/mxs/clock.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c index bfea6ab..4ff19c3 100644 --- a/arch/arm/cpu/arm926ejs/mxs/clock.c +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -333,6 +333,8 @@ uint32_t mxc_get_clock(enum mxc_clock clk) return mx28_get_sspclk(MXC_SSPCLK2); case MXC_SSP3_CLK: return mx28_get_sspclk(MXC_SSPCLK3); + case MXC_XTAL_CLK: + return XTAL_FREQ_KHZ * 1000; } return 0; -- cgit v1.1 From 83d745dd88743a8355a7e58bcb17d475c17b979d Mon Sep 17 00:00:00 2001 From: Piotr Wilczek Date: Tue, 20 Nov 2012 02:19:02 +0000 Subject: exynos:clock: Add i2c clock This patch adds i2c clock for Exynos4 Signed-off-by: Piotr Wilczek Signed-off-by: Kyungmin Park CC: Minkyu Kang --- arch/arm/cpu/armv7/exynos/clock.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 4f3b451..21e45d2 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -732,6 +732,21 @@ static unsigned long exynos5_get_i2c_clk(void) return aclk_66; } +static unsigned long exynos4_get_i2c_clk(void) +{ + struct exynos4_clock *clk = + (struct exynos4_clock *)samsung_get_base_clock(); + unsigned long sclk, aclk_100; + unsigned int ratio; + + sclk = get_pll_clk(APLL); + + ratio = (readl(&clk->div_top)) >> 4; + ratio &= 0xf; + aclk_100 = sclk / (ratio + 1); + return aclk_100; +} + unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -752,6 +767,8 @@ unsigned long get_i2c_clk(void) { if (cpu_is_exynos5()) { return exynos5_get_i2c_clk(); + } else if (cpu_is_exynos4()) { + return exynos4_get_i2c_clk(); } else { debug("I2C clock is not set for this CPU\n"); return 0; -- cgit v1.1 From 89bd58a1e9cb482109498ac38b38fc39d22fb421 Mon Sep 17 00:00:00 2001 From: Piotr Wilczek Date: Tue, 20 Nov 2012 02:19:04 +0000 Subject: exynos:pinmux: Add pinmux support for i2c This patch add pinmux for I2C for Exynos4 Signed-off-by: Piotr Wilczek Signed-off-by: Kyungmin Park CC: Minkyu Kang --- arch/arm/cpu/armv7/exynos/pinmux.c | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 7776add..44ce072 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -265,10 +265,74 @@ static int exynos5_pinmux_config(int peripheral, int flags) return 0; } +static void exynos4_i2c_config(int peripheral, int flags) +{ + struct exynos4_gpio_part1 *gpio1 = + (struct exynos4_gpio_part1 *) samsung_get_base_gpio_part1(); + + switch (peripheral) { + case PERIPH_ID_I2C0: + s5p_gpio_cfg_pin(&gpio1->d1, 0, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->d1, 1, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C1: + s5p_gpio_cfg_pin(&gpio1->d1, 2, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->d1, 3, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C2: + s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C3: + s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C4: + s5p_gpio_cfg_pin(&gpio1->b, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->b, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C5: + s5p_gpio_cfg_pin(&gpio1->b, 6, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->b, 7, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C6: + s5p_gpio_cfg_pin(&gpio1->c1, 3, GPIO_FUNC(0x4)); + s5p_gpio_cfg_pin(&gpio1->c1, 4, GPIO_FUNC(0x4)); + break; + case PERIPH_ID_I2C7: + s5p_gpio_cfg_pin(&gpio1->d0, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->d0, 3, GPIO_FUNC(0x3)); + break; + } +} + +static int exynos4_pinmux_config(int peripheral, int flags) +{ + switch (peripheral) { + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + exynos4_i2c_config(peripheral, flags); + break; + default: + debug("%s: invalid peripheral %d", __func__, peripheral); + return -1; + } + + return 0; +} + int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) return exynos5_pinmux_config(peripheral, flags); + else if (cpu_is_exynos4()) + return exynos4_pinmux_config(peripheral, flags); else { debug("pinmux functionality not supported\n"); return -1; -- cgit v1.1