diff options
Diffstat (limited to 'arch/arm/mach-mx37')
27 files changed, 11103 insertions, 0 deletions
diff --git a/arch/arm/mach-mx37/Kconfig b/arch/arm/mach-mx37/Kconfig new file mode 100644 index 000000000000..75b5e0c4ae95 --- /dev/null +++ b/arch/arm/mach-mx37/Kconfig @@ -0,0 +1,90 @@ +menu "MX37 Options" + depends on ARCH_MX37 + +config MX37_OPTIONS + bool + default y + select CPU_V6 + select ARM_ERRATA_411920 + select CACHE_L2X0 + select OUTER_CACHE + select USB_ARCH_HAS_EHCI + select ARCH_HAS_EVTMON + select MXC_TZIC + select ARCH_HAS_RNGC + +config MACH_MX37_3DS + bool "Support MX37 3-Stack platforms" + default y + select MFD_WM8350_CONFIG_MODE_0 + help + Include support for MX37 3-Stack platform. This includes specific + configurations for the board and its peripherals. + +config MXC_SDMA_API + bool "Use SDMA API" + default y + help + This selects the Freescale MXC SDMA API. + If unsure, say N. + +menu "SDMA options" + depends on MXC_SDMA_API + +config SDMA_IRAM + bool "Use Internal RAM for SDMA transfer" + default n + help + Support Internal RAM as SDMA buffer or control structures + +config SDMA_IRAM_SIZE + hex "Reserved bytes of IRAM for SDMA (0x800-0x1000)" + range 0x800 0x1000 + depends on SDMA_IRAM + default "0x1000" + help + Set the size of IRAM for SDMA. It must be a multiple of 512bytes. +endmenu + +config ARCH_MXC_HAS_NFC_V3 + bool "MXC NFC Hardware Version 3" + depends on ARCH_MX37 + default y + help + This selects the Freescale MXC Nand Flash Controller Hardware Version 3 + If unsure, say N. + +config ARCH_MXC_HAS_NFC_V3_1 + bool "MXC NFC Hardware Version 3.1" + depends on ARCH_MXC_HAS_NFC_V3 + default y + help + This selects the Freescale MXC Nand Flash Controller Hardware Version 3.1 + If unsure, say N. + +menu "Device options" + +config I2C_MXC_SELECT1 + bool "Enable I2C1 module" + default y + depends on I2C_MXC + help + Enable MX37 I2C1 module. + +config I2C_MXC_SELECT2 + bool "Enable I2C2 module" + default n + depends on I2C_MXC + help + Enable MX37 I2C2 module. + +config I2C_MXC_SELECT3 + bool "Enable I2C3 module" + default n + depends on I2C_MXC + help + Enable MX37 I2C3 module. + +endmenu + +endmenu diff --git a/arch/arm/mach-mx37/Makefile b/arch/arm/mach-mx37/Makefile new file mode 100644 index 000000000000..2b3eeadfc495 --- /dev/null +++ b/arch/arm/mach-mx37/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o lpmodes.o dptc.o bus_freq.o + + +obj-$(CONFIG_MACH_MX37_3DS) += mx37_3stack.o mx37_3stack_gpio.o +obj-$(CONFIG_SPI_MXC) += mx37_3stack_cpld.o +obj-$(CONFIG_REGULATOR_WM8350) += mx37_3stack_pmic_wm8350.o + +# power management +obj-$(CONFIG_PM) += pm.o + +ifneq ($(strip $(CONFIG_USB_GADGET_ARC) $(CONFIG_USB_EHCI_ARC_OTG)),) + obj-y += usb_dr.o +endif diff --git a/arch/arm/mach-mx37/Makefile.boot b/arch/arm/mach-mx37/Makefile.boot new file mode 100644 index 000000000000..1568ad404d59 --- /dev/null +++ b/arch/arm/mach-mx37/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x40008000 +params_phys-y := 0x40000100 +initrd_phys-y := 0x40800000 diff --git a/arch/arm/mach-mx37/board-mx37_3stack.h b/arch/arm/mach-mx37/board-mx37_3stack.h new file mode 100644 index 000000000000..82eee4d47476 --- /dev/null +++ b/arch/arm/mach-mx37/board-mx37_3stack.h @@ -0,0 +1,117 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_BOARD_MX37_3STACK_H__ +#define __ASM_ARCH_MXC_BOARD_MX37_3STACK_H__ + +/*! + * @defgroup BRDCFG_MX37 Board Configuration Options + * @ingroup MSL_MX37 + */ + +/*! + * @file mach-mx37/board-mx37_3stack.h + * + * @brief This file contains all the board level configuration options. + * + * It currently hold the options defined for MX31 ADS Platform. + * + * @ingroup BRDCFG_MX37 + */ + +/* + * Include Files + */ +#include <mach/mxc_uart.h> +#include <mach/mxc_dptc.h> + +/*! + * @name MXC UART EVB board level configurations + */ +/*! @{ */ +/*! + * Specifies if the Irda transmit path is inverting + */ +#define MXC_IRDA_TX_INV 0 +/*! + * Specifies if the Irda receive path is inverting + */ +#define MXC_IRDA_RX_INV 0 + +/* UART 1 configuration */ +/*! + * This define specifies if the UART port is configured to be in DTE or + * DCE mode. There exists a define like this for each UART port. Valid + * values that can be used are \b MODE_DTE or \b MODE_DCE. + */ +#define UART1_MODE MODE_DCE +/*! + * This define specifies if the UART is to be used for IRDA. There exists a + * define like this for each UART port. Valid values that can be used are + * \b IRDA or \b NO_IRDA. + */ +#define UART1_IR NO_IRDA +/*! + * This define is used to enable or disable a particular UART port. If + * disabled, the UART will not be registered in the file system and the user + * will not be able to access it. There exists a define like this for each UART + * port. Specify a value of 1 to enable the UART and 0 to disable it. + */ +#define UART1_ENABLED 1 +/*! @} */ +/* UART 2 configuration */ +#define UART2_MODE MODE_DCE +#define UART2_IR NO_IRDA +#define UART2_ENABLED 1 +/* UART 3 configuration */ +#define UART3_MODE MODE_DCE +#define UART3_IR NO_IRDA +#define UART3_ENABLED 1 + +#define MXC_LL_UART_PADDR UART1_BASE_ADDR +#define MXC_LL_UART_VADDR AIPS1_IO_ADDRESS(UART1_BASE_ADDR) + +#define DEBUG_BASE_ADDRESS 0x78000000 /* Use a Dummy base address */ +/* LAN9217 ethernet base address */ +#define LAN9217_BASE_ADDR DEBUG_BASE_ADDRESS +/* External UART */ +#define UARTA_BASE_ADDR (DEBUG_BASE_ADDRESS + 0x8000) +#define UARTB_BASE_ADDR (DEBUG_BASE_ADDRESS + 0x10000) + +#define BOARD_IO_ADDR 0x20000 +/* LED switchs */ +#define LED_SWITCH_REG BOARD_IO_ADDR + 0x00 +/* buttons */ +#define SWITCH_BUTTONS_REG BOARD_IO_ADDR + 0x08 +/* status, interrupt */ +#define INTR_STATUS_REG BOARD_IO_ADDR + 0x10 +#define INTR_MASK_REG BOARD_IO_ADDR + 0x38 +#define INTR_RESET_REG BOARD_IO_ADDR + 0x20 +/* magic word for debug CPLD */ +#define MAGIC_NUMBER1_REG BOARD_IO_ADDR + 0x40 +#define MAGIC_NUMBER2_REG BOARD_IO_ADDR + 0x48 +/* CPLD code version */ +#define CPLD_CODE_VER_REG BOARD_IO_ADDR + 0x50 + +extern unsigned int sdhc_get_card_det_status(struct device *dev); +extern int sdhc_write_protect(struct device *dev); +extern int sdhc_init_card_det(int id); +extern struct tve_platform_data tve_data; +extern struct mxc_dptc_data dptc_lp_data; +extern struct mxc_dptc_data dptc_gp_data; +extern struct mxc_dvfs_platform_data dvfs_core_data; +extern char *gp_reg_id; +extern char *lp_reg_id; + +extern int headphone_det_status(void); +#endif /* __ASM_ARCH_MXC_BOARD_MX37_3STACK_H__ */ diff --git a/arch/arm/mach-mx37/bus_freq.c b/arch/arm/mach-mx37/bus_freq.c new file mode 100644 index 000000000000..6af034605451 --- /dev/null +++ b/arch/arm/mach-mx37/bus_freq.c @@ -0,0 +1,460 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file bus_freq.c + * + * @brief A common API for the Freescale Semiconductor i.MXC CPUfreq module + * and DVFS CORE module. + * + * The APIs are for setting bus frequency to low or high. + * + * @ingroup PM + */ + +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <mach/clock.h> +#include <mach/hardware.h> +#include <linux/regulator/consumer.h> +#include <mach/mxc_dvfs.h> + +#include "iomux.h" +#include "crm_regs.h" + +#define GP_LPM_VOLTAGE 850000 +#define LP_LPM_VOLTAGE 1050000 +#define LP_LOWFREQ_VOLTAGE 1050000 +#define LP_NORMAL_VOLTAGE 1200000 + +DEFINE_SPINLOCK(bus_freq_lock); + +struct clk *main_bus_clk; +struct clk *pll2; +struct clk *pll1; +struct clk *axi_a_clk; +struct clk *axi_b_clk; +struct clk *axi_c_clk; +struct clk *emi_core_clk; +struct clk *emi_intr_clk; +struct clk *nfc_clk; +struct clk *ahb_clk; +struct clk *vpu_clk; +struct clk *vpu_core_clk; +struct clk *arm_axi_clk; +struct clk *ddr_clk; +struct clk *ipu_clk; +struct clk *periph_apm_clk; +struct clk *lp_apm; +struct clk *cpu_clk; +struct clk *osc; +struct clk *uart_clk; +struct regulator *lp_regulator; +int low_bus_freq_mode; +int high_bus_freq_mode; +char *gp_reg_id = "SW1"; +char *lp_reg_id = "SW2"; +static struct cpu_wp *cpu_wp_tbl; + +struct dvfs_wp dvfs_core_setpoint[] = {{33, 7, 33, 10, 10, 0x10}, + {22, 0, 33, 10, 10, 0x10},}; + +int set_low_bus_freq(void) +{ + int ret = 0; + unsigned long lp_lpm_clk; + unsigned long flags; + + struct clk *p_clk; + struct clk *amode_parent_clk; + + if (low_bus_freq_mode) + return ret; + + if (clk_get_rate(cpu_clk) != 200000000) + return; + + clk_disable(uart_clk); + + lp_lpm_clk = clk_get_rate(lp_apm); + amode_parent_clk = lp_apm; + p_clk = clk_get_parent(periph_apm_clk); + spin_lock_irqsave(&bus_freq_lock, flags); + /* Make sure osc_clk is the parent of lp_apm. */ + if (clk_get_parent(amode_parent_clk) != osc) + clk_set_parent(amode_parent_clk, osc); + + /* Set the parent of periph_apm_clk to be lp_apm */ + clk_set_parent(periph_apm_clk, amode_parent_clk); + amode_parent_clk = periph_apm_clk; + + p_clk = clk_get_parent(main_bus_clk); + /* Set the parent of main_bus_clk to be periph_apm_clk */ + clk_set_parent(main_bus_clk, amode_parent_clk); + + clk_set_rate(ahb_clk, lp_lpm_clk); + /* Set the emi_internal clock to 24MHz */ + clk_set_rate(emi_intr_clk, lp_lpm_clk); + if (clk_get_parent(emi_core_clk) != ahb_clk) + clk_set_rate(emi_core_clk, lp_lpm_clk); + + if (clk_get_usecount(axi_a_clk) != 0) + clk_set_rate(axi_a_clk, lp_lpm_clk); + + if (clk_get_usecount(axi_b_clk) != 0) + clk_set_rate(axi_b_clk, lp_lpm_clk); + + if (clk_get_usecount(axi_c_clk) != 0) + clk_set_rate(axi_c_clk, lp_lpm_clk); + + amode_parent_clk = emi_core_clk; + + p_clk = clk_get_parent(arm_axi_clk); + if (p_clk != amode_parent_clk) + clk_set_parent(arm_axi_clk, amode_parent_clk); + + p_clk = clk_get_parent(vpu_clk); + if (p_clk != amode_parent_clk) + clk_set_parent(vpu_clk, amode_parent_clk); + + p_clk = clk_get_parent(vpu_core_clk); + if (p_clk != amode_parent_clk) + clk_set_parent(vpu_core_clk, amode_parent_clk); + spin_unlock_irqrestore(&bus_freq_lock, flags); + + /* Set the voltage to 1.05V for the LP domain. */ + ret = regulator_set_voltage(lp_regulator, 1050000, 1050000); + udelay(100); + if (ret < 0) { + printk(KERN_ERR "COULD NOT SET LP VOLTAGE!!!!!!\n"); + return ret; + } + + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + return ret; +} + +int set_high_bus_freq(int high_bus_freq) +{ + struct clk *p_clk; + struct clk *rmode_parent_clk; + int ret = 0; + unsigned long flags; + + if (!low_bus_freq_mode) + return ret; + + low_bus_freq_mode = 0; + + /* Set the voltage to 1.25V for the LP domain. */ + ret = regulator_set_voltage(lp_regulator, 1250000, 1250000); + udelay(100); + if (ret < 0) { + printk(KERN_ERR "COULD NOT SET LP VOLTAGE!!!!!!\n"); + return ret; + } + + rmode_parent_clk = pll2; + spin_lock_irqsave(&bus_freq_lock, flags); + + /* Set the dividers before setting the parent clock. */ + if (clk_get_usecount(axi_a_clk) != 0) + clk_set_rate(axi_a_clk, 4800000); + if (clk_get_usecount(axi_b_clk) != 0) + clk_set_rate(axi_b_clk, 4000000); + if (clk_get_usecount(axi_c_clk) != 0) + clk_set_rate(axi_c_clk, 6000000); + if (clk_get_parent(emi_core_clk) != ahb_clk) + clk_set_rate(emi_core_clk, 4800000); + + clk_set_rate(ahb_clk, 4800000); + /* Set emi_intr clock back to divide by 2. */ + clk_set_rate(emi_intr_clk, 2400000); + /* Set the parent of main_bus_clk to be pll2 */ + clk_set_parent(main_bus_clk, rmode_parent_clk); + spin_unlock_irqrestore(&bus_freq_lock, flags); + + clk_enable(uart_clk); + high_bus_freq_mode = 1; + return ret; +} + +int low_freq_bus_used(void) +{ + if ((clk_get_usecount(ipu_clk) == 0) + && (clk_get_usecount(vpu_clk) == 0)) + return 1; + else + return 0; +} + +void setup_pll(void) +{ + u32 reg; + u32 hfsm; + struct cpu_wp *p; + + /* Setup the DPLL registers */ + hfsm = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL) & + MXC_PLL_DP_CTL_HFSM; + reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CONFIG); + reg &= ~MXC_PLL_DP_CONFIG_AREN; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CONFIG); + + if (hfsm) { + /* Running at lower frequency, need to bump up. */ + p = &cpu_wp_tbl[0]; + /* PDF and MFI */ + reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_OP); + + /* MFD */ + __raw_writel(p->mfd, MXC_DPLL1_BASE + MXC_PLL_DP_MFD); + + /* MFI */ + __raw_writel(p->mfn, MXC_DPLL1_BASE + MXC_PLL_DP_MFN); + } else { + /* Running at high frequency, need to lower it. */ + p = &cpu_wp_tbl[1]; + /* PDF and MFI */ + reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_HFS_OP); + + /* MFD */ + __raw_writel(p->mfd, MXC_DPLL1_BASE + MXC_PLL_DP_HFS_MFD); + + /* MFN */ + __raw_writel(p->mfn, MXC_DPLL1_BASE + MXC_PLL_DP_HFS_MFN); + } + + /* Set PLL2_PODF to be 3 */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= 2 << MXC_CCM_CCSR_PLL2_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set the parent of STEP_CLK to be PLL2 */ + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (2 << MXC_CCM_CCSR_STEP_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CCSR); +} + +/*! + * This is the probe routine for the bus frequency driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit busfreq_probe(struct platform_device *pdev) +{ + int cpu_wp_nr; + + main_bus_clk = clk_get(NULL, "main_bus_clk"); + if (IS_ERR(main_bus_clk)) { + printk(KERN_DEBUG "%s: failed to get main_bus_clk\n", __func__); + return PTR_ERR(main_bus_clk); + } + + pll2 = clk_get(NULL, "pll2"); + if (IS_ERR(pll2)) { + printk(KERN_DEBUG "%s: failed to get pll2\n", __func__); + return PTR_ERR(pll2); + } + + axi_a_clk = clk_get(NULL, "axi_a_clk"); + if (IS_ERR(axi_a_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_a_clk\n", __func__); + return PTR_ERR(axi_a_clk); + } + + axi_b_clk = clk_get(NULL, "axi_b_clk"); + if (IS_ERR(axi_b_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_b_clk\n", __func__); + return PTR_ERR(axi_b_clk); + } + + axi_c_clk = clk_get(NULL, "axi_c_clk"); + if (IS_ERR(axi_c_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_c_clk\n", __func__); + return PTR_ERR(axi_c_clk); + } + + emi_core_clk = clk_get(NULL, "emi_core_clk"); + if (IS_ERR(emi_core_clk)) { + printk(KERN_DEBUG "%s: failed to get emi_core_clk\n", __func__); + return PTR_ERR(emi_core_clk); + } + + emi_intr_clk = clk_get(NULL, "emi_intr_clk"); + if (IS_ERR(emi_intr_clk)) { + printk(KERN_DEBUG "%s: failed to get emi_intr_clk\n", __func__); + return PTR_ERR(emi_intr_clk); + } + + nfc_clk = clk_get(NULL, "nfc_clk"); + if (IS_ERR(nfc_clk)) { + printk(KERN_DEBUG "%s: failed to get nfc_clk\n", __func__); + return PTR_ERR(nfc_clk); + } + + ahb_clk = clk_get(NULL, "ahb_clk"); + if (IS_ERR(ahb_clk)) { + printk(KERN_DEBUG "%s: failed to get ahb_clk\n", __func__); + return PTR_ERR(ahb_clk); + } + + vpu_core_clk = clk_get(NULL, "vpu_core_clk"); + if (IS_ERR(vpu_core_clk)) { + printk(KERN_DEBUG "%s: failed to get vpu_core_clk\n", __func__); + return PTR_ERR(vpu_core_clk); + } + + arm_axi_clk = clk_get(NULL, "arm_axi_clk"); + if (IS_ERR(arm_axi_clk)) { + printk(KERN_DEBUG "%s: failed to get arm_axi_clk\n", __func__); + return PTR_ERR(arm_axi_clk); + } + + ddr_clk = clk_get(NULL, "ddr_clk"); + if (IS_ERR(ddr_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_clk\n", __func__); + return PTR_ERR(ddr_clk); + } + + ipu_clk = clk_get(NULL, "ipu_clk"); + if (IS_ERR(ipu_clk)) { + printk(KERN_DEBUG "%s: failed to get ipu_clk\n", __func__); + return PTR_ERR(ipu_clk); + } + + vpu_clk = clk_get(NULL, "vpu_clk"); + if (IS_ERR(vpu_clk)) { + printk(KERN_DEBUG "%s: failed to get vpu_clk\n", __func__); + return PTR_ERR(vpu_clk); + } + + periph_apm_clk = clk_get(NULL, "periph_apm_clk"); + if (IS_ERR(periph_apm_clk)) { + printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n", + __func__); + return PTR_ERR(periph_apm_clk); + } + + lp_apm = clk_get(NULL, "lp_apm"); + if (IS_ERR(lp_apm)) { + printk(KERN_DEBUG "%s: failed to get lp_apm\n", __func__); + return PTR_ERR(lp_apm); + } + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_DEBUG "%s: failed to get cpu_clk\n", __func__); + return PTR_ERR(cpu_clk); + } + + osc = clk_get(NULL, "osc"); + if (IS_ERR(osc)) { + printk(KERN_DEBUG "%s: failed to get osc\n", __func__); + return PTR_ERR(osc); + } + + uart_clk = clk_get(NULL, "uart_clk.0"); + if (IS_ERR(uart_clk)) { + printk(KERN_DEBUG "%s: failed to get uart_clk-0\n", __func__); + return PTR_ERR(uart_clk); + } + + pll1 = clk_get(NULL, "pll1_sw_clk"); + if (IS_ERR(pll1)) { + printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__); + return PTR_ERR(pll1); + } + + + lp_regulator = regulator_get(NULL, lp_reg_id); + if (IS_ERR(lp_regulator)) { + clk_put(ahb_clk); + printk(KERN_DEBUG "%s: failed to get lp regulator\n", __func__); + return PTR_ERR(lp_regulator); + } + + low_bus_freq_mode = 0; + high_bus_freq_mode = 0; + + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + + return 0; +} + +static struct platform_driver busfreq_driver = { + .driver = { + .name = "busfreq", + }, + .probe = busfreq_probe, +}; + +/*! + * Initialise the busfreq_driver. + * + * @return The function always returns 0. + */ + +static int __init busfreq_init(void) +{ + if (platform_driver_register(&busfreq_driver) != 0) { + printk(KERN_ERR "busfreq_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "Bus freq driver module loaded\n"); + return 0; +} + +static void __exit busfreq_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&busfreq_driver); + + clk_put(main_bus_clk); + clk_put(pll2); + clk_put(axi_a_clk); + clk_put(axi_b_clk); + clk_put(axi_c_clk); + clk_put(emi_core_clk); + clk_put(emi_intr_clk); + clk_put(nfc_clk); + clk_put(ahb_clk); + clk_put(vpu_core_clk); + clk_put(arm_axi_clk); + clk_put(ddr_clk); + clk_put(ipu_clk); + clk_put(periph_apm_clk); + clk_put(lp_apm); + clk_put(osc); + clk_put(pll1); + clk_put(pll2); + regulator_put(lp_regulator); + +} + +module_init(busfreq_init); +module_exit(busfreq_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("BusFreq driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx37/clock.c b/arch/arm/mach-mx37/clock.c new file mode 100644 index 000000000000..3d3938ca3d9b --- /dev/null +++ b/arch/arm/mach-mx37/clock.c @@ -0,0 +1,3201 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dptc.h> +#include <mach/spba.h> +#include <mach/mxc_uart.h> + +#include "crm_regs.h" +#include "iomux.h" + +extern int mxc_jtag_enabled; +extern int cpufreq_trig_needed; +extern int dvfs_core_is_active; + +static unsigned long pll_base[] = { + (unsigned long)MXC_DPLL1_BASE, + (unsigned long)MXC_DPLL2_BASE, + (unsigned long)MXC_DPLL3_BASE, +}; + +static struct clk pll1_main_clk; +static struct clk pll1_sw_clk; +static struct clk pll2_sw_clk; +static struct clk pll3_sw_clk; +static struct clk lp_apm_clk; +static struct clk emi_core_clk; +static struct clk emi_fast_clk; +static struct clk emi_slow_clk; +static struct clk emi_intr_clk; +static struct clk ddr_clk; +static struct clk ipu_clk[]; +static struct clk axi_a_clk; +static struct clk axi_b_clk; +static struct clk axi_c_clk; +static struct clk ahb_clk; + +int cpu_wp_nr; +int lp_high_freq; +int lp_med_freq; +static int cpu_curr_wp; +static struct cpu_wp *cpu_wp_tbl; + +extern void propagate_rate(struct clk *tclk); +extern void board_ref_clk_rate(unsigned long *ckil, unsigned long *osc, + unsigned long *ckih); +static int cpu_clk_set_wp(int wp); + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static void _clk_disable_inwait(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); +} + +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3) +{ + if (parent == m0) { + return 0; + } else if (parent == m1) { + return 1; + } else if (parent == m2) { + return 2; + } else if (parent == m3) { + return 3; + } else { + BUG(); + } + return 0; +} + +static inline unsigned long _get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) { + return pll_base[0]; + } else if (pll == &pll2_sw_clk) { + return pll_base[1]; + } else if (pll == &pll3_sw_clk) { + return pll_base[2]; + } else { + BUG(); + } + return 0; +} + +static struct clk ckih_clk = { + .name = "ckih", + .flags = RATE_PROPAGATES, +}; + +static struct clk osc_clk = { + .name = "osc", + .flags = RATE_PROPAGATES, +}; + +static struct clk ckil_clk = { + .name = "ckil", + .flags = RATE_PROPAGATES, +}; + +static void _fpm_recalc(struct clk *clk) +{ + clk->rate = ckil_clk.rate * 512; + if ((__raw_readl(MXC_CCM_CCR) & MXC_CCM_CCR_FPM_MULT_MASK) != 0) { + clk->rate *= 2; + } +} + +static int _fpm_enable(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCR); + reg |= MXC_CCM_CCR_FPM_EN; + __raw_writel(reg, MXC_CCM_CCR); + return 0; +} + +static void _fpm_disable(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCR); + reg &= ~MXC_CCM_CCR_FPM_EN; + __raw_writel(reg, MXC_CCM_CCR); +} + +static struct clk fpm_clk = { + .name = "fpm_clk", + .parent = &ckil_clk, + .recalc = _fpm_recalc, + .enable = _fpm_enable, + .disable = _fpm_disable, + .flags = RATE_PROPAGATES, +}; + +static void _fpm_div2_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate / 2; +} + +static struct clk fpm_div2_clk = { + .name = "fpm_div2_clk", + .parent = &fpm_clk, + .recalc = _fpm_div2_recalc, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 pllbase; + + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + + pllbase = _get_pll_base(clk); + + quad_parent_rate = 4*clk->parent->rate; + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -1; + pdf--; + + temp64 = rate*(pdf+1) - quad_parent_rate*mfi; + do_div(temp64, quad_parent_rate/1000000); + mfn = (long)temp64; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + + return 0; +} + +static void _clk_pll_recalc(struct clk *clk) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + unsigned long pllbase; + s64 temp; + + pllbase = _get_pll_base(clk); + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * clk->parent->rate; + if (dbl != 0) { + ref_clk *= 2; + } + ref_clk /= (pdf + 1); + temp = (u64) ref_clk *mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = -temp; + temp = (ref_clk * mfi) + temp; + + clk->rate = temp; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + u32 pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF)) ; + + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + u32 pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +static struct clk pll1_main_clk = { + .name = "pll1_main_clk", + .parent = &osc_clk, + .recalc = _clk_pll_recalc, + .set_rate = _clk_pll_set_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll1_main_clk) { + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + } else { + mux = _get_mux(parent, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CCSR); + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +static void _clk_pll1_sw_recalc(struct clk *clk) +{ + u32 reg, div; + div = 1; + reg = __raw_readl(MXC_CCM_CCSR); + + if (clk->parent == &pll2_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> + MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; + } else if (clk->parent == &pll3_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> + MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; + } + clk->rate = clk->parent->rate / div; +} + +/* pll1 switch clock */ +static struct clk pll1_sw_clk = { + .name = "pll1_sw_clk", + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .recalc = _clk_pll1_sw_recalc, + .flags = RATE_PROPAGATES, +}; + +/* same as pll2_main_clk. These two clocks should always be the same */ +static struct clk pll2_sw_clk = { + .name = "pll2", + .parent = &osc_clk, + .recalc = _clk_pll_recalc, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_sw_clk = { + .name = "pll3", + .parent = &osc_clk, + .recalc = _clk_pll_recalc, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == &osc_clk) { + reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; + } else if (parent == &fpm_clk) { + reg = __raw_readl(MXC_CCM_CCSR) | MXC_CCM_CCSR_LP_APM_SEL; + } else { + return -EINVAL; + } + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static struct clk lp_apm_clk = { + .name = "lp_apm", + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +static void _clk_arm_recalc(struct clk *clk) +{ + u32 cacrr, div; + + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + clk->rate = clk->parent->rate / div; +} + +static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + u32 i; + for (i = 0; i < cpu_wp_nr; i++) { + if (rate == cpu_wp_tbl[i].cpu_rate) + break; + } + if (i > cpu_wp_nr) + return -EINVAL; + cpu_clk_set_wp(i); + + return 0; +} + +static unsigned long _clk_cpu_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 i; + u32 wp; + + for (i = 0; i < cpu_wp_nr; i++) { + if (rate == cpu_wp_tbl[i].cpu_rate) + break; + } + + if (i > cpu_wp_nr) + wp = 0; + + return cpu_wp_tbl[wp].cpu_rate; +} + +static struct clk cpu_clk = { + .name = "cpu_clk", + .parent = &pll1_sw_clk, + .recalc = _clk_arm_recalc, + .set_rate = _clk_cpu_set_rate, + .round_rate = _clk_cpu_round_rate, +}; + +static int _clk_periph_apm_set_parent(struct clk *clk, + struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); + + reg = __raw_readl(MXC_CCM_CAMR) & ~MXC_CCM_CAMR_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CAMR_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static struct clk periph_apm_clk = { + .name = "periph_apm_clk", + .parent = &pll1_sw_clk, + .set_parent = _clk_periph_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +static void _clk_main_bus_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate; +} + +static int _clk_main_bus_set_rate(struct clk *clk, unsigned long rate) +{ + u32 div = 0; + + clk->rate = clk->parent->rate/(div + 1); + return 0; +} +static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, stat; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.enable(&emi_intr_clk); + + if (ipu_clk[0].usecount == 0) + ipu_clk[0].enable(&ipu_clk[0]); + + if (parent == &pll2_sw_clk) { + reg = __raw_readl(MXC_CCM_CBCDR6) & + ~MXC_CCM_CBCDR6_PERIPH_CLK_SEL; + } else if (parent == &periph_apm_clk) { + reg = __raw_readl(MXC_CCM_CBCDR6) | + MXC_CCM_CBCDR6_PERIPH_CLK_SEL; + } else { + return -EINVAL; + } + __raw_writel(reg, MXC_CCM_CBCDR6); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.disable(&emi_intr_clk); + + if (ipu_clk[0].usecount == 0) + ipu_clk[0].enable(&ipu_clk[0]); + + return 0; +} + +static struct clk main_bus_clk = { + .name = "main_bus_clk", + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, + .set_rate = _clk_main_bus_set_rate, + .recalc = _clk_main_bus_recalc, + .flags = RATE_PROPAGATES, +}; + +static int _clk_axi_a_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (ddr_clk.parent == &axi_a_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + + reg = __raw_readl(MXC_CCM_CBCDR3); + reg &= ~MXC_CCM_CBCDR3_AXI_A_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR3_AXI_A_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR3); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + clk->rate = rate; + + if (ddr_clk.parent == &axi_a_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + + return 0; +} + +static void _clk_axi_a_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR3); + div = ((reg & MXC_CCM_CBCDR3_AXI_A_PODF_MASK) >> + MXC_CCM_CBCDR3_AXI_A_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static unsigned long _clk_axi_a_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk axi_a_clk = { + .name = "axi_a_clk", + .parent = &main_bus_clk, + .recalc = _clk_axi_a_recalc, + .set_rate = _clk_axi_a_set_rate, + .round_rate = _clk_axi_a_round_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_axi_b_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (ddr_clk.parent == &axi_b_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + + reg = __raw_readl(MXC_CCM_CBCDR4); + reg &= ~MXC_CCM_CBCDR4_AXI_B_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR4_AXI_B_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR4); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + clk->rate = rate; + + if (ddr_clk.parent == &axi_c_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + + return 0; +} + +static void _clk_axi_b_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR4); + div = ((reg & MXC_CCM_CBCDR4_AXI_B_PODF_MASK) >> + MXC_CCM_CBCDR4_AXI_B_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static unsigned long _clk_axi_b_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk axi_b_clk = { + .name = "axi_b_clk", + .parent = &main_bus_clk, + .recalc = _clk_axi_b_recalc, + .set_rate = _clk_axi_b_set_rate, + .round_rate = _clk_axi_b_round_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_axi_c_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (ddr_clk.parent == &axi_c_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + + reg = __raw_readl(MXC_CCM_CBCDR5); + reg &= ~MXC_CCM_CBCDR5_AXI_C_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR5_AXI_C_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR5); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + clk->rate = rate; + + if (ddr_clk.parent == &axi_c_clk && emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + + return 0; +} + +static void _clk_axi_c_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR5); + div = ((reg & MXC_CCM_CBCDR5_AXI_C_PODF_MASK) >> + MXC_CCM_CBCDR5_AXI_C_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static unsigned long _clk_axi_c_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk axi_c_clk = { + .name = "axi_c_clk", + .parent = &main_bus_clk, + .recalc = _clk_axi_c_recalc, + .set_rate = _clk_axi_c_set_rate, + .round_rate = _clk_axi_c_round_rate, + .flags = RATE_PROPAGATES, +}; + +static void _clk_ahb_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR2); + div = ((reg & MXC_CCM_CBCDR2_AHB_PODF_MASK) >> + MXC_CCM_CBCDR2_AHB_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR2); + reg &= ~MXC_CCM_CBCDR2_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR2_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR2); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + clk->rate = rate; + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk ahb_clk = { + .name = "ahb_clk", + .parent = &main_bus_clk, + .recalc = _clk_ahb_recalc, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, + .flags = RATE_PROPAGATES, +}; + +static struct clk ahb_max_clk = { + .name = "max_clk", + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static int _clk_emi_core_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.enable(&emi_intr_clk); + + reg = __raw_readl(MXC_CCM_CBCDR6); + reg &= ~MXC_CCM_CBCDR6_EMI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR6_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR6); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + + clk->rate = rate; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.disable(&emi_intr_clk); + + return 0; +} + +static void _clk_emi_core_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR6); + div = ((reg & MXC_CCM_CBCDR6_EMI_PODF_MASK) >> + MXC_CCM_CBCDR6_EMI_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static int _clk_emi_core_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + u32 stat; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.enable(&emi_intr_clk); + + if ((ipu_clk[0].parent == &emi_core_clk) && + (ipu_clk[0].usecount == 0)) + ipu_clk[0].enable(&ipu_clk[0]); + + reg = __raw_readl(MXC_CCM_CBCDR6); + if (parent == &ahb_clk) { + reg |= MXC_CCM_CBCDR6_EMI_CLK_SEL; + } else if (parent == &main_bus_clk) { + reg &= ~MXC_CCM_CBCDR6_EMI_CLK_SEL; + } else { + BUG(); + } + __raw_writel(reg, MXC_CCM_CBCDR6); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.disable(&emi_intr_clk); + if ((ipu_clk[0].parent == &emi_core_clk) && + (ipu_clk[0].usecount == 0)) + ipu_clk[0].disable(&ipu_clk[0]); + + return 0; +} + +static unsigned long _clk_emi_core_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk emi_core_clk = { + .name = "emi_core_clk", + .set_parent = _clk_emi_core_set_parent, + .recalc = _clk_emi_core_recalc, + .set_rate = _clk_emi_core_set_rate, + .round_rate = _clk_emi_core_round_rate, + .flags = RATE_PROPAGATES, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk ahbmux1_clk = { + .name = "ahbmux1_clk", + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG4_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk ahbmux2_clk = { + .name = "ahbmux2_clk", + .id = 0, + .parent = &emi_core_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG7_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk emi_fast_clk = { + .name = "emi_fast_clk", + .parent = &emi_core_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG12_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk emi_slow_clk = { + .name = "emi_slow_clk", + .parent = &emi_core_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG13_OFFSET, + .disable = _clk_disable_inwait, +}; + +static int _clk_emi_intr_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 4)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR7); + reg &= ~MXC_CCM_CBCDR7_IPG_INIT_MEM_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR7_IPG_INT_MEM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR7); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + + clk->rate = rate; + + return 0; +} + +static void _clk_emi_intr_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR7); + div = ((reg & MXC_CCM_CBCDR7_IPG_INIT_MEM_PODF_MASK) >> + MXC_CCM_CBCDR7_IPG_INT_MEM_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static unsigned long _clk_emi_intr_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 4) + div = 4; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk emi_intr_clk = { + .name = "emi_intr_clk", + .parent = &emi_core_clk, + .secondary = &ahbmux2_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG14_OFFSET, + .disable = _clk_disable_inwait, + .recalc = _clk_emi_intr_recalc, + .set_rate = _clk_emi_intr_set_rate, + .round_rate = _clk_emi_intr_round_rate, +}; + +static void _clk_ipg_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR2); + div = ((reg & MXC_CCM_CBCDR2_IPG_PODF_MASK) >> + MXC_CCM_CBCDR2_IPG_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static struct clk ipg_clk = { + .name = "ipg_clk", + .parent = &ahb_clk, + .recalc = _clk_ipg_recalc, + .flags = RATE_PROPAGATES, +}; + +static void _clk_ipg_per_recalc(struct clk *clk) +{ + u32 reg, prediv1, prediv2, podf; + + if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { + /* the main_bus_clk is the one before the DVFS engine */ + reg = __raw_readl(MXC_CCM_CBCDR2); + prediv1 = ((reg & MXC_CCM_CBCDR2_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR2_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR2_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR2_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR2_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR2_PERCLK_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) { + clk->rate = ipg_clk.rate; + } else { + BUG(); + } +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + mux = _get_mux(parent, &main_bus_clk, &lp_apm_clk, &ipg_clk, NULL); + if (mux == 2) { + reg |= MXC_CCM_CSCMR1_PERCLK_IPG_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_PERCLK_IPG_CLK_SEL; + if (mux == 0) { + reg &= ~MXC_CCM_CSCMR1_PERCLK_LP_APM_CLK_SEL; + } else { + reg |= MXC_CCM_CSCMR1_PERCLK_LP_APM_CLK_SEL; + } + } + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ipg_perclk = { + .name = "ipg_perclk", + .parent = &ipg_clk, + .recalc = _clk_ipg_per_recalc, + .set_parent = _clk_ipg_per_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk aips_tz1_clk = { + .name = "aips_tz1_clk", + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + .name = "aips_tz2_clk", + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + .name = "gpc_dvfs_clk", + .parent = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk sdma_clk[] = { + { + .name = "sdma_ahb_clk", + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "sdma_ipg_clk", + .parent = &ipg_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &emi_intr_clk, +#endif + }, +}; + +static int _clk_tve_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + + if (parent == &pll3_sw_clk) { + reg &= ~(MXC_CCM_CSCMR1_TVE_CLK_SEL); + } else if (parent == &osc_clk) { + reg |= MXC_CCM_CSCMR1_TVE_CLK_SEL; + reg &= MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL; + } else if (parent == &ckih_clk) { + reg |= MXC_CCM_CSCMR1_TVE_CLK_SEL; + reg |= MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static void _clk_tve_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_TVE_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_TVE_CLK_PRED_MASK; + div = (reg >> MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET) + 1; + clk->rate = clk->parent->rate / div; + } else { + clk->rate = clk->parent->rate; + } +} + +static unsigned long _clk_tve_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL) { + return -EINVAL; + } + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static int _clk_tve_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL) { + return -EINVAL; + } + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) { + return -EINVAL; + } + + div--; + reg = __raw_readl(MXC_CCM_CDCDR) & ~MXC_CCM_CDCDR_TVE_CLK_PRED_MASK; + reg |= div << MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + clk->rate = rate; + return 0; +} + +static struct clk tve_clk = { + .name = "tve_clk", + .parent = &pll3_sw_clk, + .secondary = &aips_tz1_clk, + .set_parent = _clk_tve_set_parent, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG10_OFFSET, + .recalc = _clk_tve_recalc, + .round_rate = _clk_tve_round_rate, + .set_rate = _clk_tve_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = RATE_PROPAGATES, +}; + +static struct clk spba_clk = { + .name = "spba_clk", + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static void _clk_uart_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_uart_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_UART_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static int _clk_uart_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, post_div = 1; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 64) || (div == 1)) + return -EINVAL; + + if (div > 8) { + int i = 1; + while ((div / (2 * i)) > 8) + i++; + post_div = i * 2; + div = div / post_div; + } + + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET | + (post_div - 1) << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + clk->rate = rate; + + return 0; +} + +static unsigned long _clk_uart_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 64) + div = 64; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk uart_main_clk = { + .name = "uart_main_clk", + .parent = &pll2_sw_clk, + .secondary = &emi_fast_clk, + .recalc = _clk_uart_recalc, + .set_parent = _clk_uart_set_parent, + .set_rate = _clk_uart_set_rate, + .round_rate = _clk_uart_round_rate, + .flags = RATE_PROPAGATES, +}; + +static struct clk uart1_clk[] = { + { + .name = "uart_clk", + .id = 0, + .parent = &uart_main_clk, + .secondary = &uart1_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "uart_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + .name = "uart_clk", + .id = 1, + .parent = &uart_main_clk, + .secondary = &uart2_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "uart_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + .name = "uart_clk", + .id = 2, + .parent = &uart_main_clk, + .secondary = &uart3_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "uart_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_clk[] = { + { + .name = "gpt_clk", + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &gpt_clk[1], + }, + { + .name = "gpt_ipg_clk", + .parent = &ipg_clk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "gpt_32k_clk", + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk i2c_clk[] = { + { + .name = "i2c_clk", + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "i2c_clk", + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "i2c_clk", + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static void _clk_cspi_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_cspi_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_CSPI_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static int _clk_cspi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, post_div = 1; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 512) || (div == 1)) + return -EINVAL; + + if (div > 8) { + int i = 1; + while ((div / (2 * i)) > 8) + i++; + post_div = i * 2; + div = div / post_div; + } + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET; + reg |= (post_div - 1) << MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + clk->rate = rate; + + return 0; +} + +static unsigned long _clk_cspi_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 512) + div = 8; + else if (div == 1) + div = 2; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk cspi_main_clk = { + .name = "cspi_main_clk", + .parent = &pll3_sw_clk, + .recalc = _clk_cspi_recalc, + .set_parent = _clk_cspi_set_parent, + .set_rate = _clk_cspi_set_rate, + .round_rate = _clk_cspi_round_rate, + .flags = RATE_PROPAGATES, +}; + +static struct clk cspi1_clk[] = { + { + .name = "cspi_clk", + .id = 0, + .parent = &cspi_main_clk, + .secondary = &cspi1_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "cspi_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk cspi2_clk[] = { + { + .name = "cspi_clk", + .id = 1, + .parent = &cspi_main_clk, + .secondary = &cspi2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "cspi_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk cspi3_clk[] = { + { + .name = "cspi_clk", + .id = 2, + .parent = &cspi_main_clk, + .secondary = &cspi3_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "cspi_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static int _clk_ssi_lp_apm_set_parent(struct clk *clk, + struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + + if (parent == &ckih_clk) { + reg &= ~MXC_CCM_CSCMR1_SSI_APM_CLK_SEL; + } else if (parent == &lp_apm_clk) { + reg |= MXC_CCM_CSCMR1_SSI_APM_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk ssi_lp_apm_clk = { + .name = "ssi_lp_apm_clk", + .parent = &ckih_clk, + .set_parent = _clk_ssi_lp_apm_set_parent, +}; + +static void _clk_ssi1_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} +static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi1_clk[] = { + { + .name = "ssi_clk", + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi1_set_parent, + .secondary = &ssi1_clk[1], + .recalc = _clk_ssi1_recalc, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "ssi_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .secondary = &ssi1_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "ssi_dep_clk", + .id = 0, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk, +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static void _clk_ssi2_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi2_clk[] = { + { + .name = "ssi_clk", + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi2_set_parent, + .secondary = &ssi2_clk[1], + .recalc = _clk_ssi2_recalc, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "ssi_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .secondary = &ssi2_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "ssi_dep_clk", + .id = 1, + .parent = &spba_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk, +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static void _clk_ssi_ext1_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + clk->rate = clk->parent->rate; + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CSECDR1); + prediv = ((reg & MXC_CCM_CSECDR1_SSI_EXT1_CLK_PRED_MASK) >> + MXC_CCM_CSECDR1_SSI_EXT1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSECDR1_SSI_EXT1_CLK_PODF_MASK) >> + MXC_CCM_CSECDR1_SSI_EXT1_CLK_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / (prediv * podf); + } +} + +static int _clk_ssi_ext1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi1_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_ext1_clk = { + .name = "ssi_ext1_clk", + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext1_set_parent, + .recalc = _clk_ssi_ext1_recalc, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static void _clk_ssi_ext2_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + clk->rate = clk->parent->rate; + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CSECDR2); + prediv = ((reg & MXC_CCM_CSECDR2_SSI_EXT2_CLK_PRED_MASK) >> + MXC_CCM_CSECDR2_SSI_EXT2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSECDR2_SSI_EXT2_CLK_PODF_MASK) >> + MXC_CCM_CSECDR2_SSI_EXT2_CLK_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / (prediv * podf); + } +} + +static int _clk_ssi_ext2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi2_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_ext2_clk = { + .name = "ssi_ext2_clk", + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext2_set_parent, + .recalc = _clk_ssi_ext2_recalc, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk iim_clk = { + .name = "iim_clk", + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG15_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax1_clk = { + .name = "tmax1_clk", + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG0_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax2_clk = { + .name = "tmax2_clk", + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG1_OFFSET, + .disable = _clk_disable, +}; + +static void _clk_usboh2_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_USBOH2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_USBOH2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR1_USBOH2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_USBOH2_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_usboh2_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_USBOH2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_USBOH2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +/* + * This is USB core clock. + ** need access DDR/iram, TMAX + */ +static struct clk usb_core_clk[] = { + { + .name = "usb_ahb_clk", + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG11_OFFSET, + .disable = _clk_disable, + .secondary = &usb_core_clk[1], + }, + { + .name = "usb_tmax_clk", + .parent = &tmax1_clk, + .secondary = &usb_core_clk[2], + }, + { + .name = "usb_ddr_clk", + .parent = &emi_fast_clk, +#if defined CONFIG_USB_STATIC_IRAM_PPH || defined CONFIG_USB_STATIC_IRAM + .secondary = &usb_core_clk[3], +#endif + }, + /* iram patch, need access internal ram */ + { + .name = "usb_iram_clk", + .parent = &emi_intr_clk, + }, +}; + +/* used for connecting external PHY */ +static struct clk usboh2_clk = { + .name = "usboh2_clk", + .parent = &pll3_sw_clk, + .set_parent = _clk_usboh2_set_parent, + .recalc = _clk_usboh2_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG12_OFFSET, + .disable = _clk_disable, +}; + +static void _clk_usb_phy_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + if (clk->parent == &pll3_sw_clk) { + reg = __raw_readl(MXC_CCM_CDCDR); + prediv = ((reg & MXC_CCM_CDCDR_USB_PHY_PRED_MASK) >> + MXC_CCM_CDCDR_USB_PHY_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_USB_PHY_PODF_MASK) >> + MXC_CCM_CDCDR_USB_PHY_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); + } else + clk->rate = clk->parent->rate; +} + +static int _clk_usb_phy_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &osc_clk) { + reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + } else if (parent == &pll3_sw_clk) { + reg |= MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk usb_phy_clk = { + .name = "usb_phy_clk", + .parent = &osc_clk, + .set_parent = _clk_usb_phy_set_parent, + .recalc = _clk_usb_phy_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG6_OFFSET, + .disable = _clk_disable, +}; + +static struct clk esdhc_dep_clks = { + .name = "sd_dep_clk", + .parent = &spba_clk, + .secondary = &emi_fast_clk, +}; + + +static void _clk_esdhc1_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_esdhc1_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_ESDHC1_MSHC1_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc1_clk[] = { + { + .name = "esdhc_clk", + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_esdhc1_set_parent, + .recalc = _clk_esdhc1_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG14_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[1], + }, + { + .name = "esdhc_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG13_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[2], + }, + { + .name = "esdhc1_sec_clk", + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static void _clk_esdhc2_recalc(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (prediv * podf); +} + +static int _clk_esdhc2_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_ESDHC2_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc2_clk[] = { + { + .name = "esdhc_clk", + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_esdhc2_set_parent, + .recalc = _clk_esdhc2_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG0_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[1], + }, + { + .name = "esdhc_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGR2_CG15_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[2], + }, + { + .name = "esdhc2_sec_clk", + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) { + reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; + } else if (parent == &esdhc2_clk[0]) { + reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; + } else { + BUG(); + } + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc3_clk[] = { + { + .name = "esdhc_clk", + .id = 2, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc3_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG2_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[1], + }, + { + .name = "esdhc_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[2], + }, + { + .name = "esdhc3_sec_clk", + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, + +}; + +static void _clk_nfc_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR7); + div = ((reg & MXC_CCM_CBCDR7_NFC_PODF_MASK) >> + MXC_CCM_CBCDR7_NFC_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / div; +} + +static int _clk_nfc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, stat; + + div = clk->parent->rate / rate; + if (div == 0) + div++; + if (((clk->parent->rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.enable(&emi_intr_clk); + + reg = __raw_readl(MXC_CCM_CBCDR7); + reg &= ~MXC_CCM_CBCDR7_NFC_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR7_NFC_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR7); + + /* Set the Load-dividers bit in CCM */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_LOAD_DIVIDERS; + __raw_writel(reg, MXC_CCM_CCDR); + + do { + stat = __raw_readl(MXC_CCM_CCDR) & MXC_CCM_CCDR_LOAD_DIVIDERS; + } while (stat); + clk->rate = rate; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + if (emi_intr_clk.usecount == 0) + emi_intr_clk.disable(&emi_intr_clk); + + return 0; +} + +static unsigned long _clk_nfc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; +} + +static struct clk nfc_clk = { + .name = "nfc_clk", + .parent = &emi_core_clk, + .secondary = &emi_slow_clk, + .recalc = _clk_nfc_recalc, + .set_rate = _clk_nfc_set_rate, + .round_rate = _clk_nfc_round_rate, +}; + +static int _clk_spdif_xtal_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &osc_clk) { + reg &= ~MXC_CCM_CSCMR1_SPDIF_CLK_SEL; + } else if (parent == &ckih_clk) { + reg |= MXC_CCM_CSCMR1_SPDIF_CLK_SEL; + } else { + BUG(); + } + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk spdif_xtal_clk = { + .name = "spdif_xtal_clk", + .parent = &osc_clk, + .set_parent = _clk_spdif_xtal_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG10_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_spdif0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg |= MXC_CCM_CSCMR2_SPDIF0_COM; + if (parent != &ssi1_clk[0]) { + reg &= ~MXC_CCM_CSCMR2_SPDIF0_COM; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &spdif_xtal_clk); + reg = (reg & ~MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_OFFSET); + } + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static void _clk_spdif0_recalc(struct clk *clk) +{ + u32 reg, pred, podf; + + if (clk->parent == &ssi1_clk[0]) { + clk->rate = clk->parent->rate; + } else { + reg = __raw_readl(MXC_CCM_CDCDR); + pred = ((reg & MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK) >> + MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK) >> + MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / (pred * podf); + } +} + +static struct clk spdif0_clk[] = { + { + .name = "spdif_clk", + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &spdif0_clk[1], + .set_parent = _clk_spdif0_set_parent, + .recalc = _clk_spdif0_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG11_OFFSET, + .disable = _clk_disable, + }, + { + .name = "spdif_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG10_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_spdif1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg |= MXC_CCM_CSCMR2_SPDIF1_COM; + if (parent != &ssi2_clk[0]) { + reg &= ~MXC_CCM_CSCMR2_SPDIF1_COM; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &spdif_xtal_clk); + reg = (reg & ~MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_OFFSET); + } + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static void _clk_spdif1_recalc(struct clk *clk) +{ + u32 reg, pred, podf; + + if (clk->parent == &ssi2_clk[0]) { + clk->rate = clk->parent->rate; + } else { + reg = __raw_readl(MXC_CCM_CDCDR); + pred = ((reg & MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK) >> + MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK) >> + MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET) + 1; + clk->rate = clk->parent->rate / (pred * podf); + } +} + +static struct clk spdif1_clk[] = { + { + .name = "spdif_clk", + .id = 1, + .parent = &pll3_sw_clk, + .secondary = &spdif1_clk[1], + .set_parent = _clk_spdif1_set_parent, + .recalc = _clk_spdif1_recalc, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG12_OFFSET, + .disable = _clk_disable, + }, + { + .name = "spdif_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGR1_CG10_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_ipu_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + /* Handshake with IPU when certain clock rates are changed. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* Handshake with IPU when LPM is entered as its enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_ipu_disable(struct clk *clk) +{ + u32 reg; + _clk_disable(clk); + + /* No handshake with IPU as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_IPU_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* No handshake with IPU when LPM is entered as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static int _clk_ipu_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CAMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &axi_c_clk, + &emi_core_clk); + reg = (reg & ~MXC_CCM_CAMR_IPU_HSP_CLK_SEL_MASK) | + (mux << MXC_CCM_CAMR_IPU_HSP_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static struct clk ipu_clk[] = { + { + .name = "ipu_clk", + .parent = &axi_a_clk, + .secondary = &ipu_clk[1], + .set_parent = _clk_ipu_set_parent, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG15_OFFSET, + .enable = _clk_ipu_enable, + .disable = _clk_ipu_disable, + .flags = CPU_FREQ_TRIG_UPDATE, + }, + { + .name = "ipu_sec_clk", + .parent = &emi_fast_clk, + .secondary = &ahbmux1_clk, + } +}; + +static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == &tve_clk) { + mxc_iomux_set_gpr(MUX_IPUv3D_CAMP, false, 0); + } else if (parent == &ckih_clk) { + mxc_iomux_set_gpr(MUX_IPUv3D_CAMP, true, 0); + reg = __raw_readl(MXC_CCM_CSCMR1); + reg |= MXC_CCM_CSCMR1_DI_CLK_SEL; + __raw_writel(reg, MXC_CCM_CSCMR1); + } else if (parent == &osc_clk) { + mxc_iomux_set_gpr(MUX_IPUv3D_CAMP, true, 0); + reg = __raw_readl(MXC_CCM_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_DI_CLK_SEL; + __raw_writel(reg, MXC_CCM_CSCMR1); + } else { + return -EINVAL; + } + + return 0; +} + +static void _clk_ipu_di_recalc(struct clk *clk) +{ + if (clk->parent == &tve_clk) { + clk->rate = clk->parent->rate / 8; + } else { + clk->rate = clk->parent->rate; + } +} + +static struct clk ipu_di_clk = { + .name = "ipu_di_clk", + .parent = &tve_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG14_OFFSET, + .recalc = _clk_ipu_di_recalc, + .set_parent = _clk_ipu_di_set_parent, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_ddr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CAMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &axi_c_clk, + &emi_core_clk); + reg = (reg & ~MXC_CCM_CAMR_DDR_CLK_SEL_MASK) | + (mux << MXC_CCM_CAMR_DDR_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static struct clk ddr_clk = { + .name = "ddr_clk", + .parent = &axi_c_clk, + .set_parent = _clk_ddr_set_parent, +}; + +static int _clk_arm_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CAMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &axi_c_clk, + &emi_core_clk); + reg = (reg & ~MXC_CCM_CAMR_ARM_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CAMR_ARM_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static struct clk arm_axi_clk = { + .name = "arm_axi_clk", + .parent = &axi_a_clk, + .set_parent = _clk_arm_axi_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGR0_CG1_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_vpu_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CAMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &axi_c_clk, + &emi_core_clk); + reg = (reg & ~MXC_CCM_CAMR_VPU_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CAMR_VPU_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static int _clk_vpu_core_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CAMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &axi_c_clk, + &emi_core_clk); + reg = (reg & ~MXC_CCM_CAMR_VPU_CLK_SEL_MASK) | + (mux << MXC_CCM_CAMR_VPU_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CAMR); + + return 0; +} + +static struct clk vpu_clk[] = { + { + .name = "vpu_clk", + .parent = &axi_a_clk, + .set_parent = _clk_vpu_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &vpu_clk[1], + .flags = CPU_FREQ_TRIG_UPDATE, + }, + { + .name = "vpu_core_clk", + .parent = &axi_a_clk, + .secondary = &vpu_clk[2], + .set_parent = _clk_vpu_core_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG6_OFFSET, + .disable = _clk_disable, + }, + { + .name = "vpu_emi_clk", + .parent = &emi_fast_clk, +#ifdef CONFIG_MXC_VPU_IRAM + .secondary = &emi_intr_clk, +#endif + } +}; + +static int _clk_lpsr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CLPCR); + mux = _get_mux(parent, &ckil_clk, &fpm_clk, &fpm_div2_clk, NULL); + reg = (reg & ~MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK) | + (mux << MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static struct clk lpsr_clk = { + .name = "lpsr_clk", + .parent = &ckil_clk, + .set_parent = _clk_lpsr_set_parent, +}; + +static void _clk_pgc_recalc(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = (reg & MXC_CCM_CSCDR1_PGC_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET; + div = 1 >> div; + clk->rate = clk->parent->rate / div; +} + +static struct clk pgc_clk = { + .name = "pgc_clk", + .parent = &ipg_clk, + .recalc = _clk_pgc_recalc, +}; + +/*usb OTG clock */ +/*Notes: in mx37, usb clock get from UTMI PHY, always 60MHz*/ + +static struct clk usb_clk = { + .name = "usb_clk", + .rate = 60000000, +}; + +static struct clk rtc_clk = { + .name = "rtc_clk", + .parent = &ckil_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG13_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ata_clk = { + .name = "ata_clk", + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG14_OFFSET, + .disable = _clk_disable, +}; + +static struct clk rng_clk = { + .name = "rng_clk", + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGR3_CG5_OFFSET, + .disable = _clk_disable, +}; + +static struct clk scc_clk = { + .name = "scc_clk", + .parent = &ipg_clk, + .secondary = &emi_fast_clk, +}; + +static void cko1_recalc(struct clk *clk) +{ + unsigned long rate; + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg = reg >> MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + rate = clk->parent->rate; + clk->rate = rate / (reg + 1); +} + +static int cko1_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg |= MXC_CCM_CCOSR_CKOL_EN; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static void cko1_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_EN; + __raw_writel(reg, MXC_CCM_CCOSR); +} + +static int cko1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + + div = (clk->parent->rate/rate - 1) & 0x7; + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg |= div << MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long cko1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + + div = clk->parent->rate / rate; + div = div < 1 ? 1 : div; + div = div > 8 ? 8 : div; + return clk->parent->rate / div; +} + +static int cko1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &cpu_clk) + sel = 0; + else if (parent == &pll1_sw_clk) + sel = 1; + else if (parent == &pll2_sw_clk) + sel = 2; + else if (parent == &pll3_sw_clk) + sel = 3; + else if (parent == &emi_core_clk) + sel = 4; + else if (parent == &nfc_clk) + sel = 6; + else if (parent == &vpu_clk[1]) + sel = 7; + else if (parent == &ipu_di_clk) + sel = 8; + else if (parent == &ahb_clk) + sel = 11; + else if (parent == &ipg_clk) + sel = 12; + else if (parent == &ipg_perclk) + sel = 13; + else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_SEL_MASK; + reg |= sel << MXC_CCM_CCOSR_CKOL_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} +static struct clk cko1_clk = { + .name = "cko1_clk", + .recalc = cko1_recalc, + .enable = cko1_enable, + .disable = cko1_disable, + .set_rate = cko1_set_rate, + .round_rate = cko1_round_rate, + .set_parent = cko1_set_parent, +}; + +static struct clk *mxc_clks[] = { + &osc_clk, + &ckih_clk, + &ckil_clk, + &fpm_clk, + &fpm_div2_clk, + &pll1_main_clk, + &pll1_sw_clk, + &pll2_sw_clk, + &pll3_sw_clk, + &gpc_dvfs_clk, + &lp_apm_clk, + &cpu_clk, + &periph_apm_clk, + &main_bus_clk, + &axi_a_clk, + &axi_b_clk, + &axi_c_clk, + &ahb_clk, + &ahb_max_clk, + &aips_tz1_clk, + &aips_tz2_clk, + &ipg_clk, + &ipg_perclk, + &sdma_clk[0], + &sdma_clk[1], + &ipu_clk[0], + &ipu_clk[1], + &ipu_di_clk, + &tve_clk, + &uart_main_clk, + &uart1_clk[0], + &uart1_clk[1], + &uart2_clk[0], + &uart2_clk[1], + &uart3_clk[0], + &uart3_clk[1], + &spba_clk, + &i2c_clk[0], + &i2c_clk[1], + &i2c_clk[2], + &gpt_clk[0], + &gpt_clk[1], + &gpt_clk[2], + &cspi_main_clk, + &cspi1_clk[0], + &cspi1_clk[1], + &cspi2_clk[0], + &cspi2_clk[1], + &cspi3_clk[0], + &cspi3_clk[1], + &ssi_lp_apm_clk, + &ssi1_clk[0], + &ssi1_clk[1], + &ssi2_clk[0], + &ssi2_clk[1], + &ssi_ext1_clk, + &ssi_ext2_clk, + &iim_clk, + &tmax1_clk, + &tmax2_clk, + &ahbmux1_clk, + &ahbmux2_clk, + &usb_core_clk[0], + &usb_core_clk[1], + &usb_core_clk[2], + &usb_core_clk[3], + &usboh2_clk, + &usb_phy_clk, + &usb_clk, + &esdhc1_clk[0], + &esdhc1_clk[1], + &esdhc1_clk[2], + &esdhc2_clk[0], + &esdhc2_clk[1], + &esdhc2_clk[2], + &esdhc3_clk[0], + &esdhc3_clk[1], + &esdhc3_clk[2], + &esdhc_dep_clks, + &emi_core_clk, + &emi_fast_clk, + &emi_slow_clk, + &emi_intr_clk, + &nfc_clk, + &spdif_xtal_clk, + &spdif0_clk[0], + &spdif0_clk[1], + &spdif1_clk[0], + &spdif1_clk[1], + &ddr_clk, + &arm_axi_clk, + &vpu_clk[0], + &vpu_clk[1], + &vpu_clk[2], + &lpsr_clk, + &pgc_clk, + &rtc_clk, + &ata_clk, + &rng_clk, + &scc_clk, + &cko1_clk, +}; + +static void clk_tree_init(void) +{ + u32 reg, dp_ctl; + + ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); + + /* + *Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at + * 8MHz, its derived from lp_apm. + */ + reg = __raw_readl(MXC_CCM_CBCDR2); + reg &= ~MXC_CCM_CBCDR2_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR2_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR2_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR2_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR2); + + /* set pll1_main_clk parent */ + pll1_main_clk.parent = &osc_clk; + dp_ctl = __raw_readl(pll_base[0] + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll1_main_clk.parent = &fpm_clk; + /* set pll2_sw_clk parent */ + pll2_sw_clk.parent = &osc_clk; + dp_ctl = __raw_readl(pll_base[1] + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll2_sw_clk.parent = &fpm_clk; + /* set pll3_clk parent */ + pll3_sw_clk.parent = &osc_clk; + dp_ctl = __raw_readl(pll_base[2] + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll3_sw_clk.parent = &fpm_clk; + + /* set emi_core_clk parent */ + emi_core_clk.parent = &main_bus_clk; + reg = __raw_readl(MXC_CCM_CBCDR6); + if ((reg & MXC_CCM_CBCDR6_EMI_CLK_SEL) != 0) { + emi_core_clk.parent = &ahb_clk; + } + + /* set ipg_perclk parent */ + ipg_perclk.parent = &lp_apm_clk; + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_PERCLK_IPG_CLK_SEL) != 0) { + ipg_perclk.parent = &ipg_clk; + } else { + if ((reg & MXC_CCM_CSCMR1_PERCLK_LP_APM_CLK_SEL) == 0) + ipg_perclk.parent = &main_bus_clk; + } + + /* set DDR clock parent */ + reg = __raw_readl(MXC_CCM_CAMR) & MXC_CCM_CAMR_DDR_CLK_SEL_MASK; + reg >>= MXC_CCM_CAMR_DDR_CLK_SEL_OFFSET; + if (reg == 0) { + ddr_clk.parent = &axi_a_clk; + } else if (reg == 1) { + ddr_clk.parent = &axi_b_clk; + } else if (reg == 2) { + ddr_clk.parent = &axi_c_clk; + } else { + ddr_clk.parent = &emi_core_clk; + } +} + +int __init mx37_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2) +{ + struct clk **clkp; + u32 reg; + int i; + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel((1 << MXC_CCM_CCGR0_CG0_OFFSET) | + (1 << MXC_CCM_CCGR0_CG1_OFFSET) | + (1 << MXC_CCM_CCGR0_CG2_OFFSET) | + (1 << MXC_CCM_CCGR0_CG12_OFFSET) | + (1 << MXC_CCM_CCGR0_CG13_OFFSET) | + (1 << MXC_CCM_CCGR0_CG7_OFFSET) | + (1 << MXC_CCM_CCGR0_CG14_OFFSET), MXC_CCM_CCGR0); + } else { + __raw_writel((1 << MXC_CCM_CCGR0_CG0_OFFSET) | + (1 << MXC_CCM_CCGR0_CG1_OFFSET) | + (1 << MXC_CCM_CCGR0_CG12_OFFSET) | + (1 << MXC_CCM_CCGR0_CG13_OFFSET) | + (1 << MXC_CCM_CCGR0_CG7_OFFSET) | + (1 << MXC_CCM_CCGR0_CG14_OFFSET), MXC_CCM_CCGR0); + } + __raw_writel(0, MXC_CCM_CCGR1); + + /* TMAX clocks. */ + reg = __raw_readl(MXC_CCM_CCGR1); + reg |= 1 << MXC_CCM_CCGR1_CG0_OFFSET; + reg |= 1 << MXC_CCM_CCGR1_CG1_OFFSET; + __raw_writel(reg, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(0, MXC_CCM_CCGR4); + /* Initialise the EMI clocks to be OFF when ARM is in WAIT mode. */ + __raw_writel((1 << MXC_CCM_CCGR5_CG4_OFFSET) | + (1 << MXC_CCM_CCGR5_CG12_OFFSET) | + (1 << MXC_CCM_CCGR5_CG13_OFFSET) | + (1 << MXC_CCM_CCGR5_CG14_OFFSET) | + MXC_CCM_CCGR5_CG11_MASK, MXC_CCM_CCGR5); + + ckil_clk.rate = ckil; + ckih_clk.rate = ckih1; + osc_clk.rate = osc; + + clk_tree_init(); + + for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++) + clk_register(*clkp); + + reg = __raw_readl(MXC_CCM_CCSR); + /*STEP_CLK mxc_timer_init(&gpt_clk[0], IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT); + - make sure its source is lp_apm */ + reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; + __raw_writel(reg, MXC_CCM_CCSR); + + /* This will propagate to all children and init all the clock rates */ + propagate_rate(&osc_clk); + propagate_rate(&ckih_clk); + propagate_rate(&ckil_clk); + + _clk_pll_disable(&pll3_sw_clk); + + clk_enable(&cpu_clk); + clk_enable(&main_bus_clk); + + /* Move UART to run from pll2_sw_clk */ + clk_set_parent(&uart_main_clk, &pll2_sw_clk); + + /* Set the UART dividers to divide by 10, so the UART_CLK is 66.5MHz. */ + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (4 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + (1 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CSCDR1); + + /* move cspi to 24MHz */ + clk_set_parent(&cspi_main_clk, &lp_apm_clk); + clk_set_rate(&cspi_main_clk, 12000000); + + /*move the spdif0 to spdif_xtal_ckl */ + clk_set_parent(&spdif0_clk[0], &spdif_xtal_clk); + /*set the SPDIF dividers to 1 */ + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK; + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK; + __raw_writel(reg, MXC_CCM_CDCDR); + + /* move the spdif1 to 24MHz */ + clk_set_parent(&spdif1_clk[0], &spdif_xtal_clk); + /* set the spdif1 dividers to 1 */ + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK; + __raw_writel(reg, MXC_CCM_CDCDR); + + /* Move SSI clocks to SSI_LP_APM clock */ + clk_set_parent(&ssi_lp_apm_clk, &lp_apm_clk); + + clk_set_parent(&ssi1_clk[0], &ssi_lp_apm_clk); + /* set the SSI dividers to divide by 2 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + clk_set_parent(&ssi2_clk[0], &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS2CDR); + + /* Change the SSI_EXT1_CLK to be sourced from SSI1_CLK_ROOT */ + clk_set_parent(&ssi_ext1_clk, &ssi1_clk[0]); + clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]); + + propagate_rate(&ssi_lp_apm_clk); + + clk_set_parent(&arm_axi_clk, &emi_core_clk); + + clk_set_parent(&ipu_clk[0], &axi_a_clk); + clk_set_parent(&vpu_clk[0], &axi_a_clk); + clk_set_parent(&vpu_clk[1], &axi_a_clk); + + clk_set_parent(&emi_core_clk, &ahb_clk); + clk_set_rate(&emi_core_clk, clk_round_rate(&emi_core_clk, 130000000)); + propagate_rate(&emi_core_clk); + clk_set_rate(&emi_intr_clk, clk_round_rate(&emi_intr_clk, 66000000)); + /* Change the NFC clock rate to be 1:3 ratio with emi clock. */ + clk_set_rate(&nfc_clk, clk_round_rate(&nfc_clk, + (clk_get_rate(&emi_slow_clk))/3)); + + clk_set_parent(&usb_phy_clk, &osc_clk); + + clk_set_parent(&cko1_clk, &ipg_perclk); + clk_set_rate(&cko1_clk, 8000000); + /* Set the current working point. */ + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + for (i = 0; i < cpu_wp_nr; i++) { + if (clk_get_rate(&cpu_clk) == cpu_wp_tbl[i].cpu_rate) { + cpu_curr_wp = i; + break; + } + } + if (i > cpu_wp_nr) + BUG(); + + propagate_rate(&osc_clk); + propagate_rate(&pll1_sw_clk); + propagate_rate(&pll2_sw_clk); + +#ifdef DVFS_SW_WORKAROUND + clk_set_parent(&periph_apm_clk, &pll3_sw_clk); + + clk_set_parent(&main_bus_clk, &periph_apm_clk); + clk_disable(&pll2_sw_clk); + clk_set_rate(&pll2_sw_clk, 266000000); + pll2_sw_clk.recalc(&pll2_sw_clk); + clk_enable(&pll2_sw_clk); + clk_set_parent(&main_bus_clk, &pll2_sw_clk); + + clk_set_rate(&ahb_clk, clk_round_rate(&ahb_clk, 130000000)); + clk_set_rate(&axi_b_clk, clk_round_rate(&axi_b_clk, 110000000)); + clk_set_rate(&axi_c_clk, clk_round_rate(&axi_c_clk, 166000000)); + clk_set_rate(&axi_a_clk, clk_round_rate(&axi_a_clk, 130000000)); + + clk_set_parent(&emi_core_clk, &ahb_clk); + clk_set_rate(&emi_core_clk, clk_round_rate(&emi_core_clk, 130000000)); + clk_set_rate(&emi_intr_clk, clk_round_rate(&emi_intr_clk, 66000000)); + + clk_set_rate(&axi_c_clk, clk_round_rate(&axi_c_clk, 130000000)); + clk_set_parent(&ddr_clk, &axi_c_clk); + /* Set the UART dividers to divide by 6, so the UART_CLK is 66.5MHz. */ + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (3 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + (0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CSCDR1); +#endif + + mxc_timer_init(&gpt_clk[0], IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT); + + return 0; +} + +/*! + * Setup cpu clock based on working point. + * @param wp cpu freq working point + * @return 0 on success or error code on failure. + */ +static int cpu_clk_set_wp(int wp) +{ + struct cpu_wp *p; + u32 reg; + u32 stat; + + if (wp == cpu_curr_wp) + return 0; + + p = &cpu_wp_tbl[wp]; + + if (!dvfs_core_is_active) { + /* Change the ARM clock to requested frequency */ + /* First move the ARM clock to step clock */ + /* which is running at 24MHz. */ + + /* Change the source of pll1_sw_clk to be the step_clk */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + /* Stop the PLL */ + reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + + /* PDF and MFI */ + reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_OP); + + /* MFD */ + __raw_writel(p->mfd, MXC_DPLL1_BASE + MXC_PLL_DP_MFD); + + /* MFI */ + __raw_writel(p->mfn, MXC_DPLL1_BASE + MXC_PLL_DP_MFN); + + reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + reg |= MXC_PLL_DP_CTL_UPEN; + /* Set the UPEN bits */ + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + /* Forcefully restart the PLL */ + reg |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + + /* Wait for the PLL to lock */ + do { + stat = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL) & + MXC_PLL_DP_CTL_LRF; + } while (!stat); + + reg = __raw_readl(MXC_CCM_CCSR); + /* Move the PLL1 back to the pll1_main_clk */ + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } + cpu_curr_wp = wp; + + pll1_sw_clk.rate = cpu_wp_tbl[wp].cpu_rate; + pll1_main_clk.rate = pll1_sw_clk.rate; + cpu_clk.rate = pll1_sw_clk.rate; + +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + + if (wp == 0) + dptc_resume(DPTC_GP_ID); + else + dptc_suspend(DPTC_GP_ID); + + return 0; +} diff --git a/arch/arm/mach-mx37/cpu.c b/arch/arm/mach-mx37/cpu.c new file mode 100644 index 000000000000..1ca44ae9ed86 --- /dev/null +++ b/arch/arm/mach-mx37/cpu.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/*! + * @file mach-mx37/cpu.c + * + * @brief This file contains the CPU initialization code. + * + * @ingroup MSL_MX37 + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <asm/hardware/cache-l2x0.h> + +/*! + * CPU initialization. It is called by fixup_mxc_board() + */ +void __init mxc_cpu_init(void) +{ + if (!system_rev) { + mxc_set_system_rev(0x37, CHIP_REV_1_0); + } +} + +/*! + * Post CPU init code + * + * @return 0 always + */ +static int __init post_cpu_init(void) +{ + void *l2_base; + volatile unsigned long aips_reg; + + /* Initialize L2 cache */ + l2_base = ioremap(L2CC_BASE_ADDR, SZ_4K); + if (l2_base) { + l2x0_init(l2_base, 0x0003001B, 0x00000000); + } + + __raw_writel(0x0, IO_ADDRESS(AIPS1_BASE_ADDR + 0x40)); + __raw_writel(0x0, IO_ADDRESS(AIPS1_BASE_ADDR + 0x44)); + __raw_writel(0x0, IO_ADDRESS(AIPS1_BASE_ADDR + 0x48)); + __raw_writel(0x0, IO_ADDRESS(AIPS1_BASE_ADDR + 0x4C)); + aips_reg = __raw_readl(IO_ADDRESS(AIPS1_BASE_ADDR + 0x50)); + aips_reg &= 0x00FFFFFF; + __raw_writel(aips_reg, IO_ADDRESS(AIPS1_BASE_ADDR + 0x50)); + + __raw_writel(0x0, IO_ADDRESS(AIPS2_BASE_ADDR + 0x40)); + __raw_writel(0x0, IO_ADDRESS(AIPS2_BASE_ADDR + 0x44)); + __raw_writel(0x0, IO_ADDRESS(AIPS2_BASE_ADDR + 0x48)); + __raw_writel(0x0, IO_ADDRESS(AIPS2_BASE_ADDR + 0x4C)); + aips_reg = __raw_readl(IO_ADDRESS(AIPS2_BASE_ADDR + 0x50)); + aips_reg &= 0x00FFFFFF; + __raw_writel(aips_reg, IO_ADDRESS(AIPS2_BASE_ADDR + 0x50)); + + return 0; +} + +postcore_initcall(post_cpu_init); diff --git a/arch/arm/mach-mx37/crm_regs.h b/arch/arm/mach-mx37/crm_regs.h new file mode 100644 index 000000000000..ccc96f02ff68 --- /dev/null +++ b/arch/arm/mach-mx37/crm_regs.h @@ -0,0 +1,611 @@ +/* + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ARCH_ARM_MACH_MX37_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX37_CRM_REGS_H__ + +#define MXC_CCM_BASE ((char *)IO_ADDRESS(CCM_BASE_ADDR)) +#define MXC_DPLL1_BASE IO_ADDRESS(PLL0_BASE_ADDR) +#define MXC_DPLL2_BASE IO_ADDRESS(PLL1_BASE_ADDR) +#define MXC_DPLL3_BASE IO_ADDRESS(PLL2_BASE_ADDR) + +/* PLL Register Offsets */ +#define MXC_PLL_DP_CTL 0x00 +#define MXC_PLL_DP_CONFIG 0x04 +#define MXC_PLL_DP_OP 0x08 +#define MXC_PLL_DP_MFD 0x0C +#define MXC_PLL_DP_MFN 0x10 +#define MXC_PLL_DP_MFNMINUS 0x14 +#define MXC_PLL_DP_MFNPLUS 0x18 +#define MXC_PLL_DP_HFS_OP 0x1C +#define MXC_PLL_DP_HFS_MFD 0x20 +#define MXC_PLL_DP_HFS_MFN 0x24 +#define MXC_PLL_DP_MFN_TOGC 0x28 +#define MXC_PLL_DP_DESTAT 0x2c + +/* PLL Register Bit definitions */ +#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 +#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 +#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 +#define MXC_PLL_DP_CTL_ADE 0x800 +#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 +#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) +#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 +#define MXC_PLL_DP_CTL_HFSM 0x80 +#define MXC_PLL_DP_CTL_PRE 0x40 +#define MXC_PLL_DP_CTL_UPEN 0x20 +#define MXC_PLL_DP_CTL_RST 0x10 +#define MXC_PLL_DP_CTL_RCP 0x8 +#define MXC_PLL_DP_CTL_PLM 0x4 +#define MXC_PLL_DP_CTL_BRM0 0x2 +#define MXC_PLL_DP_CTL_LRF 0x1 + +#define MXC_PLL_DP_CONFIG_BIST 0x8 +#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 +#define MXC_PLL_DP_CONFIG_AREN 0x2 +#define MXC_PLL_DP_CONFIG_LDREQ 0x1 + +#define MXC_PLL_DP_OP_MFI_OFFSET 4 +#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) +#define MXC_PLL_DP_OP_PDF_OFFSET 0 +#define MXC_PLL_DP_OP_PDF_MASK 0xF + +#define MXC_PLL_DP_MFD_OFFSET 0 +#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_OFFSET 0x0 +#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17) +#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16) +#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0 +#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF + +#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) +#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF + +/* Register addresses of CCM*/ +#define MXC_CCM_CCR (MXC_CCM_BASE + 0x00) +#define MXC_CCM_CCDR (MXC_CCM_BASE + 0x04) +#define MXC_CCM_CSR (MXC_CCM_BASE + 0x08) +#define MXC_CCM_CCSR (MXC_CCM_BASE + 0x0C) +#define MXC_CCM_CACRR (MXC_CCM_BASE + 0x10) +#define MXC_CCM_CBCDR2 (MXC_CCM_BASE + 0x18) +#define MXC_CCM_CBCDR3 (MXC_CCM_BASE + 0x1C) +#define MXC_CCM_CBCDR4 (MXC_CCM_BASE + 0x20) +#define MXC_CCM_CBCDR5 (MXC_CCM_BASE + 0x24) +#define MXC_CCM_CBCDR6 (MXC_CCM_BASE + 0x28) +#define MXC_CCM_CBCDR7 (MXC_CCM_BASE + 0x2C) +#define MXC_CCM_CAMR (MXC_CCM_BASE + 0x30) +#define MXC_CCM_CSCMR1 (MXC_CCM_BASE + 0x34) +#define MXC_CCM_CSCMR2 (MXC_CCM_BASE + 0x38) +#define MXC_CCM_CSCDR1 (MXC_CCM_BASE + 0x3C) +#define MXC_CCM_CS1CDR (MXC_CCM_BASE + 0x40) +#define MXC_CCM_CS2CDR (MXC_CCM_BASE + 0x44) +#define MXC_CCM_CSECDR1 (MXC_CCM_BASE + 0x48) +#define MXC_CCM_CSECDR2 (MXC_CCM_BASE + 0x4C) +#define MXC_CCM_CECDR (MXC_CCM_BASE + 0x50) +#define MXC_CCM_CDCDR (MXC_CCM_BASE + 0x54) +#define MXC_CCM_CH1CDR (MXC_CCM_BASE + 0x58) +#define MXC_CCM_CH2CDR (MXC_CCM_BASE + 0x5C) +#define MXC_CCM_CSCDR2 (MXC_CCM_BASE + 0x60) +#define MXC_CCM_CR2 (MXC_CCM_BASE + 0x64) +#define MXC_CCM_CDHIPR (MXC_CCM_BASE + 0x68) +#define MXC_CCM_CDCR (MXC_CCM_BASE + 0x6C) +#define MXC_CCM_CTOR (MXC_CCM_BASE + 0x70) +#define MXC_CCM_CLPCR (MXC_CCM_BASE + 0x74) +#define MXC_CCM_CISR (MXC_CCM_BASE + 0x78) +#define MXC_CCM_CIMR (MXC_CCM_BASE + 0x7C) +#define MXC_CCM_CCOSR (MXC_CCM_BASE + 0x80) +#define MXC_CCM_CGPR (MXC_CCM_BASE + 0x84) +#define MXC_CCM_CCGR0 (MXC_CCM_BASE + 0x88) +#define MXC_CCM_CCGR1 (MXC_CCM_BASE + 0x8C) +#define MXC_CCM_CCGR2 (MXC_CCM_BASE + 0x90) +#define MXC_CCM_CCGR3 (MXC_CCM_BASE + 0x94) +#define MXC_CCM_CCGR4 (MXC_CCM_BASE + 0x98) +#define MXC_CCM_CCGR5 (MXC_CCM_BASE + 0x9C) +#define MXC_CCM_CMEOR (MXC_CCM_BASE + 0xA0) + +/* Define the bits in register CCR */ +#define MXC_CCM_CCR_COSC_EN (1 << 11) +#define MXC_CCM_CCR_FPM_MULT_MASK (1 << 10) +#define MXC_CCM_CCR_CAMP_EN (1 << 9) +#define MXC_CCM_CCR_FPM_EN (1 << 8) +#define MXC_CCM_CCR_OSCNT_OFFSET (0) +#define MXC_CCM_CCR_OSCNT_MASK (0xFF) + +/* Define the bits in register CCDR */ +#define MXC_CCM_CCDR_IPU_HS_MASK (0x1 << 17) +#define MXC_CCM_CCDR_EMI_HS_MASK (0x1 << 16) +#define MXC_CCM_CCDR_LOAD_DIVIDERS (0x1 << 0) + +/* Define the bits in register CSR */ +#define MXC_CCM_CSR_COSR_READY (1 << 4) +#define MXC_CCM_CSR_LVS_VALUE (1 << 3) +#define MXC_CCM_CSR_CAMP_READY (1 << 2) +#define MXC_CCM_CSR_FPM_READY (1 << 1) +#define MXC_CCM_CSR_REF_EN_B (1 << 0) + +/* Define the bits in register CCSR */ +#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 9) +#define MXC_CCM_CCSR_STEP_SEL_OFFSET (7) +#define MXC_CCM_CCSR_STEP_SEL_MASK (0x3 << 7) +#define MXC_CCM_CCSR_PLL2_PODF_OFFSET (5) +#define MXC_CCM_CCSR_PLL2_PODF_MASK (0x3 << 5) +#define MXC_CCM_CCSR_PLL3_PODF_OFFSET (3) +#define MXC_CCM_CCSR_PLL3_PODF_MASK (0x3 << 3) +#define MXC_CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) +#define MXC_CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1) +#define MXC_CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0) + +/* Define the bits in register CACRR */ +#define MXC_CCM_CACRR_ARM_PODF_OFFSET (0) +#define MXC_CCM_CACRR_ARM_PODF_MASK (0x7) + +/* Define the bits in register CBCDR2 */ +#define MXC_CCM_CBCDR2_AHB_PODF_OFFSET (10) +#define MXC_CCM_CBCDR2_AHB_PODF_MASK (0x7 << 10) +#define MXC_CCM_CBCDR2_IPG_PODF_OFFSET (8) +#define MXC_CCM_CBCDR2_IPG_PODF_MASK (0x3 << 8) +#define MXC_CCM_CBCDR2_PERCLK_PRED1_OFFSET (6) +#define MXC_CCM_CBCDR2_PERCLK_PRED1_MASK (0x3 << 6) +#define MXC_CCM_CBCDR2_PERCLK_PRED2_OFFSET (3) +#define MXC_CCM_CBCDR2_PERCLK_PRED2_MASK (0x7 << 3) +#define MXC_CCM_CBCDR2_PERCLK_PODF_OFFSET (0) +#define MXC_CCM_CBCDR2_PERCLK_PODF_MASK (0x7) + +/* Define the bits in register CBCDR3 */ +#define MXC_CCM_CBCDR3_AXI_A_PODF_OFFSET (0) +#define MXC_CCM_CBCDR3_AXI_A_PODF_MASK (0x7) + +/* Define the bits in register CBCDR4 */ +#define MXC_CCM_CBCDR4_AXI_B_PODF_OFFSET (0) +#define MXC_CCM_CBCDR4_AXI_B_PODF_MASK (0x7) + +/* Define the bits in register CBCDR5 */ +#define MXC_CCM_CBCDR5_AXI_C_PODF_OFFSET (0) +#define MXC_CCM_CBCDR5_AXI_C_PODF_MASK (0x7) + +/* Define the bits in register CBCDR6 */ +#define MXC_CCM_CBCDR6_EMI_PODF_OFFSET (0) +#define MXC_CCM_CBCDR6_EMI_PODF_MASK (0x7) +#define MXC_CCM_CBCDR6_EMI_CLK_SEL (0x1 << 3) +#define MXC_CCM_CBCDR6_PERIPH_CLK_SEL (0x1 << 4) + +/* Define the bits in register CBCDR7 */ +#define MXC_CCM_CBCDR7_IPG_INT_MEM_PODF_OFFSET (3) +#define MXC_CCM_CBCDR7_IPG_INIT_MEM_PODF_MASK (0x3 << 3) +#define MXC_CCM_CBCDR7_NFC_PODF_OFFSET (0) +#define MXC_CCM_CBCDR7_NFC_PODF_MASK (0x7) + +/* Define the bits in register CAMR */ +#define MXC_CCM_CAMR_PERIPH_CLK_SEL_OFFSET (12) +#define MXC_CCM_CAMR_PERIPH_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CAMR_DDR_CLK_SEL_OFFSET (10) +#define MXC_CCM_CAMR_DDR_CLK_SEL_MASK (0x3 << 10) +#define MXC_CCM_CAMR_ARM_AXI_CLK_SEL_OFFSET (8) +#define MXC_CCM_CAMR_ARM_AXI_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CAMR_VPU_CLK_SEL_OFFSET (6) +#define MXC_CCM_CAMR_VPU_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CAMR_VPU_AXI_CLK_SEL_OFFSET (4) +#define MXC_CCM_CAMR_VPU_AXI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CAMR_IPU_HSP_CLK_SEL_OFFSET (2) +#define MXC_CCM_CAMR_IPU_HSP_CLK_SEL_MASK (0x3 << 2) + +/* Define the bits in register CSCMR1 */ +#define MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET (30) +#define MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK (0x3 << 30) +#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET (28) +#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK (0x3 << 28) +#define MXC_CCM_CSCMR1_DI_CLK_SEL (0x1 << 27) +#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET (26) +#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL (0x1 << 26) +#define MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET (24) +#define MXC_CCM_CSCMR1_UART_CLK_SEL_MASK (0x3 << 24) +#define MXC_CCM_CSCMR1_USBOH2_CLK_SEL_OFFSET (22) +#define MXC_CCM_CSCMR1_USBOH2_CLK_SEL_MASK (0x3 << 22) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_OFFSET (20) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL (0x1 << 19) +#define MXC_CCM_CSCMR1_PERCLK_IPG_CLK_SEL (0x1 << 18) +#define MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_OFFSET (16) +#define MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET (12) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CSCMR1_SSI_APM_CLK_SEL (0x1 << 9) +#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL (0x1 << 8) +#define MXC_CCM_CSCMR1_TVE_CLK_SEL (0x1 << 7) +#define MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL (0x1 << 6) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET (4) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CSCMR1_PERCLK_LP_APM_CLK_SEL (0x1 << 2) +#define MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL (0x1 << 1) +#define MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL (0x1) + +/* Define the bits in register CSCMR2 */ +#define MXC_CCM_CSCMR2_SPDIF1_COM (1 << 5) +#define MXC_CCM_CSCMR2_SPDIF0_COM (1 << 4) +#define MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_OFFSET (2) +#define MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_MASK (0x3 << 2) +#define MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_OFFSET (0) +#define MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_MASK (0x3) + +/* Define the bits in register CSCDR1 */ +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET (14) +#define MXC_CCM_CSCDR1_PGC_CLK_PODF_MASK (0x3 << 14) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_OFFSET (11) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_MASK (0x7 << 11) +#define MXC_CCM_CSCDR1_USBOH2_CLK_PRED_OFFSET (8) +#define MXC_CCM_CSCDR1_USBOH2_CLK_PRED_MASK (0x7 << 8) +#define MXC_CCM_CSCDR1_USBOH2_CLK_PODF_OFFSET (6) +#define MXC_CCM_CSCDR1_USBOH2_CLK_PODF_MASK (0x3 << 6) +#define MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET (3) +#define MXC_CCM_CSCDR1_UART_CLK_PRED_MASK (0x7 << 3) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK (0x7) + +/* Define the bits in register CS1CDR and CS2CDR */ +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK (0x3F) + +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET (0) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CSECDR1 and CSECDR2 */ +#define MXC_CCM_CSECDR1_SSI_EXT1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSECDR1_SSI_EXT1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSECDR1_SSI_EXT1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSECDR1_SSI_EXT1_CLK_PODF_MASK (0x3F) + +#define MXC_CCM_CSECDR2_SSI_EXT2_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSECDR2_SSI_EXT2_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSECDR2_SSI_EXT2_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSECDR2_SSI_EXT2_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CDCDR */ +#define MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET (28) +#define MXC_CCM_CDCDR_TVE_CLK_PRED_MASK (0x7 << 28) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET (25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK (0x7 << 25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET (19) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK (0x3F << 19) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET (16) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET (9) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CDCDR_USB_PHY_PRED_OFFSET (4) +#define MXC_CCM_CDCDR_USB_PHY_PRED_MASK (0x7 << 4) +#define MXC_CCM_CDCDR_USB_PHY_PODF_OFFSET (1) +#define MXC_CCM_CDCDR_USB_PHY_PODF_MASK (0x7 << 1) + +/* Define the bits in register CSCDR2 */ +#define MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET (25) +#define MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK (0x7 << 25) +#define MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK (0x3F << 19) + +/* Define the bits in register CDHIPR */ +#define MXC_CCM_CDHIPR_ARM_PODF_BUSY (1 << 16) +#define MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY (1 << 4) +#define MXC_CCM_CDHIPR_EMI_PODF_BUSY (1 << 3) +#define MXC_CCM_CDHIPR_AXI_C_PODF_BUSY (1 << 2) +#define MXC_CCM_CDHIPR_AXI_B_PODF_BUSY (1 << 1) +#define MXC_CCM_CDHIPR_AXI_A_PODF_BUSY (1 << 0) + +/* Define the bits in register CDCR */ +#define MXC_CCM_CDCR_ARM_FREQ_SHIFT_DIVIDER (0x1 << 2) +#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_OFFSET (0) +#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK (0x3) + +/* Define the bits in register CLPCR */ +#define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS (0x1 << 22) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS (0x1 << 21) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS (0x1 << 20) +#define MXC_CCM_CLPCR_BYPASS_EMI_LPM_HS (0x1 << 19) +#define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS (0x1 << 18) +#define MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS (0x1 << 17) +#define MXC_CCM_CLPCR_BYPASS_RNGC_LPM_HS (0x1 << 16) +#define MXC_CCM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET (9) +#define MXC_CCM_CLPCR_STBY_COUNT_MASK (0x3 << 9) +#define MXC_CCM_CLPCR_VSTBY (0x1 << 8) +#define MXC_CCM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define MXC_CCM_CLPCR_SBYOS (0x1 << 6) +#define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET (3) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK (0x3 << 3) +#define MXC_CCM_CLPCR_LPM_OFFSET (0) +#define MXC_CCM_CLPCR_LPM_MASK (0x3) + +/* Define the bits in register CISR */ +#define MXC_CCM_CISR_ARM_PODF_LOADED (0x1 << 25) +#define MXC_CCM_CISR_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) +#define MXC_CCM_CISR_EMI_PODF_LOADED (0x1 << 20) +#define MXC_CCM_CISR_AXI_C_PODF_LOADED (0x1 << 19) +#define MXC_CCM_CISR_AXI_B_PODF_LOADED (0x1 << 18) +#define MXC_CCM_CISR_AXI_A_PODF_LOADED (0x1 << 17) +#define MXC_CCM_CISR_DIVIDER_LOADED (0x1 << 16) +#define MXC_CCM_CISR_COSC_READY (0x1 << 5) +#define MXC_CCM_CISR_CKIH_READY (0x1 << 4) +#define MXC_CCM_CISR_FPM_READY (0x1 << 3) +#define MXC_CCM_CISR_LRF_PLL3 (0x1 << 2) +#define MXC_CCM_CISR_LRF_PLL2 (0x1 << 1) +#define MXC_CCM_CISR_LRF_PLL1 (0x1) + +/* Define the bits in register CIMR */ +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (0x1 << 25) +#define MXC_CCM_CIMR_MASK_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) +#define MXC_CCM_CIMR_MASK_EMI_PODF_LOADED (0x1 << 20) +#define MXC_CCM_CIMR_MASK_AXI_C_PODF_LOADED (0x1 << 19) +#define MXC_CCM_CIMR_MASK_AXI_B_PODF_LOADED (0x1 << 18) +#define MXC_CCM_CIMR_MASK_AXI_A_PODF_LOADED (0x1 << 17) +#define MXC_CCM_CIMR_MASK_DIVIDER_LOADED (0x1 << 16) +#define MXC_CCM_CIMR_MASK_COSC_READY (0x1 << 5) +#define MXC_CCM_CIMR_MASK_CKIH_READY (0x1 << 4) +#define MXC_CCM_CIMR_MASK_FPM_READY (0x1 << 3) +#define MXC_CCM_CIMR_MASK_LRF_PLL3 (0x1 << 2) +#define MXC_CCM_CIMR_MASK_LRF_PLL2 (0x1 << 1) +#define MXC_CCM_CIMR_MASK_LRF_PLL1 (0x1) + +/* Define the bits in register CCOSR */ +#define MXC_CCM_CCOSR_CKO2_EN_OFFSET (0x1 << 24) +#define MXC_CCM_CCOSR_CKO2_DIV_OFFSET (21) +#define MXC_CCM_CCOSR_CKO2_DIV_MASK (0x7 << 21) +#define MXC_CCM_CCOSR_CKO2_SEL_OFFSET (16) +#define MXC_CCM_CCOSR_CKO2_SEL_MASK (0x1F << 16) +#define MXC_CCM_CCOSR_CKOL_EN (0x1 << 7) +#define MXC_CCM_CCOSR_CKOL_DIV_OFFSET (4) +#define MXC_CCM_CCOSR_CKOL_DIV_MASK (0x7 << 4) +#define MXC_CCM_CCOSR_CKOL_SEL_OFFSET (0) +#define MXC_CCM_CCOSR_CKOL_SEL_MASK (0xF) + +/* Define the bits in registers CGPR */ +#define MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE (0x1 << 4) +#define MXC_CCM_CGPR_FPM_SEL (0x1 << 3) +#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_OFFSET (0) +#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_MASK (0x7) + +/* Define the bits in registers CCGRx */ +#define MXC_CCM_CCGR_CG_MASK 0x3 + +#define MXC_CCM_CCGR0_CG15_OFFSET 30 +#define MXC_CCM_CCGR0_CG14_OFFSET 28 +#define MXC_CCM_CCGR0_CG14_MASK (0x3 << 28) +#define MXC_CCM_CCGR0_CG13_OFFSET 26 +#define MXC_CCM_CCGR0_CG13_MASK (0x3 << 26) +#define MXC_CCM_CCGR0_CG12_OFFSET 24 +#define MXC_CCM_CCGR0_CG12_MASK (0x3 << 24) +#define MXC_CCM_CCGR0_CG11_OFFSET 22 +#define MXC_CCM_CCGR0_CG10_OFFSET 20 +#define MXC_CCM_CCGR0_CG9_OFFSET 18 +#define MXC_CCM_CCGR0_CG8_OFFSET 16 +#define MXC_CCM_CCGR0_CG7_OFFSET 14 +#define MXC_CCM_CCGR0_CG6_OFFSET 12 +#define MXC_CCM_CCGR0_CG5_OFFSET 10 +#define MXC_CCM_CCGR0_CG4_OFFSET 8 +#define MXC_CCM_CCGR0_CG3_OFFSET 6 +#define MXC_CCM_CCGR0_CG2_OFFSET 4 +#define MXC_CCM_CCGR0_CG2_MASK (0x3 << 4) +#define MXC_CCM_CCGR0_CG1_OFFSET 2 +#define MXC_CCM_CCGR0_CG1_MASK (0x3 << 2) +#define MXC_CCM_CCGR0_CG0_OFFSET 0 +#define MXC_CCM_CCGR0_CG0_MASK 0x3 + +#define MXC_CCM_CCGR1_CG15_OFFSET 30 +#define MXC_CCM_CCGR1_CG14_OFFSET 28 +#define MXC_CCM_CCGR1_CG13_OFFSET 26 +#define MXC_CCM_CCGR1_CG12_OFFSET 24 +#define MXC_CCM_CCGR1_CG11_OFFSET 22 +#define MXC_CCM_CCGR1_CG10_OFFSET 20 +#define MXC_CCM_CCGR1_CG9_OFFSET 18 +#define MXC_CCM_CCGR1_CG8_OFFSET 16 +#define MXC_CCM_CCGR1_CG7_OFFSET 14 +#define MXC_CCM_CCGR1_CG6_OFFSET 12 +#define MXC_CCM_CCGR1_CG5_OFFSET 10 +#define MXC_CCM_CCGR1_CG4_OFFSET 8 +#define MXC_CCM_CCGR1_CG3_OFFSET 6 +#define MXC_CCM_CCGR1_CG2_OFFSET 4 +#define MXC_CCM_CCGR1_CG1_OFFSET 2 +#define MXC_CCM_CCGR1_CG0_OFFSET 0 + +#define MXC_CCM_CCGR2_CG15_OFFSET 30 +#define MXC_CCM_CCGR2_CG14_OFFSET 28 +#define MXC_CCM_CCGR2_CG13_OFFSET 26 +#define MXC_CCM_CCGR2_CG12_OFFSET 24 +#define MXC_CCM_CCGR2_CG11_OFFSET 22 +#define MXC_CCM_CCGR2_CG10_OFFSET 20 +#define MXC_CCM_CCGR2_CG9_OFFSET 18 +#define MXC_CCM_CCGR2_CG8_OFFSET 16 +#define MXC_CCM_CCGR2_CG7_OFFSET 14 +#define MXC_CCM_CCGR2_CG6_OFFSET 12 +#define MXC_CCM_CCGR2_CG5_OFFSET 10 +#define MXC_CCM_CCGR2_CG4_OFFSET 8 +#define MXC_CCM_CCGR2_CG3_OFFSET 6 +#define MXC_CCM_CCGR2_CG2_OFFSET 4 +#define MXC_CCM_CCGR2_CG1_OFFSET 2 +#define MXC_CCM_CCGR2_CG0_OFFSET 0 + +#define MXC_CCM_CCGR3_CG15_OFFSET 30 +#define MXC_CCM_CCGR3_CG14_OFFSET 28 +#define MXC_CCM_CCGR3_CG13_OFFSET 26 +#define MXC_CCM_CCGR3_CG12_OFFSET 24 +#define MXC_CCM_CCGR3_CG11_OFFSET 22 +#define MXC_CCM_CCGR3_CG10_OFFSET 20 +#define MXC_CCM_CCGR3_CG9_OFFSET 18 +#define MXC_CCM_CCGR3_CG8_OFFSET 16 +#define MXC_CCM_CCGR3_CG7_OFFSET 14 +#define MXC_CCM_CCGR3_CG6_OFFSET 12 +#define MXC_CCM_CCGR3_CG5_OFFSET 10 +#define MXC_CCM_CCGR3_CG4_OFFSET 8 +#define MXC_CCM_CCGR3_CG3_OFFSET 6 +#define MXC_CCM_CCGR3_CG2_OFFSET 4 +#define MXC_CCM_CCGR3_CG1_OFFSET 2 +#define MXC_CCM_CCGR3_CG0_OFFSET 0 + +#define MXC_CCM_CCGR4_CG15_OFFSET 30 +#define MXC_CCM_CCGR4_CG14_OFFSET 28 +#define MXC_CCM_CCGR4_CG13_OFFSET 26 +#define MXC_CCM_CCGR4_CG12_OFFSET 24 +#define MXC_CCM_CCGR4_CG11_OFFSET 22 +#define MXC_CCM_CCGR4_CG10_OFFSET 20 +#define MXC_CCM_CCGR4_CG9_OFFSET 18 +#define MXC_CCM_CCGR4_CG8_OFFSET 16 +#define MXC_CCM_CCGR4_CG7_OFFSET 14 +#define MXC_CCM_CCGR4_CG6_OFFSET 12 +#define MXC_CCM_CCGR4_CG5_OFFSET 10 +#define MXC_CCM_CCGR4_CG4_OFFSET 8 +#define MXC_CCM_CCGR4_CG3_OFFSET 6 +#define MXC_CCM_CCGR4_CG2_OFFSET 4 +#define MXC_CCM_CCGR4_CG1_OFFSET 2 +#define MXC_CCM_CCGR4_CG0_OFFSET 0 + +#define MXC_CCM_CCGR5_CG15_OFFSET 30 +#define MXC_CCM_CCGR5_CG14_OFFSET 28 +#define MXC_CCM_CCGR5_CG14_MASK (0x3 << 28) +#define MXC_CCM_CCGR5_CG13_OFFSET 26 +#define MXC_CCM_CCGR5_CG13_MASK (0x3 << 26) +#define MXC_CCM_CCGR5_CG12_OFFSET 24 +#define MXC_CCM_CCGR5_CG12_MASK (0x3 << 24) +#define MXC_CCM_CCGR5_CG11_OFFSET 22 +#define MXC_CCM_CCGR5_CG11_MASK (0x3 << 22) +#define MXC_CCM_CCGR5_CG10_OFFSET 20 +#define MXC_CCM_CCGR5_CG9_OFFSET 18 +#define MXC_CCM_CCGR5_CG8_OFFSET 16 +#define MXC_CCM_CCGR5_CG7_OFFSET 14 +#define MXC_CCM_CCGR5_CG6_OFFSET 12 +#define MXC_CCM_CCGR5_CG5_OFFSET 10 +#define MXC_CCM_CCGR5_CG4_OFFSET 8 +#define MXC_CCM_CCGR5_CG3_OFFSET 6 +#define MXC_CCM_CCGR5_CG2_OFFSET 4 +#define MXC_CCM_CCGR5_CG1_OFFSET 2 +#define MXC_CCM_CCGR5_CG0_OFFSET 0 + +#define MXC_ARM1176_BASE IO_ADDRESS(ARM1176_BASE_ADDR) +#define MXC_GPC_BASE IO_ADDRESS(GPC_BASE_ADDR) +#define MXC_DPTC_LP_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x80) +#define MXC_DPTC_GP_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x100) +#define MXC_DVFS_CORE_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x180) +#define MXC_DPTC_PER_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x1C0) +#define MXC_PGC_IPU_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x220) +#define MXC_PGC_VPU_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x240) +#define MXC_SRPGC_EMI_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x280) +#define MXC_SRPGC_ARM_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x2A0) +#define MXC_EMPGC0_ARM_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x2C0) +#define MXC_EMPGC1_ARM_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x2D0) + +/* ARM1176 platform */ +#define MXC_ARM1176_PLAT_PVID (MXC_ARM1176_BASE + 0x0) +#define MXC_ARM1176_PLAT_GPC (MXC_ARM1176_BASE + 0x4) +#define MXC_ARM1176_PLAT_PIC (MXC_ARM1176_BASE + 0x8) +#define MXC_ARM1176_PLAT_L2SO (MXC_ARM1176_BASE + 0xC) +#define MXC_ARM1176_PLAT_EMSO (MXC_ARM1176_BASE + 0x10) +#define MXC_ARM1176_PLAT_LPC (MXC_ARM1176_BASE + 0x14) +#define MXC_ARM1176_PLAT_ICGC (MXC_ARM1176_BASE + 0x18) +#define MXC_ARM1176_PLAT_AMC (MXC_ARM1176_BASE + 0x1C) + +/* GPC */ +#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0) +#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) +#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) + +/* DVFS CORE */ +#define MXC_DVFSTHRS (MXC_DVFS_CORE_BASE + 0x00) +#define MXC_DVFSCOUN (MXC_DVFS_CORE_BASE + 0x04) +#define MXC_DVFSSIG1 (MXC_DVFS_CORE_BASE + 0x08) +#define MXC_DVFSSIG0 (MXC_DVFS_CORE_BASE + 0x0C) +#define MXC_DVFSGPC0 (MXC_DVFS_CORE_BASE + 0x10) +#define MXC_DVFSGPC1 (MXC_DVFS_CORE_BASE + 0x14) +#define MXC_DVFSGPBT (MXC_DVFS_CORE_BASE + 0x18) +#define MXC_DVFSEMAC (MXC_DVFS_CORE_BASE + 0x1C) +#define MXC_DVFSCNTR (MXC_DVFS_CORE_BASE + 0x20) +#define MXC_DVFSLTR0_0 (MXC_DVFS_CORE_BASE + 0x24) +#define MXC_DVFSLTR0_1 (MXC_DVFS_CORE_BASE + 0x28) +#define MXC_DVFSLTR1_0 (MXC_DVFS_CORE_BASE + 0x2C) +#define MXC_DVFSLTR1_1 (MXC_DVFS_CORE_BASE + 0x30) +#define MXC_DVFSPT0 (MXC_DVFS_CORE_BASE + 0x34) +#define MXC_DVFSPT1 (MXC_DVFS_CORE_BASE + 0x38) +#define MXC_DVFSPT2 (MXC_DVFS_CORE_BASE + 0x3C) +#define MXC_DVFSPT3 (MXC_DVFS_CORE_BASE + 0x40) + +/* DPTC GP */ +#define MXC_GP_DPTCCR (MXC_DPTC_GP_BASE + 0x00) +#define MXC_GP_DPTCDBG (MXC_DPTC_GP_BASE + 0x04) +#define MXC_GP_DCVR0 (MXC_DPTC_GP_BASE + 0x08) +#define MXC_GP_DCVR1 (MXC_DPTC_GP_BASE + 0x0C) +#define MXC_GP_DCVR2 (MXC_DPTC_GP_BASE + 0x10) +#define MXC_GP_DCVR3 (MXC_DPTC_GP_BASE + 0x14) + +/* DPTC LP */ +#define MXC_LP_DPTCCR (MXC_DPTC_LP_BASE + 0x00) +#define MXC_LP_DPTCDBG (MXC_DPTC_LP_BASE + 0x04) +#define MXC_LP_DCVR0 (MXC_DPTC_LP_BASE + 0x08) +#define MXC_LP_DCVR1 (MXC_DPTC_LP_BASE + 0x0C) +#define MXC_LP_DCVR2 (MXC_DPTC_LP_BASE + 0x10) +#define MXC_LP_DCVR3 (MXC_DPTC_LP_BASE + 0x14) + +#define MXC_DPTCCR_DRCE3 0x00400000 +#define MXC_DPTCCR_DRCE2 0x00200000 +#define MXC_DPTCCR_DRCE1 0x00100000 +#define MXC_DPTCCR_DRCE0 0x00080000 +#define MXC_DPTCCR_DCR_256 0x00060000 +#define MXC_DPTCCR_DCR_128 0x00040000 +#define MXC_DPTCCR_DCR_64 0x00020000 +#define MXC_DPTCCR_DCR_32 0x00000000 +#define MXC_DPTCCR_DSMM 0x00000040 +#define MXC_DPTCCR_DPNVCR 0x00000020 +#define MXC_DPTCCR_DPVV 0x00000010 +#define MXC_DPTCCR_VAIM 0x00000008 +#define MXC_DPTCCR_VAI_OFFSET 1 +#define MXC_DPTCCR_VAI_MASK 0x00000006 +#define MXC_DPTCCR_DEN 0x00000001 + +#define MXC_GPCCNTR_GPCIRQ 0x00100000 +#define MXC_GPCCNTR_DPTC0CR 0x00040000 +#define MXC_GPCCNTR_DPTC1CR 0x00080000 +#define MXC_GPCCNTR_ADU 0x00008000 + +/* SRPG */ +#define MXC_SRPGC_EMI_SRPGCR (MXC_SRPGC_EMI_BASE + 0x0) +#define MXC_SRPGC_ARM_SRPGCR (MXC_SRPGC_ARM_BASE + 0x0) +#define MXC_EMPGC0_ARM_EMPGCR (MXC_EMPGC0_ARM_BASE + 0x0) +#define MXC_EMPGC1_ARM_EMPGCR (MXC_EMPGC1_ARM_BASE + 0x0) + +#define MXC_PGC_IPU_PGCR (MXC_PGC_IPU_BASE + 0x0) +#define MXC_PGC_IPU_PGSR (MXC_PGC_IPU_BASE + 0xC) +#define MXC_PGC_VPU_PGCR (MXC_PGC_VPU_BASE + 0x0) +#define MXC_PGC_VPU_PGSR (MXC_PGC_VPU_BASE + 0xC) + +#define MXC_ARM1176_PLAT_LPC_DSM (1 << 16) +#define MXC_ARM1176_PLAT_LPC_DBG_DSM (1 << 17) + +#define MXC_GPC_PGR_ARMPG_OFFSET 8 +#define MXC_GPC_PGR_ARMPG_MASK (3 << 8) + +#define MXC_PGCR_PCR 1 +#define MXC_SRPGCR_PCR 1 +#define MXC_EMPGCR_PCR 1 + +#define MXC_PGSR_PSR 1 + +#endif /* __ARCH_ARM_MACH_MX37_CRM_REGS_H__ */ diff --git a/arch/arm/mach-mx37/devices.c b/arch/arm/mach-mx37/devices.c new file mode 100644 index 000000000000..300648d8f3dd --- /dev/null +++ b/arch/arm/mach-mx37/devices.c @@ -0,0 +1,1004 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/mxc_scc2_driver.h> +#include <linux/spi/spi.h> + +#include <mach/gpio.h> +#include <mach/hardware.h> +#include <mach/mxc_dptc.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdma.h> +#include <mach/spba.h> + +#include "sdma_script_code.h" +#include "crm_regs.h" + +extern struct dptc_wp dptc_gp_wp_allfreq[DPTC_GP_WP_SUPPORTED]; +extern struct dptc_wp dptc_lp_wp_allfreq[DPTC_LP_WP_SUPPORTED]; + +void mxc_sdma_get_script_info(sdma_script_start_addrs * sdma_script_addr) +{ + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR; + sdma_script_addr->mxc_sdma_ap_2_bp_addr = -1; + sdma_script_addr->mxc_sdma_bp_2_ap_addr = -1; + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE; + sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR; + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = dptc_dvfs_ADDR; + sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_firi_2_per_addr = -1; + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_per_2_app_addr = -1; + sdma_script_addr->mxc_sdma_per_2_firi_addr = -1; + sdma_script_addr->mxc_sdma_per_2_shp_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = mcu_2_ata_ADDR; + sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = ata_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = -1; + sdma_script_addr->mxc_sdma_shp_2_per_addr = -1; + sdma_script_addr->mxc_sdma_uart_2_per_addr = -1; + sdma_script_addr->mxc_sdma_app_2_per_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = mcu_2_spdif_marley_ADDR; +} + +static void mxc_nop_release(struct device *dev) +{ + /* Nothing */ +} + +#if defined(CONFIG_W1_MASTER_MXC) || defined(CONFIG_W1_MASTER_MXC_MODULE) +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 0, +}; + +static struct platform_device mxc_w1_devices = { + .name = "mxc_w1", + .dev = { + .release = mxc_nop_release, + .platform_data = &mxc_w1_data, + }, + .id = 0 +}; + +static void mxc_init_owire(void) +{ + (void)platform_device_register(&mxc_w1_devices); +} +#else +static inline void mxc_init_owire(void) +{ +} +#endif + +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) +static struct mxc_srtc_platform_data srtc_data = { + .srtc_sec_mode_addr = 0xC3FAC80C, +}; + +static struct resource rtc_resources[] = { + { + .start = SRTC_BASE_ADDR, + .end = SRTC_BASE_ADDR + 0x40, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SRTC_NTZ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device mxc_rtc_device = { + .name = "mxc_rtc", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &srtc_data, + }, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; +static void mxc_init_rtc(void) +{ + (void)platform_device_register(&mxc_rtc_device); +} +#else +static inline void mxc_init_rtc(void) +{ +} +#endif + +#if defined(CONFIG_MXC_WATCHDOG) || defined(CONFIG_MXC_WATCHDOG_MODULE) + +static struct resource wdt_resources[] = { + { + .start = WDOG1_BASE_ADDR, + .end = WDOG1_BASE_ADDR + 0x30, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mxc_wdt_device = { + .name = "mxc_wdt", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, + .num_resources = ARRAY_SIZE(wdt_resources), + .resource = wdt_resources, +}; + +static void mxc_init_wdt(void) +{ + (void)platform_device_register(&mxc_wdt_device); +} +#else +static inline void mxc_init_wdt(void) +{ +} +#endif + +#if defined(CONFIG_MXC_IPU_V3) || defined(CONFIG_MXC_IPU_V3_MODULE) +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 1, +}; + +static struct resource ipu_resources[] = { + { + .start = IPU_CTRL_BASE_ADDR, + .end = IPU_CTRL_BASE_ADDR + SZ_512M, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_IPU_SYN, + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_IPU_ERR, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_ipu_device = { + .name = "mxc_ipu", + .id = -1, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxc_ipu_data, + }, + .num_resources = ARRAY_SIZE(ipu_resources), + .resource = ipu_resources, +}; + +static void mxc_init_ipu(void) +{ + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di_clk"); + + platform_device_register(&mxc_ipu_device); +} +#else +static inline void mxc_init_ipu(void) +{ +} +#endif + +/*! + * This is platform device structure for adding SCC + */ +#if defined(CONFIG_MXC_SECURITY_SCC) || defined(CONFIG_MXC_SECURITY_SCC_MODULE) +static struct platform_device mxc_scc_device = { + .name = "mxc_scc", + .id = 0, +}; + +static void mxc_init_scc(void) +{ + platform_device_register(&mxc_scc_device); +} +#else +static inline void mxc_init_scc(void) +{ + uint32_t reg_value; + uint8_t *UMID_base; + uint32_t *MAP_base; + uint8_t i; + uint32_t partition_no; + uint32_t scc_partno; + void *scm_ram_base; + void *scc_base; + + scc_base = ioremap((uint32_t) SCC_BASE_ADDR, 0x140); + if (scc_base == NULL) { + printk(KERN_ERR "FAILED TO MAP IRAM REGS\n"); + return; + } + scm_ram_base = ioremap((uint32_t) IRAM_BASE_ADDR, IRAM_SIZE); + if (scm_ram_base == NULL) { + printk(KERN_ERR "FAILED TO MAP IRAM\n"); + return; + } + + for (partition_no = 0; partition_no < 9; partition_no++) { + reg_value = ((partition_no << SCM_ZCMD_PART_SHIFT) & + SCM_ZCMD_PART_MASK) | ((0x03 << + SCM_ZCMD_CCMD_SHIFT) + & SCM_ZCMD_CCMD_MASK); + __raw_writel(reg_value, scc_base + SCM_ZCMD_REG); + + while ((__raw_readl(scc_base + SCM_STATUS_REG) & + SCM_STATUS_SRS_READY) != SCM_STATUS_SRS_READY) ; + + __raw_writel(0, scc_base + (SCM_SMID0_REG + 8 * partition_no)); + + reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG); + + if (((reg_value >> (2 * (partition_no))) & 3) != 3) { + printk(KERN_ERR "FAILED TO ACQUIRE IRAM PARTITION\n"); + iounmap(scm_ram_base); + return; + } + + MAP_base = scm_ram_base + (partition_no * 0x2000); + UMID_base = (uint8_t *) MAP_base + 0x10; + + for (i = 0; i < 16; i++) + UMID_base[i] = 0; + + MAP_base[0] = SCM_PERM_NO_ZEROIZE | SCM_PERM_HD_SUP_DISABLE | + SCM_PERM_HD_READ | SCM_PERM_HD_WRITE | + SCM_PERM_TH_READ | SCM_PERM_TH_WRITE; + + } + + /*Freeing 2 partitions for SCC2 */ + scc_partno = 9 - (SCC_IRAM_SIZE / SZ_8K); + for (partition_no = scc_partno; partition_no < 9; partition_no++) { + reg_value = ((partition_no << SCM_ZCMD_PART_SHIFT) & + SCM_ZCMD_PART_MASK) | ((0x03 << + SCM_ZCMD_CCMD_SHIFT) + & SCM_ZCMD_CCMD_MASK); + __raw_writel(reg_value, scc_base + SCM_ZCMD_REG); + + while ((__raw_readl(scc_base + SCM_STATUS_REG) & + SCM_STATUS_SRS_READY) != SCM_STATUS_SRS_READY) ; + } + iounmap(scm_ram_base); + iounmap(scc_base); + printk(KERN_INFO "IRAM READY\n"); + +} +#endif + +/* SPI controller and device data */ +#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) + +#ifdef CONFIG_SPI_MXC_SELECT1 +/*! + * Resource definition for the CSPI1 + */ +static struct resource mxcspi1_resources[] = { + [0] = { + .start = CSPI1_BASE_ADDR, + .end = CSPI1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_CSPI1, + .end = MXC_INT_CSPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI1 */ +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, +}; + +/*! Device Definition for MXC CSPI1 */ +static struct platform_device mxcspi1_device = { + .name = "mxc_spi", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxcspi1_data, + }, + .num_resources = ARRAY_SIZE(mxcspi1_resources), + .resource = mxcspi1_resources, +}; + +#endif /* CONFIG_SPI_MXC_SELECT1 */ + +#ifdef CONFIG_SPI_MXC_SELECT2 +/*! + * Resource definition for the CSPI2 + */ +static struct resource mxcspi2_resources[] = { + [0] = { + .start = CSPI2_BASE_ADDR, + .end = CSPI2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_CSPI2, + .end = MXC_INT_CSPI2, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI2 */ +static struct mxc_spi_master mxcspi2_data = { + .maxchipselect = 4, + .spi_version = 23, +}; + +/*! Device Definition for MXC CSPI2 */ +static struct platform_device mxcspi2_device = { + .name = "mxc_spi", + .id = 1, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxcspi2_data, + }, + .num_resources = ARRAY_SIZE(mxcspi2_resources), + .resource = mxcspi2_resources, +}; +#endif /* CONFIG_SPI_MXC_SELECT2 */ + +#ifdef CONFIG_SPI_MXC_SELECT3 +/*! + * Resource definition for the CSPI3 + */ +static struct resource mxcspi3_resources[] = { + [0] = { + .start = CSPI3_BASE_ADDR, + .end = CSPI3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_CSPI3, + .end = MXC_INT_CSPI3, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI3 */ +static struct mxc_spi_master mxcspi3_data = { + .maxchipselect = 4, + .spi_version = 23, +}; + +/*! Device Definition for MXC CSPI3 */ +static struct platform_device mxcspi3_device = { + .name = "mxc_spi", + .id = 2, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxcspi3_data, + }, + .num_resources = ARRAY_SIZE(mxcspi3_resources), + .resource = mxcspi3_resources, +}; +#endif /* CONFIG_SPI_MXC_SELECT3 */ + +void __init mxc_init_spi(void) +{ + /* SPBA configuration for CSPI2 - MCU is set */ + spba_take_ownership(SPBA_CSPI2, SPBA_MASTER_A); +#ifdef CONFIG_SPI_MXC_SELECT1 + if (platform_device_register(&mxcspi1_device) < 0) + printk("Error: Registering the SPI Controller_1\n"); +#endif /* CONFIG_SPI_MXC_SELECT1 */ +#ifdef CONFIG_SPI_MXC_SELECT2 + if (platform_device_register(&mxcspi2_device) < 0) + printk("Error: Registering the SPI Controller_2\n"); +#endif /* CONFIG_SPI_MXC_SELECT2 */ +#ifdef CONFIG_SPI_MXC_SELECT3 + if (platform_device_register(&mxcspi3_device) < 0) + printk("Error: Registering the SPI Controller_3\n"); +#endif /* CONFIG_SPI_MXC_SELECT3 */ +} +#else +void __init mxc_init_spi(void) +{ +} +#endif + +/* I2C controller and device data */ +#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE) + +#ifdef CONFIG_I2C_MXC_SELECT1 +/*! + * Resource definition for the I2C1 + */ +static struct resource mxci2c1_resources[] = { + [0] = { + .start = I2C_BASE_ADDR, + .end = I2C_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_I2C, + .end = MXC_INT_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC I2C */ +static struct mxc_i2c_platform_data mxci2c1_data = { + .i2c_clk = 100000, +}; +#endif + +#ifdef CONFIG_I2C_MXC_SELECT2 +/*! + * Resource definition for the I2C2 + */ +static struct resource mxci2c2_resources[] = { + [0] = { + .start = I2C2_BASE_ADDR, + .end = I2C2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_I2C2, + .end = MXC_INT_I2C2, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC I2C */ +static struct mxc_i2c_platform_data mxci2c2_data = { + .i2c_clk = 100000, +}; +#endif + +#ifdef CONFIG_I2C_MXC_SELECT3 +/*! + * Resource definition for the I2C3 + */ +static struct resource mxci2c3_resources[] = { + [0] = { + .start = I2C3_BASE_ADDR, + .end = I2C3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_I2C3, + .end = MXC_INT_I2C3, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC I2C */ +static struct mxc_i2c_platform_data mxci2c3_data = { + .i2c_clk = 100000, +}; +#endif + +/*! Device Definition for MXC I2C1 */ +static struct platform_device mxci2c_devices[] = { +#ifdef CONFIG_I2C_MXC_SELECT1 + { + .name = "mxc_i2c", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxci2c1_data, + }, + .num_resources = ARRAY_SIZE(mxci2c1_resources), + .resource = mxci2c1_resources,}, +#endif +#ifdef CONFIG_I2C_MXC_SELECT2 + { + .name = "mxc_i2c", + .id = 1, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxci2c2_data, + }, + .num_resources = ARRAY_SIZE(mxci2c2_resources), + .resource = mxci2c2_resources,}, +#endif +#ifdef CONFIG_I2C_MXC_SELECT3 + { + .name = "mxc_i2c", + .id = 2, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxci2c3_data, + }, + .num_resources = ARRAY_SIZE(mxci2c3_resources), + .resource = mxci2c3_resources,}, +#endif +}; + +static inline void mxc_init_i2c(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mxci2c_devices); i++) { + if (platform_device_register(&mxci2c_devices[i]) < 0) + dev_err(&mxci2c_devices[i].dev, + "Unable to register I2C device\n"); + } +} +#else +static inline void mxc_init_i2c(void) +{ +} +#endif + +struct tve_platform_data tve_data = { + .dac_reg = "VVIDEO", + .dig_reg = "VDIG", +}; + +static struct resource tve_resources[] = { + { + .start = TVE_BASE_ADDR, + .end = TVE_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_TVOUT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_tve_device = { + .name = "tve", + .dev = { + .release = mxc_nop_release, + .platform_data = &tve_data, + }, + .num_resources = ARRAY_SIZE(tve_resources), + .resource = tve_resources, +}; + +void __init mxc_init_tve(void) +{ + platform_device_register(&mxc_tve_device); +} + +/*! + * Resource definition for the DVFS CORE + */ +static struct resource dvfs_core_resources[] = { + [0] = { + .start = MXC_DVFS_CORE_BASE, + .end = MXC_DVFS_CORE_BASE + 4 * SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_GPC1, + .end = MXC_INT_GPC1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for DVFS CORE */ +struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_reg_addr = MXC_GPC_CNTR, + .gpc_vcr_reg_addr = MXC_GPC_VCR, + .ccm_cdcr_reg_addr = MXC_CCM_CDCR, + .ccm_cacrr_reg_addr = MXC_CCM_CACRR, + .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR, + .dvfs_thrs_reg_addr = MXC_DVFSTHRS, + .dvfs_coun_reg_addr = MXC_DVFSCOUN, + .dvfs_emac_reg_addr = MXC_DVFSEMAC, + .dvfs_cntr_reg_addr = MXC_DVFSCNTR, + .prediv_mask = 0x3800, + .prediv_offset = 11, + .prediv_val = 1, + .div3ck_mask = 0x00000006, + .div3ck_offset = 1, + .div3ck_val = 3, + .emac_val = 0x08, + .upthr_val = 30, + .dnthr_val = 10, + .pncthr_val = 33, + .upcnt_val = 5, + .dncnt_val = 5, + .delay_time = 100, + .num_wp = 3, +}; + +/*! Device Definition for MXC DVFS core */ +static struct platform_device mxc_dvfs_core_device = { + .name = "mxc_dvfs_core", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &dvfs_core_data, + }, + .num_resources = ARRAY_SIZE(dvfs_core_resources), + .resource = dvfs_core_resources, +}; + +static inline void mxc_init_dvfs(void) +{ + if (platform_device_register(&mxc_dvfs_core_device) < 0) + dev_err(&mxc_dvfs_core_device.dev, + "Unable to register DVFS core device\n"); +} + +/*! + * Resource definition for the DPTC GP + */ +static struct resource dptc_gp_resources[] = { + [0] = { + .start = MXC_DPTC_GP_BASE, + .end = MXC_DPTC_GP_BASE + 8 * SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_GPC1, + .end = MXC_INT_GPC1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for DPTC GP */ +struct mxc_dptc_data dptc_gp_data = { + .reg_id = "SW1", + .clk_id = "cpu_clk", + .dptccr_reg_addr = MXC_GP_DPTCCR, + .dcvr0_reg_addr = MXC_GP_DCVR0, + .gpc_cntr_reg_addr = MXC_GPC_CNTR, + .dptccr = MXC_GPCCNTR_DPTC0CR, + .dptc_wp_supported = DPTC_GP_WP_SUPPORTED, + .dptc_wp_allfreq = dptc_gp_wp_allfreq, + .clk_max_val = 532000000, + .gpc_adu = MXC_GPCCNTR_ADU, + .vai_mask = MXC_DPTCCR_VAI_MASK, + .vai_offset = MXC_DPTCCR_VAI_OFFSET, + .dptc_enable_bit = MXC_DPTCCR_DEN, + .irq_mask = MXC_DPTCCR_VAIM, + .dptc_nvcr_bit = MXC_DPTCCR_DPNVCR, + .gpc_irq_bit = MXC_GPCCNTR_GPCIRQ, + .init_config = + MXC_DPTCCR_DRCE0 | MXC_DPTCCR_DRCE1 | MXC_DPTCCR_DRCE2 | + MXC_DPTCCR_DRCE3 | MXC_DPTCCR_DCR_128 | MXC_DPTCCR_DPNVCR | + MXC_DPTCCR_DPVV, + .enable_config = + MXC_DPTCCR_DEN | MXC_DPTCCR_DPNVCR | MXC_DPTCCR_DPVV | + MXC_DPTCCR_DSMM, + .dcr_mask = MXC_DPTCCR_DCR_256, +}; + +/*! + * Resource definition for the DPTC LP + */ +static struct resource dptc_lp_resources[] = { + [0] = { + .start = MXC_DPTC_LP_BASE, + .end = MXC_DPTC_LP_BASE + 8 * SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_GPC1, + .end = MXC_INT_GPC1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC DPTC LP */ +struct mxc_dptc_data dptc_lp_data = { + .reg_id = "SW2", + .clk_id = "ahb_clk", + .dptccr_reg_addr = MXC_LP_DPTCCR, + .dcvr0_reg_addr = MXC_LP_DCVR0, + .gpc_cntr_reg_addr = MXC_GPC_CNTR, + .dptccr = MXC_GPCCNTR_DPTC1CR, + .dptc_wp_supported = DPTC_LP_WP_SUPPORTED, + .dptc_wp_allfreq = dptc_lp_wp_allfreq, + .clk_max_val = 133000000, + .gpc_adu = 0x0, + .vai_mask = MXC_DPTCCR_VAI_MASK, + .vai_offset = MXC_DPTCCR_VAI_OFFSET, + .dptc_enable_bit = MXC_DPTCCR_DEN, + .irq_mask = MXC_DPTCCR_VAIM, + .dptc_nvcr_bit = MXC_DPTCCR_DPNVCR, + .gpc_irq_bit = MXC_GPCCNTR_GPCIRQ, + .init_config = + MXC_DPTCCR_DRCE0 | MXC_DPTCCR_DRCE1 | MXC_DPTCCR_DRCE2 | + MXC_DPTCCR_DRCE3 | MXC_DPTCCR_DCR_128 | MXC_DPTCCR_DPNVCR | + MXC_DPTCCR_DPVV, + .enable_config = + MXC_DPTCCR_DEN | MXC_DPTCCR_DPNVCR | MXC_DPTCCR_DPVV | + MXC_DPTCCR_DSMM, + .dcr_mask = MXC_DPTCCR_DCR_256, +}; + +/*! Device Definition for MXC DPTC */ +static struct platform_device mxc_dptc_devices[] = { + { + .name = "mxc_dptc", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &dptc_gp_data, + }, + .num_resources = ARRAY_SIZE(dptc_gp_resources), + .resource = dptc_gp_resources, + }, + { + .name = "mxc_dptc", + .id = 1, + .dev = { + .release = mxc_nop_release, + .platform_data = &dptc_lp_data, + }, + .num_resources = ARRAY_SIZE(dptc_lp_resources), + .resource = dptc_lp_resources, + }, +}; + +static inline void mxc_init_dptc(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mxc_dptc_devices); i++) { + if (platform_device_register(&mxc_dptc_devices[i]) < 0) + dev_err(&mxc_dptc_devices[i].dev, + "Unable to register DPTC device\n"); + } +} + +struct mxc_gpio_port mxc_gpio_ports[] = { + [0] = { + .chip.label = "gpio-0", + .base = IO_ADDRESS(GPIO1_BASE_ADDR), + .irq = MXC_INT_GPIO1_LOW, + .irq_high = MXC_INT_GPIO1_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + }, + [1] = { + .chip.label = "gpio-1", + .base = IO_ADDRESS(GPIO2_BASE_ADDR), + .irq = MXC_INT_GPIO2_LOW, + .irq_high = MXC_INT_GPIO2_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 + }, + [2] = { + .chip.label = "gpio-2", + .base = IO_ADDRESS(GPIO3_BASE_ADDR), + .irq = MXC_INT_GPIO3_LOW, + .irq_high = MXC_INT_GPIO3_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 + } +}; + +int __init mxc_register_gpios(void) +{ + return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); +} + +#if defined(CONFIG_MXC_VPU) || defined(CONFIG_MXC_VPU_MODULE) +static struct resource vpu_resources[] = { + [0] = { + .start = VPU_IRAM_BASE_ADDR, + .end = VPU_IRAM_BASE_ADDR + VPU_IRAM_SIZE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IO_ADDRESS(SRC_BASE_ADDR), + .end = IO_ADDRESS(SRC_BASE_ADDR), + .flags = IORESOURCE_MEM, + }, +}; + +/*! Platform Data for MXC VPU */ +static struct platform_device mxcvpu_device = { + .name = "mxc_vpu", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, + .num_resources = ARRAY_SIZE(vpu_resources), + .resource = vpu_resources, +}; + +static inline void mxc_init_vpu(void) +{ + if (platform_device_register(&mxcvpu_device) < 0) + printk(KERN_ERR "Error: Registering the VPU.\n"); +} +#else +static inline void mxc_init_vpu(void) +{ +} +#endif + +static struct platform_device mxc_dma_device = { + .name = "mxc_dma", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, +}; + +static inline void mxc_init_dma(void) +{ + (void)platform_device_register(&mxc_dma_device); +} + +static struct resource spdif_resources[] = { + { + .start = SPDIF_BASE_ADDR, + .end = SPDIF_BASE_ADDR + 0x50, + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, + .spdif_clk_48000 = 3, + .spdif_clk = NULL, + .spdif_core_clk = NULL, +}; + +static struct platform_device mxc_alsa_spdif_device = { + .name = "mxc_alsa_spdif", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxc_spdif_data, + }, + .num_resources = ARRAY_SIZE(spdif_resources), + .resource = spdif_resources, +}; + +static inline void mxc_init_spdif(void) +{ + struct clk *ckih_clk; + ckih_clk = clk_get(NULL, "ckih"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_set_parent(mxc_spdif_data.spdif_core_clk, ckih_clk); + clk_put(ckih_clk); + clk_put(mxc_spdif_data.spdif_core_clk); + platform_device_register(&mxc_alsa_spdif_device); +} + +static struct platform_device mx37_lpmode_device = { + .name = "mx37_lpmode", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, +}; + +static inline void mx37_init_lpmode(void) +{ + (void)platform_device_register(&mx37_lpmode_device); +} + +static struct platform_device busfreq_device = { + .name = "busfreq", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, +}; + +static inline void mxc_init_busfreq(void) +{ + (void)platform_device_register(&busfreq_device); +} + +#if defined(CONFIG_HW_RANDOM_FSL_RNGC) || \ +defined(CONFIG_HW_RANDOM_FSL_RNGC_MODULE) +static struct resource rngc_resources[] = { + { + .start = RNGC_BASE_ADDR, + .end = RNGC_BASE_ADDR + 0x34, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_RNG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device fsl_rngc_device = { + .name = "fsl_rngc", + .id = -1, + .num_resources = ARRAY_SIZE(rngc_resources), + .resource = rngc_resources, +}; + +static inline void mxc_init_rngc(void) +{ + platform_device_register(&fsl_rngc_device); +} +#else +static inline void mxc_init_rngc(void) +{ +} +#endif + +#if defined(CONFIG_MXC_IIM) || defined(CONFIG_MXC_IIM_MODULE) +static struct resource mxc_iim_resources[] = { + { + .start = IIM_BASE_ADDR, + .end = IIM_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mxc_iim_device = { + .name = "mxc_iim", + .id = 0, + .dev = { + .release = mxc_nop_release, + }, + .num_resources = ARRAY_SIZE(mxc_iim_resources), + .resource = mxc_iim_resources +}; + +static inline void mxc_init_iim(void) +{ + if (platform_device_register(&mxc_iim_device) < 0) + dev_err(&mxc_iim_device.dev, + "Unable to register mxc iim device\n"); +} +#else +static inline void mxc_init_iim(void) +{ +} +#endif + +int __init mxc_init_devices(void) +{ + mxc_init_wdt(); + mxc_init_ipu(); + mxc_init_spi(); + mxc_init_i2c(); + mxc_init_rtc(); + mxc_init_owire(); + mxc_init_scc(); + mxc_init_dma(); + mxc_init_vpu(); + mxc_init_spdif(); + mxc_init_tve(); + mx37_init_lpmode(); + mxc_init_busfreq(); + mxc_init_dvfs(); + mxc_init_dptc(); + mxc_init_rngc(); + mxc_init_iim(); + + /* SPBA configuration for SSI2 - SDMA and MCU are set */ + spba_take_ownership(SPBA_SSI2, SPBA_MASTER_C | SPBA_MASTER_A); + return 0; +} diff --git a/arch/arm/mach-mx37/dma.c b/arch/arm/mach-mx37/dma.c new file mode 100644 index 000000000000..5732c5803888 --- /dev/null +++ b/arch/arm/mach-mx37/dma.c @@ -0,0 +1,666 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/device.h> +#include <asm/dma.h> +#include <mach/hardware.h> + +#include "serial.h" + +#define MXC_MMC_BUFFER_ACCESS 0x20 +#define MXC_SDHC_MMC_WML 512 +#define MXC_SDHC_SD_WML 512 +#define MXC_SSI_TX0_REG 0x0 +#define MXC_SSI_TX1_REG 0x4 +#define MXC_SSI_RX0_REG 0x8 +#define MXC_SSI_RX1_REG 0xC +#define MXC_SSI_TXFIFO_WML 0x4 +#define MXC_SSI_RXFIFO_WML 0x6 +#define MXC_SPDIF_TXFIFO_WML 0x0 +#define MXC_SPDIF_TX_REG 0x2C + +typedef struct mxc_sdma_info_entry_s { + mxc_dma_device_t device; + mxc_sdma_channel_params_t *chnl_info; +} mxc_sdma_info_entry_t; + +static mxc_sdma_channel_params_t mxc_sdma_uart1_rx_params = { + .chnl_params = { + .watermark_level = UART1_UFCR_RXTL, + .per_address = UART1_BASE_ADDR, + .peripheral_type = UART, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_UART1_RX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART1_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart1_tx_params = { + .chnl_params = { + .watermark_level = UART1_UFCR_TXTL, + .per_address = UART1_BASE_ADDR + MXC_UARTUTXD, + .peripheral_type = UART, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_UART1_TX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART1_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart2_rx_params = { + .chnl_params = { + .watermark_level = UART2_UFCR_RXTL, + .per_address = UART2_BASE_ADDR, + .peripheral_type = UART, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_UART2_RX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART2_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart2_tx_params = { + .chnl_params = { + .watermark_level = UART2_UFCR_TXTL, + .per_address = UART2_BASE_ADDR + MXC_UARTUTXD, + .peripheral_type = UART, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_UART2_TX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART2_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart3_rx_params = { + .chnl_params = { + .watermark_level = UART3_UFCR_RXTL, + .per_address = UART3_BASE_ADDR, + .peripheral_type = UART_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_UART3_RX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART3_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart3_tx_params = { + .chnl_params = { + .watermark_level = UART3_UFCR_TXTL, + .per_address = UART3_BASE_ADDR + MXC_UARTUTXD, + .peripheral_type = UART_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_UART3_TX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART3_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_mmc1_width1_params = { + .chnl_params = { + .watermark_level = MXC_SDHC_MMC_WML, + .per_address = + MMC_SDHC1_BASE_ADDR + MXC_MMC_BUFFER_ACCESS, + .peripheral_type = MMC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SDHC1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_MMC1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_mmc1_width4_params = { + .chnl_params = { + .watermark_level = MXC_SDHC_SD_WML, + .per_address = + MMC_SDHC1_BASE_ADDR + MXC_MMC_BUFFER_ACCESS, + .peripheral_type = MMC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SDHC1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_MMC1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_mmc2_width1_params = { + .chnl_params = { + .watermark_level = MXC_SDHC_MMC_WML / 32, + .per_address = + MMC_SDHC2_BASE_ADDR + MXC_MMC_BUFFER_ACCESS, + .peripheral_type = MMC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SDHC2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_MMC2, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_mmc2_width4_params = { + .chnl_params = { + .watermark_level = MXC_SDHC_SD_WML / 8, + .per_address = + MMC_SDHC2_BASE_ADDR + MXC_MMC_BUFFER_ACCESS, + .peripheral_type = MMC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SDHC2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_MMC2, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI1_RX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI1_TX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI1_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI2_RX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI_SP, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI2_TX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI2_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_memory_params = { + .chnl_params = { + .peripheral_type = MEMORY, + .transfer_type = emi_2_emi, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_MEMORY, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ata_rx_params = { + .chnl_params = { + .watermark_level = MXC_IDE_DMA_WATERMARK, + .per_address = ATA_DMA_BASE_ADDR, + .peripheral_type = ATA, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ATA_TX_END, + .event_id2 = DMA_REQ_ATA_RX, + .bd_number = MXC_IDE_DMA_BD_NR, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ATA_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ata_tx_params = { + .chnl_params = { + .watermark_level = MXC_IDE_DMA_WATERMARK, + .per_address = ATA_DMA_BASE_ADDR + 0x18, + .peripheral_type = ATA, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_ATA_TX_END, + .event_id2 = DMA_REQ_ATA_TX, + .bd_number = MXC_IDE_DMA_BD_NR, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ATA_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_spdif_16bit_tx_params = { + .chnl_params = { + .watermark_level = MXC_SPDIF_TXFIFO_WML, + .per_address = SPDIF_BASE_ADDR + MXC_SPDIF_TX_REG, + .peripheral_type = SPDIF, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SPDIF_TX, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SPDIF_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_spdif_32bit_tx_params = { + .chnl_params = { + .watermark_level = MXC_SPDIF_TXFIFO_WML, + .per_address = SPDIF_BASE_ADDR + MXC_SPDIF_TX_REG, + .peripheral_type = SPDIF, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SPDIF_TX, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SPDIF_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_info_entry_t mxc_sdma_active_dma_info[] = { + {MXC_DMA_UART1_RX, &mxc_sdma_uart1_rx_params}, + {MXC_DMA_UART1_TX, &mxc_sdma_uart1_tx_params}, + {MXC_DMA_UART2_RX, &mxc_sdma_uart2_rx_params}, + {MXC_DMA_UART2_TX, &mxc_sdma_uart2_tx_params}, + {MXC_DMA_UART3_RX, &mxc_sdma_uart3_rx_params}, + {MXC_DMA_UART3_TX, &mxc_sdma_uart3_tx_params}, + {MXC_DMA_MMC1_WIDTH_1, &mxc_sdma_mmc1_width1_params}, + {MXC_DMA_MMC1_WIDTH_4, &mxc_sdma_mmc1_width4_params}, + {MXC_DMA_MMC2_WIDTH_1, &mxc_sdma_mmc2_width1_params}, + {MXC_DMA_MMC2_WIDTH_4, &mxc_sdma_mmc2_width4_params}, + {MXC_DMA_SSI1_8BIT_RX0, &mxc_sdma_ssi1_8bit_rx0_params}, + {MXC_DMA_SSI1_8BIT_TX0, &mxc_sdma_ssi1_8bit_tx0_params}, + {MXC_DMA_SSI1_16BIT_RX0, &mxc_sdma_ssi1_16bit_rx0_params}, + {MXC_DMA_SSI1_16BIT_TX0, &mxc_sdma_ssi1_16bit_tx0_params}, + {MXC_DMA_SSI1_24BIT_RX0, &mxc_sdma_ssi1_24bit_rx0_params}, + {MXC_DMA_SSI1_24BIT_TX0, &mxc_sdma_ssi1_24bit_tx0_params}, + {MXC_DMA_SSI1_8BIT_RX1, &mxc_sdma_ssi1_8bit_rx1_params}, + {MXC_DMA_SSI1_8BIT_TX1, &mxc_sdma_ssi1_8bit_tx1_params}, + {MXC_DMA_SSI1_16BIT_RX1, &mxc_sdma_ssi1_16bit_rx1_params}, + {MXC_DMA_SSI1_16BIT_TX1, &mxc_sdma_ssi1_16bit_tx1_params}, + {MXC_DMA_SSI1_24BIT_RX1, &mxc_sdma_ssi1_24bit_rx1_params}, + {MXC_DMA_SSI1_24BIT_TX1, &mxc_sdma_ssi1_24bit_tx1_params}, + {MXC_DMA_SSI2_8BIT_RX0, &mxc_sdma_ssi2_8bit_rx0_params}, + {MXC_DMA_SSI2_8BIT_TX0, &mxc_sdma_ssi2_8bit_tx0_params}, + {MXC_DMA_SSI2_16BIT_RX0, &mxc_sdma_ssi2_16bit_rx0_params}, + {MXC_DMA_SSI2_16BIT_TX0, &mxc_sdma_ssi2_16bit_tx0_params}, + {MXC_DMA_SSI2_24BIT_RX0, &mxc_sdma_ssi2_24bit_rx0_params}, + {MXC_DMA_SSI2_24BIT_TX0, &mxc_sdma_ssi2_24bit_tx0_params}, + {MXC_DMA_SSI2_8BIT_RX1, &mxc_sdma_ssi2_8bit_rx1_params}, + {MXC_DMA_SSI2_8BIT_TX1, &mxc_sdma_ssi2_8bit_tx1_params}, + {MXC_DMA_SSI2_16BIT_RX1, &mxc_sdma_ssi2_16bit_rx1_params}, + {MXC_DMA_SSI2_16BIT_TX1, &mxc_sdma_ssi2_16bit_tx1_params}, + {MXC_DMA_SSI2_24BIT_RX1, &mxc_sdma_ssi2_24bit_rx1_params}, + {MXC_DMA_SSI2_24BIT_TX1, &mxc_sdma_ssi2_24bit_tx1_params}, + {MXC_DMA_MEMORY, &mxc_sdma_memory_params}, + {MXC_DMA_ATA_RX, &mxc_sdma_ata_rx_params}, + {MXC_DMA_ATA_TX, &mxc_sdma_ata_tx_params}, + {MXC_DMA_SPDIF_16BIT_TX, &mxc_sdma_spdif_16bit_tx_params}, + {MXC_DMA_SPDIF_32BIT_TX, &mxc_sdma_spdif_32bit_tx_params}, +}; + +static int mxc_sdma_info_entrys = + sizeof(mxc_sdma_active_dma_info) / sizeof(mxc_sdma_active_dma_info[0]); + +/*! + * This functions Returns the SDMA paramaters associated for a module + * + * @param channel_id the ID of the module requesting DMA + * @return returns the sdma parameters structure for the device + */ +mxc_sdma_channel_params_t *mxc_sdma_get_channel_params(mxc_dma_device_t + channel_id) +{ + mxc_sdma_info_entry_t *p = mxc_sdma_active_dma_info; + int i; + + for (i = 0; i < mxc_sdma_info_entrys; i++, p++) { + if (p->device == channel_id) { + return p->chnl_info; + } + } + return NULL; +} + +/*! + * This functions marks the SDMA channels that are statically allocated + * + * @param chnl the channel array used to store channel information + */ +void mxc_get_static_channels(mxc_dma_channel_t * chnl) +{ +#ifdef CONFIG_SDMA_IRAM + int i; + for (i = MXC_DMA_CHANNEL_IRAM; i < MAX_DMA_CHANNELS; i++) + chnl[i].dynamic = 0; +#endif +} + +EXPORT_SYMBOL(mxc_sdma_get_channel_params); +EXPORT_SYMBOL(mxc_get_static_channels); diff --git a/arch/arm/mach-mx37/dptc.c b/arch/arm/mach-mx37/dptc.c new file mode 100644 index 000000000000..4585423c0036 --- /dev/null +++ b/arch/arm/mach-mx37/dptc.c @@ -0,0 +1,69 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file dptc_gp.c + * + * @brief DPTC table for the Freescale Semiconductor MXC DPTC module. + * + * @ingroup PM + */ + +#include <mach/hardware.h> +#include <mach/mxc_dptc.h> + +struct dptc_wp dptc_gp_wp_allfreq[DPTC_GP_WP_SUPPORTED] = { + /* 532MHz */ + /* dcvr0 dcvr1 dcvr2 + dcvr3 voltage */ + /* wp0 */ + {DCVR(107, 108, 112), DCVR(122, 123, 127), DCVR(133, 134, 139), + DCVR(115, 116, 121), 1000}, + {DCVR(107, 108, 113), DCVR(122, 123, 127), DCVR(133, 134, 139), + DCVR(115, 117, 122), 975}, + {DCVR(107, 109, 113), DCVR(122, 123, 127), DCVR(133, 134, 139), + DCVR(115, 117, 122), 950}, + {DCVR(107, 109, 114), DCVR(122, 123, 127), DCVR(133, 135, 140), + DCVR(115, 117, 122), 925}, + {DCVR(108, 109, 115), DCVR(122, 123, 127), DCVR(133, 136, 142), + DCVR(115, 117, 123), 900}, + {DCVR(108, 110, 115), DCVR(122, 123, 127), DCVR(133, 136, 142), + DCVR(115, 117, 123), 875}, + {DCVR(108, 110, 115), DCVR(122, 124, 128), DCVR(133, 136, 143), + DCVR(115, 118, 124), 850}, +}; + +struct dptc_wp dptc_lp_wp_allfreq[DPTC_LP_WP_SUPPORTED] = { + /* 532MHz */ + /* dcvr0 dcvr1 dcvr2 + dcvr3 regulator voltage */ + /* wp0 */ + {DCVR(141, 143, 149), DCVR(155, 157, 162), DCVR(106, 108, 112), + DCVR(124, 126, 130), 1200}, + {DCVR(141, 143, 149), DCVR(155, 157, 162), DCVR(106, 108, 113), + DCVR(124, 126, 131), 1175}, + {DCVR(141, 144, 150), DCVR(155, 157, 163), DCVR(106, 108, 113), + DCVR(124, 126, 131), 1150}, + {DCVR(141, 144, 151), DCVR(155, 157, 163), DCVR(106, 108, 114), + DCVR(124, 126, 131), 1125}, + {DCVR(142, 144, 152), DCVR(155, 157, 163), DCVR(107, 109, 114), + DCVR(125, 127, 132), 1100}, + {DCVR(142, 145, 153), DCVR(155, 157, 164), DCVR(107, 109, 115), + DCVR(125, 127, 133), 1075}, + {DCVR(142, 145, 153), DCVR(155, 158, 164), DCVR(107, 109, 116), + DCVR(125, 127, 133), 1050}, + {DCVR(142, 145, 154), DCVR(155, 158, 165), DCVR(107, 110, 117), + DCVR(125, 127, 134), 1025}, + {DCVR(142, 146, 156), DCVR(155, 158, 165), DCVR(107, 110, 117), + DCVR(125, 128, 135), 1000}, +}; diff --git a/arch/arm/mach-mx37/iomux.c b/arch/arm/mach-mx37/iomux.c new file mode 100644 index 000000000000..2d8360ce2b91 --- /dev/null +++ b/arch/arm/mach-mx37/iomux.c @@ -0,0 +1,202 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup GPIO_MX37 Board GPIO and Muxing Setup + * @ingroup MSL_MX37 + */ +/*! + * @file mach-mx37/iomux.c + * + * @brief I/O Muxing control functions + * + * @ingroup GPIO_MX37 + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/irqs.h> +#include "iomux.h" + +/*! + * IOMUX register (base) addresses + */ +#define IOMUXGPR0 (IO_ADDRESS(IOMUXC_BASE_ADDR)) /*!< General purpose 0 */ +#define IOMUXGPR1 (IO_ADDRESS(IOMUXC_BASE_ADDR) + 0x004) /*!< General purpose 1 */ +#define IOMUXSW_MUX_CTL (IO_ADDRESS(IOMUXC_BASE_ADDR) + MUX_I_START) /*!< MUX control */ +#define IOMUXSW_MUX_END (IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_END) /*!< last MUX control register */ +#define IOMUXSW_PAD_CTL (IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START) /*!< Pad control */ +#define IOMUXSW_PAD_END (IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_END) /*!< last Pad control register */ +#define IOMUXSW_INPUT_CTL (IO_ADDRESS(IOMUXC_BASE_ADDR) + INPUT_CTL_START) /*!< input select register */ +#define IOMUXSW_INPUT_END (IO_ADDRESS(IOMUXC_BASE_ADDR) + INPUT_CTL_END) /*!< last input select register */ + +#define MUX_PIN_NUM_MAX (((IOMUXSW_MUX_END - IOMUXSW_MUX_CTL) >> 2) + 1) +#define MUX_INPUT_NUM_MUX (((IOMUXSW_INPUT_END - IOMUXSW_INPUT_CTL) >> 2) + 1) + +static u8 iomux_pin_res_table[MUX_PIN_NUM_MAX]; +static DEFINE_SPINLOCK(gpio_mux_lock); + +/*! + * This function is used to configure a pin through the IOMUX module. + * @param pin a pin number as defined in \b #iomux_pin_name_t + * @param config a configuration as defined in \b #iomux_pin_cfg_t + * + * @return 0 if successful; Non-zero otherwise + */ +static int iomux_config_mux(iomux_pin_name_t pin, iomux_pin_cfg_t config) +{ + u32 ret = 0; + u32 pin_index = PIN_TO_IOMUX_INDEX(pin); + void *mux_reg = IOMUXSW_MUX_CTL + PIN_TO_IOMUX_MUX(pin); + u32 mux_data = 0; + u8 *rp; + + BUG_ON((mux_reg > IOMUXSW_MUX_END) || (mux_reg < IOMUXSW_MUX_CTL)); + spin_lock(&gpio_mux_lock); + + if (config == IOMUX_CONFIG_GPIO) { + mux_data = PIN_TO_ALT_GPIO(pin); + } else { + mux_data = config; + } + + __raw_writel(mux_data, mux_reg); + + /* + * Log a warning if a pin changes ownership + */ + rp = iomux_pin_res_table + pin_index; + if ((mux_data & *rp) && (*rp != mux_data)) { + /* + * Don't call printk if we're tweaking the console uart or + * we'll deadlock. + */ + printk(KERN_ERR "iomux_config_mux: Warning: iomux pin" + " config changed, pin=%p, " + " prev=0x%x new=0x%x\n", mux_reg, *rp, mux_data); + ret = -EINVAL; + } + *rp = mux_data; + spin_unlock(&gpio_mux_lock); + return ret; +} + +/*! + * Request ownership for an IO pin. This function has to be the first one + * being called before that pin is used. The caller has to check the + * return value to make sure it returns 0. + * + * @param pin a name defined by \b iomux_pin_name_t + * @param config a configuration as defined in \b #iomux_pin_cfg_t + * + * @return 0 if successful; Non-zero otherwise + */ +int mxc_request_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t config) +{ + int ret = iomux_config_mux(pin, config); + int gpio = IOMUX_TO_GPIO(pin); + + if (!ret && (gpio < MXC_GPIO_IRQS) && ((config == IOMUX_CONFIG_GPIO) + || (config == PIN_TO_ALT_GPIO(pin)))) { + ret |= gpio_request(gpio, NULL); + } + return ret; +} + +/*! + * Release ownership for an IO pin + * + * @param pin a name defined by \b iomux_pin_name_t + * @param config config as defined in \b #iomux_pin_ocfg_t + */ +void mxc_free_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t config) +{ + u32 pin_index = PIN_TO_IOMUX_INDEX(pin); + u8 *rp = iomux_pin_res_table + pin_index; + int gpio = IOMUX_TO_GPIO(pin); + + BUG_ON(pin_index > MUX_PIN_NUM_MAX); + *rp = 0; + if ((gpio < MXC_GPIO_IRQS) && ((config == IOMUX_CONFIG_GPIO) + || (config == PIN_TO_ALT_GPIO(pin)))) { + gpio_free(gpio); + } +} + +/*! + * This function configures the pad value for a IOMUX pin. + * + * @param pin a pin number as defined in \b #iomux_pin_name_t + * @param config the ORed value of elements defined in \b #iomux_pad_config_t + */ +void mxc_iomux_set_pad(iomux_pin_name_t pin, u32 config) +{ + void *pad_reg = IOMUXSW_PAD_CTL + PIN_TO_IOMUX_PAD(pin); + + BUG_ON((pad_reg > IOMUXSW_PAD_END) || (pad_reg < IOMUXSW_PAD_CTL)); + spin_lock(&gpio_mux_lock); + __raw_writel(config, pad_reg); + spin_unlock(&gpio_mux_lock); +} + +unsigned int mxc_iomux_get_pad(iomux_pin_name_t pin) +{ + void *pad_reg = IOMUXSW_PAD_CTL + PIN_TO_IOMUX_PAD(pin); + return __raw_readl(pad_reg); +} + +/*! + * This function enables/disables the general purpose function for a particular + * signal. + * + * @param gp one signal as defined in \b #iomux_gp_func_t + * @param en \b #true to enable; \b #false to disable + * @param index 0 for GPR0 and 1 for GPR1 + */ +void mxc_iomux_set_gpr(iomux_gp_func_t gp, bool en, u8 index) +{ + volatile u32 l; + + spin_lock(&gpio_mux_lock); + l = __raw_readl(IOMUXGPR0 + (index << 2)); + if (en) { + l |= gp; + } else { + l &= ~gp; + } + __raw_writel(l, IOMUXGPR0 + (index << 2)); + spin_unlock(&gpio_mux_lock); +} + +/*! + * This function configures input path. + * + * @param input index of input select register as defined in \b #iomux_input_select_t + * @param config the binary value of elements defined in \b #iomux_input_config_t + * */ +void mxc_iomux_set_input(iomux_input_select_t input, u32 config) +{ + void *reg = IOMUXSW_INPUT_CTL + (input << 2); + + BUG_ON(input >= MUX_INPUT_NUM_MUX); + __raw_writel(config, reg); +} + +EXPORT_SYMBOL(mxc_request_iomux); +EXPORT_SYMBOL(mxc_free_iomux); +EXPORT_SYMBOL(mxc_iomux_set_input); +EXPORT_SYMBOL(mxc_iomux_set_pad); +EXPORT_SYMBOL(mxc_iomux_set_gpr); diff --git a/arch/arm/mach-mx37/iomux.h b/arch/arm/mach-mx37/iomux.h new file mode 100644 index 000000000000..b8f38212da18 --- /dev/null +++ b/arch/arm/mach-mx37/iomux.h @@ -0,0 +1,228 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __MACH_MX37_IOMUX_H__ +#define __MACH_MX37_IOMUX_H__ + +#include <linux/types.h> +#include <mach/gpio.h> +#include "mx37_pins.h" + +/*! + * @file mach-mx37/iomux.h + * + * @brief I/O Muxing control definitions and functions + * + * @ingroup GPIO_MX37 + */ + +typedef unsigned int iomux_pin_name_t; + +/*! + * various IOMUX output functions + */ +typedef enum iomux_config { + IOMUX_CONFIG_ALT0, /*!< used as alternate function 0 */ + IOMUX_CONFIG_ALT1, /*!< used as alternate function 1 */ + IOMUX_CONFIG_ALT2, /*!< used as alternate function 2 */ + IOMUX_CONFIG_ALT3, /*!< used as alternate function 3 */ + IOMUX_CONFIG_ALT4, /*!< used as alternate function 4 */ + IOMUX_CONFIG_ALT5, /*!< used as alternate function 5 */ + IOMUX_CONFIG_ALT6, /*!< used as alternate function 6 */ + IOMUX_CONFIG_ALT7, /*!< used as alternate function 7 */ + IOMUX_CONFIG_GPIO, /*!< added to help user use GPIO mode */ + IOMUX_CONFIG_SION = 0x1 << 4, /*!< used as LOOPBACK:MUX SION bit */ +} iomux_pin_cfg_t; + +/*! + * various IOMUX pad functions + */ +typedef enum iomux_pad_config { + PAD_CTL_SRE_SLOW = 0x0 << 0, + PAD_CTL_SRE_FAST = 0x1 << 0, + PAD_CTL_DRV_LOW = 0x0 << 1, + PAD_CTL_DRV_MEDIUM = 0x1 << 1, + PAD_CTL_DRV_HIGH = 0x2 << 1, + PAD_CTL_DRV_MAX = 0x3 << 1, + PAD_CTL_ODE_OPENDRAIN_NONE = 0x0 << 3, + PAD_CTL_ODE_OPENDRAIN_ENABLE = 0x1 << 3, + PAD_CTL_100K_PD = 0x0 << 4, + PAD_CTL_47K_PU = 0x1 << 4, + PAD_CTL_100K_PU = 0x2 << 4, + PAD_CTL_22K_PU = 0x3 << 4, + PAD_CTL_PUE_KEEPER = 0x0 << 6, + PAD_CTL_PUE_PULL = 0x1 << 6, + PAD_CTL_PKE_NONE = 0x0 << 7, + PAD_CTL_PKE_ENABLE = 0x1 << 7, + PAD_CTL_HYS_NONE = 0x0 << 8, + PAD_CTL_HYS_ENABLE = 0x1 << 8, + PAD_CTL_DDR_INPUT_CMOS = 0x0 << 9, + PAD_CTL_DDR_INPUT_DDR = 0x1 << 9, + PAD_CTL_DRV_VOT_LOW = 0x0 << 13, + PAD_CTL_DRV_VOT_HIGH = 0x1 << 13, +} iomux_pad_config_t; + +/*! + * various IOMUX general purpose functions + */ +typedef enum iomux_gp_func { + MUX_IPD_ESDHC_DREQ_B = 0x0 << 0, + MUX_XDRQ = 0x1 << 0, + MUX_EMI_DMA_ACCESS_1 = 0x0 << 4, + MUX_KEY_COL2 = 0x1 << 4, + MUX_TAMPER_DETECT_EN = 0x1 << 8, + MUX_IPUv3D_TVE = 0x0 << 12, + MUX_IPUv3D_CAMP = 0x1 << 12, +} iomux_gp_func_t; + +/*! + * various IOMUX input select register index + */ +typedef enum iomux_input_select { + MUX_IN_CCM_PLL1_BYPASS_CLK = 0, + MUX_IN_CCM_PLL2_BYPASS_CLK, + MUX_IN_CCM_PLL3_BYPASS_CLK, + MUX_IN_CSPI3_CSPI_CLK, + MUX_IN_CSPI3_MISO, + MUX_IN_CSPI3_MOSI, + MUX_IN_EMI_READ_MADDR_DATA_0, + MUX_IN_EMI_READ_MADDR_DATA_10, + MUX_IN_EMI_READ_MADDR_DATA_11, + MUX_IN_EMI_READ_MADDR_DATA_12, + MUX_IN_EMI_READ_MADDR_DATA_13, + MUX_IN_EMI_READ_MADDR_DATA_14, + MUX_IN_EMI_READ_MADDR_DATA_15, + MUX_IN_EMI_READ_MADDR_DATA_1, + MUX_IN_EMI_READ_MADDR_DATA_2, + MUX_IN_EMI_READ_MADDR_DATA_3, + MUX_IN_EMI_READ_MADDR_DATA_4, + MUX_IN_EMI_READ_MADDR_DATA_5, + MUX_IN_EMI_READ_MADDR_DATA_6, + MUX_IN_EMI_READ_MADDR_DATA_7, + MUX_IN_EMI_READ_MADDR_DATA_8, + MUX_IN_EMI_READ_MADDR_DATA_9, + MUX_IN_EMI_NFC_READ_DATA_IN_0, + MUX_IN_EMI_NFC_READ_DATA_IN_10, + MUX_IN_EMI_NFC_READ_DATA_IN_11, + MUX_IN_EMI_NFC_READ_DATA_IN_12, + MUX_IN_EMI_NFC_READ_DATA_IN_13, + MUX_IN_EMI_NFC_READ_DATA_IN_14, + MUX_IN_EMI_NFC_READ_DATA_IN_15, + MUX_IN_EMI_NFC_READ_DATA_IN_1, + MUX_IN_EMI_NFC_READ_DATA_IN_2, + MUX_IN_EMI_NFC_READ_DATA_IN_3, + MUX_IN_EMI_NFC_READ_DATA_IN_4, + MUX_IN_EMI_NFC_READ_DATA_IN_5, + MUX_IN_EMI_NFC_READ_DATA_IN_6, + MUX_IN_EMI_NFC_READ_DATA_IN_7, + MUX_IN_EMI_NFC_READ_DATA_IN_8, + MUX_IN_EMI_NFC_READ_DATA_IN_9, + MUX_IN_FEC_FEC_COL, + MUX_IN_FEC_FEC_CRS, MUX_IN_FEC_FEC_MDI, + MUX_IN_FEC_FEC_RDATA_0, + MUX_IN_FEC_FEC_RX_CLK, + MUX_IN_FEC_FEC_RX_DV, + MUX_IN_FEC_FEC_RX_ER, + MUX_IN_FEC_FEC_TX_CLK, + MUX_IN_I2C1_SCL, + MUX_IN_I2C1_SDA, + MUX_IN_I2C2_SCL, + MUX_IN_I2C2_SDA, + MUX_IN_I2C3_SCL, + MUX_IN_I2C3_SDA, + MUX_IN_IPU_DI_0_IND_DISPB_D0_VSYNC, + MUX_IN__IPU_DI_0_IND_DISPB_SD_D, + MUX_IN_KPP_ROW_0, + MUX_IN_KPP_ROW_1, + MUX_IN_KPP_ROW_2, + MUX_IN_KPP_ROW_3, + MUX_IN_KPP_ROW_4, + MUX_IN_KPP_ROW_5, + MUX_IN_KPP_ROW_6, + MUX_IN_KPP_ROW_7, + MUX_IN_UART1_UART_RTS_B, + MUX_IN_UART1_UART_RXD_MUX, + MUX_IN_UART2_UART_RTS_B, + MUX_IN_UART2_UART_RXD_MUX, + MUX_IN_UART3_UART_RTS_B, + MUX_IN_UART3_UART_RXD_MUX, +} iomux_input_select_t; + +/*! + * various IOMUX input functions + */ +typedef enum iomux_input_config { + INPUT_CTL_PATH0 = 0x0, + INPUT_CTL_PATH1, + INPUT_CTL_PATH2, + INPUT_CTL_PATH3, + INPUT_CTL_PATH4, + INPUT_CTL_PATH5, + INPUT_CTL_PATH6, + INPUT_CTL_PATH7, +} iomux_input_config_t; + +/*! + * Request ownership for an IO pin. This function has to be the first one + * being called before that pin is used. The caller has to check the + * return value to make sure it returns 0. + * + * @param pin a name defined by \b iomux_pin_name_t + * @param config config as defined in \b #iomux_pin_ocfg_t + * + * @return 0 if successful; Non-zero otherwise + */ +int mxc_request_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t config); + +/*! + * Release ownership for an IO pin + * + * @param pin a name defined by \b iomux_pin_name_t + * @param config config as defined in \b #iomux_pin_ocfg_t + */ +void mxc_free_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t config); + +/*! + * This function enables/disables the general purpose function for a particular + * signal. + * + * @param gp one signal as defined in \b #iomux_gp_func_t + * @param en \b #true to enable; \b #false to disable + * @param index 0 for GPR0 and 1 for GPR1 + */ +void mxc_iomux_set_gpr(iomux_gp_func_t gp, bool en, u8 index); + +/*! + * This function configures the pad value for a IOMUX pin. + * + * @param pin a pin number as defined in \b #iomux_pin_name_t + * @param config the ORed value of elements defined in \b #iomux_pad_config_t + */ +void mxc_iomux_set_pad(iomux_pin_name_t pin, u32 config); + +/*! + * This function gets the current pad value for a IOMUX pin. + * + * @param pin a pin number as defined in \b #iomux_pin_name_t + * @return current pad value + */ +unsigned int mxc_iomux_get_pad(iomux_pin_name_t pin); + +/*! + * This function configures input path. + * + * @param input index of input select register as defined in \b #iomux_input_select_t + * @param config the binary value of elements defined in \b #iomux_input_config_t + */ +void mxc_iomux_set_input(iomux_input_select_t input, u32 config); + +#endif /* __MACH_MX37_IOMUX_H__ */ diff --git a/arch/arm/mach-mx37/lpmodes.c b/arch/arm/mach-mx37/lpmodes.c new file mode 100644 index 000000000000..7685a5c249a0 --- /dev/null +++ b/arch/arm/mach-mx37/lpmodes.c @@ -0,0 +1,408 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file mx37_lpmodes.c + * + * @brief Driver for the Freescale Semiconductor MXC low power modes setup. + * + * MX37 is designed to play and video with minimal power consumption. + * This driver enables the platform to enter and exit audio and video low + * power modes. + * + * @ingroup PM + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <mach/clock.h> +#include <mach/hardware.h> +#include <linux/regulator/consumer.h> +#include "crm_regs.h" + +#define ARM_LP_CLK 200000000 +#define GP_LPM_VOLTAGE 850000 +#define LP_LPM_VOLTAGE 1000000 +#define GP_NORMAL_VOLTAGE 1000000 +#define LP_NORMAL_VOLTAGE 1200000 + +static int org_cpu_rate; +int lp_video_mode; +int lp_audio_mode; +static struct device *lpmode_dev; + +void enter_lp_video_mode(void) +{ + int ret = 0; + + struct clk *p_clk; + struct clk *tclk; + struct clk *vmode_parent_clk; + struct regulator *gp_core; + + tclk = clk_get(NULL, "main_bus_clk"); + vmode_parent_clk = clk_get(NULL, "pll2"); + p_clk = clk_get_parent(tclk); + + if (p_clk != vmode_parent_clk) { + clk_set_parent(tclk, vmode_parent_clk); + + clk_set_rate(clk_get(NULL, "axi_a_clk"), 133000000); + clk_set_rate(clk_get(NULL, "axi_b_clk"), 66500000); + clk_set_rate(clk_get(NULL, "axi_c_clk"), 166000000); + clk_set_rate(clk_get(NULL, "emi_core_clk"), 133000000); + clk_set_rate(clk_get(NULL, "nfc_clk"), 26600000); + clk_set_rate(clk_get(NULL, "ahb_clk"), 133000000); + } + + /* move VPU clock to source from the emi_core_clk */ + tclk = clk_get(NULL, "vpu_clk"); + vmode_parent_clk = clk_get(NULL, "emi_core_clk"); + if (clk_get_parent(tclk) != vmode_parent_clk) + clk_set_parent(tclk, vmode_parent_clk); + + tclk = clk_get(NULL, "vpu_core_clk"); + if (clk_get_parent(tclk) != vmode_parent_clk) + clk_set_parent(tclk, vmode_parent_clk); + + tclk = clk_get(NULL, "arm_axi_clk"); + if (clk_get_parent(tclk) != vmode_parent_clk) + clk_set_parent(tclk, vmode_parent_clk); + + tclk = clk_get(NULL, "ddr_clk"); + vmode_parent_clk = clk_get(NULL, "axi_c_clk"); + if (clk_get_parent(tclk) != vmode_parent_clk) + clk_set_parent(tclk, vmode_parent_clk); + + /* disable PLL3 */ + tclk = clk_get(NULL, "pll3"); + if (tclk->usecount == 1) + clk_disable(tclk); + + tclk = clk_get(NULL, "cpu_clk"); + org_cpu_rate = clk_get_rate(tclk); + + ret = clk_set_rate(tclk, ARM_LP_CLK); + if (ret != 0) + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + + /* Set the voltage to 0.8v for the GP domain. */ + + if (!board_is_rev(BOARD_REV_2)) + gp_core = regulator_get(NULL, "DCDC1"); + else + gp_core = regulator_get(NULL, "SW1"); + + ret = regulator_set_voltage(gp_core, GP_LPM_VOLTAGE, GP_LPM_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!\n"); + + lp_video_mode = 1; +} + +void exit_lp_video_mode(void) +{ + int ret = 0; + static struct clk *tclk; + struct regulator *gp_core; + + /*Set the voltage to 0.8v for the GP domain. */ + if (!board_is_rev(BOARD_REV_2)) + gp_core = regulator_get(NULL, "DCDC1"); + else + gp_core = regulator_get(NULL, "SW1"); + + ret = regulator_set_voltage(gp_core, GP_NORMAL_VOLTAGE, GP_NORMAL_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n"); + + tclk = clk_get(NULL, "cpu_clk"); + + ret = clk_set_rate(tclk, org_cpu_rate); + if (ret != 0) + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + + lp_video_mode = 0; +} + +void enter_lp_audio_mode(void) +{ + int ret = 0; + + struct clk *p_clk; + struct clk *tclk; + struct clk *amode_parent_clk; + struct regulator *gp_core; + struct regulator *lp_core; + + tclk = clk_get(NULL, "ipu_clk"); + if (clk_get_usecount(tclk) != 0) { + printk(KERN_INFO + "Cannot enter AUDIO LPM mode - display is still active\n"); + return; + } + + tclk = clk_get(NULL, "periph_apm_clk"); + amode_parent_clk = clk_get(NULL, "lp_apm"); + p_clk = clk_get_parent(tclk); + + /* Make sure osc_clk is the parent of lp_apm. */ + clk_set_parent(amode_parent_clk, clk_get(NULL, "osc")); + + /* Set the parent of periph_apm_clk to be lp_apm */ + clk_set_parent(tclk, amode_parent_clk); + amode_parent_clk = tclk; + + tclk = clk_get(NULL, "main_bus_clk"); + p_clk = clk_get_parent(tclk); + /* Set the parent of main_bus_clk to be periph_apm_clk */ + clk_set_parent(tclk, amode_parent_clk); + + clk_set_rate(clk_get(NULL, "axi_a_clk"), 24000000); + clk_set_rate(clk_get(NULL, "axi_b_clk"), 24000000); + clk_set_rate(clk_get(NULL, "axi_c_clk"), 24000000); + clk_set_rate(clk_get(NULL, "emi_core_clk"), 24000000); + clk_set_rate(clk_get(NULL, "nfc_clk"), 4800000); + clk_set_rate(clk_get(NULL, "ahb_clk"), 24000000); + + amode_parent_clk = clk_get(NULL, "emi_core_clk"); + + tclk = clk_get(NULL, "arm_axi_clk"); + p_clk = clk_get_parent(tclk); + if (p_clk != amode_parent_clk) { + clk_set_parent(tclk, amode_parent_clk); + } + + tclk = clk_get(NULL, "vpu_clk"); + p_clk = clk_get_parent(tclk); + if (p_clk != amode_parent_clk) { + clk_set_parent(tclk, amode_parent_clk); + } + + tclk = clk_get(NULL, "vpu_core_clk"); + p_clk = clk_get_parent(tclk); + if (p_clk != amode_parent_clk) { + clk_set_parent(tclk, amode_parent_clk); + } + + /* disable PLL3 */ + tclk = clk_get(NULL, "pll3"); + if (tclk->usecount == 1) + clk_disable(tclk); + + /* disable PLL2 */ + tclk = clk_get(NULL, "pll2"); + if (tclk->usecount == 1) + clk_disable(tclk); + + /* Set the voltage to 1.0v for the LP domain. */ + if (!board_is_rev(BOARD_REV_2)) + lp_core = regulator_get(NULL, "DCDC4"); + else + lp_core = regulator_get(NULL, "SW2"); + + if (lp_core != NULL) { + ret = regulator_set_voltage(lp_core, LP_LPM_VOLTAGE, LP_LPM_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!!!\n"); + } + + tclk = clk_get(NULL, "cpu_clk"); + org_cpu_rate = clk_get_rate(tclk); + + ret = clk_set_rate(tclk, ARM_LP_CLK); + if (ret != 0) + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + + /* Set the voltage to 0.8v for the GP domain. */ + if (!board_is_rev(BOARD_REV_2)) + gp_core = regulator_get(NULL, "DCDC1"); + else + gp_core = regulator_get(NULL, "SW1"); + + if (gp_core != NULL) { + ret = regulator_set_voltage(gp_core, GP_LPM_VOLTAGE, GP_LPM_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!!\n"); + } + lp_audio_mode = 1; +} + +void exit_lp_audio_mode(void) +{ + struct regulator *gp_core; + struct regulator *lp_core; + struct clk *tclk; + struct clk *p_clk; + struct clk *rmode_parent_clk; + int ret; + + lp_audio_mode = 0; + /* Set the voltage to 1.2v for the LP domain. */ + if (!board_is_rev(BOARD_REV_2)) + lp_core = regulator_get(NULL, "DCDC4"); + else + lp_core = regulator_get(NULL, "SW2"); + + if (lp_core != NULL) { + ret = regulator_set_voltage(lp_core, LP_NORMAL_VOLTAGE, LP_NORMAL_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!!!\n"); + } + + /* Set the voltage to 1.0v for the GP domain. */ + if (!board_is_rev(BOARD_REV_2)) + gp_core = regulator_get(NULL, "DCDC1"); + else + gp_core = regulator_get(NULL, "SW1"); + + ret = regulator_set_voltage(gp_core, GP_NORMAL_VOLTAGE, GP_NORMAL_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n"); + + tclk = clk_get(NULL, "cpu_clk"); + + ret = clk_set_rate(tclk, org_cpu_rate); + if (ret != 0) + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + + rmode_parent_clk = clk_get(NULL, "pll2"); + clk_enable(rmode_parent_clk); + + tclk = clk_get(NULL, "main_bus_clk"); + p_clk = clk_get_parent(tclk); + + /* Set the dividers before setting the parent clock. */ + clk_set_rate(clk_get(NULL, "axi_a_clk"), 4800000); + clk_set_rate(clk_get(NULL, "axi_b_clk"), 4000000); + clk_set_rate(clk_get(NULL, "axi_c_clk"), 6000000); + clk_set_rate(clk_get(NULL, "emi_core_clk"), 4800000); + clk_set_rate(clk_get(NULL, "ahb_clk"), 4800000); + + /* Set the parent of main_bus_clk to be pll2 */ + clk_set_parent(tclk, rmode_parent_clk); + udelay(5); +} + +static ssize_t lp_curr_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (lp_video_mode) + return sprintf(buf, "in lp_video_mode\n"); + else if (lp_audio_mode) + return sprintf(buf, "in lp_audio_mode\n"); + else + return sprintf(buf, "in normal mode\n"); +} + +static ssize_t set_lp_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + printk(KERN_DEBUG "In set_lp_mode() \n"); + + if (strstr(buf, "enable_lp_video") != NULL) { + if (!lp_video_mode) + enter_lp_video_mode(); + } else if (strstr(buf, "disable_lp_video") != NULL) { + if (lp_video_mode) + exit_lp_video_mode(); + } else if (strstr(buf, "enable_lp_audio") != NULL) { + if (!lp_audio_mode) + enter_lp_audio_mode(); + } else if (strstr(buf, "disable_lp_audio") != NULL) { + if (lp_audio_mode) + exit_lp_audio_mode(); + } + return size; +} + +static DEVICE_ATTR(lp_modes, 0644, lp_curr_mode, set_lp_mode); + +/*! + * This is the probe routine for the lp_mode driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit mx37_lpmode_probe(struct platform_device *pdev) +{ + u32 res = 0; + lpmode_dev = &pdev->dev; + + res = sysfs_create_file(&lpmode_dev->kobj, &dev_attr_lp_modes.attr); + if (res) { + printk(KERN_ERR + "lpmode_dev: Unable to register sysdev entry for lpmode_dev"); + return res; + } + + if (res != 0) { + printk(KERN_ERR "lpmode_dev: Unable to start"); + return res; + } + lp_video_mode = 0; + lp_audio_mode = 0; + + return 0; +} + +static struct platform_driver mx37_lpmode_driver = { + .driver = { + .name = "mx37_lpmode", + }, + .probe = mx37_lpmode_probe, +}; + +/*! + * Initialise the mx37_lpmode_driver. + * + * @return The function always returns 0. + */ + +static int __init lpmode_init(void) +{ + if (platform_driver_register(&mx37_lpmode_driver) != 0) { + printk(KERN_ERR "mx37_lpmode_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "LPMode driver module loaded\n"); + return 0; +} + +static void __exit lpmode_cleanup(void) +{ + sysfs_remove_file(&lpmode_dev->kobj, &dev_attr_lp_modes.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&mx37_lpmode_driver); +} + +module_init(lpmode_init); +module_exit(lpmode_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("LPMode driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx37/mm.c b/arch/arm/mach-mx37/mm.c new file mode 100644 index 000000000000..8f9947fc8fc6 --- /dev/null +++ b/arch/arm/mach-mx37/mm.c @@ -0,0 +1,82 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <mach/hardware.h> +#include <asm/pgtable.h> +#include <asm/mach/map.h> + +/*! + * @file mach-mx37/mm.c + * + * @brief This file creates static mapping between physical to virtual memory. + * + * @ingroup Memory_MX37 + */ + +/*! + * This structure defines the MX37 memory map. + */ +static struct map_desc mx37_io_desc[] __initdata = { + { + .virtual = IRAM_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(IRAM_BASE_ADDR), + .length = IRAM_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = PLATFORM_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(PLATFORM_BASE_ADDR), + .length = PLATFORM_SIZE, + .type = MT_DEVICE}, + { + .virtual = DEBUG_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(DEBUG_BASE_ADDR), + .length = DEBUG_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = TZIC_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(TZIC_BASE_ADDR), + .length = TZIC_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = AIPS1_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS1_BASE_ADDR), + .length = AIPS1_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = SPBA0_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(SPBA0_BASE_ADDR), + .length = SPBA0_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = AIPS2_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS2_BASE_ADDR), + .length = AIPS2_SIZE, + .type = MT_DEVICE_NONSHARED}, + { + .virtual = NFC_BASE_ADDR_AXI_VIRT, + .pfn = __phys_to_pfn(NFC_BASE_ADDR_AXI), + .length = NFC_AXI_SIZE, + .type = MT_DEVICE}, +}; + +/*! + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory map for + * the IO modules. + */ +void __init mx37_map_io(void) +{ + iotable_init(mx37_io_desc, ARRAY_SIZE(mx37_io_desc)); +} diff --git a/arch/arm/mach-mx37/mx37_3stack.c b/arch/arm/mach-mx37/mx37_3stack.c new file mode 100644 index 000000000000..b9e88e57daab --- /dev/null +++ b/arch/arm/mach-mx37/mx37_3stack.c @@ -0,0 +1,978 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/ata.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/smsc911x.h> +#include <linux/i2c/tsc2007.h> +#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/flash.h> +#endif + +#include <mach/hardware.h> +#include <mach/spba.h> +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/common.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include "board-mx37_3stack.h" +#include "iomux.h" +#include "crm_regs.h" + +/*! + * @file mach-mx37/mx37_3stack.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX37 + */ +extern void gpio_lcd_active(void); + +/* working point(wp): 0 - 532MHz; 1 - 200MHz; */ +static struct cpu_wp cpu_wp_auto[] = { + { + .pll_rate = 532000000, + .cpu_rate = 532000000, + .pdf = 0, + .mfi = 5, + .mfd = 23, + .mfn = 13, + .cpu_voltage = 1050000,}, + { + .pll_rate = 400000000, + .cpu_rate = 400000000, + .pdf = 1, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_voltage = 950000,}, + { + .pll_rate = 200000000, + .cpu_rate = 200000000, + .pdf = 3, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_voltage = 850000,}, + { + .pll_rate = 600000000, + .cpu_rate = 600000000, + .pdf = 0, + .mfi = 6, + .mfd = 3, + .mfn = 1, + .cpu_voltage = 1200000,}, +}; + +struct cpu_wp *get_cpu_wp(int *wp) +{ + *wp = 3; + return cpu_wp_auto; +} + +#if defined(CONFIG_REGULATOR_MC13892) \ + || defined(CONFIG_REGULATOR_MC13892_MODULE) +static int mc13892_reg_int(void) +{ + int i = 0; + unsigned int value; + struct regulator *regulator; + struct cpu_wp *cpu_wp_tbl1; + int cpu_wp_nr1; + char *reg_name[] = { + "SW1", + "SW2", + "SW3", + "SW4", + "SW1_STBY", + "SW2_STBY", + "SW3_STBY", + "SW4_STBY", + "SW1_DVS", + "SW2_DVS", + "SWBST", + "VIOHI", + "VPLL", + "VDIG", + "VSD", + "VUSB2", + "VVIDEO", + "VAUDIO", + "VCAM", + "VGEN1", + "VGEN2", + "VGEN3", + "USB", + "GPO1", + "GPO2", + "GPO3", + "GPO4", + }; + + /* for board v1.1 do nothing */ + if (!board_is_rev(BOARD_REV_2)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(reg_name); i++) { + regulator = regulator_get(NULL, reg_name[i]); + if (regulator != ERR_PTR(-ENOENT)) { + regulator_enable(regulator); + regulator_put(regulator); + } + } + for (i = 0; i < ARRAY_SIZE(reg_name); i++) { + if ((strcmp(reg_name[i], "VIOHI") == 0) || + (strcmp(reg_name[i], "VPLL") == 0) || + (strcmp(reg_name[i], "VDIG") == 0) || + (strcmp(reg_name[i], "VGEN2") == 0)) + continue; + regulator = regulator_get(NULL, reg_name[i]); + if (regulator != ERR_PTR(-ENOENT)) { + regulator_disable(regulator); + regulator_put(regulator); + } + } + + /* Set the current working point. */ + cpu_wp_tbl1 = get_cpu_wp(&cpu_wp_nr1); + for (i = 0; i < cpu_wp_nr1; i++) + cpu_wp_tbl1[i].cpu_voltage += 50000; + + /* Bit 4 DRM: keep VSRTC and CLK32KMCU on for all states */ + pmic_read_reg(REG_POWER_CTL0, &value, 0xffffff); + value |= 0x000010; + pmic_write_reg(REG_POWER_CTL0, value, 0xffffff); + + return 0; +} + +late_initcall(mc13892_reg_int); +#endif + +static void mxc_nop_release(struct device *dev) +{ + /* Nothing */ +} + +/* MTD NAND flash */ +#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE) \ + || defined(CONFIG_MTD_NAND_MXC_V2) || defined(CONFIG_MTD_NAND_MXC_V2_MODULE) \ + || defined(CONFIG_MTD_NAND_MXC_V3) + +static struct mtd_partition mxc_nand_partitions[] = { + { + .name = "nand.bootloader", + .offset = 0, + .size = 2 * 1024 * 1024}, + { + .name = "nand.kernel", + .offset = MTDPART_OFS_APPEND, + .size = 4 * 1024 * 1024}, + { + .name = "nand.rootfs", + .offset = MTDPART_OFS_APPEND, + .size = 256 * 1024 * 1024}, + { + .name = "nand.userfs1", + .offset = MTDPART_OFS_APPEND, + .size = 256 * 1024 * 1024}, + { + .name = "nand.userfs2", + .offset = MTDPART_OFS_APPEND, + .size = 512 * 1024 * 1024}, + { + .name = "nand.userfs3", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL}, +}; + +static struct flash_platform_data mxc_nand_data = { + .parts = mxc_nand_partitions, + .nr_parts = ARRAY_SIZE(mxc_nand_partitions), + .width = 1, +}; + +static struct platform_device mxc_nandv2_mtd_device = { + .name = "mxc_nandv2_flash", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxc_nand_data, + }, +}; + +static void mxc_init_nand_mtd(void) +{ +// if (__raw_readl(MXC_CCM_RCSR) & MXC_CCM_RCSR_NF16B) { +// mxc_nand_data.width = 2; +// } + (void)platform_device_register(&mxc_nandv2_mtd_device); +} +#else +static inline void mxc_init_nand_mtd(void) +{ +} +#endif + +static void lcd_reset(void) +{ + static int first; + + /* ensure that LCDIO(1.8V) has been turn on */ + /* active reset line GPIO */ + if (!first) { + mxc_request_iomux(MX37_PIN_GPIO1_5, IOMUX_CONFIG_GPIO); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_GPIO1_5), "gpio1_5"); + first = 1; + } + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_GPIO1_5), 0); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_GPIO1_5), 0); + /* do reset */ + msleep(10); /* tRES >= 100us */ + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_GPIO1_5), 1); + msleep(60); +} + +static struct mxc_lcd_platform_data lcd_data = { + .core_reg = "VVIDEO", + .io_reg = "SW4", + .reset = lcd_reset, +}; + +#if defined(CONFIG_KEYBOARD_MPR084) || defined(CONFIG_KEYBOARD_MPR084_MODULE) +/*! + * These functions are used to configure and the GPIO pins for keypad to + * activate and deactivate it. + */ +extern void gpio_keypad_active(void); + +extern void gpio_keypad_inactive(void); + +static u16 keymap[] = { + KEY_DOWN, KEY_LEFT, KEY_ENTER, + KEY_RIGHT, KEY_UP, KEY_LEFTALT, + KEY_TAB, KEY_ESC, +}; + +static struct mxc_keyp_platform_data keypad_data = { + .matrix = keymap, + .active = gpio_keypad_active, + .inactive = gpio_keypad_inactive, + .vdd_reg = "VGEN2", +}; +#else + +static struct mxc_keyp_platform_data keypad_data = {}; + +#endif + +static struct mxc_lightsensor_platform_data ls_data = { + .vdd_reg = "VGEN2", + .rext = 100, +}; + +#if defined(CONFIG_TOUCHSCREEN_TSC2007) || defined(CONFIG_TOUCHSCREEN_TSC2007_MODULE) +static int tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXFS)); +} + +static int tsc2007_init(void) +{ + int pad_val; + + mxc_request_iomux(MX37_PIN_AUD5_RXFS, IOMUX_CONFIG_GPIO); + pad_val = PAD_CTL_PKE_ENABLE | PAD_CTL_100K_PU; + mxc_iomux_set_pad(MX37_PIN_AUD5_RXFS, pad_val); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXFS), "aud5_rxfs"); + gpio_direction_input(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXFS)); + return 0; +} + +static void tsc2007_exit(void) +{ +} + +struct tsc2007_platform_data tsc2007_data = { + .model = 2007, + .x_plate_ohms = 400, + .get_pendown_state = tsc2007_get_pendown_state, + .init_platform_hw = tsc2007_init, + .exit_platform_hw = tsc2007_exit, +}; +#else +struct tsc2007_platform_data tsc2007_data; +#endif + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "tsc2007", + .addr = 0x48, + .irq = IOMUX_TO_IRQ(MX37_PIN_AUD5_RXFS), + .platform_data = &tsc2007_data, + }, + { + .type = "mpr084", + .addr = 0x5D, + .platform_data = &keypad_data, + .irq = IOMUX_TO_IRQ(MX37_PIN_GPIO1_3), + }, + { + .type = "isl29003", + .addr = 0x44, + .platform_data = &ls_data, + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "mc13892", + .addr = 0x08, + .platform_data = (void *)MX37_PIN_OWIRE_LINE, + }, + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, +}; + +static struct spi_board_info mxc_spi_board_info[] __initdata = { + { + .modalias = "cpld_spi", + .max_speed_hz = 27000000, + .bus_num = 2, + .chip_select = 0, + }, + { + .modalias = "lcd_spi", + .max_speed_hz = 5000000, + .bus_num = 2, + .platform_data = &lcd_data, + .chip_select = 1,}, +}; + +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) +static struct platform_device mxc_fb_device[] = { + { + .name = "mxc_sdc_fb", + .id = 0, + .dev = { + .release = mxc_nop_release, + .coherent_dma_mask = 0xFFFFFFFF, + }, + }, + { + .name = "mxc_sdc_fb", + .id = 1, + .dev = { + .release = mxc_nop_release, + .coherent_dma_mask = 0xFFFFFFFF, + }, + }, + { + .name = "mxc_sdc_fb", + .id = 2, + .dev = { + .release = mxc_nop_release, + .coherent_dma_mask = 0xFFFFFFFF, + }, + }, +}; + +static void mxc_init_fb(void) +{ + (void)platform_device_register(&mxc_fb_device[0]); + (void)platform_device_register(&mxc_fb_device[1]); + (void)platform_device_register(&mxc_fb_device[2]); + gpio_lcd_active(); +} +#else +static inline void mxc_init_fb(void) +{ +} +#endif + +static struct platform_device mxcbl_device = { + .name = "mxc_mc13892_bl", +}; + +static inline void mxc_init_bl(void) +{ + platform_device_register(&mxcbl_device); +} + +/*lan9217 device*/ +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +static struct resource smsc911x_resources[] = { + { + .start = LAN9217_BASE_ADDR, + .end = LAN9217_BASE_ADDR + 255, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_BOARD_IRQ_START, + .flags = IORESOURCE_IRQ, + }, +}; + +struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .flags = 0x8000 | SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, +}; + +static struct platform_device smsc_lan9217_device = { + .name = "smsc911x", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &smsc911x_config, + }, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, +}; + +static int __init mxc_init_enet(void) +{ + (void)platform_device_register(&smsc_lan9217_device); + return 0; +} +#else +static int __init mxc_init_enet(void) +{ + return 0; +} +#endif + +late_initcall(mxc_init_enet); + +#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) +extern void gpio_ata_active(void); +extern void gpio_ata_inactive(void); + +static int ata_init(struct platform_device *pdev) +{ + /* Configure the pins */ + gpio_ata_active(); + + return 0; +} + +static void ata_exit(void) +{ + /* Free the pins */ + gpio_ata_inactive(); +} + +static struct fsl_ata_platform_data ata_data = { + .udma_mask = ATA_UDMA3, /* board can handle up to UDMA3 */ + .mwdma_mask = ATA_MWDMA2, + .pio_mask = ATA_PIO4, + .fifo_alarm = MXC_IDE_DMA_WATERMARK / 2, + .max_sg = MXC_IDE_DMA_BD_NR, + .init = ata_init, + .exit = ata_exit, + .core_reg = NULL, /*"LDO2", */ + .io_reg = NULL, /*"LDO3", */ +}; + +static struct resource pata_fsl_resources[] = { + [0] = { /* I/O */ + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000C8, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ */ + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pata_fsl_device = { + .name = "pata_fsl", + .id = -1, + .num_resources = ARRAY_SIZE(pata_fsl_resources), + .resource = pata_fsl_resources, + .dev = { + .platform_data = &ata_data, + .coherent_dma_mask = ~0, + }, +}; + +static void __init mxc_init_pata(void) +{ + (void)platform_device_register(&pata_fsl_device); +} +#else /* CONFIG_PATA_FSL */ +static void __init mxc_init_pata(void) +{ +} +#endif /* CONFIG_PATA_FSL */ + +/*! + * Board specific fixup function. It is called by \b setup_arch() in + * setup.c file very early on during kernel starts. It allows the user to + * statically fill in the proper values for the passed-in parameters. None of + * the parameters is used currently. + * + * @param desc pointer to \b struct \b machine_desc + * @param tags pointer to \b struct \b tag + * @param cmdline pointer to the command line + * @param mi pointer to \b struct \b meminfo + */ +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mxc_cpu_init(); + +#ifdef CONFIG_DISCONTIGMEM + do { + int nid; + mi->nr_banks = MXC_NUMNODES; + for (nid = 0; nid < mi->nr_banks; nid++) { + SET_NODE(mi, nid); + } + } while (0); +#endif +} + +static void mxc_unifi_hardreset(int pin_level) +{ + struct regulator *gpo4; + + if (board_is_rev(BOARD_REV_2)) { + gpo4 = regulator_get(NULL, "GPO4"); + if (!IS_ERR(gpo4)) { + if (pin_level & 0x01) + regulator_enable(gpo4); + else + regulator_disable(gpo4); + } + regulator_put(gpo4); + } else { + mxc_request_iomux(MX37_PIN_AUD5_RXC, IOMUX_CONFIG_GPIO); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), "aud5_rxc"); + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), + pin_level & 0x01); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), 0); + mxc_free_iomux(MX37_PIN_AUD5_RXC, IOMUX_CONFIG_GPIO); + } +} + +static struct mxc_unifi_platform_data unifi_data = { + .hardreset = mxc_unifi_hardreset, + .enable = NULL, + .reg_1v5_ana_bb = "VGEN1", + .reg_vdd_vpa = "VCAM", + .reg_1v5_dd = "VGEN1", + .host_id = 1, +}; + +struct mxc_unifi_platform_data *get_unifi_plat_data(void) +{ + return &unifi_data; +} + +EXPORT_SYMBOL(get_unifi_plat_data); + +#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) +static struct mxc_mmc_platform_data mmc1_data = { + .ocr_mask = MMC_VDD_32_33, + .caps = MMC_CAP_4_BIT_DATA, + .min_clk = 150000, + .max_clk = 52000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +/*! + * Resource definition for the SDHC1 + */ +static struct resource mxcsdhc1_resources[] = { + [0] = { + .start = MMC_SDHC1_BASE_ADDR, + .end = MMC_SDHC1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_MMC_SDHC1, + .end = MXC_INT_MMC_SDHC1, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Device Definition for MXC SDHC1 */ +static struct platform_device mxcsdhc1_device = { + .name = "mxsdhci", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mmc1_data, + }, + .num_resources = ARRAY_SIZE(mxcsdhc1_resources), + .resource = mxcsdhc1_resources, +}; + +static struct mxc_mmc_platform_data mmc2_data = { + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | + MMC_VDD_31_32, + .caps = MMC_CAP_4_BIT_DATA, + .min_clk = 150000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static struct resource mxcsdhc2_resources[] = { + [0] = { + .start = MMC_SDHC2_BASE_ADDR, + .end = MMC_SDHC2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_MMC_SDHC2, + .end = MXC_INT_MMC_SDHC2, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxcsdhc2_device = { + .name = "mxsdhci", + .id = 1, + .dev = { + .release = mxc_nop_release, + .platform_data = &mmc2_data, + }, + .num_resources = ARRAY_SIZE(mxcsdhc2_resources), + .resource = mxcsdhc2_resources, +}; + +static inline void mxc_init_mmc(void) +{ + int cd_irq; + + cd_irq = sdhc_init_card_det(0); + if (cd_irq) { + mxcsdhc1_device.resource[2].start = cd_irq; + mxcsdhc1_device.resource[2].end = cd_irq; + } + + spba_take_ownership(SPBA_SDHC1, SPBA_MASTER_A | SPBA_MASTER_C); + (void)platform_device_register(&mxcsdhc1_device); + cd_irq = sdhc_init_card_det(1); + if (cd_irq) { + mxcsdhc2_device.resource[2].start = cd_irq; + mxcsdhc2_device.resource[2].end = cd_irq; + } + spba_take_ownership(SPBA_SDHC2, SPBA_MASTER_A | SPBA_MASTER_C); + (void)platform_device_register(&mxcsdhc2_device); +} +#else +static inline void mxc_init_mmc(void) +{ +} +#endif + +static void bt_reset(void) +{ + struct regulator *gpo4; + if (board_is_rev(BOARD_REV_2)) { + gpo4 = regulator_get(NULL, "GPO4"); + if (!IS_ERR(gpo4)) + regulator_enable(gpo4); + regulator_put(gpo4); + } else { + mxc_request_iomux(MX37_PIN_AUD5_RXC, IOMUX_CONFIG_GPIO); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), "aud5_rxc"); + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), 1); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXC), 0); + } +} + +static struct mxc_bt_platform_data mxc_bt_data = { + .bt_vdd = "VGEN2", + .bt_vdd_parent = NULL, + .bt_vusb = "SW4", + .bt_vusb_parent = NULL, + .bt_reset = bt_reset, +}; + +static struct platform_device mxc_bt_device = { + .name = "mxc_bt", + .id = 0, + .dev = { + .release = mxc_nop_release, + .platform_data = &mxc_bt_data, + }, +}; + +static void mxc_init_bluetooth(void) +{ + (void)platform_device_register(&mxc_bt_device); +} + +#if defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) \ + || defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000_MODULE) +static int mxc_sgtl5000_plat_init(void); +static int mxc_sgtl5000_plat_finit(void); +static int mxc_sgtl5000_amp_enable(int enable); + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .hp_irq = IOMUX_TO_IRQ(MX37_PIN_AUD5_RXFS), + .hp_status = headphone_det_status, + .vddio_reg = "SW3", + .vdda_reg = "VAUDIO", + .amp_enable = mxc_sgtl5000_amp_enable, + .vddio = 1850000, + .vdda = 2775000, + .vddd = 0, + .init = mxc_sgtl5000_plat_init, + .finit = mxc_sgtl5000_plat_finit, +}; + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", + .dev = { + .release = mxc_nop_release, + .platform_data = &sgtl5000_data, + }, +}; + +static int mxc_sgtl5000_plat_init(void) +{ + struct regulator *reg; + reg = regulator_get(&mxc_sgtl5000_device.dev, "GPO2"); + if (IS_ERR(reg)) + return -EINVAL; + sgtl5000_data.priv = reg; + return 0; +} + +static int mxc_sgtl5000_plat_finit(void) +{ + struct regulator *reg; + reg = sgtl5000_data.priv; + if (reg) { + regulator_put(reg); + sgtl5000_data.priv = NULL; + } + return 0; +} + +static int mxc_sgtl5000_amp_enable(int enable) +{ + struct regulator *reg; + reg = sgtl5000_data.priv; + + if (!reg) + return -EINVAL; + if (enable) + regulator_enable(reg); + else + regulator_disable(reg); + return 0; +} + +static void mxc_init_sgtl5000(void) +{ + int err, pin; + struct clk *cko1, *parent; + unsigned long rate; + + /* for board v1.1 do nothing */ + if (!board_is_rev(BOARD_REV_2)) + return; + + pin = MX37_PIN_AUD5_RXFS; + err = mxc_request_iomux(pin, IOMUX_CONFIG_GPIO); + if (err) { + sgtl5000_data.hp_irq = -1; + printk(KERN_ERR "Error: sgtl5000_init request gpio failed!\n"); + return; + } + mxc_iomux_set_pad(pin, PAD_CTL_PKE_ENABLE | PAD_CTL_100K_PU); + gpio_request(IOMUX_TO_GPIO(pin), "aud5_rxfs"); + gpio_direction_input(IOMUX_TO_GPIO(pin)); + + /* cko1 clock */ + mxc_request_iomux(MX37_PIN_GPIO1_6, IOMUX_CONFIG_ALT2); + + cko1 = clk_get(NULL, "cko1_clk"); + if (IS_ERR(cko1)) + return; + parent = clk_get(NULL, "ipg_perclk"); + if (IS_ERR(parent)) + return; + clk_set_parent(cko1, parent); + rate = clk_round_rate(cko1, 13000000); + if (rate < 8000000 || rate > 27000000) { + printk(KERN_ERR "Error: SGTL5000 mclk freq %d out of range!\n", + rate); + clk_put(parent); + clk_put(cko1); + return; + } + clk_set_rate(cko1, rate); + clk_enable(cko1); + sgtl5000_data.sysclk = rate; + platform_device_register(&mxc_sgtl5000_device); +} +#else +static inline void mxc_init_sgtl5000(void) +{ +} +#endif + +/*! + * fixup for mx37 3stack board v1.1(wm8350) + */ +static void mx37_3stack_fixup_for_board_v1(void) +{ + dptc_gp_data.reg_id = "DCDC1"; + dptc_lp_data.reg_id = "DCDC4"; + gp_reg_id = "DCDC1"; + lp_reg_id = "DCDC4"; + tve_data.dac_reg = "LDO2"; + tve_data.dig_reg = "LDO3"; + lcd_data.core_reg = "LDO1"; + lcd_data.io_reg = "DCDC6"; + dvfs_core_data.reg_id = "DCDC1"; + ls_data.vdd_reg = "DCDC3"; + mxc_bt_data.bt_vdd = "DCDC3"; + mxc_bt_data.bt_vusb = "DCDC6"; + + unifi_data.reg_1v5_ana_bb = NULL; /* VMAIN is used on v1 board */ + unifi_data.reg_vdd_vpa = NULL; + unifi_data.reg_1v5_dd = NULL; +#if defined(CONFIG_KEYBOARD_MPR084) || defined(CONFIG_KEYBOARD_MPR084_MODULE) + keypad_data.vdd_reg = "DCDC3"; +#endif +} + +#if defined(CONFIG_GPS_IOCTRL) || defined(CONFIG_GPS_IOCTRL_MODULE) +static struct mxc_gps_platform_data gps_data = { + .core_reg = "VIOHI", + .analog_reg = "SW3", +}; + +static struct platform_device mxc_gps_device = { + .name = "gps_ioctrl", + .id = 0, + .dev = { + .platform_data = &gps_data, + }, +}; + +static void __init mxc_init_gps(void) +{ + (void)platform_device_register(&mxc_gps_device); +} +#else +static void __init mxc_init_gps(void) +{ +} +#endif + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_cpu_common_init(); + mxc_register_gpios(); + early_console_setup(saved_command_line); + mxc_init_devices(); + if (!board_is_rev(BOARD_REV_2)) + mx37_3stack_fixup_for_board_v1(); + i2c_register_board_info(0, mxc_i2c0_board_info, + ARRAY_SIZE(mxc_i2c0_board_info)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + + spi_register_board_info(mxc_spi_board_info, + ARRAY_SIZE(mxc_spi_board_info)); + mxc_init_nand_mtd(); + mxc_init_mmc(); + mxc_init_pata(); + mxc_init_fb(); + mxc_init_bl(); + mxc_init_bluetooth(); + mxc_init_gps(); + mxc_init_sgtl5000(); +} + +static void __init mx37_3stack_timer_init(void) +{ + mx37_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mxc_timer = { + .init = mx37_3stack_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX37_3STACK data structure. + */ +/* *INDENT-OFF* */ +MACHINE_START(MX37_3DS, "Freescale MX37 3-Stack Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx37_map_io, + .init_irq = mxc_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx37/mx37_3stack_cpld.c b/arch/arm/mach-mx37/mx37_3stack_cpld.c new file mode 100644 index 000000000000..ad3ab6fb7a34 --- /dev/null +++ b/arch/arm/mach-mx37/mx37_3stack_cpld.c @@ -0,0 +1,233 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <mach/hardware.h> +#include <asm/mach/irq.h> +#include <mach/gpio.h> +#include "board-mx37_3stack.h" +#include "iomux.h" + +/*! + * @file mach-mx37/mx37_3stack_cpld.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX37 + */ + +extern int mxc_spi_poll_transfer(struct spi_device *spi, + struct spi_transfer *t); +static int __init mxc_expio_init(void); + +struct spi_device *cpld_spi; + +/*! + * This function is used to tranfer data to CPLD regs over CSPI + */ +static inline int mx37_3ds_cpld_rw(u8 * buf, size_t len) +{ + struct spi_transfer t = { + .tx_buf = (const void *)buf, + .rx_buf = buf, + .len = len, + .cs_change = 0, + .delay_usecs = 0, + }; + mxc_spi_poll_transfer(cpld_spi, &t); + return 0; +} + +/*! + * This function is called to read a CPLD register over CSPI. + * + * @param offset number of the cpld register to be read + * + * @return Returns 0 on success -1 on failure. + */ +unsigned int spi_cpld_read(unsigned int offset) +{ + unsigned int frame[2]; + unsigned int reg_num = offset >> 1; + unsigned int data = 0; + + frame[0] = (1 << 13) | ((reg_num & 0x0001FFFF) >> 5) | 0x00001000; + frame[1] = (((reg_num & 0x0000001F) << 27) | 0x0200001f); + mx37_3ds_cpld_rw((u8 *) frame, 2); + data = (frame[1] >> 6) & 0xFFFF; + + reg_num = (offset + 2) >> 1; + frame[0] = (1 << 13) | ((reg_num & 0x0001FFFF) >> 5) | 0x00001000; + frame[1] = (((reg_num & 0x0000001F) << 27) | 0x0200001f); + mx37_3ds_cpld_rw((u8 *) frame, 2); + + data |= (((frame[1] >> 6) & 0xFFFF) << 16); + return data; +} +EXPORT_SYMBOL(spi_cpld_read); + +/*! + * This function is called to write to a CPLD register over CSPI. + * + * @param offset number of the cpld register to be written + * @param reg_val value to be written + * + * @return Returns 0 on success -1 on failure. + */ +unsigned int spi_cpld_write(unsigned int offset, unsigned int reg_val) +{ + unsigned int frame[2] = { 0, 0 }; + unsigned int reg_num = offset >> 1; + unsigned int data = reg_val; + + frame[0] = ((reg_num & 0x0001FFFF) >> 5) | 0x00001000; + frame[1] = (((reg_num & 0x0000001F) << 27) | + ((data & 0x0000FFFF) << 6) | 0x03C00027); + mx37_3ds_cpld_rw((u8 *) frame, 2); + + reg_num = (offset + 2) >> 1; + data = reg_val >> 16; + frame[0] = 0; + frame[1] = 0; + frame[0] = ((reg_num & 0x0001FFFF) >> 5) | 0x00001000; + frame[1] = (((reg_num & 0x0000001F) << 27) | + ((data & 0x0000FFFF) << 6) | 0x03C00027); + + mx37_3ds_cpld_rw((u8 *) frame, 2); + + return 0; +} +EXPORT_SYMBOL(spi_cpld_write); + +static int __init mx37_3ds_cpld_probe(struct spi_device *spi) +{ + unsigned int i = 0; + + spi->bits_per_word = 46; + cpld_spi = spi; + + spi_setup(spi); + i = spi_cpld_read(CPLD_CODE_VER_REG); + pr_info("3-Stack Debug board detected, rev = 0x%04X\n", i); + spi_cpld_write(LED_SWITCH_REG, 0xFF); + + /* disable the interrupt and clear the status */ + spi_cpld_write(INTR_MASK_REG, 0); + spi_cpld_write(INTR_RESET_REG, 0xFFFF); + spi_cpld_write(INTR_RESET_REG, 0); + spi_cpld_write(INTR_MASK_REG, 0x1E); + + mxc_expio_init(); + return 0; +} + +/*! + * This structure contains pointers to the CPLD callback functions. + */ +static struct spi_driver mx37_3ds_cpld_driver = { + .driver = { + .name = "cpld_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mx37_3ds_cpld_probe, +}; + +static int __init mx37_3ds_cpld_init(void) +{ + pr_debug("Registering the CPLD Driver\n"); + return spi_register_driver(&mx37_3ds_cpld_driver); +} + +device_initcall(mx37_3ds_cpld_init); + +static void mxc_expio_irq_handler(u32 irq, struct irq_desc *desc) +{ + u32 expio_irq; + struct irq_desc *d; + + desc->chip->mask(irq); /* irq = gpio irq number */ + + expio_irq = MXC_BOARD_IRQ_START; + + d = irq_desc + expio_irq; + if (unlikely(!(d->handle_irq))) { + printk(KERN_ERR "\nEXPIO irq: %d unhandled\n", expio_irq); + BUG(); /* oops */ + } + d->handle_irq(expio_irq, d); + + desc->chip->ack(irq); + desc->chip->unmask(irq); +} + +/* + * Disable an expio pin's interrupt by setting the bit in the imr. + * @param irq an expio virtual irq number + */ +static void expio_mask_irq(u32 irq) +{ +} + +/* + * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr. + * @param irq an expanded io virtual irq number + */ +static void expio_ack_irq(u32 irq) +{ + /* clear the interrupt status */ + spi_cpld_write(INTR_RESET_REG, 1); + spi_cpld_write(INTR_RESET_REG, 0); +} + +/* + * Enable a expio pin's interrupt by clearing the bit in the imr. + * @param irq a expio virtual irq number + */ +static void expio_unmask_irq(u32 irq) +{ +} + +static struct irq_chip expio_irq_chip = { + .ack = expio_ack_irq, + .mask = expio_mask_irq, + .unmask = expio_unmask_irq, +}; + +static int __init mxc_expio_init(void) +{ + int i; + int pad_val; + + /* + * Configure INT line as GPIO input + */ + mxc_request_iomux(MX37_PIN_GPIO1_2, IOMUX_CONFIG_GPIO); + pad_val = mxc_iomux_get_pad(MX37_PIN_GPIO1_2); + pad_val |= PAD_CTL_PUE_PULL; + mxc_iomux_set_pad(MX37_PIN_GPIO1_2, pad_val); + gpio_direction_input(IOMUX_TO_GPIO(MX37_PIN_GPIO1_2)); + + for (i = MXC_BOARD_IRQ_START; i < (MXC_BOARD_IRQ_START + MXC_BOARD_IRQS); + i++) { + set_irq_chip(i, &expio_irq_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + set_irq_type(IOMUX_TO_IRQ(MX37_PIN_GPIO1_2), IRQF_TRIGGER_LOW); + set_irq_chained_handler(IOMUX_TO_IRQ(MX37_PIN_GPIO1_2), + mxc_expio_irq_handler); + return 0; +} + diff --git a/arch/arm/mach-mx37/mx37_3stack_gpio.c b/arch/arm/mach-mx37/mx37_3stack_gpio.c new file mode 100644 index 000000000000..8b4e073e1384 --- /dev/null +++ b/arch/arm/mach-mx37/mx37_3stack_gpio.c @@ -0,0 +1,1029 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/gpio.h> +#include <mach/irqs.h> + +#include "iomux.h" + +/*! + * @file mx37_3stack_gpio.c + * + * @brief This file contains all the GPIO setup functions for the board. + * + * @ingroup GPIO + */ + +void gpio_activate_audio_ports(void); + +/*! + * Setup GPIO for a UART port to be active + * + * @param port a UART port + * @param no_irda indicates if the port is used for SIR + */ +void gpio_uart_active(int port, int no_irda) +{ + /* + * Configure the IOMUX control registers for the UART signals + * and enable the UART transceivers + */ + switch (port) { + /* UART 1 IOMUX Configs */ + case 0: + mxc_request_iomux(MX37_PIN_UART1_RXD, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_UART1_RXD, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_iomux_set_input(MUX_IN_UART1_UART_RXD_MUX, INPUT_CTL_PATH4); + mxc_request_iomux(MX37_PIN_UART1_TXD, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_UART1_TXD, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_request_iomux(MX37_PIN_UART1_RTS, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_UART1_RTS, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + mxc_iomux_set_input(MUX_IN_UART1_UART_RTS_B, INPUT_CTL_PATH4); + mxc_request_iomux(MX37_PIN_UART1_CTS, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_UART1_CTS, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + break; + case 1: + mxc_request_iomux(MX37_PIN_UART1_DCD, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_UART1_DCD, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_iomux_set_input(MUX_IN_UART2_UART_RXD_MUX, INPUT_CTL_PATH1); + mxc_request_iomux(MX37_PIN_UART1_RI, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_UART1_RI, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_request_iomux(MX37_PIN_UART1_DSR, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_UART1_DSR, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + mxc_iomux_set_input(MUX_IN_UART2_UART_RTS_B, INPUT_CTL_PATH1); + mxc_request_iomux(MX37_PIN_UART1_DTR, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_UART1_DTR, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + break; + case 2: + mxc_request_iomux(MX37_PIN_AUD3_BB_TXD, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_AUD3_BB_TXD, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_iomux_set_input(MUX_IN_UART3_UART_RXD_MUX, INPUT_CTL_PATH0); + mxc_request_iomux(MX37_PIN_AUD3_BB_RXD, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_AUD3_BB_RXD, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mxc_request_iomux(MX37_PIN_AUD3_BB_CK, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_AUD3_BB_CK, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + mxc_iomux_set_input(MUX_IN_UART3_UART_RTS_B, INPUT_CTL_PATH0); + mxc_request_iomux(MX37_PIN_AUD3_BB_FS, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_AUD3_BB_FS, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH); + break; + default: + break; + } +} + +/*! + * Setup GPIO for a UART port to be inactive + * + * @param port a UART port + * @param no_irda indicates if the port is used for SIR + */ +void gpio_uart_inactive(int port, int no_irda) +{ + /* + * Configure the IOMUX control registers for the UART signals + * and disable the UART transceivers + */ + switch (port) { + case 0: + mxc_request_iomux(MX37_PIN_UART1_RXD, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_TXD, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_RTS, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_CTS, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_RXD, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_TXD, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_RTS, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_CTS, IOMUX_CONFIG_GPIO); + break; + case 1: + mxc_request_iomux(MX37_PIN_UART1_DCD, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_RI, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_DSR, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_UART1_DTR, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_DCD, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_RI, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_DSR, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_UART1_DTR, IOMUX_CONFIG_GPIO); + break; + /* UART 3 IOMUX Configs */ + case 2: + mxc_request_iomux(MX37_PIN_AUD3_BB_TXD, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_AUD3_BB_TXD, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_AUD3_BB_RXD, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_AUD3_BB_RXD, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_AUD3_BB_CK, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_AUD3_BB_CK, IOMUX_CONFIG_GPIO); + mxc_request_iomux(MX37_PIN_AUD3_BB_FS, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_AUD3_BB_FS, IOMUX_CONFIG_GPIO); + break; + default: + break; + } +} + +/*! + * Configure the IOMUX GPR register to receive shared SDMA UART events + * + * @param port a UART port + */ +void config_uartdma_event(int port) +{ + +} + +EXPORT_SYMBOL(gpio_uart_active); +EXPORT_SYMBOL(gpio_uart_inactive); +EXPORT_SYMBOL(config_uartdma_event); + +/*! + * Setup GPIO for a CSPI device to be active + * + * @param cspi_mod an CSPI device + */ +void gpio_spi_active(int cspi_mod) +{ + switch (cspi_mod) { + case 0: + break; + case 1: + /* SPI2 */ + mxc_request_iomux(MX37_PIN_CSPI2_MISO, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_CSPI2_MISO, PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_GRP_H9, PAD_CTL_HYS_ENABLE); + + mxc_request_iomux(MX37_PIN_CSPI2_MOSI, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_CSPI2_MOSI, PAD_CTL_SRE_FAST); + + mxc_request_iomux(MX37_PIN_UART1_CTS, IOMUX_CONFIG_ALT3); + mxc_iomux_set_pad(MX37_PIN_UART1_CTS, PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE); + + mxc_request_iomux(MX37_PIN_CSPI2_SCLK, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_CSPI2_SCLK, PAD_CTL_HYS_ENABLE | + PAD_CTL_SRE_FAST); + + mxc_request_iomux(MX37_PIN_CSPI2_SS1, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_CSPI2_SS1, PAD_CTL_SRE_FAST); + + mxc_request_iomux(MX37_PIN_CSPI2_SS0, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_CSPI2_SS0, PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_GRP_H10, PAD_CTL_HYS_ENABLE); + break; + case 2: + break; + default: + break; + } +} + +/*! + * Setup GPIO for a CSPI device to be inactive + * + * @param cspi_mod a CSPI device + */ +void gpio_spi_inactive(int cspi_mod) +{ +} + +/*! + * Setup 1-Wire to be active + */ +void gpio_owire_active(void) +{ + /*TODO*/} + +/*! + * Setup 1-Wire to be active + */ +void gpio_owire_inactive(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_owire_active); +EXPORT_SYMBOL(gpio_owire_inactive); + +/*! + * Setup GPIO for an I2C device to be active + * + * @param i2c_num an I2C device + */ +void gpio_i2c_active(int i2c_num) +{ + iomux_pad_config_t regval = 0; + + switch (i2c_num) { + case 0: + /* Touch */ + /* select I2C1_SCK as daisy chain input */ + mxc_request_iomux(MX37_PIN_I2C1_CLK, IOMUX_CONFIG_ALT0); + mxc_iomux_set_input(MUX_IN_I2C1_SCL, INPUT_CTL_PATH1); + /* OpenDrain enabled, 100k PU enabled */ + regval = + PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_100K_PU | + PAD_CTL_PKE_ENABLE; + mxc_iomux_set_pad(MX37_PIN_I2C1_CLK, regval); + + /*select I2C1_SDA as daisy chain input */ + mxc_request_iomux(MX37_PIN_I2C1_DAT, IOMUX_CONFIG_ALT0); + mxc_iomux_set_input(MUX_IN_I2C1_SDA, INPUT_CTL_PATH1); + mxc_iomux_set_pad(MX37_PIN_I2C1_DAT, regval); + mxc_iomux_set_pad(MX37_PIN_GRP_H3, PAD_CTL_HYS_ENABLE); + break; + case 1: + /* PMIC */ + /*select I2C2_SCL as daisy chain input */ + mxc_iomux_set_input(MUX_IN_I2C2_SCL, INPUT_CTL_PATH1); + regval = PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | + PAD_CTL_PUE_PULL | PAD_CTL_100K_PU | + PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_DRV_HIGH; + mxc_iomux_set_pad(MX37_PIN_GPIO1_0, regval); + mxc_request_iomux(MX37_PIN_GPIO1_0, + (IOMUX_CONFIG_SION | IOMUX_CONFIG_ALT2)); + + /*select I2C2_SDA as daisy chain input */ + mxc_iomux_set_input(MUX_IN_I2C2_SDA, INPUT_CTL_PATH1); + mxc_iomux_set_pad(MX37_PIN_GPIO1_1, regval); + mxc_request_iomux(MX37_PIN_GPIO1_1, + (IOMUX_CONFIG_SION | IOMUX_CONFIG_ALT2)); + break; + case 2: + break; + default: + break; + } +} + +/*! + * Setup GPIO for an I2C device to be inactive + * + * @param i2c_num an I2C device + */ +void gpio_i2c_inactive(int i2c_num) +{ + /*TODO*/} + +/*! + * This function activates DAM ports 4 & 5 to enable + * audio I/O. + */ +void gpio_activate_audio_ports(void) +{ + unsigned int pad_val; + + /* AUD4_TXD */ + mxc_request_iomux(MX37_PIN_DISP1_DAT20, IOMUX_CONFIG_ALT5); + /* AUD4_RXD */ + mxc_request_iomux(MX37_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT5); + /* AUD4_TXC */ + mxc_request_iomux(MX37_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT5); + /* AUD4_TXFS */ + mxc_request_iomux(MX37_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT5); + + pad_val = PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST; + mxc_iomux_set_pad(MX37_PIN_AUD5_WB_CK, PAD_CTL_100K_PU | pad_val); + mxc_request_iomux(MX37_PIN_AUD5_WB_CK, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_AUD5_WB_RXD, pad_val); + mxc_request_iomux(MX37_PIN_AUD5_WB_RXD, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_AUD5_WB_TXD, pad_val); + mxc_request_iomux(MX37_PIN_AUD5_WB_TXD, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_AUD5_WB_FS, PAD_CTL_100K_PU | pad_val); + mxc_request_iomux(MX37_PIN_AUD5_WB_FS, IOMUX_CONFIG_ALT0); + + /* Enable hysteresis for AUD5_WB_CK, AUD5_WB_RXD, AUD5_WB_TXD, AUD5_WB_FS */ + mxc_iomux_set_pad(MX37_PIN_GRP_H5, PAD_CTL_HYS_ENABLE); +} + +EXPORT_SYMBOL(gpio_activate_audio_ports); + +/*! + * Setup GPIO for SDHC to be active + * + * @param module SDHC module number + */ +void gpio_sdhc_active(int module) +{ + switch (module) { + case 0: + mxc_request_iomux(MX37_PIN_SD1_CLK, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD1_CMD, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD1_DATA0, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD1_DATA1, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD1_DATA2, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD1_DATA3, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + + mxc_iomux_set_pad(MX37_PIN_SD1_CMD, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD1_CLK, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA0, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA1, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA2, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA3, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + + /* Write Protected Pin */ + mxc_request_iomux(MX37_PIN_CSPI1_SS0, + IOMUX_CONFIG_SION | IOMUX_CONFIG_ALT4); + mxc_iomux_set_pad(MX37_PIN_CSPI1_SS0, + PAD_CTL_DRV_HIGH | PAD_CTL_HYS_NONE | + PAD_CTL_SRE_FAST); + /* + * SW workaround for the eSDHC1 Write Protected feature + * The PSR of CSPI1_SS0 (GPIO3_2) should be read. + */ + gpio_request(IOMUX_TO_GPIO(MX37_PIN_CSPI1_SS0), "cspi1_ss0"); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_CSPI1_SS0), 0); + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_CSPI1_SS0), 1); + break; + case 1: + mxc_request_iomux(MX37_PIN_SD2_CLK, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD2_CMD, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD2_DATA0, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD2_DATA1, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD2_DATA2, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_request_iomux(MX37_PIN_SD2_DATA3, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + + mxc_iomux_set_pad(MX37_PIN_SD2_CMD, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD2_CLK, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA0, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA1, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA2, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA3, + PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_PULL | + PAD_CTL_47K_PU | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + break; + default: + break; + } +} + +EXPORT_SYMBOL(gpio_sdhc_active); + +/*! + * Setup GPIO for SDHC1 to be inactive + * + * @param module SDHC module number + */ +void gpio_sdhc_inactive(int module) +{ + switch (module) { + case 0: + mxc_free_iomux(MX37_PIN_SD1_CLK, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD1_CMD, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD1_DATA0, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD1_DATA1, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD1_DATA2, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD1_DATA3, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + + mxc_iomux_set_pad(MX37_PIN_SD1_CLK, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD1_CMD, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA0, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA1, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA2, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD1_DATA3, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + + /* Free Write Protected Pin */ + mxc_free_iomux(MX37_PIN_CSPI1_SS0, + IOMUX_CONFIG_SION | IOMUX_CONFIG_ALT4); + mxc_iomux_set_pad(MX37_PIN_CSPI1_SS0, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + break; + case 1: + mxc_free_iomux(MX37_PIN_SD2_CLK, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD2_CMD, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD2_DATA0, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD2_DATA1, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD2_DATA2, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + mxc_free_iomux(MX37_PIN_SD2_DATA3, + IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION); + + mxc_iomux_set_pad(MX37_PIN_SD2_CLK, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD2_CMD, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA0, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA1, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA2, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA3, + (PAD_CTL_DRV_LOW | PAD_CTL_SRE_SLOW)); + break; + default: + break; + } +} + +EXPORT_SYMBOL(gpio_sdhc_inactive); + +/* + * Probe for the card. If present the GPIO data would be set. + */ +int sdhc_get_card_det_status(struct device *dev) +{ + int ret; + u32 gpio = IOMUX_TO_GPIO(MX37_PIN_OWIRE_LINE); + + if (to_platform_device(dev)->id == 0) { + if (board_is_rev(BOARD_REV_2)) + ret = gpio_get_value(IOMUX_TO_GPIO(MX37_PIN_GPIO1_4)); + else + ret = gpio_get_value(gpio); + return ret; + } else { /* config the det pin for SDHC2 */ + return 0; + } +} + +EXPORT_SYMBOL(sdhc_get_card_det_status); + +/* + * Return the card detect pin. + */ +int sdhc_init_card_det(int id) +{ + u32 gpio; + + if (id == 0) { + if (board_is_rev(BOARD_REV_2)) { + gpio = IOMUX_TO_GPIO(MX37_PIN_GPIO1_4); + mxc_request_iomux(MX37_PIN_GPIO1_4, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX37_PIN_GPIO1_4, + PAD_CTL_DRV_HIGH | + PAD_CTL_HYS_NONE | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_NONE | PAD_CTL_SRE_FAST); + gpio_request(gpio, "gpio1_4"); + gpio_direction_input(gpio); + return IOMUX_TO_IRQ(MX37_PIN_GPIO1_4); + } else { + gpio = IOMUX_TO_GPIO(MX37_PIN_OWIRE_LINE); + mxc_request_iomux(MX37_PIN_OWIRE_LINE, + IOMUX_CONFIG_ALT4); + mxc_iomux_set_pad(MX37_PIN_OWIRE_LINE, + PAD_CTL_DRV_HIGH | + PAD_CTL_HYS_NONE | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_NONE | PAD_CTL_SRE_FAST); + gpio_request(gpio, "owire_line"); + gpio_direction_input(gpio); + return IOMUX_TO_IRQ(MX37_PIN_OWIRE_LINE); + } + } else { /* config the det pin for SDHC2 */ + return 0; + + } +} + +EXPORT_SYMBOL(sdhc_init_card_det); + +/*! + * Get CSPI1_SS0 pin value to detect write protection + */ +int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + rc = gpio_get_value(IOMUX_TO_GPIO(MX37_PIN_CSPI1_SS0)); + if (rc > 0) + return 1; + else + return 0; +} + +EXPORT_SYMBOL(sdhc_write_protect); + +/*! + * Setup GPIO for LCD to be active + * + */ +void gpio_lcd_active(void) +{ + mxc_request_iomux(MX37_PIN_DI1_PIN2, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_PAD_DI1_PIN3, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_DISP_CLK, IOMUX_CONFIG_ALT0); +} + +/*! + * Setup GPIO for LCD to be inactive + * + */ +void gpio_lcd_inactive(void) +{ + /*TODO*/} + +/*! + * Setup pins for SLCD to be active + * + */ +void slcd_gpio_config(void) +{ + /*TODO*/} + +/*! + * Switch to the specified sensor - MX33 ADS has two + * + */ +void gpio_sensor_select(int sensor) +{ + /*TODO*/} + +/*! + * Setup GPIO for sensor to be active + * + */ +void gpio_sensor_active(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_sensor_active); + +/*! + * Setup GPIO for sensor to be inactive + * + */ +void gpio_sensor_inactive(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_sensor_inactive); + +/*! + * Setup GPIO for ATA interface + * + */ +void gpio_ata_active(void) +{ + /*IOMUX Settings */ + /*PATA_DMARQ_B */ + mxc_request_iomux(MX37_PIN_NANDF_RE_B, IOMUX_CONFIG_ALT1); + /*PATA_DIOR */ + mxc_request_iomux(MX37_PIN_NANDF_ALE, IOMUX_CONFIG_ALT1); + /*PATA_DIOW */ + mxc_request_iomux(MX37_PIN_NANDF_CLE, IOMUX_CONFIG_ALT1); + /*PATA_DMACK */ + mxc_request_iomux(MX37_PIN_NANDF_WP_B, IOMUX_CONFIG_ALT1); + /*PATA_RESET_B */ + mxc_request_iomux(MX37_PIN_NANDF_RB, IOMUX_CONFIG_ALT1); + /*PATA_IORDY */ + mxc_request_iomux(MX37_PIN_NANDF_CS0, IOMUX_CONFIG_ALT1); + /*PATA_INTRQ_B */ + mxc_request_iomux(MX37_PIN_NANDF_CS1, IOMUX_CONFIG_ALT1); + /*PATA_CS_0 */ + mxc_request_iomux(MX37_PIN_NANDF_CS2, IOMUX_CONFIG_ALT1); + /*PATA_CS_1 */ + mxc_request_iomux(MX37_PIN_NANDF_CS3, IOMUX_CONFIG_ALT1); + + /*PATA_D0 */ + mxc_request_iomux(MX37_PIN_EIM_D0, IOMUX_CONFIG_ALT1); + /*PATA_D1 */ + mxc_request_iomux(MX37_PIN_EIM_D1, IOMUX_CONFIG_ALT1); + /*PATA_D2 */ + mxc_request_iomux(MX37_PIN_EIM_D2, IOMUX_CONFIG_ALT1); + /*PATA_D3 */ + mxc_request_iomux(MX37_PIN_EIM_D3, IOMUX_CONFIG_ALT1); + /*PATA_D4 */ + mxc_request_iomux(MX37_PIN_EIM_D4, IOMUX_CONFIG_ALT1); + /*PATA_D5 */ + mxc_request_iomux(MX37_PIN_EIM_D5, IOMUX_CONFIG_ALT1); + /*PATA_D6 */ + mxc_request_iomux(MX37_PIN_EIM_D6, IOMUX_CONFIG_ALT1); + /*PATA_D7 */ + mxc_request_iomux(MX37_PIN_EIM_D7, IOMUX_CONFIG_ALT1); + /*PATA_D8 */ + mxc_request_iomux(MX37_PIN_EIM_D8, IOMUX_CONFIG_ALT1); + /*PATA_D9 */ + mxc_request_iomux(MX37_PIN_EIM_D9, IOMUX_CONFIG_ALT1); + /*PATA_D10 */ + mxc_request_iomux(MX37_PIN_EIM_D10, IOMUX_CONFIG_ALT1); + /*PATA_D11 */ + mxc_request_iomux(MX37_PIN_EIM_D11, IOMUX_CONFIG_ALT1); + /*PATA_D12 */ + mxc_request_iomux(MX37_PIN_EIM_D12, IOMUX_CONFIG_ALT1); + /*PATA_D13 */ + mxc_request_iomux(MX37_PIN_EIM_D13, IOMUX_CONFIG_ALT1); + /*PATA_D14 */ + mxc_request_iomux(MX37_PIN_EIM_D14, IOMUX_CONFIG_ALT1); + /*PATA_D15 */ + mxc_request_iomux(MX37_PIN_EIM_D15, IOMUX_CONFIG_ALT1); + /*PATA_DA0 */ + mxc_request_iomux(MX37_PIN_SD2_DATA3, IOMUX_CONFIG_ALT1); + /*PATA_DA1 */ + mxc_request_iomux(MX37_PIN_SD2_DATA2, IOMUX_CONFIG_ALT1); + /*PATA_DA2 */ + mxc_request_iomux(MX37_PIN_SD2_DATA1, IOMUX_CONFIG_ALT1); + + /* BUFFER_ENABLE - HDD_ENABLE_B */ + mxc_request_iomux(MX37_PIN_NANDF_WE_B, IOMUX_CONFIG_ALT1); + + /* IOMUX Pad Settings */ + mxc_iomux_set_pad(MX37_PIN_EIM_D0, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D1, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D2, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D3, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D4, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D5, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D6, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D7, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D8, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D9, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D10, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D11, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D12, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D13, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D14, 0xc0); + mxc_iomux_set_pad(MX37_PIN_EIM_D15, 0xc0); + + mxc_iomux_set_pad(MX37_PIN_NANDF_RE_B, 0x0080); + mxc_iomux_set_pad(MX37_PIN_NANDF_CS1, 0x0020); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA3, 0x00); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA2, 0x00); + mxc_iomux_set_pad(MX37_PIN_SD2_DATA1, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_ALE, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_CS2, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_CS3, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_WE_B, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_CLE, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_WP_B, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_RB, 0x00); + mxc_iomux_set_pad(MX37_PIN_NANDF_CS0, 0x0020); + +} + +EXPORT_SYMBOL(gpio_ata_active); + +/*! + * Restore ATA interface pins to reset values + * + */ +void gpio_ata_inactive(void) +{ + /*Turn off the IOMUX for ATA group B signals */ + mxc_request_iomux(MX37_PIN_EIM_D0, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D1, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D2, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D3, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D4, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D5, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D6, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D7, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D8, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D9, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D10, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D11, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D12, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D13, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D14, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_EIM_D15, IOMUX_CONFIG_ALT0); + + /* Config the multiplex pin of ATA interface DIR, DA0-2, INTRQ, DMARQ */ + mxc_request_iomux(MX37_PIN_NANDF_RE_B, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_CS1, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_ALE, IOMUX_CONFIG_ALT0); + + /* HDD_BUFF_EN (H:A->B, L:B->A) and HDD_ENABLE_B(H:Disable,L:Enable) */ + mxc_free_iomux(MX37_PIN_NANDF_WE_B, IOMUX_CONFIG_ALT0); + + /* These ATA pins are common to Group A and Group B */ + mxc_request_iomux(MX37_PIN_NANDF_CS2, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_CS3, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_ALE, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_CLE, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_WP_B, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_RB, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX37_PIN_NANDF_CS0, IOMUX_CONFIG_ALT0); + +} + +EXPORT_SYMBOL(gpio_ata_inactive); + +/*! + * Setup GPIO for Keypad to be active + * + */ +void gpio_keypad_active(void) +{ + int pad_val; + + /* + * Configure the IOMUX control register for keypad signals. + */ + /*KEY_INT */ + mxc_request_iomux(MX37_PIN_GPIO1_3, IOMUX_CONFIG_ALT0); + /*KEY_WAKE */ + mxc_request_iomux(MX37_PIN_DISP1_DAT18, IOMUX_CONFIG_ALT4); + + /* fast slew rate */ + pad_val = (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_22K_PU | \ + PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_HYS_NONE | \ + PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW); + /*KEY_INT */ + mxc_iomux_set_pad(MX37_PIN_GPIO1_3, pad_val); + + /* fast slew rate */ + pad_val = (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | \ + PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_HYS_NONE | \ + PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW); + /*KEY_WAKE */ + mxc_iomux_set_pad(MX37_PIN_DISP1_DAT18, pad_val); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_DISP1_DAT18), "disp1_dat18"); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_DISP1_DAT18), 0); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_GPIO1_3), "gpio1_3"); + gpio_direction_input(IOMUX_TO_GPIO(MX37_PIN_GPIO1_3)); + + /* drive initial value */ + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_DISP1_DAT18), 1); +} + +EXPORT_SYMBOL(gpio_keypad_active); + +/*! + * Setup GPIO for Keypad to be inactive + * + */ +void gpio_keypad_inactive(void) +{ + /*KEY_INT */ + mxc_request_iomux(MX37_PIN_GPIO1_3, IOMUX_CONFIG_ALT0); + /*KEY_WAKE */ + mxc_request_iomux(MX37_PIN_DISP1_DAT18, IOMUX_CONFIG_ALT0); +} + +EXPORT_SYMBOL(gpio_keypad_inactive); + +/* + * USB OTG HS port + */ +int gpio_usbotg_hs_active(void) +{ + /*TODO*/ return 0; +} + +EXPORT_SYMBOL(gpio_usbotg_hs_active); + +void gpio_usbotg_hs_inactive(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_usbotg_hs_inactive); + +/*! + * Setup GPIO for PCMCIA interface + * + */ +void gpio_pcmcia_active(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_pcmcia_active); + +/*! + * Setup GPIO for pcmcia to be inactive + */ +void gpio_pcmcia_inactive(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_pcmcia_inactive); + +/*! + * Setup GPIO for fec to be active + */ +void gpio_fec_active(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_fec_active); +/*! + * Setup GPIO for fec to be inactive + */ +void gpio_fec_inactive(void) +{ + /*TODO*/} + +EXPORT_SYMBOL(gpio_fec_inactive); + +void gpio_spdif_active(void) +{ + iomux_pad_config_t regval = 0; + regval = + PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_PKE_ENABLE | + PAD_CTL_100K_PU; + mxc_iomux_set_pad(MX37_PIN_AUD3_BB_RXD, regval); + mxc_request_iomux(MX37_PIN_AUD3_BB_RXD, IOMUX_CONFIG_ALT1); +} + +EXPORT_SYMBOL(gpio_spdif_active); + +void gpio_spdif_inactive(void) +{ + mxc_free_iomux(MX37_PIN_AUD3_BB_RXD, IOMUX_CONFIG_ALT1); +} + +EXPORT_SYMBOL(gpio_spdif_inactive); + +void gpio_pmic_active(void) +{ + mxc_request_iomux(MX37_PIN_OWIRE_LINE, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX37_PIN_OWIRE_LINE, PAD_CTL_SRE_SLOW | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_DRV_MEDIUM | + PAD_CTL_100K_PU | + PAD_CTL_HYS_ENABLE | + PAD_CTL_DRV_VOT_HIGH | PAD_CTL_DDR_INPUT_CMOS); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_OWIRE_LINE), "owire_line"); + gpio_direction_input(IOMUX_TO_GPIO(MX37_PIN_OWIRE_LINE)); +} + +EXPORT_SYMBOL(gpio_pmic_active); + +void gpio_gps_active(void) +{ + /* PWR_EN */ + mxc_request_iomux(MX37_PIN_EIM_OE, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX37_PIN_EIM_OE, PAD_CTL_100K_PU | + PAD_CTL_DRV_HIGH | PAD_CTL_HYS_NONE | + PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_EIM_OE), "eim_oe"); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_EIM_OE), 0); + + /* RESET */ + mxc_request_iomux(MX37_PIN_EIM_BCLK, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX37_PIN_EIM_BCLK, PAD_CTL_DRV_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + gpio_request(IOMUX_TO_GPIO(MX37_PIN_EIM_BCLK), "eim_bclk"); + gpio_direction_output(IOMUX_TO_GPIO(MX37_PIN_EIM_BCLK), 0); + + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_EIM_OE), 0); + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_EIM_BCLK), 0); + + msleep(5); + gpio_set_value(IOMUX_TO_GPIO(MX37_PIN_EIM_BCLK), 1); + + msleep(5); +} + +EXPORT_SYMBOL(gpio_gps_active); + +int gpio_gps_access(int para) +{ + iomux_pin_name_t pin; + pin = (para & 0x1) ? MX37_PIN_EIM_OE : MX37_PIN_EIM_BCLK; + + if (para & 0x4) + return gpio_get_value(IOMUX_TO_GPIO(pin)); + else if (para & 0x2) + gpio_set_value(IOMUX_TO_GPIO(pin), 1); + else + gpio_set_value(IOMUX_TO_GPIO(pin), 0); + + return 0; +} + +EXPORT_SYMBOL(gpio_gps_access); + +void gpio_gps_inactive(void) +{ + mxc_free_iomux(MX37_PIN_EIM_BCLK, IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX37_PIN_EIM_OE, IOMUX_CONFIG_GPIO); +} + +EXPORT_SYMBOL(gpio_gps_inactive); + +int headphone_det_status(void) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX37_PIN_AUD5_RXFS)); +} + +EXPORT_SYMBOL(headphone_det_status); diff --git a/arch/arm/mach-mx37/mx37_3stack_pmic_wm8350.c b/arch/arm/mach-mx37/mx37_3stack_pmic_wm8350.c new file mode 100644 index 000000000000..62ec76f0761b --- /dev/null +++ b/arch/arm/mach-mx37/mx37_3stack_pmic_wm8350.c @@ -0,0 +1,349 @@ +/* + * mx37-3stack-pmic-wm8350.c -- i.MX37 3STACK Driver for Wolfson WM8350 PMIC + * + * Copyright 2007 Wolfson Microelectronics PLC. + * Copyright 2008-2009 Freescale Semiconductor Inc. + * + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/wm8350/core.h> +#include <linux/mfd/wm8350/pmic.h> +#include <linux/mfd/wm8350/gpio.h> +#include <linux/mfd/wm8350/bl.h> +#include <mach/irqs.h> + +#include "iomux.h" + +/* CPU */ +static struct regulator_consumer_supply dcdc1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_init_data dcdc1_data = { + .constraints = { + .name = "DCDC1", + .min_uV = 850000, + .max_uV = 1200000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .state_mem = { + .uV = 1050000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(dcdc1_consumers), + .consumer_supplies = dcdc1_consumers, +}; + +/* MX37 LP */ +static struct regulator_init_data dcdc4_data = { + .constraints = { + .name = "DCDC4", + .min_uV = 1000000, + .max_uV = 1250000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .state_mem = { + .uV = 1250000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + .always_on = 1, + .boot_on = 1, + }, +}; + +/* DDR RAM */ +static struct regulator_init_data dcdc6_data = { + .constraints = { + .name = "DCDC6", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .state_mem = { + .uV = 1800000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .state_disk = { + .mode = REGULATOR_MODE_NORMAL, + .enabled = 0, + }, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + }, +}; + +static struct regulator_init_data dcdc3_data = { + .constraints = { + .name = "DCDC3", + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + }, +}; + +static struct regulator_init_data ldo1_data = { + .constraints = { + .name = "LDO1", + .min_uV = 2800000, + .max_uV = 2800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo2_data = { + .constraints = { + .name = "LDO2", + .min_uV = 2500000, + .max_uV = 2500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo3_data = { + .constraints = { + .name = "LDO3", + .min_uV = 1200000, + .max_uV = 1200000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo4_data = { + .constraints = { + .name = "LDO4", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data isinka_data = { + .constraints = { + .name = "ISINKA", + .min_uA = 0, + .max_uA = 225000, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + }, +}; + +static struct regulator_init_data dcdc5_data = { + .constraints = { + .name = "DCDC5", + .min_uV = 0, + .max_uV = 5000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + }, +}; + +static struct regulator_init_data dcdc2_data = { + .constraints = { + .name = "DCDC2", + .min_uV = 0, + .max_uV = 5000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + }, +}; + +static void wm8350_nop_release(struct device *dev) +{ + /* Nothing */ +} + +static int wm8350_check_fb(struct fb_info *info) +{ + return (to_platform_device(info->device)->id == 0); +} + +struct wm8350_bl_platform_data wm8350_bl_data = { + .isink = WM8350_ISINK_A, + .dcdc = WM8350_DCDC_5, + .voltage_ramp = WM8350_DC5_RMP_20V, + .retries = 5, + .max_brightness = 63, + .power = FB_BLANK_UNBLANK, + .brightness = 50, + .check_fb = wm8350_check_fb, +}; + +static struct platform_device mxc_wm8350_devices[] = { + { + .name = "wm8350-bl", + .id = 2, + .dev = { + .release = wm8350_nop_release, + .platform_data = &wm8350_bl_data, + }, + }, +}; + +struct mxc_audio_platform_data imx_3stack_audio_platform_data = { + .ssi_num = 2, + .src_port = 2, + .ext_port = 5, + .regulator1 = "DCDC6", + .regulator2 = "DCDC3", +}; + +static struct platform_device *imx_snd_device; + +static int mx37_wm8350_init(struct wm8350 *wm8350) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mxc_wm8350_devices); i++) { + if (platform_device_register(&mxc_wm8350_devices[i]) < 0) + dev_err(&mxc_wm8350_devices[i].dev, + "Unable to register WM8350 device\n"); + } + + wm8350->pmic.isink_A_dcdc = WM8350_DCDC_5; + + /*Note: Needs to be moved into a regulator function. */ + /* Configuring -- GPIO 7 pin */ + if (wm8350_gpio_config(wm8350, 7, WM8350_GPIO_DIR_OUT, 0, + WM8350_GPIO_ACTIVE_LOW, WM8350_GPIO_PULL_NONE, + WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF) == 0) + wm8350_set_bits(wm8350, WM8350_GPIO_PIN_STATUS, 1 << 7); + else + printk(KERN_ERR "Error in setting Wolfson GPIO pin 7 \n"); + /* enable gpio4:USB_VBUS_EN */ + ret = + wm8350_gpio_config(wm8350, 4, WM8350_GPIO_DIR_IN, + WM8350_GPIO4_MR_IN, WM8350_GPIO_ACTIVE_HIGH, + WM8350_GPIO_PULL_UP, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + if (ret) + printk(KERN_ERR "Error in setting USB VBUS enable pin\n"); + + wm8350_register_regulator(wm8350, WM8350_DCDC_1, &dcdc1_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_2, &dcdc2_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_3, &dcdc3_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_4, &dcdc4_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_5, &dcdc5_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_6, &dcdc6_data); + wm8350_register_regulator(wm8350, WM8350_LDO_1, &ldo1_data); + wm8350_register_regulator(wm8350, WM8350_LDO_2, &ldo2_data); + wm8350_register_regulator(wm8350, WM8350_LDO_3, &ldo3_data); + wm8350_register_regulator(wm8350, WM8350_LDO_4, &ldo4_data); + wm8350_register_regulator(wm8350, WM8350_ISINK_A, &isinka_data); + + /* register sound */ + pr_info("Registering imx37_snd_device"); + imx_snd_device = platform_device_alloc("wm8350-imx-3stack-audio", -1); + if (!imx_snd_device) { + ret = -ENOMEM; + goto err; + } + imx_3stack_audio_platform_data.priv = wm8350; + + imx_snd_device->dev.platform_data = &imx_3stack_audio_platform_data; + ret = platform_device_add(imx_snd_device); + if (ret) + goto snd_err; + + return 0; + +snd_err: + platform_device_put(imx_snd_device); + +err: + kfree(wm8350->reg_cache); + return ret; +} + +struct wm8350_platform_data __initdata mx37_wm8350_pdata = { + .init = mx37_wm8350_init, +}; + +static struct i2c_board_info __initdata wm8350_i2c_device = { + I2C_BOARD_INFO("wm8350", 0x1a), + .platform_data = &mx37_wm8350_pdata, + .irq = IOMUX_TO_IRQ(MX37_PIN_GPIO1_4), +}; + +static __init int mxc_init_i2c(void) +{ + i2c_register_board_info(1, &wm8350_i2c_device, 1); + return 0; +} + +subsys_initcall(mxc_init_i2c); + +static __init int wm8350_regulator_init(void) +{ + int i = 0; + int ret = 0; + struct regulator *regulator; + char *wm8350_global_regulator[] = { + "DCDC1", + "DCDC3", + "DCDC4", + "DCDC6", + "LDO3", + }; + + /* for board v2.0 later, do nothing here */ + if (board_is_rev(BOARD_REV_2)) + return 0; + while ((i < ARRAY_SIZE(wm8350_global_regulator)) && + !IS_ERR_VALUE( + (unsigned long)(regulator = + regulator_get(NULL, + wm8350_global_regulator + [i])))) { + regulator_enable(regulator); + if (wm8350_global_regulator[i] == "DCDC4") + ret = + regulator_set_voltage(regulator, 1250000, 1250000); + else if (wm8350_global_regulator[i] == "DCDC1") + ret = + regulator_set_voltage(regulator, 1050000, 1050000); + i++; + } + return ret; +} + +late_initcall(wm8350_regulator_init); diff --git a/arch/arm/mach-mx37/mx37_pins.h b/arch/arm/mach-mx37/mx37_pins.h new file mode 100644 index 000000000000..10dcbf3c8d8b --- /dev/null +++ b/arch/arm/mach-mx37/mx37_pins.h @@ -0,0 +1,256 @@ +/* + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_MX37_PINS_H__ +#define __ASM_ARCH_MXC_MX37_PINS_H__ + +/*! + * @file arch-mxc/mx37_pins.h + * + * @brief MX37 I/O Pin List + * + * @ingroup GPIO_MX37 + */ + +#ifndef __ASSEMBLY__ + +/*! + * @name IOMUX/PAD Bit field definitions + */ + +/*! @{ */ + +/*! + * In order to identify pins more effectively, each mux-controlled pin's + * enumerated value is constructed in the following way: + * + * ------------------------------------------------------------------- + * 31-29 | 28 - 24 | 23 | 22 - 20 | 19 - 10| 9 - 0 + * ------------------------------------------------------------------- + * IO_P | IO_I | RSVD_I | GPIO_I | PAD_I | MUX_I + * ------------------------------------------------------------------- + * + * Bit 0 to 9 contains MUX_I used to identify the register + * offset (0-based. base is IOMUX_module_base) defined in the Section + * "sw_pad_ctl & sw_mux_ctl details" of the IC Spec. The + * similar field definitions are used for the pad control register. + * For example, the MX37_PIN_ETM_D0 is defined in the enumeration: + * ( (0x28 - MUX_I_START) << MUX_I)|( (0x250 - PAD_I_START) << PAD_I) + * It means the mux control register is at register offset 0x28. The pad control + * register offset is: 0x250 and also occupy the least significant bits + * within the register. + */ + +/*! + * Starting bit position within each entry of \b iomux_pins to represent the + * MUX control register offset + */ +#define MUX_I 0 +/*! + * Starting bit position within each entry of \b iomux_pins to represent the + * PAD control register offset + */ +#define PAD_I 10 +/*! + * Starting bit position within each entry of \b iomux_pins to represent which + * mux mode is for GPIO (0-based) + */ +#define GPIO_I 20 +/*! + * Starting bit position which is reserved. + */ +#define RSVD_I 23 + +#define NON_GPIO_PORT 0x7 +#define PIN_TO_MUX_MASK ((1 << (PAD_I - MUX_I)) -1) +#define PIN_TO_PAD_MASK ((1 << (GPIO_I - PAD_I)) - 1) +#define PIN_TO_ALT_GPIO_MASK ((1 << (RSVD_I - GPIO_I)) - 1) + +#define NON_MUX_I PIN_TO_MUX_MASK +#define MUX_I_START 0x0008 +#define MUX_I_END (PAD_I_START - 4) +#define PAD_I_START 0x230 +#define PAD_I_END (INPUT_CTL_START - 4) +#define INPUT_CTL_START 0x508 +#define INPUT_CTL_END 0x614 + +#define _MXC_BUILD_PIN(gp, gi, ga, mi, pi) \ + (((gp) << MUX_IO_P) | ((gi) << MUX_IO_I) | \ + ((mi - MUX_I_START) << MUX_I) | \ + ((pi - PAD_I_START) << PAD_I) | \ + ((ga) << GPIO_I)) + +#define _MXC_BUILD_GPIO_PIN(gp, gi, ga, mi, pi) \ + _MXC_BUILD_PIN(gp, gi, ga, mi, pi) + +#define _MXC_BUILD_NON_GPIO_PIN(mi, pi) \ + _MXC_BUILD_PIN(NON_GPIO_PORT, 0, 0, mi, pi) + +#define PIN_TO_IOMUX_MUX(pin) ((pin >> MUX_I) & PIN_TO_MUX_MASK) +#define PIN_TO_IOMUX_PAD(pin) ((pin >> PAD_I) & PIN_TO_PAD_MASK) +#define PIN_TO_ALT_GPIO(pin) ((pin >> GPIO_I) & PIN_TO_ALT_GPIO_MASK) +#define PIN_TO_IOMUX_INDEX(pin) (PIN_TO_IOMUX_MUX(pin) >> 2) + +/*! @} End IOMUX/PAD Bit field definitions */ + +/*! + * This enumeration is constructed based on the Section + * "sw_pad_ctl & sw_mux_ctl details" of the MX37 IC Spec. Each enumerated + * value is constructed based on the rules described above. + */ +enum iomux_pins { + MX37_PIN_KEY_ROW0 = _MXC_BUILD_NON_GPIO_PIN(0x8, 0x230), + MX37_PIN_KEY_ROW1 = _MXC_BUILD_NON_GPIO_PIN(0xC, 0x234), + MX37_PIN_KEY_ROW2 = _MXC_BUILD_NON_GPIO_PIN(0x10, 0x238), + MX37_PIN_KEY_ROW3 = _MXC_BUILD_NON_GPIO_PIN(0x14, 0x23C), + MX37_PIN_KEY_ROW4 = _MXC_BUILD_NON_GPIO_PIN(0x18, 0x240), + MX37_PIN_KEY_ROW5 = _MXC_BUILD_NON_GPIO_PIN(0x1C, 0x244), + MX37_PIN_KEY_ROW6 = _MXC_BUILD_NON_GPIO_PIN(0x20, 0x248), + MX37_PIN_KEY_ROW7 = _MXC_BUILD_NON_GPIO_PIN(0x24, 0x24C), + MX37_PIN_ETM_D0 = _MXC_BUILD_NON_GPIO_PIN(0x28, 0x250), + MX37_PIN_ETM_D1 = _MXC_BUILD_NON_GPIO_PIN(0x2C, 0x254), + MX37_PIN_ETM_D2 = _MXC_BUILD_NON_GPIO_PIN(0x30, 0x258), + MX37_PIN_ETM_D3 = _MXC_BUILD_NON_GPIO_PIN(0x34, 0x25C), + MX37_PIN_ETM_D4 = _MXC_BUILD_NON_GPIO_PIN(0x38, 0x260), + MX37_PIN_ETM_D5 = _MXC_BUILD_NON_GPIO_PIN(0x3C, 0x264), + MX37_PIN_ETM_D6 = _MXC_BUILD_NON_GPIO_PIN(0x40, 0x268), + MX37_PIN_ETM_D7 = _MXC_BUILD_NON_GPIO_PIN(0x44, 0x26C), + MX37_PIN_EIM_EB0 = _MXC_BUILD_GPIO_PIN(0, 15, 3, 0x48, 0x2A8), + MX37_PIN_EIM_EB1 = _MXC_BUILD_GPIO_PIN(0, 14, 3, 0x4C, 0x2AC), + MX37_PIN_EIM_OE = _MXC_BUILD_GPIO_PIN(0, 13, 3, 0x50, 0x2B0), + MX37_PIN_EIM_CS0 = _MXC_BUILD_GPIO_PIN(1, 0, 1, 0x54, 0x2B4), + MX37_PIN_EIM_CS1 = _MXC_BUILD_GPIO_PIN(1, 1, 1, 0x58, 0x2B8), + MX37_PIN_EIM_ECB = _MXC_BUILD_GPIO_PIN(0, 12, 3, 0x5C, 0x2BC), + MX37_PIN_EIM_LBA = _MXC_BUILD_GPIO_PIN(0, 11, 3, 0x60, 0x2C0), + MX37_PIN_EIM_BCLK = _MXC_BUILD_GPIO_PIN(0, 10, 3, 0x64, 0x2C4), + MX37_PIN_EIM_RW = _MXC_BUILD_GPIO_PIN(0, 9, 3, 0x68, 0x2C8), + MX37_PIN_NANDF_WE_B = _MXC_BUILD_GPIO_PIN(1, 2, 4, 0x6C, 0x2CC), + MX37_PIN_NANDF_RE_B = _MXC_BUILD_GPIO_PIN(1, 3, 4, 0x70, 0x2D0), + MX37_PIN_NANDF_ALE = _MXC_BUILD_GPIO_PIN(1, 4, 4, 0x74, 0x2D4), + MX37_PIN_NANDF_CLE = _MXC_BUILD_GPIO_PIN(1, 5, 4, 0x78, 0x2D8), + MX37_PIN_NANDF_WP_B = _MXC_BUILD_GPIO_PIN(1, 6, 4, 0x7C, 0x2DC), + MX37_PIN_NANDF_RB = _MXC_BUILD_GPIO_PIN(1, 7, 4, 0x80, 0x2E0), + MX37_PIN_NANDF_CS0 = _MXC_BUILD_GPIO_PIN(1, 8, 4, 0x84, 0x2E4), + MX37_PIN_NANDF_CS1 = _MXC_BUILD_GPIO_PIN(1, 9, 4, 0x88, 0x2E8), + MX37_PIN_NANDF_CS2 = _MXC_BUILD_GPIO_PIN(1, 10, 4, 0x8C, 0x2EC), + MX37_PIN_NANDF_CS3 = _MXC_BUILD_GPIO_PIN(1, 11, 4, 0x90, 0x2F0), + MX37_PIN_EIM_D15 = _MXC_BUILD_NON_GPIO_PIN(0x94, 0x2F4), + MX37_PIN_EIM_D14 = _MXC_BUILD_NON_GPIO_PIN(0x98, 0x2F8), + MX37_PIN_EIM_D13 = _MXC_BUILD_NON_GPIO_PIN(0x9C, 0x2FC), + MX37_PIN_EIM_D12 = _MXC_BUILD_NON_GPIO_PIN(0xA0, 0x300), + MX37_PIN_EIM_D11 = _MXC_BUILD_NON_GPIO_PIN(0xA4, 0x304), + MX37_PIN_EIM_D10 = _MXC_BUILD_NON_GPIO_PIN(0xA8, 0x308), + MX37_PIN_EIM_D9 = _MXC_BUILD_NON_GPIO_PIN(0xAC, 0x30C), + MX37_PIN_EIM_D8 = _MXC_BUILD_GPIO_PIN(0, 8, 3, 0xB0, 0x310), + MX37_PIN_EIM_D7 = _MXC_BUILD_GPIO_PIN(2, 27, 3, 0xB4, 0x314), + MX37_PIN_EIM_D6 = _MXC_BUILD_GPIO_PIN(2, 26, 3, 0xB8, 0x318), + MX37_PIN_EIM_D5 = _MXC_BUILD_GPIO_PIN(2, 25, 3, 0xBC, 0x31C), + MX37_PIN_EIM_D4 = _MXC_BUILD_GPIO_PIN(2, 24, 3, 0xC0, 0x320), + MX37_PIN_EIM_D3 = _MXC_BUILD_GPIO_PIN(2, 23, 3, 0xC4, 0x324), + MX37_PIN_EIM_D2 = _MXC_BUILD_GPIO_PIN(2, 22, 3, 0xC8, 0x328), + MX37_PIN_EIM_D1 = _MXC_BUILD_GPIO_PIN(2, 21, 3, 0xCC, 0x32C), + MX37_PIN_EIM_D0 = _MXC_BUILD_GPIO_PIN(2, 20, 3, 0xD0, 0x330), + MX37_PIN_SD1_CMD = _MXC_BUILD_GPIO_PIN(0, 16, 3, 0xD4, 0x334), + MX37_PIN_SD1_CLK = _MXC_BUILD_GPIO_PIN(0, 17, 3, 0xD8, 0x338), + MX37_PIN_SD1_DATA0 = _MXC_BUILD_GPIO_PIN(0, 18, 3, 0xDC, 0x33C), + MX37_PIN_SD1_DATA1 = _MXC_BUILD_GPIO_PIN(0, 19, 3, 0xE0, 0x340), + MX37_PIN_SD1_DATA2 = _MXC_BUILD_GPIO_PIN(0, 20, 3, 0xE4, 0x344), + MX37_PIN_SD1_DATA3 = _MXC_BUILD_GPIO_PIN(0, 21, 3, 0xE8, 0x348), + MX37_PIN_SD2_CMD = _MXC_BUILD_GPIO_PIN(0, 22, 3, 0xEC, 0x34C), + MX37_PIN_SD2_CLK = _MXC_BUILD_GPIO_PIN(0, 23, 3, 0xF0, 0x350), + MX37_PIN_SD2_DATA0 = _MXC_BUILD_GPIO_PIN(0, 24, 3, 0xF4, 0x354), + MX37_PIN_SD2_DATA1 = _MXC_BUILD_GPIO_PIN(0, 25, 3, 0xF8, 0x358), + MX37_PIN_SD2_DATA2 = _MXC_BUILD_GPIO_PIN(0, 26, 3, 0xFC, 0x35C), + MX37_PIN_SD2_DATA3 = _MXC_BUILD_GPIO_PIN(0, 27, 3, 0x100, 0x360), + MX37_PIN_I2C1_CLK = _MXC_BUILD_GPIO_PIN(1, 12, 4, 0x104, 0x364), + MX37_PIN_I2C1_DAT = _MXC_BUILD_GPIO_PIN(1, 13, 4, 0x108, 0x368), + MX37_PIN_AUD3_BB_TXD = _MXC_BUILD_GPIO_PIN(1, 14, 4, 0x10C, 0x36C), + MX37_PIN_AUD3_BB_RXD = _MXC_BUILD_GPIO_PIN(1, 15, 4, 0x110, 0x370), + MX37_PIN_AUD3_BB_CK = _MXC_BUILD_GPIO_PIN(1, 16, 4, 0x114, 0x374), + MX37_PIN_AUD3_BB_FS = _MXC_BUILD_GPIO_PIN(1, 17, 4, 0x118, 0x378), + MX37_PIN_AUD5_RXFS = _MXC_BUILD_GPIO_PIN(1, 18, 4, 0x11C, 0x37C), + MX37_PIN_AUD5_RXC = _MXC_BUILD_GPIO_PIN(1, 19, 4, 0x120, 0x380), + MX37_PIN_AUD5_WB_TXD = _MXC_BUILD_GPIO_PIN(1, 20, 4, 0x124, 0x384), + MX37_PIN_AUD5_WB_RXD = _MXC_BUILD_GPIO_PIN(1, 21, 4, 0x128, 0x388), + MX37_PIN_AUD5_WB_CK = _MXC_BUILD_GPIO_PIN(1, 22, 4, 0x12C, 0x38C), + MX37_PIN_AUD5_WB_FS = _MXC_BUILD_GPIO_PIN(1, 23, 4, 0x130, 0x390), + MX37_PIN_CSPI1_MOSI = _MXC_BUILD_GPIO_PIN(2, 0, 4, 0x134, 0x394), + MX37_PIN_CSPI1_MISO = _MXC_BUILD_GPIO_PIN(2, 1, 4, 0x138, 0x398), + MX37_PIN_CSPI1_SS0 = _MXC_BUILD_GPIO_PIN(2, 2, 4, 0x13C, 0x39C), + MX37_PIN_CSPI1_SS1 = _MXC_BUILD_GPIO_PIN(2, 3, 4, 0x140, 0x3A0), + MX37_PIN_CSPI1_SCLK = _MXC_BUILD_GPIO_PIN(2, 4, 4, 0x144, 0x3A4), + MX37_PIN_CSPI2_MOSI = _MXC_BUILD_GPIO_PIN(2, 5, 4, 0x148, 0x3A8), + MX37_PIN_CSPI2_MISO = _MXC_BUILD_GPIO_PIN(2, 6, 4, 0x14C, 0x3AC), + MX37_PIN_CSPI2_SS0 = _MXC_BUILD_GPIO_PIN(2, 7, 4, 0x150, 0x3B0), + MX37_PIN_CSPI2_SS1 = _MXC_BUILD_GPIO_PIN(2, 8, 4, 0x154, 0x3B4), + MX37_PIN_CSPI2_SCLK = _MXC_BUILD_GPIO_PIN(2, 9, 4, 0x158, 0x3B8), + MX37_PIN_UART1_RXD = _MXC_BUILD_GPIO_PIN(1, 24, 4, 0x15C, 0x3BC), + MX37_PIN_UART1_TXD = _MXC_BUILD_GPIO_PIN(1, 25, 4, 0x160, 0x3C0), + MX37_PIN_UART1_RTS = _MXC_BUILD_GPIO_PIN(1, 26, 4, 0x164, 0x3C4), + MX37_PIN_UART1_CTS = _MXC_BUILD_GPIO_PIN(1, 27, 4, 0x168, 0x3C8), + MX37_PIN_UART1_DTR = _MXC_BUILD_GPIO_PIN(1, 28, 4, 0x16C, 0x3CC), + MX37_PIN_UART1_DSR = _MXC_BUILD_GPIO_PIN(1, 29, 4, 0x170, 0x3D0), + MX37_PIN_UART1_RI = _MXC_BUILD_GPIO_PIN(1, 30, 4, 0x174, 0x3D4), + MX37_PIN_UART1_DCD = _MXC_BUILD_GPIO_PIN(1, 31, 4, 0x178, 0x3D8), + MX37_PIN_OWIRE_LINE = _MXC_BUILD_GPIO_PIN(0, 31, 4, 0x17C, 0x3DC), + MX37_PIN_JTAG_DE_B = _MXC_BUILD_NON_GPIO_PIN(0x180, 0x3E0), + MX37_PIN_DI1_PIN11 = _MXC_BUILD_GPIO_PIN(2, 10, 4, 0x184, 0x3E4), + MX37_PIN_DI1_PIN12 = _MXC_BUILD_GPIO_PIN(2, 11, 4, 0x188, 0x3E8), + MX37_PIN_DI1_PIN13 = _MXC_BUILD_GPIO_PIN(2, 12, 4, 0x18C, 0x3EC), + MX37_PIN_DI1_D0_CS = _MXC_BUILD_GPIO_PIN(2, 13, 4, 0x190, 0x3F0), + MX37_PIN_DI1_PIN15 = _MXC_BUILD_GPIO_PIN(0, 30, 4, 0x194, 0), + MX37_PIN_DISP1_DAT0 = _MXC_BUILD_NON_GPIO_PIN(0x198, 0x3F4), + MX37_PIN_DISP1_DAT1 = _MXC_BUILD_NON_GPIO_PIN(0x19C, 0x3F8), + MX37_PIN_DISP1_DAT2 = _MXC_BUILD_NON_GPIO_PIN(0x1A0, 0x3FC), + MX37_PIN_DISP1_DAT3 = _MXC_BUILD_NON_GPIO_PIN(0x1A4, 0x400), + MX37_PIN_DISP1_DAT4 = _MXC_BUILD_NON_GPIO_PIN(0x1A8, 0x404), + MX37_PIN_DISP1_DAT5 = _MXC_BUILD_NON_GPIO_PIN(0x1AC, 0x408), + MX37_PIN_DISP1_DAT6 = _MXC_BUILD_NON_GPIO_PIN(0x1B0, 0x40C), + MX37_PIN_DISP1_DAT7 = _MXC_BUILD_NON_GPIO_PIN(0x1B4, 0x410), + MX37_PIN_DISP1_DAT8 = _MXC_BUILD_NON_GPIO_PIN(0x1B8, 0x414), + MX37_PIN_DISP1_DAT9 = _MXC_BUILD_NON_GPIO_PIN(0x1BC, 0x418), + MX37_PIN_DISP1_DAT10 = _MXC_BUILD_NON_GPIO_PIN(0x1C0, 0x41C), + MX37_PIN_DISP1_DAT11 = _MXC_BUILD_NON_GPIO_PIN(0x1C4, 0x420), + MX37_PIN_DISP1_DAT12 = _MXC_BUILD_NON_GPIO_PIN(0x1C8, 0x424), + MX37_PIN_DISP1_DAT13 = _MXC_BUILD_NON_GPIO_PIN(0x1CC, 0x428), + MX37_PIN_DISP1_DAT14 = _MXC_BUILD_NON_GPIO_PIN(0x1D0, 0x42C), + MX37_PIN_DISP1_DAT15 = _MXC_BUILD_NON_GPIO_PIN(0x1D4, 0x430), + MX37_PIN_DISP1_DAT16 = _MXC_BUILD_GPIO_PIN(0, 28, 4, 0x1D8, 0x434), + MX37_PIN_DISP1_DAT17 = _MXC_BUILD_GPIO_PIN(0, 29, 4, 0x1DC, 0x438), + MX37_PIN_DISP1_DAT18 = _MXC_BUILD_GPIO_PIN(2, 14, 4, 0x1E0, 0x43C), + MX37_PIN_DISP1_DAT19 = _MXC_BUILD_GPIO_PIN(2, 15, 4, 0x1E4, 0x440), + MX37_PIN_DISP1_DAT20 = _MXC_BUILD_GPIO_PIN(2, 16, 4, 0x1E8, 0x444), + MX37_PIN_DISP1_DAT21 = _MXC_BUILD_GPIO_PIN(2, 17, 4, 0x1EC, 0x448), + MX37_PIN_DISP1_DAT22 = _MXC_BUILD_GPIO_PIN(2, 18, 4, 0x1F0, 0x44C), + MX37_PIN_DISP1_DAT23 = _MXC_BUILD_GPIO_PIN(2, 18, 4, 0x1F4, 0x450), + MX37_PIN_PAD_DI1_PIN3 = _MXC_BUILD_GPIO_PIN(2, 29, 4, 0x1F8, 0), + MX37_PIN_DISP_CLK = _MXC_BUILD_GPIO_PIN(2, 30, 4, 0x1FC, 0), + MX37_PIN_DI1_PIN2 = _MXC_BUILD_GPIO_PIN(2, 31, 4, 0x200, 0), + MX37_PIN_BOOT_MODE1 = _MXC_BUILD_NON_GPIO_PIN(0x204, 0x454), + MX37_PIN_BOOT_MODE0 = _MXC_BUILD_NON_GPIO_PIN(0x208, 0x458), + MX37_PIN_WDOG_RST = _MXC_BUILD_GPIO_PIN(2, 28, 1, 0x20C, 0x464), + MX37_PIN_GPIO1_0 = _MXC_BUILD_GPIO_PIN(0, 0, 0, 0x210, 0x468), + MX37_PIN_GPIO1_1 = _MXC_BUILD_GPIO_PIN(0, 1, 0, 0x214, 0x46C), + MX37_PIN_GPIO1_2 = _MXC_BUILD_GPIO_PIN(0, 2, 1, 0x218, 0x470), + MX37_PIN_GPIO1_3 = _MXC_BUILD_GPIO_PIN(0, 3, 0, 0x21C, 0x474), + MX37_PIN_GPIO1_4 = _MXC_BUILD_GPIO_PIN(0, 4, 0, 0x220, 0x478), + MX37_PIN_GPIO1_5 = _MXC_BUILD_GPIO_PIN(0, 5, 0, 0x224, 0x47C), + MX37_PIN_GPIO1_6 = _MXC_BUILD_GPIO_PIN(0, 6, 0, 0x228, 0x480), + MX37_PIN_GPIO1_7 = _MXC_BUILD_GPIO_PIN(0, 7, 0, 0x22C, 0x484), + MX37_PIN_GRP_H10 = _MXC_BUILD_NON_GPIO_PIN(0x230, 0x490), + MX37_PIN_GRP_H9 = _MXC_BUILD_NON_GPIO_PIN(0x230, 0x494), + MX37_PIN_GRP_H3 = _MXC_BUILD_NON_GPIO_PIN(0x230, 0x4D0), + MX37_PIN_GRP_H5 = _MXC_BUILD_NON_GPIO_PIN(0x230, 0x4EC), +}; + +#endif /* */ +#endif /* */ diff --git a/arch/arm/mach-mx37/pm.c b/arch/arm/mach-mx37/pm.c new file mode 100644 index 000000000000..8ea478a4447c --- /dev/null +++ b/arch/arm/mach-mx37/pm.c @@ -0,0 +1,74 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <mach/hardware.h> + +static int mx37_suspend_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + mxc_cpu_lp_set(STOP_POWER_OFF); + break; + case PM_SUSPEND_STANDBY: + mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + break; + default: + return -EINVAL; + } + + if (tzic_enable_wake(0) != 0) + return -EAGAIN; + + cpu_do_idle(); + + return 0; +} + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mx37_suspend_prepare(void) +{ + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void mx37_suspend_finish(void) +{ +} + +static int mx37_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +struct platform_suspend_ops mx37_suspend_ops = { + .valid = mx37_pm_valid, + .prepare = mx37_suspend_prepare, + .enter = mx37_suspend_enter, + .finish = mx37_suspend_finish, +}; + +static int __init mx37_pm_init(void) +{ + pr_info("Static Power Management for Freescale i.MX37\n"); + suspend_set_ops(&mx37_suspend_ops); + + return 0; +} + +late_initcall(mx37_pm_init); diff --git a/arch/arm/mach-mx37/sdma_script_code.h b/arch/arm/mach-mx37/sdma_script_code.h new file mode 100644 index 000000000000..f3b7d509ffb5 --- /dev/null +++ b/arch/arm/mach-mx37/sdma_script_code.h @@ -0,0 +1,203 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. */ + +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/*! + * @file sdma_script_code.h + * @brief This file contains functions of SDMA scripts code initialization + * + * The file was generated automatically. Based on sdma scripts library. + * + * @ingroup SDMA + */ +/******************************************************************************* + + SDMA RELEASE LABEL: "SS15_MARLEY" + +*******************************************************************************/ + +#ifndef __SDMA_SCRIPT_CODE_H__ +#define __SDMA_SCRIPT_CODE_H__ + +/*! +* SDMA ROM scripts start addresses and sizes +*/ + +#define start_ADDR 0 +#define start_SIZE 20 + +#define core_ADDR 80 +#define core_SIZE 232 + +#define common_ADDR 312 +#define common_SIZE 330 + +#define ap_2_ap_ADDR 642 +#define ap_2_ap_SIZE 41 + +#define app_2_mcu_ADDR 683 +#define app_2_mcu_SIZE 64 + +#define mcu_2_app_ADDR 747 +#define mcu_2_app_SIZE 70 + +#define uart_2_mcu_ADDR 817 +#define uart_2_mcu_SIZE 75 + +#define shp_2_mcu_ADDR 892 +#define shp_2_mcu_SIZE 69 + +#define mcu_2_shp_ADDR 961 +#define mcu_2_shp_SIZE 72 + +#define uartsh_2_mcu_ADDR 1033 +#define uartsh_2_mcu_SIZE 69 + +#define mcu_2_ata_ADDR 1102 +#define mcu_2_ata_SIZE 81 + +#define ata_2_mcu_ADDR 1183 +#define ata_2_mcu_SIZE 96 + +#define burstDMA__2__burstDMA_routine_ADDR 1279 +#define burstDMA__2__burstDMA_routine_SIZE 227 + +#define test_ADDR 1506 +#define test_SIZE 63 + +#define signature_ADDR 1023 +#define signature_SIZE 1 + +/*! +* SDMA RAM scripts start addresses and sizes +*/ + +#define dptc_dvfs_ADDR 6144 +#define dptc_dvfs_SIZE 270 + +#define ext_mem__ipu_ram_ADDR 6414 +#define ext_mem__ipu_ram_SIZE 123 + +#define mcu_2_mshc_ADDR 6537 +#define mcu_2_mshc_SIZE 54 + +#define mcu_2_spdif_marley_ADDR 6591 +#define mcu_2_spdif_marley_SIZE 161 + +#define mshc_2_mcu_ADDR 6752 +#define mshc_2_mcu_SIZE 54 + +/*! +* SDMA RAM image start address and size +*/ + +#define RAM_CODE_START_ADDR 6144 +#define RAM_CODE_SIZE 662 + +/*! +* Buffer that holds the SDMA RAM image +*/ +__attribute__ ((__aligned__(4))) +#ifndef CONFIG_XIP_KERNEL +const +#endif +static const short sdma_code[] = { + 0xc13c, 0x7d70, 0x0800, 0x0970, 0x0111, 0x5111, 0x5ac1, 0x5bc9, + 0x028e, 0xc14e, 0x068a, 0x7c66, 0x5dd9, 0x5ce1, 0x0bff, 0x0311, + 0x1bff, 0x03bc, 0x5bd1, 0x1a5c, 0x6ac3, 0x63c8, 0x0363, 0x7c05, + 0x036f, 0x7d27, 0x0374, 0x7c76, 0x9874, 0xd907, 0x3c06, 0x4c00, + 0x7df7, 0x028f, 0x1a04, 0x6a20, 0x620b, 0x6f20, 0x301f, 0x00aa, + 0x0462, 0x7c04, 0x4a00, 0x7d0b, 0x2001, 0x9837, 0x048a, 0x620b, + 0x2201, 0x1c01, 0x1801, 0x02dc, 0x7d02, 0x301f, 0x00aa, 0x048f, + 0x1c04, 0x6c04, 0x0488, 0x3c1f, 0x6c2b, 0x0045, 0x028e, 0x1a5c, + 0x9818, 0x058f, 0x1d0c, 0x6d20, 0x650b, 0x007d, 0x7c01, 0x1d08, + 0x007c, 0x7c01, 0x1d04, 0x6d20, 0x650b, 0x0488, 0x3c1f, 0x0417, + 0x0417, 0x0417, 0x0417, 0x059c, 0x6d20, 0x028e, 0x1a34, 0x6ad7, + 0x0488, 0x0804, 0x7802, 0x650b, 0x6dc8, 0x008c, 0x1a28, 0x6ad7, + 0x63c8, 0x034c, 0x6bc8, 0x54d1, 0x4c00, 0x7d06, 0x0065, 0x7c02, + 0x0101, 0x0025, 0x0400, 0x9814, 0x52c1, 0x53c9, 0x54e1, 0x0453, + 0xc159, 0x7d95, 0x0200, 0x9800, 0x55d9, 0x6d04, 0x54d1, 0x058a, + 0x2508, 0x6dc7, 0x0373, 0x7c03, 0x65c8, 0x6d0b, 0x2408, 0x0372, + 0x7c04, 0x65c8, 0x6d0b, 0x2408, 0x9889, 0x6cce, 0x65c8, 0x6d0a, + 0x2404, 0x6d28, 0x6504, 0x5dd9, 0x5cd1, 0x6ad7, 0x6ae3, 0x63c8, + 0x0334, 0x6bc8, 0x0370, 0x7cad, 0x0c60, 0x0411, 0x04bb, 0x4c00, + 0x7da8, 0x0410, 0x1c30, 0x0410, 0x04bb, 0x046d, 0x7d0a, 0x047d, + 0x7c03, 0x047c, 0x7c01, 0x9841, 0x003b, 0x003a, 0x0039, 0x0058, + 0x98b8, 0x047d, 0x7d03, 0x047c, 0x7d01, 0x9841, 0x005b, 0xd8fc, + 0x1d18, 0x6d20, 0x650b, 0x0510, 0x003a, 0x0039, 0x0038, 0x00ad, + 0xd907, 0x0c30, 0x0410, 0x04bb, 0x003c, 0x003d, 0x00ac, 0xd8fc, + 0x007b, 0x7c04, 0x003d, 0x003c, 0x1d0c, 0x98d9, 0x048f, 0x1c14, + 0x6c20, 0x640b, 0x4401, 0x7d04, 0x005d, 0x005c, 0x1d0c, 0x98d9, + 0x0310, 0x3b30, 0x4b30, 0x7d01, 0x1b10, 0x0310, 0x003d, 0x003c, + 0x00ab, 0x6ad7, 0x63c8, 0x6d20, 0x650b, 0x0560, 0x7d03, 0x005e, + 0xd8f0, 0x9841, 0x003e, 0x0c80, 0x0410, 0x0394, 0xd8f0, 0x640b, + 0x037f, 0x7d02, 0x1a14, 0x98ed, 0x1a0c, 0x6ad7, 0x6cc8, 0x9841, + 0x0c7f, 0x0410, 0x03b4, 0x04b8, 0x03ac, 0x640b, 0x6bc8, 0x028e, + 0x1a04, 0x6ad7, 0x6cc8, 0x0006, 0x058f, 0x1d08, 0x6d20, 0x650b, + 0x007d, 0x7c01, 0x1d38, 0x007c, 0x7c01, 0x1d1c, 0x0006, 0x048b, + 0x042c, 0x0454, 0x042b, 0x6ad7, 0x6cc8, 0x0006, 0x0e70, 0x0611, + 0x5616, 0xc13c, 0x7d2a, 0x5ade, 0x008e, 0xc14e, 0x7c26, 0x5be0, + 0x5ef0, 0x5ce8, 0x0688, 0x08ff, 0x0011, 0x28ff, 0x00bc, 0x53f6, + 0x05df, 0x7d0b, 0x6dc5, 0x03df, 0x7d03, 0x6bd5, 0xd95d, 0x9939, + 0x6b05, 0xc55f, 0x7e27, 0x7f29, 0x9939, 0x6d01, 0x03df, 0x7d05, + 0x6bd5, 0xc589, 0x7e18, 0x7f1a, 0x9939, 0x6b05, 0xc4ff, 0x7e07, + 0x7f06, 0x52de, 0x53e6, 0xc159, 0x7dd7, 0x0200, 0x9911, 0x0007, + 0x6004, 0x680c, 0x53f6, 0x028e, 0x00a3, 0xc256, 0x048b, 0x0498, + 0x0454, 0x068a, 0x9939, 0x0207, 0x680c, 0x6ddf, 0x0107, 0x68ff, + 0x60d0, 0x9942, 0x0207, 0x68ff, 0x6d28, 0x0107, 0x6004, 0x680c, + 0x9942, 0x0007, 0x68ff, 0x60d0, 0x9942, 0x0288, 0x03a5, 0x3b03, + 0x3d03, 0x4d00, 0x7d0a, 0x0804, 0x00a5, 0x00da, 0x7d1a, 0x02a0, + 0x7b01, 0x65d8, 0x7eee, 0x65ff, 0x7eec, 0x0804, 0x02d0, 0x7d11, + 0x4b00, 0x7c0f, 0x008a, 0x3003, 0x6dcf, 0x6bdf, 0x0015, 0x0015, + 0x7b02, 0x65d8, 0x0000, 0x7edd, 0x63ff, 0x7edb, 0x3a03, 0x6dcd, + 0x6bdd, 0x008a, 0x7b02, 0x65d8, 0x0000, 0x7ed3, 0x65ff, 0x7ed1, + 0x0006, 0xc1d9, 0x0b70, 0x0311, 0x5313, 0x58d3, 0x008b, 0x5efb, + 0xc13c, 0x7d2b, 0x5ac0, 0x5bc8, 0xc14e, 0x7c27, 0x6d01, 0x0388, + 0x0dff, 0x0511, 0x1dff, 0x05bc, 0x4d00, 0x7d1a, 0x0e70, 0x0611, + 0x522e, 0x02b9, 0x4a00, 0x7c07, 0x52fe, 0x50d3, 0x02b8, 0x4a00, + 0x7c02, 0x0400, 0x999e, 0x56fb, 0x620b, 0x7e06, 0x5a06, 0x7f06, + 0x0000, 0x2504, 0x7d05, 0x999e, 0x0007, 0x680c, 0x0007, 0x0454, + 0x008b, 0x52c0, 0x53c8, 0xc159, 0x7dd6, 0x0200, 0x9990, 0xc1d9, + 0xc1e3, 0x0800, 0x005f, 0x00ac, 0x58e3, 0x0478, 0x7d5c, 0x0479, + 0x7d01, 0x0515, 0x0515, 0xda38, 0xda57, 0x0479, 0x7d26, 0x54e3, + 0x047f, 0x7d12, 0x50eb, 0x56fb, 0x0015, 0x52db, 0x7806, 0x5402, + 0x5c06, 0x1a01, 0x5402, 0x5c26, 0x1a01, 0x54e3, 0x043f, 0x5ce3, + 0x4d00, 0x7d4e, 0x0479, 0x7d14, 0x047f, 0x7d01, 0xda57, 0x52f3, + 0x6a21, 0x56db, 0x7803, 0x620b, 0x5a06, 0x1e01, 0x7f34, 0x7e33, + 0x6200, 0x5af3, 0x047f, 0x7dde, 0x9a20, 0x54e3, 0x047f, 0x7cda, + 0x54e3, 0x047f, 0x7d01, 0xda57, 0x54eb, 0x0fff, 0x0711, 0x1fff, + 0x56db, 0x52f3, 0x6a21, 0x630b, 0x028b, 0x03bf, 0xda32, 0x5b06, + 0x2401, 0x4c00, 0x7d0b, 0x1e01, 0x038a, 0x03b7, 0x0312, 0x0312, + 0xda32, 0x5b06, 0x1e01, 0x2401, 0x4c00, 0x7ced, 0x0b70, 0x0311, + 0x5313, 0x7f09, 0x7e08, 0x6200, 0x5af3, 0x54e3, 0x047f, 0x7db2, + 0x57db, 0xc1fa, 0x99cd, 0x0007, 0x680c, 0x54e3, 0x0478, 0x7c02, + 0x0800, 0x9a2e, 0x0479, 0x7d01, 0x0517, 0x0517, 0x5deb, 0xc213, + 0xc20a, 0x99c1, 0x0808, 0x7801, 0x0317, 0x0006, 0x020a, 0x0006, + 0x070a, 0xda36, 0x1a05, 0x0215, 0x5adb, 0x0708, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x080c, + 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x4800, 0x7dd2, 0x58eb, 0x0006, + 0xc1d9, 0x0b70, 0x0311, 0x5313, 0x58d3, 0x008b, 0x5efb, 0xc13c, + 0x7d2b, 0x5ac0, 0x5bc8, 0xc14e, 0x7c27, 0x0388, 0x6d05, 0x0dff, + 0x0511, 0x1dff, 0x05bc, 0x4d00, 0x7d1a, 0x0e70, 0x0611, 0x522e, + 0x02b9, 0x4a00, 0x7c07, 0x52fe, 0x50d3, 0x02b8, 0x4a00, 0x7c02, + 0x0400, 0x9a75, 0x56fb, 0x5206, 0x7e08, 0x6a0b, 0x6a28, 0x7f04, + 0x0000, 0x2504, 0x7d04, 0x9a75, 0x680c, 0x0007, 0x0454, 0x008b, + 0x52c0, 0x53c8, 0xc159, 0x7dd6, 0x0200, 0x9a67 +}; +#endif diff --git a/arch/arm/mach-mx37/serial.c b/arch/arm/mach-mx37/serial.c new file mode 100644 index 000000000000..aaa5171eb177 --- /dev/null +++ b/arch/arm/mach-mx37/serial.c @@ -0,0 +1,169 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/*! + * @file mach-mx37/serial.c + * + * @brief This file contains the UART initiliazation. + * + * @ingroup MSL_MX37 + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <mach/hardware.h> +#include <mach/mxc_uart.h> +#include <mach/spba.h> +#include "serial.h" +#include "board-mx37_3stack.h" + +#if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE) + +/*! + * This is an array where each element holds information about a UART port, + * like base address of the UART, interrupt numbers etc. This structure is + * passed to the serial_core.c file. Based on which UART is used, the core file + * passes back the appropriate port structure as an argument to the control + * functions. + */ +static uart_mxc_port mxc_ports[] = { + [0] = { + .port = { + .membase = (void *)IO_ADDRESS(UART1_BASE_ADDR), + .mapbase = UART1_BASE_ADDR, + .iotype = SERIAL_IO_MEM, + .irq = UART1_INT1, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .ints_muxed = UART1_MUX_INTS, + .irqs = {UART1_INT2, UART1_INT3}, + .mode = UART1_MODE, + .ir_mode = UART1_IR, + .enabled = UART1_ENABLED, + .hardware_flow = UART1_HW_FLOW, + .cts_threshold = UART1_UCR4_CTSTL, + .dma_enabled = UART1_DMA_ENABLE, + .dma_rxbuf_size = UART1_DMA_RXBUFSIZE, + .rx_threshold = UART1_UFCR_RXTL, + .tx_threshold = UART1_UFCR_TXTL, + .shared = UART1_SHARED_PERI, + .dma_tx_id = MXC_DMA_UART1_TX, + .dma_rx_id = MXC_DMA_UART1_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [1] = { + .port = { + .membase = (void *)IO_ADDRESS(UART2_BASE_ADDR), + .mapbase = UART2_BASE_ADDR, + .iotype = SERIAL_IO_MEM, + .irq = UART2_INT1, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .ints_muxed = UART2_MUX_INTS, + .irqs = {UART2_INT2, UART2_INT3}, + .mode = UART2_MODE, + .ir_mode = UART2_IR, + .enabled = UART2_ENABLED, + .hardware_flow = UART2_HW_FLOW, + .cts_threshold = UART2_UCR4_CTSTL, + .dma_enabled = UART2_DMA_ENABLE, + .dma_rxbuf_size = UART2_DMA_RXBUFSIZE, + .rx_threshold = UART2_UFCR_RXTL, + .tx_threshold = UART2_UFCR_TXTL, + .shared = UART2_SHARED_PERI, + .dma_tx_id = MXC_DMA_UART2_TX, + .dma_rx_id = MXC_DMA_UART2_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [2] = { + .port = { + .membase = (void *)IO_ADDRESS(UART3_BASE_ADDR), + .mapbase = UART3_BASE_ADDR, + .iotype = SERIAL_IO_MEM, + .irq = UART3_INT1, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .ints_muxed = UART3_MUX_INTS, + .irqs = {UART3_INT2, UART3_INT3}, + .mode = UART3_MODE, + .ir_mode = UART3_IR, + .enabled = UART3_ENABLED, + .hardware_flow = UART3_HW_FLOW, + .cts_threshold = UART3_UCR4_CTSTL, + .dma_enabled = UART3_DMA_ENABLE, + .dma_rxbuf_size = UART3_DMA_RXBUFSIZE, + .rx_threshold = UART3_UFCR_RXTL, + .tx_threshold = UART3_UFCR_TXTL, + .shared = UART3_SHARED_PERI, + .dma_tx_id = MXC_DMA_UART3_TX, + .dma_rx_id = MXC_DMA_UART3_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, +}; + +static struct platform_device mxc_uart_device1 = { + .name = "mxcintuart", + .id = 0, + .dev = { + .platform_data = &mxc_ports[0], + }, +}; + +static struct platform_device mxc_uart_device2 = { + .name = "mxcintuart", + .id = 1, + .dev = { + .platform_data = &mxc_ports[1], + }, +}; + +static struct platform_device mxc_uart_device3 = { + .name = "mxcintuart", + .id = 2, + .dev = { + .platform_data = &mxc_ports[2], + }, +}; + +static int __init mxc_init_uart(void) +{ + /* Register all the MXC UART platform device structures */ + platform_device_register(&mxc_uart_device1); + platform_device_register(&mxc_uart_device2); + + /* Grab ownership of shared UARTs 3 and 4, only when enabled */ +#if UART3_ENABLED == 1 +#if UART3_DMA_ENABLE == 1 + spba_take_ownership(UART3_SHARED_PERI, (SPBA_MASTER_A | SPBA_MASTER_C)); +#else + spba_take_ownership(UART3_SHARED_PERI, SPBA_MASTER_A); +#endif /* UART3_DMA_ENABLE */ + platform_device_register(&mxc_uart_device3); +#endif /* UART3_ENABLED */ + + return 0; +} + +#else +static int __init mxc_init_uart(void) +{ + return 0; +} +#endif + +arch_initcall(mxc_init_uart); diff --git a/arch/arm/mach-mx37/serial.h b/arch/arm/mach-mx37/serial.h new file mode 100644 index 000000000000..b8b8403e2698 --- /dev/null +++ b/arch/arm/mach-mx37/serial.h @@ -0,0 +1,127 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ARCH_ARM_MACH_MX37_SERIAL_H__ +#define __ARCH_ARM_MACH_MX37_SERIAL_H__ + +#include <mach/mxc_uart.h> + +/* UART 1 configuration */ +/*! + * This option allows to choose either an interrupt-driven software controlled + * hardware flow control (set this option to 0) or hardware-driven hardware + * flow control (set this option to 1). + */ +/* UART used as wakeup source */ +#define UART1_HW_FLOW 0 +/*! + * This specifies the threshold at which the CTS pin is deasserted by the + * RXFIFO. Set this value in Decimal to anything from 0 to 32 for + * hardware-driven hardware flow control. Read the HW spec while specifying + * this value. When using interrupt-driven software controlled hardware + * flow control set this option to -1. + */ +#define UART1_UCR4_CTSTL 16 +/*! + * This is option to enable (set this option to 1) or disable DMA data transfer + */ +#define UART1_DMA_ENABLE 0 +/*! + * Specify the size of the DMA receive buffer. The minimum buffer size is 512 + * bytes. The buffer size should be a multiple of 256. + */ +#define UART1_DMA_RXBUFSIZE 1024 +/*! + * Specify the MXC UART's Receive Trigger Level. This controls the threshold at + * which a maskable interrupt is generated by the RxFIFO. Set this value in + * Decimal to anything from 0 to 32. Read the HW spec while specifying this + * value. + */ +#define UART1_UFCR_RXTL 16 +/*! + * Specify the MXC UART's Transmit Trigger Level. This controls the threshold at + * which a maskable interrupt is generated by the TxFIFO. Set this value in + * Decimal to anything from 0 to 32. Read the HW spec while specifying this + * value. + */ +#define UART1_UFCR_TXTL 16 +/* UART 2 configuration */ +#define UART2_HW_FLOW 0 +#define UART2_UCR4_CTSTL -1 +#define UART2_DMA_ENABLE 0 +#define UART2_DMA_RXBUFSIZE 512 +#define UART2_UFCR_RXTL 16 +#define UART2_UFCR_TXTL 16 +/* UART 3 configuration */ +#define UART3_HW_FLOW 1 +#define UART3_UCR4_CTSTL 16 +#define UART3_DMA_ENABLE 0 +#define UART3_DMA_RXBUFSIZE 1024 +#define UART3_UFCR_RXTL 16 +#define UART3_UFCR_TXTL 16 +/* + * UART Chip level Configuration that a user may not have to edit. These + * configuration vary depending on how the UART module is integrated with + * the ARM core + */ +/* + * Is the MUXED interrupt output sent to the ARM core + */ +#define INTS_NOTMUXED 0 +#define INTS_MUXED 1 +/* UART 1 configuration */ +/*! + * This define specifies whether the muxed ANDed interrupt line or the + * individual interrupts from the UART port is integrated with the ARM core. + * There exists a define like this for each UART port. Valid values that can + * be used are \b INTS_NOTMUXED or \b INTS_MUXED. + */ +#define UART1_MUX_INTS INTS_MUXED +/*! + * This define specifies the transmitter interrupt number or the interrupt + * number of the ANDed interrupt in case the interrupts are muxed. There exists + * a define like this for each UART port. + */ +#define UART1_INT1 MXC_INT_UART1 +/*! + * This define specifies the receiver interrupt number. If the interrupts of + * the UART are muxed, then we specify here a dummy value -1. There exists a + * define like this for each UART port. + */ +#define UART1_INT2 -1 +/*! + * This specifies the master interrupt number. If the interrupts of the UART + * are muxed, then we specify here a dummy value of -1. There exists a define + * like this for each UART port. + */ +#define UART1_INT3 -1 +/*! + * This specifies if the UART is a shared peripheral. It holds the shared + * peripheral number if it is shared or -1 if it is not shared. There exists + * a define like this for each UART port. + */ +#define UART1_SHARED_PERI -1 +/* UART 2 configuration */ +#define UART2_MUX_INTS INTS_MUXED +#define UART2_INT1 MXC_INT_UART2 +#define UART2_INT2 -1 +#define UART2_INT3 -1 +#define UART2_SHARED_PERI -1 +/* UART 3 configuration */ +#define UART3_MUX_INTS INTS_MUXED +#define UART3_INT1 MXC_INT_UART3 +#define UART3_INT2 -1 +#define UART3_INT3 -1 +#define UART3_SHARED_PERI SPBA_UART3 + +#endif /* __ARCH_ARM_MACH_MX37_SERIAL_H__ */ diff --git a/arch/arm/mach-mx37/system.c b/arch/arm/mach-mx37/system.c new file mode 100644 index 000000000000..d40549b29ddc --- /dev/null +++ b/arch/arm/mach-mx37/system.c @@ -0,0 +1,192 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#define DEBUG +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <asm/proc-fns.h> +#include <asm/system.h> +#include <asm/cacheflush.h> +#include <mach/clock.h> +#include "crm_regs.h" + +/*! + * @defgroup MSL_MX37 i.MX37 Machine Specific Layer (MSL) + */ + +/*! + * @file mach-mx37/system.c + * @brief This file contains idle and reset functions. + * + * @ingroup MSL_MX37 + */ + +extern int mxc_jtag_enabled; +extern int low_bus_freq_mode; + +static struct clk *pll1_main; +static struct clk *pll1_sw_clk; +static struct clk *lp_apm_clk; +static struct clk *gpc_dvfs_clk; + +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +{ + u32 plat_lpc, gpc_pgr, arm_srpgcr, empgcr0, empgcr1, ccm_clpcr; + /* always allow platform to issue a deep sleep mode request */ + plat_lpc = __raw_readl(MXC_ARM1176_PLAT_LPC) & + ~(MXC_ARM1176_PLAT_LPC_DSM); + + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + gpc_pgr = __raw_readl(MXC_GPC_PGR) & ~(MXC_GPC_PGR_ARMPG_MASK); + arm_srpgcr = __raw_readl(MXC_SRPGC_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgcr0 = __raw_readl(MXC_EMPGC0_ARM_EMPGCR) & ~(MXC_EMPGCR_PCR); + empgcr1 = __raw_readl(MXC_EMPGC1_ARM_EMPGCR) & ~(MXC_EMPGCR_PCR); + + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); + break; + case WAIT_UNCLOCKED_POWER_OFF: + case STOP_POWER_OFF: + plat_lpc |= MXC_ARM1176_PLAT_LPC_DSM; + if (mode == WAIT_UNCLOCKED_POWER_OFF) + ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); + else { + ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); + ccm_clpcr |= (0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET); + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; + } + + gpc_pgr |= (0x1 << MXC_GPC_PGR_ARMPG_OFFSET); + arm_srpgcr |= MXC_SRPGCR_PCR; + empgcr0 |= MXC_EMPGCR_PCR; + empgcr1 |= MXC_EMPGCR_PCR; + + if (tzic_enable_wake(1) != 0) + return; + break; + case STOP_POWER_ON: + ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); + break; + default: + printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); + return; + } + + __raw_writel(plat_lpc, MXC_ARM1176_PLAT_LPC); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + __raw_writel(gpc_pgr, MXC_GPC_PGR); + __raw_writel(arm_srpgcr, MXC_SRPGC_ARM_SRPGCR); + if ((mxc_cpu_is_rev(CHIP_REV_1_0)) != 1) + __raw_writel(empgcr0, MXC_EMPGC0_ARM_EMPGCR); + + __raw_writel(empgcr1, MXC_EMPGC1_ARM_EMPGCR); + + flush_cache_all(); + + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + + /* gpc clock is needed for SRPG */ + clk_enable(gpc_dvfs_clk); + if (low_bus_freq_mode) { + if (pll1_sw_clk == NULL) + pll1_sw_clk = clk_get(NULL, "pll1_sw_clk"); + if (lp_apm_clk == NULL) + lp_apm_clk = clk_get(NULL, "lp_apm"); + if (pll1_main == NULL) + pll1_main = clk_get(NULL, "pll1_main_clk"); + + /* Move the ARM to run off the 24MHz clock. Shutdown the PLL1 */ + /* Change the source of pll1_sw_clk to be the step_clk */ + clk_set_parent(pll1_sw_clk, lp_apm_clk); + } +} + +void mxc_pg_enable(struct platform_device *pdev) +{ + if (pdev == NULL) + return; + + if (strcmp(pdev->name, "mxc_ipu") == 0) { + __raw_writel(MXC_PGCR_PCR, MXC_PGC_IPU_PGCR); + __raw_writel(MXC_PGSR_PSR, MXC_PGC_IPU_PGSR); + } else if (strcmp(pdev->name, "mxc_vpu") == 0) { + __raw_writel(MXC_PGCR_PCR, MXC_PGC_VPU_PGCR); + __raw_writel(MXC_PGSR_PSR, MXC_PGC_VPU_PGSR); + } +} + +EXPORT_SYMBOL(mxc_pg_enable); + +void mxc_pg_disable(struct platform_device *pdev) +{ + if (pdev == NULL) + return; + + if (strcmp(pdev->name, "mxc_ipu") == 0) { + __raw_writel(0x0, MXC_PGC_IPU_PGCR); + if (__raw_readl(MXC_PGC_IPU_PGSR) & MXC_PGSR_PSR) + dev_dbg(&pdev->dev, "power gating successful\n"); + __raw_writel(MXC_PGSR_PSR, MXC_PGC_IPU_PGSR); + } else if (strcmp(pdev->name, "mxc_vpu") == 0) { + __raw_writel(0x0, MXC_PGC_VPU_PGCR); + if (__raw_readl(MXC_PGC_VPU_PGSR) & MXC_PGSR_PSR) + dev_dbg(&pdev->dev, "power gating successful\n"); + __raw_writel(MXC_PGSR_PSR, MXC_PGC_VPU_PGSR); + } +} + +EXPORT_SYMBOL(mxc_pg_disable); + +/* To change the idle power mode, need to set arch_idle_mode to a different + * power mode as in enum mxc_cpu_pwr_mode. + * May allow dynamically changing the idle mode. + */ +static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF; + +/*! + * This function puts the CPU into idle mode. It is called by default_idle() + * in process.c file. + */ +void arch_idle(void) +{ + if (likely(!mxc_jtag_enabled)) { + mxc_cpu_lp_set(arch_idle_mode); + cpu_do_idle(); + /* gpc clock is needed for SRPG */ + clk_disable(gpc_dvfs_clk); + if (low_bus_freq_mode) { + /* Move ARM back to PLL from step clk. */ + /* Move the PLL1 back to the pll1_main_clk */ + clk_set_parent(pll1_sw_clk, pll1_main); + } + } +} + +/* + * This function resets the system. It is called by machine_restart(). + * + * @param mode indicates different kinds of resets + */ +void arch_reset(char mode) +{ + /* Assert SRS signal */ + mxc_wd_reset(); +} diff --git a/arch/arm/mach-mx37/usb.h b/arch/arm/mach-mx37/usb.h new file mode 100644 index 000000000000..3542866ada0b --- /dev/null +++ b/arch/arm/mach-mx37/usb.h @@ -0,0 +1,112 @@ +/* + * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + +extern int usbotg_init(struct platform_device *pdev); +extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata); +extern int gpio_usbotg_hs_active(void); +extern void gpio_usbotg_hs_inactive(void); +extern struct platform_device *host_pdev_register(struct resource *res, + int n_res, struct fsl_usb2_platform_data *config); + +extern int gpio_usbotg_utmi_active(void); +extern void gpio_usbotg_utmi_inactive(void); +static int usbotg_init_ext(struct platform_device *pdev); +static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata); + +/* + * Determine which platform_data struct to use for the DR controller, + * based on which transceiver is configured. + * PDATA is a pointer to it. + */ +#if defined(CONFIG_ISP1301_MXC) +static struct fsl_usb2_platform_data __maybe_unused dr_1301_config; +#define PDATA (&dr_1301_config) +#elif defined(CONFIG_MC13783_MXC) +static struct fsl_usb2_platform_data __maybe_unused dr_13783_config; +#define PDATA (&dr_13783_config) +#elif defined(CONFIG_UTMI_MXC) +static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config; +#define PDATA (&dr_utmi_config) +#endif + + +/* + * Used to set pdata->operating_mode before registering the platform_device. + * If OTG is configured, the controller operates in OTG mode, + * otherwise it's either host or device. + */ +#ifdef CONFIG_USB_OTG +#define DR_UDC_MODE FSL_USB2_DR_OTG +#define DR_HOST_MODE FSL_USB2_DR_OTG +#else +#define DR_UDC_MODE FSL_USB2_DR_DEVICE +#define DR_HOST_MODE FSL_USB2_DR_HOST +#endif + + +#ifdef CONFIG_USB_EHCI_ARC_OTG +static inline void dr_register_host(struct resource *r, int rs) +{ + PDATA->operating_mode = DR_HOST_MODE; + host_pdev_register(r, rs, PDATA); +} +#else +static inline void dr_register_host(struct resource *r, int rs) +{ +} +#endif + +#ifdef CONFIG_USB_GADGET_ARC +static struct platform_device dr_udc_device; + +static inline void dr_register_udc(void) +{ + PDATA->operating_mode = DR_UDC_MODE; + dr_udc_device.dev.platform_data = PDATA; + + if (platform_device_register(&dr_udc_device)) + printk(KERN_ERR "usb: can't register DR gadget\n"); + else + printk(KERN_INFO "usb: DR gadget (%s) registered\n", + PDATA->transceiver); +} +#else +static inline void dr_register_udc(void) +{ +} +#endif + +#ifdef CONFIG_USB_OTG +static struct platform_device dr_otg_device; + +/* + * set the proper operating_mode and + * platform_data pointer, then register the + * device. + */ +static inline void dr_register_otg(void) +{ + PDATA->operating_mode = FSL_USB2_DR_OTG; + dr_otg_device.dev.platform_data = PDATA; + + if (platform_device_register(&dr_otg_device)) + printk(KERN_ERR "usb: can't register otg device\n"); + else + printk(KERN_INFO "usb: DR OTG registered\n"); +} +#else +static inline void dr_register_otg(void) +{ +} +#endif diff --git a/arch/arm/mach-mx37/usb_dr.c b/arch/arm/mach-mx37/usb_dr.c new file mode 100644 index 000000000000..585553d9a03e --- /dev/null +++ b/arch/arm/mach-mx37/usb_dr.c @@ -0,0 +1,150 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <mach/hardware.h> +#include <mach/arc_otg.h> +#include "usb.h" + +static void usbotg_pm_clock(bool on); +/* + * platform data structs + * - Which one to use is determined by CONFIG options in usb.h + * - operating_mode plugged at run time + */ +static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { + .name = "DR", + .platform_init = usbotg_init_ext, + .platform_uninit = usbotg_uninit_ext, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, + .power_budget = 500, /* 500 mA max power */ + .gpio_usb_active = gpio_usbotg_hs_active, + .gpio_usb_inactive = gpio_usbotg_hs_inactive, + .usb_clock_for_pm = usbotg_pm_clock, + .transceiver = "utmi", +}; + + +/* + * resources + */ +static struct resource otg_resources[] = { + [0] = { + .start = (u32)(OTG_BASE_ADDR), + .end = (u32)(OTG_BASE_ADDR + 0x620), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + + +static u64 dr_udc_dmamask = ~(u32) 0; +static void dr_udc_release(struct device *dev) +{ +} + +/* + * platform device structs + * dev.platform_data field plugged at run time + */ +static struct platform_device dr_udc_device = { + .name = "fsl-usb2-udc", + .id = -1, + .dev = { + .release = dr_udc_release, + .dma_mask = &dr_udc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .resource = otg_resources, + .num_resources = ARRAY_SIZE(otg_resources), +}; + +static u64 dr_otg_dmamask = ~(u32) 0; +static void dr_otg_release(struct device *dev) +{} + +static struct platform_device __maybe_unused dr_otg_device = { + .name = "fsl-usb2-otg", + .id = -1, + .dev = { + .release = dr_otg_release, + .dma_mask = &dr_otg_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .resource = otg_resources, + .num_resources = ARRAY_SIZE(otg_resources), +}; + +/* Notes: configure USB clock*/ +static int usbotg_init_ext(struct platform_device *pdev) +{ + struct clk *usb_clk, *usboh2_clk; + int ret; + + usboh2_clk = clk_get(NULL, "usboh2_clk"); + clk_enable(usboh2_clk); + + usb_clk = clk_get(NULL, "usb_phy_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + ret = usbotg_init(pdev); + + /* this clock is no use after set portsc PTS bit */ + clk_disable(usboh2_clk); + clk_put(usboh2_clk); + + return ret; +} + +static void usbotg_pm_clock(bool on) +{ + struct clk *usb_clk; + + usb_clk = clk_get(NULL, "usb_phy_clk"); + /* close and open usb phy clock for suspend and resume */ + if (on) { + clk_enable(usb_clk); + } else { + clk_disable(usb_clk); + } + clk_put(usb_clk); +} + +static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) +{ + usbotg_pm_clock(false); + usbotg_uninit(pdata); +} + + + +static int __init usb_dr_init(void) +{ + pr_debug("%s: \n", __func__); + + dr_register_otg(); + dr_register_host(otg_resources, ARRAY_SIZE(otg_resources)); + dr_register_udc(); + + return 0; +} + +module_init(usb_dr_init); |