diff options
Diffstat (limited to 'arch/arm/mach-mx5')
-rw-r--r-- | arch/arm/mach-mx5/board-mx51_babbage.c | 167 | ||||
-rw-r--r-- | arch/arm/mach-mx5/clock-mx51.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-mx5/devices.c | 109 | ||||
-rw-r--r-- | arch/arm/mach-mx5/devices.h | 4 |
4 files changed, 323 insertions, 2 deletions
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index ee67a71db80..ed885f9d7b7 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -12,11 +12,16 @@ #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/fsl_devices.h> #include <mach/common.h> #include <mach/hardware.h> #include <mach/imx-uart.h> #include <mach/iomux-mx51.h> +#include <mach/mxc_ehci.h> #include <asm/irq.h> #include <asm/setup.h> @@ -26,6 +31,18 @@ #include "devices.h" +#define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ +#define BABBAGE_USBH1_STP (0*32 + 27) /* GPIO_1_27 */ +#define BABBAGE_PHY_RESET (1*32 +5) /* GPIO_2_5 */ + +/* USB_CTRL_1 */ +#define MX51_USB_CTRL_1_OFFSET 0x10 +#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) + +#define MX51_USB_PLLDIV_12_MHZ 0x00 +#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 +#define MX51_USB_PLL_DIV_24_MHZ 0x02 + static struct platform_device *devices[] __initdata = { &mxc_fec_device, }; @@ -46,6 +63,22 @@ static struct pad_desc mx51babbage_pads[] = { MX51_PAD_EIM_D26__UART3_TXD, MX51_PAD_EIM_D27__UART3_RTS, MX51_PAD_EIM_D24__UART3_CTS, + + /* USB HOST1 */ + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + + /* USB HUB reset line*/ + MX51_PAD_GPIO_1_7__GPIO1_7, }; /* Serial ports */ @@ -66,15 +99,149 @@ static inline void mxc_init_imx_uart(void) } #endif /* SERIAL_IMX */ +static int gpio_usbh1_active(void) +{ + struct pad_desc usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO_1_27; + struct pad_desc phyreset_gpio = MX51_PAD_EIM_D21__GPIO_2_5; + int ret; + + /* Set USBH1_STP to GPIO and toggle it */ + mxc_iomux_v3_setup_pad(&usbh1stp_gpio); + ret = gpio_request(BABBAGE_USBH1_STP, "usbh1_stp"); + + if (ret) { + pr_debug("failed to get MX51_PAD_USBH1_STP__GPIO_1_27: %d\n", ret); + return ret; + } + gpio_direction_output(BABBAGE_USBH1_STP, 0); + gpio_set_value(BABBAGE_USBH1_STP, 1); + msleep(100); + gpio_free(BABBAGE_USBH1_STP); + + /* De-assert USB PHY RESETB */ + mxc_iomux_v3_setup_pad(&phyreset_gpio); + ret = gpio_request(BABBAGE_PHY_RESET, "phy_reset"); + + if (ret) { + pr_debug("failed to get MX51_PAD_EIM_D21__GPIO_2_5: %d\n", ret); + return ret; + } + gpio_direction_output(BABBAGE_PHY_RESET, 1); + return 0; +} + +static inline void babbage_usbhub_reset(void) +{ + int ret; + + /* Bring USB hub out of reset */ + ret = gpio_request(BABBAGE_USB_HUB_RESET, "GPIO1_7"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret); + return; + } + gpio_direction_output(BABBAGE_USB_HUB_RESET, 0); + + /* USB HUB RESET - De-assert USB HUB RESET_N */ + msleep(1); + gpio_set_value(BABBAGE_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(BABBAGE_USB_HUB_RESET, 1); +} + +/* This function is board specific as the bit mask for the plldiv will also +be different for other Freescale SoCs, thus a common bitmask is not +possible and cannot get place in /plat-mxc/ehci.c.*/ +static int initialize_otg_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + u32 usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* Set the PHY clock to 19.2MHz */ + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; + v |= MX51_USB_PLL_DIV_19_2_MHZ; + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + iounmap(usb_base); + return 0; +} + +static int initialize_usbh1_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + u32 usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* The clock for the USBH1 ULPI port will come externally from the PHY. */ + v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET); + __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET); + iounmap(usb_base); + return 0; +} + +static struct mxc_usbh_platform_data dr_utmi_config = { + .init = initialize_otg_port, + .portsc = MXC_EHCI_UTMI_16BIT, + .flags = MXC_EHCI_INTERNAL_PHY, +}; + +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, +}; + +static struct mxc_usbh_platform_data usbh1_config = { + .init = initialize_usbh1_port, + .portsc = MXC_EHCI_MODE_ULPI, + .flags = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD), +}; + +static int otg_mode_host; + +static int __init babbage_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", babbage_otg_mode); + /* * Board specific initialization. */ static void __init mxc_board_init(void) { + struct pad_desc usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; + mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, ARRAY_SIZE(mx51babbage_pads)); mxc_init_imx_uart(); platform_add_devices(devices, ARRAY_SIZE(devices)); + + if (otg_mode_host) + mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + else { + initialize_otg_port(NULL); + mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + } + + gpio_usbh1_active(); + mxc_register_device(&mxc_usbh1_device, &usbh1_config); + /* setback USBH1_STP to be function */ + mxc_iomux_v3_setup_pad(&usbh1stp); + babbage_usbhub_reset(); } static void __init mx51_babbage_timer_init(void) diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index 1ee6ce4087b..d9f612d3370 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -37,6 +37,7 @@ static struct clk lp_apm_clk; static struct clk periph_apm_clk; static struct clk ahb_clk; static struct clk ipg_clk; +static struct clk usboh3_clk; #define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ @@ -570,6 +571,35 @@ static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) return 0; } +static unsigned long clk_usboh3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1; + + return parent_rate / (prediv * podf); +} + +static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + static unsigned long get_high_reference_clock_rate(struct clk *clk) { return external_high_reference; @@ -691,6 +721,12 @@ static struct clk uart_root_clk = { .set_parent = _clk_uart_set_parent, }; +static struct clk usboh3_clk = { + .parent = &pll2_sw_clk, + .get_rate = clk_usboh3_get_rate, + .set_parent = _clk_usboh3_set_parent, +}; + static struct clk ahb_max_clk = { .parent = &ahb_clk, .enable_reg = MXC_CCM_CCGR0, @@ -779,6 +815,12 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) _REGISTER_CLOCK(NULL, "gpt", gpt_clk) _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) }; static void clk_tree_init(void) @@ -819,6 +861,9 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, clk_enable(&cpu_clk); clk_enable(&main_bus_clk); + /* set the usboh3_clk parent to pll2_sw_clk */ + clk_set_parent(&usboh3_clk, &pll2_sw_clk); + /* System timer */ mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), MX51_MXC_INT_GPT); diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index d6fd3961ade..7130449aacd 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -1,5 +1,6 @@ /* * Copyright 2009 Amit Kucheria <amit.kucheria@canonical.com> + * Copyright (C) 2010 Freescale Semiconductor, Inc. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License @@ -10,8 +11,11 @@ */ #include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/gpio.h> #include <mach/hardware.h> #include <mach/imx-uart.h> +#include <mach/irqs.h> static struct resource uart0[] = { { @@ -89,8 +93,109 @@ struct platform_device mxc_fec_device = { .resource = mxc_fec_resources, }; -/* Dummy definition to allow compiling in AVIC and TZIC simultaneously */ +static u64 usb_dma_mask = DMA_BIT_MASK(32); + +static struct resource usbotg_resources[] = { + { + .start = MX51_OTG_BASE_ADDR, + .end = MX51_OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +/* OTG gadget device */ +struct platform_device mxc_usbdr_udc_device = { + .name = "fsl-usb2-udc", + .id = -1, + .num_resources = ARRAY_SIZE(usbotg_resources), + .resource = usbotg_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct platform_device mxc_usbdr_host_device = { + .name = "mxc-ehci", + .id = 0, + .num_resources = ARRAY_SIZE(usbotg_resources), + .resource = usbotg_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource usbh1_resources[] = { + { + .start = MX51_OTG_BASE_ADDR + 0x200, + .end = MX51_OTG_BASE_ADDR + 0x200 + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_H1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbh1_device = { + .name = "mxc-ehci", + .id = 1, + .num_resources = ARRAY_SIZE(usbh1_resources), + .resource = usbh1_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource mxc_wdt_resources[] = { + { + .start = MX51_WDOG_BASE_ADDR, + .end = MX51_WDOG_BASE_ADDR + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxc_wdt = { + .name = "imx2-wdt", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_wdt_resources), + .resource = mxc_wdt_resources, +}; + +static struct mxc_gpio_port mxc_gpio_ports[] = { + { + .chip.label = "gpio-0", + .base = MX51_IO_ADDRESS(MX51_GPIO1_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO1_LOW, + .virtual_irq_start = MXC_GPIO_IRQ_START + }, + { + .chip.label = "gpio-1", + .base = MX51_IO_ADDRESS(MX51_GPIO2_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO2_LOW, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1 + }, + { + .chip.label = "gpio-2", + .base = MX51_IO_ADDRESS(MX51_GPIO3_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO3_LOW, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 + }, + { + .chip.label = "gpio-3", + .base = MX51_IO_ADDRESS(MX51_GPIO4_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO4_LOW, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 + }, +}; + int __init mxc_register_gpios(void) { - return 0; + return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); } diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index f339ab8c19b..c879ae71cd5 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -2,3 +2,7 @@ extern struct platform_device mxc_uart_device0; extern struct platform_device mxc_uart_device1; extern struct platform_device mxc_uart_device2; extern struct platform_device mxc_fec_device; +extern struct platform_device mxc_usbdr_host_device; +extern struct platform_device mxc_usbh1_device; +extern struct platform_device mxc_usbdr_udc_device; +extern struct platform_device mxc_wdt; |