diff options
Diffstat (limited to 'arch/arm/mach-mx5')
63 files changed, 35862 insertions, 1230 deletions
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 1576d51e676c..2dc41de79f15 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -2,17 +2,122 @@ if ARCH_MX5 config ARCH_MX51 bool - default y + select USB_ARCH_HAS_EHCI + select MXC_TZIC + select ARCH_MXC_IOMUX_V3 + +config ARCH_MX53 + bool + select USB_ARCH_HAS_EHCI select MXC_TZIC select ARCH_MXC_IOMUX_V3 -comment "MX5 platforms:" +config ARCH_MX50 + bool + select ARCH_HAS_RNGC + +config FORCE_MAX_ZONEORDER + int "MAX_ORDER" + default "13" + +config MX5_MULTI_ARCH + bool + default y + select RUNTIME_PHYS_OFFSET + depends on ARCH_MX51 + depends on ARCH_MX50 || ARCH_MX53 + +config MACH_MX51_3DS + bool "Support MX51 3-Stack platform" + select ARCH_MX51 + help + Include support for MX51 3-Stack platform. This includes specific + configurations for the board and its peripherals. config MACH_MX51_BABBAGE bool "Support MX51 BABBAGE platforms" + select ARCH_MX51 help Include support for MX51 Babbage platform, also known as MX51EVK in u-boot. This includes specific configurations for the board and its peripherals. +config MACH_MX53_EVK + bool "Support MX53 EVK platform" + select ARCH_MX53 + help + Include support for MX53 EVK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_ARD + bool "Support MX53 ARD platform" + select ARCH_MX53 + help + Include support for MX53 ARD platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_SMD + bool "Support MX53 SMD platform" + select ARCH_MX53 + help + Include support for MX53 SMD platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_LOCO + bool "Support MX53 LOCO platform" + select ARCH_MX53 + help + Include support for MX53 LOCO platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX50_ARM2 + bool "Support MX50 Armadillo2 platform" + select ARCH_MX50 + help + Include support for MX50 EVK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX50_RDP + bool "Support MX50 Reference Design Platform" + select ARCH_MX50 + help + Include support for MX50 RDP platform. This includes specific + configurations for the board and its peripherals. + +comment "MX5x Options:" + +config MXC_SDMA_API + bool "Use SDMA API" + default y + help + This selects the Freescale MXC SDMA API. + If unsure, say N. + +config ARCH_MXC_HAS_NFC_V3 + bool "MXC NFC Hardware Version 3" + depends on ARCH_MX5 + default y + help + This selects the Freescale MXC Nand Flash Controller Hardware Version 3 + If unsure, say N. + +config ARCH_MXC_HAS_NFC_V3_2 + bool "MXC NFC Hardware Version 3.2" + 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. + +config SDMA_IRAM + bool "Use Internal RAM for SDMA transfer" + depends on MXC_SDMA_API + help + Support Internal RAM as SDMA buffer or control structures + +config MXC_BLUETOOTH_RFKILL + tristate "MXC Bluetooth rfkill interface support" + depends on RFKILL + ---help--- + Say Y to get the standard rfkill interface of Bluetooth endif diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index bf23f869ef51..2ef2ceb29859 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile @@ -3,7 +3,19 @@ # # Object file lists. -obj-y := cpu.o mm.o clock-mx51.o devices.o +obj-y := system.o iomux.o cpu.o mm.o devices.o serial.o dma.o lpmodes.o pm.o \ +sdram_autogating.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o dummy_gpio.o early_setup.o -obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o +obj-$(CONFIG_ARCH_MX51) += clock.o suspend.o +obj-$(CONFIG_ARCH_MX53) += clock.o suspend.o mx53_wp.o pm_da9053.o +obj-$(CONFIG_ARCH_MX50) += clock_mx50.o dmaengine.o dma-apbh.o mx50_suspend.o mx50_ddr_freq.o mx50_wfi.o +obj-$(CONFIG_MACH_MX51_3DS) += mx51_3stack.o mx51_3stack_gpio.o mx51_3stack_pmic_mc13892.o +obj-$(CONFIG_MACH_MX51_BABBAGE) += mx51_babbage.o mx51_babbage_pmic_mc13892.o +obj-$(CONFIG_MACH_MX53_EVK) += mx53_evk.o mx53_evk_pmic_mc13892.o +obj-$(CONFIG_MACH_MX53_ARD) += mx53_ard.o mx53_ard_pmic_ltc3589.o +obj-$(CONFIG_MACH_MX53_SMD) += mx53_smd.o mx53_smd_pmic_da9053.o +obj-$(CONFIG_MACH_MX53_LOCO) += mx53_loco.o mx53_loco_pmic_da9053.o +obj-$(CONFIG_MACH_MX50_ARM2) += mx50_arm2.o mx50_arm2_pmic_mc13892.o +obj-$(CONFIG_MACH_MX50_RDP) += mx50_rdp.o mx50_rdp_pmic_mc13892.o +obj-$(CONFIG_MXC_BLUETOOTH_RFKILL) += mx53_smd_rfkill.o diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot index 9939a19d99a1..434ef85a32dc 100644 --- a/arch/arm/mach-mx5/Makefile.boot +++ b/arch/arm/mach-mx5/Makefile.boot @@ -1,3 +1,9 @@ - zreladdr-y := 0x90008000 -params_phys-y := 0x90000100 -initrd_phys-y := 0x90800000 + zreladdr-$(CONFIG_ARCH_MX51) := 0x90008000 +params_phys-$(CONFIG_ARCH_MX51) := 0x90000100 +initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000 + zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000 +params_phys-$(CONFIG_ARCH_MX53) := 0x70000100 +initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000 + zreladdr-$(CONFIG_ARCH_MX50) := 0x70008000 +params_phys-$(CONFIG_ARCH_MX50) := 0x70000100 +initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000 diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index ed885f9d7b73..9968164f5271 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -19,7 +19,6 @@ #include <mach/common.h> #include <mach/hardware.h> -#include <mach/imx-uart.h> #include <mach/iomux-mx51.h> #include <mach/mxc_ehci.h> @@ -29,6 +28,7 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> +#include "devices-imx51.h" #include "devices.h" #define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ @@ -83,15 +83,15 @@ static struct pad_desc mx51babbage_pads[] = { /* Serial ports */ #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE) -static struct imxuart_platform_data uart_pdata = { +static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; static inline void mxc_init_imx_uart(void) { - mxc_register_device(&mxc_uart_device0, &uart_pdata); - mxc_register_device(&mxc_uart_device1, &uart_pdata); - mxc_register_device(&mxc_uart_device2, &uart_pdata); + imx51_add_imx_uart(0, &uart_pdata); + imx51_add_imx_uart(1, &uart_pdata); + imx51_add_imx_uart(2, &uart_pdata); } #else /* !SERIAL_IMX */ static inline void mxc_init_imx_uart(void) diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c new file mode 100644 index 000000000000..d598a0663e68 --- /dev/null +++ b/arch/arm/mach-mx5/bus_freq.c @@ -0,0 +1,1108 @@ +/* + * Copyright 2009-2011 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 <asm/io.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/iram_alloc.h> +#include <linux/mutex.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> +#include "crm_regs.h" + +#define LP_LOW_VOLTAGE 1050000 +#define LP_NORMAL_VOLTAGE 1250000 +#define LP_APM_CLK 24000000 +#define NAND_LP_APM_CLK 12000000 +#define AXI_A_NORMAL_CLK 166250000 +#define AXI_A_CLK_NORMAL_DIV 4 +#define AXI_B_CLK_NORMAL_DIV 5 +#define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV +#define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV +#define NFC_CLK_NORMAL_DIV 4 +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define HW_QOS_DISABLE 0x70 +#define HW_QOS_DISABLE_SET 0x74 +#define HW_QOS_DISABLE_CLR 0x78 +#define DDR_TYPE_DDR3 0x0 +#define DDR_TYPE_DDR2 0x1 + +DEFINE_SPINLOCK(ddr_freq_lock); + +static unsigned long lp_normal_rate; +static unsigned long lp_med_rate; +static unsigned long ddr_normal_rate; +static unsigned long ddr_med_rate; +static unsigned long ddr_low_rate; +static int cur_ddr_rate; +static unsigned char mx53_ddr_type; + +static struct clk *ddr_clk; +static struct clk *pll1_sw_clk; +static struct clk *pll1; +static struct clk *pll2; +static struct clk *pll3; +static struct clk *pll4; +static struct clk *main_bus_clk; +static struct clk *axi_a_clk; +static struct clk *axi_b_clk; +static struct clk *cpu_clk; +static struct clk *ddr_hf_clk; +static struct clk *ahb_clk; +static struct clk *ddr_clk; +static struct clk *periph_apm_clk; +static struct clk *lp_apm; +static struct clk *gpc_dvfs_clk; +static struct clk *emi_garb_clk; +static struct clk *epdc_clk; + +static void __iomem *pll1_base; +static void __iomem *pll4_base; + +static void __iomem *qosc_base; + +struct regulator *pll_regulator; + +struct regulator *lp_regulator; +int low_bus_freq_mode; +int high_bus_freq_mode; +int med_bus_freq_mode; + +int bus_freq_scaling_initialized; +char *gp_reg_id; +char *lp_reg_id; + +static struct cpu_wp *cpu_wp_tbl; +static struct device *busfreq_dev; +static int busfreq_suspended; +static int cpu_podf; +/* True if bus_frequency is scaled not using DVFS-PER */ +int bus_freq_scaling_is_active; + +int cpu_wp_nr; +int lp_high_freq; +int lp_med_freq; + +static int lp_voltage; +struct workqueue_struct *voltage_wq; +static struct work_struct voltage_change_handler; +struct completion voltage_change_cmpl; + +void enter_lpapm_mode_mx50(void); +void enter_lpapm_mode_mx51(void); +void enter_lpapm_mode_mx53(void); +void exit_lpapm_mode_mx50(int high_bus_freq); +void exit_lpapm_mode_mx51(void); +void exit_lpapm_mode_mx53(void); +int low_freq_bus_used(void); +void set_ddr_freq(int ddr_freq); +void *ddr_freq_change_iram_base; +void (*change_ddr_freq)(void *ccm_addr, void *databahn_addr, u32 freq) = NULL; + +extern void mx50_ddr_freq_change(u32 ccm_base, + u32 databahn_addr, u32 freq); +extern int dvfs_core_is_active; +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; + +struct dvfs_wp dvfs_core_setpoint[] = { + {33, 8, 33, 10, 10, 0x08}, + {26, 0, 33, 20, 10, 0x08}, + {28, 8, 33, 20, 30, 0x08}, + {29, 0, 33, 20, 10, 0x08},}; + +static DEFINE_SPINLOCK(voltage_lock); +struct mutex bus_freq_mutex; + +struct timeval start_time; +struct timeval end_time; + +static void voltage_work_handler(struct work_struct *work) +{ + if (lp_regulator != NULL) { + u32 ret = 0; + ret = regulator_set_voltage(lp_regulator, + lp_voltage, lp_voltage); + udelay(400); + if (ret < 0) { + printk(KERN_ERR "COULD NOT SET LP VOLTAGE!!!!!!\n"); + return; + } + } + complete_all(&voltage_change_cmpl); +} + +int set_low_bus_freq(void) +{ + if (busfreq_suspended) + return 0; + if (bus_freq_scaling_initialized) { + /* can not enter low bus freq, when cpu is in higher freq + * or only have one working point */ + if ((clk_get_rate(cpu_clk) > + cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) + || (cpu_wp_nr == 1)) { + return 0; + } + + mutex_lock(&bus_freq_mutex); + + stop_dvfs_per(); + + stop_sdram_autogating(); + + if (cpu_is_mx50()) + enter_lpapm_mode_mx50(); + else if (cpu_is_mx51()) + enter_lpapm_mode_mx51(); + else + enter_lpapm_mode_mx53(); + mutex_unlock(&bus_freq_mutex); + } + return 0; +} + +void enter_lpapm_mode_mx50() +{ + u32 reg; + unsigned long flags; + spin_lock_irqsave(&ddr_freq_lock, flags); + + set_ddr_freq(LP_APM_CLK); + /* Set the parent of main_bus_clk to be PLL3 */ + clk_set_parent(main_bus_clk, pll3); + + /* Set the AHB dividers to be 2. + * Set the dividers so that clock rates + * are not greater than current clock rate. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F) + udelay(10); + + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + /* Set the source of main_bus_clk to be lp-apm. */ + clk_set_parent(main_bus_clk, lp_apm); + + /* Set the AHB dividers to be 1. */ + /* Set the dividers to be 1, so the clock rates + * are at 24Mhz + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F) + udelay(10); + + spin_unlock_irqrestore(&ddr_freq_lock, flags); + + spin_lock_irqsave(&voltage_lock, flags); + lp_voltage = LP_LOW_VOLTAGE; + INIT_COMPLETION(voltage_change_cmpl); + queue_work(voltage_wq, &voltage_change_handler); + spin_unlock_irqrestore(&voltage_lock, flags); + + if (clk_get_usecount(pll1_sw_clk) == 1) { + /* Relock PLL1 to 160MHz. */ + clk_set_parent(pll1_sw_clk, pll2); + /* Set the divider to ARM_PODF to 3. */ + __raw_writel(0x02, MXC_CCM_CACRR); + + clk_set_rate(pll1, 160000000); + clk_set_parent(pll1_sw_clk, pll1); + /* Set the divider to ARM_PODF to 1. */ + __raw_writel(0x0, MXC_CCM_CACRR); + } + + udelay(100); +} + +void enter_lpapm_mode_mx51() +{ + u32 reg; + /* Set PLL3 to 133Mhz if no-one is using it. */ + if (clk_get_usecount(pll3) == 0) { + u32 pll3_rate = clk_get_rate(pll3); + + clk_enable(pll3); + clk_set_rate(pll3, clk_round_rate(pll3, 133000000)); + + /*Change the DDR freq to 133Mhz. */ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_low_rate)); + + /* Set the parent of Periph_apm_clk to be PLL3 */ + clk_set_parent(periph_apm_clk, pll3); + clk_set_parent(main_bus_clk, periph_apm_clk); + + /* Set the dividers to be 1, so the clock rates + * are at 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + clk_disable(emi_garb_clk); + + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + /* Set the source of Periph_APM_Clock to be lp-apm. */ + clk_set_parent(periph_apm_clk, lp_apm); + + /* Set PLL3 back to original rate. */ + clk_set_rate(pll3, clk_round_rate(pll3, pll3_rate)); + clk_disable(pll3); + } +} + +void enter_lpapm_mode_mx53() +{ + u32 reg; + struct timespec nstimeofday; + struct timespec curtime; + + /* TBD: Reduce DDR frequency for DDR2 */ + /* if (mx53_ddr_type == DDR_TYPE_DDR2) { + } */ + + /* move cpu clk to pll2, 400 / 3 = 133Mhz for cpu */ + /* 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); + + cpu_podf = __raw_readl(MXC_CCM_CACRR); + reg = __raw_readl(MXC_CCM_CDHIPR); + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0) + __raw_writel(0x2, MXC_CCM_CACRR); + else + printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); + clk_set_parent(pll1_sw_clk, pll2); + + /* ahb = pll2/8, axi_b = pll2/8, axi_a = pll2/1*/ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("low bus freq set rate error\n"); + } + + /* keep this infront of propagating */ + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + if (clk_get_usecount(pll1) == 0) { + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + } + if (clk_get_usecount(pll4) == 0) { + reg = __raw_readl(pll4_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll4_base + MXC_PLL_DP_CTL); + } +} + +int set_high_bus_freq(int high_bus_freq) +{ + u32 reg; + if (bus_freq_scaling_initialized) { + mutex_lock(&bus_freq_mutex); + /* + * If the CPU freq is 800MHz, set the bus to the high + * setpoint (133MHz) and DDR to 200MHz. + */ + if ((clk_get_rate(cpu_clk) > + cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) + || lp_high_freq) + high_bus_freq = 1; + + stop_sdram_autogating(); + + if (low_bus_freq_mode) { + /* Relock PLL3 to 133MHz */ + if (cpu_is_mx50()) + exit_lpapm_mode_mx50(high_bus_freq); + else if (cpu_is_mx51()) + exit_lpapm_mode_mx51(); + else + exit_lpapm_mode_mx53(); + start_dvfs_per(); + } + if (bus_freq_scaling_is_active) { + if (!high_bus_freq_mode && high_bus_freq) { + if (cpu_is_mx50()) { + if (med_bus_freq_mode) { + /* Increase SYS_CLK */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK; + reg |= 4 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + } + } else { + clk_set_rate(ahb_clk, + clk_round_rate(ahb_clk, + lp_normal_rate)); + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, + ddr_normal_rate)); + } + /* Set to the high setpoint. */ + high_bus_freq_mode = 1; + low_bus_freq_mode = 0; + med_bus_freq_mode = 0; + } else if (!med_bus_freq_mode && !high_bus_freq) { + if (cpu_is_mx50()) { + /* Set the dividers to the medium setpoint dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |3 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |5 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + /* Reduce SYS_CLK */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK; + reg |= 8 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + } else { + if (cpu_is_mx51()) + clk_set_rate(ddr_hf_clk, + clk_round_rate( + ddr_hf_clk, + ddr_low_rate)); + clk_set_rate(ahb_clk, + clk_round_rate( + ahb_clk, lp_med_rate)); + } + /* Set to the medium setpoint. */ + high_bus_freq_mode = 0; + low_bus_freq_mode = 0; + med_bus_freq_mode = 1; + } + if (cpu_is_mx50()) { + if (med_bus_freq_mode && + (cur_ddr_rate != ddr_med_rate)) + set_ddr_freq(ddr_med_rate); + if (high_bus_freq_mode && + (cur_ddr_rate != ddr_normal_rate)) + set_ddr_freq(ddr_normal_rate); + } + } + start_sdram_autogating(); + mutex_unlock(&bus_freq_mutex); + } + return 0; +} + +void exit_lpapm_mode_mx50(int high_bus_freq) +{ + u32 reg; + unsigned long flags; + + if (clk_get_usecount(pll1_sw_clk) == 1) { + /* Relock PLL1 to 800MHz. */ + clk_set_parent(pll1_sw_clk, pll2); + /* Set the divider to ARM_PODF to 3, cpu is at 160MHz. */ + __raw_writel(0x02, MXC_CCM_CACRR); + + clk_set_rate(pll1, 800000000); + clk_set_parent(pll1_sw_clk, pll1); + /* Set the divider to ARM_PODF to 5. */ + __raw_writel(0x4, MXC_CCM_CACRR); + } + + if (!completion_done(&voltage_change_cmpl)) + wait_for_completion_interruptible(&voltage_change_cmpl); + spin_lock_irqsave(&voltage_lock, flags); + if (lp_voltage != LP_NORMAL_VOLTAGE) { + INIT_COMPLETION(voltage_change_cmpl); + lp_voltage = LP_NORMAL_VOLTAGE; + if (!queue_work(voltage_wq, &voltage_change_handler)) + printk(KERN_ERR "WORK_NOT_ADDED\n"); + spin_unlock_irqrestore(&voltage_lock, flags); + wait_for_completion_interruptible(&voltage_change_cmpl); + } else { + spin_unlock_irqrestore(&voltage_lock, flags); + if (!completion_done(&voltage_change_cmpl)) + wait_for_completion_interruptible(&voltage_change_cmpl); + } + + spin_lock_irqsave(&ddr_freq_lock, flags); + if (!low_bus_freq_mode) { + spin_unlock_irqrestore(&ddr_freq_lock, flags); + return; + } + + /* Temporarily set the dividers when the source is PLL3. + * No clock rate is above 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + clk_set_parent(main_bus_clk, pll3); + + if (bus_freq_scaling_is_active && !high_bus_freq) { + /* Set the dividers to the medium setpoint dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |3 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |5 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /* Set to the medium setpoint. */ + high_bus_freq_mode = 0; + low_bus_freq_mode = 0; + med_bus_freq_mode = 1; + set_ddr_freq(ddr_med_rate); + } else { + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /* Set to the high setpoint. */ + high_bus_freq_mode = 1; + low_bus_freq_mode = 0; + med_bus_freq_mode = 0; + set_ddr_freq(ddr_normal_rate); + } + + spin_unlock_irqrestore(&ddr_freq_lock, flags); + + udelay(100); +} + +void exit_lpapm_mode_mx51() +{ + u32 reg; + + /* Temporarily Set the dividers is PLL3. + * No clock rate is above 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + clk_disable(emi_garb_clk); + + clk_set_parent(periph_apm_clk, pll3); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + clk_disable(emi_garb_clk); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /*Change the DDR freq to 200MHz*/ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_normal_rate)); +} + +void exit_lpapm_mode_mx53() +{ + u32 reg; + struct timespec nstimeofday; + struct timespec curtime; + + + /* move cpu clk to pll1 */ + reg = __raw_readl(MXC_CCM_CDHIPR); + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) != 0) + __raw_writel(cpu_podf & 0x7, + MXC_CCM_CACRR); + else + printk(KERN_DEBUG + "ARM_PODF still in busy!!!!\n"); + + clk_set_parent(pll1_sw_clk, pll1); + + + /* ahb = 400/3, axi_b = 400/2, axi_a = 400*/ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec + - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("bus freq error\n"); + } + + /* keep this infront of propagating */ + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + + /* TBD: Restore DDR frequency for DDR2 */ + /* if (mx53_ddr_type == DDR_TYPE_DDR2) { + } */ +} + +int can_change_ddr_freq(void) +{ + if (clk_get_usecount(epdc_clk) == 0) + return 1; + return 0; +} + +void set_ddr_freq(int ddr_rate) +{ + u32 reg; + unsigned long flags; + + if (!can_change_ddr_freq()) + return; + + spin_lock_irqsave(&ddr_freq_lock, flags); + local_flush_tlb_all(); + flush_cache_all(); + + /* Disable all masters from accessing the DDR. */ + reg = __raw_readl(qosc_base + HW_QOS_DISABLE); + reg |= 0xFFE; + __raw_writel(reg, qosc_base + HW_QOS_DISABLE_SET); + udelay(100); + + /* Set the DDR to default freq. + */ + change_ddr_freq(ccm_base, databahn_base, ddr_rate); + + /* Enable all masters to access the DDR. */ + __raw_writel(reg, qosc_base + HW_QOS_DISABLE_CLR); + + spin_unlock_irqrestore(&ddr_freq_lock, flags); + cur_ddr_rate = ddr_rate; + udelay(100); +} + +int low_freq_bus_used(void) +{ + if ((lp_high_freq == 0) + && (lp_med_freq == 0)) + return 1; + else + return 0; +} + +void setup_pll(void) +{ +} + +static ssize_t bus_freq_scaling_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (bus_freq_scaling_is_active) + return sprintf(buf, "Bus frequency scaling is enabled\n"); + else + return sprintf(buf, "Bus frequency scaling is disabled\n"); +} + +static ssize_t bus_freq_scaling_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + u32 reg; + + if (strncmp(buf, "1", 1) == 0) { + if (dvfs_per_active()) { + printk(KERN_INFO "bus frequency scaling cannot be\ + enabled when DVFS-PER is active\n"); + return size; + } + if (!cpu_is_mx50()) { + /* Initialize DVFS-PODF to 0. */ + reg = __raw_readl(MXC_CCM_CDCR); + reg &= ~MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK; + __raw_writel(reg, MXC_CCM_CDCR); + clk_set_parent(main_bus_clk, pll2); + } + bus_freq_scaling_is_active = 1; + set_high_bus_freq(0); + } else if (strncmp(buf, "0", 1) == 0) { + if (bus_freq_scaling_is_active) + set_high_bus_freq(1); + bus_freq_scaling_is_active = 0; + } + + return size; +} + +static int busfreq_suspend(struct platform_device *pdev, pm_message_t message) +{ + if (low_bus_freq_mode) + set_high_bus_freq(1); + busfreq_suspended = 1; + return 0; +} + +static int busfreq_resume(struct platform_device *pdev) +{ + busfreq_suspended = 0; + return 0; +} + +static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, + bus_freq_scaling_enable_store); + +/*! + * 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 err = 0; + unsigned long pll2_rate, pll1_rate; + unsigned long iram_paddr; + struct mxc_bus_freq_platform_data *p_bus_freq_data; + + p_bus_freq_data = pdev->dev.platform_data; + gp_reg_id = p_bus_freq_data->gp_reg_id; + lp_reg_id = p_bus_freq_data->lp_reg_id; + + pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K); + if (cpu_is_mx53()) + pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K); + + busfreq_dev = &pdev->dev; + + 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); + } + + pll1_sw_clk = clk_get(NULL, "pll1_sw_clk"); + if (IS_ERR(pll1_sw_clk)) { + printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__); + return PTR_ERR(pll1_sw_clk); + } + + pll1 = clk_get(NULL, "pll1_main_clk"); + if (IS_ERR(pll1)) { + printk(KERN_DEBUG "%s: failed to get pll1\n", __func__); + return PTR_ERR(pll1); + } + + pll2 = clk_get(NULL, "pll2"); + if (IS_ERR(pll2)) { + printk(KERN_DEBUG "%s: failed to get pll2\n", __func__); + return PTR_ERR(pll2); + } + + pll3 = clk_get(NULL, "pll3"); + if (IS_ERR(pll3)) { + printk(KERN_DEBUG "%s: failed to get pll3\n", __func__); + return PTR_ERR(pll3); + } + + if (cpu_is_mx53()) { + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + printk(KERN_DEBUG "%s: failed to get pll4\n", __func__); + return PTR_ERR(pll4); + } + } + + 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); + } + + 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); + } + + ddr_hf_clk = clk_get_parent(ddr_clk); + + if (IS_ERR(ddr_hf_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n", + __func__); + return PTR_ERR(ddr_hf_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); + } + + 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); + } + + if (cpu_is_mx51()) + emi_garb_clk = clk_get(NULL, "emi_intr_clk.1"); + else if (cpu_is_mx53()) + emi_garb_clk = clk_get(NULL, "emi_intr_clk.1"); + else + emi_garb_clk = clk_get(NULL, "ocram_clk"); + if (IS_ERR(emi_garb_clk)) { + printk(KERN_DEBUG "%s: failed to get emi_garb_clk\n", + __func__); + return PTR_ERR(emi_garb_clk); + } + + if (cpu_is_mx51() || cpu_is_mx53()) { + 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); + } + + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + if (IS_ERR(gpc_dvfs_clk)) { + printk(KERN_DEBUG "%s: failed to get gpc_dvfs_clk\n", __func__); + return PTR_ERR(gpc_dvfs_clk); + } + + err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + if (err) { + printk(KERN_ERR + "Unable to register sysdev entry for BUSFREQ"); + return err; + } + + pll1_rate = clk_get_rate(pll1_sw_clk); + pll2_rate = clk_get_rate(pll2); + + if (pll2_rate == 665000000) { + /* for mx51 */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll1_rate / 4; /* 200M */ + ddr_low_rate = pll1_rate / 6; /* 133M */ + } else if (pll2_rate == 600000000) { + /* for mx53 evk rev.A */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll2_rate / 2; + ddr_low_rate = pll2_rate / 2; + } else if (pll2_rate == 400000000) { + if (cpu_is_mx50()) { + lp_normal_rate = pll2_rate / 3; + ddr_normal_rate = clk_get_rate(ddr_clk); + lp_med_rate = pll2_rate / 6; + ddr_low_rate = LP_APM_CLK; + ddr_med_rate = pll2_rate / 3; + } + } + + /* for mx53 */ + if (cpu_is_mx53()) { + /* set DDR type */ + if (machine_is_mx53_evk() || machine_is_mx53_ard()) + mx53_ddr_type = DDR_TYPE_DDR2; + else + mx53_ddr_type = DDR_TYPE_DDR3; + if (mx53_ddr_type == DDR_TYPE_DDR2) { + /* DDR2 */ + lp_normal_rate = pll2_rate / 3; + lp_med_rate = pll2_rate / 5; + ddr_normal_rate = pll2_rate / 1; + ddr_low_rate = pll2_rate / 3; + } else { + /* DDR3: DDR3 frequency can not be lower than 300MHZ */ + lp_normal_rate = pll2_rate / 3; + lp_med_rate = pll2_rate / 5; + ddr_normal_rate = pll2_rate / 1; + ddr_low_rate = pll2_rate / 1; + } + } + + if (cpu_is_mx50()) { + u32 reg; + + iram_alloc(SZ_8K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, + SZ_8K, MT_HIGH_VECTORS); + memcpy(ddr_freq_change_iram_base, mx50_ddr_freq_change, SZ_8K); + change_ddr_freq = (void *)ddr_freq_change_iram_base; + cur_ddr_rate = ddr_normal_rate; + + lp_regulator = regulator_get(NULL, lp_reg_id); + if (IS_ERR(lp_regulator)) { + printk(KERN_DEBUG + "%s: failed to get lp regulator\n", __func__); + return PTR_ERR(lp_regulator); + } + + qosc_base = ioremap(QOSC_BASE_ADDR, SZ_4K); + /* Enable the QoSC */ + reg = __raw_readl(qosc_base); + reg &= ~0xC0000000; + __raw_writel(reg, qosc_base); + + voltage_wq = create_rt_workqueue("voltage_change"); + INIT_WORK(&voltage_change_handler, voltage_work_handler); + + init_completion(&voltage_change_cmpl); + + epdc_clk = clk_get(NULL, "epdc_axi"); + if (IS_ERR(epdc_clk)) { + printk(KERN_DEBUG "%s: failed to get epdc_axi_clk\n", + __func__); + return PTR_ERR(epdc_clk); + } + } + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + bus_freq_scaling_is_active = 0; + bus_freq_scaling_initialized = 1; + + mutex_init(&bus_freq_mutex); + return 0; +} + +static struct platform_driver busfreq_driver = { + .driver = { + .name = "busfreq", + }, + .probe = busfreq_probe, + .suspend = busfreq_suspend, + .resume = busfreq_resume, +}; + +/*! + * 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) +{ + sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&busfreq_driver); + bus_freq_scaling_initialized = 0; +} + +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-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c deleted file mode 100644 index d9f612d3370e..000000000000 --- a/arch/arm/mach-mx5/clock-mx51.c +++ /dev/null @@ -1,871 +0,0 @@ -/* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> - * - * 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/delay.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <asm/clkdev.h> -#include <asm/div64.h> - -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "crm_regs.h" - -/* External clock values passed-in by the board code */ -static unsigned long external_high_reference, external_low_reference; -static unsigned long oscillator_reference, ckih2_reference; - -static struct clk osc_clk; -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 periph_apm_clk; -static struct clk ahb_clk; -static struct clk ipg_clk; -static struct clk usboh3_clk; - -#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ - -static int _clk_ccgr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void _clk_ccgr_disable(struct clk *clk) -{ - u32 reg; - reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_MOD_OFF << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); - -} - -static void _clk_ccgr_disable_inwait(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - reg |= MXC_CCM_CCGRx_MOD_IDLE << 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 -EINVAL; -} - -static inline void __iomem *_get_pll_base(struct clk *pll) -{ - if (pll == &pll1_main_clk) - return MX51_DPLL1_BASE; - else if (pll == &pll2_sw_clk) - return MX51_DPLL2_BASE; - else if (pll == &pll3_sw_clk) - return MX51_DPLL3_BASE; - else - BUG(); - - return NULL; -} - -static unsigned long clk_pll_get_rate(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; - void __iomem *pllbase; - s64 temp; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - 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 * 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; - - return temp; -} - -static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - void __iomem *pllbase; - - long mfi, pdf, mfn, mfd = 999999; - s64 temp64; - unsigned long quad_parent_rate; - unsigned long pll_hfsm, dp_ctl; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pllbase = _get_pll_base(clk); - - quad_parent_rate = 4 * parent_rate; - pdf = mfi = -1; - while (++pdf < 16 && mfi < 5) - mfi = rate * (pdf+1) / quad_parent_rate; - if (mfi > 15) - return -EINVAL; - 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 int _clk_pll_enable(struct clk *clk) -{ - u32 reg; - void __iomem *pllbase; - int i = 0; - - 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 */ - do { - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); - if (reg & MXC_PLL_DP_CTL_LRF) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: pll locking failed\n"); - return -EINVAL; - } - - return 0; -} - -static void _clk_pll_disable(struct clk *clk) -{ - u32 reg; - void __iomem *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 int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, step; - - reg = __raw_readl(MXC_CCM_CCSR); - - /* When switching from pll_main_clk to a bypass clock, first select a - * multiplexed clock in 'step_sel', then shift the glitchless mux - * 'pll1_sw_clk_sel'. - * - * When switching back, do it in reverse order - */ - if (parent == &pll1_main_clk) { - /* Switch to pll1_main_clk */ - reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - __raw_writel(reg, MXC_CCM_CCSR); - /* step_clk mux switched to lp_apm, to save power. */ - reg = __raw_readl(MXC_CCM_CCSR); - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << - MXC_CCM_CCSR_STEP_SEL_OFFSET); - } else { - if (parent == &lp_apm_clk) { - step = MXC_CCM_CCSR_STEP_SEL_LP_APM; - } else if (parent == &pll2_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED; - } else if (parent == &pll3_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED; - } else - return -EINVAL; - - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (step << MXC_CCM_CCSR_STEP_SEL_OFFSET); - - __raw_writel(reg, MXC_CCM_CCSR); - /* Switch to step_clk */ - reg = __raw_readl(MXC_CCM_CCSR); - reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - } - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -static unsigned long clk_pll1_sw_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - 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; - } else - div = 1; - return parent_rate / div; -} - -static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCSR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - else - reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -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 - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CCSR); - - return 0; -} - -static unsigned long clk_arm_get_rate(struct clk *clk) -{ - u32 cacrr, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - cacrr = __raw_readl(MXC_CCM_CACRR); - div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; - - return parent_rate / div; -} - -static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - int i = 0; - - mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); - - reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CBCMR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: Set parent for periph_apm clock failed\n"); - return -EINVAL; - } - - return 0; -} - -static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCDR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else if (parent == &periph_apm_clk) - reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCDR); - - return 0; -} - -static struct clk main_bus_clk = { - .parent = &pll2_sw_clk, - .set_parent = _clk_main_bus_set_parent, -}; - -static unsigned long clk_ahb_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> - MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; - return parent_rate / div; -} - - -static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div; - unsigned long parent_rate; - int i = 0; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CBCDR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_AHB_PODF_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: clk_ahb_set_rate failed\n"); - return -EINVAL; - } - - return 0; -} - -static unsigned long _clk_ahb_round_rate(struct clk *clk, - unsigned long rate) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8) - div = 8; - else if (div == 0) - div++; - return parent_rate / div; -} - - -static int _clk_max_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - - /* Handshake with MAX when LPM is entered. */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void _clk_max_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable_inwait(clk); - - /* No Handshake with MAX when LPM is entered as its disabled. */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static unsigned long clk_ipg_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> - MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; - - return parent_rate / div; -} - -static unsigned long clk_ipg_per_get_rate(struct clk *clk) -{ - u32 reg, prediv1, prediv2, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - 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_CBCDR); - prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; - prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; - podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> - MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; - return parent_rate / (prediv1 * prediv2 * podf); - } else if (clk->parent == &ipg_clk) - return parent_rate; - else - BUG(); -} - -static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCMR); - - reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - - if (parent == &ipg_clk) - reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - else if (parent == &lp_apm_clk) - reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - else if (parent != &main_bus_clk) - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCMR); - - return 0; -} - -static unsigned long clk_uart_get_rate(struct clk *clk) -{ - u32 reg, prediv, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CSCDR1); - prediv = ((reg & MXC_CCM_CSCDR1_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; - - return 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 unsigned long clk_usboh3_get_rate(struct clk *clk) -{ - u32 reg, prediv, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CSCDR1); - prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >> - MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1; - podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >> - MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1; - - return parent_rate / (prediv * podf); -} - -static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, - &lp_apm_clk); - reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) -{ - return oscillator_reference; -} - -static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) -{ - return ckih2_reference; -} - -/* External high frequency clock */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk ckih2_clk = { - .get_rate = get_ckih2_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -/* External low frequency (32kHz) clock */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk pll1_main_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Clock tree block diagram (WIP): - * CCM: Clock Controller Module - * - * PLL output -> | - * | CCM Switcher -> CCM_CLK_ROOT_GEN -> - * PLL bypass -> | - * - */ - -/* PLL1 SW supplies to ARM core */ -static struct clk pll1_sw_clk = { - .parent = &pll1_main_clk, - .set_parent = _clk_pll1_sw_set_parent, - .get_rate = clk_pll1_sw_get_rate, -}; - -/* PLL2 SW supplies to AXI/AHB/IP buses */ -static struct clk pll2_sw_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .set_rate = _clk_pll_set_rate, - .set_parent = _clk_pll2_sw_set_parent, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */ -static struct clk pll3_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Low-power Audio Playback Mode clock */ -static struct clk lp_apm_clk = { - .parent = &osc_clk, - .set_parent = _clk_lp_apm_set_parent, -}; - -static struct clk periph_apm_clk = { - .parent = &pll1_sw_clk, - .set_parent = _clk_periph_apm_set_parent, -}; - -static struct clk cpu_clk = { - .parent = &pll1_sw_clk, - .get_rate = clk_arm_get_rate, -}; - -static struct clk ahb_clk = { - .parent = &main_bus_clk, - .get_rate = clk_ahb_get_rate, - .set_rate = _clk_ahb_set_rate, - .round_rate = _clk_ahb_round_rate, -}; - -/* Main IP interface clock for access to registers */ -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = clk_ipg_get_rate, -}; - -static struct clk ipg_perclk = { - .parent = &lp_apm_clk, - .get_rate = clk_ipg_per_get_rate, - .set_parent = _clk_ipg_per_set_parent, -}; - -static struct clk uart_root_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_uart_get_rate, - .set_parent = _clk_uart_set_parent, -}; - -static struct clk usboh3_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_usboh3_get_rate, - .set_parent = _clk_usboh3_set_parent, -}; - -static struct clk ahb_max_clk = { - .parent = &ahb_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, -}; - -static struct clk aips_tz1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk aips_tz2_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk gpt_32k_clk = { - .id = 0, - .parent = &ckil_clk, -}; - -#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = _clk_ccgr_enable, \ - .disable = _clk_ccgr_disable, \ - .parent = p, \ - .secondary = s, \ - } - -/* DEFINE_CLOCK(name, id, enable_reg, enable_shift, - get_rate, set_rate, parent, secondary); */ - -/* Shared peripheral bus arbiter */ -DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* UART */ -DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, &uart_root_clk, NULL); -DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &uart_root_clk, NULL); -DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &uart_root_clk, NULL); -DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); - -/* GPT */ -DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* FEC */ -DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK("fec.0", NULL, fec_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) -}; - -static void clk_tree_init(void) -{ - u32 reg; - - 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. - * - * FIXME: Verify if true for all boards - */ - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; - reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); - __raw_writel(reg, MXC_CCM_CBCDR); -} - -int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, - unsigned long ckih1, unsigned long ckih2) -{ - int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); - - clk_tree_init(); - - clk_enable(&cpu_clk); - clk_enable(&main_bus_clk); - - /* set the usboh3_clk parent to pll2_sw_clk */ - clk_set_parent(&usboh3_clk, &pll2_sw_clk); - - /* System timer */ - mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), - MX51_MXC_INT_GPT); - return 0; -} diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c new file mode 100644 index 000000000000..8c91002f4149 --- /dev/null +++ b/arch/arm/mach-mx5/clock.c @@ -0,0 +1,5140 @@ +/* + * Copyright (C) 2008-2011 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/types.h> +#include <linux/time.h> +#include <linux/hrtimer.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <asm/clkdev.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> + +#include "crm_regs.h" +#include "serial.h" +#include "mx53_wp.h" + +/* External clock values passed-in by the board code */ +static unsigned long external_high_reference, external_low_reference; +static unsigned long oscillator_reference, ckih2_reference; + +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 pll4_sw_clk; +static struct clk lp_apm_clk; +static struct clk tve_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 ldb_di_clk[]; +static struct clk axi_a_clk; +static struct clk axi_b_clk; +static struct clk ddr_hf_clk; +static struct clk mipi_hsp_clk; +static struct clk gpu3d_clk; +static struct clk gpu2d_clk; +static struct clk vpu_clk[]; +static int cpu_curr_wp; +static struct cpu_wp *cpu_wp_tbl; + +static void __iomem *pll1_base; +static void __iomem *pll2_base; +static void __iomem *pll3_base; +static void __iomem *pll4_base; + +extern int cpu_wp_nr; +extern int lp_high_freq; +extern int lp_med_freq; +static int max_axi_a_clk; +static int max_axi_b_clk; +static int max_ahb_clk; +static int max_emi_slow_clk; +extern int dvfs_core_is_active; + +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define MAX_AXI_A_CLK_MX51 166250000 +#define MAX_AXI_A_CLK_MX53 400000000 +#define MAX_AXI_B_CLK_MX51 133000000 +#define MAX_AXI_B_CLK_MX53 200000000 +#define MAX_AHB_CLK_MX51 133000000 +#define MAX_EMI_SLOW_CLK_MX51 133000000 +#define MAX_AHB_CLK_MX53 133333333 +#define MAX_EMI_SLOW_CLK_MX53 133333333 +#define MAX_DDR_HF_RATE 200000000 +/* To keep compatible with some NAND flash, limit + * max NAND clk to 34MHZ. The user can modify it for + * dedicate NAND flash */ +#define MAX_NFC_CLK 34000000 + +extern int mxc_jtag_enabled; +extern int uart_at_24; +extern int cpufreq_trig_needed; +extern int low_bus_freq_mode; + +static int cpu_clk_set_wp(int wp); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); + +static struct clk esdhc3_clk[]; + +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 8) { + min_pre = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = (div + *pre - 1) / *pre; + } else if (div < 8) { + *pre = div; + *post = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq++; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq++; + + return 0; +} + +static int _clk_enable_inrun(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << 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_CCGRx_CG_MASK << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq--; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq--; +} + +static void _clk_disable_inwait(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_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; +} + +/* + * For the ddr muxed input clock + */ +static inline u32 _get_mux_ddr(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3, struct clk *m4) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else if (parent == m4) + return 4; + else + BUG(); + + return 0; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return pll1_base; + else if (pll == &pll2_sw_clk) + return pll2_base; + else if (pll == &pll3_sw_clk) + return pll3_base; + else if (pll == &pll4_sw_clk) + return pll4_base; + else + BUG(); + + return NULL; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) +{ + return ckih2_reference; +} + +/* External high frequency clock */ +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk ckih2_clk = { + .get_rate = get_ckih2_reference_clock_rate, +}; + +static struct clk osc_clk = { + .get_rate = get_oscillator_reference_clock_rate, +}; + +/* External low frequency (32kHz) clock */ +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + +static unsigned long _fpm_get_rate(struct clk *clk) +{ + u32 rate = ckil_clk.get_rate(&ckil_clk) * 512; + if ((__raw_readl(MXC_CCM_CCR) & MXC_CCM_CCR_FPM_MULT_MASK) != 0) + rate *= 2; + return rate; +} + +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 = { + .parent = &ckil_clk, + .get_rate = _fpm_get_rate, + .enable = _fpm_enable, + .disable = _fpm_disable, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _fpm_div2_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk fpm_div2_clk = { + .parent = &fpm_clk, + .get_rate = _fpm_div2_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_pll_get_rate(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; + void __iomem *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_get_rate(clk->parent); + 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; + + return temp; +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, reg1; + void __iomem *pllbase; + struct timespec nstimeofday; + struct timespec curtime; + + 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_get_rate(clk->parent); + 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); + } + /* If auto restart is disabled, restart the PLL and + * wait for it to lock. + */ + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_UPEN) { + reg = __raw_readl(pllbase + MXC_PLL_DP_CONFIG); + if (!(reg & MXC_PLL_DP_CONFIG_AREN)) { + reg1 = __raw_readl(pllbase + MXC_PLL_DP_CTL); + reg1 |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg1, pllbase + MXC_PLL_DP_CTL); + } + /* Wait for lock */ + getnstimeofday(&nstimeofday); + while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) + & MXC_PLL_DP_CTL_LRF)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll_set_rate: pll relock failed\n"); + } + } + return 0; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + struct timespec nstimeofday; + struct timespec curtime; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + + if (reg & MXC_PLL_DP_CTL_UPEN) + return 0; + + reg |= MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + getnstimeofday(&nstimeofday); + while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll relock failed\n"); + } + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + void __iomem *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 = { + .parent = &osc_clk, + .get_rate = _clk_pll_get_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; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set the step_clk parent to be lp_apm, to save power. */ + mux = _get_mux(&lp_apm_clk, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == &lp_apm_clk) { + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + reg = __raw_readl(MXC_CCM_CCSR); + 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); + } 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 unsigned long _clk_pll1_sw_get_rate(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; + } + return clk_get_rate(clk->parent) / div; +} + +/* pll1 switch clock */ +static struct clk pll1_sw_clk = { + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll2_sw_clk) { + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } else { + reg = (reg & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL); + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +/* same as pll2_main_clk. These two clocks should always be the same */ +static struct clk pll2_sw_clk = { + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll_set_rate, + .set_parent = _clk_pll2_sw_set_parent, + .flags = RATE_PROPAGATES, +}; + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_sw_clk = { + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +/* same as pll4_main_clk. These two clocks should always be the same */ +static struct clk pll4_sw_clk = { + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .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 = { + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_arm_get_rate(struct clk *clk) +{ + u32 cacrr, div; + + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + return clk_get_rate(clk->parent) / 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 = { + .parent = &pll1_sw_clk, + .get_rate = _clk_arm_get_rate, + .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; + struct timespec nstimeofday; + struct timespec curtime; + + mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); + + reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll _clk_periph_apm_set_parent failed\n"); + } + return 0; +} + +static struct clk periph_apm_clk = { + .parent = &pll1_sw_clk, + .set_parent = _clk_periph_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +/* TODO: Need to sync with GPC to determine if DVFS is in place so that + * the DVFS_PODF divider can be applied in CDCR register. + */ +static unsigned long _clk_main_bus_get_rate(struct clk *clk) +{ + u32 div = 0; + + if (dvfs_per_divider_active() || low_bus_freq_mode) + div = (__raw_readl(MXC_CCM_CDCR) & 0x3); + return clk_get_rate(clk->parent) / (div + 1); +} + +static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + 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 (parent == &pll2_sw_clk) { + reg = __raw_readl(MXC_CCM_CBCDR) & + ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + } else if (parent == &periph_apm_clk) { + reg = __raw_readl(MXC_CCM_CBCDR) | MXC_CCM_CBCDR_PERIPH_CLK_SEL; + } else { + return -EINVAL; + } + __raw_writel(reg, MXC_CCM_CBCDR); + 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); + + return 0; +} + +static struct clk main_bus_clk = { + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, + .get_rate = _clk_main_bus_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_a_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_A_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_A_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_a_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((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); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AXI_A_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll _clk_axi_a_set_rate failed\n"); + } + 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); + + return 0; +} + +static unsigned long _clk_axi_a_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_axi_a_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk axi_a_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_axi_a_get_rate, + .set_rate = _clk_axi_a_set_rate, + .round_rate = _clk_axi_a_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ddr_hf_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_DDR_PODF_MASK) >> + MXC_CCM_CBCDR_DDR_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_ddr_hf_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > MAX_DDR_HF_RATE) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_ddr_hf_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((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); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_DDR_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_DDR_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_DDR_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("clk_ddr_hf_set_rate failed\n"); + } + 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); + + return 0; +} + +static struct clk ddr_hf_clk = { + .parent = &pll1_sw_clk, + .get_rate = _clk_ddr_hf_get_rate, + .round_rate = _clk_ddr_hf_round_rate, + .set_rate = _clk_ddr_hf_set_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_b_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_B_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_B_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_b_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AXI_B_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("_clk_axi_b_set_rate failed\n"); + } + + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static unsigned long _clk_axi_b_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_axi_b_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk axi_b_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_axi_b_get_rate, + .set_rate = _clk_axi_b_set_rate, + .round_rate = _clk_axi_b_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ahb_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((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); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AHB_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("_clk_ahb_set_rate failed\n"); + } + 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); + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_ahb_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk ahb_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_max_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with MAX when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; + else + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + + +static void _clk_max_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable_inwait(clk); + + /* No Handshake with MAX when LPM is entered as its disabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; + else + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk ahb_max_clk = { + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, +}; + +static int _clk_emi_slow_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + 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); + + reg = __raw_readl(MXC_CCM_CBCDR); + if (parent == &ahb_clk) { + reg |= MXC_CCM_CBCDR_EMI_CLK_SEL; + } else if (parent == &main_bus_clk) { + reg &= ~MXC_CCM_CBCDR_EMI_CLK_SEL; + } else { + BUG(); + } + __raw_writel(reg, MXC_CCM_CBCDR); + + 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); + + return 0; +} + +static unsigned long _clk_emi_slow_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >> + MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_emi_slow_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_EMI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_EMI_PODF_BUSY) { + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_emi_slow_set_rate failed\n"); + } + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + + return 0; +} + +static unsigned long _clk_emi_slow_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_emi_slow_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk emi_slow_clk = { + .parent = &main_bus_clk, + .set_parent = _clk_emi_slow_set_parent, + .get_rate = _clk_emi_slow_get_rate, + .set_rate = _clk_emi_slow_set_rate, + .round_rate = _clk_emi_slow_round_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, + .flags = RATE_PROPAGATES, +}; + +static struct clk ahbmux1_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk ahbmux2_clk = { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = _clk_disable_inwait, +}; + + +static struct clk emi_fast_clk = { + .parent = &ddr_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk emi_intr_clk[] = { + { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahbmux2_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + }, + { + /* On MX51 - this clock is name emi_garb_clk, and controls the + * access of ARM to GARB. + */ + .id = 1, + .parent = &ahb_clk, + .secondary = &ahbmux2_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + } +}; + +static unsigned long _clk_ipg_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static struct clk ipg_clk = { + .parent = &ahb_clk, + .get_rate = _clk_ipg_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ipg_per_get_rate(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_CBCDR); + prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) { + return clk_get_rate(&ipg_clk); + } + BUG(); + return 0; +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &main_bus_clk, &lp_apm_clk, &ipg_clk, NULL); + if (mux == 2) { + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + } else { + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + if (mux == 0) + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk ipg_perclk = { + .parent = &lp_apm_clk, + .get_rate = _clk_ipg_per_get_rate, + .set_parent = _clk_ipg_per_set_parent, + .flags = RATE_PROPAGATES, +}; + +static int _clk_ipmux_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_ipmux_disable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(0x1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static struct clk ipumux1_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG6_1_OFFSET, + .enable = _clk_ipmux_enable, + .disable = _clk_ipmux_disable, +}; + +static struct clk ipumux2_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG6_2_OFFSET, + .enable = _clk_ipmux_enable, + .disable = _clk_ipmux_disable, +}; + +static int _clk_ocram_enable(struct clk *clk) +{ + return 0; +} + +static void _clk_ocram_disable(struct clk *clk) +{ +} + +static struct clk ocram_clk = { + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_ocram_enable, + .disable = _clk_ocram_disable, +}; + + +static struct clk aips_tz1_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sdma_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with SDMA when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + else + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_sdma_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with SDMA as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + else + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk sdma_clk[] = { + { + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_sdma_enable, + .disable = _clk_sdma_disable, + }, + { + .parent = &ipg_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &emi_intr_clk[0], +#endif + }, +}; + +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); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + else + reg &= ~MXC_CCM_CCDR_IPU_HS_MX53_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); + + start_sdram_autogating(); + + return 0; +} + +static void _clk_ipu_disable(struct clk *clk) +{ + u32 reg; + + if (sdram_autogating_active()) + stop_sdram_autogating(); + + _clk_disable(clk); + + /* No handshake with IPU whe dividers are changed + * as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CCDR_IPU_HS_MASK; + else + reg |= MXC_CCM_CCDR_IPU_HS_MX53_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_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &ahb_clk, + &emi_slow_clk); + reg = (reg & ~MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + + +static struct clk ipu_clk[] = { + { + .parent = &ahb_clk, + .secondary = &ipu_clk[1], + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_ipu_enable, + .disable = _clk_ipu_disable, + .set_parent = _clk_ipu_set_parent, + .flags = CPU_FREQ_TRIG_UPDATE | AHB_MED_SET_POINT | RATE_PROPAGATES, + }, + { + .parent = &emi_fast_clk, + .secondary = &ahbmux1_clk, + } +}; + +static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg &= ~MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id); + if (parent == &pll3_sw_clk) + ; + else if (parent == &osc_clk) + reg |= 1 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if (parent == &ckih_clk) + reg |= 2 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if ((parent == &pll4_sw_clk) && (clk->id == 0)) { + if (cpu_is_mx51()) + return -EINVAL; + reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + } else if ((parent == &tve_clk) && (clk->id == 1)) + reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if ((parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + reg |= 5 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else /* Assume any other clock is external clock pin */ + reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int priv_div; +static unsigned long _clk_ipu_di_get_rate(struct clk *clk) +{ + u32 reg, mux; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = (reg & MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id)) >> + MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + if (mux == 0) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_DI1_CLK_PRED_MASK; + div = (reg >> MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET) + 1; + } else if ((mux == 3) && (clk->id == 1)) { + if (priv_div) + div = priv_div; + } else if ((mux == 3) && (clk->id == 0)) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_DI_PLL4_PODF_MASK; + div = (reg >> MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET) + 1; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu_di_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + if ((clk->parent == &pll4_sw_clk) && (clk->id == 0)) { + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_DI_PLL4_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + } else if (clk->parent == &pll3_sw_clk) { + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_DI1_CLK_PRED_MASK; + reg |= (div - 1) << MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + } else if (((clk->parent == &tve_clk) && (clk->id == 1)) || + ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53())) { + priv_div = div; + return 0; + } else + return -EINVAL; + + return 0; +} + +static unsigned long _clk_ipu_di_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + return parent_rate; + else { + div = (parent_rate + rate/2) / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; + } +} + +static struct clk ipu_di_clk[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .get_rate = _clk_ipu_di_get_rate, + .set_parent = _clk_ipu_di_set_parent, + .round_rate = _clk_ipu_di_round_rate, + .set_rate = _clk_ipu_di_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = RATE_PROPAGATES, + }, + { + .id = 1, + .parent = &pll3_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .get_rate = _clk_ipu_di_get_rate, + .set_parent = _clk_ipu_di_set_parent, + .round_rate = _clk_ipu_di_round_rate, + .set_rate = _clk_ipu_di_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = RATE_PROPAGATES, + }, +}; + +static int _clk_ldb_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + + if ((parent == &pll3_sw_clk)) { + if (clk->id == 0) + reg &= ~(MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL); + else + reg &= ~(MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL); + } else if ((parent == &pll4_sw_clk)) { + if (clk->id == 0) + reg |= MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL; + else + reg |= MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + return 0; +} + +static unsigned long _clk_ldb_di_get_rate(struct clk *clk) +{ + u32 div; + + if (clk->id == 0) + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + else + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV; + + if (div) + return clk_get_rate(clk->parent) / 7; + + return (2 * clk_get_rate(clk->parent)) / 7; +} + +static unsigned long _clk_ldb_di_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate/20) + return parent_rate / 7; + else + return 2 * parent_rate / 7; +} + +static int _clk_ldb_di_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div = 0; + u32 parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate/20) { + div = 7; + rate = parent_rate / 7; + } else + rate = 2 * parent_rate / 7; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (div == 7) + reg |= (clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + else + reg &= ~(clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int _clk_ldb_di_enable(struct clk *clk) +{ + _clk_enable(clk); + ipu_di_clk[clk->id].set_parent(&ipu_di_clk[clk->id], clk); + ipu_di_clk[clk->id].parent = clk; + ipu_di_clk[clk->id].enable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount++; + return 0; +} + +static void _clk_ldb_di_disable(struct clk *clk) +{ + _clk_disable(clk); + ipu_di_clk[clk->id].disable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount--; +} + +static struct clk ldb_di_clk[] = { + { + .id = 0, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .get_rate = _clk_ldb_di_get_rate, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT, + }, + { + .id = 1, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .get_rate = _clk_ldb_di_get_rate, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT, + }, +}; + +static int _clk_csi0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_csi0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR4); + pred = ((reg & MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent)/(pred * podf); +} + +static unsigned long _clk_csi0_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_csi0_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set CSI clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR4) & + ~(MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK | + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR4); + + return 0; +} + +static struct clk csi0_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_csi0_set_parent, + .get_rate = _clk_csi0_get_rate, + .round_rate = _clk_csi0_round_rate, + .set_rate = _clk_csi0_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_csi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_csi1_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR4); + pred = ((reg & MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent)/(pred * podf) ; +} + +static unsigned long _clk_csi1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_csi1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set CSI clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR4) & + ~(MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK | + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR4); + + return 0; +} + +static struct clk csi1_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_csi1_set_parent, + .get_rate = _clk_csi1_get_rate, + .round_rate = _clk_csi1_round_rate, + .set_rate = _clk_csi1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, +}; + + +static int _clk_hsc_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_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_hsc_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with HSC as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static struct clk mipi_esc_clk = { + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, +}; + +static struct clk mipi_hsc2_clk = { + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .secondary = &mipi_esc_clk, +}; + +static struct clk mipi_hsc1_clk = { + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .secondary = &mipi_hsc2_clk, +}; + +static struct clk mipi_hsp_clk = { + .parent = &ipu_clk[0], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_hsc_enable, + .disable = _clk_hsc_disable, + .secondary = &mipi_hsc1_clk, +}; + +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) && cpu_is_mx51()) { + reg &= ~(MXC_CCM_CSCMR1_TVE_CLK_SEL); + } else if ((parent == &pll4_sw_clk) && cpu_is_mx53()) { + reg &= ~(MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL); + } else if ((parent == &osc_clk) && cpu_is_mx51()) { + 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_EXT_CLK_SEL; + reg |= MXC_CCM_CSCMR1_TVE_CLK_SEL; /* Reserved on MX53 */ + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static unsigned long _clk_tve_get_rate(struct clk *clk) +{ + u32 reg, div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & (MXC_CCM_CSCMR1_TVE_CLK_SEL | MXC_CCM_CSCMR1_TVE_EXT_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; + } + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_tve_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (cpu_is_mx51() && (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL)) + return -EINVAL; + if (cpu_is_mx53() && (reg & MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL)) + return -EINVAL; + + div = (parent_rate + rate/2) / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; +} + +static int _clk_tve_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (cpu_is_mx51() && (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL)) + return -EINVAL; + if (cpu_is_mx53() && (reg & MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL)) + return -EINVAL; + + div = parent_rate / rate; + if (div == 0) + div++; + if (((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); + return 0; +} + +static struct clk tve_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_tve_set_parent, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .get_rate = _clk_tve_get_rate, + .round_rate = _clk_tve_round_rate, + .set_rate = _clk_tve_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk spba_clk = { + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_uart_get_rate(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; + + return clk_get_rate(clk->parent)/(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 struct clk uart_main_clk = { + .parent = &pll2_sw_clk, + .get_rate = _clk_uart_get_rate, + .set_parent = _clk_uart_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk uart1_clk[] = { + { + .id = 0, + .parent = &uart_main_clk, + .secondary = &uart1_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART1_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 0, + .parent = &ipg_clk, +#if UART1_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + .id = 1, + .parent = &uart_main_clk, + .secondary = &uart2_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART2_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 1, + .parent = &ipg_clk, +#if UART2_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + .id = 2, + .parent = &uart_main_clk, + .secondary = &uart3_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART3_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 2, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart4_clk[] = { + { + .id = 3, + .parent = &uart_main_clk, + .secondary = &uart4_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART4_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 3, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart5_clk[] = { + { + .id = 4, + .parent = &uart_main_clk, + .secondary = &uart5_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART5_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 4, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_clk[] = { + { + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &gpt_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm1_clk[] = { + { + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm2_clk[] = { + { + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ckil_clk, + }, +}; + +static struct clk i2c_clk[] = { + { + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_hsi2c_serial_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR3); + prediv = ((reg & MXC_CCM_CSCDR3_HSI2C_CLK_PRED_MASK) >> + MXC_CCM_CSCDR3_HSI2C_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR3_HSI2C_CLK_PODF_MASK) >> + MXC_CCM_CSCDR3_HSI2C_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static struct clk hsi2c_serial_clk = { + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .get_rate = _clk_hsi2c_serial_get_rate, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk hsi2c_clk = { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_cspi_get_rate(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; + + return clk_get_rate(clk->parent) / (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 struct clk cspi_main_clk = { + .parent = &pll3_sw_clk, + .get_rate = _clk_cspi_get_rate, + .set_parent = _clk_cspi_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk cspi1_clk[] = { + { + .id = 0, + .parent = &cspi_main_clk, + .secondary = &cspi1_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi2_clk[] = { + { + .id = 1, + .parent = &cspi_main_clk, + .secondary = &cspi2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi3_clk = { + .id = 2, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &aips_tz2_clk, +}; + +static unsigned long _clk_ieee_rtc_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_ieee_rtc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~(MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK | + MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_ieee_rtc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_ieee_rtc_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll3_sw_clk, &pll4_sw_clk, + NULL, NULL); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_IEEE_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_IEEE_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static struct clk ieee_rtc_clk = { + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ieee_rtc_set_parent, + .set_rate = _clk_ieee_rtc_set_rate, + .round_rate = _clk_ieee_rtc_round_rate, + .get_rate = _clk_ieee_rtc_get_rate, +}; + +static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ckih_clk, &lp_apm_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_lp_apm_clk = { + .parent = &ckih_clk, + .set_parent = _clk_ssi_lp_apm_set_parent, +}; + +static unsigned long _clk_ssi1_get_rate(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; + + return clk_get_rate(clk->parent) / (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[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi1_set_parent, + .secondary = &ssi1_clk[1], + .get_rate = _clk_ssi1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &ssi1_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static unsigned long _clk_ssi2_get_rate(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; + + return clk_get_rate(clk->parent) / (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[] = { + { + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi2_set_parent, + .secondary = &ssi2_clk[1], + .get_rate = _clk_ssi2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &ssi2_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &spba_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static int _clk_ssi3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI3_CLK_SEL; + + if (parent == &ssi1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_SSI3_CLK_SEL; + else if (parent == &ssi2_clk[0]) + reg |= MXC_CCM_CSCMR1_SSI3_CLK_SEL; + else { + printk(KERN_ERR"Set ssi3 clock parent failed!\n"); + printk(KERN_ERR"ssi3 only support"); + printk(KERN_ERR"ssi1 and ssi2 as parent clock\n"); + return -1; + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk ssi3_clk[] = { + { + .id = 2, + .parent = &ssi1_clk[0], + .set_parent = _clk_ssi3_set_parent, + .secondary = &ssi3_clk[1], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &ipg_clk, + .secondary = &ssi3_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk, +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static unsigned long _clk_ssi_ext1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +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 unsigned long _clk_ssi_ext1_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk ssi_ext1_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext1_set_parent, + .set_rate = _clk_ssi_ext1_set_rate, + .round_rate = _clk_ssi_ext1_round_rate, + .get_rate = _clk_ssi_ext1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_ssi_ext2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +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 = { + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext2_set_parent, + .get_rate = _clk_ssi_ext2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_esai_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (parent == &pll1_sw_clk || parent == &pll2_sw_clk || + parent == &pll3_sw_clk) { + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + NULL); + reg &= ~MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET; + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= 0 << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } else { + mux = _get_mux(parent, &ssi1_clk[0], &ssi2_clk[0], &ckih_clk, + &ckih2_clk); + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= (mux + 1) << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + + /* set podf = 0 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static unsigned long _clk_esai_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + if (clk->parent == &pll1_sw_clk || clk->parent == &pll2_sw_clk || + clk->parent == &pll3_sw_clk) { + pred = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (pred * podf); + } else { + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / podf; + } +} + +static struct clk esai_clk[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_esai_set_parent, + .get_rate = _clk_esai_get_rate, + .secondary = &esai_clk[1], + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk iim_clk = { + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax1_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }; + +static struct clk tmax2_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax3_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usboh3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk usboh3_clk[] = { + { + .parent = &pll3_sw_clk, + .set_parent = _clk_usboh3_set_parent, + .get_rate = _clk_usboh3_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, + .secondary = &usboh3_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &tmax2_clk, +#if defined(CONFIG_USB_STATIC_IRAM) \ + || defined(CONFIG_USB_STATIC_IRAM_PPH) + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static struct clk usb_ahb_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usb_phy_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + 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; + + div = (prediv * podf); + } + + return clk_get_rate(clk->parent) / div; +} + +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[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &tmax3_clk, + .set_parent = _clk_usb_phy_set_parent, + .get_rate = _clk_usb_phy_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &pll3_sw_clk, + .secondary = &tmax3_clk, + .set_parent = _clk_usb_phy_set_parent, + .get_rate = _clk_usb_phy_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk esdhc_dep_clks = { + .parent = &spba_clk, + .secondary = &emi_fast_clk, +}; + +static unsigned long _clk_esdhc1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (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_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static int _clk_sdhc1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk esdhc1_clk[] = { + { + .id = 0, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc1_set_parent, + .get_rate = _clk_esdhc1_get_rate, + .set_rate = _clk_sdhc1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &esdhc1_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax3_clk, + .secondary = &esdhc_dep_clks, + }, + +}; + +static unsigned long _clk_esdhc2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + if (cpu_is_mx51()) { + 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; + + return clk_get_rate(clk->parent) / (prediv * podf); + } + return clk_get_rate(clk->parent); +} + +static int _clk_esdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (cpu_is_mx51()) { + 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_ESDHC3_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET; + } else { /* MX53 */ + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC2_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC2_CLK_SEL; + else + BUG(); + } + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static int _clk_esdhc2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + if (cpu_is_mx51()) { + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + } + return 0; +} + +static struct clk esdhc2_clk[] = { + { + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_esdhc2_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &esdhc2_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (cpu_is_mx51()) { + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51; + else if (parent == &esdhc2_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51; + else + BUG(); + } else { /* MX53 */ + 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_ESDHC3_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET; + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_esdhc3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_sdhc3_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + if (cpu_is_mx53()) { + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + } + return 0; +} + + +static struct clk esdhc3_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_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[1], + }, + { + .id = 2, + .parent = &ipg_clk, + .secondary = &esdhc3_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + if (cpu_is_mx51()) { + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc2_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + } else {/*MX53 */ + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc4_clk[] = { + { + .id = 3, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc4_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc4_clk[1], + }, + { + .id = 3, + .parent = &ipg_clk, + .secondary = &esdhc4_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax3_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static struct clk sata_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ieee_1588_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, +}; + +static struct clk mlb_clk[] = { + { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + .secondary = &mlb_clk[1], + }, + { + .parent = &emi_fast_clk, + .secondary = &emi_intr_clk[1], + }, +}; + +static int _can_root_clk_set(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ipg_clk, &ckih_clk, &ckih2_clk, &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static struct clk can1_clk[] = { + { + .id = 0, + .parent = &lp_apm_clk, + .set_parent = _can_root_clk_set, + .enable = _clk_enable, + .secondary = &can1_clk[1], + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk can2_clk[] = { + { + .id = 1, + .parent = &lp_apm_clk, + .set_parent = _can_root_clk_set, + .enable = _clk_enable, + .secondary = &can2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_sim_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_SIM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_sim_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + pred = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (pred * podf); +} + +static unsigned long _clk_sim_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_sim_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set SIM clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR2) & + ~(MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK | + MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; + +} + +static struct clk sim_clk[] = { + { + .parent = &pll3_sw_clk, + .set_parent = _clk_sim_set_parent, + .secondary = &sim_clk[1], + .get_rate = _clk_sim_get_rate, + .round_rate = _clk_sim_round_rate, + .set_rate = _clk_sim_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_nfc_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >> + MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_nfc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + /* + * Compute the divider we'd have to use to reach the target rate. + */ + + div = parent_rate / rate; + if (div == 0) + div++; + if (parent_rate / div > MAX_NFC_CLK) + div++; + + /* + * The divider for this clock is 3 bits wide, so we can't possibly + * divide the parent by more than eight. + */ + + if (div > 8) + return -EINVAL; + + return parent_rate / div; + +} + +static int _clk_nfc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((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); + + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){ + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_nfc_set_rate failed\n"); + } + 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); + + return 0; +} + +static struct clk emi_enfc_clk = { + .parent = &emi_slow_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .disable = _clk_disable_inwait, + .get_rate = _clk_nfc_get_rate, + .round_rate = _clk_nfc_round_rate, + .set_rate = _clk_nfc_set_rate, +}; + +static int _clk_spdif_xtal_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &osc_clk, &ckih_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SPDIF_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SPDIF_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk spdif_xtal_clk = { + .parent = &osc_clk, + .set_parent = _clk_spdif_xtal_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_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 unsigned long _clk_spdif0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + u32 div = 1; + + if (clk->parent != &ssi1_clk[0]) { + 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; + div = (pred * podf); + } + return clk_get_rate(clk->parent) / div; +} + +static struct clk spdif0_clk[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_spdif0_set_parent, + .get_rate = _clk_spdif0_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_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 unsigned long _clk_spdif1_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + u32 div = 1; + + if (clk->parent != &ssi2_clk[0]) { + 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; + div = (pred * podf); + } + return clk_get_rate(clk->parent) / div; +} + +static struct clk spdif1_clk[] = { + { + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_spdif1_set_parent, + .get_rate = _clk_spdif1_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_ddr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, reg2, mux; + struct timespec nstimeofday; + struct timespec curtime; + + reg = __raw_readl(MXC_CCM_CBCMR); + reg2 = __raw_readl(MXC_CCM_CBCDR); + if (cpu_is_mx51()) { + clk->parent = &ddr_hf_clk; + mux = _get_mux_ddr(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk, &ddr_hf_clk); + } else { + clk->parent = &axi_a_clk; + mux = _get_mux_ddr(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk, NULL); + } + if (mux < 4) { + reg = (reg & ~MXC_CCM_CBCMR_DDR_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + if (cpu_is_mx51()) + reg2 = (reg2 & ~MXC_CCM_CBCDR_DDR_HF_SEL); + } else { + reg2 = (reg2 & ~MXC_CCM_CBCDR_DDR_HF_SEL) | + (MXC_CCM_CBCDR_DDR_HF_SEL); + } + if (cpu_is_mx51()) { + __raw_writel(reg2, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_DDR_HF_CLK_SEL_BUSY){ + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_ddr_set_parent failed\n"); + } + } + return 0; +} + +static struct clk ddr_clk = { + .parent = &axi_b_clk, + .set_parent = _clk_ddr_set_parent, + .flags = RATE_PROPAGATES, +}; + +static int _clk_arm_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk 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_CCGRx_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_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static int _clk_vpu_enable(struct clk *clk) +{ + /* Set VPU's parent to be axi_a or ahb when its enabled. */ + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { + clk_set_parent(&vpu_clk[0], &ahb_clk); + clk_set_parent(&vpu_clk[1], &ahb_clk); + } else if (cpu_is_mx51()) { + clk_set_parent(&vpu_clk[0], &axi_a_clk); + clk_set_parent(&vpu_clk[1], &axi_a_clk); + } + + return _clk_enable(clk); + +} + +static void _clk_vpu_disable(struct clk *clk) +{ + _clk_disable(clk); + + /* Set VPU's parent to be axi_b when its disabled. */ + if (cpu_is_mx51()) { + clk_set_parent(&vpu_clk[0], &axi_b_clk); + clk_set_parent(&vpu_clk[1], &axi_b_clk); + } +} + +static struct clk vpu_clk[] = { + { + .set_parent = _clk_vpu_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + .secondary = &vpu_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .set_parent = _clk_vpu_set_parent, + .enable = _clk_vpu_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_vpu_disable, + .secondary = &vpu_clk[2], + }, + { + .parent = &emi_fast_clk, +#ifdef CONFIG_MXC_VPU_IRAM + .secondary = &emi_intr_clk[0], +#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, &osc_clk, NULL, 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 = { + .parent = &ckil_clk, + .set_parent = _clk_lpsr_set_parent, +}; + +static unsigned long _clk_pgc_get_rate(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; + return clk_get_rate(clk->parent) / div; +} + +static struct clk pgc_clk = { + .parent = &ipg_clk, + .get_rate = _clk_pgc_get_rate, +}; + +static unsigned long _clk_usb_get_rate(struct clk *clk) +{ + return 60000000; +} + +/*usb OTG clock */ +static struct clk usb_clk = { + .get_rate = _clk_usb_get_rate, +}; + +static struct clk usb_utmi_clk = { + .enable = _clk_enable, + .enable_reg = MXC_CCM_CSCMR1, + .enable_shift = MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET, + .disable = _clk_disable, +}; + +static struct clk rtc_clk = { + .parent = &ckil_clk, + .secondary = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ata_clk = { + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk owire_clk = { + .parent = &ipg_perclk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + + +static struct clk fec_clk[] = { + { + .parent = &ipg_clk, + .secondary = &fec_clk[1], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &tmax2_clk, + .secondary = &fec_clk[2], + }, + { + .parent = &aips_tz2_clk, + .secondary = &emi_fast_clk, + }, +}; + +static struct clk sahara_clk[] = { + { + .parent = &ahb_clk, + .secondary = &sahara_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .parent = &tmax1_clk, + .secondary = &emi_fast_clk, + } +}; + +static struct clk scc_clk[] = { + { + .parent = &ahb_clk, + .secondary = &scc_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .parent = &tmax1_clk, + .secondary = &emi_fast_clk, + } +}; + + +static int _clk_gpu3d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + + +static struct clk garb_clk = { + .parent = &axi_a_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static struct clk gpu3d_clk = { + .parent = &axi_a_clk, + .set_parent = _clk_gpu3d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + .secondary = &garb_clk, +}; + +static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_clk = { + .parent = &axi_a_clk, + .set_parent = _clk_gpu2d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long cko1_get_rate(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg = reg >> MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + return clk_get_rate(clk->parent) / (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; + u32 parent_rate = clk_get_rate(clk->parent); + + div = (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; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + div = div < 1 ? 1 : div; + div = div > 8 ? 8 : div; + return 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_slow_clk) + sel = 4; + else if (parent == &pll4_sw_clk) + sel = 5; + else if (parent == &emi_enfc_clk) + sel = 6; + else if (parent == &ipu_di_clk[0]) + sel = 8; + else if (parent == &ahb_clk) + sel = 11; + else if (parent == &ipg_clk) + sel = 12; + else if (parent == &ipg_perclk) + sel = 13; + else if (parent == &ckil_clk) + sel = 14; + 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 = { + .get_rate = cko1_get_rate, + .enable = cko1_enable, + .disable = cko1_disable, + .set_rate = cko1_set_rate, + .round_rate = cko1_round_rate, + .set_parent = cko1_set_parent, +}; +static int _clk_asrc_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (parent == &pll4_sw_clk) + reg |= MXC_CCM_CSCMR2_ASRC_CLK_SEL; + else + reg &= ~MXC_CCM_CSCMR2_ASRC_CLK_SEL; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_asrc_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_asrc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2) & + ~(MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK | + MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_asrc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk asrc_clk[] = { + { + .id = 0, + .parent = &pll4_sw_clk, + .set_parent = _clk_asrc_set_parent, + .get_rate = _clk_asrc_get_rate, + .set_rate = _clk_asrc_set_rate, + .round_rate = _clk_asrc_round_rate, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "osc", osc_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk), + _REGISTER_CLOCK(NULL, "ckil", ckil_clk), + _REGISTER_CLOCK(NULL, "pll1_main_clk", pll1_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_sw_clk), + _REGISTER_CLOCK(NULL, "pll3", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "gpc_dvfs_clk", gpc_dvfs_clk), + _REGISTER_CLOCK(NULL, "lp_apm", lp_apm_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK(NULL, "periph_apm_clk", periph_apm_clk), + _REGISTER_CLOCK(NULL, "main_bus_clk", main_bus_clk), + _REGISTER_CLOCK(NULL, "axi_a_clk", axi_a_clk), + _REGISTER_CLOCK(NULL, "axi_b_clk", axi_b_clk), + _REGISTER_CLOCK(NULL, "ahb_clk", ahb_clk), + _REGISTER_CLOCK(NULL, "ahb_max_clk", ahb_max_clk), + _REGISTER_CLOCK(NULL, "vpu_clk", vpu_clk[0]), + _REGISTER_CLOCK(NULL, "vpu_core_clk", vpu_clk[1]), + _REGISTER_CLOCK(NULL, "nfc_clk", emi_enfc_clk), + _REGISTER_CLOCK("mxc_sdma", "sdma_ahb_clk", sdma_clk[0]), + _REGISTER_CLOCK("mxc_sdma", "sdma_ipg_clk", sdma_clk[1]), + _REGISTER_CLOCK(NULL, "ipu_clk", ipu_clk[0]), + _REGISTER_CLOCK(NULL, "ipu_di0_clk", ipu_di_clk[0]), + _REGISTER_CLOCK(NULL, "ipu_di1_clk", ipu_di_clk[1]), + _REGISTER_CLOCK(NULL, "csi_mclk1", csi0_clk), + _REGISTER_CLOCK(NULL, "csi_mclk2", csi1_clk), + _REGISTER_CLOCK(NULL, "tve_clk", tve_clk), + _REGISTER_CLOCK("mxcintuart.0", NULL, uart1_clk[0]), + _REGISTER_CLOCK("mxcintuart.1", NULL, uart2_clk[0]), + _REGISTER_CLOCK("mxcintuart.2", NULL, uart3_clk[0]), + _REGISTER_CLOCK(NULL, "i2c_clk", i2c_clk[0]), + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk[1]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk[0]), + _REGISTER_CLOCK("mxc_spi.0", NULL, cspi1_clk[0]), + _REGISTER_CLOCK("mxc_spi.1", NULL, cspi2_clk[0]), + _REGISTER_CLOCK("mxc_spi.2", NULL, cspi3_clk), + _REGISTER_CLOCK(NULL, "ssi_lp_apm_clk", ssi_lp_apm_clk), + _REGISTER_CLOCK("mxc_ssi.0", NULL, ssi1_clk[0]), + _REGISTER_CLOCK("mxc_ssi.1", NULL, ssi2_clk[0]), + _REGISTER_CLOCK("mxc_ssi.2", NULL, ssi3_clk[0]), + _REGISTER_CLOCK(NULL, "ssi_ext1_clk", ssi_ext1_clk), + _REGISTER_CLOCK(NULL, "ssi_ext2_clk", ssi_ext2_clk), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]), + _REGISTER_CLOCK(NULL, "usb_ahb_clk", usb_ahb_clk), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy_clk[0]), + _REGISTER_CLOCK(NULL, "usb_utmi_clk", usb_utmi_clk), + _REGISTER_CLOCK(NULL, "usb_clk", usb_clk), + _REGISTER_CLOCK("mxsdhci.0", NULL, esdhc1_clk[0]), + _REGISTER_CLOCK("mxsdhci.1", NULL, esdhc2_clk[0]), + _REGISTER_CLOCK("mxsdhci.2", NULL, esdhc3_clk[0]), + _REGISTER_CLOCK("mxsdhci.3", NULL, esdhc4_clk[0]), + _REGISTER_CLOCK(NULL, "emi_slow_clk", emi_slow_clk), + _REGISTER_CLOCK(NULL, "ddr_clk", ddr_clk), + _REGISTER_CLOCK(NULL, "emi_enfc_clk", emi_enfc_clk), + _REGISTER_CLOCK(NULL, "emi_fast_clk", emi_fast_clk), + _REGISTER_CLOCK(NULL, "emi_intr_clk.0", emi_intr_clk[0]), + _REGISTER_CLOCK(NULL, "emi_intr_clk.1", emi_intr_clk[1]), + _REGISTER_CLOCK(NULL, "spdif_xtal_clk", spdif_xtal_clk), + _REGISTER_CLOCK("mxc_alsa_spdif.0", NULL, spdif0_clk[0]), + _REGISTER_CLOCK("mxc_vpu.0", NULL, vpu_clk[0]), + _REGISTER_CLOCK(NULL, "lpsr_clk", lpsr_clk), + _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk), + _REGISTER_CLOCK("pata_fsl", NULL, ata_clk), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK(NULL, "sahara_clk", sahara_clk[0]), + _REGISTER_CLOCK(NULL, "gpu3d_clk", gpu3d_clk), + _REGISTER_CLOCK(NULL, "garb_clk", garb_clk), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_clk), + _REGISTER_CLOCK("mxc_scc.0", NULL, scc_clk[0]), + _REGISTER_CLOCK(NULL, "cko1", cko1_clk), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("fec.0", NULL, fec_clk[0]), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), +}; + +static struct clk_lookup mx51_lookups[] = { + _REGISTER_CLOCK("mxc_i2c_hs.3", NULL, hsi2c_serial_clk), + _REGISTER_CLOCK("mxc_sim.0", NULL, sim_clk[0]), + _REGISTER_CLOCK("mxc_alsa_spdif.0", NULL, spdif1_clk[0]), + _REGISTER_CLOCK(NULL, "mipi_hsp_clk", mipi_hsp_clk), + _REGISTER_CLOCK(NULL, "ddr_hf_clk", ddr_hf_clk), +}; + +static struct clk_lookup mx53_lookups[] = { + _REGISTER_CLOCK(NULL, "pll4", pll4_sw_clk), + _REGISTER_CLOCK("mxcintuart.3", NULL, uart4_clk[0]), + _REGISTER_CLOCK("mxcintuart.4", NULL, uart5_clk[0]), + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk[2]), + _REGISTER_CLOCK(NULL, "usb_phy2_clk", usb_phy_clk[1]), + _REGISTER_CLOCK(NULL, "ocram_clk", ocram_clk), + _REGISTER_CLOCK(NULL, "imx_sata_clk", sata_clk), + _REGISTER_CLOCK(NULL, "ieee_1588_clk", ieee_1588_clk), + _REGISTER_CLOCK(NULL, "ieee_rtc_clk", ieee_rtc_clk), + _REGISTER_CLOCK("mxc_mlb.0", NULL, mlb_clk[0]), + _REGISTER_CLOCK("FlexCAN.0", "can_clk", can1_clk[0]), + _REGISTER_CLOCK("FlexCAN.1", "can_clk", can2_clk[0]), + _REGISTER_CLOCK(NULL, "ldb_di0_clk", ldb_di_clk[0]), + _REGISTER_CLOCK(NULL, "ldb_di1_clk", ldb_di_clk[1]), + _REGISTER_CLOCK(NULL, "esai_clk", esai_clk[0]), + _REGISTER_CLOCK(NULL, "esai_ipg_clk", esai_clk[1]), + _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk[1]), + _REGISTER_CLOCK(NULL, "asrc_serial_clk", asrc_clk[0]), +}; + +static struct mxc_clk mx51_clks[ARRAY_SIZE(lookups) + ARRAY_SIZE(mx51_lookups)]; +static struct mxc_clk mx53_clks[ARRAY_SIZE(lookups) + ARRAY_SIZE(mx53_lookups)]; + +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_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* set pll1_main_clk parent */ + pll1_main_clk.parent = &osc_clk; + + /* set pll2_sw_clk parent */ + pll2_sw_clk.parent = &osc_clk; + + /* set pll3_clk parent */ + pll3_sw_clk.parent = &osc_clk; + + if (cpu_is_mx51()) { + dp_ctl = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll1_main_clk.parent = &fpm_clk; + + dp_ctl = __raw_readl(pll2_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll2_sw_clk.parent = &fpm_clk; + + dp_ctl = __raw_readl(pll3_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll3_sw_clk.parent = &fpm_clk; + } else { + /* set pll4_clk parent */ + pll4_sw_clk.parent = &osc_clk; + } + + /* set emi_slow_clk parent */ + emi_slow_clk.parent = &main_bus_clk; + reg = __raw_readl(MXC_CCM_CBCDR); + if ((reg & MXC_CCM_CBCDR_EMI_CLK_SEL) != 0) + emi_slow_clk.parent = &ahb_clk; + + /* set ipg_perclk parent */ + ipg_perclk.parent = &lp_apm_clk; + reg = __raw_readl(MXC_CCM_CBCMR); + if ((reg & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL) != 0) { + ipg_perclk.parent = &ipg_clk; + } else { + if ((reg & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL) == 0) + ipg_perclk.parent = &main_bus_clk; + } +} + + +int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2) +{ + __iomem void *base; + struct clk *tclk; + int i = 0, j = 0, reg; + int wp_cnt = 0; + u32 pll1_rate; + + pll1_base = ioremap(PLL1_BASE_ADDR, SZ_4K); + pll2_base = ioremap(PLL2_BASE_ADDR, SZ_4K); + pll3_base = ioremap(PLL3_BASE_ADDR, SZ_4K); + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(1 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR4); + + __raw_writel(1 << MXC_CCM_CCGRx_CG2_OFFSET | + 1 << MXC_CCM_CCGR5_CG6_1_OFFSET | + 1 << MXC_CCM_CCGR5_CG6_2_OFFSET | + 3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(1 << MXC_CCM_CCGRx_CG4_OFFSET, MXC_CCM_CCGR6); + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + /* Fix up clocks unique to MX51. */ + esdhc2_clk[0].get_rate = _clk_esdhc2_get_rate; + esdhc2_clk[0].set_rate = _clk_esdhc2_set_rate; + + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + mx51_clks[i].reg_clk = lookups[i].clk; + if (lookups[i].con_id != NULL) + strcpy(mx51_clks[i].name, lookups[i].con_id); + else + strcpy(mx51_clks[i].name, lookups[i].dev_id); + clk_register(&mx51_clks[i]); + } + + j = ARRAY_SIZE(lookups); + for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) { + clkdev_add(&mx51_lookups[i]); + mx51_clks[i+j].reg_clk = mx51_lookups[i].clk; + if (mx51_lookups[i].con_id != NULL) + strcpy(mx51_clks[i+j].name, mx51_lookups[i].con_id); + else + strcpy(mx51_clks[i+j].name, mx51_lookups[i].dev_id); + clk_register(&mx51_clks[i+j]); + } + + max_axi_a_clk = MAX_AXI_A_CLK_MX51; + max_axi_b_clk = MAX_AXI_B_CLK_MX51; + max_ahb_clk = MAX_AHB_CLK_MX51; + max_emi_slow_clk = MAX_AHB_CLK_MX51; + + /* set DDR clock parent */ + reg = 0; + if (cpu_is_mx51_rev(CHIP_REV_2_0) >= 1) { + reg = __raw_readl(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_DDR_HF_SEL; + reg >>= MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET; + + if (reg) + tclk = &ddr_hf_clk; + } + if (reg == 0) { + reg = __raw_readl(MXC_CCM_CBCMR) & + MXC_CCM_CBCMR_DDR_CLK_SEL_MASK; + reg >>= MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; + + if (reg == 0) { + tclk = &axi_a_clk; + } else if (reg == 1) { + tclk = &axi_b_clk; + } else if (reg == 2) { + tclk = &emi_slow_clk; + } else { + tclk = &ahb_clk; + } + } + clk_set_parent(&ddr_clk, tclk); + + /*Setup the LPM bypass bits */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS + | MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX51 + | MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + __raw_writel(reg, MXC_CCM_CLPCR); + + /* Disable the handshake with HSC block as its not + * initialised right now. + */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + clk_enable(&cpu_clk); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk); + clk_set_parent(&esdhc2_clk[0], &pll2_sw_clk); + + /* set SDHC root clock as 166.25MHZ*/ + clk_set_rate(&esdhc1_clk[0], 166250000); + clk_set_rate(&esdhc2_clk[0], 166250000); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + clk_set_parent(&vpu_clk[0], &axi_b_clk); + clk_set_parent(&vpu_clk[1], &axi_b_clk); + clk_set_parent(&gpu3d_clk, &axi_a_clk); + clk_set_parent(&gpu2d_clk, &axi_a_clk); + + /* 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); + + /* + * SSI3 has no clock divide register, + * we always set SSI3 parent clock to SSI1 and freq same to SSI1 + */ + clk_set_parent(&ssi3_clk[0], &ssi1_clk[0]); + + /* 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]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + + /* set usboh3_clk to pll2 */ + clk_set_parent(&usboh3_clk[0], &pll2_sw_clk); + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK; + reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET; + reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + /* Set the current working point. */ + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + /* Update the cpu working point table based on the PLL1 freq + * at boot time + */ + pll1_rate = clk_get_rate(&pll1_main_clk); + if (pll1_rate <= cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) + wp_cnt = 1; + else if (pll1_rate <= cpu_wp_tbl[1].cpu_rate && + pll1_rate > cpu_wp_tbl[2].cpu_rate) + wp_cnt = cpu_wp_nr - 1; + else + wp_cnt = cpu_wp_nr; + + cpu_wp_tbl[0].cpu_rate = pll1_rate; + + if (wp_cnt == 1) { + cpu_wp_tbl[0] = cpu_wp_tbl[cpu_wp_nr - 1]; + memset(&cpu_wp_tbl[cpu_wp_nr - 1], 0, sizeof(struct cpu_wp)); + memset(&cpu_wp_tbl[cpu_wp_nr - 2], 0, sizeof(struct cpu_wp)); + } else if (wp_cnt < cpu_wp_nr) { + for (i = 0; i < wp_cnt; i++) + cpu_wp_tbl[i] = cpu_wp_tbl[i+1]; + memset(&cpu_wp_tbl[i], 0, sizeof(struct cpu_wp)); + } + + if (wp_cnt < cpu_wp_nr) { + set_num_cpu_wp(wp_cnt); + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + } + + pll1_rate = clk_get_rate(&pll1_main_clk); + for (j = 0; j < cpu_wp_nr; j++) { + if ((ddr_clk.parent == &ddr_hf_clk)) { + /* Change the CPU podf divider based on the boot up + * pll1 rate. + */ + cpu_wp_tbl[j].cpu_podf = + (pll1_rate / cpu_wp_tbl[j].cpu_rate) + - 1; + if (pll1_rate / (cpu_wp_tbl[j].cpu_podf + 1) > + cpu_wp_tbl[j].cpu_rate) { + cpu_wp_tbl[j].cpu_podf++; + cpu_wp_tbl[j].cpu_rate = + pll1_rate / + (1000 * (cpu_wp_tbl[j].cpu_podf + 1)); + cpu_wp_tbl[j].cpu_rate *= 1000; + } + if (pll1_rate / (cpu_wp_tbl[j].cpu_podf + 1) < + cpu_wp_tbl[j].cpu_rate) { + cpu_wp_tbl[j].cpu_rate = pll1_rate; + } + } + cpu_wp_tbl[j].pll_rate = pll1_rate; + } + /* Set the current working point. */ + 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(); + + clk_set_parent(&arm_axi_clk, &axi_a_clk); + clk_set_parent(&ipu_clk[0], &axi_b_clk); + + if (uart_at_24) { + /* Move UART to run from lp_apm */ + clk_set_parent(&uart_main_clk, &lp_apm_clk); + + /* Set the UART dividers to divide, so the UART_CLK is 24MHz. */ + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (0 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + (0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CSCDR1); + } else { + clk_set_parent(&uart_main_clk, &pll2_sw_clk); + + /* Set the UART dividers to divide, 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); + } + + clk_set_parent(&emi_slow_clk, &ahb_clk); + clk_set_rate(&emi_slow_clk, clk_round_rate(&emi_slow_clk, 130000000)); + + /* Change the NFC clock rate to be 1:4 ratio with emi clock. */ + clk_set_rate(&emi_enfc_clk, clk_round_rate(&emi_enfc_clk, + (clk_get_rate(&emi_slow_clk))/4)); + + base = ioremap(GPT1_BASE_ADDR, SZ_4K); + mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT); + return 0; +} + +int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2) +{ + __iomem void *base; + struct clk *tclk; + int i = 0, j = 0, reg; + u32 pll1_rate; + + pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K); + pll2_base = ioremap(MX53_BASE_ADDR(PLL2_BASE_ADDR), SZ_4K); + pll3_base = ioremap(MX53_BASE_ADDR(PLL3_BASE_ADDR), SZ_4K); + pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K); + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(1 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR4); + + __raw_writel(1 << MXC_CCM_CCGRx_CG2_OFFSET | + 1 << MXC_CCM_CCGRx_CG6_OFFSET | + 3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG9_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG12_OFFSET | + 3 << MXC_CCM_CCGRx_CG13_OFFSET , MXC_CCM_CCGR6); + + __raw_writel(0, MXC_CCM_CCGR7); + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + usb_phy_clk[0].enable_reg = MXC_CCM_CCGR4; + usb_phy_clk[0].enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + + ipumux1_clk.enable_reg = MXC_CCM_CCGR5; + ipumux1_clk.enable_shift = MXC_CCM_CCGRx_CG6_OFFSET; + ipumux2_clk.enable_reg = MXC_CCM_CCGR6; + ipumux2_clk.enable_shift = MXC_CCM_CCGRx_CG0_OFFSET; + + esdhc3_clk[0].get_rate = _clk_esdhc3_get_rate; + esdhc3_clk[0].set_rate = _clk_sdhc3_set_rate; + +#if defined(CONFIG_USB_STATIC_IRAM) \ + || defined(CONFIG_USB_STATIC_IRAM_PPH) + usboh3_clk[1].secondary = &emi_intr_clk[1]; +#endif +#ifdef CONFIG_SND_MXC_SOC_IRAM + ssi2_clk[2].secondary = &emi_intr_clk[1]; + ssi1_clk[2].secondary = &emi_intr_clk[1]; +#endif +#ifdef CONFIG_SDMA_IRAM + sdma_clk[1].secondary = &emi_intr_clk[1]; +#endif + + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + mx53_clks[i].reg_clk = lookups[i].clk; + if (lookups[i].con_id != NULL) + strcpy(mx53_clks[i].name, lookups[i].con_id); + else + strcpy(mx53_clks[i].name, lookups[i].dev_id); + clk_register(&mx53_clks[i]); + } + + j = ARRAY_SIZE(lookups); + for (i = 0; i < ARRAY_SIZE(mx53_lookups); i++) { + clkdev_add(&mx53_lookups[i]); + mx53_clks[i+j].reg_clk = mx53_lookups[i].clk; + if (mx53_lookups[i].con_id != NULL) + strcpy(mx53_clks[i+j].name, mx53_lookups[i].con_id); + else + strcpy(mx53_clks[i+j].name, mx53_lookups[i].dev_id); + clk_register(&mx53_clks[i+j]); + } + + clk_set_parent(&esai_clk[0], &ckih_clk); + + ldb_di_clk[0].parent = ldb_di_clk[1].parent = + tve_clk.parent = &pll4_sw_clk; + + max_axi_a_clk = MAX_AXI_A_CLK_MX53; + max_axi_b_clk = MAX_AXI_B_CLK_MX53; + max_ahb_clk = MAX_AHB_CLK_MX53; + max_emi_slow_clk = MAX_AHB_CLK_MX53; + + + /* set DDR clock parent */ + reg = __raw_readl(MXC_CCM_CBCMR) & + MXC_CCM_CBCMR_DDR_CLK_SEL_MASK; + reg >>= MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; + if (reg == 0) { + tclk = &axi_a_clk; + } else if (reg == 1) { + tclk = &axi_b_clk; + } else if (reg == 2) { + tclk = &emi_slow_clk; + } else { + tclk = &ahb_clk; + } + clk_set_parent(&ddr_clk, tclk); + + clk_set_parent(&esdhc1_clk[2], &tmax2_clk); + clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]); + clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk); + + clk_set_parent(&ipu_di_clk[0], &pll4_sw_clk); + +#if 0 + /*Setup the LPM bypass bits */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS + | MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +#endif + + clk_enable(&cpu_clk); + + clk_enable(&main_bus_clk); + + /* Set AXI_B_CLK to be 200MHz */ + clk_set_rate(&axi_b_clk, 200000000); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + + clk_set_parent(&vpu_clk[0], &axi_b_clk); + clk_set_parent(&vpu_clk[1], &axi_b_clk); + + /* 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 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 PLL2 for camera */ + clk_disable(&ssi_ext1_clk); + clk_set_parent(&ssi_ext1_clk, &pll2_sw_clk); + clk_set_rate(&ssi_ext1_clk, 24000000); + clk_enable(&ssi_ext1_clk); + clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + clk_set_parent(&usb_phy_clk[1], &osc_clk); + + /* set usboh3_clk to pll2 */ + clk_set_parent(&usboh3_clk[0], &pll2_sw_clk); + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK; + reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET; + reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + /* set SDHC root clock as 200MHZ*/ + clk_set_rate(&esdhc1_clk[0], 200000000); + clk_set_rate(&esdhc3_clk[0], 200000000); + + /* Set the 1588 RTC input clocks as 108MHZ */ + clk_set_parent(&ieee_rtc_clk, &pll3_sw_clk); + clk_set_rate(&ieee_rtc_clk, 108000000); + + /* The CPU working point should be set according to part number + * information. But part number information is not clear now. + * So update the cpu working point table based on the PLL1 freq + * at boot time + */ + pll1_rate = clk_get_rate(&pll1_main_clk); + + if (pll1_rate > 1000000000) + mx53_set_cpu_part_number(IMX53_CEC_1_2G); + else if (pll1_rate > 800000000) + mx53_set_cpu_part_number(IMX53_CEC); + else + mx53_set_cpu_part_number(IMX53_AEC); + + /* 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(); + + clk_set_parent(&arm_axi_clk, &axi_b_clk); + clk_set_parent(&ipu_clk[0], &axi_b_clk); + clk_set_parent(&uart_main_clk, &pll3_sw_clk); + clk_set_parent(&gpu3d_clk, &axi_b_clk); + clk_set_parent(&gpu2d_clk, &axi_b_clk); + + clk_set_parent(&emi_slow_clk, &ahb_clk); + clk_set_rate(&emi_slow_clk, clk_round_rate(&emi_slow_clk, 133333333)); + + clk_set_rate(&emi_enfc_clk, clk_round_rate(&emi_enfc_clk, + MAX_NFC_CLK)); + + /* set the freq of asrc_serial_clk */ + clk_set_rate(&asrc_clk[0], clk_round_rate(&asrc_clk[0], + 1190000)); + base = ioremap(MX53_BASE_ADDR(GPT1_BASE_ADDR), SZ_4K); + mxc_timer_init(&gpt_clk[0], base, 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, pll_hfsm; + u32 stat; + + if (wp == cpu_curr_wp) + return 0; + + p = &cpu_wp_tbl[wp]; + + /* + * If DDR clock is sourced from PLL1, we cannot drop PLL1 freq. + * Use the ARM_PODF to change the freq of the core, leave the PLL1 + * freq unchanged. Meanwhile, if pll_rate is same, use the ARM_PODF + * to change the freq of core + */ + if ((ddr_clk.parent == &ddr_hf_clk) || + (p->pll_rate == cpu_wp_tbl[cpu_curr_wp].pll_rate)) { + reg = __raw_readl(MXC_CCM_CACRR); + reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; + reg |= cpu_wp_tbl[wp].cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CACRR); + cpu_curr_wp = wp; + } else { + struct timespec nstimeofday; + struct timespec curtime; + + /* 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(pll1_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + + reg = __raw_readl(MXC_CCM_CACRR); + reg = (reg & ~MXC_CCM_CACRR_ARM_PODF_MASK) + | p->cpu_podf; + __raw_writel(reg, MXC_CCM_CACRR); + + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + pll_hfsm = reg & MXC_PLL_DP_CTL_HFSM; + /* PDF and MFI */ + reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; + if (pll_hfsm == 0) { + __raw_writel(reg, pll1_base + MXC_PLL_DP_OP); + __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_MFD); + __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_MFN); + } else { + __raw_writel(reg, pll1_base + MXC_PLL_DP_HFS_OP); + __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_HFS_MFD); + __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_HFS_MFN); + } + + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg |= MXC_PLL_DP_CTL_UPEN; + /* Set the UPEN bits */ + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + /* Forcefully restart the PLL */ + reg |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + + /* Wait for the PLL to lock */ + getnstimeofday(&nstimeofday); + do { + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("pll1 relock failed\n"); + stat = __raw_readl(pll1_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; + } + +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + return 0; +} diff --git a/arch/arm/mach-mx5/clock_mx50.c b/arch/arm/mach-mx5/clock_mx50.c new file mode 100644 index 000000000000..87eee08fdbb5 --- /dev/null +++ b/arch/arm/mach-mx5/clock_mx50.c @@ -0,0 +1,3523 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/hrtimer.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <asm/clkdev.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> + +#include "crm_regs.h" +#include "serial.h" + +/* External clock values passed-in by the board code */ +static unsigned long external_high_reference, external_low_reference; +static unsigned long oscillator_reference, ckih2_reference; + +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 apbh_dma_clk; +static struct clk apll_clk; +static struct clk pfd0_clk; +static struct clk pfd1_clk; +static struct clk pfd2_clk; +static struct clk pfd3_clk; +static struct clk pfd4_clk; +static struct clk pfd5_clk; +static struct clk pfd6_clk; +static struct clk pfd7_clk; +static struct clk lp_apm_clk; +static struct clk weim_clk[]; +static struct clk ddr_clk; +static struct clk axi_a_clk; +static struct clk axi_b_clk; +static struct clk gpu2d_clk; +static int cpu_curr_wp; +static struct cpu_wp *cpu_wp_tbl; + +static void __iomem *pll1_base; +static void __iomem *pll2_base; +static void __iomem *pll3_base; +void __iomem *apll_base; + +extern int cpu_wp_nr; +extern int lp_high_freq; +extern int lp_med_freq; + +void __iomem *databahn; + +#define DDR_SYNC_MODE 0x30000 +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define WAIT(exp, timeout) \ +({ \ + struct timespec nstimeofday; \ + struct timespec curtime; \ + int result = 1; \ + getnstimeofday(&nstimeofday); \ + while (!(exp)) { \ + getnstimeofday(&curtime); \ + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > (timeout)) { \ + result = 0; \ + break; \ + } \ + } \ + result; \ +}) + +#define MAX_AXI_A_CLK_MX50 400000000 +#define MAX_AXI_B_CLK_MX50 200000000 +#define MAX_AHB_CLK 133333333 +#define MAX_EMI_SLOW_CLK 133000000 + +extern int mxc_jtag_enabled; +extern int uart_at_24; +extern int cpufreq_trig_needed; +extern int low_bus_freq_mode; +extern int med_bus_freq_mode; + +static int cpu_clk_set_wp(int wp); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); + +static struct clk esdhc3_clk[]; + +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 8) { + min_pre = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = (div + *pre - 1) / *pre; + } else if (div < 8) { + *pre = div; + *post = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq++; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq++; + + return 0; +} + +static int _clk_enable_inrun(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << 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_CCGRx_CG_MASK << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq--; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq--; +} + +static void _clk_disable_inwait(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); +} + +static unsigned long _clk_round_rate_div(struct clk *clk, + unsigned long rate, + u32 max_div, + u32 *new_div) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = DIV_ROUND_UP(parent_rate, rate); + if (div > max_div) + div = max_div; + else if (div == 0) + div++; + if (new_div != NULL) + *new_div = div; + + return parent_rate / div; +} +/* + * 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; +} + +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux8(struct clk *parent, struct clk *m0, struct clk *m1, + struct clk *m2, struct clk *m3, struct clk *m4, + struct clk *m5, struct clk *m6, struct clk *m7) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else if (parent == m4) + return 4; + else if (parent == m5) + return 5; + else if (parent == m6) + return 6; + else if (parent == m7) + return 7; + else + BUG(); + + return 0; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return pll1_base; + else if (pll == &pll2_sw_clk) + return pll2_base; + else if (pll == &pll3_sw_clk) + return pll3_base; + else + BUG(); + + return NULL; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) +{ + return ckih2_reference; +} + +/* External high frequency clock */ +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk ckih2_clk = { + .get_rate = get_ckih2_reference_clock_rate, +}; + +static struct clk osc_clk = { + .get_rate = get_oscillator_reference_clock_rate, +}; + +/* External low frequency (32kHz) clock */ +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + +static int apll_enable(struct clk *clk) +{ + __raw_writel(1, apll_base + MXC_ANADIG_MISC_SET); + return 0; +} + +static void apll_disable(struct clk *clk) +{ + __raw_writel(1, apll_base + MXC_ANADIG_MISC_CLR); +} + +static unsigned long apll_get_rate(struct clk *clk) +{ + return 480000000; +} + +static struct clk apll_clk = { + .get_rate = apll_get_rate, + .enable = apll_enable, + .disable = apll_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, rate); + frac = tmp; + frac = frac < 18 ? 18 : frac; + frac = frac > 35 ? 35 : frac; + do_div(tmp, frac); + return tmp; +} + +static int pfd_set_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + tmp = (u64)clk_get_rate(clk->parent) * 18; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + do_div(tmp, rate); + frac = tmp; + frac = frac < 18 ? 18 : frac; + frac = frac > 35 ? 35 : frac; + /* clear clk frac bits */ + __raw_writel(MXC_ANADIG_PFD_FRAC_MASK << clk->enable_shift, + apll_base + (int)clk->enable_reg + 8); + /* set clk frac bits */ + __raw_writel(frac << clk->enable_shift, + apll_base + (int)clk->enable_reg + 4); + + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + return 0; +} + +static int pfd_enable(struct clk *clk) +{ + int index; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + index = _get_mux8(clk, &pfd0_clk, &pfd1_clk, &pfd2_clk, &pfd3_clk, + &pfd4_clk, &pfd5_clk, &pfd6_clk, &pfd7_clk); + __raw_writel(1 << (index + MXC_ANADIG_PFD_DIS_OFFSET), + apll_base + MXC_ANADIG_PLLCTRL_CLR); + /* clear clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + apll_base + (int)clk->enable_reg + 8); + + /* check lock bit */ + if (!WAIT(__raw_readl(apll_base + MXC_ANADIG_PLLCTRL) + & MXC_ANADIG_APLL_LOCK, 50000)) { + __raw_writel(MXC_ANADIG_APLL_FORCE_LOCK, + apll_base + MXC_ANADIG_PLLCTRL_CLR); + __raw_writel(MXC_ANADIG_APLL_FORCE_LOCK, + apll_base + MXC_ANADIG_PLLCTRL_SET); + if (!WAIT(__raw_readl(apll_base + MXC_ANADIG_PLLCTRL) + & MXC_ANADIG_APLL_LOCK, SPIN_DELAY)) + panic("pfd_enable failed!\n"); + } + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + return 0; +} + +static void pfd_disable(struct clk *clk) +{ + int index; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + index = _get_mux8(clk, &pfd0_clk, &pfd1_clk, &pfd2_clk, &pfd3_clk, + &pfd4_clk, &pfd5_clk, &pfd6_clk, &pfd7_clk); + /* set clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + apll_base + (int)clk->enable_reg + 4); + __raw_writel(1 << (index + MXC_ANADIG_PFD_DIS_OFFSET), + apll_base + MXC_ANADIG_PLLCTRL_SET); + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); +} + +static struct clk pfd0_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD0_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd1_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD1_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd2_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD2_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd3_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD3_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd4_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD4_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd5_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD5_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd6_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD6_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd7_clk = { + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD7_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_pll_get_rate(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; + void __iomem *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_get_rate(clk->parent); + 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; + + return temp; +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, reg1; + void __iomem *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_get_rate(clk->parent); + 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); + } + /* If auto restart is disabled, restart the PLL and + * wait for it to lock. + */ + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_UPEN) { + reg = __raw_readl(pllbase + MXC_PLL_DP_CONFIG); + if (!(reg & MXC_PLL_DP_CONFIG_AREN)) { + reg1 = __raw_readl(pllbase + MXC_PLL_DP_CTL); + reg1 |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg1, pllbase + MXC_PLL_DP_CTL); + } + /* Wait for lock */ + if (!WAIT(__raw_readl(pllbase + MXC_PLL_DP_CTL) + & MXC_PLL_DP_CTL_LRF, SPIN_DELAY)) + panic("pll_set_rate: pll relock failed\n"); + } + return 0; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + + if (reg & MXC_PLL_DP_CTL_UPEN) + return 0; + + reg |= MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + if (!WAIT(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF, + SPIN_DELAY)) + panic("pll relock failed\n"); + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + void __iomem *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 = { + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .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; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set the step_clk parent to be lp_apm, to save power. */ + mux = _get_mux(&lp_apm_clk, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == &lp_apm_clk) { + 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; + } 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 unsigned long _clk_pll1_sw_get_rate(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; + } + return clk_get_rate(clk->parent) / div; +} + +/* pll1 switch clock */ +static struct clk pll1_sw_clk = { + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll2_sw_clk) { + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } else { + reg = (reg & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL); + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +/* same as pll2_main_clk. These two clocks should always be the same */ +static struct clk pll2_sw_clk = { + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll_set_rate, + .set_parent = _clk_pll2_sw_set_parent, + .flags = RATE_PROPAGATES, +}; + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_sw_clk = { + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .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 == &apll_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 = { + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_arm_get_rate(struct clk *clk) +{ + u32 cacrr, div; + + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + return clk_get_rate(clk->parent) / 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 = { + .parent = &pll1_sw_clk, + .get_rate = _clk_arm_get_rate, + .set_rate = _clk_cpu_set_rate, + .round_rate = _clk_cpu_round_rate, +}; + +/* TODO: Need to sync with GPC to determine if DVFS is in place so that + * the DVFS_PODF divider can be applied in CDCR register. + */ +static unsigned long _clk_main_bus_get_rate(struct clk *clk) +{ + u32 div = 0; + + if (med_bus_freq_mode) + div = (__raw_readl(MXC_CCM_CDCR) & 0x3); + return clk_get_rate(clk->parent) / (div + 1); +} + +static int _clk_main_bus_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_CBCDR) & ~MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK; + reg |= (mux << MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static struct clk main_bus_clk = { + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, + .get_rate = _clk_main_bus_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_a_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_A_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_A_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_a_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_A_PODF_BUSY), SPIN_DELAY)) + panic("pll _clk_axi_a_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_a_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + + if (div > 8) + div = 8; + else if (div == 0) + div++; + + return parent_rate / div; +} + + +static struct clk axi_a_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_axi_a_get_rate, + .set_rate = _clk_axi_a_set_rate, + .round_rate = _clk_axi_a_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_b_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_B_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_B_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_b_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_B_PODF_BUSY), SPIN_DELAY)) + panic("_clk_axi_b_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_b_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + + if (div > 8) + div = 8; + else if (div == 0) + div++; + + return parent_rate / div; +} + + +static struct clk axi_b_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_axi_b_get_rate, + .set_rate = _clk_axi_b_set_rate, + .round_rate = _clk_axi_b_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ahb_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AHB_PODF_BUSY), + SPIN_DELAY)) + panic("_clk_ahb_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > MAX_AHB_CLK) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk ahb_clk = { + .parent = &main_bus_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_max_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with MAX when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + + +static void _clk_max_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable_inwait(clk); + + /* No Handshake with MAX when LPM is entered as its disabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk ahb_max_clk = { + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, +}; + +static struct clk ahbmux1_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, +}; + +static unsigned long _clk_ipg_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static struct clk ipg_clk = { + .parent = &ahb_clk, + .get_rate = _clk_ipg_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ipg_per_get_rate(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_CBCDR); + prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) { + return clk_get_rate(&ipg_clk); + } + BUG(); + return 0; +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &main_bus_clk, &lp_apm_clk, &ipg_clk, NULL); + if (mux == 2) { + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + } else { + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + if (mux == 0) + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk ipg_perclk = { + .parent = &lp_apm_clk, + .get_rate = _clk_ipg_per_get_rate, + .set_parent = _clk_ipg_per_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk ipmux1_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk ipmux2_clk = { + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sys_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~(MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK | + MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK); + if (__raw_readl(MXC_CCM_CLKSEQ_BYPASS) & 0x1) + reg |= MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK; + else + reg |= MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_SYS); + return 0; +} + +static void _clk_sys_clk_disable(struct clk *clk) +{ + u32 reg, reg1; + + reg1 = (__raw_readl(databahn + DATABAHN_CTL_REG55)) + & DDR_SYNC_MODE; + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~(MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK | + MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK); + if (__raw_readl(MXC_CCM_CLKSEQ_BYPASS) & 0x1) + reg |= 1 << MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET; + else { + /* If DDR is sourced from SYS_CLK (in Sync mode), we cannot + * gate its clock when ARM is in wait if the DDR is not in + * self refresh. + */ + if (reg1 == DDR_SYNC_MODE) + reg |= 3 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET; + else + reg |= 1 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET; + } + __raw_writel(reg, MXC_CCM_CLK_SYS); +} + +static struct clk sys_clk = { + .enable = _clk_sys_clk_enable, + .disable = _clk_sys_clk_disable, +}; + + +static int _clk_weim_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCDR); + if (parent == &ahb_clk) + reg |= MX50_CCM_CBCDR_WEIM_CLK_SEL; + else if (parent == &main_bus_clk) + reg &= ~MX50_CCM_CBCDR_WEIM_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static int _clk_weim_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_EMI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_EMI_PODF_BUSY), + SPIN_DELAY)) + panic("_clk_emi_slow_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_weim_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; +} + +static struct clk weim_clk[] = { + { + .parent = &main_bus_clk, + .set_parent = _clk_weim_set_parent, + .set_rate = _clk_weim_set_rate, + .round_rate = _clk_weim_round_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, + .flags = RATE_PROPAGATES, + .secondary = &weim_clk[1], + }, + { + .parent = &ipg_clk, + .secondary = &sys_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = _clk_disable_inwait, + } +}; + +static int _clk_ocram_enable(struct clk *clk) +{ + return 0; +} + +static void _clk_ocram_disable(struct clk *clk) +{ +} + +static struct clk ocram_clk = { + .parent = &sys_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_ocram_enable, + .disable = _clk_ocram_disable, +}; + +static struct clk aips_tz1_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sdma_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with SDMA when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_sdma_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with SDMA as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk sdma_clk[] = { + { + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_sdma_enable, + .disable = _clk_sdma_disable, + }, + { + .parent = &ipg_clk, + .secondary = &ddr_clk, + }, +}; + +static struct clk spba_clk = { + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_uart_get_rate(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; + + return clk_get_rate(clk->parent)/(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 struct clk uart_main_clk = { + .parent = &pll2_sw_clk, + .get_rate = _clk_uart_get_rate, + .set_parent = _clk_uart_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk uart1_clk[] = { + { + .id = 0, + .parent = &uart_main_clk, + .secondary = &uart1_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART1_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 0, + .parent = &ipg_clk, +#if UART1_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + .id = 1, + .parent = &uart_main_clk, + .secondary = &uart2_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART2_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 1, + .parent = &ipg_clk, +#if UART2_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + .id = 2, + .parent = &uart_main_clk, + .secondary = &uart3_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART3_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 2, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart4_clk[] = { + { + .id = 3, + .parent = &uart_main_clk, + .secondary = &uart4_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART4_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 3, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart5_clk[] = { + { + .id = 4, + .parent = &uart_main_clk, + .secondary = &uart5_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART5_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + .id = 4, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_clk[] = { + { + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm1_clk[] = { + { + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm2_clk[] = { + { + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ckil_clk, + }, +}; + +static struct clk i2c_clk[] = { + { + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_cspi_get_rate(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; + + return clk_get_rate(clk->parent) / (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 struct clk cspi_main_clk = { + .parent = &pll3_sw_clk, + .get_rate = _clk_cspi_get_rate, + .set_parent = _clk_cspi_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk cspi1_clk[] = { + { + .id = 0, + .parent = &cspi_main_clk, + .secondary = &cspi1_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi2_clk[] = { + { + .id = 1, + .parent = &cspi_main_clk, + .secondary = &cspi2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi3_clk = { + .id = 2, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &aips_tz2_clk, +}; + +static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ckih_clk, &lp_apm_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_lp_apm_clk = { + .parent = &ckih_clk, + .set_parent = _clk_ssi_lp_apm_set_parent, +}; + +static unsigned long _clk_ssi1_get_rate(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; + + return clk_get_rate(clk->parent) / (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[] = { + { + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi1_set_parent, + .secondary = &ssi1_clk[1], + .get_rate = _clk_ssi1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &ssi1_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &aips_tz2_clk, + }, +}; + +static unsigned long _clk_ssi2_get_rate(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; + + return clk_get_rate(clk->parent) / (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[] = { + { + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi2_set_parent, + .secondary = &ssi2_clk[1], + .get_rate = _clk_ssi2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &ssi2_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &spba_clk, + }, +}; + +static unsigned long _clk_ssi_ext1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +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 unsigned long _clk_ssi_ext1_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk ssi_ext1_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext1_set_parent, + .set_rate = _clk_ssi_ext1_set_rate, + .round_rate = _clk_ssi_ext1_round_rate, + .get_rate = _clk_ssi_ext1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_ssi_ext2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +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 = { + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext2_set_parent, + .get_rate = _clk_ssi_ext2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk tmax2_clk = { + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk usb_ahb_clk = { + .parent = &ipg_clk, + .secondary = &ddr_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk usb_phy_clk[] = { + { + .id = 0, + .parent = &osc_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &osc_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk esdhc_dep_clks = { + .parent = &spba_clk, + .secondary = &ddr_clk, +}; + +static unsigned long _clk_esdhc1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_esdhc1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = reg & ~MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK; + reg |= mux << MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static int _clk_esdhc1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk esdhc1_clk[] = { + { + .id = 0, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc1_set_parent, + .get_rate = _clk_esdhc1_get_rate, + .set_rate = _clk_esdhc1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 0, + .parent = &ipg_clk, + .secondary = &esdhc1_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, + +}; + +static int _clk_esdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MX50_CCM_CSCMR1_ESDHC2_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MX50_CCM_CSCMR1_ESDHC2_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk esdhc2_clk[] = { + { + .id = 1, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc2_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 1, + .parent = &ipg_clk, + .secondary = &esdhc2_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + mux = _get_mux8(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &lp_apm_clk, &pfd0_clk, + &pfd1_clk, &pfd4_clk, &osc_clk); + reg = reg & ~MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK; + reg |= mux << MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_esdhc3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_esdhc3_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk esdhc3_clk[] = { + { + .id = 2, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc3_set_parent, + .get_rate = _clk_esdhc3_get_rate, + .set_rate = _clk_esdhc3_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 2, + .parent = &ipg_clk, + .secondary = &esdhc3_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MX50_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MX50_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc4_clk[] = { + { + .id = 3, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc4_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc4_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .id = 3, + .parent = &ipg_clk, + .secondary = &esdhc4_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + }, + { + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_ddr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CLK_DDR); + if (parent == &pfd0_clk) + reg |= MXC_CCM_CLK_DDR_DDR_PFD_SEL; + else if (parent == &pll1_sw_clk) + reg &= ~MXC_CCM_CLK_DDR_DDR_PFD_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CLK_DDR); + return 0; +} + +static unsigned long _clk_ddr_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CLK_DDR); + div = (reg & MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK) >> + MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET; + if (div) + return clk_get_rate(clk->parent) / div; + + return 0; +} + +static int _clk_ddr_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = (__raw_readl(databahn + DATABAHN_CTL_REG55)) & + DDR_SYNC_MODE; + if (reg != DDR_SYNC_MODE) { + reg = __raw_readl(MXC_CCM_CLK_DDR); + reg |= MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_DDR); + } + return 0; +} + +static void _clk_ddr_disable(struct clk *clk) +{ + _clk_disable_inwait(clk); +} + + +static struct clk ddr_clk = { + .parent = &pll1_sw_clk, + .secondary = &sys_clk, + .set_parent = _clk_ddr_set_parent, + .get_rate = _clk_ddr_get_rate, + .enable = _clk_ddr_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_ddr_disable, +}; + +static unsigned long _clk_pgc_get_rate(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; + return clk_get_rate(clk->parent) / div; +} + +static struct clk pgc_clk = { + .parent = &ipg_clk, + .get_rate = _clk_pgc_get_rate, +}; + +static unsigned long _clk_usb_get_rate(struct clk *clk) +{ + return 60000000; +} + +/*usb OTG clock */ +static struct clk usb_clk = { + .get_rate = _clk_usb_get_rate, +}; + +static struct clk rtc_clk = { + .parent = &ckil_clk, + .secondary = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, +}; + +struct clk rng_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk owire_clk = { + .parent = &ipg_perclk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + +static struct clk fec_clk[] = { + { + .parent = &ipg_clk, + .secondary = &fec_clk[1], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &aips_tz2_clk, + .secondary = &ddr_clk, + }, +}; + +static int gpmi_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_GPMI); + reg |= MXC_CCM_GPMI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_GPMI); + _clk_enable(clk); + return 0; +} + +static void gpmi_clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_GPMI); + reg &= ~MXC_CCM_GPMI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_GPMI); + _clk_disable(clk); +} + +static int bch_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_BCH); + reg |= MXC_CCM_BCH_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_BCH); + _clk_enable(clk); + return 0; +} + +static void bch_clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_BCH); + reg &= ~MXC_CCM_BCH_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_BCH); + _clk_disable(clk); +} + +static int gpmi_set_parent(struct clk *clk, struct clk *parent) +{ + /* Setting for ONFI nand which need PLL1(800MHZ) */ + if (parent == &pll1_main_clk) { + u32 reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_MASK) | + (0x2 << MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_OFFSET); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_MASK) | + (0x2 << MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + /* change to the new Parent */ + clk->parent = parent; + } else + printk(KERN_WARNING "You should not call the %s\n", __func__); + return 0; +} + +static int gpmi_set_rate(struct clk *clk, unsigned long rate) +{ + /* Setting for ONFI nand which in different mode */ + if (clk->parent == &pll1_main_clk) { + u32 value; + u32 reg; + + value = clk_get_rate(clk->parent); + value /= rate; + value /= 2; /* HW_GPMI_CTRL1's GPMI_CLK_DIV2_EN will be set */ + + /* set GPMI clock */ + reg = __raw_readl(MXC_CCM_GPMI); + reg = (reg & ~MXC_CCM_GPMI_CLK_DIV_MASK) | value; + __raw_writel(reg, MXC_CCM_GPMI); + + /* set BCH clock */ + reg = __raw_readl(MXC_CCM_BCH); + reg = (reg & ~MXC_CCM_BCH_CLK_DIV_MASK) | value; + __raw_writel(reg, MXC_CCM_BCH); + } else + printk(KERN_WARNING "You should not call the %s\n", __func__); + return 0; +} + +static struct clk gpmi_nfc_clk[] = { + { /* gpmi_io_clk */ + .parent = &osc_clk, + .secondary = &gpmi_nfc_clk[1], + .set_parent = gpmi_set_parent, + .set_rate = gpmi_set_rate, + .enable = gpmi_clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = gpmi_clk_disable, + }, + { /* gpmi_apb_clk */ + .parent = &ahb_clk, + .secondary = &gpmi_nfc_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable, + }, + { /* bch_clk */ + .parent = &osc_clk, + .secondary = &gpmi_nfc_clk[3], + .enable = bch_clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = bch_clk_disable, + }, + { /* bch_apb_clk */ + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk ocotp_clk = { + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &weim_clk[0], &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_clk = { + .parent = &axi_a_clk, + .secondary = &ddr_clk, + .set_parent = _clk_gpu2d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk apbh_dma_clk = { + .parent = &ahb_clk, + .secondary = &ddr_clk, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, +}; + +struct clk dcp_clk = { + .parent = &ahb_clk, + .secondary = &apbh_dma_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_display_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd2_clk, &pll1_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_display_axi_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_DISPLAY_AXI); + div &= MXC_CCM_DISPLAY_AXI_DIV_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_display_axi_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 6) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_display_axi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 6) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg &= ~MXC_CCM_DISPLAY_AXI_DIV_MASK; + reg |= new_div << MXC_CCM_DISPLAY_AXI_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_DISPLAY_AXI_BUSY) + ; + return 0; +} + +static struct clk display_axi_clk = { + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .set_parent = _clk_display_axi_set_parent, + .get_rate = _clk_display_axi_get_rate, + .set_rate = _clk_display_axi_set_rate, + .round_rate = _clk_display_axi_round_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_DISPLAY_AXI, + .enable_shift = MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_pxp_axi_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Set the auto-slow bits */ + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg |= (MXC_CCM_DISPLAY_AXI_PXP_ASM_EN); + reg |= (5 << MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_OFFSET); + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + return 0; +} + +static void _clk_pxp_axi_disable(struct clk *clk) +{ + u32 reg; + + /* clear the auto-slow bits */ + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg &= ~MXC_CCM_DISPLAY_AXI_PXP_ASM_EN; + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + _clk_disable(clk); +} + + +/* TODO: check Auto-Slow Mode */ +static struct clk pxp_axi_clk = { + .parent = &display_axi_clk, + .enable = _clk_pxp_axi_enable, + .disable = _clk_pxp_axi_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk elcdif_axi_clk = { + .parent = &display_axi_clk, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_elcdif_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd6_clk, &pll1_sw_clk, &ckih_clk); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_elcdif_pix_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + prediv = ((reg & MXC_CCM_ELCDIFPIX_CLK_PRED_MASK) >> + MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_ELCDIFPIX_CLK_PODF_MASK) >> + MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static unsigned long _clk_elcdif_pix_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 12) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_elcdif_pix_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 12) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + /* Pre-divider set to 1 - only use PODF for clk dividing */ + reg &= ~MXC_CCM_ELCDIFPIX_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET; + reg &= ~MXC_CCM_ELCDIFPIX_CLK_PODF_MASK; + reg |= new_div << MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + + return 0; +} + +static int _clk_elcdif_pix_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + reg |= 0x3 << MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + return 0; +} + +static void _clk_elcdif_pix_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + reg &= ~MXC_CCM_ELCDIFPIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + _clk_disable(clk); +} + +static struct clk elcdif_pix_clk = { + .parent = &osc_clk, + .secondary = &ddr_clk, + .enable = _clk_elcdif_pix_enable, + .disable = _clk_elcdif_pix_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .set_parent = _clk_elcdif_pix_set_parent, + .get_rate = _clk_elcdif_pix_get_rate, + .round_rate = _clk_elcdif_pix_round_rate, + .set_rate = _clk_elcdif_pix_set_rate, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_epdc_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd3_clk, &pll1_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_epdc_axi_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_EPDC_AXI); + div &= MXC_CCM_EPDC_AXI_DIV_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_epdc_axi_round_rate_div(struct clk *clk, + unsigned long rate, + u32 *new_div) +{ + u32 div, max_div; + + max_div = (2 << 6) - 1; + div = DIV_ROUND_UP(clk_get_rate(clk->parent), rate); + if (div > max_div) + div = max_div; + else if (div == 0) + div++; + if (new_div != NULL) + *new_div = div; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_epdc_axi_round_rate(struct clk *clk, + unsigned long rate) +{ + return _clk_epdc_axi_round_rate_div(clk, rate, NULL); +} + +static int _clk_epdc_axi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div; + u32 reg; + + _clk_epdc_axi_round_rate_div(clk, rate, &new_div); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_DIV_MASK; + reg |= new_div << MXC_CCM_EPDC_AXI_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_EPDC_AXI_BUSY) + ; + + return 0; +} + +static int _clk_epdc_axi_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg |= MXC_CCM_EPDC_AXI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + /* Set the auto-slow bits */ + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg |= (MXC_CCM_EPDC_AXI_ASM_EN); + reg |= (5 << MXC_CCM_EPDC_AXI_ASM_DIV_OFFSET); + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + return 0; +} + +static void _clk_epdc_axi_disable(struct clk *clk) +{ + u32 reg; + + /* clear the auto-slow bits */ + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_ASM_EN; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + _clk_disable(clk); +} + +/* TODO: check Auto-Slow Mode */ +static struct clk epdc_axi_clk = { + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .set_parent = _clk_epdc_axi_set_parent, + .get_rate = _clk_epdc_axi_get_rate, + .set_rate = _clk_epdc_axi_set_rate, + .round_rate = _clk_epdc_axi_round_rate, + .enable = _clk_epdc_axi_enable, + .disable = _clk_epdc_axi_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + + +static int _clk_epdc_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd5_clk, &pll1_sw_clk, &ckih_clk); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_epdc_pix_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_EPDCPIX); + div &= MXC_CCM_EPDC_PIX_CLK_PODF_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_epdc_pix_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 12) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_epdc_pix_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 12) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_EPDCPIX); + /* Pre-divider set to 1 - only use PODF for clk dividing */ + reg &= ~MXC_CCM_EPDC_PIX_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET; + reg &= ~MXC_CCM_EPDC_PIX_CLK_PODF_MASK; + reg |= new_div << MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_EPDCPIX); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_EPDC_PIX_BUSY) + ; + + return 0; +} + +static int _clk_epdc_pix_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = __raw_readl(MXC_CCM_EPDCPIX); + reg |= MXC_CCM_EPDC_PIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDCPIX); + + return 0; +} + +static void _clk_epdc_pix_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_EPDCPIX); + reg &= ~MXC_CCM_EPDC_PIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDCPIX); + _clk_disable(clk); +} + +/* TODO: check Auto-Slow Mode */ +static struct clk epdc_pix_clk = { + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .set_parent = _clk_epdc_pix_set_parent, + .get_rate = _clk_epdc_pix_get_rate, + .set_rate = _clk_epdc_pix_set_rate, + .round_rate = _clk_epdc_pix_round_rate, + .enable = _clk_epdc_pix_enable, + .disable = _clk_epdc_pix_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long cko1_get_rate(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= MX50_CCM_CCOSR_CKO1_DIV_MASK; + reg = reg >> MX50_CCM_CCOSR_CKO1_DIV_OFFSET; + return clk_get_rate(clk->parent) / (reg + 1); +} + +static int cko1_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg |= MX50_CCM_CCOSR_CKO1_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 &= ~MX50_CCM_CCOSR_CKO1_EN; + __raw_writel(reg, MXC_CCM_CCOSR); +} + +static int cko1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = (parent_rate/rate - 1) & 0x7; + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MX50_CCM_CCOSR_CKO1_DIV_MASK; + reg |= div << MX50_CCM_CCOSR_CKO1_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long cko1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + div = div < 1 ? 1 : div; + div = div > 8 ? 8 : div; + return parent_rate / div; +} + +static int cko1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg, fast; + + if (parent == &cpu_clk) { + sel = 0; + fast = 1; + } else if (parent == &pll1_sw_clk) { + sel = 1; + fast = 1; + } else if (parent == &pll2_sw_clk) { + sel = 2; + fast = 1; + } else if (parent == &pll3_sw_clk) { + sel = 3; + fast = 1; + } else if (parent == &apll_clk) { + sel = 0; + fast = 0; + } else if (parent == &pfd0_clk) { + sel = 1; + fast = 0; + } else if (parent == &pfd1_clk) { + sel = 2; + fast = 0; + } else if (parent == &pfd2_clk) { + sel = 3; + fast = 0; + } else if (parent == &pfd3_clk) { + sel = 4; + fast = 0; + } else if (parent == &pfd4_clk) { + sel = 5; + fast = 0; + } else if (parent == &pfd5_clk) { + sel = 6; + fast = 0; + } else if (parent == &pfd6_clk) { + sel = 7; + fast = 0; + } else if (parent == &weim_clk[0]) { + sel = 10; + fast = 0; + } else if (parent == &ahb_clk) { + sel = 11; + fast = 0; + } else if (parent == &ipg_clk) { + sel = 12; + fast = 0; + } else if (parent == &ipg_perclk) { + sel = 13; + fast = 0; + } else if (parent == &pfd7_clk) { + sel = 15; + fast = 0; + } else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MX50_CCM_CCOSR_CKO1_SEL_MASK; + reg |= sel << MX50_CCM_CCOSR_CKO1_SEL_OFFSET; + if (fast) + reg &= ~MX50_CCM_CCOSR_CKO1_SLOW_SEL; + else + reg |= MX50_CCM_CCOSR_CKO1_SLOW_SEL; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static struct clk cko1_clk = { + .parent = &pll1_sw_clk, + .get_rate = cko1_get_rate, + .enable = cko1_enable, + .disable = cko1_disable, + .set_rate = cko1_set_rate, + .round_rate = cko1_round_rate, + .set_parent = cko1_set_parent, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "osc", osc_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk), + _REGISTER_CLOCK(NULL, "ckil", ckil_clk), + _REGISTER_CLOCK(NULL, "pll1_main_clk", pll1_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_sw_clk), + _REGISTER_CLOCK(NULL, "pll3", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "apll", apll_clk), + _REGISTER_CLOCK(NULL, "pfd0", pfd0_clk), + _REGISTER_CLOCK(NULL, "pfd1", pfd1_clk), + _REGISTER_CLOCK(NULL, "pfd2", pfd2_clk), + _REGISTER_CLOCK(NULL, "pfd3", pfd3_clk), + _REGISTER_CLOCK(NULL, "pfd4", pfd4_clk), + _REGISTER_CLOCK(NULL, "pfd5", pfd5_clk), + _REGISTER_CLOCK(NULL, "pfd6", pfd6_clk), + _REGISTER_CLOCK(NULL, "pfd7", pfd7_clk), + _REGISTER_CLOCK(NULL, "gpc_dvfs_clk", gpc_dvfs_clk), + _REGISTER_CLOCK(NULL, "lp_apm", lp_apm_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK(NULL, "main_bus_clk", main_bus_clk), + _REGISTER_CLOCK(NULL, "axi_a_clk", axi_a_clk), + _REGISTER_CLOCK(NULL, "axi_b_clk", axi_b_clk), + _REGISTER_CLOCK(NULL, "ahb_clk", ahb_clk), + _REGISTER_CLOCK(NULL, "ahb_max_clk", ahb_max_clk), + _REGISTER_CLOCK("mxc_sdma", "sdma_ahb_clk", sdma_clk[0]), + _REGISTER_CLOCK("mxc_sdma", "sdma_ipg_clk", sdma_clk[1]), + _REGISTER_CLOCK("mxcintuart.0", NULL, uart1_clk[0]), + _REGISTER_CLOCK("mxcintuart.1", NULL, uart2_clk[0]), + _REGISTER_CLOCK("mxcintuart.2", NULL, uart3_clk[0]), + _REGISTER_CLOCK("mxcintuart.3", NULL, uart4_clk[0]), + _REGISTER_CLOCK("mxcintuart.4", NULL, uart5_clk[0]), + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk[0]), + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk[1]), + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk[2]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk[0]), + _REGISTER_CLOCK("mxc_spi.0", NULL, cspi1_clk[0]), + _REGISTER_CLOCK("mxc_spi.1", NULL, cspi2_clk[0]), + _REGISTER_CLOCK("mxc_spi.2", NULL, cspi3_clk), + _REGISTER_CLOCK(NULL, "ssi_lp_apm_clk", ssi_lp_apm_clk), + _REGISTER_CLOCK("mxc_ssi.0", NULL, ssi1_clk[0]), + _REGISTER_CLOCK("mxc_ssi.1", NULL, ssi2_clk[0]), + _REGISTER_CLOCK(NULL, "ssi_ext1_clk", ssi_ext1_clk), + _REGISTER_CLOCK(NULL, "ssi_ext2_clk", ssi_ext2_clk), + _REGISTER_CLOCK(NULL, "usb_ahb_clk", usb_ahb_clk), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy_clk[0]), + _REGISTER_CLOCK(NULL, "usb_phy2_clk", usb_phy_clk[1]), + _REGISTER_CLOCK(NULL, "usb_clk", usb_clk), + _REGISTER_CLOCK("mxsdhci.0", NULL, esdhc1_clk[0]), + _REGISTER_CLOCK("mxsdhci.1", NULL, esdhc2_clk[0]), + _REGISTER_CLOCK("mxsdhci.2", NULL, esdhc3_clk[0]), + _REGISTER_CLOCK("mxsdhci.3", NULL, esdhc4_clk[0]), + _REGISTER_CLOCK(NULL, "ddr_clk", ddr_clk), + _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_clk), + _REGISTER_CLOCK(NULL, "cko1", cko1_clk), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("fec.0", NULL, fec_clk[0]), + _REGISTER_CLOCK(NULL, "fec_sec1_clk", fec_clk[1]), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK(NULL, "gpmi-nfc", gpmi_nfc_clk[0]), + _REGISTER_CLOCK(NULL, "gpmi-apb", gpmi_nfc_clk[1]), + _REGISTER_CLOCK(NULL, "bch", gpmi_nfc_clk[2]), + _REGISTER_CLOCK(NULL, "bch-apb", gpmi_nfc_clk[3]), + _REGISTER_CLOCK(NULL, "rng_clk", rng_clk), + _REGISTER_CLOCK(NULL, "dcp_clk", dcp_clk), + _REGISTER_CLOCK(NULL, "ocotp_ctrl_apb", ocotp_clk), + _REGISTER_CLOCK(NULL, "ocram_clk", ocram_clk), + _REGISTER_CLOCK(NULL, "apbh_dma_clk", apbh_dma_clk), + _REGISTER_CLOCK(NULL, "sys_clk", sys_clk), + _REGISTER_CLOCK(NULL, "elcdif_pix", elcdif_pix_clk), + _REGISTER_CLOCK(NULL, "display_axi", display_axi_clk), + _REGISTER_CLOCK(NULL, "elcdif_axi", elcdif_axi_clk), + _REGISTER_CLOCK(NULL, "pxp_axi", pxp_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_axi", epdc_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_pix", epdc_pix_clk), +}; + +static struct mxc_clk mxc_clks[ARRAY_SIZE(lookups)]; + +static void clk_tree_init(void) +{ + u32 reg; + + 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_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* set pll1_main_clk parent */ + pll1_main_clk.parent = &osc_clk; + + /* set pll2_sw_clk parent */ + pll2_sw_clk.parent = &osc_clk; + + /* set pll3_clk parent */ + pll3_sw_clk.parent = &osc_clk; + + /* set weim_clk parent */ + weim_clk[0].parent = &main_bus_clk; + reg = __raw_readl(MXC_CCM_CBCDR); + if ((reg & MX50_CCM_CBCDR_WEIM_CLK_SEL) != 0) + weim_clk[0].parent = &ahb_clk; + + /* set ipg_perclk parent */ + ipg_perclk.parent = &lp_apm_clk; + reg = __raw_readl(MXC_CCM_CBCMR); + if ((reg & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL) != 0) { + ipg_perclk.parent = &ipg_clk; + } else { + if ((reg & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL) == 0) + ipg_perclk.parent = &main_bus_clk; + } +} + +int __init mx50_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1) +{ + __iomem void *base; + int i = 0, j = 0, reg; + int wp_cnt = 0; + u32 pll1_rate; + + pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K); + pll2_base = ioremap(MX53_BASE_ADDR(PLL2_BASE_ADDR), SZ_4K); + pll3_base = ioremap(MX53_BASE_ADDR(PLL3_BASE_ADDR), SZ_4K); + apll_base = ioremap(ANATOP_BASE_ADDR, SZ_4K); + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(0, MXC_CCM_CCGR4); + + __raw_writel(3 << MXC_CCM_CCGRx_CG6_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(3 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 2 << MXC_CCM_CCGRx_CG14_OFFSET | + 3 << MXC_CCM_CCGRx_CG15_OFFSET, MXC_CCM_CCGR6); + + __raw_writel(0, MXC_CCM_CCGR7); + + external_low_reference = ckil; + external_high_reference = ckih1; + oscillator_reference = osc; + + usb_phy_clk[0].enable_reg = MXC_CCM_CCGR4; + usb_phy_clk[0].enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + mxc_clks[i].reg_clk = lookups[i].clk; + if (lookups[i].con_id != NULL) + strcpy(mxc_clks[i].name, lookups[i].con_id); + else + strcpy(mxc_clks[i].name, lookups[i].dev_id); + clk_register(&mxc_clks[i]); + } + + /* set DDR clock parent */ + reg = __raw_readl(MXC_CCM_CLK_DDR) & + MXC_CCM_CLK_DDR_DDR_PFD_SEL; + if (reg) + clk_set_parent(&ddr_clk, &pfd0_clk); + else + clk_set_parent(&ddr_clk, &pll1_sw_clk); + + clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk); + clk_set_parent(&esdhc1_clk[2], &tmax2_clk); + clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]); + clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk); + + clk_enable(&cpu_clk); + + clk_enable(&main_bus_clk); + + clk_enable(&ocotp_clk); + + databahn = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + + clk_set_parent(&gpu2d_clk, &axi_a_clk); + + /* move cspi to 24MHz */ + clk_set_parent(&cspi_main_clk, &lp_apm_clk); + clk_set_rate(&cspi_main_clk, 12000000); + + /* + * Set DISPLAY_AXI to 200Mhz + * For Display AXI, source clocks must be + * enabled before dividers can be changed + */ + clk_enable(&display_axi_clk); + clk_enable(&elcdif_axi_clk); + clk_enable(&pxp_axi_clk); + clk_set_parent(&display_axi_clk, &pfd2_clk); + clk_set_rate(&display_axi_clk, 200000000); + clk_disable(&display_axi_clk); + clk_disable(&pxp_axi_clk); + clk_disable(&elcdif_axi_clk); + + clk_enable(&elcdif_pix_clk); + clk_set_parent(&elcdif_pix_clk, &pll1_sw_clk); + clk_disable(&elcdif_pix_clk); + + /* + * Enable and set EPDC AXI to 200MHz + * For EPDC AXI, source clocks must be + * enabled before dividers can be changed + */ + clk_enable(&epdc_axi_clk); + clk_set_parent(&epdc_axi_clk, &pfd3_clk); + clk_set_rate(&epdc_axi_clk, 200000000); + clk_disable(&epdc_axi_clk); + + clk_set_parent(&epdc_pix_clk, &pfd5_clk); + + /* 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]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + clk_set_parent(&usb_phy_clk[1], &osc_clk); + + /* move gpmi-nfc to 24MHz */ + clk_set_parent(&gpmi_nfc_clk[0], &osc_clk); + + /* set SDHC root clock as 200MHZ*/ + clk_set_rate(&esdhc1_clk[0], 200000000); + clk_set_rate(&esdhc3_clk[0], 200000000); + + /* Set the current working point. */ + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + /* Update the cpu working point table based on the PLL1 freq + * at boot time + */ + pll1_rate = clk_get_rate(&pll1_main_clk); + if (pll1_rate <= cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) + wp_cnt = 1; + else if (pll1_rate <= cpu_wp_tbl[1].cpu_rate && + pll1_rate > cpu_wp_tbl[2].cpu_rate) + wp_cnt = cpu_wp_nr - 1; + else + wp_cnt = cpu_wp_nr; + + cpu_wp_tbl[0].cpu_rate = pll1_rate; + + if (wp_cnt == 1) { + cpu_wp_tbl[0] = cpu_wp_tbl[cpu_wp_nr - 1]; + memset(&cpu_wp_tbl[cpu_wp_nr - 1], 0, sizeof(struct cpu_wp)); + memset(&cpu_wp_tbl[cpu_wp_nr - 2], 0, sizeof(struct cpu_wp)); + } else if (wp_cnt < cpu_wp_nr) { + for (i = 0; i < wp_cnt; i++) + cpu_wp_tbl[i] = cpu_wp_tbl[i+1]; + memset(&cpu_wp_tbl[i], 0, sizeof(struct cpu_wp)); + } + + if (wp_cnt < cpu_wp_nr) { + set_num_cpu_wp(wp_cnt); + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + } + + pll1_rate = clk_get_rate(&pll1_main_clk); + for (j = 0; j < cpu_wp_nr; j++) { + /* Change the CPU podf divider based on the boot up + * pll1 rate. + */ + cpu_wp_tbl[j].cpu_podf = max( + (int)((pll1_rate / cpu_wp_tbl[j].cpu_rate) + - 1), 0); + if (pll1_rate/(cpu_wp_tbl[j].cpu_podf + 1) > + cpu_wp_tbl[j].cpu_rate) { + cpu_wp_tbl[j].cpu_podf++; + cpu_wp_tbl[j].cpu_rate = + pll1_rate/ + (1000 * (cpu_wp_tbl[j].cpu_podf + 1)); + cpu_wp_tbl[j].cpu_rate *= 1000; + } + if (pll1_rate/(cpu_wp_tbl[j].cpu_podf + 1) < + cpu_wp_tbl[j].cpu_rate) { + cpu_wp_tbl[j].cpu_rate = pll1_rate; + } + cpu_wp_tbl[j].pll_rate = pll1_rate; + } + /* Set the current working point. */ + 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(); + + clk_set_parent(&uart_main_clk, &lp_apm_clk); + clk_set_parent(&gpu2d_clk, &axi_b_clk); + + clk_set_parent(&weim_clk[0], &ahb_clk); + clk_set_rate(&weim_clk[0], clk_round_rate(&weim_clk[0], 130000000)); + + /* Do the following just to disable the PLL since its not used */ + clk_enable(&pll3_sw_clk); + clk_disable(&pll3_sw_clk); + + base = ioremap(MX53_BASE_ADDR(GPT1_BASE_ADDR), SZ_4K); + mxc_timer_init(&gpt_clk[0], base, 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; + + if (wp == cpu_curr_wp) + return 0; + + p = &cpu_wp_tbl[wp]; + + /* + * leave the PLL1 freq unchanged. + */ + reg = __raw_readl(MXC_CCM_CACRR); + reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; + reg |= cpu_wp_tbl[wp].cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CACRR); + cpu_curr_wp = wp; + +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + return 0; +} diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c index 2d37785e3857..abb33781c4c1 100644 --- a/arch/arm/mach-mx5/cpu.c +++ b/arch/arm/mach-mx5/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 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 @@ -11,12 +11,37 @@ * This file contains the CPU initialization code. */ +#include <linux/proc_fs.h> #include <linux/types.h> +#include <linux/err.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/module.h> +#include <linux/init.h> +#include <linux/iram_alloc.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <mach/common.h> #include <mach/hardware.h> -#include <asm/io.h> +#include <asm/mach/map.h> + +#define CORTEXA8_PLAT_AMC 0x18 +#define SRPG_NEON_PUPSCR 0x284 +#define SRPG_NEON_PDNSCR 0x288 +#define SRPG_ARM_PUPSCR 0x2A4 +#define SRPG_ARM_PDNSCR 0x2A8 +#define SRPG_EMPGC0_PUPSCR 0x2E4 +#define SRPG_EMPGC0_PDNSCR 0x2E8 +#define SRPG_EMPGC1_PUPSCR 0x304 +#define SRPG_EMPGC1_PDNSCR 0x308 + +void __iomem *arm_plat_base; +void __iomem *gpc_base; +void __iomem *ccm_base; +void __iomem *databahn_base; +void *wait_in_iram_base; +void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); + +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); static int cpu_silicon_rev = -1; @@ -24,7 +49,7 @@ static int cpu_silicon_rev = -1; static void query_silicon_parameter(void) { - void __iomem *rom = ioremap(MX51_IROM_BASE_ADDR, MX51_IROM_SIZE); + void __iomem *rom = ioremap(IROM_BASE_ADDR, IROM_SIZE); u32 rev; if (!rom) { @@ -35,16 +60,16 @@ static void query_silicon_parameter(void) rev = readl(rom + SI_REV); switch (rev) { case 0x1: - cpu_silicon_rev = MX51_CHIP_REV_1_0; + cpu_silicon_rev = CHIP_REV_1_0; break; case 0x2: - cpu_silicon_rev = MX51_CHIP_REV_1_1; + cpu_silicon_rev = CHIP_REV_1_1; break; case 0x10: - cpu_silicon_rev = MX51_CHIP_REV_2_0; + cpu_silicon_rev = CHIP_REV_2_0; break; case 0x20: - cpu_silicon_rev = MX51_CHIP_REV_3_0; + cpu_silicon_rev = CHIP_REV_3_0; break; default: cpu_silicon_rev = 0; @@ -70,30 +95,186 @@ int mx51_revision(void) } EXPORT_SYMBOL(mx51_revision); +struct cpu_wp *(*get_cpu_wp)(int *wp); +void (*set_num_cpu_wp)(int num); + +static void __init mipi_hsc_disable(void) +{ + void __iomem *reg_hsc_mcd = ioremap(MIPI_HSC_BASE_ADDR, SZ_4K); + void __iomem *reg_hsc_mxt_conf = reg_hsc_mcd + 0x800; + struct clk *clk; + uint32_t temp; + + /* Temporarily setup MIPI module to legacy mode */ + clk = clk_get(NULL, "mipi_hsp_clk"); + if (!IS_ERR(clk)) { + clk_enable(clk); + + /* Temporarily setup MIPI module to legacy mode */ + __raw_writel(0xF00, reg_hsc_mcd); + + /* CSI mode reserved*/ + temp = __raw_readl(reg_hsc_mxt_conf); + __raw_writel(temp | 0x0FF, reg_hsc_mxt_conf); + + if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { + temp = __raw_readl(reg_hsc_mxt_conf); + __raw_writel(temp | 0x10000, reg_hsc_mxt_conf); + } + + clk_disable(clk); + clk_put(clk); + } + iounmap(reg_hsc_mcd); +} + +/*! + * This function resets IPU + */ +void mx5_ipu_reset(void) +{ + u32 *reg; + u32 value; + reg = ioremap(MX53_BASE_ADDR(SRC_BASE_ADDR), PAGE_SIZE); + value = __raw_readl(reg); + value = value | 0x8; + __raw_writel(value, reg); + iounmap(reg); +} + +void mx5_vpu_reset(void) +{ + u32 reg; + void __iomem *src_base; + + src_base = ioremap(MX53_BASE_ADDR(SRC_BASE_ADDR), PAGE_SIZE); + + /* mask interrupt due to vpu passed reset */ + reg = __raw_readl(src_base + 0x18); + reg |= 0x02; + __raw_writel(reg, src_base + 0x18); + + reg = __raw_readl(src_base); + reg |= 0x5; /* warm reset vpu */ + __raw_writel(reg, src_base); + while (__raw_readl(src_base) & 0x04) + ; + + iounmap(src_base); +} + static int __init post_cpu_init(void) { - unsigned int reg; void __iomem *base; + unsigned int reg; + struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk"); + int iram_size = IRAM_SIZE; - if (!cpu_is_mx51()) + if (!cpu_is_mx5()) return 0; - base = MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR); + if (cpu_is_mx51()) { + mipi_hsc_disable(); + +#if defined(CONFIG_MXC_SECURITY_SCC) || defined(CONFIG_MXC_SECURITY_SCC_MODULE) + iram_size -= SCC_RAM_SIZE; +#endif + iram_init(MX51_IRAM_BASE_ADDR, iram_size); + } else { + iram_init(MX53_IRAM_BASE_ADDR, iram_size); + } + + gpc_base = ioremap(MX53_BASE_ADDR(GPC_BASE_ADDR), SZ_4K); + ccm_base = ioremap(MX53_BASE_ADDR(CCM_BASE_ADDR), SZ_4K); + + clk_enable(gpcclk); + + /* Setup the number of clock cycles to wait for SRPG + * power up and power down requests. + */ + __raw_writel(0x010F0201, gpc_base + SRPG_ARM_PUPSCR); + __raw_writel(0x010F0201, gpc_base + SRPG_NEON_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC0_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC1_PUPSCR); + + __raw_writel(0x01010101, gpc_base + SRPG_ARM_PDNSCR); + __raw_writel(0x01010101, gpc_base + SRPG_NEON_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC0_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC1_PDNSCR); + + clk_disable(gpcclk); + clk_put(gpcclk); + + /* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */ + arm_plat_base = ioremap(MX53_BASE_ADDR(ARM_BASE_ADDR), SZ_4K); + reg = 0x8; + __raw_writel(reg, arm_plat_base + CORTEXA8_PLAT_AMC); + + base = ioremap(MX53_BASE_ADDR(AIPS1_BASE_ADDR), SZ_4K); __raw_writel(0x0, base + 0x40); __raw_writel(0x0, base + 0x44); __raw_writel(0x0, base + 0x48); __raw_writel(0x0, base + 0x4C); reg = __raw_readl(base + 0x50) & 0x00FFFFFF; __raw_writel(reg, base + 0x50); + iounmap(base); - base = MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR); + base = ioremap(MX53_BASE_ADDR(AIPS2_BASE_ADDR), SZ_4K); __raw_writel(0x0, base + 0x40); __raw_writel(0x0, base + 0x44); __raw_writel(0x0, base + 0x48); __raw_writel(0x0, base + 0x4C); reg = __raw_readl(base + 0x50) & 0x00FFFFFF; __raw_writel(reg, base + 0x50); + iounmap(base); + + if (cpu_is_mx51() || cpu_is_mx53()) { + /*Allow for automatic gating of the EMI internal clock. + * If this is done, emi_intr CCGR bits should be set to 11. + */ + base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); + reg = __raw_readl(base + 0x8c); + reg &= ~0x1; + __raw_writel(reg, base + 0x8c); + iounmap(base); + } + + databahn_base = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K); + + if (cpu_is_mx50()) { + struct clk *ddr_clk = clk_get(NULL, "ddr_clk"); + unsigned long iram_paddr; + iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + wait_in_iram_base = __arm_ioremap(iram_paddr, + SZ_4K, MT_HIGH_VECTORS); + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + + clk_enable(ddr_clk); + + /* Set the DDR to enter automatic self-refresh. */ + /* Set the DDR to automatically enter lower power mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG22); + reg &= ~LOWPOWER_AUTOENABLE_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG22); + + /* set the counter for entering mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG21); + reg &= ~LOWPOWER_EXTERNAL_CNT_MASK; + reg = 128 << LOWPOWER_EXTERNAL_CNT_OFFSET; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG21); + + /* Enable low power mode 4 */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG20); + reg &= ~LOWPOWER_CONTROL_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG20); + clk_disable(ddr_clk); + } return 0; } diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-mx5/crm_regs.h index c776b9af0624..45db5f60d7b1 100644 --- a/arch/arm/mach-mx5/crm_regs.h +++ b/arch/arm/mach-mx5/crm_regs.h @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 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 @@ -11,12 +11,7 @@ #ifndef __ARCH_ARM_MACH_MX51_CRM_REGS_H__ #define __ARCH_ARM_MACH_MX51_CRM_REGS_H__ -#define MX51_CCM_BASE MX51_IO_ADDRESS(MX51_CCM_BASE_ADDR) -#define MX51_DPLL1_BASE MX51_IO_ADDRESS(MX51_PLL1_BASE_ADDR) -#define MX51_DPLL2_BASE MX51_IO_ADDRESS(MX51_PLL2_BASE_ADDR) -#define MX51_DPLL3_BASE MX51_IO_ADDRESS(MX51_PLL3_BASE_ADDR) -#define MX51_CORTEXA8_BASE MX51_IO_ADDRESS(MX51_ARM_BASE_ADDR) -#define MX51_GPC_BASE MX51_IO_ADDRESS(MX51_GPC_BASE_ADDR) +#define MXC_CCM_BASE (IO_ADDRESS(CCM_BASE_ADDR)) /* PLL Register Offsets */ #define MXC_PLL_DP_CTL 0x00 @@ -73,41 +68,108 @@ #define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) #define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF +/* Register addresses of apll and pfd*/ +#define MXC_ANADIG_FRAC0 0x10 +#define MXC_ANADIG_FRAC0_SET 0x14 +#define MXC_ANADIG_FRAC0_CLR 0x18 +#define MXC_ANADIG_FRAC1 0x20 +#define MXC_ANADIG_FRAC1_SET 0x24 +#define MXC_ANADIG_FRAC1_CLR 0x28 +#define MXC_ANADIG_MISC 0x60 +#define MXC_ANADIG_MISC_SET 0x64 +#define MXC_ANADIG_MISC_CLR 0x68 +#define MXC_ANADIG_PLLCTRL 0x70 +#define MXC_ANADIG_PLLCTRL_SET 0x74 +#define MXC_ANADIG_PLLCTRL_CLR 0x78 + +/* apll and pfd Register Bit definitions */ + +#define MXC_ANADIG_PFD3_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD3_STABLE (1 << 30) +#define MXC_ANADIG_PFD3_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD_FRAC_MASK 0x3F +#define MXC_ANADIG_PFD2_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD2_STABLE (1 << 22) +#define MXC_ANADIG_PFD2_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD1_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD1_STABLE (1 << 14) +#define MXC_ANADIG_PFD1_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD0_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD0_STABLE (1 << 6) +#define MXC_ANADIG_PFD0_FRAC_OFFSET 0 + +#define MXC_ANADIG_PFD7_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD7_STABLE (1 << 30) +#define MXC_ANADIG_PFD7_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD6_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD6_STABLE (1 << 22) +#define MXC_ANADIG_PFD6_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD5_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD5_STABLE (1 << 14) +#define MXC_ANADIG_PFD5_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD4_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD4_STABLE (1 << 6) +#define MXC_ANADIG_PFD4_FRAC_OFFSET 0 + +#define MXC_ANADIG_APLL_LOCK (1 << 31) +#define MXC_ANADIG_APLL_FORCE_LOCK (1 << 30) +#define MXC_ANADIG_PFD_DIS_OFFSET 16 +#define MXC_ANADIG_PFD_DIS_MASK 0xff +#define MXC_ANADIG_APLL_LOCK_CNT_OFFSET 0 +#define MXC_ANADIG_APLL_LOCK_CNT_MASK 0xffff + /* Register addresses of CCM*/ -#define MXC_CCM_CCR (MX51_CCM_BASE + 0x00) -#define MXC_CCM_CCDR (MX51_CCM_BASE + 0x04) -#define MXC_CCM_CSR (MX51_CCM_BASE + 0x08) -#define MXC_CCM_CCSR (MX51_CCM_BASE + 0x0C) -#define MXC_CCM_CACRR (MX51_CCM_BASE + 0x10) -#define MXC_CCM_CBCDR (MX51_CCM_BASE + 0x14) -#define MXC_CCM_CBCMR (MX51_CCM_BASE + 0x18) -#define MXC_CCM_CSCMR1 (MX51_CCM_BASE + 0x1C) -#define MXC_CCM_CSCMR2 (MX51_CCM_BASE + 0x20) -#define MXC_CCM_CSCDR1 (MX51_CCM_BASE + 0x24) -#define MXC_CCM_CS1CDR (MX51_CCM_BASE + 0x28) -#define MXC_CCM_CS2CDR (MX51_CCM_BASE + 0x2C) -#define MXC_CCM_CDCDR (MX51_CCM_BASE + 0x30) -#define MXC_CCM_CHSCDR (MX51_CCM_BASE + 0x34) -#define MXC_CCM_CSCDR2 (MX51_CCM_BASE + 0x38) -#define MXC_CCM_CSCDR3 (MX51_CCM_BASE + 0x3C) -#define MXC_CCM_CSCDR4 (MX51_CCM_BASE + 0x40) -#define MXC_CCM_CWDR (MX51_CCM_BASE + 0x44) -#define MXC_CCM_CDHIPR (MX51_CCM_BASE + 0x48) -#define MXC_CCM_CDCR (MX51_CCM_BASE + 0x4C) -#define MXC_CCM_CTOR (MX51_CCM_BASE + 0x50) -#define MXC_CCM_CLPCR (MX51_CCM_BASE + 0x54) -#define MXC_CCM_CISR (MX51_CCM_BASE + 0x58) -#define MXC_CCM_CIMR (MX51_CCM_BASE + 0x5C) -#define MXC_CCM_CCOSR (MX51_CCM_BASE + 0x60) -#define MXC_CCM_CGPR (MX51_CCM_BASE + 0x64) -#define MXC_CCM_CCGR0 (MX51_CCM_BASE + 0x68) -#define MXC_CCM_CCGR1 (MX51_CCM_BASE + 0x6C) -#define MXC_CCM_CCGR2 (MX51_CCM_BASE + 0x70) -#define MXC_CCM_CCGR3 (MX51_CCM_BASE + 0x74) -#define MXC_CCM_CCGR4 (MX51_CCM_BASE + 0x78) -#define MXC_CCM_CCGR5 (MX51_CCM_BASE + 0x7C) -#define MXC_CCM_CCGR6 (MX51_CCM_BASE + 0x80) -#define MXC_CCM_CMEOR (MX51_CCM_BASE + 0x84) +#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_CBCDR (MXC_CCM_BASE + 0x14) +#define MXC_CCM_CBCMR (MXC_CCM_BASE + 0x18) +#define MXC_CCM_CSCMR1 (MXC_CCM_BASE + 0x1C) +#define MXC_CCM_CSCMR2 (MXC_CCM_BASE + 0x20) +#define MXC_CCM_CSCDR1 (MXC_CCM_BASE + 0x24) +#define MXC_CCM_CS1CDR (MXC_CCM_BASE + 0x28) +#define MXC_CCM_CS2CDR (MXC_CCM_BASE + 0x2C) +#define MXC_CCM_CDCDR (MXC_CCM_BASE + 0x30) +#define MXC_CCM_CHSCDR (MXC_CCM_BASE + 0x34) +#define MXC_CCM_CSCDR2 (MXC_CCM_BASE + 0x38) +#define MXC_CCM_CSCDR3 (MXC_CCM_BASE + 0x3C) +#define MXC_CCM_CSCDR4 (MXC_CCM_BASE + 0x40) +#define MXC_CCM_CWDR (MXC_CCM_BASE + 0x44) +#define MXC_CCM_CDHIPR (MXC_CCM_BASE + 0x48) +#define MXC_CCM_CDCR (MXC_CCM_BASE + 0x4C) +#define MXC_CCM_CTOR (MXC_CCM_BASE + 0x50) +#define MXC_CCM_CLPCR (MXC_CCM_BASE + 0x54) +#define MXC_CCM_CISR (MXC_CCM_BASE + 0x58) +#define MXC_CCM_CIMR (MXC_CCM_BASE + 0x5C) +#define MXC_CCM_CCOSR (MXC_CCM_BASE + 0x60) +#define MXC_CCM_CGPR (MXC_CCM_BASE + 0x64) +#define MXC_CCM_CCGR0 (MXC_CCM_BASE + 0x68) +#define MXC_CCM_CCGR1 (MXC_CCM_BASE + 0x6C) +#define MXC_CCM_CCGR2 (MXC_CCM_BASE + 0x70) +#define MXC_CCM_CCGR3 (MXC_CCM_BASE + 0x74) +#define MXC_CCM_CCGR4 (MXC_CCM_BASE + 0x78) +#define MXC_CCM_CCGR5 (MXC_CCM_BASE + 0x7C) +#define MXC_CCM_CCGR6 (MXC_CCM_BASE + 0x80) +#define MXC_CCM_CCGR7 (MXC_CCM_BASE + 0x84) +#define MXC_CCM_CMEOR (MXC_CCM_BASE + 0x88) +#define MXC_CCM_CSR2 (MXC_CCM_BASE + 0x8C) +#define MXC_CCM_CLKSEQ_BYPASS (MXC_CCM_BASE + 0x90) +#define MXC_CCM_CLK_SYS (MXC_CCM_BASE + 0x94) +#define MXC_CCM_CLK_DDR (MXC_CCM_BASE + 0x98) +#define MXC_CCM_ELCDIFPIX (MXC_CCM_BASE + 0x9C) +#define MXC_CCM_EPDCPIX (MXC_CCM_BASE + 0xA0) +#define MXC_CCM_DISPLAY_AXI (MXC_CCM_BASE + 0xA4) +#define MXC_CCM_EPDC_AXI (MXC_CCM_BASE + 0xA8) +#define MXC_CCM_GPMI (MXC_CCM_BASE + 0xAC) +#define MXC_CCM_BCH (MXC_CCM_BASE + 0xB0) +#define MXC_CCM_MSHC_XMSCKI (MXC_CCM_BASE + 0xB4) + +/* CCM Register Offsets. */ +#define MXC_CCM_CDCR_OFFSET 0x4C +#define MXC_CCM_CACRR_OFFSET 0x10 +#define MXC_CCM_CDHIPR_OFFSET 0x48 /* Define the bits in register CCR */ #define MXC_CCM_CCR_COSC_EN (1 << 12) @@ -119,82 +181,103 @@ #define MXC_CCM_CCR_OSCNT_MASK (0xFF) /* Define the bits in register CCDR */ +/* MX51 */ #define MXC_CCM_CCDR_HSC_HS_MASK (0x1 << 18) #define MXC_CCM_CCDR_IPU_HS_MASK (0x1 << 17) #define MXC_CCM_CCDR_EMI_HS_MASK (0x1 << 16) +/* MX53 */ +#define MXC_CCM_CCDR_IPU_HS_MX53_MASK (0x1 << 21) +#define MXC_CCM_CCDR_EMI_HS_INT2_MASK (0x1 << 20) +#define MXC_CCM_CCDR_EMI_HS_INT1_MASK (0x1 << 19) +#define MXC_CCM_CCDR_EMI_HS_SLOW_MASK (0x1 << 18) +#define MXC_CCM_CCDR_EMI_HS_FAST_MASK (0x1 << 17) +#define MXC_CCM_CCDR_EMI_HS_MASK (0x1 << 16) /* Define the bits in register CSR */ #define MXC_CCM_CSR_COSR_READY (1 << 5) -#define MXC_CCM_CSR_LVS_VALUE (1 << 4) +#define MXC_CCM_CSR_LVS_VALUE (1 << 4) #define MXC_CCM_CSR_CAMP2_READY (1 << 3) #define MXC_CCM_CSR_CAMP1_READY (1 << 2) #define MXC_CCM_CSR_FPM_READY (1 << 1) -#define MXC_CCM_CSR_REF_EN_B (1 << 0) +#define MXC_CCM_CSR_TEMP_MON_ALARM (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_PLL3_PFD_EN (0x1 << 13) +#define MXC_CCM_CCSR_PLL2_PFD_EN (0x1 << 12) +#define MXC_CCM_CCSR_PLL1_PFD_EN (0x1 << 11) +#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 10) +#define MXC_CCM_CCSR_LP_APM_SE_MX51L (0x1 << 9) +#define MXC_CCM_CCSR_PLL4_SW_CLK_SEL (1 << 9) +#define MXC_CCM_CCSR_STEP_SEL_OFFSET (7) +#define MXC_CCM_CCSR_STEP_SEL_MASK (0x3 << 7) #define MXC_CCM_CCSR_STEP_SEL_LP_APM 0 #define MXC_CCM_CCSR_STEP_SEL_PLL1_BYPASS 1 /* Only when JTAG connected? */ #define MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED 2 #define MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED 3 #define MXC_CCM_CCSR_PLL2_PODF_OFFSET (5) -#define MXC_CCM_CCSR_PLL2_PODF_MASK (0x3 << 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_PLL3_PODF_MASK (0x3 << 3) #define MXC_CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) /* 0: pll1_main_clk, 1: step_clk */ -#define MXC_CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1) -#define MXC_CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0) +#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 MXC_CCM_CACRR_ARM_PODF_MASK (0x7) /* Define the bits in register CBCDR */ -#define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) -#define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define MX50_CCM_CBCDR_WEIM_CLK_SEL (0x1 << 27) +#define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) +#define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET (25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK (0x3 << 25) #define MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET (30) -#define MXC_CCM_CBCDR_DDR_HF_SEL (0x1 << 30) +#define MXC_CCM_CBCDR_DDR_HF_SEL (0x1 << 30) #define MXC_CCM_CBCDR_DDR_PODF_OFFSET (27) #define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27) +#define MX50_CCM_CBCDR_WEIM_PODF_OFFSET (22) +#define MX50_CCM_CBCDR_WEIM_PODF_MASK (0x7 << 22) #define MXC_CCM_CBCDR_EMI_PODF_OFFSET (22) -#define MXC_CCM_CBCDR_EMI_PODF_MASK (0x7 << 22) +#define MXC_CCM_CBCDR_EMI_PODF_MASK (0x7 << 22) #define MXC_CCM_CBCDR_AXI_B_PODF_OFFSET (19) #define MXC_CCM_CBCDR_AXI_B_PODF_MASK (0x7 << 19) #define MXC_CCM_CBCDR_AXI_A_PODF_OFFSET (16) #define MXC_CCM_CBCDR_AXI_A_PODF_MASK (0x7 << 16) #define MXC_CCM_CBCDR_NFC_PODF_OFFSET (13) -#define MXC_CCM_CBCDR_NFC_PODF_MASK (0x7 << 13) +#define MXC_CCM_CBCDR_NFC_PODF_MASK (0x7 << 13) #define MXC_CCM_CBCDR_AHB_PODF_OFFSET (10) -#define MXC_CCM_CBCDR_AHB_PODF_MASK (0x7 << 10) +#define MXC_CCM_CBCDR_AHB_PODF_MASK (0x7 << 10) #define MXC_CCM_CBCDR_IPG_PODF_OFFSET (8) -#define MXC_CCM_CBCDR_IPG_PODF_MASK (0x3 << 8) -#define MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET (6) +#define MXC_CCM_CBCDR_IPG_PODF_MASK (0x3 << 8) +#define MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET (6) #define MXC_CCM_CBCDR_PERCLK_PRED1_MASK (0x3 << 6) -#define MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET (3) +#define MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET (3) #define MXC_CCM_CBCDR_PERCLK_PRED2_MASK (0x7 << 3) -#define MXC_CCM_CBCDR_PERCLK_PODF_OFFSET (0) +#define MXC_CCM_CBCDR_PERCLK_PODF_OFFSET (0) #define MXC_CCM_CBCDR_PERCLK_PODF_MASK (0x7) /* Define the bits in register CBCMR */ +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (16) +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 16) #define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET (14) -#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK (0x3 << 14) -#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET (12) -#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK (0x3 << 12) -#define MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET (10) +#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET (12) +#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET (10) #define MXC_CCM_CBCMR_DDR_CLK_SEL_MASK (0x3 << 10) #define MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_OFFSET (8) -#define MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_MASK (0x3 << 8) #define MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_OFFSET (6) -#define MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_MASK (0x3 << 6) -#define MXC_CCM_CBCMR_GPU_CLK_SEL_OFFSET (4) +#define MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CBCMR_GPU_CLK_SEL_OFFSET (4) #define MXC_CCM_CBCMR_GPU_CLK_SEL_MASK (0x3 << 4) -#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (14) -#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 14) -#define MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL (0x1 << 1) -#define MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_OFFSET (2) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_MASK (0x3 << 2) +#define MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL (0x1 << 1) +#define MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0) /* Define the bits in register CSCMR1 */ #define MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET (30) @@ -203,96 +286,128 @@ #define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK (0x3 << 28) #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_UART_CLK_SEL_OFFSET (24) +#define MXC_CCM_CSCMR1_UART_CLK_SEL_MASK (0x3 << 24) #define MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET (22) -#define MXC_CCM_CSCMR1_USBOH3_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_USBOH3_CLK_SEL_MASK (0x3 << 22) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_OFFSET (20) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51 (0x1 << 19) +#define MXC_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 19) #define MXC_CCM_CSCMR1_ESDHC4_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_SSI3_CLK_SEL (0x1 << 11) -#define MXC_CCM_CSCMR1_VPU_RCLK_SEL (0x1 << 10) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET (21) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK (0x3 << 21) +#define MX50_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 20) +#define MX50_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 19) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET (16) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK (0x7 << 16) +#define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET (16) +#define MXC_CCM_CSCMR1_ESDHC3_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_SSI3_CLK_SEL (0x1 << 11) +#define MXC_CCM_CSCMR1_VPU_RCLK_SEL (0x1 << 10) #define MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET (8) #define MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK (0x3 << 8) -#define MXC_CCM_CSCMR1_TVE_CLK_SEL (0x1 << 7) +#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_SPDIF_CLK_SEL_OFFSET (2) -#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL_MASK (0x3 << 2) -#define MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL (0x1 << 1) -#define MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL (0x1) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET (4) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL_OFFSET (2) +#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL_MASK (0x3 << 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_DI_CLK_SEL_OFFSET(n) (26+n*3) #define MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(n) (0x7 << (26+n*3)) -#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET (24) -#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK (0x3 << 24) -#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET (22) -#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_MASK (0x3 << 22) +#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET (24) +#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK (0x3 << 24) +#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET (22) +#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_MASK (0x3 << 22) +/* MX51 */ #define MXC_CCM_CSCMR2_ESC_CLK_SEL_OFFSET (20) -#define MXC_CCM_CSCMR2_ESC_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CSCMR2_ESC_CLK_SEL_MASK (0x3 << 20) #define MXC_CCM_CSCMR2_HSC2_CLK_SEL_OFFSET (18) #define MXC_CCM_CSCMR2_HSC2_CLK_SEL_MASK (0x3 << 18) #define MXC_CCM_CSCMR2_HSC1_CLK_SEL_OFFSET (16) #define MXC_CCM_CSCMR2_HSC1_CLK_SEL_MASK (0x3 << 16) #define MXC_CCM_CSCMR2_HSI2C_CLK_SEL_OFFSET (14) #define MXC_CCM_CSCMR2_HSI2C_CLK_SEL_MASK (0x3 << 14) +/* MX53 */ +#define MXC_CCM_CSCMR2_ASRC_CLK_SEL (1<<21) +#define MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET (19) +#define MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK (0x3 << 19) +#define MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET (16) +#define MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK (0x7 << 16) +#define MXC_CCM_CSCMR2_IEEE_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR2_IEEE_CLK_SEL_MASK (0x3 << 14) #define MXC_CCM_CSCMR2_FIRI_CLK_SEL_OFFSET (12) #define MXC_CCM_CSCMR2_FIRI_CLK_SEL_MASK (0x3 << 12) +/* MX51 */ #define MXC_CCM_CSCMR2_SIM_CLK_SEL_OFFSET (10) -#define MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK (0x3 << 10) +#define MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK (0x3 << 10) #define MXC_CCM_CSCMR2_SLIMBUS_COM (0x1 << 9) -#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_OFFSET (6) #define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_MASK (0x7 << 6) +/* MX53 */ +#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) +#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) +#define MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL (0x1 << 9) +#define MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL (0x1 << 8) +#define MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK (0x3 << 6) #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_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_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_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_ESDHC2_MSHC2_CLK_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_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_MSHC2_CLK_PODF_OFFSET (11) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK (0x7 << 11) #define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET (8) #define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK (0x7 << 8) #define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET (6) #define MXC_CCM_CSCDR1_USBOH3_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_PRED_MASK (0x7 << 3) #define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET (0) -#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK (0x7) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK (0x7) /* Define the bits in register CS1CDR and CS2CDR */ -#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET (22) -#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK (0x7 << 22) -#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET (16) -#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET (25) +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK (0x3F << 25) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET (22) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET (16) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET (9) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK (0x7 << 9) #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_SSI_EXT2_CLK_PRED_OFFSET (22) -#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK (0x7 << 22) -#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET (16) -#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET (16) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK (0x3F << 16) #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) @@ -300,50 +415,74 @@ /* 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_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_OFFSET (19) #define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK (0x3F << 19) -#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET (16) +/* MX51 */ +#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) +/* MX53 */ +#define MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET (16) +#define MXC_CCM_CDCDR_DI_PLL4_PODF_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_DI_CLK_PRED_OFFSET (6) -#define MXC_CCM_CDCDR_DI_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CDCDR_DI1_CLK_PRED_MASK (0x7 << 6) #define MXC_CCM_CDCDR_USB_PHY_PRED_OFFSET (3) -#define MXC_CCM_CDCDR_USB_PHY_PRED_MASK (0x7 << 3) +#define MXC_CCM_CDCDR_USB_PHY_PRED_MASK (0x7 << 3) #define MXC_CCM_CDCDR_USB_PHY_PODF_OFFSET (0) -#define MXC_CCM_CDCDR_USB_PHY_PODF_MASK (0x7) +#define MXC_CCM_CDCDR_USB_PHY_PODF_MASK (0x7) /* Define the bits in register CHSCCDR */ +/* MX51 */ #define MXC_CCM_CHSCCDR_ESC_CLK_PRED_OFFSET (12) #define MXC_CCM_CHSCCDR_ESC_CLK_PRED_MASK (0x7 << 12) -#define MXC_CCM_CHSCCDR_ESC_CLK_PODF_OFFSET (6) +#define MXC_CCM_CHSCCDR_ESC_CLK_PODF_OFFSET (6) #define MXC_CCM_CHSCCDR_ESC_CLK_PODF_MASK (0x3F << 6) -#define MXC_CCM_CHSCCDR_HSC2_CLK_PODF_OFFSET (3) +#define MXC_CCM_CHSCCDR_HSC2_CLK_PODF_OFFSET (3) #define MXC_CCM_CHSCCDR_HSC2_CLK_PODF_MASK (0x7 << 3) -#define MXC_CCM_CHSCCDR_HSC1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CHSCCDR_HSC1_CLK_PODF_OFFSET (0) #define MXC_CCM_CHSCCDR_HSC1_CLK_PODF_MASK (0x7) +/* MX53 */ +#define MXC_CCM_CHSCCDR_ESAI_HCKT_SEL_OFFSET (6) +#define MXC_CCM_CHSCCDR_ESAI_HCKT_SEL_MASK (0x3 << 6) +#define MXC_CCM_CHSCCDR_ESAI_HCKR_SEL_OFFSET (4) +#define MXC_CCM_CHSCCDR_ESAI_HCKR_SEL_MASK (0x3 << 4) +#define MXC_CCM_CHSCCDR_SSI2_MLB_SPDIF_SRC_OFFSET (2) +#define MXC_CCM_CHSCCDR_SSI2_MLB_SPDIF_SRC_MASK (0x3 << 2) +#define MXC_CCM_CHSCCDR_SSI1_MLB_SPDIF_SRC_OFFSET (0) +#define MXC_CCM_CHSCCDR_SSI1_MLB_SPDIF_SRC_MASK (0x3) /* Define the bits in register CSCDR2 */ +#define MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET (28) +#define MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK (0x7 << 28) #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) +/* MX51 */ #define MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET (16) #define MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK (0x7 << 16) #define MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET (9) #define MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK (0x3F << 9) -#define MXC_CCM_CSCDR2_SLIMBUS_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR2_SLIMBUS_CLK_PRED_OFFSET (6) #define MXC_CCM_CSCDR2_SLIMBUS_PRED_MASK (0x7 << 6) #define MXC_CCM_CSCDR2_SLIMBUS_PODF_OFFSET (0) #define MXC_CCM_CSCDR2_SLIMBUS_PODF_MASK (0x3F) +/* MX53 */ +#define MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK (0x3F) /* Define the bits in register CSCDR3 */ -#define MXC_CCM_CSCDR3_HSI2C_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR3_HSI2C_CLK_PRED_OFFSET (16) #define MXC_CCM_CSCDR3_HSI2C_CLK_PRED_MASK (0x7 << 16) -#define MXC_CCM_CSCDR3_HSI2C_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR3_HSI2C_CLK_PODF_OFFSET (9) #define MXC_CCM_CSCDR3_HSI2C_CLK_PODF_MASK (0x3F << 9) #define MXC_CCM_CSCDR3_FIRI_CLK_PRED_OFFSET (6) #define MXC_CCM_CSCDR3_FIRI_CLK_PRED_MASK (0x7 << 6) @@ -352,13 +491,13 @@ /* Define the bits in register CSCDR4 */ #define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET (16) -#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK (0x7 << 16) #define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET (9) -#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK (0x3F << 9) #define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET (6) -#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK (0x7 << 6) #define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET (0) -#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK (0x3F) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK (0x3F) /* Define the bits in register CDHIPR */ #define MXC_CCM_CDHIPR_ARM_PODF_BUSY (1 << 16) @@ -373,58 +512,92 @@ #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 MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ_STATUS (0x1 << 7) +#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ (0x1 << 6) +#define MX50_CCM_CDCR_SW_DVFS_EN (0x1 << 5) +#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 */ +/* MX51 */ #define MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS (0x1 << 23) -#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_SCC_LPM_HS_MX51 (0x1 << 22) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51 (0x1 << 21) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51 (0x1 << 20) +/* MX53 */ +#define MXC_CCM_CLPCR_BYPASS_CAN2_LPM_HS (0x1 << 27) +#define MXC_CCM_CLPCR_BYPASS_CAN1_LPM_HS (0x1 << 27) +#define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX53 (0x1 << 26) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS (0x1 << 25) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS (0x1 << 24) +#define MXC_CCM_CLPCR_BYPASS_EMI_INT2_LPM_HS (0x1 << 23) +#define MX50_CCM_CLPCR_BYPASS_RNGB_LPM_HS (0x1 << 23) +#define MXC_CCM_CLPCR_BYPASS_EMI_INT1_LPM_HS (0x1 << 22) +#define MXC_CCM_CLPCR_BYPASS_EMI_SLOW_LPM_HS (0x1 << 21) +#define MXC_CCM_CLPCR_BYPASS_EMI_FAST_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_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_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_BYPASS_PMIC_VFUNC_READY (0x1 << 2) +#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_ARM_PODF_LOADED_MX51 (0x1 << 25) +#define MXC_CCM_CISR_ARM_PODF_LOADED (0x1 << 26) +#define MXC_CCM_CISR_TEMP_MON_ALARM (0x1 << 25) +#define MXC_CCM_CISR_EMI_CLK_SEL_LOADED (0x1 << 23) +#define MXC_CCM_CISR_PER_CLK_SEL_LOADED (0x1 << 22) +#define MXC_CCM_CISR_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) #define MXC_CCM_CISR_AHB_PODF_LOADED (0x1 << 20) -#define MXC_CCM_CISR_EMI_PODF_LOADED (0x1 << 19) +#define MXC_CCM_CISR_EMI_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_DIVIDER_LOADED (0x1 << 16) #define MXC_CCM_CISR_COSC_READY (0x1 << 6) -#define MXC_CCM_CISR_CKIH2_READY (0x1 << 5) +#define MXC_CCM_CISR_CKIH2_READY (0x1 << 5) #define MXC_CCM_CISR_CKIH_READY (0x1 << 4) +#define MX50_CCM_CISR_CAMP1_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 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_ARM_PODF_LOADED_MX51 (0x1 << 25) +#define MXC_CCM_CIMR_MASK_EMI_PODF_LOADED_MX51 (0x1 << 20) +#define MXC_CCM_CIMR_MASK_AXI_C_PODF_LOADED_MX51 (0x1 << 19) +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (0x1 << 26) +#define MXC_CCM_CIMR_MASK_TEMP_MON_ALARM (0x1 << 25) +#define MXC_CCM_CIMR_MASK_EMI_CLK_SEL_LOADED (0x1 << 23) +#define MXC_CCM_CIMR_MASK_PER_CLK_SEL_LOADED (0x1 << 22) #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_AHB_PODF_LOADED_MX53 (0x1 << 20) +#define MXC_CCM_CIMR_MASK_EMI_SLOW_PODF_LOADED_MX53 (0x1 << 19) +#define MX50_CCM_CIMR_MASK_WEIM_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) +/* MX51 */ +#define MXC_CCM_CIMR_MASK_COSC_READY_MX51 (0x1 << 5) #define MXC_CCM_CIMR_MASK_CKIH_READY (0x1 << 4) #define MXC_CCM_CIMR_MASK_FPM_READY (0x1 << 3) +/* MX53/MX50 */ +#define MXC_CCM_CIMR_MASK_COSC_READY (0x1 << 6) +#define MXC_CCM_CIMR_MASK_CAMP2_READY (0x1 << 5) +#define MXC_CCM_CIMR_MASK_CAMP1_READY (0x1 << 4) +#define MXC_CCM_CIMR_MASK_LRF_PLL4 (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) @@ -442,11 +615,20 @@ #define MXC_CCM_CCOSR_CKOL_SEL_MASK (0xF) /* Define the bits in registers CGPR */ +#define MXC_CCM_CGPR_ARM_CLK_INPUT_SEL (0x1 << 24) +#define MXC_CCM_CGPR_ARM_ASYNC_REF_EN (0x1 << 23) #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 MX50_CCM_CCOSR_CKO1_SLOW_SEL (0x1 << 8) +#define MX50_CCM_CCOSR_CKO1_EN (0x1 << 7) +#define MX50_CCM_CCOSR_CKO1_DIV_OFFSET (4) +#define MX50_CCM_CCOSR_CKO1_DIV_MASK (0x7 << 4) +#define MX50_CCM_CCOSR_CKO1_SEL_OFFSET (0) +#define MX50_CCM_CCOSR_CKO1_SEL_MASK (0xF) + /* Define the bits in registers CCGRx */ #define MXC_CCM_CCGRx_CG_MASK 0x3 #define MXC_CCM_CCGRx_MOD_OFF 0x0 @@ -485,30 +667,120 @@ #define MXC_CCM_CCGRx_CG1_OFFSET 2 #define MXC_CCM_CCGRx_CG0_OFFSET 0 -#define MXC_DPTC_LP_BASE (MX51_GPC_BASE + 0x80) -#define MXC_DPTC_GP_BASE (MX51_GPC_BASE + 0x100) -#define MXC_DVFS_CORE_BASE (MX51_GPC_BASE + 0x180) -#define MXC_DPTC_PER_BASE (MX51_GPC_BASE + 0x1C0) -#define MXC_PGC_IPU_BASE (MX51_GPC_BASE + 0x220) -#define MXC_PGC_VPU_BASE (MX51_GPC_BASE + 0x240) -#define MXC_PGC_GPU_BASE (MX51_GPC_BASE + 0x260) -#define MXC_SRPG_NEON_BASE (MX51_GPC_BASE + 0x280) -#define MXC_SRPG_ARM_BASE (MX51_GPC_BASE + 0x2A0) -#define MXC_SRPG_EMPGC0_BASE (MX51_GPC_BASE + 0x2C0) -#define MXC_SRPG_EMPGC1_BASE (MX51_GPC_BASE + 0x2D0) -#define MXC_SRPG_MEGAMIX_BASE (MX51_GPC_BASE + 0x2E0) -#define MXC_SRPG_EMI_BASE (MX51_GPC_BASE + 0x300) +#define MXC_CCM_CCGR5_CG6_1_OFFSET 12 +#define MXC_CCM_CCGR5_CG6_2_OFFSET 13 + +/* Define the bits in registers CSR2 */ +#define MXC_CCM_CSR2_ELCDIF_PIX_BUSY (0x1 << 9) +#define MXC_CCM_CSR2_EPDC_PIX_BUSY (0x1 << 8) +#define MXC_CCM_CSR2_EPDC_AXI_BUSY (0x1 << 4) +#define MXC_CCM_CSR2_DISPLAY_AXI_BUSY (0x1 << 3) + +/* Define the bits in registers CLKSEQ_BYPASS */ +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET 14 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET 12 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_OFFSET 6 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_OFFSET 8 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET 4 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET 2 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK (0x3 << 2) + +/* Define the bits in registers CLK_SYS */ +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET (28) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK (0x3 << 28) +#define MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET (6) +#define MXC_CCM_CLK_SYS_DIV_XTAL_MASK (0xF << 6) +#define MXC_CCM_CLK_SYS_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_SYS_DIV_PLL_MASK (0x3F) + +/* Define the bits in registers CLK_DDR */ +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_DDR_DDR_PFD_SEL (1 << 6) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK (0x3F) + +/* Define the bits in register DISPLAY_AXI */ +#define MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_DISPLAY_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_EN (1 << 13) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_MASK (0x7 << 10) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_OFFSET 10 +#define MXC_CCM_DISPLAY_AXI_DIV_OFFSET (0) +#define MXC_CCM_DISPLAY_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDC_AXI */ +#define MXC_CCM_EPDC_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_AXI_ASM_EN (1 << 9) +#define MXC_CCM_EPDC_AXI_ASM_DIV_OFFSET (6) +#define MXC_CCM_EPDC_AXI_ASM_DIV_MASK (0x7 << 6) +#define MXC_CCM_EPDC_AXI_DIV_OFFSET (0) +#define MXC_CCM_EPDC_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDCPIX */ +#define MXC_CCM_EPDC_PIX_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_PIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_EPDC_PIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_EPDC_PIX_CLK_PODF_MASK (0xFFF) + +/* Define the bits in register ELCDIFPIX */ +#define MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET (30) +#define MXC_CCM_ELCDIFPIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_MASK (0xFFF) + + +/* Define the bits in register GPMI */ +#define MXC_CCM_GPMI_CLKGATE_OFFSET (30) +#define MXC_CCM_GPMI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_GPMI_CLK_DIV_OFFSET (0) +#define MXC_CCM_GPMI_CLK_DIV_MASK (0x3F) + +/* Define the bits in register BCH */ +#define MXC_CCM_BCH_CLKGATE_OFFSET (30) +#define MXC_CCM_BCH_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_BCH_CLK_DIV_OFFSET (0) +#define MXC_CCM_BCH_CLK_DIV_MASK (0x3F) + +#define MXC_GPC_BASE (IO_ADDRESS(GPC_BASE_ADDR)) +#define MXC_DPTC_LP_BASE (MXC_GPC_BASE + 0x80) +#define MXC_DPTC_GP_BASE (MXC_GPC_BASE + 0x100) +#define MXC_DVFS_CORE_BASE (MXC_GPC_BASE + 0x180) +#define MXC_DVFS_PER_BASE (MXC_GPC_BASE + 0x1C4) +#define MXC_PGC_IPU_BASE (MXC_GPC_BASE + 0x220) +#define MXC_PGC_VPU_BASE (MXC_GPC_BASE + 0x240) +#define MXC_PGC_GPU_BASE (MXC_GPC_BASE + 0x260) +#define MXC_SRPG_NEON_BASE (MXC_GPC_BASE + 0x280) +#define MXC_SRPG_ARM_BASE (MXC_GPC_BASE + 0x2A0) +#define MXC_SRPG_EMPGC0_BASE (MXC_GPC_BASE + 0x2C0) +#define MXC_SRPG_EMPGC1_BASE (MXC_GPC_BASE + 0x2D0) +#define MXC_SRPG_MEGAMIX_BASE (MXC_GPC_BASE + 0x2E0) +#define MXC_SRPG_EMI_BASE (MXC_GPC_BASE + 0x300) /* CORTEXA8 platform */ -#define MXC_CORTEXA8_PLAT_PVID (MX51_CORTEXA8_BASE + 0x0) -#define MXC_CORTEXA8_PLAT_GPC (MX51_CORTEXA8_BASE + 0x4) -#define MXC_CORTEXA8_PLAT_PIC (MX51_CORTEXA8_BASE + 0x8) -#define MXC_CORTEXA8_PLAT_LPC (MX51_CORTEXA8_BASE + 0xC) -#define MXC_CORTEXA8_PLAT_NEON_LPC (MX51_CORTEXA8_BASE + 0x10) -#define MXC_CORTEXA8_PLAT_ICGC (MX51_CORTEXA8_BASE + 0x14) -#define MXC_CORTEXA8_PLAT_AMC (MX51_CORTEXA8_BASE + 0x18) -#define MXC_CORTEXA8_PLAT_NMC (MX51_CORTEXA8_BASE + 0x20) -#define MXC_CORTEXA8_PLAT_NMS (MX51_CORTEXA8_BASE + 0x24) +extern void __iomem *arm_plat_base; +#define MXC_CORTEXA8_BASE (arm_plat_base) +#define MXC_CORTEXA8_PLAT_PVID (arm_plat_base + 0x0) +#define MXC_CORTEXA8_PLAT_GPC (arm_plat_base + 0x4) +#define MXC_CORTEXA8_PLAT_PIC (arm_plat_base + 0x8) +#define MXC_CORTEXA8_PLAT_LPC (arm_plat_base + 0xC) +#define MXC_CORTEXA8_PLAT_NEON_LPC (arm_plat_base + 0x10) +#define MXC_CORTEXA8_PLAT_ICGC (arm_plat_base + 0x14) +#define MXC_CORTEXA8_PLAT_AMC (arm_plat_base + 0x18) +#define MXC_CORTEXA8_PLAT_NMC (arm_plat_base + 0x20) +#define MXC_CORTEXA8_PLAT_NMS (arm_plat_base + 0x24) /* DVFS CORE */ #define MXC_DVFSTHRS (MXC_DVFS_CORE_BASE + 0x00) @@ -529,14 +801,23 @@ #define MXC_DVFSPT2 (MXC_DVFS_CORE_BASE + 0x3C) #define MXC_DVFSPT3 (MXC_DVFS_CORE_BASE + 0x40) +/* DVFS PER */ +#define MXC_DVFSPER_LTR0 (MXC_DVFS_PER_BASE) +#define MXC_DVFSPER_LTR1 (MXC_DVFS_PER_BASE + 0x04) +#define MXC_DVFSPER_LTR2 (MXC_DVFS_PER_BASE + 0x08) +#define MXC_DVFSPER_LTR3 (MXC_DVFS_PER_BASE + 0x0C) +#define MXC_DVFSPER_LTBR0 (MXC_DVFS_PER_BASE + 0x10) +#define MXC_DVFSPER_LTBR1 (MXC_DVFS_PER_BASE + 0x14) +#define MXC_DVFSPER_PMCR0 (MXC_DVFS_PER_BASE + 0x18) +#define MXC_DVFSPER_PMCR1 (MXC_DVFS_PER_BASE + 0x1C) + /* GPC */ -#define MXC_GPC_CNTR (MX51_GPC_BASE + 0x0) -#define MXC_GPC_PGR (MX51_GPC_BASE + 0x4) -#define MXC_GPC_VCR (MX51_GPC_BASE + 0x8) -#define MXC_GPC_ALL_PU (MX51_GPC_BASE + 0xC) -#define MXC_GPC_NEON (MX51_GPC_BASE + 0x10) -#define MXC_GPC_PGR_ARMPG_OFFSET 8 -#define MXC_GPC_PGR_ARMPG_MASK (3 << 8) +#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0) +#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) +#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) +#define MXC_GPC_CNTR_OFFSET 0x0 +#define MXC_GPC_PGR_OFFSET 0x4 +#define MXC_GPC_VCR_OFFSET 0x8 /* PGC */ #define MXC_PGC_IPU_PGCR (MXC_PGC_IPU_BASE + 0x0) diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h new file mode 100644 index 000000000000..8235b8c6729b --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * 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. + */ +#include <mach/mx51.h> +#include <mach/devices-common.h> + +extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst; +#define imx51_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst; +#define imx51_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata) + +extern const struct imx_spi_imx_data imx51_cspi_data __initconst; +#define imx51_add_cspi(pdata) \ + imx_add_spi_imx(&imx51_cspi_data, pdata) + +extern const struct imx_spi_imx_data imx51_ecspi_data[] __initconst; +#define imx51_add_ecspi(id, pdata) \ + imx_add_spi_imx(&imx51_ecspi_data[id], pdata) diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 7130449aacdc..68c021c28064 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -1,7 +1,8 @@ /* - * Copyright 2009 Amit Kucheria <amit.kucheria@canonical.com> - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * + * Copyright 2008-2011 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: @@ -10,79 +11,541 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> #include <linux/dma-mapping.h> -#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/ipu.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/uio_driver.h> +#include <linux/mxc_scc2_driver.h> +#include <linux/iram_alloc.h> +#include <linux/gpmi-nfc.h> +#include <linux/fsl_devices.h> +#include <mach/common.h> #include <mach/hardware.h> -#include <mach/imx-uart.h> -#include <mach/irqs.h> +#include <mach/gpio.h> +#include <mach/sdma.h> +#include "dma-apbh.h" -static struct resource uart0[] = { +/* Flag used to indicate when IRAM has been initialized */ +int iram_ready; +/* Flag used to indicate if dvfs_core is active. */ +int dvfs_core_is_active; + +static struct resource sdma_resources[] = { { - .start = MX51_UART1_BASE_ADDR, - .end = MX51_UART1_BASE_ADDR + 0xfff, + .start = SDMA_BASE_ADDR, + .end = SDMA_BASE_ADDR + SZ_4K - 1, .flags = IORESOURCE_MEM, - }, { - .start = MX51_MXC_INT_UART1, - .end = MX51_MXC_INT_UART1, + }, + { + .start = MXC_INT_SDMA, .flags = IORESOURCE_IRQ, }, }; -struct platform_device mxc_uart_device0 = { - .name = "imx-uart", +struct platform_device mxc_dma_device = { + .name = "mxc_sdma", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(sdma_resources), + .resource = sdma_resources, +}; + +static struct resource mxc_w1_master_resources[] = { + { + .start = OWIRE_BASE_ADDR, + .end = OWIRE_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_OWIRE, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_w1_master_device = { + .name = "mxc_w1", .id = 0, - .resource = uart0, - .num_resources = ARRAY_SIZE(uart0), + .num_resources = ARRAY_SIZE(mxc_w1_master_resources), + .resource = mxc_w1_master_resources, }; -static struct resource uart1[] = { +static struct resource mxc_kpp_resources[] = { { - .start = MX51_UART2_BASE_ADDR, - .end = MX51_UART2_BASE_ADDR + 0xfff, + .start = KPP_BASE_ADDR, + .end = KPP_BASE_ADDR + SZ_4K - 1, .flags = IORESOURCE_MEM, - }, { - .start = MX51_MXC_INT_UART2, - .end = MX51_MXC_INT_UART2, + }, + { + .start = MXC_INT_KPP, + .end = MXC_INT_KPP, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_keypad_device = { + .name = "mxc_keypad", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_kpp_resources), + .resource = mxc_kpp_resources, +}; + +struct platform_device mxc_powerkey_device = { + .name = "mxcpwrkey", + .id = 0, +}; +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, + }, +}; + +struct platform_device mxc_rtc_device = { + .name = "mxc_rtc", + .id = 0, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = MX51_NFC_BASE_ADDR_AXI, + .end = MX51_NFC_BASE_ADDR_AXI + SZ_8K - 1, + }, + { + .flags = IORESOURCE_MEM, + .name = "NFC_IP_BASE", + .start = NFC_BASE_ADDR + 0x00, + .end = NFC_BASE_ADDR + 0x34 - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NFC, + .end = MXC_INT_NFC, + }, +}; + +struct platform_device mxc_nandv2_mtd_device = { + .name = "mxc_nandv2_flash", + .id = 0, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), +}; + +static struct resource gpmi_nfc_resources[] = { + { + .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = GPMI_BASE_ADDR, + .end = GPMI_BASE_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_RAWNAND_GPMI, + .end = MXC_INT_RAWNAND_GPMI, + }, + { + .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = BCH_BASE_ADDR, + .end = BCH_BASE_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_RAWNAND_BCH, + .end = MXC_INT_RAWNAND_BCH, + }, + { + .name = GPMI_NFC_DMA_CHANNELS_RES_NAME, + .flags = IORESOURCE_DMA, + .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7, + }, + { + .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_APBHDMA_CHAN0, + .end = MXC_INT_APBHDMA_CHAN7, + }, +}; + +struct platform_device gpmi_nfc_device = { + .name = GPMI_NFC_DRIVER_NAME, + .id = 0, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = gpmi_nfc_resources, + .num_resources = ARRAY_SIZE(gpmi_nfc_resources), +}; + +static struct resource imx_nfc_resources[] = { + { + .flags = IORESOURCE_MEM, + .start = MX51_NFC_BASE_ADDR_AXI, + .end = MX51_NFC_BASE_ADDR_AXI + 0x1200 - 1, + .name = IMX_NFC_BUFFERS_ADDR_RES_NAME, + }, + { + .flags = IORESOURCE_MEM, + .start = MX51_NFC_BASE_ADDR_AXI + 0x1E00, + .end = MX51_NFC_BASE_ADDR_AXI + 0x1E44 - 1, + .name = IMX_NFC_PRIMARY_REGS_ADDR_RES_NAME, + }, + { + .flags = IORESOURCE_MEM, + .start = NFC_BASE_ADDR + 0x00, + .end = NFC_BASE_ADDR + 0x34 - 1, + .name = IMX_NFC_SECONDARY_REGS_ADDR_RES_NAME, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NFC, + .end = MXC_INT_NFC, + .name = IMX_NFC_INTERRUPT_RES_NAME, + }, +}; + +struct platform_device imx_nfc_device = { + .name = IMX_NFC_DRIVER_NAME, + .id = 0, + .resource = imx_nfc_resources, + .num_resources = ARRAY_SIZE(imx_nfc_resources), +}; + +static struct resource wdt_resources[] = { + { + .start = WDOG1_BASE_ADDR, + .end = WDOG1_BASE_ADDR + 0x30, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxc_wdt_device = { + .name = "mxc_wdt", + .id = 0, + .num_resources = ARRAY_SIZE(wdt_resources), + .resource = wdt_resources, +}; + +static struct resource pwm1_resources[] = { + { + .start = PWM1_BASE_ADDR, + .end = PWM1_BASE_ADDR + 0x14, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_PWM1, + .end = MXC_INT_PWM1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_pwm1_device = { + .name = "mxc_pwm", + .id = 0, + .num_resources = ARRAY_SIZE(pwm1_resources), + .resource = pwm1_resources, +}; + +static struct resource pwm2_resources[] = { + { + .start = PWM2_BASE_ADDR, + .end = PWM2_BASE_ADDR + 0x14, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_PWM2, + .end = MXC_INT_PWM2, .flags = IORESOURCE_IRQ, }, }; -struct platform_device mxc_uart_device1 = { - .name = "imx-uart", +struct platform_device mxc_pwm2_device = { + .name = "mxc_pwm", .id = 1, - .resource = uart1, - .num_resources = ARRAY_SIZE(uart1), + .num_resources = ARRAY_SIZE(pwm2_resources), + .resource = pwm2_resources, }; -static struct resource uart2[] = { +struct platform_device mxc_pwm1_backlight_device = { + .name = "pwm-backlight", + .id = 0, +}; + +struct platform_device mxc_pwm2_backlight_device = { + .name = "pwm-backlight", + .id = 1, +}; + +static struct resource flexcan0_resources[] = { { - .start = MX51_UART3_BASE_ADDR, - .end = MX51_UART3_BASE_ADDR + 0xfff, + .start = CAN1_BASE_ADDR, + .end = CAN1_BASE_ADDR + 0x3FFF, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN1, + .end = MXC_INT_CAN1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_flexcan0_device = { + .name = "FlexCAN", + .id = 0, + .num_resources = ARRAY_SIZE(flexcan0_resources), + .resource = flexcan0_resources, +}; + +static struct resource flexcan1_resources[] = { + { + .start = CAN2_BASE_ADDR, + .end = CAN2_BASE_ADDR + 0x3FFF, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN2, + .end = MXC_INT_CAN2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_flexcan1_device = { + .name = "FlexCAN", + .id = 1, + .num_resources = ARRAY_SIZE(flexcan1_resources), + .resource = flexcan1_resources, +}; + +static struct resource ipu_resources[] = { + { + .start = MX51_IPU_CTRL_BASE_ADDR, + .end = MX51_IPU_CTRL_BASE_ADDR + SZ_512M, .flags = IORESOURCE_MEM, - }, { - .start = MX51_MXC_INT_UART3, - .end = MX51_MXC_INT_UART3, + }, + { + .start = MXC_INT_IPU_SYN, + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_IPU_ERR, .flags = IORESOURCE_IRQ, }, }; -struct platform_device mxc_uart_device2 = { - .name = "imx-uart", - .id = 2, - .resource = uart2, - .num_resources = ARRAY_SIZE(uart2), +struct platform_device mxc_ipu_device = { + .name = "mxc_ipu", + .id = -1, + .num_resources = ARRAY_SIZE(ipu_resources), + .resource = ipu_resources, }; -static struct resource mxc_fec_resources[] = { +static struct resource epdc_resources[] = { + { + .start = EPDC_BASE_ADDR, + .end = EPDC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_EPDC, + .end = MXC_INT_EPDC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device epdc_device = { + .name = "mxc_epdc_fb", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(epdc_resources), + .resource = epdc_resources, +}; + +static struct resource elcdif_resources[] = { + { + .start = ELCDIF_BASE_ADDR, + .end = ELCDIF_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ELCDIF, + .end = MXC_INT_ELCDIF, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device elcdif_device = { + .name = "mxc_elcdif_fb", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(elcdif_resources), + .resource = elcdif_resources, +}; + +struct platform_device mxc_fb_devices[] = { + { + .name = "mxc_sdc_fb", + .id = 0, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, + { + .name = "mxc_sdc_fb", + .id = 1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, + { + .name = "mxc_sdc_fb", + .id = 2, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +}; + +static struct resource ldb_resources[] = { + { + .start = IOMUXC_BASE_ADDR, + .end = IOMUXC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxc_ldb_device = { + .name = "mxc_ldb", + .id = -1, + .num_resources = ARRAY_SIZE(ldb_resources), + .resource = ldb_resources, +}; + +static struct resource vpu_resources[] = { + { + .start = VPU_BASE_ADDR, + .end = VPU_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { - .start = MX51_MXC_FEC_BASE_ADDR, - .end = MX51_MXC_FEC_BASE_ADDR + 0xfff, + .start = MXC_INT_VPU, + .end = MXC_INT_VPU, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxcvpu_device = { + .name = "mxc_vpu", + .id = 0, + .num_resources = ARRAY_SIZE(vpu_resources), + .resource = vpu_resources, +}; + +struct platform_device fixed_volt_reg_device = { + .name = "reg-fixed-voltage", + .id = -1, +}; + +static struct resource scc_resources[] = { + { + .start = SCC_BASE_ADDR, + .end = SCC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_SCC_RAM_BASE_ADDR, + .end = MX51_SCC_RAM_BASE_ADDR + SZ_16K - 1, .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxcscc_device = { + .name = "mxc_scc", + .id = 0, + .num_resources = ARRAY_SIZE(scc_resources), + .resource = scc_resources, +}; + +static struct resource dcp_resources[] = { + + { + .flags = IORESOURCE_MEM, + .start = DCP_BASE_ADDR, + .end = DCP_BASE_ADDR + 0x2000 - 1, }, { - .start = MX51_MXC_INT_FEC, - .end = MX51_MXC_INT_FEC, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_DCP_CHAN0, + .end = MXC_INT_DCP_CHAN0, + }, { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_DCP_CHAN1_3, + .end = MXC_INT_DCP_CHAN1_3, + }, +}; + +struct platform_device dcp_device = { + .name = "dcp", + .id = 0, + .num_resources = ARRAY_SIZE(dcp_resources), + .resource = dcp_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + + +static struct resource rngb_resources[] = { + { + .start = RNGB_BASE_ADDR, + .end = RNGB_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_RNGB_BLOCK, + .flags = IORESOURCE_IRQ, + }, +}; + +/* the RNGC driver applies for MX50's RNGB hw */ +struct platform_device mxc_rngb_device = { + .name = "fsl_rngc", + .id = 0, + .num_resources = ARRAY_SIZE(rngb_resources), + .resource = rngb_resources, +}; + +static struct resource mxc_fec_resources[] = { + { + .start = FEC_BASE_ADDR, + .end = FEC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM + }, + { + .start = MXC_INT_FEC, + .end = MXC_INT_FEC, + .flags = IORESOURCE_IRQ }, }; @@ -93,57 +556,734 @@ struct platform_device mxc_fec_device = { .resource = mxc_fec_resources, }; +static struct resource mxc_ptp_resources[] = { + { + .start = PTP_BASE_ADDR, + .end = PTP_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM + }, + { + .start = RTC_BASE_ADDR, + .end = RTC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM + }, + { + .start = MXC_INT_PTP, + .end = MXC_INT_PTP, + .flags = IORESOURCE_IRQ + }, + { + .start = MXC_INT_RTC, + .end = MXC_INT_RTC, + .flags = IORESOURCE_IRQ + }, +}; + +struct platform_device mxc_ptp_device = { + .name = "ptp", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_ptp_resources), + .resource = mxc_ptp_resources, +}; + +static struct resource mxcspi1_resources[] = { + { + .start = CSPI1_BASE_ADDR, + .end = CSPI1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI1, + .end = MXC_INT_CSPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxcspi1_device = { + .name = "mxc_spi", + .id = 0, + .num_resources = ARRAY_SIZE(mxcspi1_resources), + .resource = mxcspi1_resources, +}; + +static struct resource mxcspi2_resources[] = { + { + .start = CSPI2_BASE_ADDR, + .end = CSPI2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI2, + .end = MXC_INT_CSPI2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxcspi2_device = { + .name = "mxc_spi", + .id = 1, + .num_resources = ARRAY_SIZE(mxcspi2_resources), + .resource = mxcspi2_resources, +}; + +static struct resource mxcspi3_resources[] = { + { + .start = CSPI3_BASE_ADDR, + .end = CSPI3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI, + .end = MXC_INT_CSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxcspi3_device = { + .name = "mxc_spi", + .id = 2, + .num_resources = ARRAY_SIZE(mxcspi3_resources), + .resource = mxcspi3_resources, +}; + +static struct resource mxci2c1_resources[] = { + { + .start = I2C1_BASE_ADDR, + .end = I2C1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C1, + .end = MXC_INT_I2C1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mxci2c2_resources[] = { + { + .start = I2C2_BASE_ADDR, + .end = I2C2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C2, + .end = MXC_INT_I2C2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mxci2c3_resources[] = { + { + .start = I2C3_BASE_ADDR, + .end = I2C3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C3, + .end = MXC_INT_I2C3, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxci2c_devices[] = { + { + .name = "imx-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(mxci2c1_resources), + .resource = mxci2c1_resources, + }, + { + .name = "imx-i2c", + .id = 1, + .num_resources = ARRAY_SIZE(mxci2c2_resources), + .resource = mxci2c2_resources, + }, + { + .name = "imx-i2c", + .id = 2, + .num_resources = ARRAY_SIZE(mxci2c3_resources), + .resource = mxci2c3_resources, + }, +}; + +static struct resource mxci2c_hs_resources[] = { + { + .start = HSI2C_DMA_BASE_ADDR, + .end = HSI2C_DMA_BASE_ADDR + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_HS_I2C, + .end = MXC_INT_HS_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxci2c_hs_device = { + .name = "mxc_i2c_hs", + .id = 3, + .num_resources = ARRAY_SIZE(mxci2c_hs_resources), + .resource = mxci2c_hs_resources +}; + +static struct resource ssi1_resources[] = { + { + .start = SSI1_BASE_ADDR, + .end = SSI1_BASE_ADDR + 0x5C, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SSI1, + .end = MXC_INT_SSI1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_ssi1_device = { + .name = "mxc_ssi", + .id = 0, + .num_resources = ARRAY_SIZE(ssi1_resources), + .resource = ssi1_resources, +}; + +static struct resource ssi2_resources[] = { + { + .start = SSI2_BASE_ADDR, + .end = SSI2_BASE_ADDR + 0x5C, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SSI2, + .end = MXC_INT_SSI2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_ssi2_device = { + .name = "mxc_ssi", + .id = 1, + .num_resources = ARRAY_SIZE(ssi2_resources), + .resource = ssi2_resources, +}; + +static struct resource ssi3_resources[] = { + { + .start = SSI3_BASE_ADDR, + .end = SSI3_BASE_ADDR + 0x5C, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SSI3, + .end = MXC_INT_SSI3, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_ssi3_device = { + .name = "mxc_ssi", + .id = 2, + .num_resources = ARRAY_SIZE(ssi3_resources), + .resource = ssi3_resources, +}; + +static struct resource esai_resources[] = { + { + .start = ESAI_BASE_ADDR, + .end = ESAI_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ESAI, + .end = MXC_INT_ESAI, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_esai_device = { + .name = "mxc_esai", + .id = 0, + .num_resources = ARRAY_SIZE(esai_resources), + .resource = esai_resources, +}; + +static struct resource tve_resources[] = { + { + .start = TVE_BASE_ADDR, + .end = TVE_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_TVE, + .end = MXC_INT_TVE, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_tve_device = { + .name = "tve", + .num_resources = ARRAY_SIZE(tve_resources), + .resource = tve_resources, +}; + +static struct resource dvfs_core_resources[] = { + { + .start = DVFSCORE_BASE_ADDR, + .end = DVFSCORE_BASE_ADDR + 4 * SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_GPC1, + .end = MXC_INT_GPC1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_dvfs_core_device = { + .name = "mxc_dvfs_core", + .id = 0, + .num_resources = ARRAY_SIZE(dvfs_core_resources), + .resource = dvfs_core_resources, +}; + +static struct resource dvfs_per_resources[] = { + { + .start = DVFSPER_BASE_ADDR, + .end = DVFSPER_BASE_ADDR + 2 * SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_GPC1, + .end = MXC_INT_GPC1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_dvfs_per_device = { + .name = "mxc_dvfsper", + .id = 0, + .num_resources = ARRAY_SIZE(dvfs_per_resources), + .resource = dvfs_per_resources, +}; + +static struct resource asrc_resources[] = { + { + .start = ASRC_BASE_ADDR, + .end = ASRC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ASRC, + .end = MXC_INT_ASRC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_asrc_device = { + .name = "mxc_asrc", + .id = 0, + .num_resources = ARRAY_SIZE(asrc_resources), + .resource = asrc_resources, +}; + +struct mxc_gpio_port mxc_gpio_ports[] = { + { + .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 + }, + { + .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 * 1 + }, + { + .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 + }, + { + .chip.label = "gpio-3", + .base = IO_ADDRESS(GPIO4_BASE_ADDR), + .irq = MXC_INT_GPIO4_LOW, + .irq_high = MXC_INT_GPIO4_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 + }, + { + .chip.label = "gpio-4", + .base = IO_ADDRESS(GPIO5_BASE_ADDR), + .irq = MXC_INT_GPIO5_LOW, + .irq_high = MXC_INT_GPIO5_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 4 + }, + { + .chip.label = "gpio-5", + .base = IO_ADDRESS(GPIO6_BASE_ADDR), + .irq = MXC_INT_GPIO6_LOW, + .irq_high = MXC_INT_GPIO6_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 5 + }, + { + .chip.label = "gpio-6", + .base = IO_ADDRESS(GPIO7_BASE_ADDR), + .irq = MXC_INT_GPIO7_LOW, + .irq_high = MXC_INT_GPIO7_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 6 + }, +}; + +int __init mxc_register_gpios(void) +{ + if (cpu_is_mx51()) + return mxc_gpio_init(mxc_gpio_ports, 4); + else if (cpu_is_mx50()) + return mxc_gpio_init(mxc_gpio_ports, 6); + return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); +} + +static struct resource spdif_resources[] = { + { + .start = SPDIF_BASE_ADDR, + .end = SPDIF_BASE_ADDR + 0x50, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SPDIF_MX51, + .end = MXC_INT_SPDIF_MX51, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_alsa_spdif_device = { + .name = "mxc_alsa_spdif", + .id = 0, + .num_resources = ARRAY_SIZE(spdif_resources), + .resource = spdif_resources, +}; + +struct platform_device mx51_lpmode_device = { + .name = "mx51_lpmode", + .id = 0, +}; + +struct platform_device busfreq_device = { + .name = "busfreq", + .id = 0, +}; + +struct platform_device pm_device = { + .name = "mx5_pm", + .id = 0, +}; + +static struct resource mxc_m4if_resources[] = { + { + .start = M4IF_BASE_ADDR, + .end = M4IF_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device sdram_autogating_device = { + .name = "sdram_autogating", + .id = 0, + .resource = mxc_m4if_resources, + .num_resources = ARRAY_SIZE(mxc_m4if_resources), +}; + +static struct resource mxc_iim_resources[] = { + { + .start = IIM_BASE_ADDR, + .end = IIM_BASE_ADDR + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_IIM, + .end = MXC_INT_IIM, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_iim_device = { + .name = "mxc_iim", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_iim_resources), + .resource = mxc_iim_resources +}; + +static struct resource mxc_sim_resources[] = { + { + .start = SIM_BASE_ADDR, + .end = SIM_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SIM_IPB, + .end = MXC_INT_SIM_IPB, + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_SIM_DAT, + .end = MXC_INT_SIM_DAT, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_sim_device = { + .name = "mxc_sim", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_sim_resources), + .resource = mxc_sim_resources, +}; + +static struct resource mxcsdhc1_resources[] = { + { + .start = MMC_SDHC1_BASE_ADDR, + .end = MMC_SDHC1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_MMC_SDHC1, + .end = MXC_INT_MMC_SDHC1, + .flags = IORESOURCE_IRQ, + }, + { + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mxcsdhc2_resources[] = { + { + .start = MMC_SDHC2_BASE_ADDR, + .end = MMC_SDHC2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_MMC_SDHC2, + .end = MXC_INT_MMC_SDHC2, + .flags = IORESOURCE_IRQ, + }, + { + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mxcsdhc3_resources[] = { + { + .start = MMC_SDHC3_BASE_ADDR, + .end = MMC_SDHC3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_MMC_SDHC3, + .end = MXC_INT_MMC_SDHC3, + .flags = IORESOURCE_IRQ, + }, + { + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxcsdhc1_device = { + .name = "mxsdhci", + .id = 0, + .num_resources = ARRAY_SIZE(mxcsdhc1_resources), + .resource = mxcsdhc1_resources, +}; + +struct platform_device mxcsdhc2_device = { + .name = "mxsdhci", + .id = 1, + .num_resources = ARRAY_SIZE(mxcsdhc2_resources), + .resource = mxcsdhc2_resources, +}; + +struct platform_device mxcsdhc3_device = { + .name = "mxsdhci", + .id = 2, + .num_resources = ARRAY_SIZE(mxcsdhc3_resources), + .resource = mxcsdhc3_resources, +}; + +static struct resource pata_fsl_resources[] = { + { + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000C8, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pata_fsl_device = { + .name = "pata_fsl", + .id = -1, + .num_resources = ARRAY_SIZE(pata_fsl_resources), + .resource = pata_fsl_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +/* On-Chip OTP device and resource */ +static struct resource otp_resource = { + .start = OCOTP_CTRL_BASE_ADDR, + .end = OCOTP_CTRL_BASE_ADDR + SZ_8K - 1, + .flags = IORESOURCE_MEM, +}; + +struct platform_device fsl_otp_device = { + .name = "ocotp", + .id = -1, + .resource = &otp_resource, + .num_resources = 1, +}; + +static struct resource ahci_fsl_resources[] = { + { + .start = MX53_SATA_BASE_ADDR, + .end = MX53_SATA_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SATA, + .end = MXC_INT_SATA, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ahci_fsl_device = { + .name = "ahci", + .id = 0, + .num_resources = ARRAY_SIZE(ahci_fsl_resources), + .resource = ahci_fsl_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + static u64 usb_dma_mask = DMA_BIT_MASK(32); -static struct resource usbotg_resources[] = { +static struct resource usbotg_host_resources[] = { + { + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource usbotg_udc_resources[] = { + { + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource usbotg_xcvr_resources[] = { { - .start = MX51_OTG_BASE_ADDR, - .end = MX51_OTG_BASE_ADDR + 0x1ff, + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_USB_OTG, + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource usbotg_wakeup_resources[] = { + { + .start = MXC_INT_USB_OTG,/* wakeup irq */ + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_USB_OTG,/* usb core irq , may be equel to wakeup irq for some imx chips */ .flags = IORESOURCE_IRQ, }, }; -/* OTG gadget device */ struct platform_device mxc_usbdr_udc_device = { .name = "fsl-usb2-udc", .id = -1, - .num_resources = ARRAY_SIZE(usbotg_resources), - .resource = usbotg_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = usbotg_udc_resources, + .num_resources = ARRAY_SIZE(usbotg_udc_resources), +}; + +struct platform_device mxc_usbdr_otg_device = { + .name = "fsl-usb2-otg", + .id = -1, .dev = { .dma_mask = &usb_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), }, + .resource = usbotg_xcvr_resources, + .num_resources = ARRAY_SIZE(usbotg_xcvr_resources), }; struct platform_device mxc_usbdr_host_device = { - .name = "mxc-ehci", + .name = "fsl-ehci", .id = 0, - .num_resources = ARRAY_SIZE(usbotg_resources), - .resource = usbotg_resources, + .num_resources = ARRAY_SIZE(usbotg_host_resources), + .resource = usbotg_host_resources, .dev = { .dma_mask = &usb_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), }, }; +struct platform_device mxc_usbdr_wakeup_device = { + .name = "usb_wakeup", + .id = 0, + .num_resources = ARRAY_SIZE(usbotg_wakeup_resources), + .resource = usbotg_wakeup_resources, +}; + static struct resource usbh1_resources[] = { { - .start = MX51_OTG_BASE_ADDR + 0x200, - .end = MX51_OTG_BASE_ADDR + 0x200 + 0x1ff, + .start = OTG_BASE_ADDR + 0x200, + .end = OTG_BASE_ADDR + 0x200 + 0x1ff, .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_USB_H1, + .start = MXC_INT_USB_H1, .flags = IORESOURCE_IRQ, }, }; +static struct resource usbh1_wakeup_resources[] = { + { + .start = MXC_INT_USB_H1, /*wakeup irq*/ + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_USB_H1, + .flags = IORESOURCE_IRQ,/* usb core irq */ + }, +}; + struct platform_device mxc_usbh1_device = { - .name = "mxc-ehci", + .name = "fsl-ehci", .id = 1, .num_resources = ARRAY_SIZE(usbh1_resources), .resource = usbh1_resources, @@ -153,49 +1293,607 @@ struct platform_device mxc_usbh1_device = { }, }; -static struct resource mxc_wdt_resources[] = { +struct platform_device mxc_usbh1_wakeup_device = { + .name = "usb_wakeup", + .id = 1, + .num_resources = ARRAY_SIZE(usbh1_wakeup_resources), + .resource = usbh1_wakeup_resources, +}; + +static struct resource usbh2_resources[] = { { - .start = MX51_WDOG_BASE_ADDR, - .end = MX51_WDOG_BASE_ADDR + SZ_16K - 1, + .start = OTG_BASE_ADDR + 0x400, + .end = OTG_BASE_ADDR + 0x400 + 0x1ff, .flags = IORESOURCE_MEM, }, + { + .start = MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ, + }, }; -struct platform_device mxc_wdt = { - .name = "imx2-wdt", +static struct resource usbh2_wakeup_resources[] = { + { + .start = MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ,/* wakeup irq */ + }, + { + .start = MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ,/* usb core irq */ + }, +}; +struct platform_device mxc_usbh2_device = { + .name = "fsl-ehci", + .id = 2, + .num_resources = ARRAY_SIZE(usbh2_resources), + .resource = usbh2_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct platform_device mxc_usbh2_wakeup_device = { + .name = "usb_wakeup", + .id = 2, + .num_resources = ARRAY_SIZE(usbh2_wakeup_resources), + .resource = usbh2_wakeup_resources, +}; + +static struct resource mxc_gpu_resources[] = { + { + .start = MXC_INT_GPU2_IRQ, + .end = MXC_INT_GPU2_IRQ, + .name = "gpu_2d_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = MXC_INT_GPU, + .end = MXC_INT_GPU, + .name = "gpu_3d_irq", + .flags = IORESOURCE_IRQ, + }, + { + .start = MX51_GPU2D_BASE_ADDR, + .end = MX51_GPU2D_BASE_ADDR + SZ_4K - 1, + .name = "gpu_2d_registers", + .flags = IORESOURCE_MEM, + }, + { + .start = GPU_BASE_ADDR, + .end = GPU_BASE_ADDR + SZ_128K - 1, + .name = "gpu_3d_registers", + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_GPU_GMEM_BASE_ADDR, + .end = MX51_GPU_GMEM_BASE_ADDR + SZ_128K - 1, + .name = "gpu_graphics_mem", + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .name = "gpu_reserved_mem", + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device gpu_device = { + .name = "mxc_gpu", .id = 0, - .num_resources = ARRAY_SIZE(mxc_wdt_resources), - .resource = mxc_wdt_resources, + .num_resources = ARRAY_SIZE(mxc_gpu_resources), + .resource = mxc_gpu_resources, }; -static struct mxc_gpio_port mxc_gpio_ports[] = { +int z160_revision; + +static struct resource mxc_gpu2d_resources[] = { { - .chip.label = "gpio-0", - .base = MX51_IO_ADDRESS(MX51_GPIO1_BASE_ADDR), - .irq = MX51_MXC_INT_GPIO1_LOW, - .virtual_irq_start = MXC_GPIO_IRQ_START + .start = MX51_GPU2D_BASE_ADDR, + .end = MX51_GPU2D_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, }, { - .chip.label = "gpio-1", - .base = MX51_IO_ADDRESS(MX51_GPIO2_BASE_ADDR), - .irq = MX51_MXC_INT_GPIO2_LOW, - .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1 + .flags = IORESOURCE_MEM, }, { - .chip.label = "gpio-2", - .base = MX51_IO_ADDRESS(MX51_GPIO3_BASE_ADDR), - .irq = MX51_MXC_INT_GPIO3_LOW, - .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 + .flags = IORESOURCE_MEM, }, +}; + +static struct resource mlb_resources[] = { + [0] = { + .start = MLB_BASE_ADDR, + .end = MLB_BASE_ADDR + 0x300, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_MLB, + .end = MXC_INT_MLB, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_mlb_device = { + .name = "mxc_mlb", + .id = 0, + .num_resources = ARRAY_SIZE(mlb_resources), + .resource = mlb_resources, +}; + +static struct resource pxp_resources[] = { { - .chip.label = "gpio-3", - .base = MX51_IO_ADDRESS(MX51_GPIO4_BASE_ADDR), - .irq = MX51_MXC_INT_GPIO4_LOW, - .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 + .start = EPXP_BASE_ADDR, + .end = EPXP_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_EPXP, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_pxp_device = { + .name = "mxc-pxp", + .id = -1, + .num_resources = ARRAY_SIZE(pxp_resources), + .resource = pxp_resources, +}; + +struct platform_device mxc_pxp_client_device = { + .name = "pxp-device", + .id = -1, +}; + +static u64 pxp_dma_mask = DMA_BIT_MASK(32); +struct platform_device mxc_pxp_v4l2 = { + .name = "pxp-v4l2", + .id = -1, + .dev = { + .dma_mask = &pxp_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; -int __init mxc_register_gpios(void) +struct platform_device mxc_v4l2_device = { + .name = "mxc_v4l2_capture", + .id = 0, +}; + +struct platform_device mxc_v4l2out_device = { + .name = "mxc_v4l2_output", + .id = 0, +}; + +struct resource viim_resources[] = { + [0] = { + .start = (GPT1_BASE_ADDR - 0x20000000), + .end = (GPT1_BASE_ADDR - 0x20000000) + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OCOTP_CTRL_BASE_ADDR, + .end = OCOTP_CTRL_BASE_ADDR + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; +struct platform_device mxs_viim = { + .name = "mxs_viim", + .id = -1, + .num_resources = ARRAY_SIZE(viim_resources), + .resource = viim_resources, +}; + +static struct resource mx5_perfmon_res[] = { + { + .flags = IORESOURCE_MEM, + .start = PERFMON_BASE_ADDR, + .end = PERFMON_BASE_ADDR + 0x1000 - 1, + }, +}; + +struct platform_device mxc_perfmon = { + .name = "mxs-perfmon", + .resource = mx5_perfmon_res, + .num_resources = ARRAY_SIZE(mx5_perfmon_res), + .id = 0 +}; + +static struct mxs_perfmon_bit_config +mx50_perfmon_bit_config[] = { + {.field = (1 << 0), .name = "MID0-CORE" }, + {.field = (1 << 1), .name = "MID1-DCP" }, + {.field = (1 << 2), .name = "MID2-PXP" }, + {.field = (1 << 3), .name = "MID3-USB" }, + {.field = (1 << 4), .name = "MID4-GPU2D" }, + {.field = (1 << 5), .name = "MID5-BCH" }, + {.field = (1 << 6), .name = "MID6-AHB" }, + {.field = (1 << 7), .name = "MID7-EPDC" }, + {.field = (1 << 8), .name = "MID8-LCDIF" }, + {.field = (1 << 9), .name = "MID9-SDMA" }, + {.field = (1 << 10), .name = "MID10-FEC" }, + {.field = (1 << 11), .name = "MID11-MSHC" } +}; + +struct mxs_platform_perfmon_data mxc_perfmon_data = { + .bit_config_tab = mx50_perfmon_bit_config, + .bit_config_cnt = ARRAY_SIZE(mx50_perfmon_bit_config), +}; + +static struct resource dma_apbh_resources[] = { + { + .start = APBHDMA_BASE_ADDR, + .end = APBHDMA_BASE_ADDR + 0x2000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxs_dma_apbh_device = { + .name = "mxs-dma-apbh", + .num_resources = ARRAY_SIZE(dma_apbh_resources), + .resource = dma_apbh_resources, +}; + +struct platform_device mxc_zq_calib_device = { + .name = "mxc_zq_calib", + .id = -1, +}; + +void __init mx5_init_irq(void) { - return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); + unsigned long tzic_addr; + + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) + tzic_addr = MX51_TZIC_BASE_ADDR_T01; + else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) + tzic_addr = MX51_TZIC_BASE_ADDR; + else /* mx53 and mx50 */ + tzic_addr = MX53_TZIC_BASE_ADDR; + + mxc_tzic_init_irq(tzic_addr); } + +#define SCM_RD_DELAY 1000000 /* in nanoseconds */ +#define SEC_TO_NANOSEC 1000000000 /*Second to nanoseconds */ +static __init void mxc_init_scc_iram(void) +{ + uint32_t reg_value; + uint32_t reg_mask = 0; + 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; + uint32_t ram_partitions, ram_partition_size, ram_size; + uint32_t scm_version_register; + struct timespec stime; + struct timespec curtime; + long scm_rd_timeout = 0; + long cur_ns = 0; + long start_ns = 0; + + scc_base = ioremap((uint32_t) scc_resources[0].start, 0x140); + if (scc_base == NULL) { + printk(KERN_ERR "FAILED TO MAP SCC REGS\n"); + return; + } + + scm_version_register = __raw_readl(scc_base + SCM_VERSION_REG); + ram_partitions = 1 + ((scm_version_register & SCM_VER_NP_MASK) + >> SCM_VER_NP_SHIFT); + ram_partition_size = (uint32_t) (1 << + ((scm_version_register & SCM_VER_BPP_MASK) + >> SCM_VER_BPP_SHIFT)); + + ram_size = (uint32_t)(ram_partitions * ram_partition_size); + + scm_ram_base = ioremap((uint32_t) scc_resources[1].start, ram_size); + + if (scm_ram_base == NULL) { + printk(KERN_ERR "FAILED TO MAP SCC RAM\n"); + return; + } + + /* Wait for any running SCC operations to finish or fail */ + getnstimeofday(&stime); + do { + reg_value = __raw_readl(scc_base + SCM_STATUS_REG); + getnstimeofday(&curtime); + if (curtime.tv_nsec > stime.tv_nsec) + scm_rd_timeout = curtime.tv_nsec - stime.tv_nsec; + else{ + /*Converted second to nanosecond and add to + nsec when current nanosec is less than + start time nanosec.*/ + cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) + + curtime.tv_nsec; + start_ns = (stime.tv_sec * SEC_TO_NANOSEC) + + stime.tv_nsec; + scm_rd_timeout = cur_ns - start_ns; + } + } while (((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY) + && ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_FAIL)); + + /* Check for failures */ + if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY) { + /* Special message for bad secret key fuses */ + if (reg_value & SCM_STATUS_KST_BAD_KEY) + printk(KERN_ERR "INVALID SCC KEY FUSE PATTERN\n"); + else + printk(KERN_ERR "SECURE RAM FAILURE\n"); + + iounmap(scm_ram_base); + iounmap(scc_base); + return; + } + + scm_rd_timeout = 0; + + /* Release all partitions for SCC2 driver on MX53*/ + if (cpu_is_mx53()) + scc_partno = 0; + /* Release final two partitions for SCC2 driver on MX51 */ + else + scc_partno = ram_partitions - + (SCC_RAM_SIZE / ram_partition_size); + + for (partition_no = scc_partno; partition_no < ram_partitions; + 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); + udelay(1); + /* Wait for zeroization to complete */ + getnstimeofday(&stime); + do { + reg_value = __raw_readl(scc_base + SCM_STATUS_REG); + getnstimeofday(&curtime); + if (curtime.tv_nsec > stime.tv_nsec) + scm_rd_timeout = curtime.tv_nsec - + stime.tv_nsec; + else { + /*Converted second to nanosecond and add to + nsec when current nanosec is less than + start time nanosec.*/ + cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) + + curtime.tv_nsec; + start_ns = (stime.tv_sec * SEC_TO_NANOSEC) + + stime.tv_nsec; + scm_rd_timeout = cur_ns - start_ns; + } + } while (((reg_value & SCM_STATUS_SRS_MASK) != + SCM_STATUS_SRS_READY) && ((reg_value & SCM_STATUS_SRS_MASK) != + SCM_STATUS_SRS_FAIL) && (scm_rd_timeout <= SCM_RD_DELAY)); + + if (scm_rd_timeout > SCM_RD_DELAY) + printk(KERN_ERR "SCM Status Register Read timeout" + "for Partition No:%d", partition_no); + + if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY) + break; + } + + /* 4 partitions on MX53 */ + if (cpu_is_mx53()) + reg_mask = 0xFF; + + /*Check all expected partitions released */ + reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG); + if ((reg_value & reg_mask) != 0) { + printk(KERN_ERR "FAILED TO RELEASE IRAM PARTITION\n"); + iounmap(scm_ram_base); + iounmap(scc_base); + return; + } + + /* we are done if this is MX53, since no sharing of IRAM and SCC_RAM */ + if (cpu_is_mx53()) + goto exit; + + reg_mask = 0; + scm_rd_timeout = 0; + /* Allocate remaining partitions for general use */ + for (partition_no = 0; partition_no < scc_partno; partition_no++) { + /* Supervisor mode claims a partition for it's own use + by writing zero to SMID register.*/ + __raw_writel(0, scc_base + (SCM_SMID0_REG + 8 * partition_no)); + + /* Wait for any zeroization to complete */ + getnstimeofday(&stime); + do { + reg_value = __raw_readl(scc_base + SCM_STATUS_REG); + getnstimeofday(&curtime); + if (curtime.tv_nsec > stime.tv_nsec) + scm_rd_timeout = curtime.tv_nsec - + stime.tv_nsec; + else{ + /*Converted second to nanosecond and add to + nsec when current nanosec is less than + start time nanosec.*/ + cur_ns = (curtime.tv_sec * SEC_TO_NANOSEC) + + curtime.tv_nsec; + start_ns = (stime.tv_sec * SEC_TO_NANOSEC) + + stime.tv_nsec; + scm_rd_timeout = cur_ns - start_ns; + } + } while (((reg_value & SCM_STATUS_SRS_MASK) != + SCM_STATUS_SRS_READY) && ((reg_value & SCM_STATUS_SRS_MASK) != + SCM_STATUS_SRS_FAIL) && (scm_rd_timeout <= SCM_RD_DELAY)); + + if (scm_rd_timeout > SCM_RD_DELAY) + printk(KERN_ERR "SCM Status Register Read timeout" + "for Partition No:%d", partition_no); + + if ((reg_value & SCM_STATUS_SRS_MASK) != SCM_STATUS_SRS_READY) + break; + /* Set UMID=0 and permissions for universal data + read/write access */ + MAP_base = scm_ram_base + + (uint32_t) (partition_no * ram_partition_size); + 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_HD_EXECUTE | SCM_PERM_TH_READ | + SCM_PERM_TH_WRITE); + reg_mask |= (3 << (2 * (partition_no))); + } + + /* Check all expected partitions allocated */ + reg_value = __raw_readl(scc_base + SCM_PART_OWNERS_REG); + if ((reg_value & reg_mask) != reg_mask) { + printk(KERN_ERR "FAILED TO ACQUIRE IRAM PARTITION\n"); + iounmap(scm_ram_base); + iounmap(scc_base); + return; + } + +exit: + iounmap(scm_ram_base); + iounmap(scc_base); + printk(KERN_INFO "IRAM READY\n"); + iram_ready = 1; +} + +#define MX53_OFFSET 0x20000000 + +int __init mxc_init_devices(void) +{ + if (cpu_is_mx53() || cpu_is_mx50()) { + sdma_resources[0].start -= MX53_OFFSET; + sdma_resources[0].end -= MX53_OFFSET; + mxc_w1_master_resources[0].start -= MX53_OFFSET; + mxc_w1_master_resources[0].end -= MX53_OFFSET; + mxc_kpp_resources[0].start -= MX53_OFFSET; + mxc_kpp_resources[0].end -= MX53_OFFSET; + rtc_resources[0].start -= MX53_OFFSET; + rtc_resources[0].end -= MX53_OFFSET; + + wdt_resources[0].start -= MX53_OFFSET; + wdt_resources[0].end -= MX53_OFFSET; + pwm1_resources[0].start -= MX53_OFFSET; + pwm1_resources[0].end -= MX53_OFFSET; + pwm2_resources[0].start -= MX53_OFFSET; + pwm2_resources[0].end -= MX53_OFFSET; + flexcan0_resources[0].start -= MX53_OFFSET; + flexcan0_resources[0].end -= MX53_OFFSET; + flexcan1_resources[0].start -= MX53_OFFSET; + flexcan1_resources[0].end -= MX53_OFFSET; + mxc_fec_resources[0].start -= MX53_OFFSET; + mxc_fec_resources[0].end -= MX53_OFFSET; + mxc_ptp_resources[0].start -= MX53_OFFSET; + mxc_ptp_resources[0].end -= MX53_OFFSET; + mxc_ptp_resources[1].start -= MX53_OFFSET; + mxc_ptp_resources[1].end -= MX53_OFFSET; + vpu_resources[0].start -= MX53_OFFSET; + vpu_resources[0].end -= MX53_OFFSET; + scc_resources[0].start -= MX53_OFFSET; + scc_resources[0].end -= MX53_OFFSET; + scc_resources[1].start = MX53_SCC_RAM_BASE_ADDR; + scc_resources[1].end = MX53_SCC_RAM_BASE_ADDR + SZ_16K - 1; + rngb_resources[0].start -= MX53_OFFSET; + rngb_resources[0].end -= MX53_OFFSET; + mxcspi1_resources[0].start -= MX53_OFFSET; + mxcspi1_resources[0].end -= MX53_OFFSET; + mxcspi2_resources[0].start -= MX53_OFFSET; + mxcspi2_resources[0].end -= MX53_OFFSET; + mxcspi3_resources[0].start -= MX53_OFFSET; + mxcspi3_resources[0].end -= MX53_OFFSET; + mxci2c1_resources[0].start -= MX53_OFFSET; + mxci2c1_resources[0].end -= MX53_OFFSET; + mxci2c2_resources[0].start -= MX53_OFFSET; + mxci2c2_resources[0].end -= MX53_OFFSET; + mxci2c3_resources[0].start -= MX53_OFFSET; + mxci2c3_resources[0].end -= MX53_OFFSET; + ssi1_resources[0].start -= MX53_OFFSET; + ssi1_resources[0].end -= MX53_OFFSET; + ssi2_resources[0].start -= MX53_OFFSET; + ssi2_resources[0].end -= MX53_OFFSET; + esai_resources[0].start -= MX53_OFFSET; + esai_resources[0].end -= MX53_OFFSET; + tve_resources[0].start -= MX53_OFFSET; + tve_resources[0].end -= MX53_OFFSET; + dvfs_core_resources[0].start -= MX53_OFFSET; + dvfs_core_resources[0].end -= MX53_OFFSET; + dvfs_per_resources[0].start -= MX53_OFFSET; + dvfs_per_resources[0].end -= MX53_OFFSET; + spdif_resources[0].start -= MX53_OFFSET; + spdif_resources[0].end -= MX53_OFFSET; + spdif_resources[1].start = MXC_INT_SPDIF_MX53; + spdif_resources[1].end = MXC_INT_SPDIF_MX53; + asrc_resources[0].start -= MX53_OFFSET; + asrc_resources[0].end -= MX53_OFFSET; + mxc_m4if_resources[0].start -= MX53_OFFSET; + mxc_m4if_resources[0].end -= MX53_OFFSET; + mxc_iim_resources[0].start -= MX53_OFFSET; + mxc_iim_resources[0].end -= MX53_OFFSET; + mxc_sim_resources[0].start -= MX53_OFFSET; + mxc_sim_resources[0].end -= MX53_OFFSET; + mxcsdhc1_resources[0].start -= MX53_OFFSET; + mxcsdhc1_resources[0].end -= MX53_OFFSET; + mxcsdhc2_resources[0].start -= MX53_OFFSET; + mxcsdhc2_resources[0].end -= MX53_OFFSET; + mxcsdhc3_resources[0].start -= MX53_OFFSET; + mxcsdhc3_resources[0].end -= MX53_OFFSET; + usbotg_host_resources[0].start -= MX53_OFFSET; + usbotg_host_resources[0].end -= MX53_OFFSET; + usbotg_udc_resources[0].start -= MX53_OFFSET; + usbotg_udc_resources[0].end -= MX53_OFFSET; + usbotg_xcvr_resources[0].start -= MX53_OFFSET; + usbotg_xcvr_resources[0].end -= MX53_OFFSET; + usbh1_resources[0].start -= MX53_OFFSET; + usbh1_resources[0].end -= MX53_OFFSET; + usbh2_resources[0].start -= MX53_OFFSET; + usbh2_resources[0].end -= MX53_OFFSET; + mxc_gpu_resources[2].start = MX53_GPU2D_BASE_ADDR; + mxc_gpu_resources[2].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1; + mxc_gpu2d_resources[0].start = MX53_GPU2D_BASE_ADDR; + mxc_gpu2d_resources[0].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1; + if (cpu_is_mx53()) { + mxc_gpu_resources[4].start = MX53_GPU_GMEM_BASE_ADDR; + mxc_gpu_resources[4].end = MX53_GPU_GMEM_BASE_ADDR + + SZ_256K - 1; + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + z160_revision = 1; + } else { + z160_revision = 0; + } + } else { + mxc_gpu_resources[1].start = 0; + mxc_gpu_resources[1].end = 0; + mxc_gpu_resources[3].start = 0; + mxc_gpu_resources[3].end = 0; + mxc_gpu_resources[4].start = 0; + mxc_gpu_resources[4].end = 0; + z160_revision = 1; + } + ipu_resources[0].start = MX53_IPU_CTRL_BASE_ADDR; + ipu_resources[0].end = MX53_IPU_CTRL_BASE_ADDR + SZ_128M - 1; + mlb_resources[0].start -= MX53_OFFSET; + mlb_resources[0].end -= MX53_OFFSET; + mxc_nandv2_mtd_device.resource[0].start = + MX53_NFC_BASE_ADDR_AXI; + mxc_nandv2_mtd_device.resource[0].end = + MX53_NFC_BASE_ADDR_AXI + SZ_8K - 1; + mxc_nandv2_mtd_device.resource[1].start -= MX53_OFFSET; + mxc_nandv2_mtd_device.resource[1].end -= MX53_OFFSET; + ldb_resources[0].start -= MX53_OFFSET; + ldb_resources[0].end -= MX53_OFFSET; + } else if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { + scc_resources[1].start += 0x8000; + scc_resources[1].end += 0x8000; + } + + + if (cpu_is_mx51() || cpu_is_mx53()) + mxc_init_scc_iram(); + return 0; +} +postcore_initcall(mxc_init_devices); + diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index c879ae71cd5b..2671b5dc6f83 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -1,8 +1,95 @@ -extern struct platform_device mxc_uart_device0; -extern struct platform_device mxc_uart_device1; -extern struct platform_device mxc_uart_device2; +/* + * Copyright (C) 2010-2011 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ extern struct platform_device mxc_fec_device; +extern struct platform_device mxc_ptp_device; +extern struct platform_device mxc_dma_device; +extern struct platform_device mxc_w1_master_device; +extern struct platform_device mxc_keypad_device; +extern struct platform_device mxc_powerkey_device; +extern struct platform_device mxc_rtc_device; +extern struct platform_device mxc_nandv2_mtd_device; +extern struct platform_device imx_nfc_device; +extern struct platform_device mxc_wdt_device; +extern struct platform_device mxc_pwm1_device; +extern struct platform_device mxc_pwm2_device; +extern struct platform_device mxc_pwm1_backlight_device; +extern struct platform_device mxc_pwm2_backlight_device; +extern struct platform_device mxc_flexcan0_device; +extern struct platform_device mxc_flexcan1_device; +extern struct platform_device mxc_ipu_device; +extern struct platform_device mxc_fb_devices[]; +extern struct platform_device mxc_ldb_device; +extern struct platform_device mxcvpu_device; +extern struct platform_device mxcscc_device; +extern struct platform_device mxcspi1_device; +extern struct platform_device mxcspi2_device; +extern struct platform_device mxcspi3_device; +extern struct platform_device mxci2c_devices[]; +extern struct platform_device mxci2c_hs_device; +extern struct platform_device mxc_tve_device; +extern struct platform_device mxc_dvfs_core_device; +extern struct platform_device mxc_dvfs_per_device; +extern struct platform_device mxc_ssi1_device; +extern struct platform_device mxc_ssi2_device; +extern struct platform_device mxc_ssi3_device; +extern struct platform_device mxc_esai_device; +extern struct platform_device mxc_alsa_spdif_device; +extern struct platform_device mx51_lpmode_device; +extern struct platform_device mx53_lpmode_device; +extern struct platform_device busfreq_device; +extern struct platform_device sdram_autogating_device; +extern struct platform_device mxc_iim_device; +extern struct platform_device mxc_sim_device; +extern struct platform_device mxcsdhc1_device; +extern struct platform_device mxcsdhc2_device; +extern struct platform_device mxcsdhc3_device; +extern struct platform_device ahci_fsl_device; +extern struct ahci_platform_data sata_data; +extern struct platform_device pata_fsl_device; +extern struct platform_device fsl_otp_device; +extern struct platform_device gpu_device; +extern struct platform_device mxc_usbdr_udc_device; +extern struct platform_device mxc_usbdr_otg_device; extern struct platform_device mxc_usbdr_host_device; +extern struct platform_device mxc_usbdr_wakeup_device; extern struct platform_device mxc_usbh1_device; -extern struct platform_device mxc_usbdr_udc_device; -extern struct platform_device mxc_wdt; +extern struct platform_device mxc_usbh1_wakeup_device; +extern struct platform_device mxc_usbh2_device; +extern struct platform_device mxc_usbh2_wakeup_device; +extern struct platform_device mxc_mlb_device; +extern struct platform_device mxc_nandv2_mtd_device; +extern struct platform_device mxc_pxp_device; +extern struct platform_device mxc_pxp_client_device; +extern struct platform_device mxc_pxp_v4l2; +extern struct platform_device epdc_device; +extern struct platform_device elcdif_device; +extern struct platform_device mxc_v4l2_device; +extern struct platform_device mxc_v4l2out_device; +extern struct platform_device mxs_viim; +extern struct platform_device mxs_dma_apbh_device; +extern struct platform_device gpmi_nfc_device; +extern struct platform_device mxc_rngb_device; +extern struct platform_device dcp_device; +extern struct platform_device pm_device; +extern struct platform_device fixed_volt_reg_device; +extern struct platform_device mxc_zq_calib_device; +extern struct platform_device mxc_asrc_device; +extern struct platform_device mxc_perfmon; +extern struct mxs_platform_perfmon_data mxc_perfmon_data; +extern int z160_revision; diff --git a/arch/arm/mach-mx5/dma-apbh.c b/arch/arm/mach-mx5/dma-apbh.c new file mode 100644 index 000000000000..9e1b10d7c35c --- /dev/null +++ b/arch/arm/mach-mx5/dma-apbh.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/dmapool.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc.h> +#include <mach/dmaengine.h> + +#include "regs-apbh.h" + +#ifndef BM_APBH_CTRL0_APB_BURST_EN +#define BM_APBH_CTRL0_APB_BURST_EN BM_APBH_CTRL0_APB_BURST4_EN +#endif + +static int mxs_dma_apbh_enable(struct mxs_dma_chan *pchan, unsigned int chan) +{ + unsigned int sem; + struct mxs_dma_device *pdev = pchan->dma; + struct mxs_dma_desc *pdesc; + + pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); + if (pdesc == NULL) + return -EFAULT; + + sem = __raw_readl(pdev->base + HW_APBH_CHn_SEMA(chan)); + sem = (sem & BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE; + if (pchan->flags & MXS_DMA_FLAGS_BUSY) { + + if (pdesc->cmd.cmd.bits.chain == 0) + return 0; + if (sem < 2) { + if (!sem) + return 0; + pdesc = list_entry(pdesc->node.next, + struct mxs_dma_desc, node); + __raw_writel(mxs_dma_cmd_address(pdesc), + pdev->base + HW_APBH_CHn_NXTCMDAR(chan)); + } + sem = pchan->pending_num; + pchan->pending_num = 0; + __raw_writel(BF_APBH_CHn_SEMA_INCREMENT_SEMA(sem), + pdev->base + HW_APBH_CHn_SEMA(chan)); + pchan->active_num += sem; + return 0; + } + + pchan->active_num += pchan->pending_num; + pchan->pending_num = 0; + __raw_writel(mxs_dma_cmd_address(pdesc), + pdev->base + HW_APBH_CHn_NXTCMDAR(chan)); + __raw_writel(pchan->active_num, pdev->base + HW_APBH_CHn_SEMA(chan)); + __raw_writel(1 << chan, pdev->base + HW_APBH_CTRL0_CLR); + return 0; +} + +static void mxs_dma_apbh_disable(struct mxs_dma_chan *pchan, unsigned int chan) +{ + struct mxs_dma_device *pdev = pchan->dma; + __raw_writel(1 << (chan + BP_APBH_CTRL0_CLKGATE_CHANNEL), + pdev->base + HW_APBH_CTRL0_SET); +} + +static void mxs_dma_apbh_reset(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << (chan + BP_APBH_CHANNEL_CTRL_RESET_CHANNEL), + pdev->base + HW_APBH_CHANNEL_CTRL_SET); +} + +static void mxs_dma_apbh_freeze(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBH_CHANNEL_CTRL_SET); +} + +static void +mxs_dma_apbh_unfreeze(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBH_CHANNEL_CTRL_CLR); +} + +static void mxs_dma_apbh_info(struct mxs_dma_device *pdev, + unsigned int chan, struct mxs_dma_info *info) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBH_CTRL2); + info->status = reg >> chan; + info->buf_addr = __raw_readl(pdev->base + HW_APBH_CHn_BAR(chan)); +} + +static int +mxs_dma_apbh_read_semaphore(struct mxs_dma_device *pdev, unsigned int chan) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBH_CHn_SEMA(chan)); + return (reg & BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE; +} + +static void +mxs_dma_apbh_enable_irq(struct mxs_dma_device *pdev, + unsigned int chan, int enable) +{ + if (enable) + __raw_writel(1 << (chan + 16), pdev->base + HW_APBH_CTRL1_SET); + else + __raw_writel(1 << (chan + 16), pdev->base + HW_APBH_CTRL1_CLR); + +} + +static int +mxs_dma_apbh_irq_is_pending(struct mxs_dma_device *pdev, unsigned int chan) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBH_CTRL1); + reg |= __raw_readl(pdev->base + HW_APBH_CTRL2); + return reg & (1 << chan); +} + +static void mxs_dma_apbh_ack_irq(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBH_CTRL1_CLR); + __raw_writel(1 << chan, pdev->base + HW_APBH_CTRL2_CLR); +} + +static struct mxs_dma_device mxs_dma_apbh = { + .name = "mxs-dma-apbh", + .enable = mxs_dma_apbh_enable, + .disable = mxs_dma_apbh_disable, + .reset = mxs_dma_apbh_reset, + .freeze = mxs_dma_apbh_freeze, + .unfreeze = mxs_dma_apbh_unfreeze, + .info = mxs_dma_apbh_info, + .read_semaphore = mxs_dma_apbh_read_semaphore, + .enable_irq = mxs_dma_apbh_enable_irq, + .irq_is_pending = mxs_dma_apbh_irq_is_pending, + .ack_irq = mxs_dma_apbh_ack_irq, +}; + +static int __devinit dma_apbh_probe(struct platform_device *pdev) +{ + int i; + struct resource *res; + struct mxs_dma_plat_data *plat; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOMEM; + mxs_dma_apbh.base = ioremap(res->start, resource_size(res)); + __raw_writel(BM_APBH_CTRL0_SFTRST, + mxs_dma_apbh.base + HW_APBH_CTRL0_CLR); + for (i = 0; i < 10000; i++) { + if (!(__raw_readl(mxs_dma_apbh.base + HW_APBH_CTRL0_CLR) & + BM_APBH_CTRL0_SFTRST)) + break; + udelay(2); + } + if (i >= 10000) + return -ETIME; + __raw_writel(BM_APBH_CTRL0_CLKGATE, + mxs_dma_apbh.base + HW_APBH_CTRL0_CLR); + + plat = (struct mxs_dma_plat_data *)pdev->dev.platform_data; + if (!plat) + return -ENODEV; + if (plat->burst8) + __raw_writel(BM_APBH_CTRL0_AHB_BURST8_EN, + mxs_dma_apbh.base + HW_APBH_CTRL0_SET); + else + __raw_writel(BM_APBH_CTRL0_AHB_BURST8_EN, + mxs_dma_apbh.base + HW_APBH_CTRL0_CLR); + + if (plat->burst) + __raw_writel(BM_APBH_CTRL0_APB_BURST_EN, + mxs_dma_apbh.base + HW_APBH_CTRL0_SET); + else + __raw_writel(BM_APBH_CTRL0_APB_BURST_EN, + mxs_dma_apbh.base + HW_APBH_CTRL0_CLR); + + mxs_dma_apbh.pdev = pdev; + mxs_dma_apbh.chan_base = plat->chan_base; + mxs_dma_apbh.chan_num = plat->chan_num; + platform_set_drvdata(pdev, &mxs_dma_apbh); + return mxs_dma_device_register(&mxs_dma_apbh); +} + +static int __devexit dma_apbh_remove(struct platform_device *pdev) +{ + iounmap(mxs_dma_apbh.base); + return 0; +} + +static struct platform_driver dma_apbh_driver = { + .probe = dma_apbh_probe, + .remove = __devexit_p(dma_apbh_remove), + .driver = { + .name = "mxs-dma-apbh"}, +}; + +static int __init mxs_dma_apbh_init(void) +{ + return platform_driver_register(&dma_apbh_driver); +} + +fs_initcall(mxs_dma_apbh_init); diff --git a/arch/arm/mach-mx5/dma-apbh.h b/arch/arm/mach-mx5/dma-apbh.h new file mode 100644 index 000000000000..9d8d1de53ecf --- /dev/null +++ b/arch/arm/mach-mx5/dma-apbh.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ASM_ARCH_MACH_DMA_H__ +#define __ASM_ARCH_MACH_DMA_H__ + +enum { + MXS_DMA_CHANNEL_AHB_APBH = 0, + MXS_DMA_CHANNEL_AHB_APBH_GPMI0 = MXS_DMA_CHANNEL_AHB_APBH, + MXS_DMA_CHANNEL_AHB_APBH_GPMI1, + MXS_DMA_CHANNEL_AHB_APBH_GPMI2, + MXS_DMA_CHANNEL_AHB_APBH_GPMI3, + MXS_DMA_CHANNEL_AHB_APBH_GPMI4, + MXS_DMA_CHANNEL_AHB_APBH_GPMI5, + MXS_DMA_CHANNEL_AHB_APBH_GPMI6, + MXS_DMA_CHANNEL_AHB_APBH_GPMI7, + MXS_DMA_CHANNEL_AHB_APBH_SSP, + MXS_MAX_DMA_CHANNELS, +}; +#endif diff --git a/arch/arm/mach-mx5/dma.c b/arch/arm/mach-mx5/dma.c new file mode 100644 index 000000000000..aec79d5a96bb --- /dev/null +++ b/arch/arm/mach-mx5/dma.c @@ -0,0 +1,1724 @@ +/* + * Copyright (C) 2008-2010 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/dma.h> +#include <mach/hardware.h> +#include <mach/mxc_uart.h> + +#include "serial.h" +#include "sdma_script_code_mx51.h" +#include "sdma_script_code_mx53.h" +#include "sdma_script_code_mx50.h" + +#define MXC_MMC_BUFFER_ACCESS 0x20 +#define MXC_SDHC_MMC_WML 64 +#define MXC_SDHC_SD_WML 256 +#define MXC_SSI_TX0_REG 0x0 +#define MXC_SSI_TX1_REG 0x4 +#define MXC_SSI_RX0_REG 0x8 +#define MXC_SSI_RX1_REG 0xC +#ifdef CONFIG_MXC_SSI_DUAL_FIFO +#define MXC_SSI_TXFIFO_WML 0x8 +#define MXC_SSI_RXFIFO_WML 0xC +#else +#define MXC_SSI_TXFIFO_WML 0x4 +#define MXC_SSI_RXFIFO_WML 0x6 +#endif +#define MXC_SPDIF_TXFIFO_WML 0x8 +#define MXC_SPDIF_RXFIFO_WML 0x8 +#define MXC_SPDIF_TX_REG 0x2C +#define MXC_SPDIF_RX_REG 0x14 +#define MXC_ASRC_FIFO_WML 0x40 +#define MXC_ASRCA_RX_REG 0x60 +#define MXC_ASRCA_TX_REG 0x64 +#define MXC_ASRCB_RX_REG 0x68 +#define MXC_ASRCB_TX_REG 0x6C +#define MXC_ASRCC_RX_REG 0x70 +#define MXC_ASRCC_TX_REG 0x74 +#define MXC_ESAI_TX_REG 0x00 +#define MXC_ESAI_RX_REG 0x04 +#define MXC_ESAI_FIFO_WML 0x40 + +typedef struct mxc_sdma_info_entry_s { + mxc_dma_device_t device; + void *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_MX51, + .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_MX51, + .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_uart4_rx_params = { + .chnl_params = { + .watermark_level = UART4_UFCR_RXTL, + .per_address = UART4_BASE_ADDR, + .peripheral_type = UART, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ATA_RX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART4_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart4_tx_params = { + .chnl_params = { + .watermark_level = UART4_UFCR_TXTL, + .per_address = UART4_BASE_ADDR + MXC_UARTUTXD, + .peripheral_type = UART, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_ATA_TX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART4_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart5_rx_params = { + .chnl_params = { + .watermark_level = UART5_UFCR_RXTL, + .per_address = UART5_BASE_ADDR, + .peripheral_type = UART, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_UART5_RX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART5_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_uart5_tx_params = { + .chnl_params = { + .watermark_level = UART5_UFCR_TXTL, + .per_address = UART5_BASE_ADDR + MXC_UARTUTXD, + .peripheral_type = UART, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_UART5_TX, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_UART5_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, + .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, + .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 * (sizeof(u16)), + .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 * (sizeof(u16)), + .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 * (sizeof(u32)), + .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 * (sizeof(u32)), + .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 * (sizeof(u16)), + .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 * (sizeof(u16)), + .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 * (sizeof(u32)), + .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 * (sizeof(u32)), + .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 * (sizeof(u16)), + .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 * (sizeof(u16)), + .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 * (sizeof(u32)), + .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 * (sizeof(u32)), + .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 * (sizeof(u16)), + .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 * (sizeof(u16)), + .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 * (sizeof(u32)), + .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 * (sizeof(u32)), + .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_ssi3_8bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_8bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX1, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_16bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML * (sizeof(u16)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_16bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML * (sizeof(u16)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX1, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_24bit_rx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML * (sizeof(u32)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX0_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_24bit_tx0_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML * (sizeof(u32)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_8bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML, + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_8bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML, + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX2, + .bd_number = 32, + .word_size = TRANSFER_8BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_16bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML * (sizeof(u16)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_16bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML * (sizeof(u16)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX2, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_TX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_24bit_rx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_RXFIFO_WML * (sizeof(u32)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_RX1_REG, + .peripheral_type = SSI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SSI3_RX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_RX, + .chnl_priority = 2, +}; + +static mxc_sdma_channel_params_t mxc_sdma_ssi3_24bit_tx1_params = { + .chnl_params = { + .watermark_level = MXC_SSI_TXFIFO_WML * (sizeof(u32)), + .per_address = SSI3_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = SSI, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_SSI3_TX2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SSI3_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_MX51, + .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_MX51, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SPDIF_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_spdif_32bit_rx_params = { + .chnl_params = { + .watermark_level = MXC_SPDIF_RXFIFO_WML, + .per_address = SPDIF_BASE_ADDR + MXC_SPDIF_RX_REG, + .peripheral_type = SPDIF, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_SPDIF_RX, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_SPDIF_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrca_rx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML, + .per_address = ASRC_BASE_ADDR + MXC_ASRCA_RX_REG, + .peripheral_type = ASRC, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_ASRC_DMA1, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrca_tx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML, + .per_address = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrcb_rx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML, + .per_address = ASRC_BASE_ADDR + MXC_ASRCB_RX_REG, + .peripheral_type = ASRC, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_ASRC_DMA2, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrcb_tx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML, + .per_address = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrcc_rx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML * 3, + .per_address = ASRC_BASE_ADDR + MXC_ASRCC_RX_REG, + .peripheral_type = ASRC, + .transfer_type = emi_2_per, + .event_id = DMA_REQ_ASRC_DMA3, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCC_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_asrcc_tx_params = { + .chnl_params = { + .watermark_level = MXC_ASRC_FIFO_WML * 3, + .per_address = ASRC_BASE_ADDR + MXC_ASRCC_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ASRC_DMA6, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCC_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrca_ssi1_tx0_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI1_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI1_TX1, + .event_id2 = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_SSI1_TX0, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrca_ssi1_tx1_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI1_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI1_TX2, + .event_id2 = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_SSI1_TX1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrca_ssi2_tx0_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI2_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI2_TX1, + .event_id2 = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_SSI2_TX0, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrca_ssi2_tx1_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI2_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI2_TX2, + .event_id2 = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_SSI2_TX1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcb_ssi1_tx0_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI1_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI1_TX1, + .event_id2 = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_SSI1_TX0, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcb_ssi1_tx1_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI1_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI1_TX2, + .event_id2 = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_SSI1_TX1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcb_ssi2_tx0_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI2_BASE_ADDR + MXC_SSI_TX0_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI2_TX1, + .event_id2 = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_SSI2_TX0, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcb_ssi2_tx1_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + SSI2_BASE_ADDR + MXC_SSI_TX1_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_SSI2_TX2, + .event_id2 = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_SSI_TXFIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_SSI2_TX1, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrca_esai_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + ESAI_BASE_ADDR + MXC_ESAI_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_ESAI_TX, + .event_id2 = DMA_REQ_ASRC_DMA4, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_ESAI_FIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCA_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCA_ESAI, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcb_esai_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + ESAI_BASE_ADDR + MXC_ESAI_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_ESAI_TX, + .event_id2 = DMA_REQ_ASRC_DMA5, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_ESAI_FIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCB_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCB_ESAI, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_ext_params_t mxc_sdma_asrcc_esai_params = { + .chnl_ext_params = { + .common = { + .watermark_level = + MXC_ASRC_FIFO_WML >> 1, + .per_address = + ESAI_BASE_ADDR + MXC_ESAI_TX_REG, + .peripheral_type = ASRC, + .transfer_type = per_2_per, + .event_id = DMA_REQ_ESAI_TX, + .event_id2 = DMA_REQ_ASRC_DMA6, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + .ext = 1, + }, + .p2p_dir = 0, + .info_bits = + SDMA_ASRC_P2P_INFO_CONT | SDMA_ASRC_P2P_INFO_SP | + SDMA_ASRC_P2P_INFO_DP, + .watermark_level2 = MXC_ASRC_FIFO_WML, + .per_address2 = ASRC_BASE_ADDR + MXC_ASRCC_TX_REG, + }, + .channel_num = MXC_DMA_CHANNEL_ASRCC_ESAI, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_esai_16bit_rx_params = { + .chnl_params = { + .watermark_level = MXC_ESAI_FIFO_WML, + .per_address = ESAI_BASE_ADDR + MXC_ESAI_RX_REG, + .peripheral_type = ESAI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ESAI_RX, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ESAI_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_esai_16bit_tx_params = { + .chnl_params = { + .watermark_level = MXC_ESAI_FIFO_WML, + .per_address = ESAI_BASE_ADDR + MXC_ESAI_TX_REG, + .peripheral_type = ESAI, + .transfer_type = int_2_per, + .event_id = DMA_REQ_ESAI_TX, + .bd_number = 32, + .word_size = TRANSFER_16BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ESAI_TX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_esai_24bit_rx_params = { + .chnl_params = { + .watermark_level = MXC_ESAI_FIFO_WML, + .per_address = ESAI_BASE_ADDR + MXC_ESAI_RX_REG, + .peripheral_type = ESAI, + .transfer_type = per_2_emi, + .event_id = DMA_REQ_ESAI_RX, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ESAI_RX, + .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY, +}; + +static mxc_sdma_channel_params_t mxc_sdma_esai_24bit_tx_params = { + .chnl_params = { + .watermark_level = MXC_ESAI_FIFO_WML, + .per_address = ESAI_BASE_ADDR + MXC_ESAI_TX_REG, + .peripheral_type = ESAI, + .transfer_type = int_2_per, + .event_id = DMA_REQ_ESAI_TX, + .bd_number = 32, + .word_size = TRANSFER_32BIT, + }, + .channel_num = MXC_DMA_CHANNEL_ESAI_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_UART4_RX, &mxc_sdma_uart4_rx_params}, + {MXC_DMA_UART4_TX, &mxc_sdma_uart4_tx_params}, + {MXC_DMA_UART5_RX, &mxc_sdma_uart5_rx_params}, + {MXC_DMA_UART5_TX, &mxc_sdma_uart5_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_SSI3_8BIT_RX0, &mxc_sdma_ssi3_8bit_rx0_params}, + {MXC_DMA_SSI3_8BIT_TX0, &mxc_sdma_ssi3_8bit_tx0_params}, + {MXC_DMA_SSI3_16BIT_RX0, &mxc_sdma_ssi3_16bit_rx0_params}, + {MXC_DMA_SSI3_16BIT_TX0, &mxc_sdma_ssi3_16bit_tx0_params}, + {MXC_DMA_SSI3_24BIT_RX0, &mxc_sdma_ssi3_24bit_rx0_params}, + {MXC_DMA_SSI3_24BIT_TX0, &mxc_sdma_ssi3_24bit_tx0_params}, + {MXC_DMA_SSI3_8BIT_RX1, &mxc_sdma_ssi3_8bit_rx1_params}, + {MXC_DMA_SSI3_8BIT_TX1, &mxc_sdma_ssi3_8bit_tx1_params}, + {MXC_DMA_SSI3_16BIT_RX1, &mxc_sdma_ssi3_16bit_rx1_params}, + {MXC_DMA_SSI3_16BIT_TX1, &mxc_sdma_ssi3_16bit_tx1_params}, + {MXC_DMA_SSI3_24BIT_RX1, &mxc_sdma_ssi3_24bit_rx1_params}, + {MXC_DMA_SSI3_24BIT_TX1, &mxc_sdma_ssi3_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}, + {MXC_DMA_SPDIF_32BIT_RX, &mxc_sdma_spdif_32bit_rx_params}, + {MXC_DMA_ASRC_A_RX, &mxc_sdma_asrca_rx_params}, + {MXC_DMA_ASRC_A_TX, &mxc_sdma_asrca_tx_params}, + {MXC_DMA_ASRC_B_RX, &mxc_sdma_asrcb_rx_params}, + {MXC_DMA_ASRC_B_TX, &mxc_sdma_asrcb_tx_params}, + {MXC_DMA_ASRC_C_RX, &mxc_sdma_asrcc_rx_params}, + {MXC_DMA_ASRC_C_TX, &mxc_sdma_asrcc_tx_params}, + {MXC_DMA_ASRCA_SSI1_TX0, &mxc_sdma_asrca_ssi1_tx0_params}, + {MXC_DMA_ASRCA_SSI1_TX1, &mxc_sdma_asrca_ssi1_tx1_params}, + {MXC_DMA_ASRCA_SSI2_TX0, &mxc_sdma_asrca_ssi2_tx0_params}, + {MXC_DMA_ASRCA_SSI2_TX1, &mxc_sdma_asrca_ssi2_tx1_params}, + {MXC_DMA_ASRCB_SSI1_TX0, &mxc_sdma_asrcb_ssi1_tx0_params}, + {MXC_DMA_ASRCB_SSI1_TX1, &mxc_sdma_asrcb_ssi1_tx1_params}, + {MXC_DMA_ASRCB_SSI2_TX0, &mxc_sdma_asrcb_ssi2_tx0_params}, + {MXC_DMA_ASRCB_SSI2_TX1, &mxc_sdma_asrcb_ssi2_tx1_params}, + {MXC_DMA_ASRCA_ESAI, &mxc_sdma_asrca_esai_params}, + {MXC_DMA_ASRCB_ESAI, &mxc_sdma_asrcb_esai_params}, + {MXC_DMA_ASRCC_ESAI, &mxc_sdma_asrcc_esai_params}, + {MXC_DMA_ESAI_16BIT_RX, &mxc_sdma_esai_16bit_rx_params}, + {MXC_DMA_ESAI_16BIT_TX, &mxc_sdma_esai_16bit_tx_params}, + {MXC_DMA_ESAI_24BIT_RX, &mxc_sdma_esai_24bit_rx_params}, + {MXC_DMA_ESAI_24BIT_TX, &mxc_sdma_esai_24bit_tx_params}, +}; + +static int mxc_sdma_info_entrys = + sizeof(mxc_sdma_active_dma_info) / sizeof(mxc_sdma_active_dma_info[0]); + +static int __init dma_fixups(void) +{ + mxc_sdma_info_entry_t *p = mxc_sdma_active_dma_info; + int i; + dma_channel_ext_params *params; + + if (cpu_is_mx51()) + return 0; + + for (i = 0; i < mxc_sdma_info_entrys; i++, p++) { + params = &(((mxc_sdma_channel_ext_params_t *)p->chnl_info)->chnl_ext_params); + params->common.per_address -= 0x20000000; + if (params->common.ext) + params->per_address2 -= 0x20000000; + } + + mxc_sdma_uart2_rx_params.chnl_params.event_id = DMA_REQ_FIRI_RX; + mxc_sdma_uart2_tx_params.chnl_params.event_id = DMA_REQ_FIRI_TX; + mxc_sdma_uart3_rx_params.chnl_params.event_id = DMA_REQ_UART3_RX_MX53; + mxc_sdma_uart3_tx_params.chnl_params.event_id = DMA_REQ_UART3_TX_MX53; + mxc_sdma_spdif_16bit_tx_params.chnl_params.event_id = DMA_REQ_SPDIF_TX; + mxc_sdma_spdif_32bit_tx_params.chnl_params.event_id = DMA_REQ_SPDIF_TX; + + if (cpu_is_mx53()) { + mxc_sdma_ssi3_8bit_tx1_params.chnl_params.event_id = + DMA_REQ_SSI3_TX2_MX53; + mxc_sdma_ssi3_16bit_tx1_params.chnl_params.event_id = + DMA_REQ_SSI3_TX2_MX53; + mxc_sdma_ssi3_24bit_tx1_params.chnl_params.event_id = + DMA_REQ_SSI3_TX2_MX53; + } else if (cpu_is_mx50()) { + /* mx50 not support double fifo */ +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + u32 tx_wm = MXC_SSI_TXFIFO_WML/2; + u32 rx_wm = MXC_SSI_RXFIFO_WML/2; +#else + u32 tx_wm = MXC_SSI_TXFIFO_WML; + u32 rx_wm = MXC_SSI_RXFIFO_WML; +#endif + mxc_sdma_ssi1_8bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_8bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi1_16bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_16bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi1_24bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_24bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi1_8bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_8bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi1_16bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_16bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi1_24bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi1_24bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_8bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_8bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_16bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_16bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_24bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_24bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_8bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_8bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_16bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_16bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi2_24bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi2_24bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_8bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_8bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_16bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_16bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_24bit_tx0_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_24bit_rx0_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_8bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_8bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_16bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_16bit_rx1_params.chnl_params.watermark_level = + rx_wm; + mxc_sdma_ssi3_24bit_tx1_params.chnl_params.watermark_level = + tx_wm; + mxc_sdma_ssi3_24bit_rx1_params.chnl_params.watermark_level = + rx_wm; + } + return 0; +} +arch_initcall(dma_fixups); + +/*! + * 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; +} +EXPORT_SYMBOL(mxc_sdma_get_channel_params); + +/*! + * 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_get_static_channels); + +static void __init mx51_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) +{ + /* AP<->BP */ + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR_MX51; + 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_ap_2_ap_fixed_addr = -1; + + /*misc */ + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + + /* firi */ + sdma_script_addr->mxc_sdma_firi_2_per_addr = -1; + sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_per_2_firi_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1; + + /* uart */ + sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_per_ADDR_MX51; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR_MX51; + + /* UART SH */ + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_per_ADDR_MX51; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_MX51; + + /* SHP */ + sdma_script_addr->mxc_sdma_per_2_shp_addr = per_2_shp_ADDR_MX51; + sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_per_ADDR_MX51; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR_MX51; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR_MX51; + + /* ATA */ + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = mcu_2_ata_ADDR_MX51; + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = ata_2_mcu_ADDR_MX51; + + /* app */ + sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_per_ADDR_MX51; + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR_MX51; + sdma_script_addr->mxc_sdma_per_2_app_addr = per_2_app_ADDR_MX51; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR_MX51; + + /* MSHC */ + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + + /* spdif */ + sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = mcu_2_spdif_ADDR_MX51; + + /* IPU */ + sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = + ext_mem__ipu_ram_ADDR_MX51; + + /* DVFS */ + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; + + /* SSI */ +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + sdma_script_addr->mxc_sdma_mcu_2_ssiapp_addr = mcu_2_ssiapp_ADDR_MX51; + sdma_script_addr->mxc_sdma_ssiapp_2_mcu_addr = ssiapp_2_mcu_ADDR_MX51; + + sdma_script_addr->mxc_sdma_mcu_2_ssish_addr = mcu_2_ssish_ADDR_MX51; + sdma_script_addr->mxc_sdma_ssish_2_mcu_addr = ssish_2_mcu_ADDR_MX51; +#endif + + /* core */ + sdma_script_addr->mxc_sdma_start_addr = + (unsigned short *)sdma_code_mx51; + sdma_script_addr->mxc_sdma_ram_code_start_addr = + RAM_CODE_START_ADDR_MX51; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX51; +} + +static void __init mx53_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) +{ + /* AP<->BP */ + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR_MX53; + 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_ap_2_ap_fixed_addr = -1; + + /*misc */ + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + + /* firi */ + sdma_script_addr->mxc_sdma_firi_2_per_addr = firi_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_firi_2_mcu_addr = firi_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_per_2_firi_addr = mcu_2_firi_ADDR_MX53; + sdma_script_addr->mxc_sdma_mcu_2_firi_addr = mcu_2_firi_ADDR_MX53; + + /* uart */ + sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR_MX53; + + /* UART SH */ + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_MX53; + + /* SHP */ + sdma_script_addr->mxc_sdma_per_2_shp_addr = mcu_2_shp_ADDR_MX53; + sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR_MX53; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR_MX53; + + /* ATA use it's own DMA */ + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = -1; + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = -1; + + /* app */ + sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_per_2_app_addr = mcu_2_app_ADDR_MX53; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR_MX53; + + /* MSHC */ + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + + /* spdif */ + sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = spdif_2_mcu_ADDR_MX53; + sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = mcu_2_spdif_ADDR_MX53; + + /* asrc script address change to use shp_2_mcu since v01.01 */ + sdma_script_addr->mxc_sdma_asrc_2_mcu_addr = shp_2_mcu_ADDR_MX53; + + /* IPU */ + sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = mcu_2_app_ADDR_MX53; + + /* DVFS */ + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; + + /* SSI */ +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + sdma_script_addr->mxc_sdma_mcu_2_ssiapp_addr = mcu_2_ssiapp_ADDR_MX53; + sdma_script_addr->mxc_sdma_ssiapp_2_mcu_addr = ssiapp_2_mcu_ADDR_MX53; + + sdma_script_addr->mxc_sdma_mcu_2_ssish_addr = mcu_2_ssish_ADDR_MX53; + sdma_script_addr->mxc_sdma_ssish_2_mcu_addr = ssish_2_mcu_ADDR_MX53; +#endif + + /* core */ + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx53; + sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX53; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX53; +} + +static void __init mx50_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) +{ + /* AP<->BP */ + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR_MX50; + 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_ap_2_ap_fixed_addr = -1; + + /*misc */ + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + + /* firi */ + sdma_script_addr->mxc_sdma_firi_2_per_addr = -1; + sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_per_2_firi_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1; + + /* uart */ + sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR_MX50; + + /* UART SH */ + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_MX50; + + /* SHP */ + sdma_script_addr->mxc_sdma_per_2_shp_addr = mcu_2_shp_ADDR_MX50; + sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR_MX50; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR_MX50; + + /* ATA use it's own DMA */ + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = -1; + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = -1; + + /* app */ + sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_per_2_app_addr = mcu_2_app_ADDR_MX50; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR_MX50; + + /* MSHC */ + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + + /* spdif */ + sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = -1; + + sdma_script_addr->mxc_sdma_asrc_2_mcu_addr = -1; + + /* IPU */ + sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = -1; + + /* DVFS */ + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; + + /* core */ + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx50; + sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX50; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX50; +} + +void __init mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) +{ + if (cpu_is_mx51()) + mx51_sdma_get_script_info(sdma_script_addr); + else if (cpu_is_mx53()) + mx53_sdma_get_script_info(sdma_script_addr); + else + mx50_sdma_get_script_info(sdma_script_addr); +} + diff --git a/arch/arm/mach-mx5/dmaengine.c b/arch/arm/mach-mx5/dmaengine.c new file mode 100644 index 000000000000..e92d9b9202e8 --- /dev/null +++ b/arch/arm/mach-mx5/dmaengine.c @@ -0,0 +1,682 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <mach/dmaengine.h> + +#include "dma-apbh.h" + +static void *mxs_dma_pool; +static int mxs_dma_alignment = MXS_DMA_ALIGNMENT; + +/* + * The mutex that arbitrates access to the array of structures that represent + * all the DMA channels in the system (see mxs_dma_channels, below). + */ + +static DEFINE_MUTEX(mxs_dma_mutex); + +/* + * The list of DMA drivers that manage various DMA channels. A DMA device + * driver registers to manage DMA channels by calling mxs_dma_device_register(). + */ + +static LIST_HEAD(mxs_dma_devices); + +/* + * The array of struct mxs_dma_chan that represent every DMA channel in the + * system. The index of the structure in the array indicates the specific DMA + * hardware it represents (see mach-mx28/include/mach/dma.h). + */ + +static struct mxs_dma_chan mxs_dma_channels[MXS_MAX_DMA_CHANNELS]; + +int mxs_dma_request(int channel, struct device *dev, const char *name) +{ + int ret = 0; + struct mxs_dma_chan *pchan; + + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + + if (!dev || !name) + return -EINVAL; + pchan = mxs_dma_channels + channel; + mutex_lock(&mxs_dma_mutex); + if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) { + ret = -ENODEV; + goto out; + } + if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) { + ret = -EBUSY; + goto out; + } + pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; + pchan->name = name; + pchan->dev = (unsigned long)dev; + pchan->active_num = 0; + pchan->pending_num = 0; + spin_lock_init(&pchan->lock); + INIT_LIST_HEAD(&pchan->active); + INIT_LIST_HEAD(&pchan->done); +out: + mutex_unlock(&mxs_dma_mutex); + return ret; +} +EXPORT_SYMBOL(mxs_dma_request); + +void mxs_dma_release(int channel, struct device *dev) +{ + struct mxs_dma_chan *pchan; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + + if (pchan->flags & MXS_DMA_FLAGS_BUSY) + return; + + if (pchan->dev != (unsigned long)dev) + return; + + mutex_lock(&mxs_dma_mutex); + pchan->dev = 0; + pchan->active_num = 0; + pchan->pending_num = 0; + pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; + mutex_unlock(&mxs_dma_mutex); +} +EXPORT_SYMBOL(mxs_dma_release); + +int mxs_dma_enable(int channel) +{ + int ret = 0; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pchan->pending_num && pdma->enable) + ret = pdma->enable(pchan, channel - pdma->chan_base); + pchan->flags |= MXS_DMA_FLAGS_BUSY; + spin_unlock_irqrestore(&pchan->lock, flags); + return ret; +} +EXPORT_SYMBOL(mxs_dma_enable); + +void mxs_dma_disable(int channel) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->disable) + pdma->disable(pchan, channel - pdma->chan_base); + pchan->flags &= ~MXS_DMA_FLAGS_BUSY; + pchan->active_num = 0; + pchan->pending_num = 0; + list_splice_init(&pchan->active, &pchan->done); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_disable); + +int mxs_dma_get_info(int channel, struct mxs_dma_info *info) +{ + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; +#ifdef DUMPING_DMA_ALL + struct list_head *pos; + int value, i, offset; +#endif + + if (!info) + return -EINVAL; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EFAULT; + pdma = pchan->dma; + if (pdma->info) + pdma->info(pdma, channel - pdma->chan_base, info); + +#ifdef DUMPING_DMA_ALL + printk(KERN_INFO "\n[ %s ] channel : %d ,active : %d, pending : %d\n", + __func__, channel, pchan->active_num, pchan->pending_num); + + for (i = 0; i < 6; i++) { + offset = i * 0x10 + channel * 0x70; + value = __raw_readl(pdma->base + offset); + printk(KERN_INFO "[ %s ] offset : 0x%.3x -- 0x%.8x\n", + __func__, offset, value); + } + for (i = 0; i < 7; i++) { + offset = 0x100 + i * 0x10 + channel * 0x70; + value = __raw_readl(pdma->base + offset); + printk(KERN_INFO "[ %s ] offset : 0x%.3x -- 0x%.8x\n", + __func__, offset, value); + } + + offset = 0; + list_for_each(pos, &pchan->active) { + struct mxs_dma_desc *pdesc; + + pdesc = list_entry(pos, struct mxs_dma_desc, node); + printk(KERN_INFO "========================================\n"); + printk(KERN_INFO "The whole chain of CMD %d is :\n" + "\tNEXT_COMMAND_ADDRESS : 0x%.8lx\n" + "\tCMD : 0x%.8lx\n" + "\tDMA Buffer : 0x%.8x\n" + "\taddress : 0x%.8x\n", + offset++, + pdesc->cmd.next, + pdesc->cmd.cmd.data, + (int)pdesc->cmd.address, + (int)pdesc->address); + + for (i = 0; i < pdesc->cmd.cmd.bits.pio_words; i++) { + printk(KERN_INFO "PIO WORD [ %d ] --> 0x%.8lx\n", + i, pdesc->cmd.pio_words[i]); + } + printk(KERN_INFO "==================================\n"); + } +#endif + return 0; +} +EXPORT_SYMBOL(mxs_dma_get_info); + +int mxs_dma_cooked(int channel, struct list_head *head) +{ + int sem; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct list_head *p, *q; + struct mxs_dma_desc *pdesc; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + + sem = mxs_dma_read_semaphore(channel); + if (sem < 0) + return sem; + if (sem == pchan->active_num) + return 0; + BUG_ON(sem > pchan->active_num); + spin_lock_irqsave(&pchan->lock, flags); + list_for_each_safe(p, q, &pchan->active) { + if ((pchan->active_num) <= sem) + break; + pdesc = list_entry(p, struct mxs_dma_desc, node); + pdesc->flags &= ~MXS_DMA_DESC_READY; + if (head) + list_move_tail(p, head); + else + list_move_tail(p, &pchan->done); + if (pdesc->flags & MXS_DMA_DESC_LAST) + pchan->active_num--; + } + if (sem == 0) + pchan->flags &= ~MXS_DMA_FLAGS_BUSY; + spin_unlock_irqrestore(&pchan->lock, flags); + + BUG_ON(sem != pchan->active_num); + return 0; +} +EXPORT_SYMBOL(mxs_dma_cooked); + +void mxs_dma_reset(int channel) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->reset) + pdma->reset(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_reset); + +void mxs_dma_freeze(int channel) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->freeze) + pdma->freeze(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_freeze); + +void mxs_dma_unfreeze(int channel) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->unfreeze) + pdma->unfreeze(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_unfreeze); + +int mxs_dma_read_semaphore(int channel) +{ + int ret = -EINVAL; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return ret; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return ret; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->read_semaphore) + ret = pdma->read_semaphore(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); + return ret; +} +EXPORT_SYMBOL(mxs_dma_read_semaphore); + +void mxs_dma_enable_irq(int channel, int en) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->enable_irq) + pdma->enable_irq(pdma, channel - pdma->chan_base, en); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_enable_irq); + +int mxs_dma_irq_is_pending(int channel) +{ + int ret = 0; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return ret; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return ret; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->irq_is_pending) + ret = pdma->irq_is_pending(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); + return ret; +} +EXPORT_SYMBOL(mxs_dma_irq_is_pending); + +void mxs_dma_ack_irq(int channel) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->ack_irq) + pdma->ack_irq(pdma, channel - pdma->chan_base); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_ack_irq); + +void mxs_dma_set_target(int channel, int target) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return; + if (pchan->flags & MXS_DMA_FLAGS_BUSY) + return; + pdma = pchan->dma; + spin_lock_irqsave(&pchan->lock, flags); + if (pdma->set_target) + pdma->set_target(pdma, channel - pdma->chan_base, target); + spin_unlock_irqrestore(&pchan->lock, flags); +} +EXPORT_SYMBOL(mxs_dma_set_target); + +/* mxs dma utility function */ +struct mxs_dma_desc *mxs_dma_alloc_desc(void) +{ + struct mxs_dma_desc *pdesc; + unsigned int address; + if (mxs_dma_pool == NULL) + return NULL; + + pdesc = dma_pool_alloc(mxs_dma_pool, GFP_KERNEL, &address); + if (pdesc == NULL) + return NULL; + memset(pdesc, 0, sizeof(*pdesc)); + pdesc->address = address; + return pdesc; +}; +EXPORT_SYMBOL(mxs_dma_alloc_desc); + +void mxs_dma_free_desc(struct mxs_dma_desc *pdesc) +{ + if (pdesc == NULL) + return; + + if (mxs_dma_pool == NULL) + return; + + dma_pool_free(mxs_dma_pool, pdesc, pdesc->address); +} +EXPORT_SYMBOL(mxs_dma_free_desc); + +int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) +{ + int ret = 0; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_desc *last; + struct mxs_dma_device *pdma; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + pdma = pchan->dma; + pdesc->cmd.next = mxs_dma_cmd_address(pdesc); + pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; + spin_lock_irqsave(&pchan->lock, flags); + if (!list_empty(&pchan->active)) { + + last = list_entry(pchan->active.prev, + struct mxs_dma_desc, node); + + pdesc->flags &= ~MXS_DMA_DESC_FIRST; + last->flags &= ~MXS_DMA_DESC_LAST; + + last->cmd.next = mxs_dma_cmd_address(pdesc); + last->cmd.cmd.bits.chain = 1; + } + pdesc->flags |= MXS_DMA_DESC_READY; + if (pdesc->flags & MXS_DMA_DESC_FIRST) + pchan->pending_num++; + list_add_tail(&pdesc->node, &pchan->active); + spin_unlock_irqrestore(&pchan->lock, flags); + return ret; +} +EXPORT_SYMBOL(mxs_dma_desc_append); + +int mxs_dma_desc_add_list(int channel, struct list_head *head) +{ + int ret = 0, size = 0; + unsigned long flags; + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdma; + struct list_head *p; + struct mxs_dma_desc *prev = NULL, *pcur; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + + if (list_empty(head)) + return 0; + + pdma = pchan->dma; + list_for_each(p, head) { + pcur = list_entry(p, struct mxs_dma_desc, node); + if (!(pcur->cmd.cmd.bits.dec_sem || pcur->cmd.cmd.bits.chain)) + return -EINVAL; + if (prev) + prev->cmd.next = mxs_dma_cmd_address(pcur); + else + pcur->flags |= MXS_DMA_DESC_FIRST; + pcur->flags |= MXS_DMA_DESC_READY; + prev = pcur; + size++; + } + pcur = list_first_entry(head, struct mxs_dma_desc, node); + prev->cmd.next = mxs_dma_cmd_address(pcur); + prev->flags |= MXS_DMA_DESC_LAST; + + spin_lock_irqsave(&pchan->lock, flags); + if (!list_empty(&pchan->active)) { + pcur = list_entry(pchan->active.next, + struct mxs_dma_desc, node); + if (pcur->cmd.cmd.bits.dec_sem != prev->cmd.cmd.bits.dec_sem) { + ret = -EFAULT; + goto out; + } + prev->cmd.next = mxs_dma_cmd_address(pcur); + prev = list_entry(pchan->active.prev, + struct mxs_dma_desc, node); + pcur = list_first_entry(head, struct mxs_dma_desc, node); + pcur->flags &= ~MXS_DMA_DESC_FIRST; + prev->flags &= ~MXS_DMA_DESC_LAST; + prev->cmd.next = mxs_dma_cmd_address(pcur); + } + list_splice(head, &pchan->active); + pchan->pending_num += size; + if (!(pcur->cmd.cmd.bits.dec_sem) && (pcur->flags & MXS_DMA_DESC_FIRST)) + pchan->pending_num += 1; + else + pchan->pending_num += size; +out: + spin_unlock_irqrestore(&pchan->lock, flags); + return ret; +} +EXPORT_SYMBOL(mxs_dma_desc_add_list); + +int mxs_dma_get_cooked(int channel, struct list_head *head) +{ + unsigned long flags; + struct mxs_dma_chan *pchan; + if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + + if (head == NULL) + return 0; + + spin_lock_irqsave(&pchan->lock, flags); + list_splice(&pchan->done, head); + spin_unlock_irqrestore(&pchan->lock, flags); + return 0; +} +EXPORT_SYMBOL(mxs_dma_get_cooked); + +int mxs_dma_device_register(struct mxs_dma_device *pdev) +{ + int i; + struct mxs_dma_chan *pchan; + + if (pdev == NULL || !pdev->chan_num) + return -EINVAL; + + if ((pdev->chan_base >= MXS_MAX_DMA_CHANNELS) || + ((pdev->chan_base + pdev->chan_num) > MXS_MAX_DMA_CHANNELS)) + return -EINVAL; + + mutex_lock(&mxs_dma_mutex); + pchan = mxs_dma_channels + pdev->chan_base; + for (i = 0; i < pdev->chan_num; i++, pchan++) { + pchan->dma = pdev; + pchan->flags = MXS_DMA_FLAGS_VALID; + } + list_add(&pdev->node, &mxs_dma_devices); + mutex_unlock(&mxs_dma_mutex); + return 0; +} +EXPORT_SYMBOL(mxs_dma_device_register); + +static int __init mxs_dma_alignment_setup(char *line) +{ + get_option(&line, &mxs_dma_alignment); + mxs_dma_alignment = (mxs_dma_alignment + 3) & (~3); + mxs_dma_alignment = max(mxs_dma_alignment, MXS_DMA_ALIGNMENT); + return 1; +}; + +__setup("mxs-dma-alignment=", mxs_dma_alignment_setup); + +static int mxs_dmaengine_init(void) +{ + mxs_dma_pool = dma_pool_create("mxs_dma", NULL, + sizeof(struct mxs_dma_desc), + mxs_dma_alignment, PAGE_SIZE); + if (mxs_dma_pool == NULL) + return -ENOMEM; + return 0; +} + +subsys_initcall(mxs_dmaengine_init); + +#ifdef CONFIG_PROC_FS + +static void *mxs_dma_proc_seq_start(struct seq_file *file, loff_t * index) +{ + if (*index >= MXS_MAX_DMA_CHANNELS) + return NULL; + return mxs_dma_channels + *index; +} + +static void *mxs_dma_proc_seq_next(struct seq_file *file, void *data, + loff_t *index) +{ + if (data == NULL) + return NULL; + + if (*index >= MXS_MAX_DMA_CHANNELS) + return NULL; + + return mxs_dma_channels + (*index)++; +} + +static void mxs_dma_proc_seq_stop(struct seq_file *file, void *data) +{ +} + +static int mxs_dma_proc_seq_show(struct seq_file *file, void *data) +{ + int result; + struct mxs_dma_chan *pchan = (struct mxs_dma_chan *)data; + struct mxs_dma_device *pdev = pchan->dma; + result = seq_printf(file, "%s-channel%-d (%s)\n", + pdev->name, + pchan - mxs_dma_channels, + pchan->name ? pchan->name : "idle"); + return result; +} + +static const struct seq_operations mxc_dma_proc_seq_ops = { + .start = mxs_dma_proc_seq_start, + .next = mxs_dma_proc_seq_next, + .stop = mxs_dma_proc_seq_stop, + .show = mxs_dma_proc_seq_show +}; + +static int mxs_dma_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &mxc_dma_proc_seq_ops); +} + +static const struct file_operations mxs_dma_proc_info_ops = { + .open = mxs_dma_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init mxs_dmaengine_info_init(void) +{ + struct proc_dir_entry *res; + res = create_proc_entry("dma-engine", 0, NULL); + if (!res) { + printk(KERN_ERR "Failed to create dma info file \n"); + return -ENOMEM; + } + res->proc_fops = &mxs_dma_proc_info_ops; + return 0; +} + +late_initcall(mxs_dmaengine_info_init); +#endif diff --git a/arch/arm/mach-mx5/dummy_gpio.c b/arch/arm/mach-mx5/dummy_gpio.c new file mode 100644 index 000000000000..6766cdf43911 --- /dev/null +++ b/arch/arm/mach-mx5/dummy_gpio.c @@ -0,0 +1,119 @@ +/* + * Copyright 2007-2010 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> + +void gpio_uart_active(int port, int no_irda) {} +EXPORT_SYMBOL(gpio_uart_active); + +void gpio_uart_inactive(int port, int no_irda) {} +EXPORT_SYMBOL(gpio_uart_inactive); + +void gpio_gps_active(void) {} +EXPORT_SYMBOL(gpio_gps_active); + +void gpio_gps_inactive(void) {} +EXPORT_SYMBOL(gpio_gps_inactive); + +void config_uartdma_event(int port) {} +EXPORT_SYMBOL(config_uartdma_event); + +void gpio_spi_active(int cspi_mod) {} +EXPORT_SYMBOL(gpio_spi_active); + +void gpio_spi_inactive(int cspi_mod) {} +EXPORT_SYMBOL(gpio_spi_inactive); + +void gpio_owire_active(void) {} +EXPORT_SYMBOL(gpio_owire_active); + +void gpio_owire_inactive(void) {} +EXPORT_SYMBOL(gpio_owire_inactive); + +void gpio_i2c_active(int i2c_num) {} +EXPORT_SYMBOL(gpio_i2c_active); + +void gpio_i2c_inactive(int i2c_num) {} +EXPORT_SYMBOL(gpio_i2c_inactive); + +void gpio_i2c_hs_active(void) {} +EXPORT_SYMBOL(gpio_i2c_hs_active); + +void gpio_i2c_hs_inactive(void) {} +EXPORT_SYMBOL(gpio_i2c_hs_inactive); + +void gpio_pmic_active(void) {} +EXPORT_SYMBOL(gpio_pmic_active); + +void gpio_activate_audio_ports(void) {} +EXPORT_SYMBOL(gpio_activate_audio_ports); + +void gpio_sdhc_active(int module) {} +EXPORT_SYMBOL(gpio_sdhc_active); + +void gpio_sdhc_inactive(int module) {} +EXPORT_SYMBOL(gpio_sdhc_inactive); + +void gpio_sensor_select(int sensor) {} + +void gpio_sensor_active(unsigned int csi) {} +EXPORT_SYMBOL(gpio_sensor_active); + +void gpio_sensor_inactive(unsigned int csi) {} +EXPORT_SYMBOL(gpio_sensor_inactive); + +void gpio_ata_active(void) {} +EXPORT_SYMBOL(gpio_ata_active); + +void gpio_ata_inactive(void) {} +EXPORT_SYMBOL(gpio_ata_inactive); + +void gpio_nand_active(void) {} +EXPORT_SYMBOL(gpio_nand_active); + +void gpio_nand_inactive(void) {} +EXPORT_SYMBOL(gpio_nand_inactive); + +void gpio_keypad_active(void) {} +EXPORT_SYMBOL(gpio_keypad_active); + +void gpio_keypad_inactive(void) {} +EXPORT_SYMBOL(gpio_keypad_inactive); + +int gpio_usbotg_hs_active(void) +{ + return 0; +} +EXPORT_SYMBOL(gpio_usbotg_hs_active); + +void gpio_usbotg_hs_inactive(void) {} +EXPORT_SYMBOL(gpio_usbotg_hs_inactive); + +void gpio_fec_active(void) {} +EXPORT_SYMBOL(gpio_fec_active); + +void gpio_fec_inactive(void) {} +EXPORT_SYMBOL(gpio_fec_inactive); + +void gpio_spdif_active(void) {} +EXPORT_SYMBOL(gpio_spdif_active); + +void gpio_spdif_inactive(void) {} +EXPORT_SYMBOL(gpio_spdif_inactive); + +void gpio_mlb_active(void) {} +EXPORT_SYMBOL(gpio_mlb_active); + +void gpio_mlb_inactive(void) {} +EXPORT_SYMBOL(gpio_mlb_inactive); diff --git a/arch/arm/mach-mx5/early_setup.c b/arch/arm/mach-mx5/early_setup.c new file mode 100644 index 000000000000..dd731d7f822e --- /dev/null +++ b/arch/arm/mach-mx5/early_setup.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/string.h> + +int __initdata primary_di = { 0 }; +static int __init di_setup(char *__unused) +{ + primary_di = 1; + return 1; +} +__setup("di1_primary", di_setup); + diff --git a/arch/arm/mach-mx5/iomux.c b/arch/arm/mach-mx5/iomux.c new file mode 100644 index 000000000000..25b8514b7048 --- /dev/null +++ b/arch/arm/mach-mx5/iomux.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2008-2010 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_MX5 Board GPIO and Muxing Setup + * @ingroup MSL_MX5 + */ +/*! + * @file mach-mx5/iomux.c + * + * @brief I/O Muxing control functions + * + * @ingroup GPIO_MX5 + */ + +#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" +#include "mx51_pins.h" + +#define MUX_I_START_MX53 0x0020 +#define PAD_I_START_MX53 0x348 +#define INPUT_CTL_START_MX53 0x730 +#define MUX_I_END_MX53 (PAD_I_START_MX53 - 4) + +#define PAD_I_START_MX50 0x2CC +#define INPUT_CTL_START_MX50 0x6C4 + +/*! + * IOMUX register (base) addressesf + */ +#define IOMUXGPR0 (IO_ADDRESS(IOMUXC_BASE_ADDR)) +#define IOMUXGPR1 (IO_ADDRESS(IOMUXC_BASE_ADDR) + 0x004) +#define IOMUXSW_MUX_CTL (IO_ADDRESS(IOMUXC_BASE_ADDR)) +#define IOMUXSW_INPUT_CTL (IO_ADDRESS(IOMUXC_BASE_ADDR)) + +static u8 iomux_pin_res_table[(0x3F0 / 4) + 1]; +static DEFINE_SPINLOCK(gpio_mux_lock); + +static inline void *_get_sw_pad(void) +{ + if (cpu_is_mx51()) + return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX51; + else if (cpu_is_mx53()) + return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX53; + else + return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX50; +} + +static inline void *_get_mux_reg(iomux_pin_name_t pin) +{ + u32 mux_reg = PIN_TO_IOMUX_MUX(pin); + + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { + if ((pin == MX51_PIN_NANDF_RB5) || + (pin == MX51_PIN_NANDF_RB6) || + (pin == MX51_PIN_NANDF_RB7)) + ; /* Do nothing */ + else if (mux_reg >= 0x2FC) + mux_reg += 8; + else if (mux_reg >= 0x130) + mux_reg += 0xC; + } + return IOMUXSW_MUX_CTL + mux_reg; +} + +static inline void *_get_pad_reg(iomux_pin_name_t pin) +{ + u32 pad_reg = PIN_TO_IOMUX_PAD(pin); + void __iomem *sw_pad_reg = _get_sw_pad(); + + + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { + if ((pin == MX51_PIN_NANDF_RB5) || + (pin == MX51_PIN_NANDF_RB6) || + (pin == MX51_PIN_NANDF_RB7)) + ; /* Do nothing */ + else if (pad_reg == 0x4D0 - PAD_I_START_MX51) + pad_reg += 0x4C; + else if (pad_reg == 0x860 - PAD_I_START_MX51) + pad_reg += 0x9C; + else if (pad_reg >= 0x804 - PAD_I_START_MX51) + pad_reg += 0xB0; + else if (pad_reg >= 0x7FC - PAD_I_START_MX51) + pad_reg += 0xB4; + else if (pad_reg >= 0x4E4 - PAD_I_START_MX51) + pad_reg += 0xCC; + else + pad_reg += 8; + } + return sw_pad_reg + pad_reg; +} + +static inline void *_get_mux_end(void) +{ + if (cpu_is_mx50()) + return IO_ADDRESS(IOMUXC_BASE_ADDR) + 0x2C8; + + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) + return IO_ADDRESS(IOMUXC_BASE_ADDR) + (0x3F8 - 4); + else + return IO_ADDRESS(IOMUXC_BASE_ADDR) + (0x3F0 - 4); +} + +/*! + * 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 __iomem *mux_reg = _get_mux_reg(pin); + u32 mux_data = 0; + u8 *rp; + + BUG_ON((mux_reg > _get_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, reg=%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; +} +EXPORT_SYMBOL(mxc_request_iomux); + +/*! + * 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); + + *rp = 0; + if ((gpio < MXC_GPIO_IRQS) + && ((config == IOMUX_CONFIG_GPIO) + || (config == PIN_TO_ALT_GPIO(pin)))) + gpio_free(gpio); + +} +EXPORT_SYMBOL(mxc_free_iomux); + +/*! + * 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 __iomem *pad_reg = _get_pad_reg(pin); + void __iomem *sw_pad_reg = _get_sw_pad(); + + BUG_ON(pad_reg < sw_pad_reg); + __raw_writel(config, pad_reg); +} +EXPORT_SYMBOL(mxc_iomux_set_pad); + +unsigned int mxc_iomux_get_pad(iomux_pin_name_t pin) +{ + void __iomem *pad_reg = _get_pad_reg(pin); + + return __raw_readl(pad_reg); +} +EXPORT_SYMBOL(mxc_iomux_get_pad); + +/*! + * 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 __iomem *reg; + + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { + if (input == MUX_IN_IPU_IPP_DI_0_IND_DISPB_SD_D_SELECT_INPUT) + input -= 4; + else if (input == MUX_IN_IPU_IPP_DI_1_IND_DISPB_SD_D_SELECT_INPUT) + input -= 3; + else if (input >= MUX_IN_KPP_IPP_IND_COL_6_SELECT_INPUT) + input -= 2; + else if (input >= MUX_IN_HSC_MIPI_MIX_PAR_SISG_TRIG_SELECT_INPUT) + input -= 5; + else if (input >= MUX_IN_HSC_MIPI_MIX_IPP_IND_SENS1_DATA_EN_SELECT_INPUT) + input -= 3; + else if (input >= MUX_IN_ECSPI2_IPP_IND_SS_B_3_SELECT_INPUT) + input -= 2; + else if (input >= MUX_IN_CCM_PLL1_BYPASS_CLK_SELECT_INPUT) + input -= 1; + + reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51_TO1; + } else if (cpu_is_mx51()) { + reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51; + } else if (cpu_is_mx53()) { + reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX53; + } else + reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX50; + + BUG_ON(input >= MUX_INPUT_NUM_MUX); + __raw_writel(config, reg); +} +EXPORT_SYMBOL(mxc_iomux_set_input); diff --git a/arch/arm/mach-mx5/iomux.h b/arch/arm/mach-mx5/iomux.h new file mode 100644 index 000000000000..0732f2169e0a --- /dev/null +++ b/arch/arm/mach-mx5/iomux.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2008-2010 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_MX5_IOMUX_H__ +#define __MACH_MX5_IOMUX_H__ + +#include <linux/types.h> +#include <mach/gpio.h> + +/*! + * @file mach-mx5/iomux.h + * + * @brief I/O Muxing control definitions and functions + * + * @ingroup GPIO_MX5 + */ + +/*! + * @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 - 21 | 20 - 10| 9 - 0 + * ------------------------------------------------------------------- + * IO_P | IO_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 MX51_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 21 + +#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 << (MUX_IO_I - GPIO_I)) - 1) + +#define NON_MUX_I PIN_TO_MUX_MASK +#define NON_PAD_I PIN_TO_PAD_MASK + +#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 */ + +typedef unsigned int iomux_pin_name_t; +typedef unsigned int iomux_input_select_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_360K_PD = 0x0 << 4, + PAD_CTL_47K_PU = 0x1 << 4, + PAD_CTL_75k_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 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; + +struct mxc_iomux_pin_cfg { + iomux_pin_name_t pin; + u8 mux_mode; + u16 pad_cfg; + u8 in_select; + u8 in_mode; +}; + +/*! + * 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 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_MX5_IOMUX_H__ */ diff --git a/arch/arm/mach-mx5/lpmodes.c b/arch/arm/mach-mx5/lpmodes.c new file mode 100644 index 000000000000..fad2d814fdef --- /dev/null +++ b/arch/arm/mach-mx5/lpmodes.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2008-2010 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 mx51_lpmodes.c + * + * @brief Driver for the Freescale Semiconductor MXC low power modes setup. + * + * MX51 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/machine.h> + +#define ARM_LP_CLK 166250000 +#define GP_LPM_VOLTAGE 775000 +#define GP_NORMAL_VOLTAGE 1050000 + +static int org_cpu_rate; +int lp_video_mode; +int lp_audio_mode; +static struct device *lpmode_dev; +struct regulator *gp_core; + +void enter_lp_video_mode(void) +{ +} + +void exit_lp_video_mode(void) +{ +} + +void enter_lp_audio_mode(void) +{ + struct clk *tclk; + int ret; + + struct clk *p_clk; + struct clk *amode_parent_clk; + + + 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, "cpu_clk"); + org_cpu_rate = clk_get_rate(tclk); + +#ifdef CHANGE_DDR2_TO_PLL2 + tclk = clk_get(NULL, "ddr_clk"); + clk_set_parent(tclk, clk_get(NULL, "axi_a_clk")); + + /* Set CPU clock to be derived from PLL2 instead of PLL1 */ + tclk = clk_get(NULL, "pll1_sw_clk"); + clk_set_parent(tclk, clk_get(NULL, "pll2")); + clk_enable(tclk); + + tclk = clk_get(NULL, "ddr_clk"); + clk_set_parent(tclk, clk_get(NULL, "ddr_hf_clk")); +#endif + + /*Change the DDR freq to 133Mhz. */ + tclk = clk_get(NULL, "ddr_hf_clk"); + clk_set_rate(tclk, clk_round_rate(tclk, 133000000)); + + tclk = clk_get(NULL, "cpu_clk"); + ret = clk_set_rate(tclk, ARM_LP_CLK); + if (ret != 0) + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + clk_put(tclk); + /* Set the voltage to 0.775v for the GP domain. */ + ret = regulator_set_voltage(gp_core, GP_LPM_VOLTAGE, GP_LPM_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!\n"); + + 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, "ahb_clk"), 24000000); + clk_set_rate(clk_get(NULL, "emi_slow_clk"), 24000000); + clk_set_rate(clk_get(NULL, "nfc_clk"), 12000000); + + /* 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); + + /* disable PLL1 */ + tclk = clk_get(NULL, "pll1_main_clk"); + if (tclk->usecount == 1) + clk_disable(tclk); + + lp_audio_mode = 1; +} + +void exit_lp_audio_mode(void) +{ + struct clk *tclk; + struct clk *p_clk; + struct clk *rmode_parent_clk; + int ret; + + /* Set the voltage to 1.05v for the GP domain. */ + ret = regulator_set_voltage(gp_core, + GP_NORMAL_VOLTAGE, GP_NORMAL_VOLTAGE); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!\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"), 6000000); + clk_set_rate(clk_get(NULL, "axi_b_clk"), 4800000); + clk_set_rate(clk_get(NULL, "ahb_clk"), 4800000); + clk_set_rate(clk_get(NULL, "emi_slow_clk"), 4800000); + clk_set_rate(clk_get(NULL, "nfc_clk"), 1200000); + /* Set the parent of main_bus_clk to be pll2 */ + clk_set_parent(tclk, rmode_parent_clk); + +#ifdef CHANGE_DDR2_TO_PLL2 + tclk = clk_get(NULL, "ddr_clk"); + clk_set_parent(tclk, clk_get(NULL, "axi_a_clk")); + + /* Set CPU clock to be derived from PLL1 instead of PLL2 */ + tclk = clk_get(NULL, "pll1_sw_clk"); + clk_set_parent(tclk, clk_get(NULL, "pll1_main_clk")); + clk_disable(tclk); + + tclk = clk_get(NULL, "ddr_clk"); + clk_set_parent(tclk, clk_get(NULL, "ddr_hf_clk")); +#endif + + 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"); + clk_put(tclk); + + 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"); + + + /*Change the DDR freq to 200MHz*/ + tclk = clk_get(NULL, "ddr_hf_clk"); + clk_set_rate(tclk, clk_round_rate(tclk, 200000000)); + lp_audio_mode = 0; + +} + +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 mx51_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; + } + gp_core = regulator_get(NULL, "SW1"); + lp_video_mode = 0; + lp_audio_mode = 0; + + return 0; +} + +static struct platform_driver mx51_lpmode_driver = { + .driver = { + .name = "mx51_lpmode", + }, + .probe = mx51_lpmode_probe, +}; + +/*! + * Initialise the mx51_lpmode_driver. + * + * @return The function always returns 0. + */ + +static int __init lpmode_init(void) +{ + if (platform_driver_register(&mx51_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(&mx51_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-mx5/mm.c b/arch/arm/mach-mx5/mm.c index b7677ef80cc4..a17ae5a588c2 100644 --- a/arch/arm/mach-mx5/mm.c +++ b/arch/arm/mach-mx5/mm.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 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 @@ -15,69 +15,50 @@ #include <linux/init.h> #include <asm/mach/map.h> +#include <mach/iomux-v3.h> #include <mach/hardware.h> #include <mach/common.h> #include <mach/iomux-v3.h> -/* - * Define the MX51 memory map. +/*! + * This structure defines the MX5x memory map. */ -static struct map_desc mxc_io_desc[] __initdata = { +static struct map_desc mx5_io_desc[] __initdata = { + { + .virtual = AIPS1_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS1_BASE_ADDR), + .length = AIPS1_SIZE, + .type = MT_DEVICE}, { - .virtual = MX51_IRAM_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_IRAM_BASE_ADDR), - .length = MX51_IRAM_SIZE, - .type = MT_DEVICE - }, { - .virtual = MX51_DEBUG_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_DEBUG_BASE_ADDR), - .length = MX51_DEBUG_SIZE, - .type = MT_DEVICE - }, { - .virtual = MX51_AIPS1_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_AIPS1_BASE_ADDR), - .length = MX51_AIPS1_SIZE, - .type = MT_DEVICE - }, { - .virtual = MX51_SPBA0_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_SPBA0_BASE_ADDR), - .length = MX51_SPBA0_SIZE, - .type = MT_DEVICE - }, { - .virtual = MX51_AIPS2_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_AIPS2_BASE_ADDR), - .length = MX51_AIPS2_SIZE, - .type = MT_DEVICE - }, + .virtual = SPBA0_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(SPBA0_BASE_ADDR), + .length = SPBA0_SIZE, + .type = MT_DEVICE}, + { + .virtual = AIPS2_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS2_BASE_ADDR), + .length = AIPS2_SIZE, + .type = MT_DEVICE}, }; -/* +/*! * This function initializes the memory map. It is called during the - * system startup to create static physical to virtual memory mappings - * for the IO modules. + * system startup to create static physical to virtual memory map for + * the IO modules. */ -void __init mx51_map_io(void) +void __init mx5_map_io(void) { - mxc_set_cpu_type(MXC_CPU_MX51); - mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR)); - mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG_BASE_ADDR)); - iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); -} - -void __init mx51_init_irq(void) -{ - unsigned long tzic_addr; - void __iomem *tzic_virt; + int i; - if (mx51_revision() < MX51_CHIP_REV_2_0) - tzic_addr = MX51_TZIC_BASE_ADDR_TO1; - else - tzic_addr = MX51_TZIC_BASE_ADDR; + mxc_iomux_v3_init(IO_ADDRESS(IOMUXC_BASE_ADDR)); + /* Fixup the mappings for MX53 */ + if (cpu_is_mx53() || cpu_is_mx50()) { + for (i = 0; i < ARRAY_SIZE(mx5_io_desc); i++) + mx5_io_desc[i].pfn -= __phys_to_pfn(0x20000000); + } - tzic_virt = ioremap(tzic_addr, SZ_16K); - if (!tzic_virt) - panic("unable to map TZIC interrupt controller\n"); - - tzic_init_irq(tzic_virt); + iotable_init(mx5_io_desc, ARRAY_SIZE(mx5_io_desc)); + mxc_arch_reset_init(IO_ADDRESS(WDOG1_BASE_ADDR)); } + diff --git a/arch/arm/mach-mx5/mx50_arm2.c b/arch/arm/mach-mx5/mx50_arm2.c new file mode 100644 index 000000000000..01d6d3db4533 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_arm2.c @@ -0,0 +1,1260 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/max17135.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/videodev2.h> +#include <linux/mxcfb.h> +#include <linux/fec.h> +#include <linux/gpmi-nfc.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 <asm/mach/flash.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/arc_otg.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx50.h> +#include <mach/i2c.h> + +#include "devices.h" +#include "crm_regs.h" +#include "usb.h" +#include "dma-apbh.h" + +#define SD1_WP (3*32 + 19) /*GPIO_4_19 */ +#define SD1_CD (0*32 + 27) /*GPIO_1_27 */ +#define SD2_WP (4*32 + 16) /*GPIO_5_16 */ +#define SD2_CD (4*32 + 17) /*GPIO_5_17 */ +#define SD3_WP (4*32 + 28) /*GPIO_5_28 */ +#define SD3_CD (3*32 + 4) /*GPIO_4_4 */ +#define HP_DETECT (3*32 + 15) /*GPIO_4_15 */ +#define PWR_INT (3*32 + 18) /*GPIO_4_18 */ + +#define EPDC_D0 (2*32 + 0) /*GPIO_3_0 */ +#define EPDC_D1 (2*32 + 1) /*GPIO_3_1 */ +#define EPDC_D2 (2*32 + 2) /*GPIO_3_2 */ +#define EPDC_D3 (2*32 + 3) /*GPIO_3_3 */ +#define EPDC_D4 (2*32 + 4) /*GPIO_3_4 */ +#define EPDC_D5 (2*32 + 5) /*GPIO_3_5 */ +#define EPDC_D6 (2*32 + 6) /*GPIO_3_6 */ +#define EPDC_D7 (2*32 + 7) /*GPIO_3_7 */ +#define EPDC_GDCLK (2*32 + 16) /*GPIO_3_16 */ +#define EPDC_GDSP (2*32 + 17) /*GPIO_3_17 */ +#define EPDC_GDOE (2*32 + 18) /*GPIO_3_18 */ +#define EPDC_GDRL (2*32 + 19) /*GPIO_3_19 */ +#define EPDC_SDCLK (2*32 + 20) /*GPIO_3_20 */ +#define EPDC_SDOE (2*32 + 23) /*GPIO_3_23 */ +#define EPDC_SDLE (2*32 + 24) /*GPIO_3_24 */ +#define EPDC_SDSHR (2*32 + 26) /*GPIO_3_26 */ +#define EPDC_BDR0 (3*32 + 23) /*GPIO_4_23 */ +#define EPDC_SDCE0 (3*32 + 25) /*GPIO_4_25 */ +#define EPDC_SDCE1 (3*32 + 26) /*GPIO_4_26 */ +#define EPDC_SDCE2 (3*32 + 27) /*GPIO_4_27 */ + +#define EPDC_PMIC_WAKE (5*32 + 16) /*GPIO_6_16 */ +#define EPDC_PMIC_INT (5*32 + 17) /*GPIO_6_17 */ +#define EPDC_VCOM (3*32 + 21) /*GPIO_4_21 */ +#define EPDC_PWRSTAT (2*32 + 28) /*GPIO_3_28 */ +#define EPDC_ELCDIF_BACKLIGHT (1*32 + 18) /*GPIO_2_18 */ +#define CSPI_CS1 (3*32 + 13) /*GPIO_4_13 */ +#define CSPI_CS2 (3*32 + 11) /*GPIO_4_11*/ +#define USB_OTG_PWR (5*32 + 25) /*GPIO_6_25*/ + +extern int __init mx50_arm2_init_mc13892(void); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); +static int max17135_regulator_init(struct max17135 *max17135); +static int num_cpu_wp = 2; + +static struct pad_desc mx50_armadillo2[] = { + /* SD1 */ + MX50_PAD_ECSPI2_SS0__GPIO_4_19, + MX50_PAD_EIM_CRE__GPIO_1_27, + MX50_PAD_SD1_CMD__SD1_CMD, + + MX50_PAD_SD1_CLK__SD1_CLK, + MX50_PAD_SD1_D0__SD1_D0, + MX50_PAD_SD1_D1__SD1_D1, + MX50_PAD_SD1_D2__SD1_D2, + MX50_PAD_SD1_D3__SD1_D3, + + /* SD2 */ + MX50_PAD_SD2_CD__GPIO_5_17, + MX50_PAD_SD2_WP__GPIO_5_16, + MX50_PAD_SD2_CMD__SD2_CMD, + MX50_PAD_SD2_CLK__SD2_CLK, + MX50_PAD_SD2_D0__SD2_D0, + MX50_PAD_SD2_D1__SD2_D1, + MX50_PAD_SD2_D2__SD2_D2, + MX50_PAD_SD2_D3__SD2_D3, + MX50_PAD_SD2_D4__SD2_D4, + MX50_PAD_SD2_D5__SD2_D5, + MX50_PAD_SD2_D6__SD2_D6, + MX50_PAD_SD2_D7__SD2_D7, + + /* SD3 */ + MX50_PAD_SD3_WP__GPIO_5_28, + MX50_PAD_KEY_COL2__GPIO_4_4, + MX50_PAD_SD3_CMD__SD3_CMD, + MX50_PAD_SD3_CLK__SD3_CLK, + MX50_PAD_SD3_D0__SD3_D0, + MX50_PAD_SD3_D1__SD3_D1, + MX50_PAD_SD3_D2__SD3_D2, + MX50_PAD_SD3_D3__SD3_D3, + MX50_PAD_SD3_D4__SD3_D4, + MX50_PAD_SD3_D5__SD3_D5, + MX50_PAD_SD3_D6__SD3_D6, + MX50_PAD_SD3_D7__SD3_D7, + + MX50_PAD_SSI_RXD__SSI_RXD, + MX50_PAD_SSI_TXD__SSI_TXD, + MX50_PAD_SSI_TXC__SSI_TXC, + MX50_PAD_SSI_TXFS__SSI_TXFS, + + /* LINE1_DETECT (headphone detect) */ + MX50_PAD_ECSPI1_SS0__GPIO_4_15, + + /* PWR_INT */ + MX50_PAD_ECSPI2_MISO__GPIO_4_18, + + /* UART pad setting */ + MX50_PAD_UART1_TXD__UART1_TXD, + MX50_PAD_UART1_RXD__UART1_RXD, + MX50_PAD_UART1_CTS__UART1_CTS, + MX50_PAD_UART1_RTS__UART1_RTS, + MX50_PAD_UART2_TXD__UART2_TXD, + MX50_PAD_UART2_RXD__UART2_RXD, + MX50_PAD_UART2_CTS__UART2_CTS, + MX50_PAD_UART2_RTS__UART2_RTS, + + MX50_PAD_I2C1_SCL__I2C1_SCL, + MX50_PAD_I2C1_SDA__I2C1_SDA, + MX50_PAD_I2C2_SCL__I2C2_SCL, + MX50_PAD_I2C2_SDA__I2C2_SDA, + MX50_PAD_I2C3_SCL__I2C3_SCL, + MX50_PAD_I2C3_SDA__I2C3_SDA, + + /* EPDC pins */ + MX50_PAD_EPDC_D0__EPDC_D0, + MX50_PAD_EPDC_D1__EPDC_D1, + MX50_PAD_EPDC_D2__EPDC_D2, + MX50_PAD_EPDC_D3__EPDC_D3, + MX50_PAD_EPDC_D4__EPDC_D4, + MX50_PAD_EPDC_D5__EPDC_D5, + MX50_PAD_EPDC_D6__EPDC_D6, + MX50_PAD_EPDC_D7__EPDC_D7, + MX50_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX50_PAD_EPDC_GDSP__EPDC_GDSP, + MX50_PAD_EPDC_GDOE__EPDC_GDOE , + MX50_PAD_EPDC_GDRL__EPDC_GDRL, + MX50_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX50_PAD_EPDC_SDOE__EPDC_SDOE, + MX50_PAD_EPDC_SDLE__EPDC_SDLE, + MX50_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX50_PAD_EPDC_BDR0__EPDC_BDR0, + MX50_PAD_EPDC_SDCE0__EPDC_SDCE0, + MX50_PAD_EPDC_SDCE1__EPDC_SDCE1, + MX50_PAD_EPDC_SDCE2__EPDC_SDCE2, + + MX50_PAD_EPDC_PWRSTAT__GPIO_3_28, + MX50_PAD_EPDC_VCOM0__GPIO_4_21, + + MX50_PAD_DISP_D8__DISP_D8, + MX50_PAD_DISP_D9__DISP_D9, + MX50_PAD_DISP_D10__DISP_D10, + MX50_PAD_DISP_D11__DISP_D11, + MX50_PAD_DISP_D12__DISP_D12, + MX50_PAD_DISP_D13__DISP_D13, + MX50_PAD_DISP_D14__DISP_D14, + MX50_PAD_DISP_D15__DISP_D15, + MX50_PAD_DISP_RS__ELCDIF_VSYNC, + + /* ELCDIF contrast */ + MX50_PAD_DISP_BUSY__GPIO_2_18, + + MX50_PAD_DISP_CS__ELCDIF_HSYNC, + MX50_PAD_DISP_RD__ELCDIF_EN, + MX50_PAD_DISP_WR__ELCDIF_PIXCLK, + + /* EPD PMIC WAKEUP */ + MX50_PAD_UART4_TXD__GPIO_6_16, + + /* EPD PMIC intr */ + MX50_PAD_UART4_RXD__GPIO_6_17, + + MX50_PAD_EPITO__USBH1_PWR, + /* Need to comment below line if + * one needs to debug owire. + */ + MX50_PAD_OWIRE__USBH1_OC, + /* using gpio to control otg pwr */ + MX50_PAD_PWM2__GPIO_6_25, + MX50_PAD_PWM1__USBOTG_OC, + + MX50_PAD_SSI_RXC__FEC_MDIO, + MX50_PAD_SSI_RXC__FEC_MDIO, + MX50_PAD_DISP_D0__FEC_TXCLK, + MX50_PAD_DISP_D1__FEC_RX_ER, + MX50_PAD_DISP_D2__FEC_RX_DV, + MX50_PAD_DISP_D3__FEC_RXD1, + MX50_PAD_DISP_D4__FEC_RXD0, + MX50_PAD_DISP_D5__FEC_TX_EN, + MX50_PAD_DISP_D6__FEC_TXD1, + MX50_PAD_DISP_D7__FEC_TXD0, + MX50_PAD_SSI_RXFS__FEC_MDC, + + MX50_PAD_CSPI_SS0__CSPI_SS0, + MX50_PAD_ECSPI1_MOSI__CSPI_SS1, + MX50_PAD_CSPI_MOSI__CSPI_MOSI, + MX50_PAD_CSPI_MISO__CSPI_MISO, +}; + +static struct pad_desc mx50_gpmi_nand[] = { + MX50_PIN_EIM_DA8__NANDF_CLE, + MX50_PIN_EIM_DA9__NANDF_ALE, + MX50_PIN_EIM_DA10__NANDF_CE0, + MX50_PIN_EIM_DA11__NANDF_CE1, + MX50_PIN_EIM_DA12__NANDF_CE2, + MX50_PIN_EIM_DA13__NANDF_CE3, + MX50_PIN_EIM_DA14__NANDF_READY, + MX50_PIN_EIM_DA15__NANDF_DQS, + MX50_PIN_SD3_D4__NANDF_D0, + MX50_PIN_SD3_D5__NANDF_D1, + MX50_PIN_SD3_D6__NANDF_D2, + MX50_PIN_SD3_D7__NANDF_D3, + MX50_PIN_SD3_D0__NANDF_D4, + MX50_PIN_SD3_D1__NANDF_D5, + MX50_PIN_SD3_D2__NANDF_D6, + MX50_PIN_SD3_D3__NANDF_D7, + MX50_PIN_SD3_CLK__NANDF_RDN, + MX50_PIN_SD3_CMD__NANDF_WRN, + MX50_PIN_SD3_WP__NANDF_RESETN, +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, + .num_wp = 2, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ +static struct cpu_wp cpu_wp_auto[] = { + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .pdf = 4, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 4, + .cpu_voltage = 850000,}, +}; + +static struct cpu_wp *mx50_arm2_get_cpu_wp(int *wp) +{ + *wp = num_cpu_wp; + return cpu_wp_auto; +} + +static void mx50_arm2_set_num_cpu_wp(int num) +{ + num_cpu_wp = num; + return; +} + +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 1, +}; + +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +/* workaround for cspi chipselect pin may not keep correct level when idle */ +static void mx50_arm2_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + break; + case 2: + break; + case 3: + switch (chipselect) { + case 0x1: + { + struct pad_desc cspi_ss0 = MX50_PAD_CSPI_SS0__CSPI_SS0; + struct pad_desc cspi_cs1 = MX50_PAD_ECSPI1_MOSI__GPIO_4_13; + + /* pull up/down deassert it */ + mxc_iomux_v3_setup_pad(&cspi_ss0); + mxc_iomux_v3_setup_pad(&cspi_cs1); + + gpio_request(CSPI_CS1, "cspi-cs1"); + gpio_direction_input(CSPI_CS1); + } + break; + case 0x2: + { + struct pad_desc cspi_ss1 = MX50_PAD_ECSPI1_MOSI__CSPI_SS1; + struct pad_desc cspi_ss0 = MX50_PAD_CSPI_SS0__GPIO_4_11; + + /*disable other ss */ + mxc_iomux_v3_setup_pad(&cspi_ss1); + mxc_iomux_v3_setup_pad(&cspi_ss0); + + /* pull up/down deassert it */ + gpio_request(CSPI_CS2, "cspi-cs2"); + gpio_direction_input(CSPI_CS2); + } + break; + default: + break; + } + break; + + default: + break; + } +} + +static void mx50_arm2_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + break; + case 2: + break; + case 3: + switch (chipselect) { + case 0x1: + gpio_free(CSPI_CS1); + break; + case 0x2: + gpio_free(CSPI_CS2); + break; + default: + break; + } + break; + default: + break; + } + +} + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = mx50_arm2_gpio_spi_chipselect_active, + .chipselect_inactive = mx50_arm2_gpio_spi_chipselect_inactive, +}; + +static struct mxc_spi_master mxcspi3_data = { + .maxchipselect = 4, + .spi_version = 7, + .chipselect_active = mx50_arm2_gpio_spi_chipselect_active, + .chipselect_inactive = mx50_arm2_gpio_spi_chipselect_inactive, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +static struct regulator_init_data max17135_init_data[] __initdata = { + { + .constraints = { + .name = "DISPLAY", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, { + .constraints = { + .name = "GVDD", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "GVEE", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINN", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINP", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "VCOM", + .min_uV = mV_to_uV(-4325), + .max_uV = mV_to_uV(-500), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + }, { + .constraints = { + .name = "VNEG", + .min_uV = V_to_uV(-15), + .max_uV = V_to_uV(-15), + }, + }, { + .constraints = { + .name = "VPOS", + .min_uV = V_to_uV(15), + .max_uV = V_to_uV(15), + }, + }, +}; + +static void epdc_get_pins(void) +{ + /* Claim GPIOs for EPDC pins - used during power up/down */ + gpio_request(EPDC_D0, "epdc_d0"); + gpio_request(EPDC_D1, "epdc_d1"); + gpio_request(EPDC_D2, "epdc_d2"); + gpio_request(EPDC_D3, "epdc_d3"); + gpio_request(EPDC_D4, "epdc_d4"); + gpio_request(EPDC_D5, "epdc_d5"); + gpio_request(EPDC_D6, "epdc_d6"); + gpio_request(EPDC_D7, "epdc_d7"); + gpio_request(EPDC_GDCLK, "epdc_gdclk"); + gpio_request(EPDC_GDSP, "epdc_gdsp"); + gpio_request(EPDC_GDOE, "epdc_gdoe"); + gpio_request(EPDC_GDRL, "epdc_gdrl"); + gpio_request(EPDC_SDCLK, "epdc_sdclk"); + gpio_request(EPDC_SDOE, "epdc_sdoe"); + gpio_request(EPDC_SDLE, "epdc_sdle"); + gpio_request(EPDC_SDSHR, "epdc_sdshr"); + gpio_request(EPDC_BDR0, "epdc_bdr0"); + gpio_request(EPDC_SDCE0, "epdc_sdce0"); + gpio_request(EPDC_SDCE1, "epdc_sdce1"); + gpio_request(EPDC_SDCE2, "epdc_sdce2"); +} + +static void epdc_put_pins(void) +{ + gpio_free(EPDC_D0); + gpio_free(EPDC_D1); + gpio_free(EPDC_D2); + gpio_free(EPDC_D3); + gpio_free(EPDC_D4); + gpio_free(EPDC_D5); + gpio_free(EPDC_D6); + gpio_free(EPDC_D7); + gpio_free(EPDC_GDCLK); + gpio_free(EPDC_GDSP); + gpio_free(EPDC_GDOE); + gpio_free(EPDC_GDRL); + gpio_free(EPDC_SDCLK); + gpio_free(EPDC_SDOE); + gpio_free(EPDC_SDLE); + gpio_free(EPDC_SDSHR); + gpio_free(EPDC_BDR0); + gpio_free(EPDC_SDCE0); + gpio_free(EPDC_SDCE1); + gpio_free(EPDC_SDCE2); +} + +static struct pad_desc mx50_epdc_pads_enabled[] = { + MX50_PAD_EPDC_D0__EPDC_D0, + MX50_PAD_EPDC_D1__EPDC_D1, + MX50_PAD_EPDC_D2__EPDC_D2, + MX50_PAD_EPDC_D3__EPDC_D3, + MX50_PAD_EPDC_D4__EPDC_D4, + MX50_PAD_EPDC_D5__EPDC_D5, + MX50_PAD_EPDC_D6__EPDC_D6, + MX50_PAD_EPDC_D7__EPDC_D7, + MX50_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX50_PAD_EPDC_GDSP__EPDC_GDSP, + MX50_PAD_EPDC_GDOE__EPDC_GDOE, + MX50_PAD_EPDC_GDRL__EPDC_GDRL, + MX50_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX50_PAD_EPDC_SDOE__EPDC_SDOE, + MX50_PAD_EPDC_SDLE__EPDC_SDLE, + MX50_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX50_PAD_EPDC_BDR0__EPDC_BDR0, + MX50_PAD_EPDC_SDCE0__EPDC_SDCE0, + MX50_PAD_EPDC_SDCE1__EPDC_SDCE1, + MX50_PAD_EPDC_SDCE2__EPDC_SDCE2, +}; + +static struct pad_desc mx50_epdc_pads_disabled[] = { + MX50_PAD_EPDC_D0__GPIO_3_0, + MX50_PAD_EPDC_D1__GPIO_3_1, + MX50_PAD_EPDC_D2__GPIO_3_2, + MX50_PAD_EPDC_D3__GPIO_3_3, + MX50_PAD_EPDC_D4__GPIO_3_4, + MX50_PAD_EPDC_D5__GPIO_3_5, + MX50_PAD_EPDC_D6__GPIO_3_6, + MX50_PAD_EPDC_D7__GPIO_3_7, + MX50_PAD_EPDC_GDCLK__GPIO_3_16, + MX50_PAD_EPDC_GDSP__GPIO_3_17, + MX50_PAD_EPDC_GDOE__GPIO_3_18, + MX50_PAD_EPDC_GDRL__GPIO_3_19, + MX50_PAD_EPDC_SDCLK__GPIO_3_20, + MX50_PAD_EPDC_SDOE__GPIO_3_23, + MX50_PAD_EPDC_SDLE__GPIO_3_24, + MX50_PAD_EPDC_SDSHR__GPIO_3_26, + MX50_PAD_EPDC_BDR0__GPIO_4_23, + MX50_PAD_EPDC_SDCE0__GPIO_4_25, + MX50_PAD_EPDC_SDCE1__GPIO_4_26, + MX50_PAD_EPDC_SDCE2__GPIO_4_27, +}; + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_enabled, \ + ARRAY_SIZE(mx50_epdc_pads_enabled)); + + gpio_direction_input(EPDC_D0); + gpio_direction_input(EPDC_D1); + gpio_direction_input(EPDC_D2); + gpio_direction_input(EPDC_D3); + gpio_direction_input(EPDC_D4); + gpio_direction_input(EPDC_D5); + gpio_direction_input(EPDC_D6); + gpio_direction_input(EPDC_D7); + gpio_direction_input(EPDC_GDCLK); + gpio_direction_input(EPDC_GDSP); + gpio_direction_input(EPDC_GDOE); + gpio_direction_input(EPDC_GDRL); + gpio_direction_input(EPDC_SDCLK); + gpio_direction_input(EPDC_SDOE); + gpio_direction_input(EPDC_SDLE); + gpio_direction_input(EPDC_SDSHR); + gpio_direction_input(EPDC_BDR0); + gpio_direction_input(EPDC_SDCE0); + gpio_direction_input(EPDC_SDCE1); + gpio_direction_input(EPDC_SDCE2); +} + +static void epdc_disable_pins(void) +{ + /* Configure MUX settings for EPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_disabled, \ + ARRAY_SIZE(mx50_epdc_pads_disabled)); + + gpio_direction_output(EPDC_D0, 0); + gpio_direction_output(EPDC_D1, 0); + gpio_direction_output(EPDC_D2, 0); + gpio_direction_output(EPDC_D3, 0); + gpio_direction_output(EPDC_D4, 0); + gpio_direction_output(EPDC_D5, 0); + gpio_direction_output(EPDC_D6, 0); + gpio_direction_output(EPDC_D7, 0); + gpio_direction_output(EPDC_GDCLK, 0); + gpio_direction_output(EPDC_GDSP, 0); + gpio_direction_output(EPDC_GDOE, 0); + gpio_direction_output(EPDC_GDRL, 0); + gpio_direction_output(EPDC_SDCLK, 0); + gpio_direction_output(EPDC_SDOE, 0); + gpio_direction_output(EPDC_SDLE, 0); + gpio_direction_output(EPDC_SDSHR, 0); + gpio_direction_output(EPDC_BDR0, 0); + gpio_direction_output(EPDC_SDCE0, 0); + gpio_direction_output(EPDC_SDCE1, 0); + gpio_direction_output(EPDC_SDCE2, 0); +} + +static struct fb_videomode e60_v110_mode = { + .name = "E60_V110", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 18604700, + .left_margin = 8, + .right_margin = 178, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e60_v220_mode = { + .name = "E60_V220", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 32000000, + .left_margin = 8, + .right_margin = 166, + .upper_margin = 4, + .lower_margin = 26, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e97_v110_mode = { + .name = "E97_V110", + .refresh = 50, + .xres = 1200, + .yres = 825, + .pixclock = 32000000, + .left_margin = 12, + .right_margin = 128, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct mxc_epdc_fb_mode panel_modes[] = { + { + &e60_v110_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 428, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e60_v220_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 428, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e97_v110_mode, + 8, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 632, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 3, /* num_ce */ + } +}; + +static struct mxc_epdc_fb_platform_data epdc_data = { + .epdc_mode = panel_modes, + .num_modes = ARRAY_SIZE(panel_modes), + .get_pins = epdc_get_pins, + .put_pins = epdc_put_pins, + .enable_pins = epdc_enable_pins, + .disable_pins = epdc_disable_pins, +}; + +static struct platform_device max17135_sensor_device = { + .name = "max17135_sensor", + .id = 0, +}; + +static struct max17135_platform_data max17135_pdata __initdata = { + .vneg_pwrup = 1, + .gvee_pwrup = 1, + .vpos_pwrup = 2, + .gvdd_pwrup = 1, + .gvdd_pwrdn = 1, + .vpos_pwrdn = 2, + .gvee_pwrdn = 1, + .vneg_pwrdn = 1, + .gpio_pmic_pwrgood = EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = EPDC_VCOM, + .gpio_pmic_wakeup = EPDC_PMIC_WAKE, + .gpio_pmic_intr = EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int max17135_regulator_init(struct max17135 *max17135) +{ + struct max17135_platform_data *pdata = &max17135_pdata; + int i, ret; + + max17135->gvee_pwrup = pdata->gvee_pwrup; + max17135->vneg_pwrup = pdata->vneg_pwrup; + max17135->vpos_pwrup = pdata->vpos_pwrup; + max17135->gvdd_pwrup = pdata->gvdd_pwrup; + max17135->gvdd_pwrdn = pdata->gvdd_pwrdn; + max17135->vpos_pwrdn = pdata->vpos_pwrdn; + max17135->vneg_pwrdn = pdata->vneg_pwrdn; + max17135->gvee_pwrdn = pdata->gvee_pwrdn; + + max17135->max_wait = pdata->vpos_pwrup + pdata->vneg_pwrup + + pdata->gvdd_pwrup + pdata->gvee_pwrup; + + max17135->gpio_pmic_pwrgood = pdata->gpio_pmic_pwrgood; + max17135->gpio_pmic_vcom_ctrl = pdata->gpio_pmic_vcom_ctrl; + max17135->gpio_pmic_wakeup = pdata->gpio_pmic_wakeup; + max17135->gpio_pmic_intr = pdata->gpio_pmic_intr; + + max17135->vcom_setup = false; + max17135->init_done = false; + + for (i = 0; i <= MAX17135_VPOS; i++) { + ret = max17135_register_regulator(max17135, i, + &pdata->regulator_init[i]); + if (ret != 0) { + printk(KERN_ERR"max17135 regulator init failed: %d\n", + ret); + return ret; + } + } + + regulator_has_full_constraints(); + + return 0; +} + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "backlight-i2c", + .addr = 0x2c, + }, + { + .type = "eeprom", + .addr = 0x50, + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 3, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0],}, +}; + +static void mx50_arm2_usb_set_vbus(bool enable) +{ + gpio_set_value(USB_OTG_PWR, enable); +} + + +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(SD1_WP); + else if (to_platform_device(dev)->id == 1) + rc = gpio_get_value(SD2_WP); + else if (to_platform_device(dev)->id == 2) + rc = gpio_get_value(SD3_WP); + + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret = 0; + if (to_platform_device(dev)->id == 0) + ret = gpio_get_value(SD1_CD); + else if (to_platform_device(dev)->id == 1) + ret = gpio_get_value(SD2_CD); + else if (to_platform_device(dev)->id == 2) + ret = gpio_get_value(SD3_CD); + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +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 | MMC_CAP_8_BIT_DATA, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static struct mxc_mmc_platform_data mmc3_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 | MMC_CAP_8_BIT_DATA | MMC_CAP_DATA_DDR, + .min_clk = 400000, + .max_clk = 40000000, + .dll_override_en = 1, + .dll_delay_cells = 0xc, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static int mxc_sgtl5000_amp_enable(int enable) +{ +/* TO DO */ + return 0; +} + +static int headphone_det_status(void) +{ + return (gpio_get_value(HP_DETECT) != 0); +} + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_irq = IOMUX_TO_IRQ_V3(HP_DETECT), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .sysclk = 12288000, +}; + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static struct pad_desc armadillo2_wvga_pads[] = { + MX50_PAD_DISP_D0__DISP_D0, + MX50_PAD_DISP_D1__DISP_D1, + MX50_PAD_DISP_D2__DISP_D2, + MX50_PAD_DISP_D3__DISP_D3, + MX50_PAD_DISP_D4__DISP_D4, + MX50_PAD_DISP_D5__DISP_D5, + MX50_PAD_DISP_D6__DISP_D6, + MX50_PAD_DISP_D7__DISP_D7, +}; + +static void wvga_reset(void) +{ + mxc_iomux_v3_setup_multiple_pads(armadillo2_wvga_pads, \ + ARRAY_SIZE(armadillo2_wvga_pads)); + return; +} + +static struct mxc_lcd_platform_data lcd_wvga_data = { + .reset = wvga_reset, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_claa", + .dev = { + .platform_data = &lcd_wvga_data, + }, +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx50(); +} + +__setup("w1", w1_setup); + +static struct mxs_dma_plat_data dma_apbh_data = { + .chan_base = MXS_DMA_CHANNEL_AHB_APBH, + .chan_num = MXS_MAX_DMA_CHANNELS, +}; + +static int gpmi_nfc_platform_init(unsigned int max_chip_count) +{ + mxc_iomux_v3_setup_multiple_pads(mx50_gpmi_nand, + ARRAY_SIZE(mx50_gpmi_nand)); + return 0; +} + +static void gpmi_nfc_platform_exit(unsigned int max_chip_count) +{ +} + +static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 }; + +static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = { + .nfc_version = 2, + .boot_rom_version = 1, + .clock_name = "gpmi-nfc", + .platform_init = gpmi_nfc_platform_init, + .platform_exit = gpmi_nfc_platform_exit, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 2, + .boot_area_size_in_bytes = 20 * SZ_1M, + .partition_source_types = gpmi_nfc_partition_source_types, + .partitions = 0, + .partition_count = 0, +}; + +/* OTP data */ +/* Building up eight registers's names of a bank */ +#define BANK(a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define BANKS (5) +#define BANK_ITEMS (8) +static const char *bank_reg_desc[BANKS][BANK_ITEMS] = { + BANK(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6), + BANK(MEM0, MEM1, MEM2, MEM3, MEM4, MEM5, GP0, GP1), + BANK(SCC0, SCC1, SCC2, SCC3, SCC4, SCC5, SCC6, SCC7), + BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7), + BANK(SJC0, SJC1, MAC0, MAC1, HWCAP0, HWCAP1, HWCAP2, SWCAP), +}; + +static struct fsl_otp_data otp_data = { + .fuse_name = (char **)bank_reg_desc, + .fuse_num = BANKS * BANK_ITEMS, +}; +#undef BANK +#undef BANKS +#undef BANK_ITEMS + +/*! + * 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_set_cpu_type(MXC_CPU_MX50); + + get_cpu_wp = mx50_arm2_get_cpu_wp; + set_num_cpu_wp = mx50_arm2_set_num_cpu_wp; +} + +static void __init mx50_arm2_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx50_armadillo2, \ + ARRAY_SIZE(mx50_armadillo2)); + + gpio_request(SD1_WP, "sdhc1-wp"); + gpio_direction_input(SD1_WP); + + gpio_request(SD1_CD, "sdhc1-cd"); + gpio_direction_input(SD1_CD); + + gpio_request(SD2_WP, "sdhc2-wp"); + gpio_direction_input(SD2_WP); + + gpio_request(SD2_CD, "sdhc2-cd"); + gpio_direction_input(SD2_CD); + + gpio_request(SD3_WP, "sdhc3-wp"); + gpio_direction_input(SD3_WP); + + gpio_request(SD3_CD, "sdhc3-cd"); + gpio_direction_input(SD3_CD); + + gpio_request(HP_DETECT, "hp-det"); + gpio_direction_input(HP_DETECT); + + gpio_request(PWR_INT, "pwr-int"); + gpio_direction_input(PWR_INT); + + gpio_request(EPDC_PMIC_WAKE, "epdc-pmic-wake"); + gpio_direction_output(EPDC_PMIC_WAKE, 0); + + gpio_request(EPDC_VCOM, "epdc-vcom"); + gpio_direction_output(EPDC_VCOM, 0); + + gpio_request(EPDC_PMIC_INT, "epdc-pmic-int"); + gpio_direction_input(EPDC_PMIC_INT); + + gpio_request(EPDC_PWRSTAT, "epdc-pwrstat"); + gpio_direction_input(EPDC_PWRSTAT); + + /* ELCDIF backlight */ + gpio_request(EPDC_ELCDIF_BACKLIGHT, "elcdif-backlight"); + gpio_direction_output(EPDC_ELCDIF_BACKLIGHT, 1); + + if (enable_w1) { + struct pad_desc one_wire = MX50_PAD_OWIRE__OWIRE; + mxc_iomux_v3_setup_pad(&one_wire); + } + + /* USB OTG PWR */ + gpio_request(USB_OTG_PWR, "usb otg power"); + gpio_direction_output(USB_OTG_PWR, 1); + gpio_set_value(USB_OTG_PWR, 0); +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + /* SD card detect irqs */ + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(SD1_CD); + mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(SD2_CD); + mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(SD2_CD); + mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(SD3_CD); + mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(SD3_CD); + + mxc_cpu_common_init(); + mx50_arm2_io_init(); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxs_dma_apbh_device, &dma_apbh_data); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxcspi3_device, &mxcspi3_data); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_devices[2], &mxci2c_data); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxc_pxp_device, NULL); + mxc_register_device(&mxc_pxp_client_device, NULL); + mxc_register_device(&mxc_pxp_v4l2, NULL); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, &bus_freq_data); + + /* + mxc_register_device(&mx53_lpmode_device, NULL); + mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); + */ + +/* mxc_register_device(&mxc_keypad_device, &keypad_plat_data); */ + + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&mxc_fec_device, &fec_data); + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + mxc_register_device(&max17135_sensor_device, NULL); + mxc_register_device(&epdc_device, &epdc_data); + mxc_register_device(&lcd_wvga_device, &lcd_wvga_data); + mxc_register_device(&elcdif_device, &fb_data[0]); + mxc_register_device(&mxs_viim, NULL); + + mx50_arm2_init_mc13892(); +/* + pm_power_off = mxc_power_off; + */ + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mxc_register_device(&gpmi_nfc_device, &gpmi_nfc_platform_data); + + mx5_set_otghost_vbus_func(mx50_arm2_usb_set_vbus); + mx5_usb_dr_init(); + mx5_usbh1_init(); + + mxc_register_device(&mxc_rngb_device, NULL); + mxc_register_device(&dcp_device, NULL); + mxc_register_device(&fsl_otp_device, &otp_data); + if (cpu_is_mx50_rev(CHIP_REV_1_1) >= 1) + mxc_register_device(&mxc_zq_calib_device, NULL); + mxc_register_device(&mxc_perfmon, &mxc_perfmon_data); +} + +static void __init mx50_arm2_timer_init(void) +{ + struct clk *uart_clk; + + mx50_clocks_init(32768, 24000000, 22579200); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx50_arm2_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX50_ARM2 data structure. + */ +MACHINE_START(MX50_ARM2, "Freescale MX50 ARM2 Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx50_arm2_pmic_mc13892.c b/arch/arm/mach-mx5/mx50_arm2_pmic_mc13892.c new file mode 100644 index 000000000000..014ec1a985d7 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_arm2_pmic_mc13892.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892/core.h> +#include <mach/irqs.h> + +#include <mach/iomux-mx50.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* regulator standby mask */ +#define GEN1_STBY_MASK (1 << 1) +#define IOHI_STBY_MASK (1 << 4) +#define DIG_STBY_MASK (1 << 10) +#define GEN2_STBY_MASK (1 << 13) +#define PLL_STBY_MASK (1 << 16) +#define USB2_STBY_MASK (1 << 19) + +#define GEN3_STBY_MASK (1 << 1) +#define CAM_STBY_MASK (1 << 7) +#define VIDEO_STBY_MASK (1 << 13) +#define AUDIO_STBY_MASK (1 << 16) +#define SD_STBY_MASK (1 << 19) + +#define REG_MODE_0_ALL_MASK (DIG_STBY_MASK | GEN1_STBY_MASK) +#define REG_MODE_1_ALL_MASK (CAM_STBY_MASK | VIDEO_STBY_MASK |\ + AUDIO_STBY_MASK | SD_STBY_MASK) + +/* switch mode setting */ +#define SW1MODE_LSB 0 +#define SW2MODE_LSB 10 +#define SW3MODE_LSB 0 +#define SW4MODE_LSB 8 + +#define SWMODE_MASK 0xF +#define SWMODE_AUTO 0x8 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_consumer_supply vgen1_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDA", + .dev_name = "1-000a", + }, + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1200), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + }, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2775), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(3000), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static int mc13892_regulator_init(struct mc13892 *mc13892) +{ + unsigned int value, register_mask; + printk("Initializing regulators for mx50 arm2.\n"); + + /* enable standby controll for all regulators */ + pmic_read_reg(REG_MODE_0, &value, 0xffffff); + value |= REG_MODE_0_ALL_MASK; + pmic_write_reg(REG_MODE_0, value, 0xffffff); + + pmic_read_reg(REG_MODE_1, &value, 0xffffff); + value |= REG_MODE_1_ALL_MASK; + pmic_write_reg(REG_MODE_1, value, 0xffffff); + + /* enable switch audo mode */ + pmic_read_reg(REG_IDENTIFICATION, &value, 0xffffff); + /* only for mc13892 2.0A */ + if ((value & 0x0000FFFF) == 0x45d0) { + pmic_read_reg(REG_SW_4, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW1MODE_LSB) | + (SWMODE_MASK << SW2MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW1MODE_LSB) | + (SWMODE_AUTO << SW2MODE_LSB); + pmic_write_reg(REG_SW_4, value, 0xffffff); + + pmic_read_reg(REG_SW_5, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW3MODE_LSB) | + (SWMODE_MASK << SW4MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW3MODE_LSB) | + (SWMODE_AUTO << SW4MODE_LSB); + pmic_write_reg(REG_SW_5, value, 0xffffff); + } + /* Enable coin cell charger */ + value = BITFVAL(COINCHEN, 1) | BITFVAL(VCOIN, VCOIN_3_0V); + register_mask = BITFMASK(COINCHEN) | BITFMASK(VCOIN); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); + +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) + value = BITFVAL(DRM, 1); + register_mask = BITFMASK(DRM); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); +#endif + + mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init); + mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init); + mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init); + mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init); + mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init); + mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init); + mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init); + mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init); + mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init); + mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init); + mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init); + mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init); + mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init); + mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init); + mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init); + mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init); + mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init); + mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init); + mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init); + mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init); + mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init); + + regulator_has_full_constraints(); + + return 0; +} + +static struct mc13892_platform_data mc13892_plat = { + .init = mc13892_regulator_init, +}; + +static struct spi_board_info __initdata mc13892_spi_device = { + .modalias = "pmic_spi", + .irq = IOMUX_TO_IRQ_V3(114), + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ + .bus_num = 3, + .chip_select = 0, + .platform_data = &mc13892_plat, +}; + + +int __init mx50_arm2_init_mc13892(void) +{ + return spi_register_board_info(&mc13892_spi_device, 1); +} diff --git a/arch/arm/mach-mx5/mx50_ddr_freq.S b/arch/arm/mach-mx5/mx50_ddr_freq.S new file mode 100644 index 000000000000..38317675c52f --- /dev/null +++ b/arch/arm/mach-mx5/mx50_ddr_freq.S @@ -0,0 +1,832 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +/* + * mx50_ddr_freq_change + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx50_ddr_freq_change) + stmfd sp!, {r3,r4,r5,r6, r7} @ Save registers + + mov r6, r0 @save CCM address + mov r5, r1 @save DataBahn address + mov r4, r2 @save new freq requested + + /* Make sure no TLB miss will occur when the DDR is in self refresh. */ + /* Invalidate TLB single entry to ensure that the address is not + * already in the TLB. + */ + adr r3, LoopCKE2 @Address in this function. + mcr p15, 0, r3, c8, c7, 1 @ Make sure freq code address + @ is not already in TLB. + mcr p15, 0, r6, c8, c7, 1 @ Make sure CCM address + @ is not already in TLB. + mcr p15, 0, r5, c8, c7, 1 @ make sure Databahn address + @ is not already in TLB. + mrc p15, 0, r0, c10, c0, 0 @ Read the TLB lockdown register + orr r0, r0, #1 @ Set the Preserve bit. + mcr p15, 0, r0, c10, c0, 0 @ Write to the lockdown register + ldr r2, [r6] @ TLB will miss, + @CCM address will be loaded + ldr r2, [r5] @ TLB will miss, + @Databahn address will be loaded + ldr r2, [r3] @ TLB will miss + mrc p15, 0, r0, c10, c0, 0 @ Read the lockdown register + @ (victim will be incremented) + bic r0, r0, #1 @ Clear the preserve bit + mcr p15, 0, r0, c10, c0, 0 @ Write to the lockdown register. + + /* If Databahn is in LPM4, exit that mode first. */ + ldr r1,[r5, #0x50] @Store LPM mode in r1. + mov r0, r1 + bic r0, #0x1F + str r0,[r5, #0x50] + +LoopCKE2: + /*Wait for CKE = 1 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE2 + +/* Wait for the databahn to idle + Meaning, no access to the databahn is + being made. +*/ +NotIdle: + ldr r0,[r5, #0x13c] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + beq NotIdle + + /* + * Make sure the DDR is self-refresh, before switching its frequency + * and clock source + */ + + /* Step 1: Enter self-refresh mode */ + ldr r0,[r5, #0x4c] + orr r0,r0,#0x1 + str r0,[r5, #0x4c] + + /* Step 2: Poll the CKE_STATUS bit. */ +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Step 3: Mask the DLL lock state change, set bit 8 in int_mask. */ + ldr r0, [r5, #0xac] + orr r0, r0, #0x100 + str r0, [r5, #0xac] + + /* Step 4: Stop the Controller. */ + ldr r0,[r5] + bic r0, r0, #0x1 + str r0,[r5] + + /* Step 5: Clear the DLL lock state change bit 8 in int_ack */ + ldr r0, [r5, #0xa8] + orr r0, r0, #0x1000000 + str r0, [r5, #0xa8] + + /* Step 6: Clear the interrupt mask for DLL lock state. + * Bit 8 in int_mask */ + ldr r0, [r5, #0xac] + bic r0, r0, #0x100 + str r0, [r5, #0xac] + + /* Change the freq now */ + /* If the freq req is below 24MHz, set DDR to synchronous mode. + * else set to async mode. */ + ldr r0, =24000000 + cmp r4, r0 + bgt Async_Mode + + /* Set the DDR to be Synchronous + mode. */ + /* Set the Databahn to sync mode. */ + ldr r0, [r5, #0xdc] + orr r0, r0, #0x30000 + str r0, [r5, #0xdc] + + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + /* Check if XTAL can source the DDR. */ + ldr r0, =24000000 + cmp r4, r0 + ble databahn_ddr_24 + + /*Source DDR from PLL1. Setup the dividers accordingly. */ + ldr r0, =800000000 + ldr r3, =1 +Loop1: + sub r0, r0, r4 + cmp r0, r4 + blt Div_Found + add r3, r3, #1 + bgt Loop1 + +Div_Found: + ldr r0, [r6, #0x94] + bic r0, r0, #0x3f + orr r0, r0, r3 + str r0, [r6, #0x94] + /* Set the DDR to sourced from PLL1 in sync path */ + ldr r0, [r6, #0x90] + orr r0, r0, #0x3 + str r0, [r6, #0x90] + + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, =24000000 + cmp r4, r0 + beq databahn_ddr_24 + + b Ddr_not_24 + +databahn_ddr_24: + + /* Check for mDDR v LPDDR2 memory type */ + ldr r0, [r5] + ldr r2, =0x100 + and r0, r0, #0xF00 + cmp r0, r2 + beq mddr_24 + + /* LPDDR2 settings */ + ldr r0, =0x00000003 + str r0, [r5, #0x08] + ldr r0, =0x000012c0 + str r0, [r5, #0x0c] + ldr r0, =0x00000018 + + str r0, [r5, #0x10] + ldr r0, =0x000000f0 + str r0, [r5, #0x14] + ldr r0, =0x02030b0c + str r0, [r5, #0x18] + ldr r0, =0x02020104 + str r0, [r5, #0x1c] + + ldr r0, =0x05010102 + str r0, [r5, #0x20] + ldr r0, =0x00068005 + str r0, [r5, #0x24] + ldr r0, =0x01000103 + str r0, [r5, #0x28] + ldr r0, =0x04030101 + str r0, [r5, #0x2c] + + ldr r0, =0x00000202 + str r0, [r5, #0x34] + ldr r0, =0x00000001 + str r0, [r5, #0x38] + ldr r0, =0x00000401 + str r0, [r5, #0x3c] + + /* Set TREF. */ + ldr r0, =0x00030050 + str r0, [r5, #0x40] + ldr r0, =0x00040004 + str r0, [r5, #0x48] + + ldr r0, =0x00040022 + str r0, [r5, #0x6c] + + ldr r0, =0x00040022 + str r0, [r5, #0x78] + + ldr r0, =0x00180000 + str r0, [r5, #0x80] + ldr r0, =0x00000009 + str r0, [r5, #0x84] + ldr r0, =0x02400003 + str r0, [r5, #0x88] + ldr r0, =0x01000200 + str r0, [r5, #0x8c] + + ldr r0, =0x00000000 + str r0, [r5, #0xcc] + + ldr r0, =0x01010301 + str r0, [r5, #0xd4] + ldr r0, =0x00000101 + str r0, [r5, #0xd8] + + ldr r0, =0x02000602 + str r0, [r5, #0x104] + ldr r0, =0x00560000 + str r0, [r5, #0x108] + ldr r0, =0x00560056 + str r0, [r5, #0x10c] + + ldr r0, =0x00560056 + str r0, [r5, #0x110] + ldr r0, =0x03060056 + str r0, [r5, #0x114] + + /* Set the Databahn DLL in bypass mode */ + /* PHY Register settings. */ + ldr r0, =0x0 + str r0, [r5, #0x200] + ldr r0, =0x0 + str r0, [r5, #0x204] + ldr r0, =0xf3003a27 + str r0, [r5, #0x208] + ldr r0, =0x074002c1 + str r0, [r5, #0x20c] + + ldr r0, =0xf3003a27 + str r0, [r5, #0x210] + ldr r0, =0x074002c1 + str r0, [r5, #0x214] + ldr r0, =0xf3003a27 + str r0, [r5, #0x218] + ldr r0, =0x074002c1 + str r0, [r5, #0x21c] + + ldr r0, =0xf3003a27 + str r0, [r5, #0x220] + ldr r0, =0x074002c1 + str r0, [r5, #0x224] + ldr r0, =0xf3003a27 + str r0, [r5, #0x228] + ldr r0, =0x074002c1 + str r0, [r5, #0x22c] + + ldr r0, =0x00810004 + str r0, [r5, #0x234] + ldr r0, =0x30219fd3 + str r0, [r5, #0x238] + ldr r0, =0x00219fc1 + str r0, [r5, #0x23c] + + ldr r0, =0x30219fd3 + str r0, [r5, #0x240] + ldr r0, =0x00219fc1 + str r0, [r5, #0x244] + ldr r0, =0x30219fd3 + str r0, [r5, #0x248] + ldr r0, =0x00219fc1 + str r0, [r5, #0x24c] + + ldr r0, =0x30219fd3 + str r0, [r5, #0x250] + ldr r0, =0x00219fc1 + str r0, [r5, #0x254] + ldr r0, =0x30219fd3 + str r0, [r5, #0x258] + ldr r0, =0x00219fc1 + str r0, [r5, #0x25c] + + b clocking + +/* mDDR settings */ +mddr_24: + ldr r0, =0x000012c0 + str r0, [r5, #0x08] + ldr r0, =0x02000000 + str r0, [r5, #0x14] + ldr r0, =0x01010506 + str r0, [r5, #0x18] + ldr r0, =0x01020101 + str r0, [r5, #0x1c] + + ldr r0, =0x02000103 + str r0, [r5, #0x20] + ldr r0, =0x01069002 + str r0, [r5, #0x24] + ldr r0, =0x01000101 + str r0, [r5, #0x28] + ldr r0, =0x02010101 + str r0, [r5, #0x2c] + + ldr r0, =0x00000602 + str r0, [r5, #0x34] + ldr r0, =0x00000001 + str r0, [r5, #0x38] + ldr r0, =0x00000301 + str r0, [r5, #0x3c] + + /* Set TREF. */ + ldr r0, =0x000500b0 + str r0, [r5, #0x40] + ldr r0, =0x00030003 + str r0, [r5, #0x48] + + ldr r0, =0x00000000 + str r0, [r5, #0x6c] + + ldr r0, =0x00000200 + str r0, [r5, #0xd4] + + ldr r0, =0x00b30000 + str r0, [r5, #0x108] + ldr r0, =0x00b300b3 + str r0, [r5, #0x10c] + + ldr r0, =0x00b300b3 + str r0, [r5, #0x110] + ldr r0, =0x010300b3 + str r0, [r5, #0x114] + + /* Set the Databahn DLL in bypass mode */ + /* PHY Register settings. */ + ldr r0, =0x00000100 + str r0, [r5, #0x200] + ldr r0, =0x0 + str r0, [r5, #0x204] + ldr r0, =0xf4003a27 + str r0, [r5, #0x208] + ldr r0, =0x074002c0 + str r0, [r5, #0x20c] + + ldr r0, =0xf4003a27 + str r0, [r5, #0x210] + ldr r0, =0x074002c0 + str r0, [r5, #0x214] + ldr r0, =0xf4003a27 + str r0, [r5, #0x218] + ldr r0, =0x074002c0 + str r0, [r5, #0x21c] + + ldr r0, =0xf4003a27 + str r0, [r5, #0x220] + ldr r0, =0x074002c0 + str r0, [r5, #0x224] + ldr r0, =0xf4003a27 + str r0, [r5, #0x228] + ldr r0, =0x074002c0 + str r0, [r5, #0x22c] + + ldr r0, =0x00800005 + str r0, [r5, #0x234] + ldr r0, =0x30319f14 + str r0, [r5, #0x238] + ldr r0, =0x00319f01 + str r0, [r5, #0x23c] + + ldr r0, =0x30319f14 + str r0, [r5, #0x240] + ldr r0, =0x00319f01 + str r0, [r5, #0x244] + ldr r0, =0x30319f14 + str r0, [r5, #0x248] + ldr r0, =0x00319f01 + str r0, [r5, #0x24c] + + ldr r0, =0x30319f14 + str r0, [r5, #0x250] + ldr r0, =0x00319f01 + str r0, [r5, #0x254] + ldr r0, =0x30319f14 + str r0, [r5, #0x258] + ldr r0, =0x00319f01 + str r0, [r5, #0x25c] + +clocking: + /* Set SYS_CLK to be sourced from 24MHz. */ + /* Set the SYS_XTAL_DIV */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3c0 + orr r0, r0, #0x40 + str r0, [r6, #0x94] + + /* Enable SYS_XTAL_CLKGATE. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x94] + + /* set SYS_CLK to be sourced from XTAL. */ + ldr r0, [r6, #0x90] + bic r0, r0, #0x1 + str r0, [r6, #0x90] + + /* Disable SYS_PLL_CLKGATE.*/ + ldr r0, [r6, #0x94] + bic r0, r0, #0x30000000 + str r0, [r6, #0x94] + b Setup_Done + +Async_Mode: + /* If SYS_CLK is running at 24MHz, increase + * it to 200MHz. + */ + /* r7 indicates that we are moving from 133Mhz<-> 266MHz */ + ldr r7, =1 + ldr r0, [r6, #0x90] + and r0, r0, #0x1 + cmp r0, #0 + bne Sys_Clk_Not_24 + ldr r7, =0 + + /* Disable SYS_PLL_CLKGATE. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x30000000 + str r0, [r6, #0x94] + + /* Set the new divider. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3f + orr r0, r0, #4 + str r0, [r6, #0x94] + + /* Enable SYS_PLL_CLKGATE. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0x30000000 + str r0, [r6, #0x94] + + /* SYS_CLK to be sourced from PLL1. */ + ldr r0, [r6, #0x90] + orr r0, r0, #0x3 + str r0, [r6, #0x90] + + /* Disable SYS_XTAL_CLKGATE. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x94] + +Sys_Clk_Not_24: + /* Set the Databahn to async mode. */ + ldr r0, [r5, #0xdc] + and r0, r0, #0xfffcffff + str r0, [r5, #0xdc] + + /*Source DDR from PLL1. Setup the dividers accordingly. */ + ldr r0, =800000000 + ldr r3, =1 +Loop2: + sub r0, r0, r4 + cmp r0, r4 + blt Div_Found1 + add r3, r3, #1 + bgt Loop2 + +Div_Found1: + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, [r6, #0x98] + bic r0, r0, #0x3f + orr r0, r0, r3 + str r0, [r6, #0x98] + + /* Set the DDR to sourced from PLL1 in async path */ + ldr r0, [r6, #0x98] + bic r0, r0, #0x40 + str r0, [r6, #0x98] + + /* Turn ON the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, =24000000 + cmp r4, r0 + beq databahn_ddr_24 + +Ddr_not_24: + /* Check for mDDR v LPDDR2 memory type */ + ldr r0, [r5] + ldr r2, =0x100 + and r0, r0, #0xF00 + cmp r0, r2 + beq mddr_not_24 + + cmp r7, #1 + beq just_set_tref + + ldr r0, =0x0000001b + str r0, [r5, #0x8] + ldr r0, =0x0000d056 + str r0, [r5, #0xc] + + ldr r0, =0x0000010b + str r0, [r5, #0x10] + ldr r0, =0x00000a6b + str r0, [r5, #0x14] + ldr r0, =0x02030d0c + str r0, [r5, #0x18] + ldr r0, =0x0c110304 + str r0, [r5, #0x1c] + + ldr r0, =0x05020503 + str r0, [r5, #0x20] + ldr r0, =0x0048D005 + str r0, [r5, #0x24] + ldr r0, =0x01000403 + str r0, [r5, #0x28] + ldr r0, =0x09040501 + str r0, [r5, #0x2c] + + ldr r0, =0x00000e02 + str r0, [r5, #0x34] + ldr r0, =0x00000006 + str r0, [r5, #0x38] + ldr r0, =0x00002301 + str r0, [r5, #0x3c] + +just_set_tref: + ldr r0, =133333333 + cmp r4, r0 + bgt ddr_266 + ldr r0, =0x00050180 + b tref_done +ddr_266: + ldr r0, =0x00050300 +tref_done: + str r0, [r5, #0x40] + + cmp r7, #1 + beq Setup_Done + + ldr r0, =0x00260026 + str r0, [r5, #0x48] + + ldr r0, =0x00040042 + str r0, [r5, #0x6c] + + ldr r0, =0x00040042 + str r0, [r5, #0x78] + + ldr r0, =0x010b0000 + str r0, [r5, #0x80] + ldr r0, =0x00000060 + str r0, [r5, #0x84] + ldr r0, =0x02400018 + str r0, [r5, #0x88] + ldr r0, =0x01000e00 + str r0, [r5, #0x8c] + + ldr r0, =0x01000000 + str r0, [r5, #0xcc] + + ldr r0, =0x00000200 + str r0, [r5, #0xd4] + ldr r0, =0x00000102 + str r0, [r5, #0xd8] + + ldr r0, =0x02000802 + str r0, [r5, #0x104] + ldr r0, =0x04080000 + str r0, [r5, #0x108] + ldr r0, =0x04080408 + str r0, [r5, #0x10c] + + ldr r0, =0x04080408 + str r0, [r5, #0x110] + ldr r0, =0x03060408 + str r0, [r5, #0x114] + + /* PHY setting for 266MHz */ + ldr r0, =0x00000000 + str r0, [r5, #0x200] + ldr r0, =0x00000000 + str r0, [r5, #0x204] + ldr r0, =0xf5003a27 + str r0, [r5, #0x208] + + ldr r0, =0xf5003a27 + str r0, [r5, #0x210] + ldr r0, =0xf5003a27 + str r0, [r5, #0x218] + + ldr r0, =0xf5003a27 + str r0, [r5, #0x220] + ldr r0, =0xf5003a27 + str r0, [r5, #0x228] + + ldr r0, =0x074002e1 + str r0, [r5, #0x20c] + ldr r0, =0x074002e1 + str r0, [r5, #0x214] + ldr r0, =0x074002e1 + str r0, [r5, #0x21c] + ldr r0, =0x074002e1 + str r0, [r5, #0x224] + ldr r0, =0x074002e1 + str r0, [r5, #0x22c] + + ldr r0, =0x00810006 + str r0, [r5, #0x234] + ldr r0, =0x60099414 + str r0, [r5, #0x238] + ldr r0, =0x000a0b01 + str r0, [r5, #0x23c] + + ldr r0, =0x60099414 + str r0, [r5, #0x240] + ldr r0, =0x000a0b01 + str r0, [r5, #0x244] + ldr r0, =0x60099414 + str r0, [r5, #0x248] + ldr r0, =0x000a0b01 + str r0, [r5, #0x24c] + + ldr r0, =0x60099414 + str r0, [r5, #0x250] + ldr r0, =0x000a0b01 + str r0, [r5, #0x254] + ldr r0, =0x60099414 + str r0, [r5, #0x258] + ldr r0, =0x000a0b01 + str r0, [r5, #0x25c] + + b Setup_Done + +mddr_not_24: + /* mDDR settings */ + cmp r7, #1 + beq just_set_tref_mddr + + ldr r0, =0x00009c40 + str r0, [r5, #0x8] + + ldr r0, =0x02000000 + str r0, [r5, #0x14] + ldr r0, =0x01010706 + str r0, [r5, #0x18] + ldr r0, =0x080b0201 + str r0, [r5, #0x1c] + + ldr r0, =0x02000303 + str r0, [r5, #0x20] + ldr r0, =0x0136b002 + str r0, [r5, #0x24] + ldr r0, =0x01000101 + str r0, [r5, #0x28] + ldr r0, =0x06030301 + str r0, [r5, #0x2c] + + ldr r0, =0x00000a02 + str r0, [r5, #0x34] + ldr r0, =0x00000003 + str r0, [r5, #0x38] + ldr r0, =0x00001401 + str r0, [r5, #0x3c] + +just_set_tref_mddr: + ldr r0, =133333333 + cmp r4, r0 + bgt mddr_200 + ldr r0, =0x00050208 + b tref_done1 +mddr_200: + ldr r0, =0x0005030f +tref_done1: + str r0, [r5, #0x40] + + cmp r7, #1 + beq Setup_Done + + ldr r0, =0x00180018 + str r0, [r5, #0x48] + + ldr r0, =0x00800000 + str r0, [r5, #0x6c] + + ldr r0, =0x02030302 + str r0, [r5, #0xd4] + + ldr r0, =0x06120000 + str r0, [r5, #0x108] + ldr r0, =0x06120612 + str r0, [r5, #0x10c] + + ldr r0, =0x06120612 + str r0, [r5, #0x110] + ldr r0, =0x01030612 + str r0, [r5, #0x114] + + /* PHY setting for 200 MHz */ + ldr r0, =0x00000000 + str r0, [r5, #0x200] + ldr r0, =0x00000000 + str r0, [r5, #0x204] + ldr r0, =0xf5002725 + str r0, [r5, #0x208] + + ldr r0, =0xf5002725 + str r0, [r5, #0x210] + ldr r0, =0xf5002725 + str r0, [r5, #0x218] + + ldr r0, =0xf5002725 + str r0, [r5, #0x220] + ldr r0, =0xf5002725 + str r0, [r5, #0x228] + + ldr r0, =0x070002d0 + str r0, [r5, #0x20c] + ldr r0, =0x074002d0 + str r0, [r5, #0x214] + ldr r0, =0x074002d0 + str r0, [r5, #0x21c] + ldr r0, =0x074002d0 + str r0, [r5, #0x224] + ldr r0, =0x074002d0 + str r0, [r5, #0x22c] + + ldr r0, =0x00800006 + str r0, [r5, #0x234] + ldr r0, =0x200e1014 + str r0, [r5, #0x238] + ldr r0, =0x000d9f01 + str r0, [r5, #0x23c] + + ldr r0, =0x200e1014 + str r0, [r5, #0x240] + ldr r0, =0x000d9f01 + str r0, [r5, #0x244] + ldr r0, =0x200e1014 + str r0, [r5, #0x248] + ldr r0, =0x000d9f01 + str r0, [r5, #0x24c] + + ldr r0, =0x200e1014 + str r0, [r5, #0x250] + ldr r0, =0x000d9f01 + str r0, [r5, #0x254] + ldr r0, =0x200e1014 + str r0, [r5, #0x258] + ldr r0, =0x000d9f01 + str r0, [r5, #0x25c] + +Setup_Done: + /* Start controller */ + ldr r0,[r5] + orr r0, r0,#0x1 + str r0,[r5] + + /* Poll the DLL lock state change in int_status reg*/ + /* DLL is bypassed in the 24MHz mode, so no waiting for DLL to lock. */ + ldr r0, =24000000 + cmp r4, r0 + beq Exit_Self_Refresh + +DllLock: + ldr r0, [r5, #0xa8] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + bne DllLock + + /*Leave self-refresh mode */ +Exit_Self_Refresh: + ldr r0,[r5, #0x4c] + and r0,r0,#0xfffffffe + str r0,[r5, #0x4c] + +LoopCKE1: + /*Wait for CKE = 1 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE1 + + /* Put the databahn back to into the LPM mode. */ + str r1,[r5, #0x50] + + /* Restore registers */ + ldmfd sp!, {r3,r4,r5,r6, r7} + mov pc, lr + + .type mx50_do_ddr_freq_change, #object +ENTRY(mx50_do_ddr_freq_change) + .word mx50_ddr_freq_change + .size mx50_ddr_freq_change, . - mx50_ddr_freq_change diff --git a/arch/arm/mach-mx5/mx50_rdp.c b/arch/arm/mach-mx5/mx50_rdp.c new file mode 100644 index 000000000000..f5b64400f4a5 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_rdp.c @@ -0,0 +1,1595 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/videodev2.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/gpmi-nfc.h> +#include <linux/powerkey.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 <asm/mach/flash.h> +#include <asm/mach/keypad.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/memory.h> +#include <mach/arc_otg.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx50.h> +#include <mach/i2c.h> + +#include "devices.h" +#include "usb.h" +#include "crm_regs.h" +#include "dma-apbh.h" + +#define SD1_WP (3*32 + 19) /*GPIO_4_19 */ +#define SD1_CD (0*32 + 27) /*GPIO_1_27 */ +#define SD2_WP (4*32 + 16) /*GPIO_5_16 */ +#define SD2_CD (4*32 + 17) /*GPIO_5_17 */ +#define HP_DETECT (3*32 + 15) /*GPIO_4_15 */ +#define PWR_INT (3*32 + 18) /*GPIO_4_18 */ +#define EPDC_D0 (2*32 + 0) /*GPIO_3_0 */ +#define EPDC_D1 (2*32 + 1) /*GPIO_3_1 */ +#define EPDC_D2 (2*32 + 2) /*GPIO_3_2 */ +#define EPDC_D3 (2*32 + 3) /*GPIO_3_3 */ +#define EPDC_D4 (2*32 + 4) /*GPIO_3_4 */ +#define EPDC_D5 (2*32 + 5) /*GPIO_3_5 */ +#define EPDC_D6 (2*32 + 6) /*GPIO_3_6 */ +#define EPDC_D7 (2*32 + 7) /*GPIO_3_7 */ +#define EPDC_GDCLK (2*32 + 16) /*GPIO_3_16 */ +#define EPDC_GDSP (2*32 + 17) /*GPIO_3_17 */ +#define EPDC_GDOE (2*32 + 18) /*GPIO_3_18 */ +#define EPDC_GDRL (2*32 + 19) /*GPIO_3_19 */ +#define EPDC_SDCLK (2*32 + 20) /*GPIO_3_20 */ +#define EPDC_SDOE (2*32 + 23) /*GPIO_3_23 */ +#define EPDC_SDLE (2*32 + 24) /*GPIO_3_24 */ +#define EPDC_SDSHR (2*32 + 26) /*GPIO_3_26 */ +#define EPDC_BDR0 (3*32 + 23) /*GPIO_4_23 */ +#define EPDC_SDCE0 (3*32 + 25) /*GPIO_4_25 */ +#define EPDC_SDCE1 (3*32 + 26) /*GPIO_4_26 */ +#define EPDC_SDCE2 (3*32 + 27) /*GPIO_4_27 */ +#define EPDC_PMIC_WAKE (5*32 + 16) /*GPIO_6_16 */ +#define EPDC_PMIC_INT (5*32 + 17) /*GPIO_6_17 */ +#define EPDC_VCOM (3*32 + 21) /*GPIO_4_21 */ +#define EPDC_PWRSTAT (2*32 + 28) /*GPIO_3_28 */ +#define ELCDIF_PWR_ON (1*32 + 21) /*GPIO_2_21 */ +#define ELCDIF_DAT0_DUMMY (0*32 + 0) /*GPIO_1_0 */ +#define ELCDIF_DAT1_DUMMY (0*32 + 1) /*GPIO_1_1 */ +#define ELCDIF_DAT2_DUMMY (0*32 + 2) /*GPIO_1_2 */ +#define ELCDIF_DAT8_DUMMY (0*32 + 3) /*GPIO_1_3 */ +#define ELCDIF_DAT9_DUMMY (0*32 + 4) /*GPIO_1_4 */ +#define ELCDIF_DAT16_DUMMY (0*32 + 5) /*GPIO_1_5 */ +#define ELCDIF_DAT17_DUMMY (0*32 + 6) /*GPIO_1_6 */ +#define ELCDIF_DAT18_DUMMY (0*32 + 7) /*GPIO_1_7 */ +#define CSPI_CS1 (3*32 + 13) /*GPIO_4_13 */ +#define CSPI_CS2 (3*32 + 11) /*GPIO_4_11*/ +#define SGTL_OSCEN (5*32 + 8) /*GPIO_6_8*/ +#define SGTL_AMP_SHDN (5*32 + 15) /*GPIO_6_15*/ +#define FEC_EN (5*32 + 23) /*GPIO_6_23*/ +#define FEC_RESET_B (3*32 + 12) /*GPIO_4_12*/ +#define USB_OTG_PWR (5*32 + 25) /*GPIO_6_25*/ + +extern int __init mx50_rdp_init_mc13892(void); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); +static int max17135_regulator_init(struct max17135 *max17135); +static int num_cpu_wp = 2; + +static struct pad_desc mx50_rdp[] = { + /* SD1 */ + MX50_PAD_ECSPI2_SS0__GPIO_4_19, + MX50_PAD_EIM_CRE__GPIO_1_27, + MX50_PAD_SD1_CMD__SD1_CMD, + + MX50_PAD_SD1_CLK__SD1_CLK, + MX50_PAD_SD1_D0__SD1_D0, + MX50_PAD_SD1_D1__SD1_D1, + MX50_PAD_SD1_D2__SD1_D2, + MX50_PAD_SD1_D3__SD1_D3, + + /* SD2 */ + MX50_PAD_SD2_CD__GPIO_5_17, + MX50_PAD_SD2_WP__GPIO_5_16, + MX50_PAD_SD2_CMD__SD2_CMD, + MX50_PAD_SD2_CLK__SD2_CLK, + MX50_PAD_SD2_D0__SD2_D0, + MX50_PAD_SD2_D1__SD2_D1, + MX50_PAD_SD2_D2__SD2_D2, + MX50_PAD_SD2_D3__SD2_D3, + MX50_PAD_SD2_D4__SD2_D4, + MX50_PAD_SD2_D5__SD2_D5, + MX50_PAD_SD2_D6__SD2_D6, + MX50_PAD_SD2_D7__SD2_D7, + + /* SD3 */ + MX50_PAD_SD3_CMD__SD3_CMD, + MX50_PAD_SD3_CLK__SD3_CLK, + MX50_PAD_SD3_D0__SD3_D0, + MX50_PAD_SD3_D1__SD3_D1, + MX50_PAD_SD3_D2__SD3_D2, + MX50_PAD_SD3_D3__SD3_D3, + MX50_PAD_SD3_D4__SD3_D4, + MX50_PAD_SD3_D5__SD3_D5, + MX50_PAD_SD3_D6__SD3_D6, + MX50_PAD_SD3_D7__SD3_D7, + + MX50_PAD_SSI_RXD__SSI_RXD, + MX50_PAD_SSI_TXD__SSI_TXD, + MX50_PAD_SSI_TXC__SSI_TXC, + MX50_PAD_SSI_TXFS__SSI_TXFS, + + /* HP_DET_B (headphone detect) */ + MX50_PAD_ECSPI1_SS0__GPIO_4_15, + + /* PWR_INT */ + MX50_PAD_ECSPI2_MISO__GPIO_4_18, + + /* UART pad setting */ + MX50_PAD_UART1_TXD__UART1_TXD, + MX50_PAD_UART1_RXD__UART1_RXD, + MX50_PAD_UART1_RTS__UART1_RTS, + MX50_PAD_UART2_TXD__UART2_TXD, + MX50_PAD_UART2_RXD__UART2_RXD, + MX50_PAD_UART2_CTS__UART2_CTS, + MX50_PAD_UART2_RTS__UART2_RTS, + + MX50_PAD_I2C1_SCL__I2C1_SCL, + MX50_PAD_I2C1_SDA__I2C1_SDA, + MX50_PAD_I2C2_SCL__I2C2_SCL, + MX50_PAD_I2C2_SDA__I2C2_SDA, + + /* EPDC pins */ + MX50_PAD_EPDC_D0__EPDC_D0, + MX50_PAD_EPDC_D1__EPDC_D1, + MX50_PAD_EPDC_D2__EPDC_D2, + MX50_PAD_EPDC_D3__EPDC_D3, + MX50_PAD_EPDC_D4__EPDC_D4, + MX50_PAD_EPDC_D5__EPDC_D5, + MX50_PAD_EPDC_D6__EPDC_D6, + MX50_PAD_EPDC_D7__EPDC_D7, + MX50_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX50_PAD_EPDC_GDSP__EPDC_GDSP, + MX50_PAD_EPDC_GDOE__EPDC_GDOE , + MX50_PAD_EPDC_GDRL__EPDC_GDRL, + MX50_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX50_PAD_EPDC_SDOE__EPDC_SDOE, + MX50_PAD_EPDC_SDLE__EPDC_SDLE, + MX50_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX50_PAD_EPDC_BDR0__EPDC_BDR0, + MX50_PAD_EPDC_SDCE0__EPDC_SDCE0, + MX50_PAD_EPDC_SDCE1__EPDC_SDCE1, + MX50_PAD_EPDC_SDCE2__EPDC_SDCE2, + + MX50_PAD_EPDC_PWRSTAT__GPIO_3_28, + MX50_PAD_EPDC_VCOM0__GPIO_4_21, + + MX50_PAD_DISP_D8__DISP_D8, + MX50_PAD_DISP_D9__DISP_D9, + MX50_PAD_DISP_D10__DISP_D10, + MX50_PAD_DISP_D11__DISP_D11, + MX50_PAD_DISP_D12__DISP_D12, + MX50_PAD_DISP_D13__DISP_D13, + MX50_PAD_DISP_D14__DISP_D14, + MX50_PAD_DISP_D15__DISP_D15, + MX50_PAD_DISP_RS__ELCDIF_VSYNC, + + /* ELCDIF contrast */ + MX50_PAD_PWM1__PWMO, + + /* ELCDIF power on */ + MX50_PAD_DISP_CS__GPIO_2_21, + + MX50_PAD_DISP_BUSY__ELCDIF_HSYNC, + MX50_PAD_DISP_RD__ELCDIF_EN, + MX50_PAD_DISP_WR__ELCDIF_PIXCLK, + + /* EPD PMIC WAKEUP */ + MX50_PAD_UART4_TXD__GPIO_6_16, + + /* EPD PMIC intr */ + MX50_PAD_UART4_RXD__GPIO_6_17, + + MX50_PAD_EPITO__USBH1_PWR, + /* Need to comment below line if + * one needs to debug owire. + */ + MX50_PAD_OWIRE__USBH1_OC, + /* using gpio to control otg pwr */ + MX50_PAD_PWM2__GPIO_6_25, + MX50_PAD_I2C3_SCL__USBOTG_OC, + + MX50_PAD_SSI_RXC__FEC_MDIO, + MX50_PAD_SSI_RXC__FEC_MDIO, + MX50_PAD_DISP_D0__FEC_TXCLK, + MX50_PAD_DISP_D1__FEC_RX_ER, + MX50_PAD_DISP_D2__FEC_RX_DV, + MX50_PAD_DISP_D3__FEC_RXD1, + MX50_PAD_DISP_D4__FEC_RXD0, + MX50_PAD_DISP_D5__FEC_TX_EN, + MX50_PAD_DISP_D6__FEC_TXD1, + MX50_PAD_DISP_D7__FEC_TXD0, + MX50_PAD_SSI_RXFS__FEC_MDC, + MX50_PAD_I2C3_SDA__GPIO_6_23, + MX50_PAD_ECSPI1_SCLK__GPIO_4_12, + + MX50_PAD_CSPI_SS0__CSPI_SS0, + MX50_PAD_ECSPI1_MOSI__CSPI_SS1, + MX50_PAD_CSPI_MOSI__CSPI_MOSI, + MX50_PAD_CSPI_MISO__CSPI_MISO, + + /* SGTL500_OSC_EN */ + MX50_PAD_UART1_CTS__GPIO_6_8, + + /* SGTL_AMP_SHDN */ + MX50_PAD_UART3_RXD__GPIO_6_15, + + /* Keypad */ + MX50_PAD_KEY_COL0__KEY_COL0, + MX50_PAD_KEY_ROW0__KEY_ROW0, + MX50_PAD_KEY_COL1__KEY_COL1, + MX50_PAD_KEY_ROW1__KEY_ROW1, + MX50_PAD_KEY_COL2__KEY_COL2, + MX50_PAD_KEY_ROW2__KEY_ROW2, + MX50_PAD_KEY_COL3__KEY_COL3, + MX50_PAD_KEY_ROW3__KEY_ROW3, + MX50_PAD_EIM_DA0__KEY_COL4, + MX50_PAD_EIM_DA1__KEY_ROW4, + MX50_PAD_EIM_DA2__KEY_COL5, + MX50_PAD_EIM_DA3__KEY_ROW5, + MX50_PAD_EIM_DA4__KEY_COL6, + MX50_PAD_EIM_DA5__KEY_ROW6, + MX50_PAD_EIM_DA6__KEY_COL7, + MX50_PAD_EIM_DA7__KEY_ROW7, + /*EIM pads */ + MX50_PAD_EIM_DA8__GPIO_1_8, + MX50_PAD_EIM_DA9__GPIO_1_9, + MX50_PAD_EIM_DA10__GPIO_1_10, + MX50_PAD_EIM_DA11__GPIO_1_11, + MX50_PAD_EIM_DA12__GPIO_1_12, + MX50_PAD_EIM_DA13__GPIO_1_13, + MX50_PAD_EIM_DA14__GPIO_1_14, + MX50_PAD_EIM_DA15__GPIO_1_15, + MX50_PAD_EIM_CS2__GPIO_1_16, + MX50_PAD_EIM_CS1__GPIO_1_17, + MX50_PAD_EIM_CS0__GPIO_1_18, + MX50_PAD_EIM_EB0__GPIO_1_19, + MX50_PAD_EIM_EB1__GPIO_1_20, + MX50_PAD_EIM_WAIT__GPIO_1_21, + MX50_PAD_EIM_BCLK__GPIO_1_22, + MX50_PAD_EIM_RDY__GPIO_1_23, + MX50_PAD_EIM_OE__GPIO_1_24, + MX50_PAD_EIM_RW__GPIO_1_25, + MX50_PAD_EIM_LBA__GPIO_1_26, +}; + +static struct pad_desc mx50_gpmi_nand[] = { + MX50_PIN_EIM_DA8__NANDF_CLE, + MX50_PIN_EIM_DA9__NANDF_ALE, + MX50_PIN_EIM_DA10__NANDF_CE0, + MX50_PIN_EIM_DA11__NANDF_CE1, + MX50_PIN_EIM_DA12__NANDF_CE2, + MX50_PIN_EIM_DA13__NANDF_CE3, + MX50_PIN_EIM_DA14__NANDF_READY, + MX50_PIN_EIM_DA15__NANDF_DQS, + MX50_PIN_SD3_D4__NANDF_D0, + MX50_PIN_SD3_D5__NANDF_D1, + MX50_PIN_SD3_D6__NANDF_D2, + MX50_PIN_SD3_D7__NANDF_D3, + MX50_PIN_SD3_D0__NANDF_D4, + MX50_PIN_SD3_D1__NANDF_D5, + MX50_PIN_SD3_D2__NANDF_D6, + MX50_PIN_SD3_D3__NANDF_D7, + MX50_PIN_SD3_CLK__NANDF_RDN, + MX50_PIN_SD3_CMD__NANDF_WRN, + MX50_PIN_SD3_WP__NANDF_RESETN, +}; + +static struct pad_desc suspend_enter_pads[] = { + MX50_PAD_EIM_DA0__GPIO_1_0, + MX50_PAD_EIM_DA1__GPIO_1_1, + MX50_PAD_EIM_DA2__GPIO_1_2, + MX50_PAD_EIM_DA3__GPIO_1_3, + MX50_PAD_EIM_DA4__GPIO_1_4, + MX50_PAD_EIM_DA5__GPIO_1_5, + MX50_PAD_EIM_DA6__GPIO_1_6, + MX50_PAD_EIM_DA7__GPIO_1_7, + + MX50_PAD_EIM_DA8__GPIO_1_8, + MX50_PAD_EIM_DA9__GPIO_1_9, + MX50_PAD_EIM_DA10__GPIO_1_10, + MX50_PAD_EIM_DA11__GPIO_1_11, + MX50_PAD_EIM_DA12__GPIO_1_12, + MX50_PAD_EIM_DA13__GPIO_1_13, + MX50_PAD_EIM_DA14__GPIO_1_14, + MX50_PAD_EIM_DA15__GPIO_1_15, + MX50_PAD_EIM_CS2__GPIO_1_16, + MX50_PAD_EIM_CS1__GPIO_1_17, + MX50_PAD_EIM_CS0__GPIO_1_18, + MX50_PAD_EIM_EB0__GPIO_1_19, + MX50_PAD_EIM_EB1__GPIO_1_20, + MX50_PAD_EIM_WAIT__GPIO_1_21, + MX50_PAD_EIM_BCLK__GPIO_1_22, + MX50_PAD_EIM_RDY__GPIO_1_23, + MX50_PAD_EIM_OE__GPIO_1_24, + MX50_PAD_EIM_RW__GPIO_1_25, + MX50_PAD_EIM_LBA__GPIO_1_26, + MX50_PAD_EIM_CRE__GPIO_1_27, + + /* NVCC_NANDF pads */ + MX50_PAD_DISP_D8__GPIO_2_8, + MX50_PAD_DISP_D9__GPIO_2_9, + MX50_PAD_DISP_D10__GPIO_2_10, + MX50_PAD_DISP_D11__GPIO_2_11, + MX50_PAD_DISP_D12__GPIO_2_12, + MX50_PAD_DISP_D13__GPIO_2_13, + MX50_PAD_DISP_D14__GPIO_2_14, + MX50_PAD_DISP_D15__GPIO_2_15, + MX50_PAD_SD3_CMD__GPIO_5_18, + MX50_PAD_SD3_CLK__GPIO_5_19, + MX50_PAD_SD3_D0__GPIO_5_20, + MX50_PAD_SD3_D1__GPIO_5_21, + MX50_PAD_SD3_D2__GPIO_5_22, + MX50_PAD_SD3_D3__GPIO_5_23, + MX50_PAD_SD3_D4__GPIO_5_24, + MX50_PAD_SD3_D5__GPIO_5_25, + MX50_PAD_SD3_D6__GPIO_5_26, + MX50_PAD_SD3_D7__GPIO_5_27, + MX50_PAD_SD3_WP__GPIO_5_28, + + /* NVCC_LCD pads */ + MX50_PAD_DISP_D0__GPIO_2_0, + MX50_PAD_DISP_D1__GPIO_2_1, + MX50_PAD_DISP_D2__GPIO_2_2, + MX50_PAD_DISP_D3__GPIO_2_3, + MX50_PAD_DISP_D4__GPIO_2_4, + MX50_PAD_DISP_D5__GPIO_2_5, + MX50_PAD_DISP_D6__GPIO_2_6, + MX50_PAD_DISP_D7__GPIO_2_7, + MX50_PAD_DISP_WR__GPIO_2_16, + MX50_PAD_DISP_RS__GPIO_2_17, + MX50_PAD_DISP_BUSY__GPIO_2_18, + MX50_PAD_DISP_RD__GPIO_2_19, + MX50_PAD_DISP_RESET__GPIO_2_20, + MX50_PAD_DISP_CS__GPIO_2_21, + + /* CSPI pads */ + MX50_PAD_CSPI_SCLK__GPIO_4_8, + MX50_PAD_CSPI_MOSI__GPIO_4_9, + MX50_PAD_CSPI_MISO__GPIO_4_10, + MX50_PAD_CSPI_SS0__GPIO_4_11, + + /*NVCC_MISC pins as GPIO */ + MX50_PAD_I2C1_SCL__GPIO_6_18, + MX50_PAD_I2C1_SDA__GPIO_6_19, + MX50_PAD_I2C2_SCL__GPIO_6_20, + MX50_PAD_I2C2_SDA__GPIO_6_21, + MX50_PAD_I2C3_SCL__GPIO_6_22, + MX50_PAD_I2C3_SDA__GPIO_6_23, + + /* NVCC_MISC_PWM_USB_OTG pins */ + MX50_PAD_PWM1__GPIO_6_24, + MX50_PAD_PWM2__GPIO_6_25, + MX50_PAD_EPITO__GPIO_6_27, + MX50_PAD_WDOG__GPIO_6_28, + + /* FEC related. */ + MX50_PAD_EPDC_D10__GPIO_3_10, + MX50_PAD_SSI_RXC__GPIO_6_5, + MX50_PAD_SSI_RXFS__GPIO_6_4, +}; + +static struct pad_desc suspend_exit_pads[ARRAY_SIZE(suspend_enter_pads)]; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 80, + .num_wp = 2, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ +static struct cpu_wp cpu_wp_auto[] = { + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .pdf = 4, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 4, + .cpu_voltage = 850000,}, +}; + +static struct cpu_wp *mx50_rdp_get_cpu_wp(int *wp) +{ + *wp = num_cpu_wp; + return cpu_wp_auto; +} + +static void mx50_rdp_set_num_cpu_wp(int num) +{ + num_cpu_wp = num; + return; +} + +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 1, +}; + +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static u16 keymapping[] = { + KEY_9, KEY_0, KEY_O, KEY_P, KEY_L, KEY_DELETE, KEY_SLASH, KEY_ENTER, + KEY_F4, KEY_F1, KEY_F6, KEY_F9, KEY_F5, KEY_BACKSPACE, KEY_MENU, 0, + KEY_PREVIOUS, KEY_NEXT, KEY_HOME, KEY_NEXT, KEY_F2, KEY_F3, KEY_F8, KEY_F7, + KEY_F11, KEY_CAPSLOCK, KEY_SPACE, KEY_SPACE, KEY_LEFTALT, KEY_LEFTSHIFT, 0, 0, + KEY_COMMA, KEY_M, KEY_N, KEY_B, KEY_V, KEY_C, KEY_X, KEY_Z, + KEY_K, KEY_J, KEY_H, KEY_G, KEY_F, KEY_D, KEY_S, KEY_A, + KEY_I, KEY_U, KEY_Y, KEY_T, KEY_R, KEY_E, KEY_W, KEY_Q, + KEY_8, KEY_7, KEY_6, KEY_5, KEY_4, KEY_3, KEY_2, KEY_1 +}; + +static struct keypad_data keypad_plat_data = { + .rowmax = 8, + .colmax = 8, + .irq = MXC_INT_KPP, + .learning = 0, + .delay = 2, + .matrix = keymapping, +}; + + +/* workaround for cspi chipselect pin may not keep correct level when idle */ +static void mx50_rdp_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + break; + case 2: + break; + case 3: + switch (chipselect) { + case 0x1: + { + struct pad_desc cspi_ss0 = MX50_PAD_CSPI_SS0__CSPI_SS0; + struct pad_desc cspi_cs1 = + MX50_PAD_ECSPI1_MOSI__GPIO_4_13; + + /* pull up/down deassert it */ + mxc_iomux_v3_setup_pad(&cspi_ss0); + mxc_iomux_v3_setup_pad(&cspi_cs1); + + gpio_request(CSPI_CS1, "cspi-cs1"); + gpio_direction_input(CSPI_CS1); + } + break; + case 0x2: + { + struct pad_desc cspi_ss1 = + MX50_PAD_ECSPI1_MOSI__CSPI_SS1; + struct pad_desc cspi_ss0 = MX50_PAD_CSPI_SS0__GPIO_4_11; + + /*disable other ss */ + mxc_iomux_v3_setup_pad(&cspi_ss1); + mxc_iomux_v3_setup_pad(&cspi_ss0); + + /* pull up/down deassert it */ + gpio_request(CSPI_CS2, "cspi-cs2"); + gpio_direction_input(CSPI_CS2); + } + break; + default: + break; + } + break; + + default: + break; + } +} + +static void mx50_rdp_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + break; + case 2: + break; + case 3: + switch (chipselect) { + case 0x1: + gpio_free(CSPI_CS1); + break; + case 0x2: + gpio_free(CSPI_CS2); + break; + default: + break; + } + break; + default: + break; + } + +} + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = mx50_rdp_gpio_spi_chipselect_active, + .chipselect_inactive = mx50_rdp_gpio_spi_chipselect_inactive, +}; + +static struct mxc_spi_master mxcspi3_data = { + .maxchipselect = 4, + .spi_version = 7, + .chipselect_active = mx50_rdp_gpio_spi_chipselect_active, + .chipselect_inactive = mx50_rdp_gpio_spi_chipselect_inactive, +}; + +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +static struct regulator_init_data max17135_init_data[] __initdata = { + { + .constraints = { + .name = "DISPLAY", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, { + .constraints = { + .name = "GVDD", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "GVEE", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINN", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINP", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "VCOM", + .min_uV = mV_to_uV(-4325), + .max_uV = mV_to_uV(-500), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + }, { + .constraints = { + .name = "VNEG", + .min_uV = V_to_uV(-15), + .max_uV = V_to_uV(-15), + }, + }, { + .constraints = { + .name = "VPOS", + .min_uV = V_to_uV(15), + .max_uV = V_to_uV(15), + }, + }, +}; + +/* Fixed voltage regulator DCDC_3V15 */ +static struct regulator_consumer_supply fixed_volt_reg_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +static struct regulator_init_data fixed_volt_reg_init_data = { + .constraints = { + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(fixed_volt_reg_consumers), + .consumer_supplies = fixed_volt_reg_consumers, +}; + +static struct fixed_voltage_config fixed_volt_reg_pdata = { + .supply_name = "DCDC_3V15", + .microvolts = 3150000, + .init_data = &fixed_volt_reg_init_data, + .gpio = -EINVAL, +}; + +static void epdc_get_pins(void) +{ + /* Claim GPIOs for EPDC pins - used during power up/down */ + gpio_request(EPDC_D0, "epdc_d0"); + gpio_request(EPDC_D1, "epdc_d1"); + gpio_request(EPDC_D2, "epdc_d2"); + gpio_request(EPDC_D3, "epdc_d3"); + gpio_request(EPDC_D4, "epdc_d4"); + gpio_request(EPDC_D5, "epdc_d5"); + gpio_request(EPDC_D6, "epdc_d6"); + gpio_request(EPDC_D7, "epdc_d7"); + gpio_request(EPDC_GDCLK, "epdc_gdclk"); + gpio_request(EPDC_GDSP, "epdc_gdsp"); + gpio_request(EPDC_GDOE, "epdc_gdoe"); + gpio_request(EPDC_GDRL, "epdc_gdrl"); + gpio_request(EPDC_SDCLK, "epdc_sdclk"); + gpio_request(EPDC_SDOE, "epdc_sdoe"); + gpio_request(EPDC_SDLE, "epdc_sdle"); + gpio_request(EPDC_SDSHR, "epdc_sdshr"); + gpio_request(EPDC_BDR0, "epdc_bdr0"); + gpio_request(EPDC_SDCE0, "epdc_sdce0"); + gpio_request(EPDC_SDCE1, "epdc_sdce1"); + gpio_request(EPDC_SDCE2, "epdc_sdce2"); +} + +static void epdc_put_pins(void) +{ + gpio_free(EPDC_D0); + gpio_free(EPDC_D1); + gpio_free(EPDC_D2); + gpio_free(EPDC_D3); + gpio_free(EPDC_D4); + gpio_free(EPDC_D5); + gpio_free(EPDC_D6); + gpio_free(EPDC_D7); + gpio_free(EPDC_GDCLK); + gpio_free(EPDC_GDSP); + gpio_free(EPDC_GDOE); + gpio_free(EPDC_GDRL); + gpio_free(EPDC_SDCLK); + gpio_free(EPDC_SDOE); + gpio_free(EPDC_SDLE); + gpio_free(EPDC_SDSHR); + gpio_free(EPDC_BDR0); + gpio_free(EPDC_SDCE0); + gpio_free(EPDC_SDCE1); + gpio_free(EPDC_SDCE2); +} + +static struct pad_desc mx50_epdc_pads_enabled[] = { + MX50_PAD_EPDC_D0__EPDC_D0, + MX50_PAD_EPDC_D1__EPDC_D1, + MX50_PAD_EPDC_D2__EPDC_D2, + MX50_PAD_EPDC_D3__EPDC_D3, + MX50_PAD_EPDC_D4__EPDC_D4, + MX50_PAD_EPDC_D5__EPDC_D5, + MX50_PAD_EPDC_D6__EPDC_D6, + MX50_PAD_EPDC_D7__EPDC_D7, + MX50_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX50_PAD_EPDC_GDSP__EPDC_GDSP, + MX50_PAD_EPDC_GDOE__EPDC_GDOE, + MX50_PAD_EPDC_GDRL__EPDC_GDRL, + MX50_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX50_PAD_EPDC_SDOE__EPDC_SDOE, + MX50_PAD_EPDC_SDLE__EPDC_SDLE, + MX50_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX50_PAD_EPDC_BDR0__EPDC_BDR0, + MX50_PAD_EPDC_SDCE0__EPDC_SDCE0, + MX50_PAD_EPDC_SDCE1__EPDC_SDCE1, + MX50_PAD_EPDC_SDCE2__EPDC_SDCE2, +}; + +static struct pad_desc mx50_epdc_pads_disabled[] = { + MX50_PAD_EPDC_D0__GPIO_3_0, + MX50_PAD_EPDC_D1__GPIO_3_1, + MX50_PAD_EPDC_D2__GPIO_3_2, + MX50_PAD_EPDC_D3__GPIO_3_3, + MX50_PAD_EPDC_D4__GPIO_3_4, + MX50_PAD_EPDC_D5__GPIO_3_5, + MX50_PAD_EPDC_D6__GPIO_3_6, + MX50_PAD_EPDC_D7__GPIO_3_7, + MX50_PAD_EPDC_GDCLK__GPIO_3_16, + MX50_PAD_EPDC_GDSP__GPIO_3_17, + MX50_PAD_EPDC_GDOE__GPIO_3_18, + MX50_PAD_EPDC_GDRL__GPIO_3_19, + MX50_PAD_EPDC_SDCLK__GPIO_3_20, + MX50_PAD_EPDC_SDOE__GPIO_3_23, + MX50_PAD_EPDC_SDLE__GPIO_3_24, + MX50_PAD_EPDC_SDSHR__GPIO_3_26, + MX50_PAD_EPDC_BDR0__GPIO_4_23, + MX50_PAD_EPDC_SDCE0__GPIO_4_25, + MX50_PAD_EPDC_SDCE1__GPIO_4_26, + MX50_PAD_EPDC_SDCE2__GPIO_4_27, +}; + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_enabled, \ + ARRAY_SIZE(mx50_epdc_pads_enabled)); + + gpio_direction_input(EPDC_D0); + gpio_direction_input(EPDC_D1); + gpio_direction_input(EPDC_D2); + gpio_direction_input(EPDC_D3); + gpio_direction_input(EPDC_D4); + gpio_direction_input(EPDC_D5); + gpio_direction_input(EPDC_D6); + gpio_direction_input(EPDC_D7); + gpio_direction_input(EPDC_GDCLK); + gpio_direction_input(EPDC_GDSP); + gpio_direction_input(EPDC_GDOE); + gpio_direction_input(EPDC_GDRL); + gpio_direction_input(EPDC_SDCLK); + gpio_direction_input(EPDC_SDOE); + gpio_direction_input(EPDC_SDLE); + gpio_direction_input(EPDC_SDSHR); + gpio_direction_input(EPDC_BDR0); + gpio_direction_input(EPDC_SDCE0); + gpio_direction_input(EPDC_SDCE1); + gpio_direction_input(EPDC_SDCE2); +} + +static void epdc_disable_pins(void) +{ + /* Configure MUX settings for EPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_disabled, \ + ARRAY_SIZE(mx50_epdc_pads_disabled)); + + gpio_direction_output(EPDC_D0, 0); + gpio_direction_output(EPDC_D1, 0); + gpio_direction_output(EPDC_D2, 0); + gpio_direction_output(EPDC_D3, 0); + gpio_direction_output(EPDC_D4, 0); + gpio_direction_output(EPDC_D5, 0); + gpio_direction_output(EPDC_D6, 0); + gpio_direction_output(EPDC_D7, 0); + gpio_direction_output(EPDC_GDCLK, 0); + gpio_direction_output(EPDC_GDSP, 0); + gpio_direction_output(EPDC_GDOE, 0); + gpio_direction_output(EPDC_GDRL, 0); + gpio_direction_output(EPDC_SDCLK, 0); + gpio_direction_output(EPDC_SDOE, 0); + gpio_direction_output(EPDC_SDLE, 0); + gpio_direction_output(EPDC_SDSHR, 0); + gpio_direction_output(EPDC_BDR0, 0); + gpio_direction_output(EPDC_SDCE0, 0); + gpio_direction_output(EPDC_SDCE1, 0); + gpio_direction_output(EPDC_SDCE2, 0); +} + +static struct fb_videomode e60_v110_mode = { + .name = "E60_V110", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 18604700, + .left_margin = 8, + .right_margin = 178, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e60_v220_mode = { + .name = "E60_V220", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 32000000, + .left_margin = 8, + .right_margin = 166, + .upper_margin = 4, + .lower_margin = 26, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e97_v110_mode = { + .name = "E97_V110", + .refresh = 50, + .xres = 1200, + .yres = 825, + .pixclock = 32000000, + .left_margin = 12, + .right_margin = 128, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct mxc_epdc_fb_mode panel_modes[] = { + { + &e60_v110_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 428, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e60_v220_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 428, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e97_v110_mode, + 8, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 632, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 3, /* num_ce */ + } +}; + +static struct mxc_epdc_fb_platform_data epdc_data = { + .epdc_mode = panel_modes, + .num_modes = ARRAY_SIZE(panel_modes), + .get_pins = epdc_get_pins, + .put_pins = epdc_put_pins, + .enable_pins = epdc_enable_pins, + .disable_pins = epdc_disable_pins, +}; + +static struct platform_device max17135_sensor_device = { + .name = "max17135_sensor", + .id = 0, +}; + +static struct max17135_platform_data max17135_pdata __initdata = { + .vneg_pwrup = 1, + .gvee_pwrup = 1, + .vpos_pwrup = 2, + .gvdd_pwrup = 1, + .gvdd_pwrdn = 1, + .vpos_pwrdn = 2, + .gvee_pwrdn = 1, + .vneg_pwrdn = 1, + .gpio_pmic_pwrgood = EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = EPDC_VCOM, + .gpio_pmic_wakeup = EPDC_PMIC_WAKE, + .gpio_pmic_intr = EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int max17135_regulator_init(struct max17135 *max17135) +{ + struct max17135_platform_data *pdata = &max17135_pdata; + int i, ret; + + max17135->gvee_pwrup = pdata->gvee_pwrup; + max17135->vneg_pwrup = pdata->vneg_pwrup; + max17135->vpos_pwrup = pdata->vpos_pwrup; + max17135->gvdd_pwrup = pdata->gvdd_pwrup; + max17135->gvdd_pwrdn = pdata->gvdd_pwrdn; + max17135->vpos_pwrdn = pdata->vpos_pwrdn; + max17135->vneg_pwrdn = pdata->vneg_pwrdn; + max17135->gvee_pwrdn = pdata->gvee_pwrdn; + + max17135->max_wait = pdata->vpos_pwrup + pdata->vneg_pwrup + + pdata->gvdd_pwrup + pdata->gvee_pwrup; + + max17135->gpio_pmic_pwrgood = pdata->gpio_pmic_pwrgood; + max17135->gpio_pmic_vcom_ctrl = pdata->gpio_pmic_vcom_ctrl; + max17135->gpio_pmic_wakeup = pdata->gpio_pmic_wakeup; + max17135->gpio_pmic_intr = pdata->gpio_pmic_intr; + + max17135->vcom_setup = false; + max17135->init_done = false; + + for (i = 0; i <= MAX17135_VPOS; i++) { + ret = max17135_register_regulator(max17135, i, + &pdata->regulator_init[i]); + if (ret != 0) { + printk(KERN_ERR"max17135 regulator init failed: %d\n", + ret); + return ret; + } + } + + regulator_has_full_constraints(); + + return 0; +} + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, + { + .type = "mma8450", + .addr = 0x1c, + }, + { + .type = "eeprom", + .addr = 0x50, + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 3, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0],}, +}; + +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(SD1_WP); + else if (to_platform_device(dev)->id == 1) + rc = gpio_get_value(SD2_WP); + else if (to_platform_device(dev)->id == 2) + rc = 0; + + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret = 0; + if (to_platform_device(dev)->id == 0) + ret = gpio_get_value(SD1_CD); + else if (to_platform_device(dev)->id == 1) + ret = gpio_get_value(SD2_CD); + else if (to_platform_device(dev)->id == 2) + ret = 1; + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +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 | MMC_CAP_8_BIT_DATA, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = "VSD" +}; + +static struct mxc_mmc_platform_data mmc3_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 | MMC_CAP_8_BIT_DATA, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static int mxc_sgtl5000_amp_enable(int enable) +{ + gpio_set_value(SGTL_AMP_SHDN, !enable); + return 0; +} + +static int mxc_sgtl5000_clock_enable(int enable) +{ + gpio_set_value(SGTL_OSCEN, enable); + return 0; +} + +static int headphone_det_status(void) +{ + return (gpio_get_value(HP_DETECT) == 0); +} + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_irq = IOMUX_TO_IRQ_V3(HP_DETECT), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .clock_enable = mxc_sgtl5000_clock_enable, + .sysclk = 12288000, +}; + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static struct pad_desc rdp_wvga_pads[] = { + MX50_PAD_DISP_D0__DISP_D0, + MX50_PAD_DISP_D1__DISP_D1, + MX50_PAD_DISP_D2__DISP_D2, + MX50_PAD_DISP_D3__DISP_D3, + MX50_PAD_DISP_D4__DISP_D4, + MX50_PAD_DISP_D5__DISP_D5, + MX50_PAD_DISP_D6__DISP_D6, + MX50_PAD_DISP_D7__DISP_D7, + MX50_PAD_EIM_DA0__GPIO_1_0, + MX50_PAD_EIM_DA1__GPIO_1_1, + MX50_PAD_EIM_DA2__GPIO_1_2, + MX50_PAD_EIM_DA3__GPIO_1_3, + MX50_PAD_EIM_DA4__GPIO_1_4, + MX50_PAD_EIM_DA5__GPIO_1_5, + MX50_PAD_EIM_DA6__GPIO_1_6, + MX50_PAD_EIM_DA7__GPIO_1_7, +}; + +static void wvga_reset(void) +{ + mxc_iomux_v3_setup_multiple_pads(rdp_wvga_pads, \ + ARRAY_SIZE(rdp_wvga_pads)); + + gpio_direction_output(FEC_EN, 1); + + gpio_request(ELCDIF_DAT0_DUMMY, "elcdif-data0"); + gpio_direction_output(ELCDIF_DAT0_DUMMY, 0); + gpio_request(ELCDIF_DAT1_DUMMY, "elcdif-data1"); + gpio_direction_output(ELCDIF_DAT1_DUMMY, 0); + gpio_request(ELCDIF_DAT2_DUMMY, "elcdif-data2"); + gpio_direction_output(ELCDIF_DAT2_DUMMY, 0); + gpio_request(ELCDIF_DAT8_DUMMY, "elcdif-data8"); + gpio_direction_output(ELCDIF_DAT8_DUMMY, 0); + gpio_request(ELCDIF_DAT9_DUMMY, "elcdif-data9"); + gpio_direction_output(ELCDIF_DAT9_DUMMY, 0); + gpio_request(ELCDIF_DAT16_DUMMY, "elcdif-data16"); + gpio_direction_output(ELCDIF_DAT16_DUMMY, 0); + gpio_request(ELCDIF_DAT17_DUMMY, "elcdif-data17"); + gpio_direction_output(ELCDIF_DAT17_DUMMY, 0); + + return; +} + +static struct mxc_lcd_platform_data lcd_wvga_data = { + .reset = wvga_reset, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_seiko", + .dev = { + .platform_data = &lcd_wvga_data, + }, +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ + "SEIKO-WVGA", 60, 800, 480, 29850, 99, 164, 33, 10, 10, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB565, + .mode_str = "SEIKO-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 2000000, +}; + +static void mx50_arm2_usb_set_vbus(bool enable) +{ + gpio_set_value(USB_OTG_PWR, enable); +} + +static void mxc_register_powerkey(pwrkey_callback pk_cb) +{ + pmic_event_callback_t power_key_event; + + power_key_event.param = (void *)1; + power_key_event.func = (void *)pk_cb; + pmic_event_subscribe(EVENT_PWRONI, power_key_event); + power_key_event.param = (void *)3; + pmic_event_subscribe(EVENT_PWRON3I, power_key_event); +} + +static int mxc_pwrkey_getstatus(int id) +{ + int sense, off = 3; + + pmic_read_reg(REG_INT_SENSE1, &sense, 0xffffffff); + switch (id) { + case 2: + off = 4; + break; + case 3: + off = 2; + break; + } + + if (sense & (1 << off)) + return 0; + + return 1; +} + +static struct power_key_platform_data pwrkey_data = { + .key_value = KEY_F4, + .register_pwrkey = mxc_register_powerkey, + .get_key_status = mxc_pwrkey_getstatus, +}; + + +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx50(); +} + +__setup("w1", w1_setup); + +static int __initdata enable_keypad = {0}; +static int __init keypad_setup(char *__unused) +{ + enable_keypad = 1; + return cpu_is_mx50(); +} + +__setup("keypad", keypad_setup); + +static struct mxs_dma_plat_data dma_apbh_data = { + .chan_base = MXS_DMA_CHANNEL_AHB_APBH, + .chan_num = MXS_MAX_DMA_CHANNELS, +}; + +static int gpmi_nfc_platform_init(unsigned int max_chip_count) +{ + mxc_iomux_v3_setup_multiple_pads(mx50_gpmi_nand, + ARRAY_SIZE(mx50_gpmi_nand)); + + return 0; +} + +static void gpmi_nfc_platform_exit(unsigned int max_chip_count) +{ +} + +static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 }; + +static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = { + .nfc_version = 2, + .boot_rom_version = 1, + .clock_name = "gpmi-nfc", + .platform_init = gpmi_nfc_platform_init, + .platform_exit = gpmi_nfc_platform_exit, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 2, + .boot_area_size_in_bytes = 20 * SZ_1M, + .partition_source_types = gpmi_nfc_partition_source_types, + .partitions = 0, + .partition_count = 0, +}; + +static void fec_gpio_iomux_init() +{ + struct pad_desc iomux_setting = + MX50_PAD_I2C3_SDA__GPIO_6_23; + + /* Enable the Pull/keeper */ + iomux_setting.pad_ctrl = 0x84; + mxc_iomux_v3_setup_pad(&iomux_setting); + gpio_request(FEC_EN, "fec-en"); + gpio_direction_output(FEC_EN, 0); + gpio_request(FEC_RESET_B, "fec-reset_b"); + gpio_direction_output(FEC_RESET_B, 0); + udelay(500); + gpio_set_value(FEC_RESET_B, 1); +} + +static void fec_gpio_iomux_deinit() +{ + struct pad_desc iomux_setting = + MX50_PAD_I2C3_SDA__GPIO_6_23; + + /* Disable the Pull/keeper */ + iomux_setting.pad_ctrl = 0xE4; + mxc_iomux_v3_setup_pad(&iomux_setting); + gpio_request(FEC_EN, "fec-en"); + gpio_direction_input(FEC_EN); + gpio_request(FEC_RESET_B, "fec-reset_b"); + gpio_direction_input(FEC_RESET_B); +} + +static void mx50_suspend_enter() +{ + struct pad_desc *p = suspend_enter_pads; + int i; + /* Set PADCTRL to 0 for all IOMUX. */ + for (i = 0; i < ARRAY_SIZE(suspend_enter_pads); i++) { + suspend_exit_pads[i] = *p; + p->pad_ctrl = 0; + p++; + } + mxc_iomux_v3_get_multiple_pads(suspend_exit_pads, + ARRAY_SIZE(suspend_exit_pads)); + mxc_iomux_v3_setup_multiple_pads( + suspend_enter_pads, + ARRAY_SIZE(suspend_enter_pads)); + + fec_gpio_iomux_deinit(); +} + +static void mx50_suspend_exit() +{ + mxc_iomux_v3_setup_multiple_pads( + suspend_exit_pads, + ARRAY_SIZE(suspend_exit_pads)); + fec_gpio_iomux_init(); +} + +static struct mxc_pm_platform_data mx50_pm_data = { + .suspend_enter = mx50_suspend_enter, + .suspend_exit = mx50_suspend_exit, +}; + +/*! + * 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_set_cpu_type(MXC_CPU_MX50); + + get_cpu_wp = mx50_rdp_get_cpu_wp; + set_num_cpu_wp = mx50_rdp_set_num_cpu_wp; +} + +static void __init mx50_rdp_io_init(void) +{ + struct pad_desc cspi_keeper = MX50_PAD_ECSPI1_SCLK__GPIO_4_12; + struct pad_desc *p = mx50_rdp; + int i; + + /* Set PADCTRL to 0 for all IOMUX. */ + for (i = 0; i < ARRAY_SIZE(mx50_rdp); i++) { + int pad_ctl = p->pad_ctrl; + p->pad_ctrl = 0; + mxc_iomux_v3_setup_pad(p); + p->pad_ctrl = pad_ctl; + p++; + } + + mxc_iomux_v3_setup_multiple_pads(mx50_rdp, \ + ARRAY_SIZE(mx50_rdp)); + + gpio_request(SD1_WP, "sdhc1-wp"); + gpio_direction_input(SD1_WP); + + gpio_request(SD1_CD, "sdhc1-cd"); + gpio_direction_input(SD1_CD); + + gpio_request(SD2_WP, "sdhc2-wp"); + gpio_direction_input(SD2_WP); + + gpio_request(SD2_CD, "sdhc2-cd"); + gpio_direction_input(SD2_CD); + + gpio_request(HP_DETECT, "hp-det"); + gpio_direction_input(HP_DETECT); + + gpio_request(PWR_INT, "pwr-int"); + gpio_direction_input(PWR_INT); + + gpio_request(EPDC_PMIC_WAKE, "epdc-pmic-wake"); + gpio_direction_output(EPDC_PMIC_WAKE, 0); + + gpio_request(EPDC_VCOM, "epdc-vcom"); + gpio_direction_output(EPDC_VCOM, 0); + + gpio_request(EPDC_PMIC_INT, "epdc-pmic-int"); + gpio_direction_input(EPDC_PMIC_INT); + + gpio_request(EPDC_PWRSTAT, "epdc-pwrstat"); + gpio_direction_input(EPDC_PWRSTAT); + + gpio_request(ELCDIF_PWR_ON, "elcdif-power-on"); + gpio_direction_output(ELCDIF_PWR_ON, 1); + + if (enable_w1) { + struct pad_desc one_wire = MX50_PAD_OWIRE__OWIRE; + mxc_iomux_v3_setup_pad(&one_wire); + } + + /* SGTL5000_OSC_EN */ + gpio_request(SGTL_OSCEN, "sgtl5000-osc-en"); + gpio_direction_output(SGTL_OSCEN, 1); + + gpio_request(SGTL_AMP_SHDN, "sgtl5000-amp-shdn"); + gpio_direction_output(SGTL_AMP_SHDN, 1); + + fec_gpio_iomux_init(); + + /* USB OTG PWR */ + gpio_request(USB_OTG_PWR, "usb otg power"); + gpio_direction_output(USB_OTG_PWR, 0); + + cspi_keeper.pad_ctrl = 0x0; /* Disable all keepers */ + mxc_iomux_v3_setup_pad(&cspi_keeper); +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + /* SD card detect irqs */ + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(SD1_CD); + mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(SD2_CD); + mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(SD2_CD); + + mxc_cpu_common_init(); + mx50_rdp_io_init(); + + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxcspi3_device, &mxcspi3_data); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxs_dma_apbh_device, &dma_apbh_data); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_devices[2], &mxci2c_data); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxc_pxp_device, NULL); + mxc_register_device(&mxc_pxp_client_device, NULL); + mxc_register_device(&mxc_pxp_v4l2, NULL); + mxc_register_device(&busfreq_device, &bus_freq_data); + mxc_register_device(&pm_device, &mx50_pm_data); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + + if (enable_keypad) + mxc_register_device(&mxc_keypad_device, &keypad_plat_data); + + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&mxc_fec_device, &fec_data); + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); + 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)); + + mxc_register_device(&max17135_sensor_device, NULL); + mxc_register_device(&epdc_device, &epdc_data); + mxc_register_device(&lcd_wvga_device, &lcd_wvga_data); + mxc_register_device(&elcdif_device, &fb_data[0]); + mxc_register_device(&mxc_pwm1_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, + &mxc_pwm_backlight_data); + mxc_register_device(&mxs_viim, NULL); + mxc_register_device(&mxc_rngb_device, NULL); + mxc_register_device(&dcp_device, NULL); + mxc_register_device(&mxc_powerkey_device, &pwrkey_data); + mxc_register_device(&fixed_volt_reg_device, &fixed_volt_reg_pdata); + if (cpu_is_mx50_rev(CHIP_REV_1_1) >= 1) + mxc_register_device(&mxc_zq_calib_device, NULL); + mx50_rdp_init_mc13892(); +/* + pm_power_off = mxc_power_off; + */ + mx5_set_otghost_vbus_func(mx50_arm2_usb_set_vbus); + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mxc_register_device(&gpmi_nfc_device, &gpmi_nfc_platform_data); + mx5_usb_dr_init(); + mx5_usbh1_init(); + mxc_register_device(&mxc_perfmon, &mxc_perfmon_data); +} + +static void __init mx50_rdp_timer_init(void) +{ + struct clk *uart_clk; + + mx50_clocks_init(32768, 24000000, 22579200); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx50_rdp_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX50_RDP data structure. + */ +MACHINE_START(MX50_RDP, "Freescale MX50 Reference Design Platform") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c b/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c new file mode 100644 index 000000000000..883108a2b53a --- /dev/null +++ b/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892/core.h> +#include <mach/irqs.h> + +#include <mach/iomux-mx50.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* regulator standby mask */ +#define GEN1_STBY_MASK (1 << 1) +#define IOHI_STBY_MASK (1 << 4) +#define DIG_STBY_MASK (1 << 10) +#define GEN2_STBY_MASK (1 << 13) +#define PLL_STBY_MASK (1 << 16) +#define USB2_STBY_MASK (1 << 19) + +#define GEN3_STBY_MASK (1 << 1) +#define CAM_STBY_MASK (1 << 7) +#define VIDEO_STBY_MASK (1 << 13) +#define AUDIO_STBY_MASK (1 << 16) +#define SD_STBY_MASK (1 << 19) + +#define REG_MODE_0_ALL_MASK (DIG_STBY_MASK | GEN1_STBY_MASK\ + | PLL_STBY_MASK | IOHI_STBY_MASK) +#define REG_MODE_1_ALL_MASK (CAM_STBY_MASK | VIDEO_STBY_MASK |\ + AUDIO_STBY_MASK | SD_STBY_MASK | GEN3_STBY_MASK) + +/* switch mode setting */ +#define SW1MODE_LSB 0 +#define SW2MODE_LSB 10 +#define SW3MODE_LSB 0 +#define SW4MODE_LSB 8 + +#define SWMODE_MASK 0xF +#define SWMODE_AUTO 0x8 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_consumer_supply sw4_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDA", + .dev_name = "1-000a", + }, +}; + +static struct regulator_consumer_supply vgen1_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1200), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + }, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2775), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(3000), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static int mc13892_regulator_init(struct mc13892 *mc13892) +{ + unsigned int value, register_mask; + printk("Initializing regulators for mx50 rdp.\n"); + + /* enable standby controll for all regulators */ + pmic_read_reg(REG_MODE_0, &value, 0xffffff); + value |= REG_MODE_0_ALL_MASK; + pmic_write_reg(REG_MODE_0, value, 0xffffff); + + pmic_read_reg(REG_MODE_1, &value, 0xffffff); + value |= REG_MODE_1_ALL_MASK; + pmic_write_reg(REG_MODE_1, value, 0xffffff); + + /* enable switch audo mode */ + pmic_read_reg(REG_IDENTIFICATION, &value, 0xffffff); + /* only for mc13892 2.0A */ + if ((value & 0x0000FFFF) == 0x45d0) { + pmic_read_reg(REG_SW_4, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW1MODE_LSB) | + (SWMODE_MASK << SW2MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW1MODE_LSB) | + (SWMODE_AUTO << SW2MODE_LSB); + pmic_write_reg(REG_SW_4, value, 0xffffff); + + pmic_read_reg(REG_SW_5, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW3MODE_LSB) | + (SWMODE_MASK << SW4MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW3MODE_LSB) | + (SWMODE_AUTO << SW4MODE_LSB); + pmic_write_reg(REG_SW_5, value, 0xffffff); + } + /* Enable coin cell charger */ + value = BITFVAL(COINCHEN, 1) | BITFVAL(VCOIN, VCOIN_3_0V); + register_mask = BITFMASK(COINCHEN) | BITFMASK(VCOIN); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); + +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) + value = BITFVAL(DRM, 1); + register_mask = BITFMASK(DRM); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); +#endif + + mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init); + mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init); + mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init); + mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init); + mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init); + mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init); + mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init); + mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init); + mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init); + mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init); + mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init); + mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init); + mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init); + mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init); + mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init); + mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init); + mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init); + mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init); + mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init); + mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init); + mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init); + + regulator_has_full_constraints(); + + return 0; +} + +static struct mc13892_platform_data mc13892_plat = { + .init = mc13892_regulator_init, +}; + +static struct spi_board_info __initdata mc13892_spi_device = { + .modalias = "pmic_spi", + .irq = IOMUX_TO_IRQ_V3(114), + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ + .bus_num = 3, + .chip_select = 0, + .platform_data = &mc13892_plat, +}; + + +int __init mx50_rdp_init_mc13892(void) +{ + return spi_register_board_info(&mc13892_spi_device, 1); +} diff --git a/arch/arm/mach-mx5/mx50_suspend.S b/arch/arm/mach-mx5/mx50_suspend.S new file mode 100644 index 000000000000..4d9e1b49a23d --- /dev/null +++ b/arch/arm/mach-mx5/mx50_suspend.S @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_CTRL_ICACHE 1 << 12 +#define ARM_AUXCR_L2EN 1 << 1 + +/* + * mx50_suspend + * + * Suspend the processor (eg, wait for interrupt). + * Set the DDR into Self Refresh + * IRQs are already disabled. + */ +ENTRY(mx50_suspend) + stmfd sp!, {r4,r5,r6,r7,r8, r9,r10,r11} @ Save registers + + mov r6, r0 @save databahn address + +/* Before putting DDR into self-refresh, make sure + any LPM mode that the DDR might be in is exited. +*/ + /* If Databahn is in LPM4, exit that mode first. */ + ldr r8,[r6, #0x50] @Store LPM mode in r8 + mov r0, r8 + bic r0, r0, #0x1F + str r0,[r6, #0x50] + + + /* Disable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + bic r0, r0, #ARM_CTRL_ICACHE @ Disable ICache + bic r0, r0, #ARM_CTRL_DCACHE @ Disable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedClean + mov r10, #0 +Loop1Clean: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type + @ for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipClean @ No cache or only instruction cache + @ at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset + @ (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the + @ way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way + @ size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index + @ size (right aligned) +Loop2Clean: + mov r9, r4 @ R9 working copy of the max way size + @ (right aligned) +Loop3Clean: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache + @ number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c14, 2 @ Clean and invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Clean + subs r7, r7, #1 @ Decrement the index + bge Loop2Clean +SkipClean: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Clean + +FinishedClean: + + /* Disable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + bic r0, r0, #ARM_AUXCR_L2EN @ Disable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + +/* Wait for the databahn to idle + Meaning, no access to the databahn is + being made. +*/ +EnterWFI: + ldr r0,[r6, #0x13c] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + beq EnterWFI + + /* Enter self-refresh mode */ + ldr r0,[r6, #0x4c] + orr r0,r0,#0x1 + str r0,[r6, #0x4c] + +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r6, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Stop controller */ + ldr r0,[r6] + bic r0, r0, #0x1 + str r0,[r6] + + .long 0xe320f003 @ Opcode for WFI + + /* Start controller */ + ldr r0,[r6] + orr r0,r0,#0x1 + str r0,[r6] + +LoopPHY: + /* Wait for PHY ready */ + ldr r0,[r6, #0x264] + and r0, r0, #0xfffffffe + ldr r2, =0x0 + cmp r0, r2 + beq LoopPHY + + /*Leave self-refresh mode */ + ldr r0,[r6, #0x4c] + and r0,r0,#0xfffffffe + str r0,[r6, #0x4c] + +LoopCKE1: + /*Wait for CKE = 1 */ + ldr r0,[r6, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE1 + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Invalidate inst cache + +/* Invalidate data caches */ + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedInvalidate + mov r10, #0 +Loop1Invalidate: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache + @ Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipInvalidate @ No cache or only instruction cache + @at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset + @(log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way + @size (right aligned) + clz r5, r4 @ R5 is the bit position of the way + @ size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the + @ index size (right aligned) +Loop2Invalidate: + mov r9, r4 @ R9 working copy of the max way + @ size (right aligned) +Loop3Invalidate: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache + @ number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c6, 2 @ Invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Invalidate + subs r7, r7, #1 @ Decrement the index + bge Loop2Invalidate +SkipInvalidate: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Invalidate + +FinishedInvalidate: + + /* Enable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + orr r0, r0, #ARM_AUXCR_L2EN @ Enable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + + /* Enable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + orr r0, r0, #ARM_CTRL_ICACHE @ Enable ICache + orr r0, r0, #ARM_CTRL_DCACHE @ Enable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + /* restore LPM mode. */ + str r8, [r6, #0x50] + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11} + mov pc, lr + + .type mx50_do_suspend, #object +ENTRY(mx50_do_suspend) + .word mx50_suspend + .size mx50_suspend, . - mx50_suspend diff --git a/arch/arm/mach-mx5/mx50_wfi.S b/arch/arm/mach-mx5/mx50_wfi.S new file mode 100644 index 000000000000..3335b0f320a4 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_wfi.S @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +/* + * mx50_wait + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx50_wait) + stmfd sp!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} @ Save registers + + mov r6, r0 @save CCM address + mov r5, r1 @save DataBahn address + + /* + * Make sure the DDR is self-refresh, before setting the clock bits. + */ + + /* Step 2: Poll the CKE_STATUS bit. */ +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Check if Databahn is in SYNC or ASYNC mode. */ + ldr r4, [r5, #0xdc] + and r4, r4, #0x30000 + cmp r4, #0x30000 + beq Sync_mode + + /* Set the DDR_CLKGATE to 0x1. */ + ldr r0, [r6, #0x98] + bic r0, r0, #0x80000000 + str r0, [r6, #0x98] + + .long 0xe320f003 @ Opcode for WFI + + /* Set the DDR_CLKGATE to 0x3. */ + ldr r0, [r6, #0x98] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x98] + b Wfi_Done + +Sync_mode: + /* Check if PLL1 is sourcing SYS_CLK. */ + ldr r5, [r6, #0x90] + and r5, r0, #0x1 + cmp r5, #0x1 + beq pll1_source + + /* Set the SYS_XTAL_CLKGATE to 0x1. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x80000000 + str r0, [r6, #0x94] + + /* Set the SYS_XTAL_DIV to 0xF (1.6MHz) to reduce power. + * since this clock is not gated when ARM is in WFI. + */ + + ldr r0, [r6, #0x94] + orr r0, r0, #0x3c0 + str r0, [r6, #0x94] + + b do_wfi +pll1_source: + /* Set the SYS_PLL_CLKGATE to 0x1. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x40000000 + str r0, [r6, #0x94] + +do_wfi: + .long 0xe320f003 @ Opcode for WFI + + cmp r5, #1 + beq pll1_source1 + /* Set the SYS_XTAL_DIV to 24MHz.*/ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3c0 + orr r0, r0, #0x40 + str r0, [r6, #0x94] + + /* Set the SYS_XTAL_CLKGATE to 0x3. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x94] + b Wfi_Done + +pll1_source1: + /* Set the SYS_PLL_CLKGATE to 0x3. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0x30000000 + str r0, [r6, #0x94] + +Wfi_Done: + /* Restore registers */ + ldmfd sp!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} + mov pc, lr + + .type mx50_do_wait, #object +ENTRY(mx50_do_wait) + .word mx50_wait + .size mx50_wait, . - mx50_wait diff --git a/arch/arm/mach-mx5/mx51_3stack.c b/arch/arm/mach-mx5/mx51_3stack.c new file mode 100644 index 000000000000..3188cc77bf45 --- /dev/null +++ b/arch/arm/mach-mx5/mx51_3stack.c @@ -0,0 +1,1078 @@ +/* + * Copyright (C) 2008-2011 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/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/ata.h> +#include <linux/pmic_external.h> +#include <linux/ipu.h> +#include <linux/pwm_backlight.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 <linux/regulator/consumer.h> +#include <mach/hardware.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/keypad.h> +#include <mach/common.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/i2c.h> + +#include "devices.h" +#include "iomux.h" +#include "mx51_pins.h" +#include "crm_regs.h" +#include "usb.h" + +/*! + * @file mach-mx51/mx51_3stack.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX51 + */ +#define DEBUG_BOARD_BASE_ADDRESS(n) (n) +/* LAN9217 ethernet base address */ +#define LAN9217_BASE_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n)) + +#define BOARD_IO_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n) + 0x20000) +/* LED switchs */ +#define LED_SWITCH_REG 0x00 +/* buttons */ +#define SWITCH_BUTTONS_REG 0x08 +/* status, interrupt */ +#define INTR_STATUS_REG 0x10 +#define INTR_MASK_REG 0x38 +#define INTR_RESET_REG 0x20 +/* magic word for debug CPLD */ +#define MAGIC_NUMBER1_REG 0x40 +#define MAGIC_NUMBER2_REG 0x48 +/* CPLD code version */ +#define CPLD_CODE_VER_REG 0x50 +/* magic word for debug CPLD */ +#define MAGIC_NUMBER3_REG 0x58 +/* module reset register*/ +#define MODULE_RESET_REG 0x60 +/* CPU ID and Personality ID */ +#define MCU_BOARD_ID_REG 0x68 + +/* interrupts like external uart , external ethernet etc*/ +#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX51_PIN_GPIO1_6) + +#define EXPIO_INT_ENET (MXC_BOARD_IRQ_START + 0) +#define EXPIO_INT_XUART_A (MXC_BOARD_IRQ_START + 1) +#define EXPIO_INT_XUART_B (MXC_BOARD_IRQ_START + 2) +#define EXPIO_INT_BUTTON_A (MXC_BOARD_IRQ_START + 3) +#define EXPIO_INT_BUTTON_B (MXC_BOARD_IRQ_START + 4) + +#define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_BOARD_IRQ_START) + +/*! This is System IRQ used by LAN9217 */ +#define LAN9217_IRQ EXPIO_INT_ENET + +extern int __init mx51_3stack_init_mc13892(void); +extern void __init mx51_3stack_io_init(void); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); +static int num_cpu_wp = 3; +static bool debug_board_present; + +/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ +static struct cpu_wp cpu_wp_auto[] = { + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1175000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1100000,}, + { + .pll_rate = 800000000, + .cpu_rate = 166250000, + .pdf = 4, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 4, + .cpu_voltage = 850000,}, +}; + +struct cpu_wp *mx51_3stack_get_cpu_wp(int *wp) +{ + *wp = num_cpu_wp; + return cpu_wp_auto; +} + +void mx51_3stack_set_num_cpu_wp(int num) +{ + num_cpu_wp = num; + return; +} + +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 1, +}; + +static u16 keymapping[24] = { + KEY_1, KEY_2, KEY_3, KEY_F1, KEY_UP, KEY_F2, + KEY_4, KEY_5, KEY_6, KEY_LEFT, KEY_SELECT, KEY_RIGHT, + KEY_7, KEY_8, KEY_9, KEY_F3, KEY_DOWN, KEY_F4, + KEY_0, KEY_OK, KEY_ESC, KEY_ENTER, KEY_MENU, KEY_BACK, +}; + +static struct keypad_data keypad_plat_data = { + .rowmax = 4, + .colmax = 6, + .learning = 0, + .delay = 2, + .matrix = keymapping, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 78770, +}; + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 2, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx51_3ds_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + u32 gpio; + + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_CSPI1_SS0, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + break; + case 0x2: + gpio = IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + gpio_request(gpio, "cspi1_ss0"); + gpio_direction_output(gpio, 0); + gpio_set_value(gpio, 1 & (~status)); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx51_3ds_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + case 0x2: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = mx51_3ds_gpio_spi_chipselect_active, + .chipselect_inactive = mx51_3ds_gpio_spi_chipselect_inactive, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct mxc_i2c_platform_data mxci2c_hs_data = { + .i2c_clk = 400000, +}; + +static struct tve_platform_data tve_data = { + .dac_reg = "VVIDEO", + .dig_reg = "VDIG", +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, + .num_wp = 3, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +static struct mxc_dvfsper_data dvfs_per_data = { + .reg_id = "SW2", + .clk_id = "gpc_dvfs_clk", + .gpc_cntr_reg_addr = MXC_GPC_CNTR, + .gpc_vcr_reg_addr = MXC_GPC_VCR, + .gpc_adu = 0x0, + .vai_mask = MXC_DVFSPMCR0_FSVAI_MASK, + .vai_offset = MXC_DVFSPMCR0_FSVAI_OFFSET, + .dvfs_enable_bit = MXC_DVFSPMCR0_DVFEN, + .irq_mask = MXC_DVFSPMCR0_FSVAIM, + .div3_offset = 0, + .div3_mask = 0x7, + .div3_div = 2, + .lp_high = 1250000, + .lp_low = 1250000, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* spdif_ext_clk source for 44.1KHz */ + .spdif_clk_48000 = 7, /* audio osc source */ + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + + +/* NAND Flash Partitions */ +#ifdef CONFIG_MTD_PARTITIONS + +static struct mtd_partition nand_flash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 3 * 1024 * 1024}, + { + .name = "nand.kernel", + .offset = MTDPART_OFS_APPEND, + .size = 5 * 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 = MTDPART_SIZ_FULL}, +}; + +#endif + +extern void gpio_nand_active(void); +extern void gpio_nand_inactive(void); + +static int nand_init(void) +{ + /* Configure the pins */ + gpio_nand_active(); + return 0; +} + +static void nand_exit(void) +{ + /* Free the pins */ + gpio_nand_inactive(); +} + +static struct flash_platform_data mxc_nand_data = { + #ifdef CONFIG_MTD_PARTITIONS + .parts = nand_flash_partitions, + .nr_parts = ARRAY_SIZE(nand_flash_partitions), + #endif + .width = 1, + .init = nand_init, + .exit = nand_exit, +}; + +/* i.MX MTD NAND Flash Controller */ + +#if defined(CONFIG_MTD_NAND_IMX_NFC) || defined(CONFIG_MTD_NAND_IMX_NFC_MODULE) + +/* + * Platform-specific information about this device. Some of the details depend + * on the SoC. See imx_init_nfc() below for code that fills in the rest. + */ + +static struct imx_nfc_platform_data imx_nfc_platform_data = { + .nfc_major_version = 3, + .nfc_minor_version = 2, + .force_ce = false, + .target_cycle_in_ns = 30, + .clock_name = "nfc_clk", + .set_page_size = 0, + .interleave = false, + #ifdef CONFIG_MTD_PARTITIONS + .partitions = nand_flash_partitions, + .partition_count = ARRAY_SIZE(nand_flash_partitions), + #endif +}; + +#endif /* i.MX MTD NAND Flash Controller */ + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + }, + { + .interface_pix_fmt = IPU_PIX_FMT_YUV444, + }, +}; + +static void lcd_reset_to2(void) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 0); + ipu_reset_disp_panel(); + + return; +} + +static void lcd_reset(void) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), 0); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), "ser_rs"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), 0); + /* do reset */ + msleep(10); /* tRES >= 100us */ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), 1); + msleep(60); +} + +static struct mxc_lcd_platform_data lcd_data = { + .core_reg = "VIOHI", + .io_reg = "SW4", + .reset = lcd_reset, +}; + +static struct platform_device mxc_lcd_device = { + .name = "lcd_spi", +}; + +static void wvga_reset(void) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 1); +} + +static struct mxc_lcd_platform_data lcd_wvga_data = { + .reset = wvga_reset, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_claa", +}; + +static struct platform_device mxcbl_device = { + .name = "mxc_mc13892_bl", +}; + +static void si4702_reset(void) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_DTACK), 0); + msleep(100); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_DTACK), 1); + msleep(100); +} + +static void si4702_clock_ctl(int flag) +{ +} + +static void si4702_gpio_get(void) +{ + /* reset pin */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_DTACK), "eim_dtack"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_DTACK), 0); +} + +static void si4702_gpio_put(void) +{ +} + +static struct mxc_fm_platform_data si4702_data = { + .reg_vio = "SW4", + .reg_vdd = "VIOHI", + .gpio_get = si4702_gpio_get, + .gpio_put = si4702_gpio_put, + .reset = si4702_reset, + .clock_ctl = si4702_clock_ctl, + .sksnr = 0, + .skcnt = 0, + .band = 0, + .space = 100, + .seekth = 0xa, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "wm8903-i2c", + .addr = 0x1a, + }, + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "tsc2007", + .addr = 0x48, + .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_5), + }, + { + .type = "si4702", + .addr = 0x10, + .platform_data = (void *)&si4702_data, + }, +}; + +static struct mxc_camera_platform_data camera_data = { + .io_regulator = "SW4", + .analog_regulator = "VIOHI", + .mclk = 24000000, + .csi = 0, +}; +static struct mxc_lightsensor_platform_data ls_data = { + .vdd_reg = NULL, + .rext = 100, +}; + +static struct i2c_board_info mxc_i2c_hs_board_info[] __initdata = { + { + .type = "ov3640", + .addr = 0x3C, + .platform_data = (void *)&camera_data, + }, + { + .type = "isl29003", + .addr = 0x44, + .platform_data = &ls_data, + }, +}; + +static struct resource smsc911x_resources[] = { + { + .start = CS5_BASE_ADDR, + .end = CS5_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = LAN9217_IRQ, + .end = LAN9217_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY, +}; + +static struct platform_device smsc_lan9217_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, +}; + +static struct mxc_sim_platform_data sim_data = { + .clk_rate = 4000000, + .clock_sim = "sim_clk", + .power_sim = NULL, + .init = NULL, + .exit = NULL, + .detect = 0, +}; + +/*! + * Get WP pin value to detect write protection + */ +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_1)); + else + rc = 0; + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret; + + if (to_platform_device(dev)->id == 0) { + ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0)); + return ret; + } else { /* config the det pin for SDHC2 */ + return 0; + } +} + +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", + .power_mmc = NULL, +}; +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 u32 brd_io; +static void expio_ack_irq(u32 irq); + +static void mxc_expio_irq_handler(u32 irq, struct irq_desc *desc) +{ + u32 imr_val; + u32 int_valid; + u32 expio_irq; + + desc->chip->mask(irq); /* irq = gpio irq number */ + + imr_val = __raw_readw(brd_io + INTR_MASK_REG); + int_valid = __raw_readw(brd_io + INTR_STATUS_REG) & ~imr_val; + + if (unlikely(!int_valid)) + goto out; + + expio_irq = MXC_BOARD_IRQ_START; + for (; int_valid != 0; int_valid >>= 1, expio_irq++) { + struct irq_desc *d; + if ((int_valid & 1) == 0) + continue; + 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); + } + + out: + 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) +{ + u16 reg; + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* mask the interrupt */ + reg = __raw_readw(brd_io + INTR_MASK_REG); + reg |= (1 << expio); + __raw_writew(reg, brd_io + INTR_MASK_REG); +} + +/* + * 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) +{ + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* clear the interrupt status */ + __raw_writew(1 << expio, brd_io + INTR_RESET_REG); + __raw_writew(0, brd_io + INTR_RESET_REG); + /* mask the interrupt */ + expio_mask_irq(irq); +} + +/* + * 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) +{ + u16 reg; + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* unmask the interrupt */ + reg = __raw_readw(brd_io + INTR_MASK_REG); + reg &= ~(1 << expio); + __raw_writew(reg, brd_io + INTR_MASK_REG); +} + +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; + + brd_io = (u32) ioremap(BOARD_IO_ADDR(CS5_BASE_ADDR), SZ_4K); + if (brd_io == 0) + return -ENOMEM; + + if ((__raw_readw(brd_io + MAGIC_NUMBER1_REG) != 0xAAAA) || + (__raw_readw(brd_io + MAGIC_NUMBER2_REG) != 0x5555) || + (__raw_readw(brd_io + MAGIC_NUMBER3_REG) != 0xCAFE)) { + pr_info("3-Stack Debug board not detected \n"); + return -ENODEV; + } else { + debug_board_present = true; + } + + pr_info("3-Stack Debug board detected, rev = 0x%04X\n", + readw(brd_io + CPLD_CODE_VER_REG)); + + /* + * Configure INT line as GPIO input + */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_GPIO1_6), "gpio1_6"); + gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_GPIO1_6)); + + /* disable the interrupt and clear the status */ + __raw_writew(0, brd_io + INTR_MASK_REG); + __raw_writew(0xFFFF, brd_io + INTR_RESET_REG); + __raw_writew(0, brd_io + INTR_RESET_REG); + __raw_writew(0x1F, brd_io + INTR_MASK_REG); + 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(EXPIO_PARENT_INT, IRQF_TRIGGER_LOW); + set_irq_chained_handler(EXPIO_PARENT_INT, mxc_expio_irq_handler); + + return 0; +} + +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, + .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, + .io_reg = NULL, +}; + +static struct platform_device mxc_wm8903_device = { + .name = "imx-3stack-wm8903", + .id = 0, +}; + +static struct mxc_audio_platform_data wm8903_data; + +static void __init mxc_init_wm8903(void) +{ + wm8903_data.ssi_clk[0] = clk_get(NULL, "ssi_clk.0"); + clk_put(wm8903_data.ssi_clk[0]); + + wm8903_data.ssi_clk[1] = clk_get(NULL, "ssi_clk.1"); + clk_put(wm8903_data.ssi_clk[1]); + + wm8903_data.ssi_num = 1; + wm8903_data.src_port = 2; + wm8903_data.ext_port = 3; + + (void)platform_device_register(&mxc_wm8903_device); +} + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +int headphone_det_status(void) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26)); +} + +static struct mxc_audio_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 struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_irq = IOMUX_TO_IRQ(MX51_PIN_EIM_A26), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .sysclk = 12000000, + .init = mxc_sgtl5000_plat_init, + .finit = mxc_sgtl5000_plat_finit, +}; + +static void bt_reset(void) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D19), 1); +} + +static struct mxc_bt_platform_data mxc_bt_data = { + .bt_vdd = NULL, + .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, +}; + +static void mxc_unifi_hardreset(int pin_level) +{ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D19), pin_level & 0x01); +} + +static struct mxc_unifi_platform_data unifi_data = { + .hardreset = mxc_unifi_hardreset, + .reg_vdd_vpa = "VSD", + .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); + +/*! + * 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_set_cpu_type(MXC_CPU_MX51); + + get_cpu_wp = mx51_3stack_get_cpu_wp; + set_num_cpu_wp = mx51_3stack_set_num_cpu_wp; +} + +static struct mxc_gps_platform_data gps_data = { + .core_reg = "VIOHI", + .analog_reg = "SW4", +}; + +static struct platform_device mxc_gps_device = { + .name = "gps_ioctrl", + .id = -1, +}; + +int gpio_gps_access(int para) +{ + iomux_pin_name_t pin; + pin = (para & 0x1) ? MX51_PIN_EIM_CS2 : MX51_PIN_EIM_CRE; + + if (para & 0x4) /* Read GPIO */ + return gpio_get_value(IOMUX_TO_GPIO(pin)); + else if (para & 0x2) /* Write GPIO */ + gpio_set_value(IOMUX_TO_GPIO(pin), 1); + else + gpio_set_value(IOMUX_TO_GPIO(pin), 0); + return 0; +} +EXPORT_SYMBOL(gpio_gps_access); + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + int err; + + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1"); + mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2"); + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mxc_cpu_common_init(); + mx51_3stack_io_init(); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_hs_device, &mxci2c_hs_data); + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_tve_device, &tve_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, NULL); + mxc_register_device(&mxcscc_device, NULL); + mxc_register_device(&mx51_lpmode_device, NULL); + mxc_register_device(&busfreq_device, &bus_freq_data); + mxc_register_device(&sdram_autogating_device, NULL); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); + mxc_register_device(&mxc_iim_device, NULL); + mxc_register_device(&mxc_pwm1_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, + &mxc_pwm_backlight_data); + mxc_register_device(&mxc_keypad_device, &keypad_plat_data); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + mxc_register_device(&mxc_sim_device, &sim_data); + mxc_register_device(&pata_fsl_device, &ata_data); + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + + mxc_expio_init(); + if (debug_board_present) + mxc_register_device(&smsc_lan9217_device, &smsc911x_config); + + if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) + lcd_data.reset = lcd_reset_to2; + + mxc_register_device(&mxc_lcd_device, &lcd_data); + mxc_register_device(&lcd_wvga_device, &lcd_wvga_data); + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + mxc_register_device(&mxc_fb_devices[2], NULL); + mxc_register_device(&mxcbl_device, NULL); + +#if defined(CONFIG_MTD_NAND_IMX_NFC) || defined(CONFIG_MTD_NAND_IMX_NFC_MODULE) + mxc_register_device(&imx_nfc_device, &imx_nfc_platform_data); +#else + mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); +#endif + mx51_3stack_init_mc13892(); + + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + i2c_register_board_info(3, mxc_i2c_hs_board_info, + ARRAY_SIZE(mxc_i2c_hs_board_info)); + + mxc_init_wm8903(); + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mxc_register_device(&mxc_bt_device, &mxc_bt_data); + mxc_register_device(&mxc_gps_device, &gps_data); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); + + mx5_usb_dr_init(); + mx5_usbh1_init(); + + /* Setup Touchscreen interrupt */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), "gpio1_5"); + gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5)); + + err = mxc_request_iomux(MX51_PIN_EIM_D19, IOMUX_CONFIG_GPIO); + if (err) + printk(KERN_ERR "Error: bt reset request gpio failed!\n"); + else { + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_D19), "eim_d19"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D19), 0); + } +} + +static void __init mx51_3stack_timer_init(void) +{ + struct clk *uart_clk; + + /* Change the CPU voltages for TO2*/ + if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) { + cpu_wp_auto[0].cpu_voltage = 1175000; + cpu_wp_auto[1].cpu_voltage = 1100000; + cpu_wp_auto[2].cpu_voltage = 1000000; + } + + mx51_clocks_init(32768, 24000000, 22579200, 24576000); + + uart_clk = clk_get(NULL, "uart_clk.0"); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx51_3stack_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX51_3STACK data structure. + */ +/* *INDENT-OFF* */ +MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx51_3stack_gpio.c b/arch/arm/mach-mx5/mx51_3stack_gpio.c new file mode 100644 index 000000000000..b0fca773eaaa --- /dev/null +++ b/arch/arm/mach-mx5/mx51_3stack_gpio.c @@ -0,0 +1,852 @@ +/* + * Copyright (C) 2008-2010 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 <asm/io.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/gpio.h> + +#include "iomux.h" +#include "mx51_pins.h" + +/*! + * @file mach-mx5/mx51_3stack_gpio.c + * + * @brief This file contains all the GPIO setup functions for the board. + * + * @ingroup GPIO + */ +#define ATA_PAD_CONFIG (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH) + +static struct mxc_iomux_pin_cfg __initdata mxc_iomux_pins[] = { + /* CSI0 */ + { + MX51_PIN_CSI1_D8, IOMUX_CONFIG_ALT3, + PAD_CTL_PKE_ENABLE, + MUX_IN_GPIO3_IPP_IND_G_IN_12_SELECT_INPUT, + INPUT_CTL_PATH1, + }, + { + MX51_PIN_CSI1_D9, IOMUX_CONFIG_ALT3, + PAD_CTL_PKE_ENABLE, + }, + { + MX51_PIN_CSI1_D10, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D11, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D12, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D13, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D14, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D15, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D16, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D17, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D18, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D19, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_VSYNC, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + { + MX51_PIN_CSI1_HSYNC, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + { + MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT5 | IOMUX_CONFIG_SION, + (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_100K_PU | + PAD_CTL_HYS_ENABLE | PAD_CTL_DRV_VOT_HIGH), + MUX_IN_HSC_MIPI_MIX_IPP_IND_SENS2_DATA_EN_SELECT_INPUT, + INPUT_CTL_PATH0, + }, + { /* SPI1 */ + MX51_PIN_CSPI1_MISO, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_CSPI1_MOSI, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_CSPI1_RDY, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_CSPI1_SCLK, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_OWIRE_LINE, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | + PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP2_DAT15, IOMUX_CONFIG_ALT5, + }, + { + MX51_PIN_DI_GP2, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_DI_GP3, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL0, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL1, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL2, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL3, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL4, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_COL5, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_ROW0, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_ROW1, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_ROW2, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_KEY_ROW3, IOMUX_CONFIG_ALT0, + }, + { /* AUD3_TXD */ + MX51_PIN_AUD3_BB_TXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | + PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_100K_PU | + PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW), + }, + { /* AUD3_RXD */ + MX51_PIN_AUD3_BB_RXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | + PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_100K_PU | + PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW), + }, + { /* AUD3_CLK */ + MX51_PIN_AUD3_BB_CK, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | + PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_100K_PU | + PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW), + }, + { /* AUD3_FS */ + MX51_PIN_AUD3_BB_FS, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | + PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_100K_PU | + PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | PAD_CTL_DRV_VOT_LOW), + }, + { + MX51_PIN_EIM_D16, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_EIM_A27, IOMUX_CONFIG_ALT2, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { + MX51_PIN_EIM_EB2, IOMUX_CONFIG_ALT1, + PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_100K_PD, + }, + { + MX51_PIN_EIM_DTACK, IOMUX_CONFIG_GPIO, + (PAD_CTL_PKE_ENABLE | PAD_CTL_100K_PU), + }, + { + MX51_PIN_EIM_CS2, IOMUX_CONFIG_GPIO, + (PAD_CTL_DRV_HIGH | PAD_CTL_HYS_NONE | PAD_CTL_PUE_KEEPER | + PAD_CTL_100K_PU | PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_EIM_CRE, IOMUX_CONFIG_GPIO, + (PAD_CTL_DRV_HIGH | PAD_CTL_HYS_NONE | PAD_CTL_PUE_KEEPER | + PAD_CTL_100K_PU | PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DI_GP4, IOMUX_CONFIG_ALT2, + }, + { + MX51_PIN_DISPB2_SER_DIN, IOMUX_CONFIG_GPIO, + 0, + MUX_IN_GPIO3_IPP_IND_G_IN_5_SELECT_INPUT, + INPUT_CTL_PATH1, + }, + { + MX51_PIN_DISPB2_SER_RS, IOMUX_CONFIG_GPIO, + }, + { + MX51_PIN_DISPB2_SER_DIO, IOMUX_CONFIG_GPIO, + }, + { /* TO2 */ + MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_ALT4, + }, + { /* TO2 */ + MX51_PIN_DI1_D0_CS, IOMUX_CONFIG_ALT1, + }, + { /* TO2 */ + MX51_PIN_DI1_PIN11, IOMUX_CONFIG_ALT1, + }, + { /* TO2 */ + MX51_PIN_DI1_PIN12, IOMUX_CONFIG_ALT1, + }, + { /* TO2 */ + MX51_PIN_DI1_PIN13, IOMUX_CONFIG_ALT1, + }, +#ifdef CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL + { + MX51_PIN_DISP1_DAT0, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT1, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT2, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT3, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT4, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT5, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT6, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT7, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT8, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT9, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT10, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT11, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT12, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT13, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT14, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT15, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT16, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT17, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT18, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT19, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT20, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, +#endif + { + MX51_PIN_I2C1_CLK, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + 0x1E4, + }, + { + MX51_PIN_I2C1_DAT, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + 0x1E4, + }, + { + MX51_PIN_GPIO1_6, IOMUX_CONFIG_GPIO, + }, + { + MX51_PIN_GPIO1_7, IOMUX_CONFIG_ALT2, + (PAD_CTL_DRV_HIGH | PAD_CTL_PUE_PULL | + PAD_CTL_100K_PU | PAD_CTL_PKE_ENABLE | + PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_GPIO1_2, IOMUX_CONFIG_ALT2 | IOMUX_CONFIG_SION, + (PAD_CTL_SRE_FAST | PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_100K_PU | PAD_CTL_HYS_ENABLE), + MUX_IN_I2C2_IPP_SCL_IN_SELECT_INPUT, INPUT_CTL_PATH3, + }, + { + MX51_PIN_GPIO1_3, IOMUX_CONFIG_ALT2 | IOMUX_CONFIG_SION, + (PAD_CTL_SRE_FAST | PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_100K_PU | PAD_CTL_HYS_ENABLE), + MUX_IN_I2C2_IPP_SDA_IN_SELECT_INPUT, INPUT_CTL_PATH3, + }, + { + MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_PUE_KEEPER | + PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_CLK */ + MX51_PIN_USBH1_CLK, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_PUE_KEEPER | + PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE | PAD_CTL_DDR_INPUT_CMOS), + }, + { /* USBH1_DIR */ + MX51_PIN_USBH1_DIR, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_PUE_KEEPER | + PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE | PAD_CTL_DDR_INPUT_CMOS), + }, + { /* USBH1_NXT */ + MX51_PIN_USBH1_NXT, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_PUE_KEEPER | + PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE | PAD_CTL_DDR_INPUT_CMOS), + }, + { /* USBH1_DATA0 */ + MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA1 */ + MX51_PIN_USBH1_DATA1, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA2 */ + MX51_PIN_USBH1_DATA2, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA3 */ + MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA4 */ + MX51_PIN_USBH1_DATA4, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA5 */ + MX51_PIN_USBH1_DATA5, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA6 */ + MX51_PIN_USBH1_DATA6, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USBH1_DATA7 */ + MX51_PIN_USBH1_DATA7, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + }, + { /* USB1_OC */ + MX51_PIN_GPIO1_9, IOMUX_CONFIG_ALT1, + (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_LOW | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | + PAD_CTL_HYS_ENABLE), + }, + { /* USB1_PWR */ + MX51_PIN_GPIO1_8, IOMUX_CONFIG_ALT1, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_NONE | PAD_CTL_HYS_ENABLE), + }, + { + MX51_PIN_SD1_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD1_CLK, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD1_DATA0, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD1_DATA1, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD1_DATA2, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD1_DATA3, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_GPIO1_0, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), + }, + { + MX51_PIN_GPIO1_1, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), + }, + { + MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0, + (PAD_CTL_DRV_MAX | PAD_CTL_22K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_UART1_RXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + MUX_IN_UART1_IPP_UART_RXD_MUX_SELECT_INPUT, + INPUT_CTL_PATH0, + }, + { + MX51_PIN_UART1_TXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_UART1_RTS, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH), + MUX_IN_UART1_IPP_UART_RTS_B_SELECT_INPUT, + INPUT_CTL_PATH0, + }, + { + MX51_PIN_UART1_CTS, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH), + }, + { + MX51_PIN_UART2_RXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + MUX_IN_UART2_IPP_UART_RXD_MUX_SELECT_INPUT, + INPUT_CTL_PATH2, + }, + { + MX51_PIN_UART2_TXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_EIM_D26, IOMUX_CONFIG_ALT4, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + MUX_IN_UART2_IPP_UART_RTS_B_SELECT_INPUT, + INPUT_CTL_PATH3, + }, + { + MX51_PIN_EIM_D25, IOMUX_CONFIG_ALT4, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_UART3_RXD, IOMUX_CONFIG_ALT1, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + MUX_IN_UART3_IPP_UART_RXD_MUX_SELECT_INPUT, + INPUT_CTL_PATH4, + }, + { + MX51_PIN_UART3_TXD, IOMUX_CONFIG_ALT1, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_EIM_D27, IOMUX_CONFIG_ALT3, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + MUX_IN_UART3_IPP_UART_RTS_B_SELECT_INPUT, + INPUT_CTL_PATH3, + }, + { + MX51_PIN_EIM_D24, IOMUX_CONFIG_ALT3, + (PAD_CTL_HYS_NONE | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_KEEPER | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST), + }, +}; + +static struct mxc_iomux_pin_cfg __initdata ata_iomux_pins[] = { + { + MX51_PIN_NANDF_ALE, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CS2, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CS3, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_RE_B, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_WE_B, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_CLE, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_RB0, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_WP_B, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + /* TO 2.0 */ + { + MX51_PIN_GPIO_NAND, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + /* TO 1.0 */ + { + MX51_PIN_NANDF_RB5, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_RB1, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D0, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D1, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D2, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D3, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D4, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D5, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D6, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D7, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D8, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D9, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D10, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D11, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D12, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D13, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D14, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, + { + MX51_PIN_NANDF_D15, IOMUX_CONFIG_ALT1, + ATA_PAD_CONFIG, + }, +}; + +static struct mxc_iomux_pin_cfg __initdata nand_iomux_pins[] = { + { + MX51_PIN_NANDF_CS0, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS1, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS2, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS3, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT0, + }, + { + MX51_PIN_NANDF_CS7, IOMUX_CONFIG_ALT0, + }, + /* TO2 */ + { + MX51_PIN_GPIO_NAND, IOMUX_CONFIG_ALT0, + }, + /* TO1 */ + { + MX51_PIN_NANDF_RB5, IOMUX_CONFIG_ALT0, + }, +}; + +static struct mxc_iomux_pin_cfg __initdata sim_iomux_pins[] = { + { + MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT6, + PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_47K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE, + }, + { + MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT6, + PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_47K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE, + }, + { + MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT6, + PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_100K_PD | + PAD_CTL_PUE_PULL | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE, + }, + { + MX51_PIN_NANDF_CS7, IOMUX_CONFIG_ALT6, + PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_22K_PU | + PAD_CTL_PUE_PULL | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE, + }, +}; + +static int __initdata enable_ata = { 0 }; +static int __init ata_setup(char *__unused) +{ + enable_ata = 1; + return 1; +} + +__setup("ata", ata_setup); + +static int __initdata enable_sim = { 0 }; +static int __init sim_setup(char *__unused) +{ + enable_sim = 1; + return 1; +} + +__setup("sim", sim_setup); + +void __init mx51_3stack_io_init(void) +{ + int i, num; + struct mxc_iomux_pin_cfg *pin_ptr; + + for (i = 0; i < ARRAY_SIZE(mxc_iomux_pins); i++) { + mxc_request_iomux(mxc_iomux_pins[i].pin, + mxc_iomux_pins[i].mux_mode); + if (mxc_iomux_pins[i].pad_cfg) + mxc_iomux_set_pad(mxc_iomux_pins[i].pin, + mxc_iomux_pins[i].pad_cfg); + if (mxc_iomux_pins[i].in_select) + mxc_iomux_set_input(mxc_iomux_pins[i].in_select, + mxc_iomux_pins[i].in_mode); + } + + if (enable_ata) { + pin_ptr = ata_iomux_pins; + num = ARRAY_SIZE(ata_iomux_pins); + } else if (enable_sim) { + pin_ptr = sim_iomux_pins; + num = ARRAY_SIZE(sim_iomux_pins); + } else { + pin_ptr = nand_iomux_pins; + num = ARRAY_SIZE(nand_iomux_pins); + } + + for (i = 0; i < num; i++) { + mxc_request_iomux(pin_ptr[i].pin, pin_ptr[i].mux_mode); + if (pin_ptr[i].pad_cfg) + mxc_iomux_set_pad(pin_ptr[i].pin, pin_ptr[i].pad_cfg); + if (pin_ptr[i].in_select) + mxc_iomux_set_input(pin_ptr[i].in_select, + pin_ptr[i].in_mode); + } + + /* TO3 doesn't need pad to drive CSI_DATA_EN[0] high */ + if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) + mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT0); + + /* Camera low power */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_CSI1_D8), "csi1_d8"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_CSI1_D8), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D8), 0); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_EB2), "eim_eb2"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_EB2), 0); /* TO1 */ + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_EB2), 0); /* TO1 */ + + /* Camera reset */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), "csi1_d9"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 1); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), "di1_d1_cs"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 0); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0), "gpio1_0"); + gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0)); /* SD1 CD */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_GPIO1_1), "gpio1_1"); + gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_GPIO1_1)); /* SD1 WP */ + + /* EIM_D16 */ + /* osc_en is shared by SPDIF */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_D16), "eim_d16"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D16), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D16), 1); + + /* LCD related gpio */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), "di1_d1_cs"); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), "dispb2_ser_di0"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 0); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 0); + + /* GPS related gpio */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_CS2), "eim_cs2"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_CS2), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_CS2), 0); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_CRE), "eim_cre"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_CRE), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_CRE), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_CRE), 1); +} diff --git a/arch/arm/mach-mx5/mx51_3stack_pmic_mc13892.c b/arch/arm/mach-mx5/mx51_3stack_pmic_mc13892.c new file mode 100644 index 000000000000..7f2136d44152 --- /dev/null +++ b/arch/arm/mach-mx5/mx51_3stack_pmic_mc13892.c @@ -0,0 +1,370 @@ +/* + * mx51-3stack-pmic-mc13892.c -- i.MX51 3STACK Driver for Atlas MC13892 PMIC + */ + /* + * Copyright (C) 2009-2010 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/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892/core.h> +#include <mach/irqs.h> +#include "iomux.h" +#include "mx51_pins.h" + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +#define STANDBYSECINV_LSH 11 +#define STANDBYSECINV_WID 1 + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +/*! + * the event handler for power on event + */ +static void power_on_evt_handler(void) +{ + pr_info("pwr on event1 is received \n"); +} + +static int mc13892_regulator_init(struct mc13892 *mc13892) +{ + unsigned int value; + pmic_event_callback_t power_key_event; + int register_mask; + + printk("Initializing regulators for 3-stack.\n"); + if (mxc_cpu_is_rev(CHIP_REV_2_0) < 0) + sw2_init.constraints.state_mem.uV = 1100000; + else if (mxc_cpu_is_rev(CHIP_REV_2_0) == 1) { + sw2_init.constraints.state_mem.uV = 1250000; + sw1_init.constraints.state_mem.uV = 1000000; + } + + /* subscribe PWRON1 event to enable ON_OFF key */ + power_key_event.param = NULL; + power_key_event.func = (void *)power_on_evt_handler; + pmic_event_subscribe(EVENT_PWRONI, power_key_event); + + /* Bit 4 DRM: keep VSRTC and CLK32KMCU on for all states */ +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) + value = BITFVAL(DRM, 1); + register_mask = BITFMASK(DRM); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); +#endif + /* Set the STANDBYSECINV bit, so that STANDBY pin is + * interpreted as active low. + */ + value = BITFVAL(STANDBYSECINV, 1); + register_mask = BITFMASK(STANDBYSECINV); + pmic_write_reg(REG_POWER_CTL2, value, register_mask); + + /* Enable coin cell charger */ + value = BITFVAL(COINCHEN, 1) | BITFVAL(VCOIN, VCOIN_3_0V); + register_mask = BITFMASK(COINCHEN) | BITFMASK(VCOIN); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); + + mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init); + mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init); + mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init); + mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init); + mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init); + mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init); + mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init); + mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init); + mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init); + mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init); + mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init); + mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init); + mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init); + mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init); + mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init); + mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init); + mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init); + mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init); + mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init); + mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init); + mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init); + + return 0; +} + +static struct mc13892_platform_data mc13892_plat = { + .init = mc13892_regulator_init, +}; + +static struct i2c_board_info __initdata mc13892_i2c_device = { + I2C_BOARD_INFO("mc13892", 0x08), + .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_5), + .platform_data = &mc13892_plat, +}; + +int __init mx51_3stack_init_mc13892(void) +{ + return i2c_register_board_info(1, &mc13892_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx51_babbage.c b/arch/arm/mach-mx5/mx51_babbage.c new file mode 100644 index 000000000000..b6edc8078aab --- /dev/null +++ b/arch/arm/mach-mx5/mx51_babbage.c @@ -0,0 +1,1325 @@ +/* + * Copyright 2009-2011 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/slab.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.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/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/powerkey.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/keypad.h> +#include <asm/mach/flash.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/mxc_edid.h> +#include <mach/iomux-mx51.h> +#include <mach/i2c.h> +#include <mach/mxc_iim.h> + +#include "devices.h" +#include "crm_regs.h" +#include "usb.h" + +/*! + * @file mach-mx51/mx51_babbage.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX51 + */ + +#define BABBAGE_SD1_CD (0*32 + 0) /* GPIO_1_0 */ +#define BABBAGE_SD1_WP (0*32 + 1) /* GPIO_1_1 */ +#define BABBAGE_SD2_CD_2_0 (0*32 + 4) /* GPIO_1_4 */ +#define BABBAGE_SD2_WP (0*32 + 5) /* GPIO_1_5 */ +#define BABBAGE_SD2_CD_2_5 (0*32 + 6) /* GPIO_1_6 */ +#define BABBAGE_USBH1_HUB_RST (0*32 + 7) /* GPIO_1_7 */ +#define BABBAGE_PMIC_INT (0*32 + 8) /* GPIO_1_8 */ + +#define BABBAGE_USB_CLK_EN_B (1*32 + 1) /* GPIO_2_1 */ +#define BABBAGE_OSC_EN_B (1*32 + 2) /* GPIO_2_2 */ +#define BABBAGE_PHY_RESET (1*32 + 5) /* GPIO_2_5 */ +#define BABBAGE_CAM_RESET (1*32 + 7) /* GPIO_2_7 */ +#define BABBAGE_FM_PWR (1*32 + 12) /* GPIO_2_12 */ +#define BABBAGE_VGA_RESET (1*32 + 13) /* GPIO_2_13 */ +#define BABBAGE_FEC_PHY_RESET (1*32 + 14) /* GPIO_2_14 */ +#define BABBAGE_FM_RESET (1*32 + 15) /* GPIO_2_15 */ +#define BABBAGE_AUDAMP_STBY (1*32 + 17) /* GPIO_2_17 */ +#define BABBAGE_POWER_KEY (1*32 + 21) /* GPIO_2_21 */ + +#define BABBAGE_26M_OSC_EN (2*32 + 1) /* GPIO_3_1 */ +#define BABBAGE_LVDS_POWER_DOWN (2*32 + 3) /* GPIO_3_3 */ +#define BABBAGE_DISP_BRIGHTNESS_CTL (2*32 + 4) /* GPIO_3_4 */ +#define BABBAGE_DVI_RESET (2*32 + 5) /* GPIO_3_5 */ +#define BABBAGE_DVI_POWER (2*32 + 6) /* GPIO_3_6 */ +#define BABBAGE_HEADPHONE_DET (2*32 + 26) /* GPIO_3_26 */ +#define BABBAGE_DVI_DET (2*32 + 28) /* GPIO_3_28 */ + +#define BABBAGE_LCD_3V3_ON (3*32 + 9) /* GPIO_4_9 */ +#define BABBAGE_LCD_5V_ON (3*32 + 10) /* GPIO_4_10 */ +#define BABBAGE_CAM_LOW_POWER (3*32 + 10) /* GPIO_4_12 */ +#define BABBAGE_DVI_I2C_EN (3*32 + 14) /* GPIO_4_14 */ +#define BABBAGE_CSP1_SS0_GPIO (3*32 + 24) /* GPIO_4_24 */ +#define BABBAGE_AUDIO_CLK_EN (3*32 + 26) /* GPIO_4_26 */ + +extern int __init mx51_babbage_init_mc13892(void); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); +static int num_cpu_wp = 3; + +static struct pad_desc mx51babbage_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + MX51_PAD_UART2_RXD__UART2_RXD, + MX51_PAD_UART2_TXD__UART2_TXD, + + /* USB HOST1 */ + MX51_PAD_USBH1_STP__USBH1_STP, + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + + MX51_PAD_GPIO_1_0__GPIO_1_0, + MX51_PAD_GPIO_1_1__GPIO_1_1, + MX51_PAD_GPIO_1_4__GPIO_1_4, + MX51_PAD_GPIO_1_5__GPIO_1_5, + MX51_PAD_GPIO_1_6__GPIO_1_6, + MX51_PAD_GPIO_1_7__GPIO_1_7, + MX51_PAD_GPIO_1_8__GPIO_1_8, + MX51_PAD_UART3_RXD__GPIO_1_22, + + MX51_PAD_EIM_D17__GPIO_2_1, + MX51_PAD_EIM_D18__GPIO_2_2, + MX51_PAD_EIM_D21__GPIO_2_5, + MX51_PAD_EIM_D23__GPIO_2_7, + MX51_PAD_EIM_A16__GPIO_2_10, + MX51_PAD_EIM_A17__GPIO_2_11, + MX51_PAD_EIM_A18__GPIO_2_12, + MX51_PAD_EIM_A19__GPIO_2_13, + MX51_PAD_EIM_A20__GPIO_2_14, + MX51_PAD_EIM_A21__GPIO_2_15, + MX51_PAD_EIM_A22__GPIO_2_16, + MX51_PAD_EIM_A23__GPIO_2_17, + MX51_PAD_EIM_A27__GPIO_2_21, + MX51_PAD_EIM_DTACK__GPIO_2_31, + + MX51_PAD_EIM_LBA__GPIO_3_1, + MX51_PAD_DI1_D0_CS__GPIO_3_3, + MX51_PAD_DISPB2_SER_DIN__GPIO_3_5, + MX51_PAD_DISPB2_SER_DIO__GPIO_3_6, + MX51_PAD_NANDF_CS0__GPIO_3_16, + MX51_PAD_NANDF_CS1__GPIO_3_17, + MX51_PAD_NANDF_D14__GPIO_3_26, + MX51_PAD_NANDF_D12__GPIO_3_28, + + MX51_PAD_CSI2_D12__GPIO_4_9, + MX51_PAD_CSI2_D13__GPIO_4_10, + MX51_PAD_CSI2_D19__GPIO_4_12, + MX51_PAD_CSI2_HSYNC__GPIO_4_14, + MX51_PAD_CSPI1_RDY__GPIO_4_26, + + MX51_PAD_EIM_EB2__FEC_MDIO, + MX51_PAD_EIM_EB3__FEC_RDAT1, + MX51_PAD_EIM_CS2__FEC_RDAT2, + MX51_PAD_EIM_CS3__FEC_RDAT3, + MX51_PAD_EIM_CS4__FEC_RX_ER, + MX51_PAD_EIM_CS5__FEC_CRS, + MX51_PAD_NANDF_RB2__FEC_COL, + MX51_PAD_NANDF_RB3__FEC_RXCLK, + MX51_PAD_NANDF_RB6__FEC_RDAT0, + MX51_PAD_NANDF_RB7__FEC_TDAT0, + MX51_PAD_NANDF_CS2__FEC_TX_ER, + MX51_PAD_NANDF_CS3__FEC_MDC, + MX51_PAD_NANDF_CS4__FEC_TDAT1, + MX51_PAD_NANDF_CS5__FEC_TDAT2, + MX51_PAD_NANDF_CS6__FEC_TDAT3, + MX51_PAD_NANDF_CS7__FEC_TX_EN, + MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK, + + MX51_PAD_GPIO_NAND__PATA_INTRQ, + + MX51_PAD_DI_GP4__DI2_PIN15, +#ifdef CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL + MX51_PAD_DISP1_DAT22__DISP2_DAT16, + MX51_PAD_DISP1_DAT23__DISP2_DAT17, + + MX51_PAD_DI1_D1_CS__GPIO_3_4, +#endif + MX51_PAD_I2C1_CLK__HSI2C_CLK, + MX51_PAD_I2C1_DAT__HSI2C_DAT, + MX51_PAD_EIM_D16__I2C1_SDA, + MX51_PAD_EIM_D19__I2C1_SCL, + + MX51_PAD_GPIO_1_2__PWM_PWMO, + + MX51_PAD_KEY_COL5__I2C2_SDA, + MX51_PAD_KEY_COL4__I2C2_SCL, + + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, + + MX51_PAD_AUD3_BB_TXD__AUD3_BB_TXD, + MX51_PAD_AUD3_BB_RXD__AUD3_BB_RXD, + MX51_PAD_AUD3_BB_CK__AUD3_BB_CK, + MX51_PAD_AUD3_BB_FS__AUD3_BB_FS, + + MX51_PAD_CSPI1_SS1__CSPI1_SS1, + + MX51_PAD_DI_GP3__CSI1_DATA_EN, + MX51_PAD_CSI1_D10__CSI1_D10, + MX51_PAD_CSI1_D11__CSI1_D11, + MX51_PAD_CSI1_D12__CSI1_D12, + MX51_PAD_CSI1_D13__CSI1_D13, + MX51_PAD_CSI1_D14__CSI1_D14, + MX51_PAD_CSI1_D15__CSI1_D15, + MX51_PAD_CSI1_D16__CSI1_D16, + MX51_PAD_CSI1_D17__CSI1_D17, + MX51_PAD_CSI1_D18__CSI1_D18, + MX51_PAD_CSI1_D19__CSI1_D19, + MX51_PAD_CSI1_VSYNC__CSI1_VSYNC, + MX51_PAD_CSI1_HSYNC__CSI1_HSYNC, + + MX51_PAD_OWIRE_LINE__SPDIF_OUT1, +}; + +/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ +static struct cpu_wp cpu_wp_auto[] = { + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1175000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1100000,}, + { + .pll_rate = 800000000, + .cpu_rate = 166250000, + .pdf = 4, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 4, + .cpu_voltage = 850000,}, +}; + +static struct fb_videomode video_modes[] = { + { + /*MITSUBISHI LVDS panel */ + "XGA", 60, 1024, 768, 15385, + 220, 40, + 21, 7, + 60, 10, + 0, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +struct cpu_wp *mx51_babbage_get_cpu_wp(int *wp) +{ + *wp = num_cpu_wp; + return cpu_wp_auto; +} + +void mx51_babbage_set_num_cpu_wp(int num) +{ + num_cpu_wp = num; + return; +} + +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 1, +}; + +static u16 keymapping[16] = { + KEY_UP, KEY_DOWN, KEY_MENU, KEY_BACK, + KEY_RIGHT, KEY_LEFT, KEY_SELECT, KEY_ENTER, + KEY_F1, KEY_F3, KEY_1, KEY_3, + KEY_F2, KEY_F4, KEY_2, KEY_4, +}; + +static struct keypad_data keypad_plat_data = { + .rowmax = 4, + .colmax = 4, + .learning = 0, + .delay = 2, + .matrix = keymapping, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 78770, +}; + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 2, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + { + struct pad_desc cspi1_ss0 = MX51_PAD_CSPI1_SS0__CSPI1_SS0; + + mxc_iomux_v3_setup_pad(&cspi1_ss0); + break; + } + case 0x2: + { + struct pad_desc cspi1_ss0_gpio = MX51_PAD_CSPI1_SS0__GPIO_4_24; + + mxc_iomux_v3_setup_pad(&cspi1_ss0_gpio); + gpio_request(BABBAGE_CSP1_SS0_GPIO, "cspi1-gpio"); + gpio_direction_output(BABBAGE_CSP1_SS0_GPIO, 0); + gpio_set_value(BABBAGE_CSP1_SS0_GPIO, 1 & (~status)); + break; + } + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + break; + case 0x2: + gpio_free(BABBAGE_CSP1_SS0_GPIO); + break; + + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = mx51_babbage_gpio_spi_chipselect_active, + .chipselect_inactive = mx51_babbage_gpio_spi_chipselect_inactive, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct mxc_i2c_platform_data mxci2c_hs_data = { + .i2c_clk = 400000, +}; + +static struct tve_platform_data tve_data = { + .dac_reg = "VVIDEO", +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, + .num_wp = 3, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +static struct mxc_dvfsper_data dvfs_per_data = { + .reg_id = "SW2", + .clk_id = "gpc_dvfs_clk", + .gpc_cntr_reg_addr = MXC_GPC_CNTR, + .gpc_vcr_reg_addr = MXC_GPC_VCR, + .gpc_adu = 0x0, + .vai_mask = MXC_DVFSPMCR0_FSVAI_MASK, + .vai_offset = MXC_DVFSPMCR0_FSVAI_OFFSET, + .dvfs_enable_bit = MXC_DVFSPMCR0_DVFEN, + .irq_mask = MXC_DVFSPMCR0_FSVAIM, + .div3_offset = 0, + .div3_mask = 0x7, + .div3_div = 2, + .lp_high = 1250000, + .lp_low = 1250000, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* spdif_ext_clk source for 44.1KHz */ + .spdif_clk_48000 = 7, /* audio osc source */ + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct resource mxcfb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, + { + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "800x480M@55", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + /* Enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + + /* Disable fuse blown */ + if (!ccm_base) + return; + + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_data iim_data = { + .bank_start = MXC_IIM_MX51_BANK_START_ADDR, + .bank_end = MXC_IIM_MX51_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +extern int primary_di; +static int __init mxc_init_fb(void) +{ + if (!machine_is_mx51_babbage()) + return 0; + + /* DI0-LVDS */ + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 0); + msleep(1); + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 1); + gpio_set_value(BABBAGE_LCD_3V3_ON, 1); + gpio_set_value(BABBAGE_LCD_5V_ON, 1); + + /* DVI Detect */ + gpio_request(BABBAGE_DVI_DET, "dvi-detect"); + gpio_direction_input(BABBAGE_DVI_DET); + /* DVI Reset - Assert for i2c disabled mode */ + gpio_request(BABBAGE_DVI_RESET, "dvi-reset"); + gpio_direction_output(BABBAGE_DVI_RESET, 0); + /* DVI Power-down */ + gpio_request(BABBAGE_DVI_POWER, "dvi-power"); + gpio_direction_output(BABBAGE_DVI_POWER, 1); + + /* WVGA Reset */ + gpio_set_value(BABBAGE_DISP_BRIGHTNESS_CTL, 1); + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); + +static int handle_edid(int *pixclk) +{ +#if 0 + int err = 0; + int dvi = 0; + int fb0 = 0; + int fb1 = 1; + struct fb_var_screeninfo screeninfo; + struct i2c_adapter *adp; + + memset(&screeninfo, 0, sizeof(screeninfo)); + + adp = i2c_get_adapter(1); + + if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) { + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_HSYNC), 1); + msleep(1); + } + err = read_edid(adp, &screeninfo, &dvi); + if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_HSYNC), 0); + + if (!err) { + printk(KERN_INFO " EDID read\n"); + if (!dvi) { + enable_vga = 1; + fb0 = 1; /* fb0 will be VGA */ + fb1 = 0; /* fb1 will be DVI or TV */ + } + + /* Handle TV modes */ + /* This logic is fairly complex yet still doesn't handle all + possibilities. Once a customer knows the platform + configuration, this should be simplified to what is desired. + */ + if (screeninfo.xres == 1920 && screeninfo.yres != 1200) { + /* MX51 can't handle clock speeds for anything larger.*/ + if (!enable_tv) + enable_tv = 1; + if (enable_vga || enable_wvga || enable_tv == 2) + enable_tv = 2; + fb_data[0].mode = &(video_modes[0]); + if (!enable_wvga) + fb_data[1].mode_str = "800x600M-16@60"; + } else if (screeninfo.xres > 1280 && screeninfo.yres > 1024) { + if (!enable_wvga) { + fb_data[fb0].mode_str = "1280x1024M-16@60"; + fb_data[fb1].mode_str = NULL; + } else { + /* WVGA is preset so the DVI can't be > this. */ + fb_data[0].mode_str = "1024x768M-16@60"; + } + } else if (screeninfo.xres > 0 && screeninfo.yres > 0) { + if (!enable_wvga) { + fb_data[fb0].mode = + kzalloc(sizeof(struct fb_videomode), + GFP_KERNEL); + fb_var_to_videomode(fb_data[fb0].mode, + &screeninfo); + fb_data[fb0].mode_str = NULL; + if (screeninfo.xres >= 1280 && + screeninfo.yres > 720) + fb_data[fb1].mode_str = NULL; + else if (screeninfo.xres > 1024 && + screeninfo.yres > 768) + fb_data[fb1].mode_str = + "800x600M-16@60"; + else if (screeninfo.xres > 800 && + screeninfo.yres > 600) + fb_data[fb1].mode_str = + "1024x768M-16@60"; + } else { + /* A WVGA panel was specified and an EDID was + read thus there is a DVI monitor attached. */ + if (screeninfo.xres >= 1024) + fb_data[0].mode_str = "1024x768M-16@60"; + else if (screeninfo.xres >= 800) + fb_data[0].mode_str = "800x600M-16@60"; + else + fb_data[0].mode_str = "640x480M-16@60"; + } + } + } +#endif + return 0; +} + +static void dvi_reset(void) +{ + gpio_direction_output(BABBAGE_DVI_RESET, 0); + gpio_set_value(BABBAGE_DVI_RESET, 0); + msleep(50); + + /* do reset */ + gpio_set_value(BABBAGE_DVI_RESET, 1); + msleep(20); /* tRES >= 50us */ + + gpio_set_value(BABBAGE_DVI_RESET, 0); +} + +static struct mxc_lcd_platform_data dvi_data = { + .core_reg = "VGEN1", + .io_reg = "VGEN3", + .reset = dvi_reset, +}; + +static void vga_reset(void) +{ + + gpio_set_value(BABBAGE_VGA_RESET, 0); + msleep(50); + /* do reset */ + gpio_set_value(BABBAGE_VGA_RESET, 1); + msleep(10); /* tRES >= 50us */ + gpio_set_value(BABBAGE_VGA_RESET, 0); +} + +static struct mxc_lcd_platform_data vga_data = { + .core_reg = "VCAM", + .io_reg = "VGEN3", + .analog_reg = "VAUDIO", + .reset = vga_reset, +}; + +static void si4702_reset(void) +{ + return; + + gpio_set_value(BABBAGE_FM_RESET, 0); + msleep(100); + gpio_set_value(BABBAGE_FM_RESET, 1); + msleep(100); +} + +static void si4702_clock_ctl(int flag) +{ + gpio_set_value(BABBAGE_FM_PWR, flag); + msleep(100); +} + +static void si4702_gpio_get(void) +{ + gpio_request(BABBAGE_FM_PWR, "fm-power"); + gpio_direction_output(BABBAGE_FM_PWR, 0); +} + +static void si4702_gpio_put(void) +{ +} + +static struct mxc_fm_platform_data si4702_data = { + .reg_vio = "SW4", + .reg_vdd = "VIOHI", + .gpio_get = si4702_gpio_get, + .gpio_put = si4702_gpio_put, + .reset = si4702_reset, + .clock_ctl = si4702_clock_ctl, +}; + +static struct mxc_camera_platform_data camera_data = { + .io_regulator = "SW4", + .analog_regulator = "VIOHI", + .mclk = 24000000, + .csi = 0, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "ov3640", + .addr = 0x3C, + .platform_data = (void *)&camera_data, + }, +}; + +static struct mxc_lightsensor_platform_data ls_data = { + .vdd_reg = "VIOHI", + .rext = 100, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "isl29003", + .addr = 0x44, + .platform_data = &ls_data, + }, +}; + +static struct i2c_board_info mxc_i2c_hs_board_info[] __initdata = { + { + .type = "sii9022", + .addr = 0x39, + .platform_data = &dvi_data, + }, + { + .type = "ch7026", + .addr = 0x75, + .platform_data = &vga_data, + }, + { + .type = "si4702", + .addr = 0x10, + .platform_data = (void *)&si4702_data, + }, +}; + +static struct mtd_partition mxc_spi_nor_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00040000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, + +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_spi_nor", + .parts = mxc_spi_nor_partitions, + .nr_parts = ARRAY_SIZE(mxc_spi_nor_partitions), + .type = "sst25vf016b",}, + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + +static struct spi_board_info mxc_spi_nor_device[] __initdata = { + { + .modalias = "mxc_spi_nor", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0], + }, +}; + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[1],}, +}; + +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(BABBAGE_SD1_WP); + else + rc = gpio_get_value(BABBAGE_SD2_WP); + + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret; + + if (to_platform_device(dev)->id == 0) { + ret = gpio_get_value(BABBAGE_SD1_CD); + return ret; + } else { /* config the det pin for SDHC2 */ + if (board_is_rev(BOARD_REV_2)) + /* BB2.5 */ + ret = gpio_get_value(BABBAGE_SD2_CD_2_5); + else + /* BB2.0 */ + ret = gpio_get_value(BABBAGE_SD2_CD_2_0); + return ret; + } +} + +static struct mxc_mmc_platform_data mmc1_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 = 52000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +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 int mxc_sgtl5000_amp_enable(int enable) +{ + gpio_set_value(BABBAGE_AUDAMP_STBY, enable ? 1 : 0); + return 0; +} + +static int mxc_sgtl5000_clock_enable(int enable) +{ + gpio_set_value(BABBAGE_AUDIO_CLK_EN, !enable); + return 0; +} + +static int headphone_det_status(void) +{ + return (gpio_get_value(BABBAGE_HEADPHONE_DET) == 0); +} + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_irq = IOMUX_TO_IRQ_V3(BABBAGE_HEADPHONE_DET), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .clock_enable = mxc_sgtl5000_clock_enable, + .sysclk = 12288000, +}; + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx51(); +} + +__setup("w1", w1_setup); + +/*! + * 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) +{ + char *str; + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_512M; + int left_mem = 0; + int gpu_mem = SZ_64M; + int fb_mem = SZ_32M; + + mxc_set_cpu_type(MXC_CPU_MX51); + + get_cpu_wp = mx51_babbage_get_cpu_wp; + set_num_cpu_wp = mx51_babbage_set_num_cpu_wp; + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_device.resource[5].start = + mem_tag->u.mem.start + left_mem; + gpu_device.resource[5].end = + gpu_device.resource[5].start + gpu_mem - 1; +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ + defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) + if (fb_mem) { + mxcfb_resources[0].start = + gpu_device.resource[5].end + 1; + mxcfb_resources[0].end = + mxcfb_resources[0].start + fb_mem - 1; + } else { + mxcfb_resources[0].start = 0; + mxcfb_resources[0].end = 0; + } +#endif + } +} + +#define PWGT1SPIEN (1<<15) +#define PWGT2SPIEN (1<<16) +#define USEROFFSPI (1<<3) + +static void mxc_power_off(void) +{ + /* We can do power down one of two ways: + Set the power gating + Set USEROFFSPI */ + + /* Set the power gate bits to power down */ + pmic_write_reg(REG_POWER_MISC, (PWGT1SPIEN|PWGT2SPIEN), + (PWGT1SPIEN|PWGT2SPIEN)); +} + +/*! + * Power Key interrupt handler. + */ +static irqreturn_t power_key_int(int irq, void *dev_id) +{ + pwrkey_callback cb = (pwrkey_callback)dev_id; + + cb((void *)1); + + if (gpio_get_value(BABBAGE_POWER_KEY)) + set_irq_type(irq, IRQF_TRIGGER_FALLING); + else + set_irq_type(irq, IRQF_TRIGGER_RISING); + + return 0; +} + +static void mxc_register_powerkey(pwrkey_callback pk_cb) +{ + /* Set power key as wakeup resource */ + int irq, ret; + irq = IOMUX_TO_IRQ_V3(BABBAGE_POWER_KEY); + + if (gpio_get_value(BABBAGE_POWER_KEY)) + set_irq_type(irq, IRQF_TRIGGER_FALLING); + else + set_irq_type(irq, IRQF_TRIGGER_RISING); + + ret = request_irq(irq, power_key_int, 0, "power_key", pk_cb); + if (ret) + pr_info("register on-off key interrupt failed\n"); + else + enable_irq_wake(irq); +} + +static int mxc_pwrkey_getstatus(int id) +{ + return gpio_get_value(BABBAGE_POWER_KEY); +} + +static struct power_key_platform_data pwrkey_data = { + .key_value = KEY_F4, + .register_pwrkey = mxc_register_powerkey, + .get_key_status = mxc_pwrkey_getstatus, +}; + +static void __init mx51_babbage_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, + ARRAY_SIZE(mx51babbage_pads)); + + gpio_request(BABBAGE_PMIC_INT, "pmic-int"); + gpio_request(BABBAGE_SD1_CD, "sdhc1-detect"); + gpio_request(BABBAGE_SD1_WP, "sdhc1-wp"); + + gpio_direction_input(BABBAGE_PMIC_INT); + gpio_direction_input(BABBAGE_SD1_CD); + gpio_direction_input(BABBAGE_SD1_WP); + + if (board_is_rev(BOARD_REV_2)) { + /* SD2 CD for BB2.5 */ + gpio_request(BABBAGE_SD2_CD_2_5, "sdhc2-detect"); + gpio_direction_input(BABBAGE_SD2_CD_2_5); + } else { + /* SD2 CD for BB2.0 */ + gpio_request(BABBAGE_SD2_CD_2_0, "sdhc2-detect"); + gpio_direction_input(BABBAGE_SD2_CD_2_0); + } + gpio_request(BABBAGE_SD2_WP, "sdhc2-wp"); + gpio_direction_input(BABBAGE_SD2_WP); + + /* reset usbh1 hub */ + gpio_request(BABBAGE_USBH1_HUB_RST, "hub-rst"); + gpio_direction_output(BABBAGE_USBH1_HUB_RST, 0); + gpio_set_value(BABBAGE_USBH1_HUB_RST, 0); + msleep(1); + gpio_set_value(BABBAGE_USBH1_HUB_RST, 1); + + /* reset FEC PHY */ + gpio_request(BABBAGE_FEC_PHY_RESET, "fec-phy-reset"); + gpio_direction_output(BABBAGE_FEC_PHY_RESET, 0); + msleep(10); + gpio_set_value(BABBAGE_FEC_PHY_RESET, 1); + + /* reset FM */ + gpio_request(BABBAGE_FM_RESET, "fm-reset"); + gpio_direction_output(BABBAGE_FM_RESET, 0); + msleep(10); + gpio_set_value(BABBAGE_FM_RESET, 1); + + /* Drive 26M_OSC_EN line high */ + gpio_request(BABBAGE_26M_OSC_EN, "26m-osc-en"); + gpio_direction_output(BABBAGE_26M_OSC_EN, 1); + + /* Drive USB_CLK_EN_B line low */ + gpio_request(BABBAGE_USB_CLK_EN_B, "usb-clk_en_b"); + gpio_direction_output(BABBAGE_USB_CLK_EN_B, 0); + + /* De-assert USB PHY RESETB */ + gpio_request(BABBAGE_PHY_RESET, "usb-phy-reset"); + gpio_direction_output(BABBAGE_PHY_RESET, 1); + + /* hphone_det_b */ + gpio_request(BABBAGE_HEADPHONE_DET, "hphone-det"); + gpio_direction_input(BABBAGE_HEADPHONE_DET); + + /* audio_clk_en_b */ + gpio_request(BABBAGE_AUDIO_CLK_EN, "audio-clk-en"); + gpio_direction_output(BABBAGE_AUDIO_CLK_EN, 0); + + /* power key */ + gpio_request(BABBAGE_POWER_KEY, "power-key"); + gpio_direction_input(BABBAGE_POWER_KEY); + + if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) { + /* DVI_I2C_ENB = 0 tristates the DVI I2C level shifter */ + gpio_request(BABBAGE_DVI_I2C_EN, "dvi-i2c-en"); + gpio_direction_output(BABBAGE_DVI_I2C_EN, 0); + } + + /* Deassert VGA reset to free i2c bus */ + gpio_request(BABBAGE_VGA_RESET, "vga-reset"); + gpio_direction_output(BABBAGE_VGA_RESET, 1); + + /* LCD related gpio */ + gpio_request(BABBAGE_DISP_BRIGHTNESS_CTL, "disp-brightness-ctl"); + gpio_request(BABBAGE_LVDS_POWER_DOWN, "lvds-power-down"); + gpio_request(BABBAGE_LCD_3V3_ON, "lcd-3v3-on"); + gpio_request(BABBAGE_LCD_5V_ON, "lcd-5v-on"); + gpio_direction_output(BABBAGE_DISP_BRIGHTNESS_CTL, 0); + gpio_direction_output(BABBAGE_LVDS_POWER_DOWN, 0); + gpio_direction_output(BABBAGE_LCD_3V3_ON, 0); + gpio_direction_output(BABBAGE_LCD_5V_ON, 0); + + /* Camera reset */ + gpio_request(BABBAGE_CAM_RESET, "cam-reset"); + gpio_direction_output(BABBAGE_CAM_RESET, 1); + + /* Camera low power */ + gpio_request(BABBAGE_CAM_LOW_POWER, "cam-low-power"); + gpio_direction_output(BABBAGE_CAM_LOW_POWER, 0); + + /* OSC_EN */ + gpio_request(BABBAGE_OSC_EN_B, "osc-en"); + gpio_direction_output(BABBAGE_OSC_EN_B, 1); + + if (enable_w1) { + /* OneWire */ + struct pad_desc onewire = MX51_PAD_OWIRE_LINE__OWIRE_LINE; + mxc_iomux_v3_setup_pad(&onewire); + } +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1"); + mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2"); + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + /* SD card detect irqs */ + mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5); + mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD); + + mxc_cpu_common_init(); + mx51_babbage_io_init(); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_hs_device, &mxci2c_hs_data); + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_tve_device, &tve_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, NULL); + mxc_register_device(&mxcscc_device, NULL); + mxc_register_device(&mx51_lpmode_device, NULL); + mxc_register_device(&busfreq_device, &bus_freq_data); + mxc_register_device(&sdram_autogating_device, NULL); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); + mxc_register_device(&mxc_iim_device, &iim_data); + mxc_register_device(&mxc_pwm1_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, + &mxc_pwm_backlight_data); + mxc_register_device(&mxc_keypad_device, &keypad_plat_data); + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&mxc_ssi3_device, NULL); + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + mxc_register_device(&mxc_fec_device, NULL); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); + mxc_register_device(&mxc_powerkey_device, &pwrkey_data); + + mx51_babbage_init_mc13892(); + + if (board_is_rev(BOARD_REV_2)) + /* BB2.5 */ + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); + else + /* BB2.0 */ + spi_register_board_info(mxc_spi_nor_device, + ARRAY_SIZE(mxc_spi_nor_device)); + + 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)); + + if (cpu_is_mx51_rev(CHIP_REV_2_0) >= 1) { + vga_data.core_reg = NULL; + vga_data.io_reg = NULL; + vga_data.analog_reg = NULL; + } + i2c_register_board_info(3, mxc_i2c_hs_board_info, + ARRAY_SIZE(mxc_i2c_hs_board_info)); + + pm_power_off = mxc_power_off; + + if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) { + sgtl5000_data.sysclk = 26000000; + } + gpio_request(BABBAGE_AUDAMP_STBY, "audioamp-stdby"); + gpio_direction_output(BABBAGE_AUDAMP_STBY, 0); + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + + mx5_usb_dr_init(); + mx5_usbh1_init(); +} + +static void __init mx51_babbage_timer_init(void) +{ + struct clk *uart_clk; + + /* Change the CPU voltages for TO2*/ + if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) { + cpu_wp_auto[0].cpu_voltage = 1175000; + cpu_wp_auto[1].cpu_voltage = 1100000; + cpu_wp_auto[2].cpu_voltage = 1000000; + } + + mx51_clocks_init(32768, 24000000, 22579200, 24576000); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx51_babbage_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX51_BABBAGE data structure. + */ +/* *INDENT-OFF* */ +MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c new file mode 100644 index 000000000000..1d5a06bfb5f4 --- /dev/null +++ b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c @@ -0,0 +1,436 @@ +/* + * mx51-babbage-pmic-mc13892.c -- i.MX51 Babbage Driver for Atlas MC13892 PMIC + */ + /* + * Copyright (C) 2009-2010 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/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892/core.h> +#include <mach/irqs.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* regulator standby mask */ +#define GEN1_STBY_MASK (1 << 1) +#define IOHI_STBY_MASK (1 << 4) +#define DIG_STBY_MASK (1 << 10) +#define GEN2_STBY_MASK (1 << 13) +#define PLL_STBY_MASK (1 << 16) +#define USB2_STBY_MASK (1 << 19) + +#define GEN3_STBY_MASK (1 << 1) +#define CAM_STBY_MASK (1 << 7) +#define VIDEO_STBY_MASK (1 << 13) +#define AUDIO_STBY_MASK (1 << 16) +#define SD_STBY_MASK (1 << 19) + +/* 0x92412 */ +#define REG_MODE_0_ALL_MASK (GEN1_STBY_MASK |\ + DIG_STBY_MASK | GEN2_STBY_MASK |\ + PLL_STBY_MASK) +/* 0x92082 */ +#define REG_MODE_1_ALL_MASK (CAM_STBY_MASK | VIDEO_STBY_MASK |\ + AUDIO_STBY_MASK | SD_STBY_MASK) + +/* switch mode setting */ +#define SW1MODE_LSB 0 +#define SW2MODE_LSB 10 +#define SW3MODE_LSB 0 +#define SW4MODE_LSB 8 + +#define SWMODE_MASK 0xF +#define SWMODE_AUTO 0x8 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_consumer_supply vdig_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDA", + .dev_name = "1-000a", + }, +}; + +static struct regulator_consumer_supply vvideo_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1650), + .max_uV = mV_to_uV(1650), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vdig_consumers), + .consumer_supplies = vdig_consumers, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2775), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vvideo_consumers), + .consumer_supplies = vvideo_consumers, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1200), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static int mc13892_regulator_init(struct mc13892 *mc13892) +{ + unsigned int value, register_mask; + printk("Initializing regulators for Babbage.\n"); + if (mxc_cpu_is_rev(CHIP_REV_2_0) < 0) + sw2_init.constraints.state_mem.uV = 1100000; + else if (mxc_cpu_is_rev(CHIP_REV_2_0) == 1) { + sw2_init.constraints.state_mem.uV = 1250000; + sw1_init.constraints.state_mem.uV = 1000000; + } + + /* enable standby controll for all regulators */ + pmic_read_reg(REG_MODE_0, &value, 0xffffff); + value |= REG_MODE_0_ALL_MASK; + pmic_write_reg(REG_MODE_0, value, 0xffffff); + + pmic_read_reg(REG_MODE_1, &value, 0xffffff); + value |= REG_MODE_1_ALL_MASK; + pmic_write_reg(REG_MODE_1, value, 0xffffff); + + /* enable switch audo mode */ + pmic_read_reg(REG_IDENTIFICATION, &value, 0xffffff); + /* only for mc13892 2.0A */ + if ((value & 0x0000FFFF) == 0x45d0) { + pmic_read_reg(REG_SW_4, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW1MODE_LSB) | + (SWMODE_MASK << SW2MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW1MODE_LSB) | + (SWMODE_AUTO << SW2MODE_LSB); + pmic_write_reg(REG_SW_4, value, 0xffffff); + + pmic_read_reg(REG_SW_5, &value, 0xffffff); + register_mask = (SWMODE_MASK << SW3MODE_LSB) | + (SWMODE_MASK << SW4MODE_LSB); + value &= ~register_mask; + value |= (SWMODE_AUTO << SW3MODE_LSB) | + (SWMODE_AUTO << SW4MODE_LSB); + pmic_write_reg(REG_SW_5, value, 0xffffff); + } + + /* Enable coin cell charger */ + value = BITFVAL(COINCHEN, 1) | BITFVAL(VCOIN, VCOIN_3_0V); + register_mask = BITFMASK(COINCHEN) | BITFMASK(VCOIN); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); + +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) + value = BITFVAL(DRM, 1); + register_mask = BITFMASK(DRM); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); +#endif + + mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init); + mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init); + mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init); + mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init); + mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init); + mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init); + mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init); + mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init); + mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init); + mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init); + mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init); + mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init); + mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init); + mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init); + mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init); + mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init); + mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init); + mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init); + mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init); + mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init); + mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init); + + regulator_has_full_constraints(); + + return 0; +} + +static struct mc13892_platform_data mc13892_plat = { + .init = mc13892_regulator_init, +}; + +static struct spi_board_info __initdata mc13892_spi_device = { + .modalias = "pmic_spi", + .irq = IOMUX_TO_IRQ_V3(8), + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ + .bus_num = 1, + .chip_select = 0, + .platform_data = &mc13892_plat, +}; + + +int __init mx51_babbage_init_mc13892(void) +{ + return spi_register_board_info(&mc13892_spi_device, 1); +} diff --git a/arch/arm/mach-mx5/mx51_pins.h b/arch/arm/mach-mx5/mx51_pins.h new file mode 100644 index 000000000000..351cdb29a32a --- /dev/null +++ b/arch/arm/mach-mx5/mx51_pins.h @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2008-2010 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_MX51_PINS_H__ +#define __ASM_ARCH_MXC_MX51_PINS_H__ +#include "iomux.h" + +/*! + * @file arch-mxc/mx51_pins.h + * + * @brief MX51 I/O Pin List + * + * @ingroup GPIO_MX51 + */ + +#ifndef __ASSEMBLY__ + +#define PAD_I_START_MX51 0x3F0 +#define INPUT_CTL_START_MX51 0x8C4 +#define INPUT_CTL_START_MX51_TO1 0x928 + +#define MUX_I_END_MX51 (PAD_I_START_MX51 - 4) + +#define _MXC_BUILD_PIN_MX51(gp, gi, ga, mi, pi) \ + (((gp) << MUX_IO_P) | ((gi) << MUX_IO_I) | \ + ((mi) << MUX_I) | \ + ((pi - PAD_I_START_MX51) << PAD_I) | \ + ((ga) << GPIO_I)) + +#define _MXC_BUILD_GPIO_PIN_MX51(gp, gi, ga, mi, pi) \ + _MXC_BUILD_PIN_MX51(gp, gi, ga, mi, pi) + +#define _MXC_BUILD_NON_GPIO_PIN_MX51(mi, pi) \ + _MXC_BUILD_PIN_MX51(NON_GPIO_PORT, 0, 0, mi, pi) +/*! + * This enumeration is constructed based on the Section + * "sw_pad_ctl & sw_mux_ctl details" of the MX51 IC Spec. Each enumerated + * value is constructed based on the rules described above. + */ +enum iomux_pins_mx51 { + MX51_PIN_EIM_DA0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1C, 0x7A8), + MX51_PIN_EIM_DA1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x20, 0x7A8), + MX51_PIN_EIM_DA2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x24, 0x7A8), + MX51_PIN_EIM_DA3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x28, 0x7A8), + MX51_PIN_EIM_DA4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2C, 0x7AC), + MX51_PIN_EIM_DA5 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x30, 0x7AC), + MX51_PIN_EIM_DA6 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x34, 0x7AC), + MX51_PIN_EIM_DA7 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x38, 0x7AC), + MX51_PIN_EIM_DA8 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3C, 0x7B0), + MX51_PIN_EIM_DA9 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x40, 0x7B0), + MX51_PIN_EIM_DA10 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x44, 0x7B0), + MX51_PIN_EIM_DA11 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x48, 0x7B0), + MX51_PIN_EIM_DA12 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x4C, 0x7BC), + MX51_PIN_EIM_DA13 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x50, 0x7BC), + MX51_PIN_EIM_DA14 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x54, 0x7BC), + MX51_PIN_EIM_DA15 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x58, 0x7BC), + MX51_PIN_EIM_D16 = _MXC_BUILD_GPIO_PIN_MX51(1, 0, 1, 0x5C, 0x3F0), + MX51_PIN_EIM_D17 = _MXC_BUILD_GPIO_PIN_MX51(1, 1, 1, 0x60, 0x3F4), + MX51_PIN_EIM_D18 = _MXC_BUILD_GPIO_PIN_MX51(1, 2, 1, 0x64, 0x3F8), + MX51_PIN_EIM_D19 = _MXC_BUILD_GPIO_PIN_MX51(1, 3, 1, 0x68, 0x3FC), + MX51_PIN_EIM_D20 = _MXC_BUILD_GPIO_PIN_MX51(1, 4, 1, 0x6C, 0x400), + MX51_PIN_EIM_D21 = _MXC_BUILD_GPIO_PIN_MX51(1, 5, 1, 0x70, 0x404), + MX51_PIN_EIM_D22 = _MXC_BUILD_GPIO_PIN_MX51(1, 6, 1, 0x74, 0x408), + MX51_PIN_EIM_D23 = _MXC_BUILD_GPIO_PIN_MX51(1, 7, 1, 0x78, 0x40C), + MX51_PIN_EIM_D24 = _MXC_BUILD_GPIO_PIN_MX51(1, 8, 1, 0x7C, 0x410), + MX51_PIN_EIM_D25 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x80, 0x414), + MX51_PIN_EIM_D26 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x84, 0x418), + MX51_PIN_EIM_D27 = _MXC_BUILD_GPIO_PIN_MX51(1, 9, 1, 0x88, 0x41C), + MX51_PIN_EIM_D28 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x8C, 0x420), + MX51_PIN_EIM_D29 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x90, 0x424), + MX51_PIN_EIM_D30 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x94, 0x428), + MX51_PIN_EIM_D31 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x98, 0x42C), + MX51_PIN_EIM_A16 = _MXC_BUILD_GPIO_PIN_MX51(1, 10, 1, 0x9C, 0x430), + MX51_PIN_EIM_A17 = _MXC_BUILD_GPIO_PIN_MX51(1, 11, 1, 0xA0, 0x434), + MX51_PIN_EIM_A18 = _MXC_BUILD_GPIO_PIN_MX51(1, 12, 1, 0xA4, 0x438), + MX51_PIN_EIM_A19 = _MXC_BUILD_GPIO_PIN_MX51(1, 13, 1, 0xA8, 0x43C), + MX51_PIN_EIM_A20 = _MXC_BUILD_GPIO_PIN_MX51(1, 14, 1, 0xAC, 0x440), + MX51_PIN_EIM_A21 = _MXC_BUILD_GPIO_PIN_MX51(1, 15, 1, 0xB0, 0x444), + MX51_PIN_EIM_A22 = _MXC_BUILD_GPIO_PIN_MX51(1, 16, 1, 0xB4, 0x448), + MX51_PIN_EIM_A23 = _MXC_BUILD_GPIO_PIN_MX51(1, 17, 1, 0xB8, 0x44C), + MX51_PIN_EIM_A24 = _MXC_BUILD_GPIO_PIN_MX51(1, 18, 1, 0xBC, 0x450), + MX51_PIN_EIM_A25 = _MXC_BUILD_GPIO_PIN_MX51(1, 19, 1, 0xC0, 0x454), + MX51_PIN_EIM_A26 = _MXC_BUILD_GPIO_PIN_MX51(1, 20, 1, 0xC4, 0x458), + MX51_PIN_EIM_A27 = _MXC_BUILD_GPIO_PIN_MX51(1, 21, 1, 0xC8, 0x45C), + MX51_PIN_EIM_EB0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0xCC, 0x460), + MX51_PIN_EIM_EB1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0xD0, 0x464), + MX51_PIN_EIM_EB2 = _MXC_BUILD_GPIO_PIN_MX51(1, 22, 1, 0xD4, 0x468), + MX51_PIN_EIM_EB3 = _MXC_BUILD_GPIO_PIN_MX51(1, 23, 1, 0xD8, 0x46C), + MX51_PIN_EIM_OE = _MXC_BUILD_GPIO_PIN_MX51(1, 24, 1, 0xDC, 0x470), + MX51_PIN_EIM_CS0 = _MXC_BUILD_GPIO_PIN_MX51(1, 25, 1, 0xE0, 0x474), + MX51_PIN_EIM_CS1 = _MXC_BUILD_GPIO_PIN_MX51(1, 26, 1, 0xE4, 0x478), + MX51_PIN_EIM_CS2 = _MXC_BUILD_GPIO_PIN_MX51(1, 27, 1, 0xE8, 0x47C), + MX51_PIN_EIM_CS3 = _MXC_BUILD_GPIO_PIN_MX51(1, 28, 1, 0xEC, 0x480), + MX51_PIN_EIM_CS4 = _MXC_BUILD_GPIO_PIN_MX51(1, 29, 1, 0xF0, 0x484), + MX51_PIN_EIM_CS5 = _MXC_BUILD_GPIO_PIN_MX51(1, 30, 1, 0xF4, 0x488), + MX51_PIN_EIM_DTACK = _MXC_BUILD_GPIO_PIN_MX51(1, 31, 1, 0xF8, 0x48C), + MX51_PIN_EIM_LBA = _MXC_BUILD_GPIO_PIN_MX51(2, 1, 1, 0xFC, 0x494), + MX51_PIN_EIM_CRE = _MXC_BUILD_GPIO_PIN_MX51(2, 2, 1, 0x100, 0x4A0), + MX51_PIN_DRAM_CS1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x104, 0x4D0), + MX51_PIN_NANDF_WE_B = _MXC_BUILD_GPIO_PIN_MX51(2, 3, 3, 0x108, 0x4E4), + MX51_PIN_NANDF_RE_B = _MXC_BUILD_GPIO_PIN_MX51(2, 4, 3, 0x10C, 0x4E8), + MX51_PIN_NANDF_ALE = _MXC_BUILD_GPIO_PIN_MX51(2, 5, 3, 0x110, 0x4EC), + MX51_PIN_NANDF_CLE = _MXC_BUILD_GPIO_PIN_MX51(2, 6, 3, 0x114, 0x4F0), + MX51_PIN_NANDF_WP_B = _MXC_BUILD_GPIO_PIN_MX51(2, 7, 3, 0x118, 0x4F4), + MX51_PIN_NANDF_RB0 = _MXC_BUILD_GPIO_PIN_MX51(2, 8, 3, 0x11C, 0x4F8), + MX51_PIN_NANDF_RB1 = _MXC_BUILD_GPIO_PIN_MX51(2, 9, 3, 0x120, 0x4FC), + MX51_PIN_NANDF_RB2 = _MXC_BUILD_GPIO_PIN_MX51(2, 10, 3, 0x124, 0x500), + MX51_PIN_NANDF_RB3 = _MXC_BUILD_GPIO_PIN_MX51(2, 11, 3, 0x128, 0x504), + MX51_PIN_GPIO_NAND = _MXC_BUILD_GPIO_PIN_MX51(2, 12, 3, 0x12C, 0x514), + MX51_PIN_NANDF_RB4 = MX51_PIN_GPIO_NAND, + MX51_PIN_NANDF_RB5 = _MXC_BUILD_GPIO_PIN_MX51(2, 13, 3, 0x130, 0x5D8), + MX51_PIN_NANDF_RB6 = _MXC_BUILD_GPIO_PIN_MX51(2, 14, 3, 0x134, 0x5DC), + MX51_PIN_NANDF_RB7 = _MXC_BUILD_GPIO_PIN_MX51(2, 15, 3, 0x138, 0x5E0), + MX51_PIN_NANDF_CS0 = _MXC_BUILD_GPIO_PIN_MX51(2, 16, 3, 0x130, 0x518), + MX51_PIN_NANDF_CS1 = _MXC_BUILD_GPIO_PIN_MX51(2, 17, 3, 0x134, 0x51C), + MX51_PIN_NANDF_CS2 = _MXC_BUILD_GPIO_PIN_MX51(2, 18, 3, 0x138, 0x520), + MX51_PIN_NANDF_CS3 = _MXC_BUILD_GPIO_PIN_MX51(2, 19, 3, 0x13C, 0x524), + MX51_PIN_NANDF_CS4 = _MXC_BUILD_GPIO_PIN_MX51(2, 20, 3, 0x140, 0x528), + MX51_PIN_NANDF_CS5 = _MXC_BUILD_GPIO_PIN_MX51(2, 21, 3, 0x144, 0x52C), + MX51_PIN_NANDF_CS6 = _MXC_BUILD_GPIO_PIN_MX51(2, 22, 3, 0x148, 0x530), + MX51_PIN_NANDF_CS7 = _MXC_BUILD_GPIO_PIN_MX51(2, 23, 3, 0x14C, 0x534), + MX51_PIN_NANDF_RDY_INT = _MXC_BUILD_GPIO_PIN_MX51(2, 24, 3, 0x150, 0x538), + MX51_PIN_NANDF_D15 = _MXC_BUILD_GPIO_PIN_MX51(2, 25, 3, 0x154, 0x53C), + MX51_PIN_NANDF_D14 = _MXC_BUILD_GPIO_PIN_MX51(2, 26, 3, 0x158, 0x540), + MX51_PIN_NANDF_D13 = _MXC_BUILD_GPIO_PIN_MX51(2, 27, 3, 0x15C, 0x544), + MX51_PIN_NANDF_D12 = _MXC_BUILD_GPIO_PIN_MX51(2, 28, 3, 0x160, 0x548), + MX51_PIN_NANDF_D11 = _MXC_BUILD_GPIO_PIN_MX51(2, 29, 3, 0x164, 0x54C), + MX51_PIN_NANDF_D10 = _MXC_BUILD_GPIO_PIN_MX51(2, 30, 3, 0x168, 0x550), + MX51_PIN_NANDF_D9 = _MXC_BUILD_GPIO_PIN_MX51(2, 31, 3, 0x16C, 0x554), + MX51_PIN_NANDF_D8 = _MXC_BUILD_GPIO_PIN_MX51(3, 0, 3, 0x170, 0x558), + MX51_PIN_NANDF_D7 = _MXC_BUILD_GPIO_PIN_MX51(3, 1, 3, 0x174, 0x55C), + MX51_PIN_NANDF_D6 = _MXC_BUILD_GPIO_PIN_MX51(3, 2, 3, 0x178, 0x560), + MX51_PIN_NANDF_D5 = _MXC_BUILD_GPIO_PIN_MX51(3, 3, 3, 0x17C, 0x564), + MX51_PIN_NANDF_D4 = _MXC_BUILD_GPIO_PIN_MX51(3, 4, 3, 0x180, 0x568), + MX51_PIN_NANDF_D3 = _MXC_BUILD_GPIO_PIN_MX51(3, 5, 3, 0x184, 0x56C), + MX51_PIN_NANDF_D2 = _MXC_BUILD_GPIO_PIN_MX51(3, 6, 3, 0x188, 0x570), + MX51_PIN_NANDF_D1 = _MXC_BUILD_GPIO_PIN_MX51(3, 7, 3, 0x18C, 0x574), + MX51_PIN_NANDF_D0 = _MXC_BUILD_GPIO_PIN_MX51(3, 8, 3, 0x190, 0x578), + MX51_PIN_CSI1_D8 = _MXC_BUILD_GPIO_PIN_MX51(2, 12, 3, 0x194, 0x57C), + MX51_PIN_CSI1_D9 = _MXC_BUILD_GPIO_PIN_MX51(2, 13, 3, 0x198, 0x580), + MX51_PIN_CSI1_D10 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x19C, 0x584), + MX51_PIN_CSI1_D11 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1A0, 0x588), + MX51_PIN_CSI1_D12 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1A4, 0x58C), + MX51_PIN_CSI1_D13 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1A8, 0x590), + MX51_PIN_CSI1_D14 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1AC, 0x594), + MX51_PIN_CSI1_D15 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1B0, 0x598), + MX51_PIN_CSI1_D16 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1B4, 0x59C), + MX51_PIN_CSI1_D17 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1B8, 0x5A0), + MX51_PIN_CSI1_D18 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1BC, 0x5A4), + MX51_PIN_CSI1_D19 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x1C0, 0x5A8), + MX51_PIN_CSI1_VSYNC = _MXC_BUILD_GPIO_PIN_MX51(2, 14, 3, 0x1C4, 0x5AC), + MX51_PIN_CSI1_HSYNC = _MXC_BUILD_GPIO_PIN_MX51(2, 15, 3, 0x1C8, 0x5B0), + MX51_PIN_CSI1_PIXCLK = _MXC_BUILD_NON_GPIO_PIN_MX51(NON_MUX_I, 0x5B4), + MX51_PIN_CSI1_MCLK = _MXC_BUILD_NON_GPIO_PIN_MX51(NON_MUX_I, 0x5B8), + MX51_PIN_CSI1_PKE0 = _MXC_BUILD_NON_GPIO_PIN_MX51(NON_MUX_I, 0x860), + MX51_PIN_CSI2_D12 = _MXC_BUILD_GPIO_PIN_MX51(3, 9, 3, 0x1CC, 0x5BC), + MX51_PIN_CSI2_D13 = _MXC_BUILD_GPIO_PIN_MX51(3, 10, 3, 0x1D0, 0x5C0), + MX51_PIN_CSI2_D14 = _MXC_BUILD_GPIO_PIN_MX51(3, 11, 3, 0x1D4, 0x5C4), + MX51_PIN_CSI2_D15 = _MXC_BUILD_GPIO_PIN_MX51(3, 12, 3, 0x1D8, 0x5C8), + MX51_PIN_CSI2_D16 = _MXC_BUILD_GPIO_PIN_MX51(3, 11, 3, 0x1DC, 0x5CC), + MX51_PIN_CSI2_D17 = _MXC_BUILD_GPIO_PIN_MX51(3, 12, 3, 0x1E0, 0x5D0), + MX51_PIN_CSI2_D18 = _MXC_BUILD_GPIO_PIN_MX51(3, 11, 3, 0x1E4, 0x5D4), + MX51_PIN_CSI2_D19 = _MXC_BUILD_GPIO_PIN_MX51(3, 12, 3, 0x1E8, 0x5D8), + MX51_PIN_CSI2_VSYNC = _MXC_BUILD_GPIO_PIN_MX51(3, 13, 3, 0x1EC, 0x5DC), + MX51_PIN_CSI2_HSYNC = _MXC_BUILD_GPIO_PIN_MX51(3, 14, 3, 0x1F0, 0x5E0), + MX51_PIN_CSI2_PIXCLK = _MXC_BUILD_GPIO_PIN_MX51(3, 15, 3, 0x1F4, 0x5E4), + MX51_PIN_CSI2_PKE0 = _MXC_BUILD_NON_GPIO_PIN_MX51(NON_MUX_I, 0x81C), + MX51_PIN_I2C1_CLK = _MXC_BUILD_GPIO_PIN_MX51(3, 16, 3, 0x1F8, 0x5E8), + MX51_PIN_I2C1_DAT = _MXC_BUILD_GPIO_PIN_MX51(3, 17, 3, 0x1FC, 0x5EC), + MX51_PIN_AUD3_BB_TXD = _MXC_BUILD_GPIO_PIN_MX51(3, 18, 3, 0x200, 0x5F0), + MX51_PIN_AUD3_BB_RXD = _MXC_BUILD_GPIO_PIN_MX51(3, 19, 3, 0x204, 0x5F4), + MX51_PIN_AUD3_BB_CK = _MXC_BUILD_GPIO_PIN_MX51(3, 20, 3, 0x208, 0x5F8), + MX51_PIN_AUD3_BB_FS = _MXC_BUILD_GPIO_PIN_MX51(3, 21, 3, 0x20C, 0x5FC), + MX51_PIN_CSPI1_MOSI = _MXC_BUILD_GPIO_PIN_MX51(3, 22, 3, 0x210, 0x600), + MX51_PIN_CSPI1_MISO = _MXC_BUILD_GPIO_PIN_MX51(3, 23, 3, 0x214, 0x604), + MX51_PIN_CSPI1_SS0 = _MXC_BUILD_GPIO_PIN_MX51(3, 24, 3, 0x218, 0x608), + MX51_PIN_CSPI1_SS1 = _MXC_BUILD_GPIO_PIN_MX51(3, 25, 3, 0x21C, 0x60C), + MX51_PIN_CSPI1_RDY = _MXC_BUILD_GPIO_PIN_MX51(3, 26, 3, 0x220, 0x610), + MX51_PIN_CSPI1_SCLK = _MXC_BUILD_GPIO_PIN_MX51(3, 27, 3, 0x224, 0x614), + MX51_PIN_UART1_RXD = _MXC_BUILD_GPIO_PIN_MX51(3, 28, 3, 0x228, 0x618), + MX51_PIN_UART1_TXD = _MXC_BUILD_GPIO_PIN_MX51(3, 29, 3, 0x22C, 0x61C), + MX51_PIN_UART1_RTS = _MXC_BUILD_GPIO_PIN_MX51(3, 30, 3, 0x230, 0x620), + MX51_PIN_UART1_CTS = _MXC_BUILD_GPIO_PIN_MX51(3, 31, 3, 0x234, 0x624), + MX51_PIN_UART2_RXD = _MXC_BUILD_GPIO_PIN_MX51(0, 20, 3, 0x238, 0x628), + MX51_PIN_UART2_TXD = _MXC_BUILD_GPIO_PIN_MX51(0, 21, 3, 0x23C, 0x62C), + MX51_PIN_UART3_RXD = _MXC_BUILD_GPIO_PIN_MX51(0, 22, 3, 0x240, 0x630), + MX51_PIN_UART3_TXD = _MXC_BUILD_GPIO_PIN_MX51(0, 23, 3, 0x244, 0x634), + MX51_PIN_OWIRE_LINE = _MXC_BUILD_GPIO_PIN_MX51(0, 24, 3, 0x248, 0x638), + MX51_PIN_KEY_ROW0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x24C, 0x63C), + MX51_PIN_KEY_ROW1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x250, 0x640), + MX51_PIN_KEY_ROW2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x254, 0x644), + MX51_PIN_KEY_ROW3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x258, 0x648), + MX51_PIN_KEY_COL0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x25C, 0x64C), + MX51_PIN_KEY_COL1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x260, 0x650), + MX51_PIN_KEY_COL2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x264, 0x654), + MX51_PIN_KEY_COL3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x268, 0x658), + MX51_PIN_KEY_COL4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x26C, 0x65C), + MX51_PIN_KEY_COL5 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x270, 0x660), + MX51_PIN_USBH1_CLK = _MXC_BUILD_GPIO_PIN_MX51(0, 25, 2, 0x278, 0x678), + MX51_PIN_USBH1_DIR = _MXC_BUILD_GPIO_PIN_MX51(0, 26, 2, 0x27C, 0x67C), + MX51_PIN_USBH1_STP = _MXC_BUILD_GPIO_PIN_MX51(0, 27, 2, 0x280, 0x680), + MX51_PIN_USBH1_NXT = _MXC_BUILD_GPIO_PIN_MX51(0, 28, 2, 0x284, 0x684), + MX51_PIN_USBH1_DATA0 = _MXC_BUILD_GPIO_PIN_MX51(0, 11, 2, 0x288, 0x688), + MX51_PIN_USBH1_DATA1 = _MXC_BUILD_GPIO_PIN_MX51(0, 12, 2, 0x28C, 0x68C), + MX51_PIN_USBH1_DATA2 = _MXC_BUILD_GPIO_PIN_MX51(0, 13, 2, 0x290, 0x690), + MX51_PIN_USBH1_DATA3 = _MXC_BUILD_GPIO_PIN_MX51(0, 14, 2, 0x294, 0x694), + MX51_PIN_USBH1_DATA4 = _MXC_BUILD_GPIO_PIN_MX51(0, 15, 2, 0x298, 0x698), + MX51_PIN_USBH1_DATA5 = _MXC_BUILD_GPIO_PIN_MX51(0, 16, 2, 0x29C, 0x69C), + MX51_PIN_USBH1_DATA6 = _MXC_BUILD_GPIO_PIN_MX51(0, 17, 2, 0x2A0, 0x6A0), + MX51_PIN_USBH1_DATA7 = _MXC_BUILD_GPIO_PIN_MX51(0, 18, 2, 0x2A4, 0x6A4), + MX51_PIN_DI1_PIN11 = _MXC_BUILD_GPIO_PIN_MX51(2, 0, 4, 0x2A8, 0x6A8), + MX51_PIN_DI1_PIN12 = _MXC_BUILD_GPIO_PIN_MX51(2, 1, 4, 0x2AC, 0x6AC), + MX51_PIN_DI1_PIN13 = _MXC_BUILD_GPIO_PIN_MX51(2, 2, 4, 0x2B0, 0x6B0), + MX51_PIN_DI1_D0_CS = _MXC_BUILD_GPIO_PIN_MX51(2, 3, 4, 0x2B4, 0x6B4), + MX51_PIN_DI1_D1_CS = _MXC_BUILD_GPIO_PIN_MX51(2, 4, 4, 0x2B8, 0x6B8), + MX51_PIN_DISPB2_SER_DIN = _MXC_BUILD_GPIO_PIN_MX51(2, 5, 4, 0x2BC, 0x6BC), + MX51_PIN_DISPB2_SER_DIO = _MXC_BUILD_GPIO_PIN_MX51(2, 6, 4, 0x2C0, 0x6C0), + MX51_PIN_DISPB2_SER_CLK = _MXC_BUILD_GPIO_PIN_MX51(2, 7, 4, 0x2C4, 0x6C4), + MX51_PIN_DISPB2_SER_RS = _MXC_BUILD_GPIO_PIN_MX51(2, 8, 4, 0x2C8, 0x6C8), + MX51_PIN_DISP1_DAT0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2CC, 0x6CC), + MX51_PIN_DISP1_DAT1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2D0, 0x6D0), + MX51_PIN_DISP1_DAT2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2D4, 0x6D4), + MX51_PIN_DISP1_DAT3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2D8, 0x6D8), + MX51_PIN_DISP1_DAT4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2DC, 0x6DC), + MX51_PIN_DISP1_DAT5 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2E0, 0x6E0), + MX51_PIN_DISP1_DAT6 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2E4, 0x6E4), + MX51_PIN_DISP1_DAT7 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2E8, 0x6E8), + MX51_PIN_DISP1_DAT8 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2EC, 0x6EC), + MX51_PIN_DISP1_DAT9 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2F0, 0x6F0), + MX51_PIN_DISP1_DAT10 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2F4, 0x6F4), + MX51_PIN_DISP1_DAT11 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2F8, 0x6F8), + MX51_PIN_DISP1_DAT12 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x2FC, 0x6FC), + MX51_PIN_DISP1_DAT13 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x300, 0x700), + MX51_PIN_DISP1_DAT14 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x304, 0x704), + MX51_PIN_DISP1_DAT15 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x308, 0x708), + MX51_PIN_DISP1_DAT16 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x30C, 0x70C), + MX51_PIN_DISP1_DAT17 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x310, 0x710), + MX51_PIN_DISP1_DAT18 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x314, 0x714), + MX51_PIN_DISP1_DAT19 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x318, 0x718), + MX51_PIN_DISP1_DAT20 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x31C, 0x71C), + MX51_PIN_DISP1_DAT21 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x320, 0x720), + MX51_PIN_DISP1_DAT22 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x324, 0x724), + MX51_PIN_DISP1_DAT23 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x328, 0x728), + MX51_PIN_DI1_PIN3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x32C, 0x72C), + MX51_PIN_DI1_PIN2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x330, 0x734), + MX51_PIN_DI_GP1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x334, 0x73C), + MX51_PIN_DI_GP2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x338, 0x740), + MX51_PIN_DI_GP3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x33C, 0x744), + MX51_PIN_DI2_PIN4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x340, 0x748), + MX51_PIN_DI2_PIN2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x344, 0x74C), + MX51_PIN_DI2_PIN3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x348, 0x750), + MX51_PIN_DI2_DISP_CLK = _MXC_BUILD_NON_GPIO_PIN_MX51(0x34C, 0x754), + MX51_PIN_DI_GP4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x350, 0x758), + MX51_PIN_DISP2_DAT0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x354, 0x75C), + MX51_PIN_DISP2_DAT1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x358, 0x760), + MX51_PIN_DISP2_DAT2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x35C, 0x764), + MX51_PIN_DISP2_DAT3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x360, 0x768), + MX51_PIN_DISP2_DAT4 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x364, 0x76C), + MX51_PIN_DISP2_DAT5 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x368, 0x770), + MX51_PIN_DISP2_DAT6 = _MXC_BUILD_GPIO_PIN_MX51(0, 19, 5, 0x36C, 0x774), + MX51_PIN_DISP2_DAT7 = _MXC_BUILD_GPIO_PIN_MX51(0, 29, 5, 0x370, 0x778), + MX51_PIN_DISP2_DAT8 = _MXC_BUILD_GPIO_PIN_MX51(0, 30, 5, 0x374, 0x77C), + MX51_PIN_DISP2_DAT9 = _MXC_BUILD_GPIO_PIN_MX51(0, 31, 5, 0x378, 0x780), + MX51_PIN_DISP2_DAT10 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x37C, 0x784), + MX51_PIN_DISP2_DAT11 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x380, 0x788), + MX51_PIN_DISP2_DAT12 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x384, 0x78C), + MX51_PIN_DISP2_DAT13 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x388, 0x790), + MX51_PIN_DISP2_DAT14 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x38C, 0x794), + MX51_PIN_DISP2_DAT15 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x390, 0x798), + MX51_PIN_SD1_CMD = _MXC_BUILD_NON_GPIO_PIN_MX51(0x394, 0x79C), + MX51_PIN_SD1_CLK = _MXC_BUILD_NON_GPIO_PIN_MX51(0x398, 0x7A0), + MX51_PIN_SD1_DATA0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x39C, 0x7A4), + MX51_PIN_SD1_DATA1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3A0, 0x7A8), + MX51_PIN_SD1_DATA2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3A4, 0x7AC), + MX51_PIN_SD1_DATA3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3A8, 0x7B0), + MX51_PIN_GPIO1_0 = _MXC_BUILD_GPIO_PIN_MX51(0, 0, 1, 0x3AC, 0x7B4), + MX51_PIN_GPIO1_1 = _MXC_BUILD_GPIO_PIN_MX51(0, 1, 1, 0x3B0, 0x7B8), + MX51_PIN_SD2_CMD = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3B4, 0x7BC), + MX51_PIN_SD2_CLK = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3B8, 0x7C0), + MX51_PIN_SD2_DATA0 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3BC, 0x7C4), + MX51_PIN_SD2_DATA1 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3C0, 0x7C8), + MX51_PIN_SD2_DATA2 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3C4, 0x7CC), + MX51_PIN_SD2_DATA3 = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3C8, 0x7D0), + MX51_PIN_GPIO1_2 = _MXC_BUILD_GPIO_PIN_MX51(0, 2, 0, 0x3CC, 0x7D4), + MX51_PIN_GPIO1_3 = _MXC_BUILD_GPIO_PIN_MX51(0, 3, 0, 0x3D0, 0x7D8), + MX51_PIN_PMIC_INT_REQ = _MXC_BUILD_NON_GPIO_PIN_MX51(0x3D4, 0x7FC), + MX51_PIN_GPIO1_4 = _MXC_BUILD_GPIO_PIN_MX51(0, 4, 0, 0x3D8, 0x804), + MX51_PIN_GPIO1_5 = _MXC_BUILD_GPIO_PIN_MX51(0, 5, 0, 0x3DC, 0x808), + MX51_PIN_GPIO1_6 = _MXC_BUILD_GPIO_PIN_MX51(0, 6, 0, 0x3E0, 0x80C), + MX51_PIN_GPIO1_7 = _MXC_BUILD_GPIO_PIN_MX51(0, 7, 0, 0x3E4, 0x810), + MX51_PIN_GPIO1_8 = _MXC_BUILD_GPIO_PIN_MX51(0, 8, 0, 0x3E8, 0x814), + MX51_PIN_GPIO1_9 = _MXC_BUILD_GPIO_PIN_MX51(0, 9, 0, 0x3EC, 0x818), +}; + +/*! + * various IOMUX input select register index + */ +enum iomux_input_select_mx51 { + MUX_IN_AUDMUX_P4_INPUT_DA_AMX_SELECT_I = 0, + MUX_IN_AUDMUX_P4_INPUT_DB_AMX_SELECT_I, + MUX_IN_AUDMUX_P4_INPUT_TXCLK_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P4_INPUT_TXFS_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P5_INPUT_DA_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P5_INPUT_DB_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P5_INPUT_RXCLK_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P5_INPUT_RXFS_AMX_SELECT, + MUX_IN_AUDMUX_P5_INPUT_TXCLK_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P5_INPUT_TXFS_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_DA_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_DB_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_RXCLK_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_RXFS_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_TXCLK_AMX_SELECT_INPUT, + MUX_IN_AUDMUX_P6_INPUT_TXFS_AMX_SELECT_INPUT, + MUX_IN_CCM_IPP_DI_CLK_SELECT_INPUT, + /* TO2 */ + MUX_IN_CCM_IPP_DI1_CLK_SELECT_INPUT, + MUX_IN_CCM_PLL1_BYPASS_CLK_SELECT_INPUT, + MUX_IN_CCM_PLL2_BYPASS_CLK_SELECT_INPUT, + MUX_IN_CSPI_IPP_CSPI_CLK_IN_SELECT_INPUT, + MUX_IN_CSPI_IPP_IND_MISO_SELECT_INPUT, + MUX_IN_CSPI_IPP_IND_MOSI_SELECT_INPUT, + MUX_IN_CSPI_IPP_IND_SS_B_1_SELECT_INPUT, + MUX_IN_CSPI_IPP_IND_SS_B_2_SELECT_INPUT, + MUX_IN_CSPI_IPP_IND_SS_B_3_SELECT_INPUT, + MUX_IN_DPLLIP1_L1T_TOG_EN_SELECT_INPUT, + /* TO2 */ + MUX_IN_ECSPI2_IPP_IND_SS_B_1_SELECT_INPUT, + MUX_IN_ECSPI2_IPP_IND_SS_B_3_SELECT_INPUT, + MUX_IN_EMI_IPP_IND_RDY_INT_SELECT_INPUT, + MUX_IN_ESDHC3_IPP_DAT0_IN_SELECT_INPUT, + MUX_IN_ESDHC3_IPP_DAT1_IN_SELECT_INPUT, + MUX_IN_ESDHC3_IPP_DAT2_IN_SELECT_INPUT, + MUX_IN_ESDHC3_IPP_DAT3_IN_SELECT_INPUT, + MUX_IN_FEC_FEC_COL_SELECT_INPUT, + MUX_IN_FEC_FEC_CRS_SELECT_INPUT, + MUX_IN_FEC_FEC_MDI_SELECT_INPUT, + MUX_IN_FEC_FEC_RDATA_0_SELECT_INPUT, + MUX_IN_FEC_FEC_RDATA_1_SELECT_INPUT, + MUX_IN_FEC_FEC_RDATA_2_SELECT_INPUT, + MUX_IN_FEC_FEC_RDATA_3_SELECT_INPUT, + MUX_IN_FEC_FEC_RX_CLK_SELECT_INPUT, + MUX_IN_FEC_FEC_RX_DV_SELECT_INPUT, + MUX_IN_FEC_FEC_RX_ER_SELECT_INPUT, + MUX_IN_FEC_FEC_TX_CLK_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_1_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_2_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_3_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_4_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_5_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_7_SELECT_INPUT, + MUX_IN_GPIO3_IPP_IND_G_IN_8_SELECT_INPUT, + /* TO2 */ + MUX_IN_GPIO3_IPP_IND_G_IN_12_SELECT_INPUT, + MUX_IN_HSC_MIPI_MIX_IPP_IND_SENS1_DATA_EN_SELECT_INPUT, + MUX_IN_HSC_MIPI_MIX_IPP_IND_SENS2_DATA_EN_SELECT_INPUT, + /* TO2 */ + MUX_IN_HSC_MIPI_MIX_PAR_VSYNC_SELECT_INPUT, + /* TO2 */ + MUX_IN_HSC_MIPI_MIX_PAR_DI_WAIT_SELECT_INPUT, + MUX_IN_HSC_MIPI_MIX_PAR_SISG_TRIG_SELECT_INPUT, + MUX_IN_I2C1_IPP_SCL_IN_SELECT_INPUT, + MUX_IN_I2C1_IPP_SDA_IN_SELECT_INPUT, + MUX_IN_I2C2_IPP_SCL_IN_SELECT_INPUT, + MUX_IN_I2C2_IPP_SDA_IN_SELECT_INPUT, + + MUX_IN_IPU_IPP_DI_0_IND_DISPB_SD_D_SELECT_INPUT, + + MUX_IN_IPU_IPP_DI_1_IND_DISPB_SD_D_SELECT_INPUT, + + MUX_IN_KPP_IPP_IND_COL_6_SELECT_INPUT, + MUX_IN_KPP_IPP_IND_COL_7_SELECT_INPUT, + MUX_IN_KPP_IPP_IND_ROW_4_SELECT_INPUT, + MUX_IN_KPP_IPP_IND_ROW_5_SELECT_INPUT, + MUX_IN_KPP_IPP_IND_ROW_6_SELECT_INPUT, + MUX_IN_KPP_IPP_IND_ROW_7_SELECT_INPUT, + MUX_IN_UART1_IPP_UART_RTS_B_SELECT_INPUT, + MUX_IN_UART1_IPP_UART_RXD_MUX_SELECT_INPUT, + MUX_IN_UART2_IPP_UART_RTS_B_SELECT_INPUT, + MUX_IN_UART2_IPP_UART_RXD_MUX_SELECT_INPUT, + MUX_IN_UART3_IPP_UART_RTS_B_SELECT_INPUT, + MUX_IN_UART3_IPP_UART_RXD_MUX_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_CLK_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_0_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_1_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_2_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_3_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_4_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_5_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_6_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DATA_7_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_DIR_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_NXT_SELECT_INPUT, + MUX_IN_USBOH3_IPP_IND_UH3_STP_SELECT_INPUT, + MUX_INPUT_NUM_MUX, +}; + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_ARCH_MXC_MX51_PINS_H__ */ diff --git a/arch/arm/mach-mx5/mx53_ard.c b/arch/arm/mach-mx5/mx53_ard.c new file mode 100644 index 000000000000..dd59608dd338 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_ard.c @@ -0,0 +1,1322 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <mach/common.h> +#include <mach/hardware.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 <asm/mach/keypad.h> +#include <asm/mach/flash.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx53.h> +#include <mach/i2c.h> +#include <mach/mxc_iim.h> + +#include "crm_regs.h" +#include "devices.h" +#include "usb.h" + +#define ARD_SD1_CD (0*32 + 1) /* GPIO_1_1 */ +#define ARD_SD2_WP (0*32 + 2) /* GPIO_1_2 */ +#define ARD_SD2_CD (0*32 + 4) /* GPIO_1_4 */ +#define ARD_VIDEOIN_INT_B (0*32 + 7) /* GPIO_1_7 */ +#define ARD_SD1_WP (0*32 + 9) /* GPIO_1_9 */ +#define ARD_PMIC_RDY (0*32 + 24) /* GPIO_1_24 */ + + +#define ARD_CAN1_NERR_B (1*32 + 0) /* GPIO_2_0 */ +#define ARD_CAN2_NERR_B (1*32 + 1) /* GPIO_2_1 */ +#define ARD_VIDEOIN_PWR (1*32 + 2) /* GPIO_2_2 */ +#define ARD_I2CPORTEXP_B (1*32 + 3) /* GPIO_2_3 */ +#define ARD_ESAI_INT (1*32 + 4) /* GPIO_2_4 */ +#define ARD_GPS_PWREN (1*32 + 5) /* GPIO_2_5 */ +#define ARD_GPS_INT_B (1*32 + 6) /* GPIO_2_6 */ +#define ARD_MLB_INT (1*32 + 7) /* GPIO_2_7 */ +#define ARD_ETHERNET_INT_B (1*32 + 31) /* GPIO_2_31 */ + +#define ARD_SATE_REQ (3*32 + 0) /* GPIO_4_0 */ +#define ARD_USBH1_OC (3*32 + 1) /* GPIO_4_1 */ +#define ARD_USBH2_OC (3*32 + 2) /* GPIO_4_2 */ +#define ARD_USBH1_PWR (3*32 + 3) /* GPIO_4_3 */ +#define ARD_USER_LED (3*32 + 4) /* GPIO_4_4 */ +#define ARD_FPGA_INT_B (3*32 + 5) /* GPIO_4_5 */ +#define ARD_USBH2_PHYRST_B (3*32 + 14) /* GPIO_4_14 */ +#define ARD_CAN_STBY (3*32 + 15) /* GPIO_4_15 */ +#define ARD_PWM1_OFF (3*32 + 29) /* GPIO_4_29 */ +#define ARD_PWM2_OFF (3*32 + 30) /* GPIO_4_30 */ + +#define ARD_USBOTG_PWR (4*32 + 2) /* GPIO_5_2 */ +#define ARD_USBOTG_OC (4*32 + 4) /* GPIO_5_4 */ +#define ARD_PMIC_INT (4*32 + 7) /* GPIO_5_7 */ +#define ARD_PMIC_PBSTAT (4*32 + 8) /* GPIO_5_8 */ +#define ARD_MLB_PWRDN (4*32 + 9) /* GPIO_5_9 */ + +#define ARD_CAN_EN (6*32 + 6) /* GPIO_7_6 */ +#define ARD_TS_INT (6*32 + 12) /* GPIO_7_12 */ +#define ARD_SD1_LCTL (6*32 + 13) /* GPIO_7_13 */ + +/* Start directly after the CPU's GPIO*/ +#define MAX7310_BASE_ADDR 224 /* 7x32 */ +#define ARD_BACKLIGHT_ON MAX7310_BASE_ADDR +#define ARD_SPARE (MAX7310_BASE_ADDR + 1) +#define ARD_CPU_PER_RST_B (MAX7310_BASE_ADDR + 2) +#define ARD_MAIN_PER_RST_B (MAX7310_BASE_ADDR + 3) +#define ARD_IPOD_RST_B (MAX7310_BASE_ADDR + 4) +#define ARD_MLB_RST_B (MAX7310_BASE_ADDR + 5) +#define ARD_SSI_STEERING (MAX7310_BASE_ADDR + 6) +#define ARD_GPS_RST_B (MAX7310_BASE_ADDR + 7) + +/*! + * @file mach-mx53/mx53_ard.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX53 + */ + +static struct pad_desc mx53ard_pads[] = { + /* UART1 */ + MX53_PAD_ATA_DIOW__UART1_TXD, + MX53_PAD_ATA_DMACK__UART1_RXD, + + /* UART2 */ + MX53_PAD_ATA_BUFFER_EN__UART2_RXD, + MX53_PAD_ATA_DMARQ__UART2_TXD, + MX53_PAD_ATA_DIOR__UART2_RTS, + MX53_PAD_ATA_INTRQ__UART2_CTS, + + /* UART3 */ + MX53_PAD_ATA_CS_0__UART3_TXD, + MX53_PAD_ATA_CS_1__UART3_RXD, + MX53_PAD_ATA_DA_1__UART3_CTS, + MX53_PAD_ATA_DA_2__UART3_RTS, + + /* PMIC */ + MX53_PAD_DISP0_DAT13__GPIO_5_7, + MX53_PAD_FEC_RX_ER__GPIO_1_24, + MX53_PAD_DISP0_DAT14__GPIO_5_8, + + /* USBOTG_OC and USBOTG_PWR */ + MX53_PAD_EIM_A24__GPIO_5_4, + MX53_PAD_EIM_A25__GPIO_5_2, + + /* USBH */ + MX53_PAD_GPIO_11__GPIO_4_1, + MX53_PAD_GPIO_12__GPIO_4_2, + MX53_PAD_GPIO_13__GPIO_4_3, + MX53_PAD_KEY_COL4__GPIO_4_14, + + /* MAINBRD_SPDIF_IN */ + MX53_PAD_KEY_COL3__SPDIF_IN1, + + /* CAN */ + MX53_PAD_KEY_COL2__TXCAN1, + MX53_PAD_KEY_ROW2__RXCAN1, + MX53_PAD_ATA_RESET_B__TXCAN2, + MX53_PAD_ATA_IORDY__RXCAN2, + + /* CAN1, CAN2 -- EN */ + MX53_PAD_ATA_DA_0__GPIO_7_6, + /* CAN1, CAN2 -- STBY */ + MX53_PAD_KEY_ROW4__GPIO_4_15, + /* CAN1 -- NERR */ + MX53_PAD_ATA_DATA0__GPIO_2_0, + /* CAN2 -- NERR */ + MX53_PAD_ATA_DATA1__GPIO_2_1, + + MX53_PAD_DISP0_DAT0__USBH2_DAT0, + MX53_PAD_DISP0_DAT1__USBH2_DAT1, + MX53_PAD_DISP0_DAT2__USBH2_DAT2, + MX53_PAD_DISP0_DAT3__USBH2_DAT3, + MX53_PAD_DISP0_DAT4__USBH2_DAT4, + MX53_PAD_DISP0_DAT5__USBH2_DAT5, + MX53_PAD_DISP0_DAT6__USBH2_DAT6, + MX53_PAD_DISP0_DAT7__USBH2_DAT7, + MX53_PAD_DISP0_DAT8__PWM1, + MX53_PAD_DISP0_DAT9__PWM2, + MX53_PAD_DISP0_DAT10__USBH2_STP, + MX53_PAD_DISP0_DAT11__USBH2_NXT, + MX53_PAD_DISP0_DAT12__USBH2_CLK, + MX53_PAD_DI0_DISP_CLK__USBH2_DIR, + + MX53_PAD_LVDS0_TX3_P__LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LVDS0_TX0, + + MX53_PAD_LVDS1_TX3_P__LVDS1_TX3, + MX53_PAD_LVDS1_CLK_P__LVDS1_CLK, + MX53_PAD_LVDS1_TX2_P__LVDS1_TX2, + MX53_PAD_LVDS1_TX1_P__LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LVDS1_TX0, + + /* Bluetooth */ + MX53_PAD_DISP0_DAT23__AUD4_SSI_RXD, + MX53_PAD_DISP0_DAT21__AUD4_TXD, + MX53_PAD_DISP0_DAT20__AUD4_TXC, + MX53_PAD_DISP0_DAT22__AUD4_TXFS, + + /* Video in */ + MX53_PAD_CSI0_D4__CSI0_D4, + MX53_PAD_CSI0_D5__CSI0_D5, + MX53_PAD_CSI0_D6__CSI0_D6, + MX53_PAD_CSI0_D7__CSI0_D7, + MX53_PAD_CSI0_D8__CSI0_D8, + MX53_PAD_CSI0_D9__CSI0_D9, + MX53_PAD_CSI0_D10__CSI0_D10, + MX53_PAD_CSI0_D11__CSI0_D11, + MX53_PAD_CSI0_D12__CSI0_D12, + MX53_PAD_CSI0_D13__CSI0_D13, + MX53_PAD_CSI0_D14__CSI0_D14, + MX53_PAD_CSI0_D15__CSI0_D15, + MX53_PAD_CSI0_D16__CSI0_D16, + MX53_PAD_CSI0_D17__CSI0_D17, + MX53_PAD_CSI0_D18__CSI0_D18, + MX53_PAD_CSI0_D19__CSI0_D19, + + MX53_PAD_CSI0_VSYNC__CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK, + + /* VIDEO_ADC_PWRDN_B */ + MX53_PAD_GPIO_7__GPIO_1_7, + MX53_PAD_ATA_DATA2__GPIO_2_2, + + /* MLB */ + MX53_PAD_FEC_TXD1__MLBCLK, + MX53_PAD_FEC_MDC__MLBDAT, + MX53_PAD_GPIO_6__MLBSIG, + MX53_PAD_ATA_DATA7__GPIO_2_7, + MX53_PAD_DISP0_DAT15__GPIO_5_9, + + /* esdhc1 */ + MX53_PAD_SD1_CMD__SD1_CMD, + MX53_PAD_SD1_CLK__SD1_CLK, + MX53_PAD_SD1_DATA0__SD1_DATA0, + MX53_PAD_SD1_DATA1__SD1_DATA1, + MX53_PAD_SD1_DATA2__SD1_DATA2, + MX53_PAD_SD1_DATA3__SD1_DATA3, + MX53_PAD_ATA_DATA8__SD1_DATA4, + MX53_PAD_ATA_DATA9__SD1_DATA5, + MX53_PAD_ATA_DATA10__SD1_DATA6, + MX53_PAD_ATA_DATA11__SD1_DATA7, + MX53_PAD_GPIO_1__GPIO_1_1, + MX53_PAD_GPIO_9__GPIO_1_9, + + /* esdhc2 */ + MX53_PAD_SD2_DATA0__SD2_DAT0, + MX53_PAD_SD2_DATA1__SD2_DAT1, + MX53_PAD_SD2_DATA2__SD2_DAT2, + MX53_PAD_SD2_DATA3__SD2_DAT3, + MX53_PAD_ATA_DATA12__SD2_DAT4, + MX53_PAD_ATA_DATA13__SD2_DAT5, + MX53_PAD_ATA_DATA14__SD2_DAT6, + MX53_PAD_ATA_DATA15__SD2_DAT7, + MX53_PAD_SD2_CLK__SD2_CLK, + MX53_PAD_SD2_CMD__SD2_CMD, + MX53_PAD_GPIO_4__GPIO_1_4, + MX53_PAD_GPIO_2__GPIO_1_2, + + /* WEIM for CS1 */ + /* ETHERNET_INT_B */ + MX53_PAD_EIM_EB3__GPIO_2_31, + MX53_PAD_EIM_D16__EIM_D16, + MX53_PAD_EIM_D17__EIM_D17, + MX53_PAD_EIM_D18__EIM_D18, + MX53_PAD_EIM_D19__EIM_D19, + MX53_PAD_EIM_D20__EIM_D20, + MX53_PAD_EIM_D21__EIM_D21, + MX53_PAD_EIM_D22__EIM_D22, + MX53_PAD_EIM_D23__EIM_D23, + MX53_PAD_EIM_D24__EIM_D24, + MX53_PAD_EIM_D25__EIM_D25, + MX53_PAD_EIM_D26__EIM_D26, + MX53_PAD_EIM_D27__EIM_D27, + MX53_PAD_EIM_D28__EIM_D28, + MX53_PAD_EIM_D29__EIM_D29, + MX53_PAD_EIM_D30__EIM_D30, + MX53_PAD_EIM_D31__EIM_D31, + MX53_PAD_EIM_DA0__EIM_DA0, + MX53_PAD_EIM_DA1__EIM_DA1, + MX53_PAD_EIM_DA2__EIM_DA2, + MX53_PAD_EIM_DA3__EIM_DA3, + MX53_PAD_EIM_DA4__EIM_DA4, + MX53_PAD_EIM_DA5__EIM_DA5, + MX53_PAD_EIM_DA6__EIM_DA6, + MX53_PAD_EIM_OE__EIM_OE, + MX53_PAD_EIM_RW__EIM_RW, + MX53_PAD_EIM_CS1__EIM_CS1, + + /* I2C2 */ + MX53_PAD_EIM_EB2__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + + /* I2C3 */ + MX53_PAD_GPIO_3__I2C3_SCL, + MX53_PAD_GPIO_16__I2C3_SDA, + + /* TOUCH_INT_B */ + MX53_PAD_GPIO_17__GPIO_7_12, + + /* Tuner */ + MX53_PAD_DI0_PIN15__AUD6_TXC, + MX53_PAD_DI0_PIN4__AUD6_RXD, + MX53_PAD_DI0_PIN3__AUD6_TXFS, + + /* FPGA */ + MX53_PAD_EIM_A23__EIM_A23, + MX53_PAD_GPIO_19__GPIO_4_5, + + /* eCSPI */ + MX53_PAD_DISP0_DAT16__ECSPI2_MOSI, + MX53_PAD_DISP0_DAT17__ECSPI2_MISO, + MX53_PAD_DISP0_DAT18__ECSPI2_SS0, + MX53_PAD_DISP0_DAT19__ECSPI2_SCLK, + + /* NAND */ + MX53_PAD_NANDF_CLE__NANDF_CLE, + MX53_PAD_NANDF_ALE__NANDF_ALE, + MX53_PAD_NANDF_WP_B__NANDF_WP_B, + MX53_PAD_NANDF_WE_B__NANDF_WE_B, + MX53_PAD_NANDF_RE_B__NANDF_RE_B, + MX53_PAD_NANDF_RB0__NANDF_RB0, + MX53_PAD_NANDF_CS0__NANDF_CS0, + MX53_PAD_NANDF_CS1__NANDF_CS1 , + MX53_PAD_EIM_DA0__EIM_DA0, + MX53_PAD_EIM_DA1__EIM_DA1, + MX53_PAD_EIM_DA2__EIM_DA2, + MX53_PAD_EIM_DA3__EIM_DA3, + MX53_PAD_EIM_DA4__EIM_DA4, + MX53_PAD_EIM_DA5__EIM_DA5, + MX53_PAD_EIM_DA6__EIM_DA6, + MX53_PAD_EIM_DA7__EIM_DA7, + + /* IO Port Expander */ + MX53_PAD_ATA_DATA3__GPIO_2_3, + + /* GPS */ + MX53_PAD_GPIO_0__CLKO, + MX53_PAD_ATA_DATA5__GPIO_2_5, + MX53_PAD_ATA_DATA6__GPIO_2_6, + + MX53_PAD_GPIO_10__GPIO_4_0, + MX53_PAD_GPIO_14__GPIO_4_4, + MX53_PAD_GPIO_18__GPIO_7_13, + MX53_PAD_GPIO_19__GPIO_4_5, + + /* EIM_WAIT, EIM_OE ... */ +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 1600x1200 @ 60 Hz 162M pixel clk*/ + "UXGA", 60, 1600, 1200, 6172, + 304, 64, + 1, 46, + 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, + 0,}, + /* 2 LVDS modes, had better remove from here */ + { + "1080P60", 60, 1920, 1080, 7692, + 100, 40, + 30, 3, + 10, 2, + 0, + FB_VMODE_NONINTERLACED, + 0,}, + { + "XGA", 60, 1024, 768, 15385, + 220, 40, + 21, 7, + 60, 10, + 0, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct pad_desc mx53_ard_pwm_pads[] = { + MX53_PAD_DISP0_DAT8__PWM1, + MX53_PAD_DISP0_DAT9__PWM2, + MX53_PAD_DISP0_DAT8__GPIO_4_29, + MX53_PAD_DISP0_DAT9__GPIO_4_30, +}; + +static void enable_pwm1_pad(void) +{ + mxc_iomux_v3_setup_pad(&mx53_ard_pwm_pads[0]); +} + +static void disable_pwm1_pad(void) +{ + mxc_iomux_v3_setup_pad(&mx53_ard_pwm_pads[2]); + + gpio_request(ARD_PWM2_OFF, "pwm2-off"); + gpio_direction_output(ARD_PWM2_OFF, 1); + gpio_free(ARD_PWM2_OFF); +} + +static struct mxc_pwm_platform_data mxc_pwm1_platform_data = { + .pwmo_invert = 1, + .enable_pwm_pad = enable_pwm1_pad, + .disable_pwm_pad = disable_pwm1_pad, +}; + +static struct platform_pwm_backlight_data mxc_pwm1_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 5000000, +}; + +static void enable_pwm2_pad(void) +{ + mxc_iomux_v3_setup_pad(&mx53_ard_pwm_pads[1]); +} + +static void disable_pwm2_pad(void) +{ + mxc_iomux_v3_setup_pad(&mx53_ard_pwm_pads[3]); + + gpio_request(ARD_PWM2_OFF, "pwm2-off"); + gpio_direction_output(ARD_PWM2_OFF, 1); + gpio_free(ARD_PWM2_OFF); +} + +static struct mxc_pwm_platform_data mxc_pwm2_platform_data = { + .pwmo_invert = 1, + .enable_pwm_pad = enable_pwm2_pad, + .disable_pwm_pad = disable_pwm2_pad, +}; + +static struct platform_pwm_backlight_data mxc_pwm2_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 5000000, +}; + +static void flexcan_xcvr_enable(int id, int en) +{ + if (id < 0 || id > 1) + return; + + if (en) + gpio_set_value(ARD_CAN_EN, 1); + else + gpio_set_value(ARD_CAN_EN, 0); +} + +static struct flexcan_platform_data flexcan0_data = { + .core_reg = NULL, + .io_reg = NULL, + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 1, + .br_rjw = 2, + .br_presdiv = 5, + .br_propseg = 5, + .br_pseg1 = 4, + .br_pseg2 = 7, + .bcc = 1, + .srx_dis = 1, + .smp = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; +static struct flexcan_platform_data flexcan1_data = { + .core_reg = NULL, + .io_reg = NULL, + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 1, + .br_rjw = 2, + .br_presdiv = 5, + .br_propseg = 5, + .br_pseg1 = 4, + .br_pseg2 = 7, + .bcc = 1, + .srx_dis = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; + + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 3, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, +}; + +static struct imxi2c_platform_data mxci2c1_data = { + .bitrate = 50000, +}; + +static struct imxi2c_platform_data mxci2c2_data = { + .bitrate = 400000, +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +static struct ldb_platform_data ldb_data = { + .ext_ref = 1, +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +static struct pad_desc mx53_ard_esai_pads[] = { + MX53_PAD_FEC_MDIO__ESAI_SCKR, + MX53_PAD_FEC_REF_CLK__ESAI_FSR, + MX53_PAD_FEC_CRS_DV__ESAI_SCKT, + MX53_PAD_FEC_RXD1__ESAI_FST, + MX53_PAD_FEC_TX_EN__ESAI_TX3_RX2, + MX53_PAD_GPIO_5__ESAI_TX2_RX3, + MX53_PAD_FEC_TXD0__ESAI_TX4_RX1, + MX53_PAD_GPIO_8__ESAI_TX5_RX0, + MX53_PAD_NANDF_CS2__ESAI_TX0, + MX53_PAD_NANDF_CS3__ESAI_TX1, + MX53_PAD_ATA_DATA4__GPIO_2_4, +}; + + +void ard_gpio_activate_esai_ports(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_ard_esai_pads, + ARRAY_SIZE(mx53_ard_esai_pads)); + /* ESAI_INT */ + gpio_request(ARD_ESAI_INT, "esai-int"); + gpio_direction_input(ARD_ESAI_INT); + +} + +static struct mxc_esai_platform_data esai_data = { + .activate_esai_ports = ard_gpio_activate_esai_ports, +}; + +static void mx53_ard_usbotg_driver_vbus(bool on) +{ + if (on) + gpio_set_value(ARD_USBOTG_PWR, 1); + else + gpio_set_value(ARD_USBOTG_PWR, 0); +} + +static void mx53_ard_host1_driver_vbus(bool on) +{ + if (on) + gpio_set_value(ARD_USBH1_PWR, 1); + else + gpio_set_value(ARD_USBH1_PWR, 0); +} + +static void adv7180_pwdn(int pwdn) +{ + gpio_request(ARD_VIDEOIN_PWR, "tvin-pwr"); + if (pwdn) + gpio_set_value(ARD_VIDEOIN_PWR, 0); + else + gpio_set_value(ARD_VIDEOIN_PWR, 1); + gpio_free(ARD_VIDEOIN_PWR); +} + +static struct mxc_tvin_platform_data adv7180_data = { + .dvddio_reg = NULL, + .dvdd_reg = NULL, + .avdd_reg = NULL, + .pvdd_reg = NULL, + .pwdn = adv7180_pwdn, + .reset = NULL, + .cvbs = true, +}; + +static struct resource mxcfb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "800x480M@55", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, + { + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +extern int primary_di; +static int __init mxc_init_fb(void) +{ + if (!machine_is_mx53_ard()) + return 0; + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); + +static struct mxc_audio_codec_platform_data cs42888_data = { + .analog_regulator = NULL, +}; + +static int mx53_ard_max7310_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + static int max7310_gpio_value[] = { + 1, 1, 1, 1, 0, 0, 0, 0, + }; + int n; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 GPIO Expander"); + if (max7310_gpio_value[n] < 0) + gpio_direction_input(gpio_base + n); + else + gpio_direction_output(gpio_base + n, + max7310_gpio_value[n]); + /* Export, direction locked down */ + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data mx53_i2c_max7310_platdata = { + .gpio_base = MAX7310_BASE_ADDR, + .invert = 0, /* Do not invert */ + .setup = mx53_ard_max7310_setup, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "cs42888", + .addr = 0x48, + .platform_data = &cs42888_data, + }, + { + .type = "ipod", + .addr = 0x10, + }, + { + .type = "tuner", + .addr = 0x62, + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + .type = "max11801", + .addr = 0x49, + .irq = IOMUX_TO_IRQ_V3(ARD_TS_INT), + }, + { + .type = "max7310", + .addr = 0x18, + .platform_data = &mx53_i2c_max7310_platdata, + }, + { + .type = "mlb", + .addr = 0x20, + }, + { + .type = "adv7180", + .addr = 0x21, + .platform_data = (void *)&adv7180_data, + }, +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0],}, +}; + +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(ARD_SD1_WP); + else + rc = gpio_get_value(ARD_SD2_WP); + + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret; + if (to_platform_device(dev)->id == 0) { + ret = gpio_get_value(ARD_SD1_CD); + } else{ /* config the det pin for SDHC2 */ + ret = gpio_get_value(ARD_SD2_CD); + } + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 | MMC_CAP_8_BIT_DATA, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +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 | MMC_CAP_8_BIT_DATA, + .min_clk = 400000, + .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 ard_smsc911x_resources[] = { + { + .start = MX53_CS1_BASE_ADDR, + .end = MX53_CS1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IOMUX_TO_IRQ_V3(ARD_ETHERNET_INT_B), + .end = IOMUX_TO_IRQ_V3(ARD_ETHERNET_INT_B), + .flags = IORESOURCE_IRQ, + }, +}; + +struct smsc911x_platform_config ard_smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT, +}; + +static struct platform_device ard_smsc_lan9220_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(ard_smsc911x_resources), + .resource = ard_smsc911x_resources, +}; + +static struct mxc_mlb_platform_data mlb_data = { + .reg_nvcc = NULL, + .mlb_clk = "mlb_clk", +}; + +/* NAND Flash Partitions */ +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition nand_flash_partitions[] = { +/* MX53 ROM require the boot FCB/DBBT support which need + * more space to store such info on NAND boot partition. + * 16M should cover all kind of NAND boot support on MX53. + */ + { + .name = "bootloader", + .offset = 0, + .size = 16 * 1024 * 1024}, + { + .name = "nand.kernel", + .offset = MTDPART_OFS_APPEND, + .size = 5 * 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 = MTDPART_SIZ_FULL}, +}; +#endif + +static int nand_init(void) +{ + u32 i, reg; + void __iomem *base; + + #define M4IF_GENP_WEIM_MM_MASK 0x00000001 + #define WEIM_GCR2_MUX16_BYP_GRANT_MASK 0x00001000 + + base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); + reg = __raw_readl(base + 0xc); + reg &= ~M4IF_GENP_WEIM_MM_MASK; + __raw_writel(reg, base + 0xc); + + iounmap(base); + + base = ioremap(MX53_BASE_ADDR(WEIM_BASE_ADDR), SZ_4K); + for (i = 0x4; i < 0x94; i += 0x18) { + reg = __raw_readl((u32)base + i); + reg &= ~WEIM_GCR2_MUX16_BYP_GRANT_MASK; + __raw_writel(reg, (u32)base + i); + } + + iounmap(base); + + return 0; +} + +static struct flash_platform_data mxc_nand_data = { +#ifdef CONFIG_MTD_PARTITIONS + .parts = nand_flash_partitions, + .nr_parts = ARRAY_SIZE(nand_flash_partitions), +#endif + .width = 1, + .init = nand_init, +}; + +static struct mxc_asrc_platform_data mxc_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2. +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 0, + .spdif_rx = 1, + .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* Source from CKIH2 for 48k and 32k */ + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, + .sysclk = 24576000, +}; + + +static struct platform_device mxc_alsa_surround_device = { + .name = "imx-3stack-cs42888", +}; + +/*! + * 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) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_1G; + int left_mem = 0; + int gpu_mem = SZ_128M; + int fb_mem = SZ_32M; + char *str; + + mxc_set_cpu_type(MXC_CPU_MX53); + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_device.resource[5].start = + mem_tag->u.mem.start + left_mem; + gpu_device.resource[5].end = + gpu_device.resource[5].start + gpu_mem - 1; +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ + defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) + if (fb_mem) { + mxcfb_resources[0].start = + gpu_device.resource[5].end + 1; + mxcfb_resources[0].end = + mxcfb_resources[0].start + fb_mem - 1; + } else { + mxcfb_resources[0].start = 0; + mxcfb_resources[0].end = 0; + } +#endif + } +} + +static void __init mx53_ard_io_init(void) +{ + /* MX53 ARD board */ + pr_info("MX53 ARD board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53ard_pads, + ARRAY_SIZE(mx53ard_pads)); + + /* USBOTG_OC */ + gpio_request(ARD_USBOTG_OC, "otg-oc"); + gpio_direction_input(ARD_USBOTG_OC); + /* USBOTG_PWR */ + gpio_request(ARD_USBOTG_PWR, "otg-pwr"); + gpio_direction_output(ARD_USBOTG_PWR, 1); + + gpio_request(ARD_USBH1_OC, "usbh1-oc"); + gpio_direction_input(ARD_USBH1_OC); + + gpio_request(ARD_USBH2_OC, "usbh2-oc"); + gpio_direction_input(ARD_USBH2_OC); + + gpio_request(ARD_USBH1_PWR, "usbh1-pwr"); + gpio_direction_output(ARD_USBH1_PWR, 1); + + gpio_request(ARD_USBH2_PHYRST_B, "usbh2-phyrst"); + gpio_direction_output(ARD_USBH2_PHYRST_B, 1); + + gpio_request(ARD_SD1_CD, "sdhc1-cd"); + gpio_direction_input(ARD_SD1_CD); /* SD1 CD */ + gpio_request(ARD_SD1_WP, "sdhc1-wp"); + gpio_direction_input(ARD_SD1_WP); /* SD1 WP */ + + /* SD2 CD */ + gpio_request(ARD_SD2_CD, "sdhc2-cd"); + gpio_direction_input(ARD_SD2_CD); + + /* SD2 WP */ + gpio_request(ARD_SD2_WP, "sdhc2-wp"); + gpio_direction_input(ARD_SD2_WP); + + gpio_request(ARD_PMIC_INT, "pmic-int"); + gpio_direction_input(ARD_PMIC_INT); /*PMIC_INT*/ + gpio_request(ARD_PMIC_RDY, "pmic-rdy"); + gpio_direction_input(ARD_PMIC_RDY); /*PMIC_RDY*/ + gpio_request(ARD_PMIC_PBSTAT, "pmic-pbstat"); + gpio_direction_input(ARD_PMIC_PBSTAT); /*PMIC_PBSTAT*/ + + /* CAN1 enable GPIO*/ + gpio_request(ARD_CAN_EN, "can-en"); + gpio_direction_output(ARD_CAN_EN, 0); + + gpio_request(ARD_CAN_STBY, "can-stby"); + gpio_direction_output(ARD_CAN_STBY, 0); + + gpio_request(ARD_CAN1_NERR_B, "can1-nerr"); + gpio_direction_input(ARD_CAN1_NERR_B); + + gpio_request(ARD_CAN2_NERR_B, "can2-nerr"); + gpio_direction_input(ARD_CAN2_NERR_B); + + gpio_request(ARD_VIDEOIN_PWR, "videoin-pwr"); + gpio_direction_output(ARD_VIDEOIN_PWR, 0); + + gpio_request(ARD_I2CPORTEXP_B, "i2cptexp-rst"); + gpio_direction_output(ARD_I2CPORTEXP_B, 1); + + gpio_request(ARD_GPS_PWREN, "gps-pwren"); + gpio_direction_output(ARD_GPS_PWREN, 1); + + gpio_request(ARD_GPS_INT_B, "gps-int"); + gpio_direction_input(ARD_GPS_INT_B); + + gpio_request(ARD_MLB_INT, "mlb-int"); + gpio_direction_input(ARD_MLB_INT); + + gpio_request(ARD_MLB_PWRDN, "mlb-pwrdn"); + gpio_direction_input(ARD_MLB_PWRDN); + + gpio_request(ARD_ETHERNET_INT_B, "eth-int-b"); + gpio_direction_input(ARD_ETHERNET_INT_B); + + gpio_request(ARD_FPGA_INT_B, "fpga-int"); + gpio_direction_input(ARD_FPGA_INT_B); + + gpio_request(ARD_TS_INT, "ts-int"); + gpio_direction_input(ARD_TS_INT); + gpio_free(ARD_TS_INT); +} + +/* Config CS1 settings for ethernet controller */ +static void weim_cs_config(void) +{ + u32 reg; + void __iomem *weim_base, *iomuxc_base; + + weim_base = ioremap(MX53_BASE_ADDR(WEIM_BASE_ADDR), SZ_4K); + iomuxc_base = ioremap(MX53_BASE_ADDR(IOMUXC_BASE_ADDR), SZ_4K); + + /* CS1 timings for LAN9220 */ + writel(0x20001, (weim_base + 0x18)); + writel(0x0, (weim_base + 0x1C)); + writel(0x16000202, (weim_base + 0x20)); + writel(0x00000002, (weim_base + 0x24)); + writel(0x16002082, (weim_base + 0x28)); + writel(0x00000000, (weim_base + 0x2C)); + writel(0x00000000, (weim_base + 0x90)); + + /* specify 64 MB on CS1 and CS0 on GPR1 */ + reg = readl(iomuxc_base + 0x4); + reg &= ~0x3F; + reg |= 0x1B; + writel(reg, (iomuxc_base + 0x4)); + + iounmap(iomuxc_base); + iounmap(weim_base); +} + +static int mxc_read_mac_iim(void) +{ + struct clk *iim_clk; + void __iomem *iim_base = IO_ADDRESS(IIM_BASE_ADDR); + void __iomem *iim_mac_base = iim_base + \ + MXC_IIM_MX53_BANK_AREA_1_OFFSET + \ + MXC_IIM_MX53_MAC_ADDR_OFFSET; + int i; + + iim_clk = clk_get(NULL, "iim_clk"); + + if (!iim_clk) { + printk(KERN_ERR "Could not get IIM clk to read MAC fuses!\n"); + return ~EINVAL; + } + + clk_enable(iim_clk); + + for (i = 0; i < 6; i++) + ard_smsc911x_config.mac[i] = readl(iim_mac_base + (i*4)); + + clk_disable(iim_clk); + return 0; +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "ssi_ext1_clk"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(ARD_SD2_CD); + mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(ARD_SD2_CD); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(ARD_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(ARD_SD1_CD); + + mxc_cpu_common_init(); + + mx53_ard_io_init(); + weim_cs_config(); + mxc_read_mac_iim(); + mxc_register_device(&ard_smsc_lan9220_device, &ard_smsc911x_config); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c1_data); + mxc_register_device(&mxci2c_devices[2], &mxci2c2_data); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_ldb_device, &ldb_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxcscc_device, NULL); + + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, &bus_freq_data); + + mxc_register_device(&mxc_iim_device, &iim_data); + + mxc_register_device(&mxc_pwm1_device, &mxc_pwm1_platform_data); + mxc_register_device(&mxc_pwm1_backlight_device, + &mxc_pwm1_backlight_data); + + mxc_register_device(&mxc_pwm2_device, &mxc_pwm2_platform_data); + mxc_register_device(&mxc_pwm2_backlight_device, + &mxc_pwm2_backlight_data); + + mxc_register_device(&mxc_flexcan0_device, &flexcan0_data); + mxc_register_device(&mxc_flexcan1_device, &flexcan1_data); + + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + + mxc_register_device(&ahci_fsl_device, &sata_data); + + /* ASRC is only available for MX53 TO2.0 */ + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + mxc_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + clk_put(mxc_asrc_data.asrc_core_clk); + mxc_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + clk_put(mxc_asrc_data.asrc_audio_clk); + mxc_register_device(&mxc_asrc_device, &mxc_asrc_data); + } + + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + mxc_register_device(&mxc_mlb_device, &mlb_data); + mx5_set_otghost_vbus_func(mx53_ard_usbotg_driver_vbus); + mx5_usb_dr_init(); + mx5_set_host1_vbus_func(mx53_ard_host1_driver_vbus); + mx5_usbh1_init(); + mx5_usbh2_init(); + mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); + mxc_register_device(&mxc_esai_device, &esai_data); + mxc_register_device(&mxc_alsa_surround_device, + &mxc_surround_audio_data); + + mxc_register_device(&mxc_v4l2out_device, NULL); + mxc_register_device(&mxc_v4l2_device, NULL); +} + +static void __init mx53_ard_timer_init(void) +{ + struct clk *uart_clk; + + mx53_clocks_init(32768, 24000000, 22579200, 24576000); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx53_ard_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX53_ARD data structure. + */ +MACHINE_START(MX53_ARD, "Freescale MX53 ARD Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx53_ard_pmic_ltc3589.c b/arch/arm/mach-mx5/mx53_ard_pmic_ltc3589.c new file mode 100644 index 000000000000..02538815d2a4 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_ard_pmic_ltc3589.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * mx53_ard_pmic_ltc3589.c -- i.MX53 ARD Driver for Linear LTC3589 + * PMIC + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/regulator/ltc3589.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/ltc3589/core.h> +#include <mach/iomux-mx53.h> +#include <mach/irqs.h> + +#define ARD_PMIC_INT (4*32 + 7) /* GPIO_5_7 */ + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +struct ltc3589; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = 564000, + .max_uV = 1167000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = 704000, + .max_uV = 1456000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = 1342000, + .max_uV = 2775000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .apply_uV = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data ldo1_init = { + .constraints = { + .name = "LDO1_STBY", + .apply_uV = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo2_init = { + .constraints = { + .name = "LDO2", + .min_uV = 704000, + .max_uV = 1456000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo3_init = { + .constraints = { + .name = "LDO3", + .apply_uV = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data ldo4_init = { + .constraints = { + .name = "LDO4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .always_on = 1, + .boot_on = 1, + }, +}; + +static void ltc3589_nop_release(struct device *dev) +{ + /* Nothing */ +} + +static struct platform_device ltc3589_regulator_device[] = { + { + .name = "ltc3589-dev", + .id = 0, + .dev = { + .release = ltc3589_nop_release, + }, + }, +}; + +static int mx53_ltc3589_init(struct ltc3589 *ltc3589) +{ + int i; + + printk(KERN_INFO "Initializing regulators for ARD\n"); + for (i = 0; i < ARRAY_SIZE(ltc3589_regulator_device); i++) { + if (platform_device_register(<c3589_regulator_device[i]) < 0) + dev_err(<c3589_regulator_device[i].dev, + "Unable to register LTC3589 device\n"); + } + + ltc3589_register_regulator(ltc3589, LTC3589_SW1, &sw1_init); + ltc3589_register_regulator(ltc3589, LTC3589_SW2, &sw2_init); + ltc3589_register_regulator(ltc3589, LTC3589_SW3, &sw3_init); + ltc3589_register_regulator(ltc3589, LTC3589_SW4, &sw4_init); + ltc3589_register_regulator(ltc3589, LTC3589_LDO1, &ldo1_init); + ltc3589_register_regulator(ltc3589, LTC3589_LDO2, &ldo2_init); + ltc3589_register_regulator(ltc3589, LTC3589_LDO3, &ldo3_init); + ltc3589_register_regulator(ltc3589, LTC3589_LDO4, &ldo4_init); + + return 0; +} + +static struct ltc3589_platform_data __initdata ltc3589_plat = { + .init = mx53_ltc3589_init, +}; + +static struct i2c_board_info __initdata ltc3589_i2c_device = { + I2C_BOARD_INFO("ltc3589", 0x34), + .irq = IOMUX_TO_IRQ_V3(ARD_PMIC_INT), + .platform_data = <c3589_plat, +}; + +static __init int mx53_init_i2c(void) +{ + return i2c_register_board_info(1, <c3589_i2c_device, 1); +} + +subsys_initcall(mx53_init_i2c); + +static __init int ltc3589_pmic_init(void) +{ + int i = 0; + int ret = 0; + struct regulator *regulator; + + char *ltc3589_global_regulator[] = { + "SW1", + "SW2", + "SW3", + "SW4", + "LDO1_STBY", + "LDO2", + "LDO3", + "LDO4", + }; + + while ((i < ARRAY_SIZE(ltc3589_global_regulator)) && + !IS_ERR_VALUE( + (unsigned long)(regulator = + regulator_get(NULL, + ltc3589_global_regulator + [i])))) { + regulator_enable(regulator); + i++; + } + + return ret; +} + +late_initcall(ltc3589_pmic_init); + diff --git a/arch/arm/mach-mx5/mx53_evk.c b/arch/arm/mach-mx5/mx53_evk.c new file mode 100644 index 000000000000..092aec5498d0 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_evk.c @@ -0,0 +1,1562 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/powerkey.h> +#include <mach/common.h> +#include <mach/hardware.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 <asm/mach/keypad.h> +#include <asm/mach/flash.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx53.h> +#include <mach/i2c.h> +#include <mach/mxc_iim.h> + +#include "crm_regs.h" +#include "devices.h" +#include "usb.h" + +#define ARM2_SD1_CD (0*32 + 1) /* GPIO_1_1 */ + +#define MX53_HP_DETECT (1*32 + 5) /* GPIO_2_5 */ + +#define EVK_SD3_CD (2*32 + 11) /* GPIO_3_11 */ +#define EVK_SD3_WP (2*32 + 12) /* GPIO_3_12 */ +#define EVK_SD1_CD (2*32 + 13) /* GPIO_3_13 */ +#define EVK_SD1_WP (2*32 + 14) /* GPIO_3_14 */ +#define ARM2_OTG_VBUS (2*32 + 22) /* GPIO_3_22 */ +#define MX53_DVI_PD (2*32 + 24) /* GPIO_3_24 */ +#define EVK_TS_INT (2*32 + 26) /* GPIO_3_26 */ +#define MX53_DVI_I2C (2*32 + 28) /* GPIO_3_28 */ +#define MX53_DVI_DETECT (2*32 + 31) /* GPIO_3_31 */ + +#define MX53_CAM_RESET (3*32 + 0) /* GPIO_4_0 */ +#define MX53_ESAI_RESET (3*32 + 2) /* GPIO_4_2 */ +#define MX53_CAN2_EN2 (3*32 + 4) /* GPIO_4_4 */ +#define MX53_12V_EN (3*32 + 5) /* GPIO_4_5 */ +#define ARM2_LCD_CONTRAST (3*32 + 20) /* GPIO_4_20 */ + +#define MX53_DVI_RESET (4*32 + 0) /* GPIO_5_0 */ +#define EVK_USB_HUB_RESET (4*32 + 20) /* GPIO_5_20 */ +#define MX53_TVIN_PWR (4*32 + 23) /* GPIO_5_23 */ +#define MX53_CAN2_EN1 (4*32 + 24) /* GPIO_5_24 */ +#define MX53_TVIN_RESET (4*32 + 25) /* GPIO_5_25 */ + +#define EVK_OTG_VBUS (5*32 + 6) /* GPIO_6_6 */ + +#define EVK_FEC_PHY_RESET (6*32 + 6) /* GPIO_7_6 */ +#define EVK_USBH1_VBUS (6*32 + 8) /* GPIO_7_8 */ +#define MX53_PMIC_INT (6*32 + 11) /* GPIO_7_11 */ +#define MX53_CAN1_EN1 (6*32 + 12) /* GPIO_7_12 */ +#define MX53_CAN1_EN2 (6*32 + 13) /* GPIO_7_13 */ + +/*! + * @file mach-mx53/mx53_evk.c + * + * @brief This file contains the board specific initialization routines. + * + * @ingroup MSL_MX53 + */ +extern int __init mx53_evk_init_mc13892(void); + +static struct pad_desc mx53common_pads[] = { + MX53_PAD_EIM_WAIT__GPIO_5_0, + + MX53_PAD_EIM_OE__DI1_PIN7, + MX53_PAD_EIM_RW__DI1_PIN8, + + MX53_PAD_EIM_A25__DI0_D1_CS, + + MX53_PAD_EIM_D16__CSPI1_SCLK, + MX53_PAD_EIM_D17__CSPI1_MISO, + MX53_PAD_EIM_D18__CSPI1_MOSI, + + MX53_PAD_EIM_D20__SER_DISP0_CS, + + MX53_PAD_EIM_D23__DI0_D0_CS, + + MX53_PAD_EIM_D24__GPIO_3_24, + MX53_PAD_EIM_D26__GPIO_3_26, + + MX53_PAD_EIM_D29__DISPB0_SER_RS, + + MX53_PAD_EIM_D30__DI0_PIN11, + MX53_PAD_EIM_D31__DI0_PIN12, + + MX53_PAD_ATA_DA_1__GPIO_7_7, + MX53_PAD_ATA_DATA4__GPIO_2_4, + MX53_PAD_ATA_DATA5__GPIO_2_5, + MX53_PAD_ATA_DATA6__GPIO_2_6, + + MX53_PAD_SD2_CLK__SD2_CLK, + MX53_PAD_SD2_CMD__SD2_CMD, + MX53_PAD_SD2_DATA0__SD2_DAT0, + MX53_PAD_SD2_DATA1__SD2_DAT1, + MX53_PAD_SD2_DATA2__SD2_DAT2, + MX53_PAD_SD2_DATA3__SD2_DAT3, + MX53_PAD_ATA_DATA12__SD2_DAT4, + MX53_PAD_ATA_DATA13__SD2_DAT5, + MX53_PAD_ATA_DATA14__SD2_DAT6, + MX53_PAD_ATA_DATA15__SD2_DAT7, + + MX53_PAD_CSI0_D10__UART1_TXD, + MX53_PAD_CSI0_D11__UART1_RXD, + + MX53_PAD_ATA_BUFFER_EN__UART2_RXD, + MX53_PAD_ATA_DMARQ__UART2_TXD, + MX53_PAD_ATA_DIOR__UART2_RTS, + MX53_PAD_ATA_INTRQ__UART2_CTS, + + MX53_PAD_ATA_CS_0__UART3_TXD, + MX53_PAD_ATA_CS_1__UART3_RXD, + + MX53_PAD_KEY_COL0__AUD5_TXC, + MX53_PAD_KEY_ROW0__AUD5_TXD, + MX53_PAD_KEY_COL1__AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUD5_RXD, + + MX53_PAD_CSI0_D7__GPIO_5_25, + + MX53_PAD_GPIO_2__MLBDAT, + MX53_PAD_GPIO_3__MLBCLK, + + MX53_PAD_GPIO_6__MLBSIG, + + MX53_PAD_GPIO_4__GPIO_1_4, + MX53_PAD_GPIO_7__GPIO_1_7, + MX53_PAD_GPIO_8__GPIO_1_8, + + MX53_PAD_GPIO_10__GPIO_4_0, + + MX53_PAD_KEY_COL2__TXCAN1, + MX53_PAD_KEY_ROW2__RXCAN1, + + /* CAN1 -- EN */ + MX53_PAD_GPIO_18__GPIO_7_13, + /* CAN1 -- STBY */ + MX53_PAD_GPIO_17__GPIO_7_12, + /* CAN1 -- NERR */ + MX53_PAD_GPIO_5__GPIO_1_5, + + MX53_PAD_KEY_COL4__TXCAN2, + MX53_PAD_KEY_ROW4__RXCAN2, + + /* CAN2 -- EN */ + MX53_PAD_CSI0_D6__GPIO_5_24, + /* CAN2 -- STBY */ + MX53_PAD_GPIO_14__GPIO_4_4, + /* CAN2 -- NERR */ + MX53_PAD_CSI0_D4__GPIO_5_22, + + MX53_PAD_GPIO_11__GPIO_4_1, + MX53_PAD_GPIO_12__GPIO_4_2, + MX53_PAD_GPIO_13__GPIO_4_3, + MX53_PAD_GPIO_16__GPIO_7_11, + MX53_PAD_GPIO_19__GPIO_4_5, + + /* DI0 display clock */ + MX53_PAD_DI0_DISP_CLK__DI0_DISP_CLK, + + /* DI0 data enable */ + MX53_PAD_DI0_PIN15__DI0_PIN15, + /* DI0 HSYNC */ + MX53_PAD_DI0_PIN2__DI0_PIN2, + /* DI0 VSYNC */ + MX53_PAD_DI0_PIN3__DI0_PIN3, + + MX53_PAD_DISP0_DAT0__DISP0_DAT0, + MX53_PAD_DISP0_DAT1__DISP0_DAT1, + MX53_PAD_DISP0_DAT2__DISP0_DAT2, + MX53_PAD_DISP0_DAT3__DISP0_DAT3, + MX53_PAD_DISP0_DAT4__DISP0_DAT4, + MX53_PAD_DISP0_DAT5__DISP0_DAT5, + MX53_PAD_DISP0_DAT6__DISP0_DAT6, + MX53_PAD_DISP0_DAT7__DISP0_DAT7, + MX53_PAD_DISP0_DAT8__DISP0_DAT8, + MX53_PAD_DISP0_DAT9__DISP0_DAT9, + MX53_PAD_DISP0_DAT10__DISP0_DAT10, + MX53_PAD_DISP0_DAT11__DISP0_DAT11, + MX53_PAD_DISP0_DAT12__DISP0_DAT12, + MX53_PAD_DISP0_DAT13__DISP0_DAT13, + MX53_PAD_DISP0_DAT14__DISP0_DAT14, + MX53_PAD_DISP0_DAT15__DISP0_DAT15, + MX53_PAD_DISP0_DAT16__DISP0_DAT16, + MX53_PAD_DISP0_DAT17__DISP0_DAT17, + MX53_PAD_DISP0_DAT18__DISP0_DAT18, + MX53_PAD_DISP0_DAT19__DISP0_DAT19, + MX53_PAD_DISP0_DAT20__DISP0_DAT20, + MX53_PAD_DISP0_DAT21__DISP0_DAT21, + MX53_PAD_DISP0_DAT22__DISP0_DAT22, + MX53_PAD_DISP0_DAT23__DISP0_DAT23, + + MX53_PAD_LVDS0_TX3_P__LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LVDS0_TX0, + + MX53_PAD_LVDS1_TX3_P__LVDS1_TX3, + MX53_PAD_LVDS1_CLK_P__LVDS1_CLK, + MX53_PAD_LVDS1_TX2_P__LVDS1_TX2, + MX53_PAD_LVDS1_TX1_P__LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LVDS1_TX0, + + /* audio and CSI clock out */ + MX53_PAD_GPIO_0__SSI_EXT1_CLK, + + MX53_PAD_CSI0_D12__CSI0_D12, + MX53_PAD_CSI0_D13__CSI0_D13, + MX53_PAD_CSI0_D14__CSI0_D14, + MX53_PAD_CSI0_D15__CSI0_D15, + MX53_PAD_CSI0_D16__CSI0_D16, + MX53_PAD_CSI0_D17__CSI0_D17, + MX53_PAD_CSI0_D18__CSI0_D18, + MX53_PAD_CSI0_D19__CSI0_D19, + + MX53_PAD_CSI0_VSYNC__CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK, + /* Camera low power */ + MX53_PAD_CSI0_D5__GPIO_5_23, + + /* esdhc1 */ + MX53_PAD_SD1_CMD__SD1_CMD, + MX53_PAD_SD1_CLK__SD1_CLK, + MX53_PAD_SD1_DATA0__SD1_DATA0, + MX53_PAD_SD1_DATA1__SD1_DATA1, + MX53_PAD_SD1_DATA2__SD1_DATA2, + MX53_PAD_SD1_DATA3__SD1_DATA3, + + /* esdhc3 */ + MX53_PAD_ATA_DATA8__SD3_DAT0, + MX53_PAD_ATA_DATA9__SD3_DAT1, + MX53_PAD_ATA_DATA10__SD3_DAT2, + MX53_PAD_ATA_DATA11__SD3_DAT3, + MX53_PAD_ATA_DATA0__SD3_DAT4, + MX53_PAD_ATA_DATA1__SD3_DAT5, + MX53_PAD_ATA_DATA2__SD3_DAT6, + MX53_PAD_ATA_DATA3__SD3_DAT7, + MX53_PAD_ATA_RESET_B__SD3_CMD, + MX53_PAD_ATA_IORDY__SD3_CLK, + + /* FEC pins */ + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_REF_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_CRS_DV, + MX53_PAD_FEC_RXD1__FEC_RXD1, + MX53_PAD_FEC_RXD0__FEC_RXD0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TXD1, + MX53_PAD_FEC_TXD0__FEC_TXD0, + MX53_PAD_FEC_MDC__FEC_MDC, + + MX53_PAD_CSI0_D8__I2C1_SDA, + MX53_PAD_CSI0_D9__I2C1_SCL, + + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, +}; + +static struct pad_desc mx53evk_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_A24__GPIO_5_4, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_A23__GPIO_6_6, + + /* DISPB0_SER_CLK */ + MX53_PAD_EIM_D21__DISPB0_SER_CLK, + + /* DI0_PIN1 */ + MX53_PAD_EIM_D22__DISPB0_SER_DIN, + + /* DVI I2C ENABLE */ + MX53_PAD_EIM_D28__GPIO_3_28, + + /* DVI DET */ + MX53_PAD_EIM_D31__GPIO_3_31, + + /* SDHC1 SD_CD */ + MX53_PAD_EIM_DA13__GPIO_3_13, + + /* SDHC1 SD_WP */ + MX53_PAD_EIM_DA14__GPIO_3_14, + + /* SDHC3 SD_CD */ + MX53_PAD_EIM_DA11__GPIO_3_11, + + /* SDHC3 SD_WP */ + MX53_PAD_EIM_DA12__GPIO_3_12, + + /* PWM backlight */ + MX53_PAD_GPIO_1__PWMO, + + /* USB HOST USB_PWR */ + MX53_PAD_ATA_DA_2__GPIO_7_8, + + /* USB HOST USB_RST */ + MX53_PAD_CSI0_DATA_EN__GPIO_5_20, + + /* USB HOST CARD_ON */ + MX53_PAD_EIM_DA15__GPIO_3_15, + + /* USB HOST CARD_RST */ + MX53_PAD_ATA_DATA7__GPIO_2_7, + + /* USB HOST WAN_WAKE */ + MX53_PAD_EIM_D25__GPIO_3_25, + + /* FEC_RST */ + MX53_PAD_ATA_DA_0__GPIO_7_6, +}; + +static struct pad_desc mx53arm2_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_D21__GPIO_3_21, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_D22__GPIO_3_22, + + /* SDHC1 SD_CD */ + MX53_PAD_GPIO_1__GPIO_1_1, + + /* gpio backlight */ + MX53_PAD_DI0_PIN4__GPIO_4_20, +}; + +static struct pad_desc mx53_nand_pads[] = { + MX53_PAD_NANDF_CLE__NANDF_CLE, + MX53_PAD_NANDF_ALE__NANDF_ALE, + MX53_PAD_NANDF_WP_B__NANDF_WP_B, + MX53_PAD_NANDF_WE_B__NANDF_WE_B, + MX53_PAD_NANDF_RE_B__NANDF_RE_B, + MX53_PAD_NANDF_RB0__NANDF_RB0, + MX53_PAD_NANDF_CS0__NANDF_CS0, + MX53_PAD_NANDF_CS1__NANDF_CS1 , + MX53_PAD_NANDF_CS2__NANDF_CS2, + MX53_PAD_NANDF_CS3__NANDF_CS3 , + MX53_PAD_EIM_DA0__EIM_DA0, + MX53_PAD_EIM_DA1__EIM_DA1, + MX53_PAD_EIM_DA2__EIM_DA2, + MX53_PAD_EIM_DA3__EIM_DA3, + MX53_PAD_EIM_DA4__EIM_DA4, + MX53_PAD_EIM_DA5__EIM_DA5, + MX53_PAD_EIM_DA6__EIM_DA6, + MX53_PAD_EIM_DA7__EIM_DA7, +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 1600x1200 @ 60 Hz 162M pixel clk*/ + "UXGA", 60, 1600, 1200, 6172, + 304, 64, + 1, 46, + 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, + 0,}, + /* 2 LVDS modes, had better remove from here */ + { + "1080P60", 60, 1920, 1080, 7692, + 100, 40, + 30, 3, + 10, 2, + 0, + FB_VMODE_NONINTERLACED, + 0,}, + { + "XGA", 60, 1024, 768, 15385, + 220, 40, + 21, 7, + 60, 10, + 0, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_w1_config mxc_w1_data = { + .search_rom_accelerator = 1, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static void flexcan_xcvr_enable(int id, int en) +{ + static int pwdn; + if (id < 0 || id > 1) + return; + + if (en) { + if (!(pwdn++)) + gpio_set_value(MX53_12V_EN, 1); + + if (id == 0) { + gpio_set_value(MX53_CAN1_EN1, 1); + gpio_set_value(MX53_CAN1_EN2, 1); + } else { + gpio_set_value(MX53_CAN2_EN1, 1); + gpio_set_value(MX53_CAN2_EN2, 1); + } + + } else { + if (!(--pwdn)) + gpio_set_value(MX53_12V_EN, 0); + + if (id == 0) { + gpio_set_value(MX53_CAN1_EN1, 0); + gpio_set_value(MX53_CAN1_EN2, 0); + } else { + gpio_set_value(MX53_CAN2_EN1, 0); + gpio_set_value(MX53_CAN2_EN2, 0); + } + } +} + +static struct flexcan_platform_data flexcan0_data = { + .core_reg = NULL, + .io_reg = NULL, + .root_clk_id = "lp_apm", /*lp_apm is 24MHz */ + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 0, + .br_rjw = 2, + .br_presdiv = 3, + .br_propseg = 2, + .br_pseg1 = 3, + .br_pseg2 = 3, + .bcc = 1, + .srx_dis = 1, + .smp = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; +static struct flexcan_platform_data flexcan1_data = { + .core_reg = NULL, + .io_reg = NULL, + .root_clk_id = "lp_apm", /*lp_apm is 24MHz */ + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 0, + .br_rjw = 2, + .br_presdiv = 3, + .br_propseg = 2, + .br_pseg1 = 3, + .br_pseg2 = 3, + .bcc = 1, + .srx_dis = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; + + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 3, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx53_evk_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + { + struct pad_desc eim_d19_gpio = MX53_PAD_EIM_D19__GPIO_3_19; + struct pad_desc cspi_ss0 = MX53_PAD_EIM_EB2__CSPI_SS0; + + /* de-select SS1 of instance: ecspi1. */ + mxc_iomux_v3_setup_pad(&eim_d19_gpio); + mxc_iomux_v3_setup_pad(&cspi_ss0); + } + break; + case 0x2: + { + struct pad_desc eim_eb2_gpio = MX53_PAD_EIM_EB2__GPIO_2_30; + struct pad_desc cspi_ss1 = MX53_PAD_EIM_D19__CSPI_SS1; + + /* de-select SS0 of instance: ecspi1. */ + mxc_iomux_v3_setup_pad(&eim_eb2_gpio); + mxc_iomux_v3_setup_pad(&cspi_ss1); + } + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx53_evk_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + break; + case 0x2: + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = mx53_evk_gpio_spi_chipselect_active, + .chipselect_inactive = mx53_evk_gpio_spi_chipselect_inactive, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "SW1", + .lp_reg_id = "SW2", +}; + +static struct tve_platform_data tve_data = { + .dac_reg = "VVIDEO", +}; + +static struct ldb_platform_data ldb_data = { + .lvds_bg_reg = "VAUDIO", + .ext_ref = 1, +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +static struct pad_desc mx53esai_pads[] = { + MX53_PAD_FEC_MDIO__ESAI_SCKR, + MX53_PAD_FEC_REF_CLK__ESAI_FSR, + MX53_PAD_FEC_RX_ER__ESAI_HCKR, + MX53_PAD_FEC_CRS_DV__ESAI_SCKT, + MX53_PAD_FEC_RXD1__ESAI_FST, + MX53_PAD_FEC_RXD0__ESAI_HCKT, + MX53_PAD_FEC_TX_EN__ESAI_TX3_RX2, + MX53_PAD_FEC_TXD1__ESAI_TX2_RX3, + MX53_PAD_FEC_TXD0__ESAI_TX4_RX1, + MX53_PAD_FEC_MDC__ESAI_TX5_RX0, + MX53_PAD_NANDF_CS2__ESAI_TX0, + MX53_PAD_NANDF_CS3__ESAI_TX1, +}; + +void gpio_activate_esai_ports(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53esai_pads, + ARRAY_SIZE(mx53esai_pads)); +} + +static struct mxc_esai_platform_data esai_data = { + .activate_esai_ports = gpio_activate_esai_ports, +}; + +void gpio_cs42888_pdwn(int pdwn) +{ + if (pdwn) + gpio_set_value(MX53_ESAI_RESET, 0); + else + gpio_set_value(MX53_ESAI_RESET, 1); +} + +static void gpio_usbotg_vbus_active(void) +{ + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + /* Enable OTG VBus with GPIO low */ + gpio_set_value(ARM2_OTG_VBUS, 0); + } else if (board_is_mx53_evk_a()) { + /* MX53 EVK board ver A*/ + /* Enable OTG VBus with GPIO low */ + gpio_set_value(EVK_OTG_VBUS, 0); + } else if (board_is_mx53_evk_b()) { + /* MX53 EVK board ver B*/ + /* Enable OTG VBus with GPIO high */ + gpio_set_value(EVK_OTG_VBUS, 1); + } +} + +static void gpio_usbotg_vbus_inactive(void) +{ + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + /* Disable OTG VBus with GPIO high */ + gpio_set_value(ARM2_OTG_VBUS, 1); + } else if (board_is_mx53_evk_a()) { + /* MX53 EVK board ver A*/ + /* Disable OTG VBus with GPIO high */ + gpio_set_value(EVK_OTG_VBUS, 1); + } else if (board_is_mx53_evk_b()) { + /* MX53 EVK board ver B*/ + /* Disable OTG VBus with GPIO low */ + gpio_set_value(EVK_OTG_VBUS, 0); + } +} + +static void mx53_gpio_usbotg_driver_vbus(bool on) +{ + if (on) + gpio_usbotg_vbus_active(); + else + gpio_usbotg_vbus_inactive(); +} + +static void mx53_gpio_host1_driver_vbus(bool on) +{ + if (on) + gpio_set_value(EVK_USBH1_VBUS, 1); + else + gpio_set_value(EVK_USBH1_VBUS, 0); +} + +static void adv7180_pwdn(int pwdn) +{ + gpio_request(MX53_TVIN_PWR, "tvin-pwr"); + if (pwdn) + gpio_set_value(MX53_TVIN_PWR, 0); + else + gpio_set_value(MX53_TVIN_PWR, 1); + gpio_free(MX53_TVIN_PWR); +} + +static struct mxc_tvin_platform_data adv7180_data = { + .dvddio_reg = NULL, + .dvdd_reg = NULL, + .avdd_reg = NULL, + .pvdd_reg = NULL, + .pwdn = adv7180_pwdn, + .reset = NULL, +}; + +static struct resource mxcfb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "800x480M@55", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, + { + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +extern int primary_di; +static int __init mxc_init_fb(void) +{ + if (!machine_is_mx53_evk()) + return 0; + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); + +static void camera_pwdn(int pwdn) +{ + gpio_request(MX53_TVIN_PWR, "tvin-pwr"); + gpio_set_value(MX53_TVIN_PWR, pwdn); + gpio_free(MX53_TVIN_PWR); +} + +static struct mxc_camera_platform_data camera_data = { + .analog_regulator = "VSD", + .gpo_regulator = "VVIDEO", + .mclk = 24000000, + .csi = 0, + .pwdn = camera_pwdn, +}; + +static struct mxc_audio_codec_platform_data cs42888_data = { + .analog_regulator = "VSD", + .pwdn = gpio_cs42888_pdwn, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "ov3640", + .addr = 0x3C, + .platform_data = (void *)&camera_data, + }, + { + .type = "adv7180", + .addr = 0x21, + .platform_data = (void *)&adv7180_data, + }, + { + .type = "cs42888", + .addr = 0x48, + .platform_data = &cs42888_data, + }, +}; + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX53_DVI_RESET, 0); + msleep(10); + gpio_set_value(MX53_DVI_RESET, 1); + msleep(10); +} + +static struct mxc_lcd_platform_data sii902x_hdmi_data = { + .reset = sii902x_hdmi_reset, +}; + +/* TO DO add platform data */ +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "tsc2007", + .addr = 0x48, + .irq = IOMUX_TO_IRQ_V3(EVK_TS_INT), + }, + { + .type = "backlight-i2c", + .addr = 0x2c, + }, + { + .type = "vga-ddc", + .addr = 0x1f, + }, + { + .type = "eeprom", + .addr = 0x50, + }, + { + .type = "sii902x", + .addr = 0x39, + .irq = IOMUX_TO_IRQ_V3(MX53_DVI_DETECT), + .platform_data = &sii902x_hdmi_data, + }, +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0],}, +}; + +static int sdhc_write_protect(struct device *dev) +{ + unsigned short rc = 0; + + if (!board_is_mx53_arm2()) { + if (to_platform_device(dev)->id == 0) + rc = gpio_get_value(EVK_SD1_WP); + else + rc = gpio_get_value(EVK_SD3_WP); + } + + return rc; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret; + if (board_is_mx53_arm2()) { + if (to_platform_device(dev)->id == 0) + ret = gpio_get_value(ARM2_SD1_CD); + else + ret = 1; + } else { + if (to_platform_device(dev)->id == 0) { + ret = gpio_get_value(EVK_SD1_CD); + } else{ /* config the det pin for SDHC3 */ + ret = gpio_get_value(EVK_SD3_CD); + } + } + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +static struct mxc_mmc_platform_data mmc3_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 | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static int mxc_sgtl5000_amp_enable(int enable) +{ +/* TO DO */ +return 0; +} + +static int headphone_det_status(void) +{ + return (gpio_get_value(MX53_HP_DETECT) == 0); +} + +static int mxc_sgtl5000_init(void); + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .hp_irq = IOMUX_TO_IRQ(MX53_HP_DETECT), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .init = mxc_sgtl5000_init, +}; + +static int mxc_sgtl5000_init(void) +{ + struct clk *ssi_ext1; + int rate; + + if (board_is_mx53_arm2()) { + sgtl5000_data.sysclk = 12000000; + } else { + ssi_ext1 = clk_get(NULL, "ssi_ext1_clk"); + if (IS_ERR(ssi_ext1)) + return -1; + + rate = clk_round_rate(ssi_ext1, 24000000); + if (rate < 8000000 || rate > 27000000) { + printk(KERN_ERR "Error: SGTL5000 mclk freq %d out of range!\n", + rate); + clk_put(ssi_ext1); + return -1; + } + + clk_set_rate(ssi_ext1, rate); + clk_enable(ssi_ext1); + sgtl5000_data.sysclk = rate; + } + + return 0; +} + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static struct mxc_mlb_platform_data mlb_data = { + .reg_nvcc = "VCAM", + .mlb_clk = "mlb_clk", +}; + +static void mxc_register_powerkey(pwrkey_callback pk_cb) +{ + pmic_event_callback_t power_key_event; + + power_key_event.param = (void *)1; + power_key_event.func = (void *)pk_cb; + pmic_event_subscribe(EVENT_PWRONI, power_key_event); +} + +static int mxc_pwrkey_getstatus(int id) +{ + int sense; + + pmic_read_reg(REG_INT_SENSE1, &sense, 0xffffffff); + if (sense & (1 << 3)) + return 0; + + return 1; +} + +static struct power_key_platform_data pwrkey_data = { + .key_value = KEY_F4, + .register_pwrkey = mxc_register_powerkey, + .get_key_status = mxc_pwrkey_getstatus, +}; + +/* NAND Flash Partitions */ +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition nand_flash_partitions[] = { +/* MX53 ROM require the boot FCB/DBBT support which need + * more space to store such info on NAND boot partition. + * 16M should cover all kind of NAND boot support on MX53. + */ + { + .name = "bootloader", + .offset = 0, + .size = 16 * 1024 * 1024}, + { + .name = "nand.kernel", + .offset = MTDPART_OFS_APPEND, + .size = 5 * 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 = MTDPART_SIZ_FULL}, +}; +#endif + +static int nand_init(void) +{ + u32 i, reg; + void __iomem *base; + + #define M4IF_GENP_WEIM_MM_MASK 0x00000001 + #define WEIM_GCR2_MUX16_BYP_GRANT_MASK 0x00001000 + + base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); + reg = __raw_readl(base + 0xc); + reg &= ~M4IF_GENP_WEIM_MM_MASK; + __raw_writel(reg, base + 0xc); + + iounmap(base); + + base = ioremap(MX53_BASE_ADDR(WEIM_BASE_ADDR), SZ_4K); + for (i = 0x4; i < 0x94; i += 0x18) { + reg = __raw_readl((u32)base + i); + reg &= ~WEIM_GCR2_MUX16_BYP_GRANT_MASK; + __raw_writel(reg, (u32)base + i); + } + + iounmap(base); + + return 0; +} + +static struct flash_platform_data mxc_nand_data = { +#ifdef CONFIG_MTD_PARTITIONS + .parts = nand_flash_partitions, + .nr_parts = ARRAY_SIZE(nand_flash_partitions), +#endif + .width = 1, + .init = nand_init, +}; + +static struct mxc_asrc_platform_data mxc_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* Source from CKIH2 for 48k and 32k */ + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, + .sysclk = 22579200, +}; + + +static struct platform_device mxc_alsa_surround_device = { + .name = "imx-3stack-cs42888", +}; + +static int __initdata mxc_apc_on = { 0 }; /* OFF: 0 (default), ON: 1 */ +static int __init apc_setup(char *__unused) +{ + mxc_apc_on = 1; + printk(KERN_INFO "Automotive Port Card is Plugged on\n"); + return 1; +} +__setup("apc", apc_setup); + +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx53(); +} +__setup("w1", w1_setup); + + +static int __initdata enable_spdif = { 0 }; +static int __init spdif_setup(char *__unused) +{ + enable_spdif = 1; + return 1; +} +__setup("spdif", spdif_setup); + +/*! + * 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) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_1G; + int left_mem = 0; + int gpu_mem = SZ_128M; + int fb_mem = SZ_32M; + char *str; + + mxc_set_cpu_type(MXC_CPU_MX53); + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_device.resource[5].start = + mem_tag->u.mem.start + left_mem; + gpu_device.resource[5].end = + gpu_device.resource[5].start + gpu_mem - 1; +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ + defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) + if (fb_mem) { + mxcfb_resources[0].start = + gpu_device.resource[5].end + 1; + mxcfb_resources[0].end = + mxcfb_resources[0].start + fb_mem - 1; + } else { + mxcfb_resources[0].start = 0; + mxcfb_resources[0].end = 0; + } +#endif + } +} + +static void __init mx53_evk_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53common_pads, + ARRAY_SIZE(mx53common_pads)); + + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + pr_info("MX53 ARM2 board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53arm2_pads, + ARRAY_SIZE(mx53arm2_pads)); + + /* Config GPIO for OTG VBus */ + gpio_request(ARM2_OTG_VBUS, "otg-vbus"); + gpio_direction_output(ARM2_OTG_VBUS, 1); + + gpio_request(ARM2_SD1_CD, "sdhc1-cd"); + gpio_direction_input(ARM2_SD1_CD); /* SD1 CD */ + + gpio_request(ARM2_LCD_CONTRAST, "lcd-contrast"); + gpio_direction_output(ARM2_LCD_CONTRAST, 1); + } else { + /* MX53 EVK board */ + pr_info("MX53 EVK board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53evk_pads, + ARRAY_SIZE(mx53evk_pads)); + + /* Host1 Vbus with GPIO high */ + gpio_request(EVK_USBH1_VBUS, "usbh1-vbus"); + gpio_direction_output(EVK_USBH1_VBUS, 1); + /* shutdown the Host1 Vbus when system bring up, + * Vbus will be opened in Host1 driver's probe function */ + gpio_set_value(EVK_USBH1_VBUS, 0); + + /* USB HUB RESET - De-assert USB HUB RESET_N */ + gpio_request(EVK_USB_HUB_RESET, "usb-hub-reset"); + gpio_direction_output(EVK_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(EVK_USB_HUB_RESET, 1); + + /* Config GPIO for OTG VBus */ + gpio_request(EVK_OTG_VBUS, "otg-vbus"); + gpio_direction_output(EVK_OTG_VBUS, 0); + if (board_is_mx53_evk_a()) /*rev A,"1" disable, "0" enable vbus*/ + gpio_set_value(EVK_OTG_VBUS, 1); + else if (board_is_mx53_evk_b()) /* rev B,"0" disable,"1" enable Vbus*/ + gpio_set_value(EVK_OTG_VBUS, 0); + + gpio_request(EVK_SD1_CD, "sdhc1-cd"); + gpio_direction_input(EVK_SD1_CD); /* SD1 CD */ + gpio_request(EVK_SD1_WP, "sdhc1-wp"); + gpio_direction_input(EVK_SD1_WP); /* SD1 WP */ + + /* SD3 CD */ + gpio_request(EVK_SD3_CD, "sdhc3-cd"); + gpio_direction_input(EVK_SD3_CD); + + /* SD3 WP */ + gpio_request(EVK_SD3_WP, "sdhc3-wp"); + gpio_direction_input(EVK_SD3_WP); + + /* reset FEC PHY */ + gpio_request(EVK_FEC_PHY_RESET, "fec-phy-reset"); + gpio_direction_output(EVK_FEC_PHY_RESET, 0); + msleep(1); + gpio_set_value(EVK_FEC_PHY_RESET, 1); + + gpio_request(MX53_ESAI_RESET, "fesai-reset"); + gpio_direction_output(MX53_ESAI_RESET, 0); + } + + /* DVI Detect */ + gpio_request(MX53_DVI_DETECT, "dvi-detect"); + gpio_direction_input(MX53_DVI_DETECT); + /* DVI Reset - Assert for i2c disabled mode */ + gpio_request(MX53_DVI_RESET, "dvi-reset"); + gpio_direction_output(MX53_DVI_RESET, 0); + + /* DVI Power-down */ + gpio_request(MX53_DVI_PD, "dvi-pd"); + gpio_direction_output(MX53_DVI_PD, 1); + + /* DVI I2C enable */ + gpio_request(MX53_DVI_I2C, "dvi-i2c"); + gpio_direction_output(MX53_DVI_I2C, 0); + + mxc_iomux_v3_setup_multiple_pads(mx53_nand_pads, + ARRAY_SIZE(mx53_nand_pads)); + + gpio_request(MX53_PMIC_INT, "pmic-int"); + gpio_direction_input(MX53_PMIC_INT); /*PMIC_INT*/ + + /* headphone_det_b */ + gpio_request(MX53_HP_DETECT, "hp-detect"); + gpio_direction_input(MX53_HP_DETECT); + + /* power key */ + + /* LCD related gpio */ + + /* Camera reset */ + gpio_request(MX53_CAM_RESET, "cam-reset"); + gpio_direction_output(MX53_CAM_RESET, 1); + + /* TVIN reset */ + gpio_request(MX53_TVIN_RESET, "tvin-reset"); + gpio_direction_output(MX53_TVIN_RESET, 0); + msleep(5); + gpio_set_value(MX53_TVIN_RESET, 1); + + /* TVin power down */ + gpio_request(MX53_TVIN_PWR, "tvin-pwr"); + gpio_direction_output(MX53_TVIN_PWR, 0); + + /* CAN1 enable GPIO*/ + gpio_request(MX53_CAN1_EN1, "can1-en1"); + gpio_direction_output(MX53_CAN1_EN1, 0); + + gpio_request(MX53_CAN1_EN2, "can1-en2"); + gpio_direction_output(MX53_CAN1_EN2, 0); + + /* CAN2 enable GPIO*/ + gpio_request(MX53_CAN2_EN1, "can2-en1"); + gpio_direction_output(MX53_CAN2_EN1, 0); + + gpio_request(MX53_CAN2_EN2, "can2-en2"); + gpio_direction_output(MX53_CAN2_EN2, 0); + + if (enable_spdif) { + struct pad_desc spdif_pin = MX53_PAD_GPIO_19__SPDIF_TX1; + mxc_iomux_v3_setup_pad(&spdif_pin); + } else { + /* GPIO for 12V */ + gpio_request(MX53_12V_EN, "12v-en"); + gpio_direction_output(MX53_12V_EN, 0); + } +} + +extern void mx53_gpio_usbotg_driver_vbus(bool on); +extern void mx53_gpio_host1_driver_vbus(bool on); +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "ssi_ext1_clk"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + /* SD card detect irqs */ + if (board_is_mx53_arm2()) { + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(ARM2_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(ARM2_SD1_CD); + mmc3_data.card_inserted_state = 1; + mmc3_data.status = NULL; + mmc3_data.wp_status = NULL; + mmc1_data.wp_status = NULL; + } else { + mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD3_CD); + mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD3_CD); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD1_CD); + } + + mxc_cpu_common_init(); + mx53_evk_io_init(); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_devices[2], &mxci2c_data); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_ldb_device, &ldb_data); + mxc_register_device(&mxc_tve_device, &tve_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxcscc_device, NULL); + /* + mxc_register_device(&mx53_lpmode_device, NULL); + mxc_register_device(&sdram_autogating_device, NULL); + */ + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, &bus_freq_data); + + /* + mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); + */ + + mxc_register_device(&mxc_iim_device, &iim_data); + if (!board_is_mx53_arm2()) { + mxc_register_device(&mxc_pwm2_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, + &mxc_pwm_backlight_data); + } + mxc_register_device(&mxc_flexcan0_device, &flexcan0_data); + mxc_register_device(&mxc_flexcan1_device, &flexcan1_data); + +/* mxc_register_device(&mxc_keypad_device, &keypad_plat_data); */ + + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&ahci_fsl_device, &sata_data); + + /* ASRC is only available for MX53 TO2.0 */ + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + mxc_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + clk_put(mxc_asrc_data.asrc_core_clk); + mxc_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + clk_put(mxc_asrc_data.asrc_audio_clk); + mxc_register_device(&mxc_asrc_device, &mxc_asrc_data); + } + + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + if (!mxc_apc_on) { + mxc_register_device(&mxc_fec_device, &fec_data); + mxc_register_device(&mxc_ptp_device, NULL); + } + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); + 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)); + + mx53_evk_init_mc13892(); +/* + pm_power_off = mxc_power_off; + */ + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mxc_register_device(&mxc_mlb_device, &mlb_data); + mxc_register_device(&mxc_powerkey_device, &pwrkey_data); + mx5_set_otghost_vbus_func(mx53_gpio_usbotg_driver_vbus); + mx5_usb_dr_init(); + mx5_set_host1_vbus_func(mx53_gpio_host1_driver_vbus); + mx5_usbh1_init(); + mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); + if (mxc_apc_on) { + mxc_register_device(&mxc_esai_device, &esai_data); + mxc_register_device(&mxc_alsa_surround_device, + &mxc_surround_audio_data); + } + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); +} + +static void __init mx53_evk_timer_init(void) +{ + struct clk *uart_clk; + + mx53_clocks_init(32768, 24000000, 22579200, 24576000); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx53_evk_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX53_EVK data structure. + */ +MACHINE_START(MX53_EVK, "Freescale MX53 EVK Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c new file mode 100644 index 000000000000..3ed2e14e49ba --- /dev/null +++ b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c @@ -0,0 +1,351 @@ +/* + * mx53-evk-pmic-mc13892.c -- i.MX53 3STACK Driver for Atlas MC13892 PMIC + */ + /* + * Copyright (C) 2010 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/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892/core.h> +#include <mach/irqs.h> + +#include <mach/iomux-mx53.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +#define STANDBYSECINV_LSH 11 +#define STANDBYSECINV_WID 1 + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static int mc13892_regulator_init(struct mc13892 *mc13892) +{ + unsigned int value; + int register_mask; + + pr_info("Initializing regulators for MX53 EVK \n"); + + /* Bit 4 DRM: keep VSRTC and CLK32KMCU on for all states */ +#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) + value = BITFVAL(DRM, 1); + register_mask = BITFMASK(DRM); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); +#endif + /* Set the STANDBYSECINV bit, so that STANDBY pin is + * interpreted as active low. + */ + value = BITFVAL(STANDBYSECINV, 1); + register_mask = BITFMASK(STANDBYSECINV); + pmic_write_reg(REG_POWER_CTL2, value, register_mask); + + /* Disable coin cell charger since the cell is not rechargeable */ + value = BITFVAL(COINCHEN, 0) | BITFVAL(VCOIN, VCOIN_3_0V); + register_mask = BITFMASK(COINCHEN) | BITFMASK(VCOIN); + pmic_write_reg(REG_POWER_CTL0, value, register_mask); + + mc13892_register_regulator(mc13892, MC13892_SW1, &sw1_init); + mc13892_register_regulator(mc13892, MC13892_SW2, &sw2_init); + mc13892_register_regulator(mc13892, MC13892_SW3, &sw3_init); + mc13892_register_regulator(mc13892, MC13892_SW4, &sw4_init); + mc13892_register_regulator(mc13892, MC13892_SWBST, &swbst_init); + mc13892_register_regulator(mc13892, MC13892_VIOHI, &viohi_init); + mc13892_register_regulator(mc13892, MC13892_VPLL, &vpll_init); + mc13892_register_regulator(mc13892, MC13892_VDIG, &vdig_init); + mc13892_register_regulator(mc13892, MC13892_VSD, &vsd_init); + mc13892_register_regulator(mc13892, MC13892_VUSB2, &vusb2_init); + mc13892_register_regulator(mc13892, MC13892_VVIDEO, &vvideo_init); + mc13892_register_regulator(mc13892, MC13892_VAUDIO, &vaudio_init); + mc13892_register_regulator(mc13892, MC13892_VCAM, &vcam_init); + mc13892_register_regulator(mc13892, MC13892_VGEN1, &vgen1_init); + mc13892_register_regulator(mc13892, MC13892_VGEN2, &vgen2_init); + mc13892_register_regulator(mc13892, MC13892_VGEN3, &vgen3_init); + mc13892_register_regulator(mc13892, MC13892_VUSB, &vusb_init); + mc13892_register_regulator(mc13892, MC13892_GPO1, &gpo1_init); + mc13892_register_regulator(mc13892, MC13892_GPO2, &gpo2_init); + mc13892_register_regulator(mc13892, MC13892_GPO3, &gpo3_init); + mc13892_register_regulator(mc13892, MC13892_GPO4, &gpo4_init); + + return 0; +} + +static struct mc13892_platform_data mc13892_plat = { + .init = mc13892_regulator_init, +}; + +static struct i2c_board_info __initdata mc13892_i2c_device = { + I2C_BOARD_INFO("mc13892", 0x08), + .irq = IOMUX_TO_IRQ_V3(203), + .platform_data = &mc13892_plat, +}; + +int __init mx53_evk_init_mc13892(void) +{ + return i2c_register_board_info(1, &mc13892_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx53_loco.c b/arch/arm/mach-mx5/mx53_loco.c new file mode 100644 index 000000000000..7074dcdf55de --- /dev/null +++ b/arch/arm/mach-mx5/mx53_loco.c @@ -0,0 +1,839 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/ahci_platform.h> +#include <linux/gpio_keys.h> +#include <mach/common.h> +#include <mach/hardware.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 <asm/mach/keypad.h> +#include <asm/mach/flash.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx53.h> +#include <mach/i2c.h> +#include <mach/mxc_iim.h> + +#include "crm_regs.h" +#include "devices.h" +#include "usb.h" + +/*! + * @file mach-mx5/mx53_loco.c + * + * @brief This file contains MX53 loco board specific initialization routines. + * + * @ingroup MSL_MX53 + */ + +/* MX53 LOCO GPIO PIN configurations */ +#define NVDD_FAULT (0*32 + 5) /* GPIO1_5 */ + +#define FEC_INT (1*32 + 4) /* GPIO_2_4 */ +#define HEADPHONE_DEC_B (1*32 + 5) /* GPIO_2_5 */ +#define MIC_DEC_B (1*32 + 6) /* GPIO_2_6 */ +#define USER_UI1 (1*32 + 14) /* GPIO_2_14 */ +#define USER_UI2 (1*32 + 15) /* GPIO_2_15 */ +#define MX53_nONKEY (0*32 + 8) /* GPIO_1_8 */ + +#define SD3_CD (2*32 + 11) /* GPIO_3_11 */ +#define SD3_WP (2*32 + 12) /* GPIO_3_12 */ +#define DISP0_POWER_EN (2*32 + 24) /* GPIO_3_24 */ +#define DISP0_DET_INT (2*32 + 31) /* GPIO_3_31 */ + +#define DISP0_RESET (4*32 + 0) /* GPIO_5_0 */ + +#define CSI0_RTSB (5*32 + 9) /* GPIO_6_9 */ +#define CSI0_PWDN (5*32 + 10) /* GPIO_6_10 */ +#define ACCL_EN (5*32 + 14) /* GPIO_6_14 */ +#define ACCL_INT1_IN (5*32 + 15) /* GPIO_6_15 */ +#define ACCL_INT2_IN (5*32 + 16) /* GPIO_6_16 */ + +#define LCD_BLT_EN (6*32 + 2) /* GPIO_7_2 */ +#define FEC_RST (6*32 + 6) /* GPIO_7_6 */ +#define USER_LED_EN (6*32 + 7) /* GPIO_7_7 */ +#define USB_PWREN (6*32 + 8) /* GPIO_7_8 */ +#define NIRQ (6*32 + 11) /* GPIO7_11 */ + +extern int __init mx53_loco_init_da9052(void); + +static struct pad_desc mx53_loco_pads[] = { + /* FEC */ + MX53_PAD_FEC_MDC__FEC_MDC, + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_REF_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_CRS_DV, + MX53_PAD_FEC_RXD1__FEC_RXD1, + MX53_PAD_FEC_RXD0__FEC_RXD0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TXD1, + MX53_PAD_FEC_TXD0__FEC_TXD0, + /* FEC_nRST */ + MX53_PAD_ATA_DA_0__GPIO_7_6, + /* FEC_nINT */ + MX53_PAD_ATA_DATA4__GPIO_2_4, + /* AUDMUX5 */ + MX53_PAD_KEY_COL0__AUD5_TXC, + MX53_PAD_KEY_ROW0__AUD5_TXD, + MX53_PAD_KEY_COL1__AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUD5_RXD, + /* I2C2 */ + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + /* SD1 */ + MX53_PAD_SD1_CMD__SD1_CMD, + MX53_PAD_SD1_CLK__SD1_CLK, + MX53_PAD_SD1_DATA0__SD1_DATA0, + MX53_PAD_SD1_DATA1__SD1_DATA1, + MX53_PAD_SD1_DATA2__SD1_DATA2, + MX53_PAD_SD1_DATA3__SD1_DATA3, + /* SD3 */ + MX53_PAD_ATA_DATA8__SD3_DAT0, + MX53_PAD_ATA_DATA9__SD3_DAT1, + MX53_PAD_ATA_DATA10__SD3_DAT2, + MX53_PAD_ATA_DATA11__SD3_DAT3, + MX53_PAD_ATA_DATA0__SD3_DAT4, + MX53_PAD_ATA_DATA1__SD3_DAT5, + MX53_PAD_ATA_DATA2__SD3_DAT6, + MX53_PAD_ATA_DATA3__SD3_DAT7, + MX53_PAD_ATA_IORDY__SD3_CLK, + MX53_PAD_ATA_RESET_B__SD3_CMD, + /* SD3_CD */ + MX53_PAD_EIM_DA11__GPIO_3_11, + /* SD3_WP */ + MX53_PAD_EIM_DA12__GPIO_3_12, + /* VGA */ + MX53_PAD_EIM_OE__DI1_PIN7, + MX53_PAD_EIM_RW__DI1_PIN8, + /* DISPLB */ + MX53_PAD_EIM_D20__SER_DISP0_CS, + MX53_PAD_EIM_D21__DISPB0_SER_CLK, + MX53_PAD_EIM_D22__DISPB0_SER_DIN, + MX53_PAD_EIM_D23__DI0_D0_CS, + /* DISP0_POWER_EN */ + MX53_PAD_EIM_D24__GPIO_3_24, + /* DISP0 DET INT */ + MX53_PAD_EIM_D31__GPIO_3_31, + + /* LVDS */ + MX53_PAD_LVDS0_TX3_P__LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LVDS0_TX0, + MX53_PAD_LVDS1_TX3_P__LVDS1_TX3, + MX53_PAD_LVDS1_TX2_P__LVDS1_TX2, + MX53_PAD_LVDS1_CLK_P__LVDS1_CLK, + MX53_PAD_LVDS1_TX1_P__LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LVDS1_TX0, + /* I2C1 */ + MX53_PAD_CSI0_D8__I2C1_SDA, + MX53_PAD_CSI0_D9__I2C1_SCL, + /* UART1 */ + MX53_PAD_CSI0_D10__UART1_TXD, + MX53_PAD_CSI0_D11__UART1_RXD, + /* CSI0 */ + MX53_PAD_CSI0_D12__CSI0_D12, + MX53_PAD_CSI0_D13__CSI0_D13, + MX53_PAD_CSI0_D14__CSI0_D14, + MX53_PAD_CSI0_D15__CSI0_D15, + MX53_PAD_CSI0_D16__CSI0_D16, + MX53_PAD_CSI0_D17__CSI0_D17, + MX53_PAD_CSI0_D18__CSI0_D18, + MX53_PAD_CSI0_D19__CSI0_D19, + MX53_PAD_CSI0_VSYNC__CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK, + /* DISPLAY */ + MX53_PAD_DI0_DISP_CLK__DI0_DISP_CLK, + MX53_PAD_DI0_PIN15__DI0_PIN15, + MX53_PAD_DI0_PIN2__DI0_PIN2, + MX53_PAD_DI0_PIN3__DI0_PIN3, + MX53_PAD_DISP0_DAT0__DISP0_DAT0, + MX53_PAD_DISP0_DAT1__DISP0_DAT1, + MX53_PAD_DISP0_DAT2__DISP0_DAT2, + MX53_PAD_DISP0_DAT3__DISP0_DAT3, + MX53_PAD_DISP0_DAT4__DISP0_DAT4, + MX53_PAD_DISP0_DAT5__DISP0_DAT5, + MX53_PAD_DISP0_DAT6__DISP0_DAT6, + MX53_PAD_DISP0_DAT7__DISP0_DAT7, + MX53_PAD_DISP0_DAT8__DISP0_DAT8, + MX53_PAD_DISP0_DAT9__DISP0_DAT9, + MX53_PAD_DISP0_DAT10__DISP0_DAT10, + MX53_PAD_DISP0_DAT11__DISP0_DAT11, + MX53_PAD_DISP0_DAT12__DISP0_DAT12, + MX53_PAD_DISP0_DAT13__DISP0_DAT13, + MX53_PAD_DISP0_DAT14__DISP0_DAT14, + MX53_PAD_DISP0_DAT15__DISP0_DAT15, + MX53_PAD_DISP0_DAT16__DISP0_DAT16, + MX53_PAD_DISP0_DAT17__DISP0_DAT17, + MX53_PAD_DISP0_DAT18__DISP0_DAT18, + MX53_PAD_DISP0_DAT19__DISP0_DAT19, + MX53_PAD_DISP0_DAT20__DISP0_DAT20, + MX53_PAD_DISP0_DAT21__DISP0_DAT21, + MX53_PAD_DISP0_DAT22__DISP0_DAT22, + MX53_PAD_DISP0_DAT23__DISP0_DAT23, + /* Audio CLK*/ + MX53_PAD_GPIO_0__SSI_EXT1_CLK, + /* PWM */ + MX53_PAD_GPIO_1__PWMO, + /* SPDIF */ + MX53_PAD_GPIO_7__PLOCK, + MX53_PAD_GPIO_17__SPDIF_OUT1, + /* GPIO */ + MX53_PAD_ATA_DA_1__GPIO_7_7, + MX53_PAD_ATA_DA_2__GPIO_7_8, + MX53_PAD_ATA_DATA5__GPIO_2_5, + MX53_PAD_ATA_DATA6__GPIO_2_6, + MX53_PAD_ATA_DATA14__GPIO_2_14, + MX53_PAD_ATA_DATA15__GPIO_2_15, + MX53_PAD_ATA_INTRQ__GPIO_7_2, + MX53_PAD_EIM_WAIT__GPIO_5_0, + MX53_PAD_NANDF_WP_B__GPIO_6_9, + MX53_PAD_NANDF_RB0__GPIO_6_10, + MX53_PAD_NANDF_CS1__GPIO_6_14, + MX53_PAD_NANDF_CS2__GPIO_6_15, + MX53_PAD_NANDF_CS3__GPIO_6_16, + MX53_PAD_GPIO_5__GPIO_1_5, + MX53_PAD_GPIO_16__GPIO_7_11, + MX53_PAD_GPIO_8__GPIO_1_8, +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 800x480 @ 60 Hz , pixel clk @ 32MHz */ + "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 1600x1200 @ 60 Hz 162M pixel clk*/ + "UXGA", 60, 1600, 1200, 6172, + 304, 64, + 1, 46, + 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, + 0,}, + /* 2 LVDS modes, had better remove from here */ + { + "1080P60", 60, 1920, 1080, 7692, + 100, 40, + 30, 3, + 10, 2, + 0, + FB_VMODE_NONINTERLACED, + 0,}, + { + "XGA", 60, 1024, 768, 15385, + 220, 40, + 21, 7, + 60, 10, + 0, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 3, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "DA9052_BUCK_CORE", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "DA9052_BUCK_CORE", + .lp_reg_id = "DA9052_BUCK_PRO", +}; + +static struct tve_platform_data tve_data = { + .dac_reg = "DA9052_LDO7", +}; + +static struct ldb_platform_data ldb_data = { + .ext_ref = 1, +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +static struct resource mxcfb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "800x480M@55", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, + { + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +extern int primary_di; +static int __init mxc_init_fb(void) +{ + if (!machine_is_mx53_loco()) + return 0; + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(DISP0_RESET, 0); + msleep(10); + gpio_set_value(DISP0_RESET, 1); + msleep(10); +} + +static struct mxc_lcd_platform_data sii902x_hdmi_data = { + .reset = sii902x_hdmi_reset, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "mma8450", + .addr = 0x1C, + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "sii902x", + .addr = 0x39, + .irq = IOMUX_TO_IRQ_V3(DISP0_DET_INT), + .platform_data = &sii902x_hdmi_data, + }, +}; + +static int sdhc_write_protect(struct device *dev) +{ + int ret = 0; + + if (to_platform_device(dev)->id == 2) + ret = gpio_get_value(SD3_WP); + + return ret; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret = 0; + + if (to_platform_device(dev)->id == 2) + ret = gpio_get_value(SD3_CD); + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 1, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +static struct mxc_mmc_platform_data mmc3_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 | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", +}; + +static int headphone_det_status(void) +{ + return (gpio_get_value(HEADPHONE_DEC_B) == 0); +} + +static int mxc_sgtl5000_init(void); + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .hp_irq = IOMUX_TO_IRQ_V3(HEADPHONE_DEC_B), + .hp_status = headphone_det_status, + .init = mxc_sgtl5000_init, +}; + +static int mxc_sgtl5000_init(void) +{ + struct clk *ssi_ext1; + int rate; + + ssi_ext1 = clk_get(NULL, "ssi_ext1_clk"); + if (IS_ERR(ssi_ext1)) + return -1; + + rate = clk_round_rate(ssi_ext1, 24000000); + if (rate < 8000000 || rate > 27000000) { + printk(KERN_ERR "Error: SGTL5000 mclk freq %d out of range!\n", + rate); + clk_put(ssi_ext1); + return -1; + } + + clk_set_rate(ssi_ext1, rate); + clk_enable(ssi_ext1); + sgtl5000_data.sysclk = rate; + + return 0; +} + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static struct mxc_asrc_platform_data mxc_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = -1, /* Souce from CKIH1 for 44.1K */ + /* Source from CCM spdif_clk (24M) for 48k and 32k + * It's not accurate + */ + .spdif_clk_48000 = 1, + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static void mx53_loco_usbh1_vbus(bool on) +{ + if (on) + gpio_set_value(USB_PWREN, 1); + else + gpio_set_value(USB_PWREN, 0); +} + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ +} + +static struct gpio_keys_button loco_buttons[] = { + GPIO_BUTTON(MX53_nONKEY, KEY_POWER, 1, "power", 0), + GPIO_BUTTON(USER_UI1, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(USER_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static struct gpio_keys_platform_data loco_button_data = { + .buttons = loco_buttons, + .nbuttons = ARRAY_SIZE(loco_buttons), +}; + +static struct platform_device loco_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &loco_button_data, + } +}; + +static void __init loco_add_device_buttons(void) +{ + platform_device_register(&loco_button_device); +} +#else +static void __init loco_add_device_buttons(void) {} +#endif + + +/*! + * 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) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_1G; + int left_mem = 0; + int gpu_mem = SZ_128M; + int fb_mem = SZ_32M; + char *str; + + mxc_set_cpu_type(MXC_CPU_MX53); + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_device.resource[5].start = + mem_tag->u.mem.start + left_mem; + gpu_device.resource[5].end = + gpu_device.resource[5].start + gpu_mem - 1; +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ + defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) + if (fb_mem) { + mxcfb_resources[0].start = + gpu_device.resource[5].end + 1; + mxcfb_resources[0].end = + mxcfb_resources[0].start + fb_mem - 1; + } else { + mxcfb_resources[0].start = 0; + mxcfb_resources[0].end = 0; + } +#endif + } +} + +static void __init mx53_loco_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads, + ARRAY_SIZE(mx53_loco_pads)); + + /* SD3 */ + gpio_request(SD3_CD, "sd3-cd"); + gpio_direction_input(SD3_CD); + gpio_request(SD3_WP, "sd3-wp"); + gpio_direction_input(SD3_WP); + + /* reset FEC PHY */ + gpio_request(FEC_RST, "fec-rst"); + gpio_direction_output(FEC_RST, 0); + gpio_set_value(FEC_RST, 0); + msleep(1); + gpio_set_value(FEC_RST, 1); + + /* headphone_det_b */ + gpio_request(HEADPHONE_DEC_B, "headphone-dec"); + gpio_direction_input(HEADPHONE_DEC_B); + + /* USB PWR enable */ + gpio_request(USB_PWREN, "usb-pwr"); + gpio_direction_output(USB_PWREN, 0); + + /* Sii902x HDMI controller */ + gpio_request(DISP0_RESET, "disp0-reset"); + gpio_direction_output(DISP0_RESET, 0); + gpio_request(DISP0_DET_INT, "disp0-detect"); + gpio_direction_input(DISP0_DET_INT); + + /* LCD panel power enable */ + gpio_request(DISP0_POWER_EN, "disp0-power-en"); + gpio_direction_output(DISP0_POWER_EN, 1); +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "ssi_ext1_clk"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(SD3_CD); + mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(SD3_CD); + + mxc_cpu_common_init(); + mx53_loco_io_init(); + + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + + mx53_loco_init_da9052(); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_ldb_device, &ldb_data); + mxc_register_device(&mxc_tve_device, &tve_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxcscc_device, NULL); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, &bus_freq_data); + mxc_register_device(&mxc_iim_device, &iim_data); + mxc_register_device(&mxc_pwm2_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, &mxc_pwm_backlight_data); + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + mxc_register_device(&ahci_fsl_device, &sata_data); + mxc_register_device(&mxc_fec_device, &fec_data); + /* ASRC is only available for MX53 TO2.0 */ + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + mxc_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + clk_put(mxc_asrc_data.asrc_core_clk); + mxc_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + clk_put(mxc_asrc_data.asrc_audio_clk); + mxc_register_device(&mxc_asrc_device, &mxc_asrc_data); + } + + 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)); + + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mx5_usb_dr_init(); + mx5_set_host1_vbus_func(mx53_loco_usbh1_vbus); + mx5_usbh1_init(); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); + loco_add_device_buttons(); +} + +static void __init mx53_loco_timer_init(void) +{ + struct clk *uart_clk; + + mx53_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx53_loco_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX53_LOCO data structure. + */ +MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c b/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c new file mode 100644 index 000000000000..e11243b67043 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +/* + * mx53_loco_pmic_da9053.c -- i.MX53 LOCO driver for pmic da9053 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/pm.h> +#include <linux/mfd/da9052/led.h> +#include <linux/mfd/da9052/tsi.h> +#include <mach/irqs.h> +#include <mach/iomux-mx53.h> + +#define DA9052_LDO(max, min, rname, suspend_mv) \ +{\ + .constraints = {\ + .name = (rname), \ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + |REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + .state_mem = { \ + .uV = suspend_mv * 1000, \ + .mode = REGULATOR_MODE_NORMAL, \ + .enabled = (0 == suspend_mv) ? 0 : 1, \ + .disabled = 0, \ + }, \ + },\ +} + +/* currently the suspend_mv here takes no effects for DA9053 +preset-voltage have to be done in the latest stage during +suspend*/ +static struct regulator_init_data da9052_regulators_init[] = { + DA9052_LDO(DA9052_LDO1_VOLT_UPPER, + DA9052_LDO1_VOLT_LOWER, "DA9052_LDO1", 1300), + DA9052_LDO(DA9052_LDO2_VOLT_UPPER, + DA9052_LDO2_VOLT_LOWER, "DA9052_LDO2", 1300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO3", 3300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO4", 2775), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO5", 1300), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO6", 1200), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO7", 2750), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO8", 1800), + DA9052_LDO(DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, "DA9052_LDO9", 2500), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO10", 1200), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_CORE", 850), + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_PRO", 950), + DA9052_LDO(DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, "DA9052_BUCK_MEM", 1500), + DA9052_LDO(DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, "DA9052_BUCK_PERI", 2500) +}; + + +static struct da9052_tsi_platform_data da9052_tsi = { + .pen_up_interval = 50, + .tsi_delay_bit_shift = 6, + .tsi_skip_bit_shift = 3, + .num_gpio_tsi_register = 3, + .tsi_supply_voltage = 2500, + /* This is the DA9052 LDO number used for powering the TSI */ + .tsi_ref_source = 9, + .max_tsi_delay = TSI_DELAY_4SLOTS, + .max_tsi_skip_slot = TSI_SKIP_330SLOTS, +}; + +static struct da9052_led_platform_data da9052_gpio_led[] = { + { + .id = DA9052_LED_4, + .name = "LED_GPIO14", + }, + { + .id = DA9052_LED_5, + .name = "LED_GPIO15", + }, +}; + +static struct da9052_leds_platform_data da9052_gpio_leds = { + .num_leds = ARRAY_SIZE(da9052_gpio_led), + .led = da9052_gpio_led, +}; + + +static struct da9052_bat_platform_data da9052_bat = { + .sw_temp_control_en = 0, + .monitoring_interval = 500, + .sw_bat_temp_threshold = 60, + .sw_junc_temp_threshold = 120, + .hysteresis_window_size = 1, + .current_monitoring_window = 10, + .bat_with_no_resistor = 62, + .bat_capacity_limit_low = 4, + .bat_capacity_full = 100, + .bat_capacity_limit_high = 70, + .chg_hysteresis_const = 89, + .hysteresis_reading_interval = 1000, + .hysteresis_no_of_reading = 10, + .filter_size = 4, + .bat_volt_cutoff = 2800, + .vbat_first_valid_detect_iteration = 3, +}; + +static void da9052_init_ssc_cache(struct da9052 *da9052) +{ + unsigned char cnt; + + /* First initialize all registers as Non-volatile */ + for (cnt = 0; cnt < DA9052_REG_CNT; cnt++) { + da9052->ssc_cache[cnt].type = NON_VOLATILE; + da9052->ssc_cache[cnt].status = INVALID; + da9052->ssc_cache[cnt].val = 0; + } + + /* Now selectively set type for all Volatile registers */ + /* Reg 1 - 9 */ + da9052->ssc_cache[DA9052_STATUSA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_FAULTLOG_REG].type = VOLATILE; + + /* Reg 15 */ + da9052->ssc_cache[DA9052_CONTROLB_REG].type = VOLATILE; + /* Reg - 17 */ + da9052->ssc_cache[DA9052_CONTROLD_REG].type = VOLATILE; + /* Reg - 60 */ + da9052->ssc_cache[DA9052_SUPPLY_REG].type = VOLATILE; + /* Reg - 62 */ + da9052->ssc_cache[DA9052_CHGBUCK_REG].type = VOLATILE; + + /* Reg 67 - 68 */ + da9052->ssc_cache[DA9052_INPUTCONT_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_CHGTIME_REG].type = VOLATILE; + + /* Reg - 70 */ + da9052->ssc_cache[DA9052_BOOST_REG].type = VOLATILE; + + /* Reg - 81 */ + da9052->ssc_cache[DA9052_ADCMAN_REG].type = VOLATILE; + + /* Reg - 83 - 85 */ + da9052->ssc_cache[DA9052_ADCRESL_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ADCRESH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_VDDRES_REG].type = VOLATILE; + + /* Reg - 87 */ + da9052->ssc_cache[DA9052_ICHGAV_REG].type = VOLATILE; + + /* Reg - 90 */ + da9052->ssc_cache[DA9052_TBATRES_REG].type = VOLATILE; + + /* Reg - 95 */ + da9052->ssc_cache[DA9052_ADCIN4RES_REG].type = VOLATILE; + + /* Reg - 98 */ + da9052->ssc_cache[DA9052_ADCIN5RES_REG].type = VOLATILE; + + /* Reg - 101 */ + da9052->ssc_cache[DA9052_ADCIN6RES_REG].type = VOLATILE; + + /* Reg - 104 */ + da9052->ssc_cache[DA9052_TJUNCRES_REG].type = VOLATILE; + + /* Reg 106 - 110 */ + da9052->ssc_cache[DA9052_TSICONTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIXMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIYMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSILSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIZMSB_REG].type = VOLATILE; + + /* Reg 111 - 117 */ + da9052->ssc_cache[DA9052_COUNTS_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMI_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMO_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTY_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ALARMMI_REG].type = VOLATILE; + + /* Reg 122 - 125 */ + da9052->ssc_cache[DA9052_SECONDA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDD_REG].type = VOLATILE; + + /* Following addresses are not assigned to any register */ + da9052->ssc_cache[126].type = VOLATILE; + da9052->ssc_cache[127].type = VOLATILE; +} + + +#define MX53_LOCO_DA9052_IRQ (6*32 + 11) /* GPIO7_11 */ + +static int __init loco_da9052_init(struct da9052 *da9052) +{ + /* Configuring for DA9052 interrupt servce */ + /* s3c_gpio_setpull(DA9052_IRQ_PIN, S3C_GPIO_PULL_UP);*/ + + /* Set interrupt as LOW LEVEL interrupt source */ + set_irq_type(IOMUX_TO_IRQ_V3(MX53_LOCO_DA9052_IRQ), IRQF_TRIGGER_LOW); + + da9052_init_ssc_cache(da9052); + + return 0; +} + +static struct da9052_platform_data __initdata da9052_plat = { + .init = loco_da9052_init, + .num_regulators = ARRAY_SIZE(da9052_regulators_init), + .regulators = da9052_regulators_init, + .led_data = &da9052_gpio_leds, + .tsi_data = &da9052_tsi, + .bat_data = &da9052_bat, + /* .gpio_base = GPIO_BOARD_START, */ +}; + + +static struct i2c_board_info __initdata da9052_i2c_device = { + I2C_BOARD_INFO(DA9052_SSC_I2C_DEVICE_NAME, DA9052_I2C_ADDR >> 1), + .irq = IOMUX_TO_IRQ_V3(MX53_LOCO_DA9052_IRQ), + .platform_data = &da9052_plat, +}; + +int __init mx53_loco_init_da9052(void) +{ + return i2c_register_board_info(0, &da9052_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx53_smd.c b/arch/arm/mach-mx5/mx53_smd.c new file mode 100644 index 000000000000..fd46e9de944a --- /dev/null +++ b/arch/arm/mach-mx5/mx53_smd.c @@ -0,0 +1,1122 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.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/i2c/mpr.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/ahci_platform.h> +#include <linux/gpio_keys.h> +#include <mach/common.h> +#include <mach/hardware.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 <asm/mach/keypad.h> +#include <asm/mach/flash.h> +#include <mach/memory.h> +#include <mach/gpio.h> +#include <mach/mmc.h> +#include <mach/mxc_dvfs.h> +#include <mach/iomux-mx53.h> +#include <mach/i2c.h> +#include <mach/mxc_iim.h> +#include <mach/mxc_rfkill.h> + +#include "crm_regs.h" +#include "devices.h" +#include "usb.h" + +/*! + * @file mach-mx5/mx53_smd.c + * + * @brief This file contains MX53 smd board specific initialization routines. + * + * @ingroup MSL_MX53 + */ + +/* MX53 SMD GPIO PIN configurations */ +#define MX53_SMD_KEY_RESET (0*32 + 2) /* GPIO1_2 */ +#define MX53_SMD_SATA_CLK_GPEN (0*32 + 4) /* GPIO1_4 */ +#define MX53_SMD_PMIC_FAULT (0*32 + 5) /* GPIO1_5 */ +#define MX53_SMD_SYS_ON_OFF_CTL (0*32 + 7) /* GPIO1_7 */ +#define MX53_SMD_PMIC_ON_OFF_REQ (0*32 + 8) /* GPIO1_8 */ + +#define MX53_SMD_FEC_INT (1*32 + 4) /* GPIO2_4 */ +#define MX53_SMD_HEADPHONE_DEC (1*32 + 5) /* GPIO2_5 */ +#define MX53_SMD_ZIGBEE_INT (1*32 + 6) /* GPIO2_6 */ +#define MX53_SMD_ZIGBEE_RESET_B (1*32 + 7) /* GPIO2_7 */ +#define MX53_SMD_GPS_RESET_B (1*32 + 12) /* GPIO2_12 */ +#define MX53_SMD_WAKEUP_ZIGBEE (1*32 + 13) /* GPIO2_13 */ +#define MX53_SMD_KEY_VOL_DOWN (1*32 + 14) /* GPIO2_14 */ +#define MX53_SMD_KEY_VOL_UP (1*32 + 15) /* GPIO2_15 */ +#define MX53_SMD_FEC_PWR_EN (1*32 + 16) /* GPIO_2_16 */ +#define MX53_SMD_LID_OPN_CLS_SW (1*32 + 23) /* GPIO_2_23 */ +#define MX53_SMD_GPS_PPS (1*32 + 24) /* GPIO_2_24 */ + +#define MX53_SMD_DCDC1V8_EN (2*32 + 1) /*GPIO_3_1 */ +#define MX53_SMD_AUD_AMP_STBY_B (2*32 + 2) /*GPIO_3_2 */ +#define MX53_SMD_SATA_PWR_EN (2*32 + 3) /*GPIO_3_3 */ +#define MX53_SMD_TPM_OSC_EN (2*32 + 4) /*GPIO_3_4 */ +#define MX53_SMD_WLAN_PD (2*32 + 5) /*GPIO_3_5 */ +#define MX53_SMD_WiFi_BT_PWR_EN (2*32 + 10) /*GPIO_3_10 */ +#define MX53_SMD_RECOVERY_MODE_SW (2*32 + 11) /*GPIO_3_11 */ +#define MX53_SMD_USB_OTG_OC (2*32 + 12) /*GPIO_3_12 */ +#define MX53_SMD_SD1_CD (2*32 + 13) /*GPIO_3_13 */ +#define MX53_SMD_USB_HUB_RESET_B (2*32 + 14) /*GPIO_3_14 */ +#define MX53_SMD_eCOMPASS_INT (2*32 + 15) /*GPIO_3_15 */ +#define MX53_SMD_CAP_TCH_INT1 (2*32 + 20) /* GPIO_3_20 */ +#define MX53_SMD_BT_PRIORITY (2*32 + 21) /* GPIO_3_21 */ +#define MX53_SMD_ALS_INT (2*32 + 22) /* GPIO_3_22 */ +#define MX53_SMD_TPM_INT (2*32 + 26) /* GPIO_3_26 */ +#define MX53_SMD_MODEM_WKUP (2*32 + 27) /* GPIO_3_27 */ +#define MX53_SMD_BT_RESET (2*32 + 28) /* GPIO_3_28 */ +#define MX53_SMD_TPM_RST_B (2*32 + 29) /* GPIO_3_29 */ +#define MX53_SMD_CHRG_OR_CMOS (2*32 + 30) /* GPIO_3_30 */ +#define MX53_SMD_CAP_TCH_INT0 (2*32 + 31) /* GPIO_3_31 */ + +#define MX53_SMD_CHA_ISET (3*32 + 2) /* GPIO_4_2 */ +#define MX53_SMD_SYS_EJECT (3*32 + 3) /* GPIO_4_3 */ +#define MX53_SMD_HDMI_CEC_D (3*32 + 4) /* GPIO_4_4 */ + +#define MX53_SMD_MODEM_DISABLE_B (3*32 + 10) /* GPIO_4_10 */ +#define MX53_SMD_SD1_WP (3*32 + 11) /* GPIO_4_11 */ +#define MX53_SMD_DCDC5V_BB_EN (3*32 + 14) /* GPIO_4_14 */ +#define MX53_SMD_WLAN_HOST_WAKE (3*32 + 15) /* GPIO_4_15 */ + +#define MX53_SMD_HDMI_RESET_B (4*32 + 0) /* GPIO_5_0 */ +#define MX53_SMD_MODEM_RESET_B (4*32 + 2) /* GPIO_5_2 */ +#define MX53_SMD_KEY_INT (4*32 + 4) /* GPIO_5_4 */ + +#define MX53_SMD_CAP_TCH_FUN0 (5*32 + 6) /* GPIO_6_6 */ +#define MX53_SMD_CSI0_RST (5*32 + 9) /* GPIO_6_9 */ +#define MX53_SMD_CSI0_PWN (5*32 + 10) /* GPIO_6_10 */ +#define MX53_SMD_OSC_CKIH1_EN (5*32 + 11) /* GPIO_6_11 */ +#define MX53_SMD_HDMI_INT (5*32 + 12) /* GPIO_6_12 */ +#define MX53_SMD_LCD_PWR_EN (5*32 + 13) /* GPIO_6_13 */ +#define MX53_SMD_ACCL_INT1_IN (5*32 + 15) /* GPIO_6_15 */ +#define MX53_SMD_ACCL_INT2_IN (5*32 + 16) /* GPIO_6_16 */ +#define MX53_SMD_AC_IN (5*32 + 17) /* GPIO_6_17 */ +#define MX53_SMD_PWR_GOOD (5*32 + 18) /* GPIO_6_18 */ + +#define MX53_SMD_CABC_EN0 (6*32 + 2) /* GPIO_7_2 */ +#define MX53_SMD_DOCK_DECTECT (6*32 + 3) /* GPIO_7_3 */ +#define MX53_SMD_FEC_RST (6*32 + 6) /* GPIO_7_6 */ +#define MX53_SMD_USER_DEG_CHG_NONE (6*32 + 7) /* GPIO_7_7 */ +#define MX53_SMD_USB_OTG_PWR_EN (6*32 + 8) /* GPIO_7_8 */ +#define MX53_SMD_DEVELOP_MODE_SW (6*32 + 9) /* GPIO_7_9 */ +#define MX53_SMD_CABC_EN1 (6*32 + 10) /* GPIO_7_10 */ +#define MX53_SMD_PMIC_INT (6*32 + 11) /* GPIO_7_11 */ +#define MX53_SMD_CAP_TCH_FUN1 (6*32 + 13) /* GPIO_7_13 */ + +extern int __init mx53_smd_init_da9052(void); + +static struct pad_desc mx53_smd_pads[] = { + /* DI_VGA_HSYNC */ + MX53_PAD_EIM_OE__DI1_PIN7, + /* HDMI reset */ + MX53_PAD_EIM_WAIT__GPIO_5_0, + /* DI_VGA_VSYNC */ + MX53_PAD_EIM_RW__DI1_PIN8, + /* CSPI1 */ + MX53_PAD_EIM_EB2__CSPI_SS0, + MX53_PAD_EIM_D16__CSPI1_SCLK, + MX53_PAD_EIM_D17__CSPI1_MISO, + MX53_PAD_EIM_D18__CSPI1_MOSI, + MX53_PAD_EIM_D19__CSPI_SS1, + /* BT: UART3*/ + MX53_PAD_EIM_D23__UART3_CTS, + MX53_PAD_EIM_D24_UART3_TXD, + MX53_PAD_EIM_EB3__UART3_RTS, + MX53_PAD_EIM_D25__UART3_RXD, + /* LID_OPN_CLS_SW*/ + MX53_PAD_EIM_CS0__GPIO_2_23, + /* GPS_PPS */ + MX53_PAD_EIM_CS1__GPIO_2_24, + /* FEC_PWR_EN */ + MX53_PAD_EIM_A22__GPIO_2_16, + /* CAP_TCH_FUN0*/ + MX53_PAD_EIM_A23__GPIO_6_6, + /* KEY_INT */ + MX53_PAD_EIM_A24__GPIO_5_4, + /* MODEM_RESET_B */ + MX53_PAD_EIM_A25__GPIO_5_2, + /* CAP_TCH_INT1 */ + MX53_PAD_EIM_D20__GPIO_3_20, + /* BT_PRIORITY */ + MX53_PAD_EIM_D21__GPIO_3_21, + /* ALS_INT */ + MX53_PAD_EIM_D22__GPIO_3_22, + /* TPM_INT */ + MX53_PAD_EIM_D26__GPIO_3_26, + /* MODEM_WKUP */ + MX53_PAD_EIM_D27__GPIO_3_27, + /* BT_RESET */ + MX53_PAD_EIM_D28__GPIO_3_28, + /* TPM_RST_B */ + MX53_PAD_EIM_D29__GPIO_3_29, + /* CHARGER_NOW_OR_CMOS_RUN */ + MX53_PAD_EIM_D30__GPIO_3_30, + /* CAP_TCH_INT0 */ + MX53_PAD_EIM_D31__GPIO_3_31, + /* DCDC1V8_EN */ + MX53_PAD_EIM_DA1__GPIO_3_1, + /* AUD_AMP_STBY_B */ + MX53_PAD_EIM_DA2__GPIO_3_2, + /* SATA_PWR_EN */ + MX53_PAD_EIM_DA3__GPIO_3_3, + /* TPM_OSC_EN */ + MX53_PAD_EIM_DA4__GPIO_3_4, + /* WLAN_PD */ + MX53_PAD_EIM_DA5__GPIO_3_5, + /* WiFi_BT_PWR_EN */ + MX53_PAD_EIM_DA10__GPIO_3_10, + /* RECOVERY_MODE_SW */ + MX53_PAD_EIM_DA11__GPIO_3_11, + /* USB_OTG_OC */ + MX53_PAD_EIM_DA12__GPIO_3_12, + /* SD1_CD */ + MX53_PAD_EIM_DA13__GPIO_3_13, + /* USB_HUB_RESET_B */ + MX53_PAD_EIM_DA14__GPIO_3_14, + /* eCOMPASS_IN */ + MX53_PAD_EIM_DA15__GPIO_3_15, + /* HDMI_INT */ + MX53_PAD_NANDF_WE_B__GPIO_6_12, + /* LCD_PWR_EN */ + MX53_PAD_NANDF_RE_B__GPIO_6_13, + /* CSI0_RST */ + MX53_PAD_NANDF_WP_B__GPIO_6_9, + /* CSI0_PWN */ + MX53_PAD_NANDF_RB0__GPIO_6_10, + /* OSC_CKIH1_EN */ + MX53_PAD_NANDF_CS0__GPIO_6_11, + /* ACCL_INT1_IN */ + MX53_PAD_NANDF_CS2__GPIO_6_15, + /* ACCL_INT2_IN */ + MX53_PAD_NANDF_CS3__GPIO_6_16, + /* AUDMUX */ + MX53_PAD_CSI0_D4__AUD3_TXC, + MX53_PAD_CSI0_D5__AUD3_TXD, + MX53_PAD_CSI0_D6__AUD3_TXFS, + MX53_PAD_CSI0_D7__AUD3_RXD, + /* I2C1 */ + MX53_PAD_CSI0_D8__I2C1_SDA, + MX53_PAD_CSI0_D9__I2C1_SCL, + /* UART1 */ + MX53_PAD_CSI0_D10__UART1_TXD, + MX53_PAD_CSI0_D11__UART1_RXD, + /* CSI0 */ + MX53_PAD_CSI0_D12__CSI0_D12, + MX53_PAD_CSI0_D13__CSI0_D13, + MX53_PAD_CSI0_D14__CSI0_D14, + MX53_PAD_CSI0_D15__CSI0_D15, + MX53_PAD_CSI0_D16__CSI0_D16, + MX53_PAD_CSI0_D17__CSI0_D17, + MX53_PAD_CSI0_D18__CSI0_D18, + MX53_PAD_CSI0_D19__CSI0_D19, + MX53_PAD_CSI0_VSYNC__CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK, + /* DISPLAY */ + MX53_PAD_DI0_DISP_CLK__DI0_DISP_CLK, + MX53_PAD_DI0_PIN15__DI0_PIN15, + MX53_PAD_DI0_PIN2__DI0_PIN2, + MX53_PAD_DI0_PIN3__DI0_PIN3, + MX53_PAD_DISP0_DAT0__DISP0_DAT0, + MX53_PAD_DISP0_DAT1__DISP0_DAT1, + MX53_PAD_DISP0_DAT2__DISP0_DAT2, + MX53_PAD_DISP0_DAT3__DISP0_DAT3, + MX53_PAD_DISP0_DAT4__DISP0_DAT4, + MX53_PAD_DISP0_DAT5__DISP0_DAT5, + MX53_PAD_DISP0_DAT6__DISP0_DAT6, + MX53_PAD_DISP0_DAT7__DISP0_DAT7, + MX53_PAD_DISP0_DAT8__DISP0_DAT8, + MX53_PAD_DISP0_DAT9__DISP0_DAT9, + MX53_PAD_DISP0_DAT10__DISP0_DAT10, + MX53_PAD_DISP0_DAT11__DISP0_DAT11, + MX53_PAD_DISP0_DAT12__DISP0_DAT12, + MX53_PAD_DISP0_DAT13__DISP0_DAT13, + MX53_PAD_DISP0_DAT14__DISP0_DAT14, + MX53_PAD_DISP0_DAT15__DISP0_DAT15, + MX53_PAD_DISP0_DAT16__DISP0_DAT16, + MX53_PAD_DISP0_DAT17__DISP0_DAT17, + MX53_PAD_DISP0_DAT18__DISP0_DAT18, + MX53_PAD_DISP0_DAT19__DISP0_DAT19, + MX53_PAD_DISP0_DAT20__DISP0_DAT20, + MX53_PAD_DISP0_DAT21__DISP0_DAT21, + MX53_PAD_DISP0_DAT22__DISP0_DAT22, + MX53_PAD_DISP0_DAT23__DISP0_DAT23, + /* FEC */ + MX53_PAD_FEC_MDC__FEC_MDC, + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_REF_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_CRS_DV, + MX53_PAD_FEC_RXD1__FEC_RXD1, + MX53_PAD_FEC_RXD0__FEC_RXD0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TXD1, + MX53_PAD_FEC_TXD0__FEC_TXD0, + /* AUDMUX5 */ + MX53_PAD_KEY_COL0__AUD5_TXC, + MX53_PAD_KEY_ROW0__AUD5_TXD, + MX53_PAD_KEY_COL1__AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUD5_RXD, + /* MODEM_DISABLE_B */ + MX53_PAD_KEY_COL2__GPIO_4_10, + /* SD1_WP */ + MX53_PAD_KEY_ROW2__GPIO_4_11, + /* I2C2 */ + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + /* DCDC5V_BB_EN */ + MX53_PAD_KEY_COL4__GPIO_4_14, + /* WLAN_HOST_WAKE */ + MX53_PAD_KEY_ROW4__GPIO_4_15, + /* SD1 */ + MX53_PAD_SD1_CMD__SD1_CMD, + MX53_PAD_SD1_CLK__SD1_CLK, + MX53_PAD_SD1_DATA0__SD1_DATA0, + MX53_PAD_SD1_DATA1__SD1_DATA1, + MX53_PAD_SD1_DATA2__SD1_DATA2, + MX53_PAD_SD1_DATA3__SD1_DATA3, + /* SD2 */ + MX53_PAD_SD2_CMD__SD2_CMD, + MX53_PAD_SD2_CLK__SD2_CLK, + MX53_PAD_SD2_DATA0__SD2_DAT0, + MX53_PAD_SD2_DATA1__SD2_DAT1, + MX53_PAD_SD2_DATA2__SD2_DAT2, + MX53_PAD_SD2_DATA3__SD2_DAT3, + /* UART2 */ + MX53_PAD_ATA_BUFFER_EN__UART2_RXD, + MX53_PAD_ATA_DMARQ__UART2_TXD, + /* DEVELOP_MODE_SW */ + MX53_PAD_ATA_CS_0__GPIO_7_9, + /* CABC_EN1 */ + MX53_PAD_ATA_CS_1__GPIO_7_10, + /* FEC_nRST */ + MX53_PAD_ATA_DA_0__GPIO_7_6, + /* USER_DEBUG_OR_CHARGER_DONE */ + MX53_PAD_ATA_DA_1__GPIO_7_7, + /* USB_OTG_PWR_EN */ + MX53_PAD_ATA_DA_2__GPIO_7_8, + /* SD3 */ + MX53_PAD_ATA_DATA8__SD3_DAT0, + MX53_PAD_ATA_DATA9__SD3_DAT1, + MX53_PAD_ATA_DATA10__SD3_DAT2, + MX53_PAD_ATA_DATA11__SD3_DAT3, + MX53_PAD_ATA_DATA0__SD3_DAT4, + MX53_PAD_ATA_DATA1__SD3_DAT5, + MX53_PAD_ATA_DATA2__SD3_DAT6, + MX53_PAD_ATA_DATA3__SD3_DAT7, + MX53_PAD_ATA_IORDY__SD3_CLK, + MX53_PAD_ATA_RESET_B__SD3_CMD, + /* FEC_nINT */ + MX53_PAD_ATA_DATA4__GPIO_2_4, + /* HEADPHONE DET*/ + MX53_PAD_ATA_DATA5__GPIO_2_5, + /* ZigBee_INT*/ + MX53_PAD_ATA_DATA6__GPIO_2_6, + /* ZigBee_RESET_B */ + MX53_PAD_ATA_DATA7__GPIO_2_7, + /* GPS_RESET_B*/ + MX53_PAD_ATA_DATA12__GPIO_2_12, + /* WAKEUP_ZigBee */ + MX53_PAD_ATA_DATA13__GPIO_2_13, + /* KEY_VOL- */ + MX53_PAD_ATA_DATA14__GPIO_2_14, + /* KEY_VOL+ */ + MX53_PAD_ATA_DATA15__GPIO_2_15, + /* DOCK_DECTECT */ + MX53_PAD_ATA_DIOR__GPIO_7_3, + /* AC_IN */ + MX53_PAD_ATA_DIOW__GPIO_6_17, + /* PWR_GOOD */ + MX53_PAD_ATA_DMACK__GPIO_6_18, + /* CABC_EN0 */ + MX53_PAD_ATA_INTRQ__GPIO_7_2, + MX53_PAD_GPIO_0__SSI_EXT1_CLK, + MX53_PAD_GPIO_1__PWMO, + /* KEY_RESET */ + MX53_PAD_GPIO_2__GPIO_1_2, + /* I2C3 */ + MX53_PAD_GPIO_3__I2C3_SCL, + MX53_PAD_GPIO_6__I2C3_SDA, + /* SATA_CLK_GPEN */ + MX53_PAD_GPIO_4__GPIO_1_4, + /* PMIC_FAULT */ + MX53_PAD_GPIO_5__GPIO_1_5, + /* SYS_ON_OFF_CTL */ + MX53_PAD_GPIO_7__GPIO_1_7, + /* PMIC_ON_OFF_REQ */ + MX53_PAD_GPIO_8__GPIO_1_8, + /* CHA_ISET */ + MX53_PAD_GPIO_12__GPIO_4_2, + /* SYS_EJECT */ + MX53_PAD_GPIO_13__GPIO_4_3, + /* HDMI_CEC_D */ + MX53_PAD_GPIO_14__GPIO_4_4, + /* PMIC_INT */ + MX53_PAD_GPIO_16__GPIO_7_11, + MX53_PAD_GPIO_17__SPDIF_OUT1, + /* CAP_TCH_FUN1 */ + MX53_PAD_GPIO_18__GPIO_7_13, + /* LVDS */ + MX53_PAD_LVDS0_TX3_P__LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LVDS0_TX0, + MX53_PAD_LVDS1_TX3_P__LVDS1_TX3, + MX53_PAD_LVDS1_TX2_P__LVDS1_TX2, + MX53_PAD_LVDS1_CLK_P__LVDS1_CLK, + MX53_PAD_LVDS1_TX1_P__LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LVDS1_TX0, +}; + +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 1600x1200 @ 60 Hz 162M pixel clk*/ + "UXGA", 60, 1600, 1200, 6172, + 304, 64, + 1, 46, + 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, + 0,}, + /* 2 LVDS modes, had better remove from here */ + { + "1080P60", 60, 1920, 1080, 7692, + 100, 40, + 30, 3, + 10, 2, + 0, + FB_VMODE_NONINTERLACED, + 0,}, + { + "XGA", 60, 1024, 768, 15385, + 220, 40, + 21, 7, + 60, 10, + 0, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +extern void mx5_ipu_reset(void); +static struct mxc_ipu_config mxc_ipu_data = { + .rev = 3, + .reset = mx5_ipu_reset, +}; + +extern void mx5_vpu_reset(void); +static struct mxc_vpu_platform_data mxc_vpu_data = { + .reset = mx5_vpu_reset, +}; + +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 4, + .spi_version = 23, + .chipselect_active = NULL, + .chipselect_inactive = NULL, +}; + +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "DA9052_BUCK_CORE", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static struct mxc_bus_freq_platform_data bus_freq_data = { + .gp_reg_id = "DA9052_BUCK_CORE", + .lp_reg_id = "DA9052_BUCK_PRO", +}; + +static struct tve_platform_data tve_data = { + .dac_reg = "DA9052_LDO7", +}; + +static struct ldb_platform_data ldb_data = { + .ext_ref = 1, +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +static struct resource mxcfb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, + { + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +extern int primary_di; +static int __init mxc_init_fb(void) +{ + if (!machine_is_mx53_smd()) + return 0; + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX53_SMD_HDMI_RESET_B, 0); + msleep(10); + gpio_set_value(MX53_SMD_HDMI_RESET_B, 1); + msleep(10); +} + +static struct mxc_lcd_platform_data sii902x_hdmi_data = { + .reset = sii902x_hdmi_reset, +}; + +static struct imxi2c_platform_data mxci2c_data = { + .bitrate = 100000, +}; + +static struct mxc_camera_platform_data camera_data = { + .analog_regulator = "DA9052_LDO7", + .core_regulator = "DA9052_LDO9", + .mclk = 24000000, + .csi = 0, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "mma8451", + .addr = 0x1C, + }, + { + .type = "ov3640", + .addr = 0x3C, + .platform_data = (void *)&camera_data, + }, +}; + +static u16 smd_touchkey_martix[4] = { + KEY_BACK, KEY_HOME, KEY_MENU, KEY_SEARCH, +}; + +static struct mpr121_platform_data mpr121_keyboard_platdata = { + .keycount = ARRAY_SIZE(smd_touchkey_martix), + .vdd_uv = 3300000, + .matrix = smd_touchkey_martix, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "mpr121_touchkey", + .addr = 0x5a, + .irq = IOMUX_TO_IRQ_V3(MX53_SMD_KEY_INT), + .platform_data = &mpr121_keyboard_platdata, + }, +}; + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ +} + +static struct gpio_keys_button smd_buttons[] = { + GPIO_BUTTON(MX53_SMD_KEY_VOL_UP, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(MX53_SMD_KEY_VOL_DOWN, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static struct gpio_keys_platform_data smd_button_data = { + .buttons = smd_buttons, + .nbuttons = ARRAY_SIZE(smd_buttons), +}; + +static struct platform_device smd_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &smd_button_data, + } +}; + +static void __init smd_add_device_buttons(void) +{ + platform_device_register(&smd_button_device); +} +#else +static void __init smd_add_device_buttons(void) {} +#endif + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + .type = "sii902x", + .addr = 0x39, + .irq = IOMUX_TO_IRQ_V3(MX53_SMD_HDMI_INT), + .platform_data = &sii902x_hdmi_data, + }, +}; + +static void mx53_gpio_usbotg_driver_vbus(bool on) +{ + if (on) + gpio_set_value(MX53_SMD_USB_OTG_PWR_EN, 1); + else + gpio_set_value(MX53_SMD_USB_OTG_PWR_EN, 0); +} + +static int sdhc_write_protect(struct device *dev) +{ + int ret = 0; + + if (to_platform_device(dev)->id == 0) + ret = gpio_get_value(MX53_SMD_SD1_WP); + + return ret; +} + +static unsigned int sdhc_get_card_det_status(struct device *dev) +{ + int ret = 0; + + if (to_platform_device(dev)->id == 0) + ret = gpio_get_value(MX53_SMD_SD1_CD); + + return ret; +} + +static struct mxc_mmc_platform_data mmc1_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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 0, + .status = sdhc_get_card_det_status, + .wp_status = sdhc_write_protect, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +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 = 400000, + .max_clk = 50000000, + .card_inserted_state = 1, + .clock_mmc = "esdhc_clk", + .power_mmc = NULL, +}; + +static struct mxc_mmc_platform_data mmc3_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 | MMC_CAP_8_BIT_DATA | MMC_CAP_DATA_DDR, + .min_clk = 400000, + .max_clk = 50000000, + .card_inserted_state = 1, + .clock_mmc = "esdhc_clk", +}; + + +static int mxc_sgtl5000_amp_enable(int enable) +{ + gpio_request(MX53_SMD_AUD_AMP_STBY_B, "amp-standby"); + if (enable) + gpio_direction_output(MX53_SMD_AUD_AMP_STBY_B, 1); + else + gpio_direction_output(MX53_SMD_AUD_AMP_STBY_B, 0); + gpio_free(MX53_SMD_AUD_AMP_STBY_B); + return 0; +} + +static int headphone_det_status(void) +{ + return (gpio_get_value(MX53_SMD_HEADPHONE_DEC) == 0); +} + +static int mxc_sgtl5000_init(void); + +static struct mxc_audio_platform_data sgtl5000_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .hp_irq = IOMUX_TO_IRQ_V3(MX53_SMD_HEADPHONE_DEC), + .hp_status = headphone_det_status, + .amp_enable = mxc_sgtl5000_amp_enable, + .init = mxc_sgtl5000_init, +}; + +static int mxc_sgtl5000_init(void) +{ + sgtl5000_data.sysclk = 22579200; + return 0; +} + +static struct platform_device mxc_sgtl5000_device = { + .name = "imx-3stack-sgtl5000", +}; + +static struct mxc_asrc_platform_data mxc_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */ + /* Source from CCM spdif_clk (24M) for 48k and 32k + * It's not accurate + */ + .spdif_clk_48000 = 1, + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static void mx53_smd_bt_reset(void) +{ + gpio_request(MX53_SMD_BT_RESET, "bt-reset"); + gpio_direction_output(MX53_SMD_BT_RESET, 0); + /* pull down reset pin at least >5ms */ + mdelay(6); + /* pull up after power supply BT */ + gpio_set_value(MX53_SMD_BT_RESET, 1); + gpio_free(MX53_SMD_BT_RESET); + msleep(100); + /* Bluetooth need some time to reset */ +} + +static int mx53_smd_bt_power_change(int status) +{ + if (status) + mx53_smd_bt_reset(); + + return 0; +} + +static struct platform_device mxc_bt_rfkill = { + .name = "mxc_bt_rfkill", +}; + +static struct mxc_bt_rfkill_platform_data mxc_bt_rfkill_data = { + .power_change = mx53_smd_bt_power_change, +}; + +static void mx53_smd_power_off(void) +{ + gpio_request(MX53_SMD_SYS_ON_OFF_CTL, "power-off"); + gpio_set_value(MX53_SMD_SYS_ON_OFF_CTL, 0); +} +/*! + * 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) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_1G; + int left_mem = 0; + int gpu_mem = SZ_128M; + int fb_mem = SZ_32M; + char *str; + + mxc_set_cpu_type(MXC_CPU_MX53); + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_device.resource[5].start = + mem_tag->u.mem.start + left_mem; + gpu_device.resource[5].end = + gpu_device.resource[5].start + gpu_mem - 1; +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ + defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) + if (fb_mem) { + mxcfb_resources[0].start = + gpu_device.resource[5].end + 1; + mxcfb_resources[0].end = + mxcfb_resources[0].start + fb_mem - 1; + } else { + mxcfb_resources[0].start = 0; + mxcfb_resources[0].end = 0; + } +#endif + } +} + +static void __init mx53_smd_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads, + ARRAY_SIZE(mx53_smd_pads)); + + /* SD1 CD */ + gpio_request(MX53_SMD_SD1_CD, "sd1-cd"); + gpio_direction_input(MX53_SMD_SD1_CD); + /* SD1 WP */ + gpio_request(MX53_SMD_SD1_WP, "sd1-wp"); + gpio_direction_input(MX53_SMD_SD1_WP); + + /* reset FEC PHY */ + gpio_request(MX53_SMD_FEC_RST, "fec-rst"); + gpio_direction_output(MX53_SMD_FEC_RST, 0); + gpio_set_value(MX53_SMD_FEC_RST, 0); + msleep(1); + gpio_set_value(MX53_SMD_FEC_RST, 1); + + /* headphone_det_b */ + gpio_request(MX53_SMD_HEADPHONE_DEC, "headphone-dec"); + gpio_direction_input(MX53_SMD_HEADPHONE_DEC); + + /* USB PWR enable */ + gpio_request(MX53_SMD_USB_OTG_PWR_EN, "usb-pwr"); + gpio_direction_output(MX53_SMD_USB_OTG_PWR_EN, 0); + + /* Enable MX53_SMD_DCDC1V8_EN */ + gpio_request(MX53_SMD_DCDC1V8_EN, "dcdc1v8-en"); + gpio_direction_output(MX53_SMD_DCDC1V8_EN, 1); + gpio_set_value(MX53_SMD_DCDC1V8_EN, 1); + + /* Enable OSC_CKIH1_EN for audio */ + gpio_request(MX53_SMD_OSC_CKIH1_EN, "osc-en"); + gpio_direction_output(MX53_SMD_OSC_CKIH1_EN, 1); + gpio_set_value(MX53_SMD_OSC_CKIH1_EN, 1); + + /* Sii902x HDMI controller */ + gpio_request(MX53_SMD_HDMI_RESET_B, "disp0-pwr-en"); + gpio_direction_output(MX53_SMD_HDMI_RESET_B, 0); + gpio_request(MX53_SMD_HDMI_INT, "disp0-det-int"); + gpio_direction_input(MX53_SMD_HDMI_INT); + + /* MPR121 capacitive button */ + gpio_request(MX53_SMD_KEY_INT, "cap-button-irq"); + gpio_direction_input(MX53_SMD_KEY_INT); + gpio_free(MX53_SMD_KEY_INT); + + /* Camera reset */ + gpio_request(MX53_SMD_CSI0_RST, "cam-reset"); + gpio_set_value(MX53_SMD_CSI0_RST, 1); + + /* Camera power down */ + gpio_request(MX53_SMD_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(MX53_SMD_CSI0_PWN, 1); + msleep(1); + gpio_set_value(MX53_SMD_CSI0_PWN, 0); + + /* Enable WiFi/BT Power*/ + gpio_request(MX53_SMD_WiFi_BT_PWR_EN, "bt-wifi-pwren"); + gpio_direction_output(MX53_SMD_WiFi_BT_PWR_EN, 1); + + /* WiFi Power up sequence */ + gpio_request(MX53_SMD_WLAN_PD, "wifi-pd"); + gpio_direction_output(MX53_SMD_WLAN_PD, 1); + mdelay(1); + gpio_set_value(MX53_SMD_WLAN_PD, 0); + mdelay(5); + gpio_set_value(MX53_SMD_WLAN_PD, 1); + gpio_free(MX53_SMD_WLAN_PD); +} + +/*! + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); + mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "ssi_ext1_clk"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(MX53_SMD_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(MX53_SMD_SD1_CD); + + mxc_cpu_common_init(); + mx53_smd_io_init(); + + pm_power_off = mx53_smd_power_off; + mxc_register_device(&mxc_dma_device, NULL); + mxc_register_device(&mxc_wdt_device, NULL); + mxc_register_device(&mxcspi1_device, &mxcspi1_data); + mxc_register_device(&mxci2c_devices[0], &mxci2c_data); + mxc_register_device(&mxci2c_devices[1], &mxci2c_data); + mxc_register_device(&mxci2c_devices[2], &mxci2c_data); + mx53_smd_init_da9052(); + + mxc_register_device(&mxc_rtc_device, NULL); + mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); + mxc_register_device(&mxc_ldb_device, &ldb_data); + mxc_register_device(&mxc_tve_device, &tve_data); + mxc_register_device(&mxcvpu_device, &mxc_vpu_data); + mxc_register_device(&gpu_device, &z160_revision); + mxc_register_device(&mxcscc_device, NULL); + mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, &bus_freq_data); + mxc_register_device(&mxc_iim_device, &iim_data); + mxc_register_device(&mxc_pwm2_device, NULL); + mxc_register_device(&mxc_pwm1_backlight_device, &mxc_pwm_backlight_data); + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + mxc_register_device(&mxcsdhc2_device, &mmc2_data); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + mxc_register_device(&mxc_ssi1_device, NULL); + mxc_register_device(&mxc_ssi2_device, NULL); + mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); + mxc_register_device(&ahci_fsl_device, &sata_data); + /* AHCI SATA PWR EN(DCDC_5V, DCDC_3V3_BB) on SATA bus */ + gpio_request(MX53_SMD_SATA_PWR_EN, "sata-pwr-en"); + gpio_direction_output(MX53_SMD_SATA_PWR_EN, 1); + + mxc_register_device(&mxc_fec_device, &fec_data); + /* ASRC is only available for MX53 TO2.0 */ + if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) { + mxc_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + clk_put(mxc_asrc_data.asrc_core_clk); + mxc_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + clk_put(mxc_asrc_data.asrc_audio_clk); + mxc_register_device(&mxc_asrc_device, &mxc_asrc_data); + } + + 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)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mx5_set_otghost_vbus_func(mx53_gpio_usbotg_driver_vbus); + mx5_usb_dr_init(); + mx5_usbh1_init(); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); + mxc_register_device(&mxc_bt_rfkill, &mxc_bt_rfkill_data); + smd_add_device_buttons(); +} + +static void __init mx53_smd_timer_init(void) +{ + struct clk *uart_clk; + + mx53_clocks_init(32768, 24000000, 22579200, 0); + + uart_clk = clk_get_sys("mxcintuart.0", NULL); + early_console_setup(MX53_BASE_ADDR(UART1_BASE_ADDR), uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx53_smd_timer_init, +}; + +/* + * The following uses standard kernel macros define in arch.h in order to + * initialize __mach_desc_MX53_SMD data structure. + */ +MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c b/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c new file mode 100644 index 000000000000..e6cf9e380f30 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2010-2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +/* + * mx53_smd_pmic_da9053.c -- i.MX53 SMD driver for pmic da9053 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/pm.h> +#include <linux/mfd/da9052/led.h> +#include <linux/mfd/da9052/tsi.h> +#include <mach/irqs.h> +#include <mach/iomux-mx53.h> + +#define DA9052_LDO(max, min, rname, suspend_mv) \ +{\ + .constraints = {\ + .name = (rname), \ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + |REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + .state_mem = { \ + .uV = suspend_mv * 1000, \ + .mode = REGULATOR_MODE_NORMAL, \ + .enabled = (0 == suspend_mv) ? 0 : 1, \ + .disabled = 0, \ + }, \ + },\ +} + +/* currently the suspend_mv field here takes no effects for DA9053 +preset-voltage have to be done in the latest stage during +suspend*/ +static struct regulator_init_data da9052_regulators_init[] = { + DA9052_LDO(DA9052_LDO1_VOLT_UPPER, + DA9052_LDO1_VOLT_LOWER, "DA9052_LDO1", 1300), + DA9052_LDO(DA9052_LDO2_VOLT_UPPER, + DA9052_LDO2_VOLT_LOWER, "DA9052_LDO2", 1300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO3", 3300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO4", 2775), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO5", 1300), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO6", 1200), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO7", 2750), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO8", 1800), + DA9052_LDO(DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, "DA9052_LDO9", 2500), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO10", 1200), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_CORE", 850), + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_PRO", 950), + DA9052_LDO(DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, "DA9052_BUCK_MEM", 1500), + DA9052_LDO(DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, "DA9052_BUCK_PERI", 2500) +}; + + +#define MX53_SMD_WiFi_BT_PWR_EN (2*32 + 10) /*GPIO_3_10 */ +struct regulator_init_data wifi_bt_reg_initdata = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +static struct fixed_voltage_config wifi_bt_reg_config = { + .supply_name = "wifi_bt", + .microvolts = 3300000, + .gpio = MX53_SMD_WiFi_BT_PWR_EN, + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &wifi_bt_reg_initdata, +}; + +static struct platform_device wifi_bt_reg_device = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &wifi_bt_reg_config, + }, +}; + + +static struct da9052_tsi_platform_data da9052_tsi = { + .pen_up_interval = 50, + .tsi_delay_bit_shift = 6, + .tsi_skip_bit_shift = 3, + .num_gpio_tsi_register = 3, + .tsi_supply_voltage = 2500, + /* This is the DA9052 LDO number used for powering the TSI */ + .tsi_ref_source = 9, + .max_tsi_delay = TSI_DELAY_4SLOTS, + .max_tsi_skip_slot = TSI_SKIP_330SLOTS, +}; + +static struct da9052_led_platform_data da9052_gpio_led[] = { + { + .id = DA9052_LED_4, + .name = "LED_GPIO14", + }, + { + .id = DA9052_LED_5, + .name = "LED_GPIO15", + }, +}; + +static struct da9052_leds_platform_data da9052_gpio_leds = { + .num_leds = ARRAY_SIZE(da9052_gpio_led), + .led = da9052_gpio_led, +}; + + +static struct da9052_bat_platform_data da9052_bat = { + .sw_temp_control_en = 0, + .monitoring_interval = 500, + .sw_bat_temp_threshold = 60, + .sw_junc_temp_threshold = 120, + .hysteresis_window_size = 1, + .current_monitoring_window = 10, + .bat_with_no_resistor = 62, + .bat_capacity_limit_low = 4, + .bat_capacity_full = 100, + .bat_capacity_limit_high = 70, + .chg_hysteresis_const = 89, + .hysteresis_reading_interval = 1000, + .hysteresis_no_of_reading = 10, + .filter_size = 4, + .bat_volt_cutoff = 2800, + .vbat_first_valid_detect_iteration = 3, +}; + +static void da9052_init_ssc_cache(struct da9052 *da9052) +{ + unsigned char cnt; + + /* First initialize all registers as Non-volatile */ + for (cnt = 0; cnt < DA9052_REG_CNT; cnt++) { + da9052->ssc_cache[cnt].type = NON_VOLATILE; + da9052->ssc_cache[cnt].status = INVALID; + da9052->ssc_cache[cnt].val = 0; + } + + /* Now selectively set type for all Volatile registers */ + /* Reg 1 - 9 */ + da9052->ssc_cache[DA9052_STATUSA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_FAULTLOG_REG].type = VOLATILE; + + /* Reg 15 */ + da9052->ssc_cache[DA9052_CONTROLB_REG].type = VOLATILE; + /* Reg - 17 */ + da9052->ssc_cache[DA9052_CONTROLD_REG].type = VOLATILE; + /* Reg - 60 */ + da9052->ssc_cache[DA9052_SUPPLY_REG].type = VOLATILE; + /* Reg - 62 */ + da9052->ssc_cache[DA9052_CHGBUCK_REG].type = VOLATILE; + + /* Reg 67 - 68 */ + da9052->ssc_cache[DA9052_INPUTCONT_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_CHGTIME_REG].type = VOLATILE; + + /* Reg - 70 */ + da9052->ssc_cache[DA9052_BOOST_REG].type = VOLATILE; + + /* Reg - 81 */ + da9052->ssc_cache[DA9052_ADCMAN_REG].type = VOLATILE; + + /* Reg - 83 - 85 */ + da9052->ssc_cache[DA9052_ADCRESL_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ADCRESH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_VDDRES_REG].type = VOLATILE; + + /* Reg - 87 */ + da9052->ssc_cache[DA9052_ICHGAV_REG].type = VOLATILE; + + /* Reg - 90 */ + da9052->ssc_cache[DA9052_TBATRES_REG].type = VOLATILE; + + /* Reg - 95 */ + da9052->ssc_cache[DA9052_ADCIN4RES_REG].type = VOLATILE; + + /* Reg - 98 */ + da9052->ssc_cache[DA9052_ADCIN5RES_REG].type = VOLATILE; + + /* Reg - 101 */ + da9052->ssc_cache[DA9052_ADCIN6RES_REG].type = VOLATILE; + + /* Reg - 104 */ + da9052->ssc_cache[DA9052_TJUNCRES_REG].type = VOLATILE; + + /* Reg 106 - 110 */ + da9052->ssc_cache[DA9052_TSICONTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIXMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIYMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSILSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIZMSB_REG].type = VOLATILE; + + /* Reg 111 - 117 */ + da9052->ssc_cache[DA9052_COUNTS_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMI_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMO_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTY_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ALARMMI_REG].type = VOLATILE; + + /* Reg 122 - 125 */ + da9052->ssc_cache[DA9052_SECONDA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDD_REG].type = VOLATILE; + + /* Following addresses are not assigned to any register */ + da9052->ssc_cache[126].type = VOLATILE; + da9052->ssc_cache[127].type = VOLATILE; +} + + +#define MX53_SMD_DA9052_IRQ (6*32 + 11) /* GPIO7_11 */ + +static int __init smd_da9052_init(struct da9052 *da9052) +{ + /* Configuring for DA9052 interrupt servce */ + /* s3c_gpio_setpull(DA9052_IRQ_PIN, S3C_GPIO_PULL_UP);*/ + int ret; + /* Set interrupt as LOW LEVEL interrupt source */ + set_irq_type(IOMUX_TO_IRQ_V3(MX53_SMD_DA9052_IRQ), IRQF_TRIGGER_LOW); + + da9052_init_ssc_cache(da9052); + ret = platform_device_register(&wifi_bt_reg_device); + + return 0; +} + +static struct da9052_platform_data __initdata da9052_plat = { + .init = smd_da9052_init, + .num_regulators = ARRAY_SIZE(da9052_regulators_init), + .regulators = da9052_regulators_init, + .led_data = &da9052_gpio_leds, + .tsi_data = &da9052_tsi, + .bat_data = &da9052_bat, + /* .gpio_base = GPIO_BOARD_START, */ +}; + + +static struct i2c_board_info __initdata da9052_i2c_device = { + I2C_BOARD_INFO(DA9052_SSC_I2C_DEVICE_NAME, DA9052_I2C_ADDR >> 1), + .irq = IOMUX_TO_IRQ_V3(MX53_SMD_DA9052_IRQ), + .platform_data = &da9052_plat, +}; + +int __init mx53_smd_init_da9052(void) +{ + return i2c_register_board_info(0, &da9052_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx53_smd_rfkill.c b/arch/arm/mach-mx5/mx53_smd_rfkill.c new file mode 100644 index 000000000000..f0f95a839381 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_smd_rfkill.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @file mxc_bt_rfkill.c + * + * @brief This driver is implement a rfkill control interface of bluetooth + * chip on i.MX serial boards. Register the power regulator function and + * reset function in platform data. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/rfkill.h> +#include <mach/hardware.h> +#include <mach/mxc_rfkill.h> + +static int mxc_bt_set_block(void *rfkdata, bool blocked) +{ + struct mxc_bt_rfkill_platform_data *data = rfkdata; + int ret; + + pr_info("rfkill: BT RF going to : %s\n", blocked ? "off" : "on"); + if (!blocked) + ret = data->power_change(1); + else + ret = data->power_change(0); + + return ret; +} + +static const struct rfkill_ops mxc_bt_rfkill_ops = { + .set_block = mxc_bt_set_block, +}; + +static int mxc_bt_rfkill_probe(struct platform_device *dev) +{ + int rc; + struct rfkill *rfk; + + struct mxc_bt_rfkill_platform_data *data = dev->dev.platform_data; + + if (data->power_change == NULL) { + rc = -EINVAL; + dev_err(&dev->dev, "no power_change function\n"); + goto error_check_func; + } + + rfk = rfkill_alloc("mxc-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, + &mxc_bt_rfkill_ops, data); + + if (!rfk) { + rc = -ENOMEM; + goto error_rfk_alloc; + } + + rfkill_set_led_trigger_name(rfk, "mxc_bt"); + + rc = rfkill_register(rfk); + if (rc) + goto error_rfkill; + + platform_set_drvdata(dev, rfk); + printk(KERN_INFO "mxc_bt_rfkill driver success loaded\n"); + return 0; + +error_rfkill: + rfkill_destroy(rfk); +error_rfk_alloc: +error_check_func: + return rc; +} + +static int __devexit mxc_bt_rfkill_remove(struct platform_device *dev) +{ + struct mxc_bt_rfkill_platform_data *data = dev->dev.platform_data; + struct rfkill *rfk = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + if (rfk) { + rfkill_unregister(rfk); + rfkill_destroy(rfk); + } + + data->power_change(0); + + return 0; +} + +static struct platform_driver mxc_bt_rfkill_drv = { + .driver = { + .name = "mxc_bt_rfkill", + }, + + .probe = mxc_bt_rfkill_probe, + .remove = __devexit_p(mxc_bt_rfkill_remove), +}; + +static int __init mxc_bt_rfkill_init(void) +{ + return platform_driver_register(&mxc_bt_rfkill_drv); +} + +module_init(mxc_bt_rfkill_init); + +static void __exit mxc_bt_rfkill_exit(void) +{ + platform_driver_unregister(&mxc_bt_rfkill_drv); +} + +module_exit(mxc_bt_rfkill_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("RFKill control interface of BT on MX53 SMD"); diff --git a/arch/arm/mach-mx5/mx53_wp.c b/arch/arm/mach-mx5/mx53_wp.c new file mode 100644 index 000000000000..a09cb735c1d0 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_wp.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <mach/hardware.h> +#include "mx53_wp.h" + +/*! + * @file mach-mx5/mx53_wp.c + * + * @brief This file contains the information about MX53 CPU working points. + * + * @ingroup MSL_MX53 + */ +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); +static int num_cpu_wp; +static struct cpu_wp *cpu_wp_table; + +/* working point for auto*/ +static struct cpu_wp cpu_wp_aec[] = { + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, +}; + +/* working point for consumer 1G*/ +static struct cpu_wp cpu_wp_ces[] = { + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1200000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .cpu_podf = 1, + .cpu_voltage = 950000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .cpu_podf = 4, + .cpu_voltage = 900000,}, +}; + +/* working point for consumer 1.2G*/ +static struct cpu_wp cpu_wp_ces_1_2g[] = { + { + .pll_rate = 1200000000, + .cpu_rate = 1200000000, + .pdf = 0, + .mfi = 12, + .mfd = 1, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1300000,}, + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1200000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .cpu_podf = 1, + .cpu_voltage = 950000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .cpu_podf = 4, + .cpu_voltage = 900000,}, +}; + + +struct cpu_wp *mx53_get_cpu_wp(int *wp) +{ + *wp = num_cpu_wp; + return cpu_wp_table; +} + +void mx53_set_num_cpu_wp(int num) +{ + num_cpu_wp = num; + return; +} + +void mx53_set_cpu_part_number(enum mx53_cpu_part_number part_num) +{ + get_cpu_wp = mx53_get_cpu_wp; + set_num_cpu_wp = mx53_set_num_cpu_wp; + + switch (part_num) { + case IMX53_CEC_1_2G: + cpu_wp_table = cpu_wp_ces_1_2g; + num_cpu_wp = ARRAY_SIZE(cpu_wp_ces_1_2g); + break; + case IMX53_CEC: + cpu_wp_table = cpu_wp_ces; + num_cpu_wp = ARRAY_SIZE(cpu_wp_ces); + break; + case IMX53_AEC: + default: + cpu_wp_table = cpu_wp_aec; + num_cpu_wp = ARRAY_SIZE(cpu_wp_aec); + break; + } +} + + diff --git a/arch/arm/mach-mx5/mx53_wp.h b/arch/arm/mach-mx5/mx53_wp.h new file mode 100644 index 000000000000..353b5320a1b8 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_wp.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ARCH_ARM_MACH_MX53_WP_H__ +#define __ARCH_ARM_MACH_MX53_WP_H__ +#include <linux/types.h> + +/*! + * @file mach-mx5/mx53_wp.h + * + * @brief This file contains the information about MX53 CPU working points. + * + * @ingroup MSL_MX53 + */ +enum mx53_cpu_part_number { + IMX53_AEC, /* automative and infotainment AP */ + IMX53_CEC, /* Consumer AP, CPU freq is up to 1G */ + IMX53_CEC_1_2G, /* Consumer AP, CPU freq is up to 1.2GHZ */ +}; + +void mx53_set_cpu_part_number(enum mx53_cpu_part_number part_num); + +#endif /*__ARCH_ARM_MACH_MX53_WP_H__ */ + + + diff --git a/arch/arm/mach-mx5/pm.c b/arch/arm/mach-mx5/pm.c new file mode 100644 index 000000000000..f07681be3748 --- /dev/null +++ b/arch/arm/mach-mx5/pm.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008-2011 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/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/regulator/machine.h> +#include <linux/proc_fs.h> +#include <linux/cpufreq.h> +#include <linux/iram_alloc.h> +#include <linux/fsl_devices.h> +#include <asm/mach-types.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> +#include <asm/delay.h> +#include <asm/mach/map.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#ifdef CONFIG_ARCH_MX50 +#include <mach/iomux-mx50.h> +#endif + +#define MXC_SRPG_EMPGC0_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2C0) +#define MXC_SRPG_EMPGC1_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2D0) +#define DATABAHN_CTL_REG0 0 +#define DATABAHN_CTL_REG19 0x4c +#define DATABAHN_CTL_REG79 0x13c +#define DATABAHN_PHY_REG25 0x264 +#define MX53_OFFSET 0x20000000 + +static struct cpu_wp *cpu_wp_tbl; +static int cpu_wp_nr; +static struct clk *cpu_clk; +static struct mxc_pm_platform_data *pm_data; + +#if defined(CONFIG_CPU_FREQ) +static int org_freq; +extern int cpufreq_suspended; +extern int set_cpu_freq(int wp); +#endif + + +static struct device *pm_dev; +struct clk *gpc_dvfs_clk; +extern void cpu_do_suspend_workaround(u32 sdclk_iomux_addr); +extern void mx50_suspend(u32 databahn_addr); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void __iomem *databahn_base; +extern void da9053_suspend_cmd(void); +extern void pm_da9053_i2c_init(u32 base_addr); + +extern int iram_ready; +void *suspend_iram_base; +void (*suspend_in_iram)(void *sdclk_iomux_addr) = NULL; +void __iomem *suspend_param1; + +#define TZIC_WAKEUP0_OFFSET 0x0E00 +#define TZIC_WAKEUP1_OFFSET 0x0E04 +#define TZIC_WAKEUP2_OFFSET 0x0E08 +#define TZIC_WAKEUP3_OFFSET 0x0E0C +#define GPIO7_0_11_IRQ_BIT (0x1<<11) + +static void mx53_smd_loco_irq_wake_fixup(void) +{ + void __iomem *tzic_base; + tzic_base = ioremap(MX53_TZIC_BASE_ADDR, SZ_4K); + if (NULL == tzic_base) { + pr_err("fail to map MX53_TZIC_BASE_ADDR\n"); + return; + } + __raw_writel(0, tzic_base + TZIC_WAKEUP0_OFFSET); + __raw_writel(0, tzic_base + TZIC_WAKEUP1_OFFSET); + __raw_writel(0, tzic_base + TZIC_WAKEUP2_OFFSET); + /* only enable irq wakeup for da9053 */ + __raw_writel(GPIO7_0_11_IRQ_BIT, tzic_base + TZIC_WAKEUP3_OFFSET); + iounmap(tzic_base); + pr_debug("only da9053 irq is wakeup-enabled\n"); +} + +static int mx5_suspend_enter(suspend_state_t state) +{ + 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); + 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; + + if (state == PM_SUSPEND_MEM) { + local_flush_tlb_all(); + flush_cache_all(); + + if (cpu_is_mx51() || cpu_is_mx53()) { + if (machine_is_mx53_smd() || + machine_is_mx53_loco()) { + mx53_smd_loco_irq_wake_fixup(); + da9053_suspend_cmd(); + } + /* Run the suspend code from iRAM. */ + suspend_in_iram(suspend_param1); + + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + } else { + if (machine_is_mx50_rdp() && pm_data->suspend_enter) + pm_data->suspend_enter(); + /* Suspend now. */ + suspend_in_iram(databahn_base); + if (machine_is_mx50_rdp() && pm_data->suspend_exit) + pm_data->suspend_exit(); + } + } else { + cpu_do_idle(); + } + clk_disable(gpc_dvfs_clk); + + return 0; +} + + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mx5_suspend_prepare(void) +{ +#if defined(CONFIG_CPU_FREQ) +#define MX53_SUSPEND_CPU_WP 400000000 + struct cpufreq_freqs freqs; + u32 suspend_wp = 0; + org_freq = clk_get_rate(cpu_clk); + /* workaround for mx53 to suspend on 400MHZ wp */ + if (cpu_is_mx53()) + for (suspend_wp = 0; suspend_wp < cpu_wp_nr; suspend_wp++) + if (cpu_wp_tbl[suspend_wp].cpu_rate + == MX53_SUSPEND_CPU_WP) + break; + if (suspend_wp == cpu_wp_nr) + suspend_wp = 0; + pr_info("suspend wp cpu=%d\n", cpu_wp_tbl[suspend_wp].cpu_rate); + freqs.old = org_freq / 1000; + freqs.new = cpu_wp_tbl[suspend_wp].cpu_rate / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + cpufreq_suspended = 1; + if (clk_get_rate(cpu_clk) != cpu_wp_tbl[suspend_wp].cpu_rate) { + set_cpu_freq(cpu_wp_tbl[suspend_wp].cpu_rate); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } +#endif + return 0; +} + +/* + * Called before devices are re-setup. + */ +static void mx5_suspend_finish(void) +{ +#if defined(CONFIG_CPU_FREQ) + struct cpufreq_freqs freqs; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = org_freq / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + cpufreq_suspended = 0; + + if (org_freq != clk_get_rate(cpu_clk)) { + set_cpu_freq(org_freq); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } +#endif +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void mx5_suspend_end(void) +{ +} + +static int mx5_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +struct platform_suspend_ops mx5_suspend_ops = { + .valid = mx5_pm_valid, + .prepare = mx5_suspend_prepare, + .enter = mx5_suspend_enter, + .finish = mx5_suspend_finish, + .end = mx5_suspend_end, +}; + +static int __devinit mx5_pm_probe(struct platform_device *pdev) +{ + pm_dev = &pdev->dev; + pm_data = pdev->dev.platform_data; + + return 0; +} + +static struct platform_driver mx5_pm_driver = { + .driver = { + .name = "mx5_pm", + }, + .probe = mx5_pm_probe, +}; + +static int __init pm_init(void) +{ + unsigned long iram_paddr; + + pr_info("Static Power Management for Freescale i.MX5\n"); + if (platform_driver_register(&mx5_pm_driver) != 0) { + printk(KERN_ERR "mx5_pm_driver register failed\n"); + return -ENODEV; + } + suspend_set_ops(&mx5_suspend_ops); + /* Move suspend routine into iRAM */ + iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K, + MT_HIGH_VECTORS); + + if (cpu_is_mx51() || cpu_is_mx53()) { + suspend_param1 = IO_ADDRESS(IOMUXC_BASE_ADDR + 0x4b8); + memcpy(suspend_iram_base, cpu_do_suspend_workaround, + SZ_4K); + } else if (cpu_is_mx50()) { + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into self refresh mode manually. + */ + memcpy(suspend_iram_base, mx50_suspend, SZ_4K); + + suspend_param1 = databahn_base; + } + suspend_in_iram = (void *)suspend_iram_base; + + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + + 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); + } + printk(KERN_INFO "PM driver module loaded\n"); + + if (machine_is_mx53_smd() || + machine_is_mx53_loco()) + pm_da9053_i2c_init(I2C1_BASE_ADDR - MX53_OFFSET); + + return 0; +} + + +static void __exit pm_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&mx5_pm_driver); +} + +module_init(pm_init); +module_exit(pm_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("PM driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx5/pm_da9053.c b/arch/arm/mach-mx5/pm_da9053.c new file mode 100644 index 000000000000..6e24fb2823d4 --- /dev/null +++ b/arch/arm/mach-mx5/pm_da9053.c @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/mfd/da9052/reg.h> + +#include <mach/hardware.h> +#include <mach/i2c.h> + +/** Defines ******************************************************************** +*******************************************************************************/ + + +/* IMX I2C registers */ +#define IMX_I2C_IADR 0x00 /* i2c slave address */ +#define IMX_I2C_IFDR 0x04 /* i2c frequency divider */ +#define IMX_I2C_I2CR 0x08 /* i2c control */ +#define IMX_I2C_I2SR 0x0C /* i2c status */ +#define IMX_I2C_I2DR 0x10 /* i2c transfer data */ + +/* Bits of IMX I2C registers */ +#define I2SR_RXAK 0x01 +#define I2SR_IIF 0x02 +#define I2SR_SRW 0x04 +#define I2SR_IAL 0x10 +#define I2SR_IBB 0x20 +#define I2SR_IAAS 0x40 +#define I2SR_ICF 0x80 +#define I2CR_RSTA 0x04 +#define I2CR_TXAK 0x08 +#define I2CR_MTX 0x10 +#define I2CR_MSTA 0x20 +#define I2CR_IIEN 0x40 +#define I2CR_IEN 0x80 + +static void __iomem *base; +static int stopped; + +/** Functions for IMX I2C adapter driver *************************************** +*******************************************************************************/ + +static int pm_i2c_imx_bus_busy(int for_busy) +{ + unsigned int temp; + + while (1) { + temp = readb(base + IMX_I2C_I2SR); + if (for_busy && (temp & I2SR_IBB)) + break; + if (!for_busy && !(temp & I2SR_IBB)) + break; + pr_debug("waiting bus busy=%d\n", for_busy); + } + + return 0; +} + +static int pm_i2c_imx_trx_complete(void) +{ + unsigned int temp; + while (!((temp = readb(base + IMX_I2C_I2SR)) & I2SR_IIF)) + pr_debug("waiting or I2SR_IIF\n"); + temp &= ~I2SR_IIF; + writeb(temp, base + IMX_I2C_I2SR); + + return 0; +} + +static int pm_i2c_imx_acked(void) +{ + if (readb(base + IMX_I2C_I2SR) & I2SR_RXAK) { + pr_info("<%s> No ACK\n", __func__); + return -EIO; /* No ACK */ + } + return 0; +} + +static int pm_i2c_imx_start(void) +{ + unsigned int temp = 0; + int result; + + /* Enable I2C controller */ + writeb(0, base + IMX_I2C_I2SR); + writeb(I2CR_IEN, base + IMX_I2C_I2CR); + + /* Wait controller to be stable */ + udelay(50); + + /* Start I2C transaction */ + temp = readb(base + IMX_I2C_I2CR); + temp |= I2CR_MSTA; + writeb(temp, base + IMX_I2C_I2CR); + result = pm_i2c_imx_bus_busy(1); + + temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; + writeb(temp, base + IMX_I2C_I2CR); + return result; +} + +static void pm_i2c_imx_stop(void) +{ + unsigned int temp = 0; + + /* Stop I2C transaction */ + temp = readb(base + IMX_I2C_I2CR); + temp &= ~(I2CR_MSTA | I2CR_MTX); + writeb(temp, base + IMX_I2C_I2CR); + + pm_i2c_imx_bus_busy(0); + + /* Disable I2C controller */ + writeb(0, base + IMX_I2C_I2CR); +} + +static int pm_i2c_imx_write(struct i2c_msg *msgs) +{ + int i, result; + + /* write slave address */ + writeb(msgs->addr << 1, base + IMX_I2C_I2DR); + result = pm_i2c_imx_trx_complete(); + if (result) + return result; + result = pm_i2c_imx_acked(); + if (result) + return result; + + /* write data */ + for (i = 0; i < msgs->len; i++) { + writeb(msgs->buf[i], base + IMX_I2C_I2DR); + result = pm_i2c_imx_trx_complete(); + if (result) + return result; + result = pm_i2c_imx_acked(); + if (result) + return result; + } + return 0; +} + +static int pm_i2c_imx_read(struct i2c_msg *msgs) +{ + int i, result; + unsigned int temp; + + /* write slave address */ + writeb((msgs->addr << 1) | 0x01, base + IMX_I2C_I2DR); + result = pm_i2c_imx_trx_complete(); + if (result) + return result; + result = pm_i2c_imx_acked(); + if (result) + return result; + + /* setup bus to read data */ + temp = readb(base + IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + if (msgs->len - 1) + temp &= ~I2CR_TXAK; + writeb(temp, base + IMX_I2C_I2CR); + readb(base + IMX_I2C_I2DR); /* dummy read */ + + /* read data */ + for (i = 0; i < msgs->len; i++) { + result = pm_i2c_imx_trx_complete(); + if (result) + return result; + if (i == (msgs->len - 1)) { + /* It must generate STOP before read I2DR to prevent + controller from generating another clock cycle */ + temp = readb(base + IMX_I2C_I2CR); + temp &= ~(I2CR_MSTA | I2CR_MTX); + writeb(temp, base + IMX_I2C_I2CR); + pm_i2c_imx_bus_busy(0); + stopped = 1; + } else if (i == (msgs->len - 2)) { + temp = readb(base + IMX_I2C_I2CR); + temp |= I2CR_TXAK; + writeb(temp, base + IMX_I2C_I2CR); + } + msgs->buf[i] = readb(base + IMX_I2C_I2DR); + } + return 0; +} + +int pm_i2c_imx_xfer(struct i2c_msg *msgs, int num) +{ + unsigned int i, temp; + int result; + + /* Start I2C transfer */ + result = pm_i2c_imx_start(); + if (result) + goto fail0; + + /* read/write data */ + for (i = 0; i < num; i++) { + if (i) { + temp = readb(base + IMX_I2C_I2CR); + temp |= I2CR_RSTA; + writeb(temp, base + IMX_I2C_I2CR); + result = pm_i2c_imx_bus_busy(1); + if (result) + goto fail0; + } + /* write/read data */ + if (msgs[i].flags & I2C_M_RD) + result = pm_i2c_imx_read(&msgs[i]); + else + result = pm_i2c_imx_write(&msgs[i]); + if (result) + goto fail0; + } + +fail0: + /* Stop I2C transfer */ + pm_i2c_imx_stop(); + + return (result < 0) ? result : num; +} + +void pm_da9053_i2c_init(u32 base_addr) +{ + base = ioremap(base_addr, SZ_4K); +} + +void pm_da9053_i2c_deinit(void) +{ + iounmap(base); +} + +void pm_da9053_read_reg(u8 reg, u8 *value) +{ + unsigned char buf[2] = {0, 0}; + struct i2c_msg i2cmsg[2]; + buf[0] = reg; + i2cmsg[0].addr = 0x48 ; + i2cmsg[0].len = 1; + i2cmsg[0].buf = &buf[0]; + + i2cmsg[0].flags = 0; + + i2cmsg[1].addr = 0x48 ; + i2cmsg[1].len = 1; + i2cmsg[1].buf = &buf[1]; + + i2cmsg[1].flags = I2C_M_RD; + + pm_i2c_imx_xfer(i2cmsg, 2); + *value = buf[1]; +} + +void pm_da9053_write_reg(u8 reg, u8 value) +{ + unsigned char buf[2] = {0, 0}; + struct i2c_msg i2cmsg[2]; + buf[0] = reg; + buf[1] = value; + i2cmsg[0].addr = 0x48 ; + i2cmsg[0].len = 2; + i2cmsg[0].buf = &buf[0]; + i2cmsg[0].flags = 0; + pm_i2c_imx_xfer(i2cmsg, 1); +} + +/* have to hard-code the preset voltage here for they share the register +as the normal setting on Da9053 */ +/* preset buck core to 850 mv */ +#define BUCKCORE_SUSPEND_PRESET 0xCE +/* preset buck core to 950 mv */ +#define BUCKPRO_SUSPEND_PRESET 0xD2 +/* preset ldo6 to 1200 mv */ +#define LDO6_SUSPEND_PRESET 0xC0 +/* preset ldo10 to 1200 mv */ +#define iLDO10_SUSPEND_PRESET 0xC0 +#define CONF_BIT 0x80 + +static u8 volt_settings[DA9052_LDO10_REG - DA9052_BUCKCORE_REG + 1]; +static void pm_da9053_preset_voltage(void) +{ + u8 reg, data; + for (reg = DA9052_BUCKCORE_REG; + reg <= DA9052_LDO10_REG; reg++) { + pm_da9053_read_reg(reg, &data); + volt_settings[reg - DA9052_BUCKCORE_REG] = data; + data |= CONF_BIT; + pm_da9053_write_reg(reg, data); + } + pm_da9053_write_reg(DA9052_BUCKCORE_REG, BUCKCORE_SUSPEND_PRESET); + pm_da9053_write_reg(DA9052_BUCKPRO_REG, BUCKPRO_SUSPEND_PRESET); + pm_da9053_write_reg(DA9052_LDO6_REG, LDO6_SUSPEND_PRESET); + pm_da9053_write_reg(DA9052_LDO10_REG, iLDO10_SUSPEND_PRESET); +} + +#define DA9053_SLEEP_DELAY 0x1f +int da9053_suspend_cmd(void) +{ + unsigned char buf[2] = {0, 0}; + struct clk *i2c_clk; + u8 data; + buf[0] = 29; + + i2c_clk = clk_get(NULL, "i2c_clk"); + if (IS_ERR(i2c_clk)) { + pr_err("unable to get i2c clk\n"); + return PTR_ERR(i2c_clk); + } + clk_enable(i2c_clk); + + pm_da9053_preset_voltage(); + + pm_da9053_read_reg(DA9052_ID01_REG, &data); + data &= ~(DA9052_ID01_DEFSUPPLY | DA9052_ID01_nRESMODE); + pm_da9053_write_reg(DA9052_ID01_REG, data); + + pm_da9053_write_reg(DA9052_SEQB_REG, DA9053_SLEEP_DELAY); + + pm_da9053_read_reg(DA9052_CONTROLB_REG, &data); + data |= DA9052_CONTROLB_DEEPSLEEP; + pm_da9053_write_reg(DA9052_CONTROLB_REG, data); + + clk_disable(i2c_clk); + clk_put(i2c_clk); + return 0; +} + +void da9053_restore_volt_settings(void) +{ + u8 reg; + for (reg = DA9052_BUCKCORE_REG; + reg <= DA9052_LDO10_REG; reg++) + pm_da9053_write_reg(reg, + volt_settings[reg - DA9052_BUCKCORE_REG]); +} + +int da9053_poweroff_cmd(void) +{ + unsigned char buf[2] = {0, 0}; + struct clk *i2c_clk; + u8 data; + buf[0] = 29; + + i2c_clk = clk_get(NULL, "i2c_clk"); + if (IS_ERR(i2c_clk)) { + pr_err("unable to get i2c clk\n"); + return PTR_ERR(i2c_clk); + } + clk_enable(i2c_clk); + + pm_da9053_read_reg(DA9052_CONTROLB_REG, &data); + data |= DA9052_CONTROLB_SHUTDOWN; + pm_da9053_write_reg(DA9052_CONTROLB_REG, data); + + clk_disable(i2c_clk); + clk_put(i2c_clk); + return 0; +} + diff --git a/arch/arm/mach-mx5/regs-apbh.h b/arch/arm/mach-mx5/regs-apbh.h new file mode 100644 index 000000000000..23b9f4baa404 --- /dev/null +++ b/arch/arm/mach-mx5/regs-apbh.h @@ -0,0 +1,512 @@ +/* + * Freescale APBH Register Definitions + * + * Copyright 2008-2010 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 + * + * This file is created by xml file. Don't Edit it. + * + * Xml Revision: 1.3 + * Template revision: 1.3 + */ + +#ifndef __ARCH_ARM___APBH_H +#define __ARCH_ARM___APBH_H + + +#define HW_APBH_CTRL0 (0x00000000) +#define HW_APBH_CTRL0_SET (0x00000004) +#define HW_APBH_CTRL0_CLR (0x00000008) +#define HW_APBH_CTRL0_TOG (0x0000000c) + +#define BM_APBH_CTRL0_SFTRST 0x80000000 +#define BM_APBH_CTRL0_CLKGATE 0x40000000 +#define BM_APBH_CTRL0_AHB_BURST8_EN 0x20000000 +#define BM_APBH_CTRL0_APB_BURST_EN 0x10000000 +#define BP_APBH_CTRL0_RSVD0 16 +#define BM_APBH_CTRL0_RSVD0 0x0FFF0000 +#define BF_APBH_CTRL0_RSVD0(v) \ + (((v) << 16) & BM_APBH_CTRL0_RSVD0) +#define BP_APBH_CTRL0_CLKGATE_CHANNEL 0 +#define BM_APBH_CTRL0_CLKGATE_CHANNEL 0x0000FFFF +#define BF_APBH_CTRL0_CLKGATE_CHANNEL(v) \ + (((v) << 0) & BM_APBH_CTRL0_CLKGATE_CHANNEL) +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND0 0x0001 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND1 0x0002 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND2 0x0004 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND3 0x0008 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND4 0x0010 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND5 0x0020 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND6 0x0040 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND7 0x0080 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__SSP 0x0100 + +#define HW_APBH_CTRL1 (0x00000010) +#define HW_APBH_CTRL1_SET (0x00000014) +#define HW_APBH_CTRL1_CLR (0x00000018) +#define HW_APBH_CTRL1_TOG (0x0000001c) + +#define BM_APBH_CTRL1_CH15_CMDCMPLT_IRQ_EN 0x80000000 +#define BM_APBH_CTRL1_CH14_CMDCMPLT_IRQ_EN 0x40000000 +#define BM_APBH_CTRL1_CH13_CMDCMPLT_IRQ_EN 0x20000000 +#define BM_APBH_CTRL1_CH12_CMDCMPLT_IRQ_EN 0x10000000 +#define BM_APBH_CTRL1_CH11_CMDCMPLT_IRQ_EN 0x08000000 +#define BM_APBH_CTRL1_CH10_CMDCMPLT_IRQ_EN 0x04000000 +#define BM_APBH_CTRL1_CH9_CMDCMPLT_IRQ_EN 0x02000000 +#define BM_APBH_CTRL1_CH8_CMDCMPLT_IRQ_EN 0x01000000 +#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ_EN 0x00800000 +#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ_EN 0x00400000 +#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ_EN 0x00200000 +#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ_EN 0x00100000 +#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ_EN 0x00080000 +#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ_EN 0x00040000 +#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ_EN 0x00020000 +#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ_EN 0x00010000 +#define BM_APBH_CTRL1_CH15_CMDCMPLT_IRQ 0x00008000 +#define BM_APBH_CTRL1_CH14_CMDCMPLT_IRQ 0x00004000 +#define BM_APBH_CTRL1_CH13_CMDCMPLT_IRQ 0x00002000 +#define BM_APBH_CTRL1_CH12_CMDCMPLT_IRQ 0x00001000 +#define BM_APBH_CTRL1_CH11_CMDCMPLT_IRQ 0x00000800 +#define BM_APBH_CTRL1_CH10_CMDCMPLT_IRQ 0x00000400 +#define BM_APBH_CTRL1_CH9_CMDCMPLT_IRQ 0x00000200 +#define BM_APBH_CTRL1_CH8_CMDCMPLT_IRQ 0x00000100 +#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ 0x00000080 +#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ 0x00000040 +#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ 0x00000020 +#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ 0x00000010 +#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ 0x00000008 +#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ 0x00000004 +#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ 0x00000002 +#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001 + +#define HW_APBH_CTRL2 (0x00000020) +#define HW_APBH_CTRL2_SET (0x00000024) +#define HW_APBH_CTRL2_CLR (0x00000028) +#define HW_APBH_CTRL2_TOG (0x0000002c) + +#define BM_APBH_CTRL2_CH15_ERROR_STATUS 0x80000000 +#define BV_APBH_CTRL2_CH15_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH15_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH14_ERROR_STATUS 0x40000000 +#define BV_APBH_CTRL2_CH14_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH14_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH13_ERROR_STATUS 0x20000000 +#define BV_APBH_CTRL2_CH13_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH13_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH12_ERROR_STATUS 0x10000000 +#define BV_APBH_CTRL2_CH12_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH12_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH11_ERROR_STATUS 0x08000000 +#define BV_APBH_CTRL2_CH11_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH11_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH10_ERROR_STATUS 0x04000000 +#define BV_APBH_CTRL2_CH10_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH10_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH9_ERROR_STATUS 0x02000000 +#define BV_APBH_CTRL2_CH9_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH9_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH8_ERROR_STATUS 0x01000000 +#define BV_APBH_CTRL2_CH8_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH8_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH7_ERROR_STATUS 0x00800000 +#define BV_APBH_CTRL2_CH7_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH7_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH6_ERROR_STATUS 0x00400000 +#define BV_APBH_CTRL2_CH6_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH6_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH5_ERROR_STATUS 0x00200000 +#define BV_APBH_CTRL2_CH5_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH5_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH4_ERROR_STATUS 0x00100000 +#define BV_APBH_CTRL2_CH4_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH4_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH3_ERROR_STATUS 0x00080000 +#define BV_APBH_CTRL2_CH3_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH3_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH2_ERROR_STATUS 0x00040000 +#define BV_APBH_CTRL2_CH2_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH2_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH1_ERROR_STATUS 0x00020000 +#define BV_APBH_CTRL2_CH1_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH1_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH0_ERROR_STATUS 0x00010000 +#define BV_APBH_CTRL2_CH0_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH0_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH15_ERROR_IRQ 0x00008000 +#define BM_APBH_CTRL2_CH14_ERROR_IRQ 0x00004000 +#define BM_APBH_CTRL2_CH13_ERROR_IRQ 0x00002000 +#define BM_APBH_CTRL2_CH12_ERROR_IRQ 0x00001000 +#define BM_APBH_CTRL2_CH11_ERROR_IRQ 0x00000800 +#define BM_APBH_CTRL2_CH10_ERROR_IRQ 0x00000400 +#define BM_APBH_CTRL2_CH9_ERROR_IRQ 0x00000200 +#define BM_APBH_CTRL2_CH8_ERROR_IRQ 0x00000100 +#define BM_APBH_CTRL2_CH7_ERROR_IRQ 0x00000080 +#define BM_APBH_CTRL2_CH6_ERROR_IRQ 0x00000040 +#define BM_APBH_CTRL2_CH5_ERROR_IRQ 0x00000020 +#define BM_APBH_CTRL2_CH4_ERROR_IRQ 0x00000010 +#define BM_APBH_CTRL2_CH3_ERROR_IRQ 0x00000008 +#define BM_APBH_CTRL2_CH2_ERROR_IRQ 0x00000004 +#define BM_APBH_CTRL2_CH1_ERROR_IRQ 0x00000002 +#define BM_APBH_CTRL2_CH0_ERROR_IRQ 0x00000001 + +#define HW_APBH_CHANNEL_CTRL (0x00000030) +#define HW_APBH_CHANNEL_CTRL_SET (0x00000034) +#define HW_APBH_CHANNEL_CTRL_CLR (0x00000038) +#define HW_APBH_CHANNEL_CTRL_TOG (0x0000003c) + +#define BP_APBH_CHANNEL_CTRL_RESET_CHANNEL 16 +#define BM_APBH_CHANNEL_CTRL_RESET_CHANNEL 0xFFFF0000 +#define BF_APBH_CHANNEL_CTRL_RESET_CHANNEL(v) \ + (((v) << 16) & BM_APBH_CHANNEL_CTRL_RESET_CHANNEL) +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND0 0x0001 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND1 0x0002 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND2 0x0004 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND3 0x0008 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND4 0x0010 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND5 0x0020 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND6 0x0040 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__NAND7 0x0080 +#define BV_APBH_CHANNEL_CTRL_RESET_CHANNEL__SSP 0x0100 +#define BP_APBH_CHANNEL_CTRL_FREEZE_CHANNEL 0 +#define BM_APBH_CHANNEL_CTRL_FREEZE_CHANNEL 0x0000FFFF +#define BF_APBH_CHANNEL_CTRL_FREEZE_CHANNEL(v) \ + (((v) << 0) & BM_APBH_CHANNEL_CTRL_FREEZE_CHANNEL) +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND0 0x0001 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND1 0x0002 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND2 0x0004 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND3 0x0008 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND4 0x0010 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND5 0x0020 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND6 0x0040 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__NAND7 0x0080 +#define BV_APBH_CHANNEL_CTRL_FREEZE_CHANNEL__SSP 0x0100 + +#define HW_APBH_DEVSEL (0x00000040) + +#define BP_APBH_DEVSEL_CH15 30 +#define BM_APBH_DEVSEL_CH15 0xC0000000 +#define BF_APBH_DEVSEL_CH15(v) \ + (((v) << 30) & BM_APBH_DEVSEL_CH15) +#define BP_APBH_DEVSEL_CH14 28 +#define BM_APBH_DEVSEL_CH14 0x30000000 +#define BF_APBH_DEVSEL_CH14(v) \ + (((v) << 28) & BM_APBH_DEVSEL_CH14) +#define BP_APBH_DEVSEL_CH13 26 +#define BM_APBH_DEVSEL_CH13 0x0C000000 +#define BF_APBH_DEVSEL_CH13(v) \ + (((v) << 26) & BM_APBH_DEVSEL_CH13) +#define BP_APBH_DEVSEL_CH12 24 +#define BM_APBH_DEVSEL_CH12 0x03000000 +#define BF_APBH_DEVSEL_CH12(v) \ + (((v) << 24) & BM_APBH_DEVSEL_CH12) +#define BP_APBH_DEVSEL_CH11 22 +#define BM_APBH_DEVSEL_CH11 0x00C00000 +#define BF_APBH_DEVSEL_CH11(v) \ + (((v) << 22) & BM_APBH_DEVSEL_CH11) +#define BP_APBH_DEVSEL_CH10 20 +#define BM_APBH_DEVSEL_CH10 0x00300000 +#define BF_APBH_DEVSEL_CH10(v) \ + (((v) << 20) & BM_APBH_DEVSEL_CH10) +#define BP_APBH_DEVSEL_CH9 18 +#define BM_APBH_DEVSEL_CH9 0x000C0000 +#define BF_APBH_DEVSEL_CH9(v) \ + (((v) << 18) & BM_APBH_DEVSEL_CH9) +#define BP_APBH_DEVSEL_CH8 16 +#define BM_APBH_DEVSEL_CH8 0x00030000 +#define BF_APBH_DEVSEL_CH8(v) \ + (((v) << 16) & BM_APBH_DEVSEL_CH8) +#define BP_APBH_DEVSEL_CH7 14 +#define BM_APBH_DEVSEL_CH7 0x0000C000 +#define BF_APBH_DEVSEL_CH7(v) \ + (((v) << 14) & BM_APBH_DEVSEL_CH7) +#define BP_APBH_DEVSEL_CH6 12 +#define BM_APBH_DEVSEL_CH6 0x00003000 +#define BF_APBH_DEVSEL_CH6(v) \ + (((v) << 12) & BM_APBH_DEVSEL_CH6) +#define BP_APBH_DEVSEL_CH5 10 +#define BM_APBH_DEVSEL_CH5 0x00000C00 +#define BF_APBH_DEVSEL_CH5(v) \ + (((v) << 10) & BM_APBH_DEVSEL_CH5) +#define BP_APBH_DEVSEL_CH4 8 +#define BM_APBH_DEVSEL_CH4 0x00000300 +#define BF_APBH_DEVSEL_CH4(v) \ + (((v) << 8) & BM_APBH_DEVSEL_CH4) +#define BP_APBH_DEVSEL_CH3 6 +#define BM_APBH_DEVSEL_CH3 0x000000C0 +#define BF_APBH_DEVSEL_CH3(v) \ + (((v) << 6) & BM_APBH_DEVSEL_CH3) +#define BP_APBH_DEVSEL_CH2 4 +#define BM_APBH_DEVSEL_CH2 0x00000030 +#define BF_APBH_DEVSEL_CH2(v) \ + (((v) << 4) & BM_APBH_DEVSEL_CH2) +#define BP_APBH_DEVSEL_CH1 2 +#define BM_APBH_DEVSEL_CH1 0x0000000C +#define BF_APBH_DEVSEL_CH1(v) \ + (((v) << 2) & BM_APBH_DEVSEL_CH1) +#define BP_APBH_DEVSEL_CH0 0 +#define BM_APBH_DEVSEL_CH0 0x00000003 +#define BF_APBH_DEVSEL_CH0(v) \ + (((v) << 0) & BM_APBH_DEVSEL_CH0) + +#define HW_APBH_DMA_BURST_SIZE (0x00000050) + +#define BP_APBH_DMA_BURST_SIZE_CH15 30 +#define BM_APBH_DMA_BURST_SIZE_CH15 0xC0000000 +#define BF_APBH_DMA_BURST_SIZE_CH15(v) \ + (((v) << 30) & BM_APBH_DMA_BURST_SIZE_CH15) +#define BP_APBH_DMA_BURST_SIZE_CH14 28 +#define BM_APBH_DMA_BURST_SIZE_CH14 0x30000000 +#define BF_APBH_DMA_BURST_SIZE_CH14(v) \ + (((v) << 28) & BM_APBH_DMA_BURST_SIZE_CH14) +#define BP_APBH_DMA_BURST_SIZE_CH13 26 +#define BM_APBH_DMA_BURST_SIZE_CH13 0x0C000000 +#define BF_APBH_DMA_BURST_SIZE_CH13(v) \ + (((v) << 26) & BM_APBH_DMA_BURST_SIZE_CH13) +#define BP_APBH_DMA_BURST_SIZE_CH12 24 +#define BM_APBH_DMA_BURST_SIZE_CH12 0x03000000 +#define BF_APBH_DMA_BURST_SIZE_CH12(v) \ + (((v) << 24) & BM_APBH_DMA_BURST_SIZE_CH12) +#define BP_APBH_DMA_BURST_SIZE_CH11 22 +#define BM_APBH_DMA_BURST_SIZE_CH11 0x00C00000 +#define BF_APBH_DMA_BURST_SIZE_CH11(v) \ + (((v) << 22) & BM_APBH_DMA_BURST_SIZE_CH11) +#define BP_APBH_DMA_BURST_SIZE_CH10 20 +#define BM_APBH_DMA_BURST_SIZE_CH10 0x00300000 +#define BF_APBH_DMA_BURST_SIZE_CH10(v) \ + (((v) << 20) & BM_APBH_DMA_BURST_SIZE_CH10) +#define BP_APBH_DMA_BURST_SIZE_CH9 18 +#define BM_APBH_DMA_BURST_SIZE_CH9 0x000C0000 +#define BF_APBH_DMA_BURST_SIZE_CH9(v) \ + (((v) << 18) & BM_APBH_DMA_BURST_SIZE_CH9) +#define BP_APBH_DMA_BURST_SIZE_CH8 16 +#define BM_APBH_DMA_BURST_SIZE_CH8 0x00030000 +#define BF_APBH_DMA_BURST_SIZE_CH8(v) \ + (((v) << 16) & BM_APBH_DMA_BURST_SIZE_CH8) +#define BV_APBH_DMA_BURST_SIZE_CH8__BURST0 0x0 +#define BV_APBH_DMA_BURST_SIZE_CH8__BURST4 0x1 +#define BV_APBH_DMA_BURST_SIZE_CH8__BURST8 0x2 +#define BP_APBH_DMA_BURST_SIZE_CH7 14 +#define BM_APBH_DMA_BURST_SIZE_CH7 0x0000C000 +#define BF_APBH_DMA_BURST_SIZE_CH7(v) \ + (((v) << 14) & BM_APBH_DMA_BURST_SIZE_CH7) +#define BP_APBH_DMA_BURST_SIZE_CH6 12 +#define BM_APBH_DMA_BURST_SIZE_CH6 0x00003000 +#define BF_APBH_DMA_BURST_SIZE_CH6(v) \ + (((v) << 12) & BM_APBH_DMA_BURST_SIZE_CH6) +#define BP_APBH_DMA_BURST_SIZE_CH5 10 +#define BM_APBH_DMA_BURST_SIZE_CH5 0x00000C00 +#define BF_APBH_DMA_BURST_SIZE_CH5(v) \ + (((v) << 10) & BM_APBH_DMA_BURST_SIZE_CH5) +#define BP_APBH_DMA_BURST_SIZE_CH4 8 +#define BM_APBH_DMA_BURST_SIZE_CH4 0x00000300 +#define BF_APBH_DMA_BURST_SIZE_CH4(v) \ + (((v) << 8) & BM_APBH_DMA_BURST_SIZE_CH4) +#define BP_APBH_DMA_BURST_SIZE_CH3 6 +#define BM_APBH_DMA_BURST_SIZE_CH3 0x000000C0 +#define BF_APBH_DMA_BURST_SIZE_CH3(v) \ + (((v) << 6) & BM_APBH_DMA_BURST_SIZE_CH3) +#define BP_APBH_DMA_BURST_SIZE_CH2 4 +#define BM_APBH_DMA_BURST_SIZE_CH2 0x00000030 +#define BF_APBH_DMA_BURST_SIZE_CH2(v) \ + (((v) << 4) & BM_APBH_DMA_BURST_SIZE_CH2) +#define BP_APBH_DMA_BURST_SIZE_CH1 2 +#define BM_APBH_DMA_BURST_SIZE_CH1 0x0000000C +#define BF_APBH_DMA_BURST_SIZE_CH1(v) \ + (((v) << 2) & BM_APBH_DMA_BURST_SIZE_CH1) +#define BP_APBH_DMA_BURST_SIZE_CH0 0 +#define BM_APBH_DMA_BURST_SIZE_CH0 0x00000003 +#define BF_APBH_DMA_BURST_SIZE_CH0(v) \ + (((v) << 0) & BM_APBH_DMA_BURST_SIZE_CH0) + +#define HW_APBH_DEBUG (0x00000060) + +#define BP_APBH_DEBUG_RSVD 1 +#define BM_APBH_DEBUG_RSVD 0xFFFFFFFE +#define BF_APBH_DEBUG_RSVD(v) \ + (((v) << 1) & BM_APBH_DEBUG_RSVD) +#define BM_APBH_DEBUG_GPMI_ONE_FIFO 0x00000001 + +/* + * multi-register-define name HW_APBH_CHn_CURCMDAR + * base 0x00000100 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_CURCMDAR(n) (0x00000100 + (n) * 0x70) +#define BP_APBH_CHn_CURCMDAR_CMD_ADDR 0 +#define BM_APBH_CHn_CURCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBH_CHn_CURCMDAR_CMD_ADDR(v) (v) + +/* + * multi-register-define name HW_APBH_CHn_NXTCMDAR + * base 0x00000110 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_NXTCMDAR(n) (0x00000110 + (n) * 0x70) +#define BP_APBH_CHn_NXTCMDAR_CMD_ADDR 0 +#define BM_APBH_CHn_NXTCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBH_CHn_NXTCMDAR_CMD_ADDR(v) (v) + +/* + * multi-register-define name HW_APBH_CHn_CMD + * base 0x00000120 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_CMD(n) (0x00000120 + (n) * 0x70) +#define BP_APBH_CHn_CMD_XFER_COUNT 16 +#define BM_APBH_CHn_CMD_XFER_COUNT 0xFFFF0000 +#define BF_APBH_CHn_CMD_XFER_COUNT(v) \ + (((v) << 16) & BM_APBH_CHn_CMD_XFER_COUNT) +#define BP_APBH_CHn_CMD_CMDWORDS 12 +#define BM_APBH_CHn_CMD_CMDWORDS 0x0000F000 +#define BF_APBH_CHn_CMD_CMDWORDS(v) \ + (((v) << 12) & BM_APBH_CHn_CMD_CMDWORDS) +#define BP_APBH_CHn_CMD_RSVD1 9 +#define BM_APBH_CHn_CMD_RSVD1 0x00000E00 +#define BF_APBH_CHn_CMD_RSVD1(v) \ + (((v) << 9) & BM_APBH_CHn_CMD_RSVD1) +#define BM_APBH_CHn_CMD_HALTONTERMINATE 0x00000100 +#define BM_APBH_CHn_CMD_WAIT4ENDCMD 0x00000080 +#define BM_APBH_CHn_CMD_SEMAPHORE 0x00000040 +#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020 +#define BM_APBH_CHn_CMD_NANDLOCK 0x00000010 +#define BM_APBH_CHn_CMD_IRQONCMPLT 0x00000008 +#define BM_APBH_CHn_CMD_CHAIN 0x00000004 +#define BP_APBH_CHn_CMD_COMMAND 0 +#define BM_APBH_CHn_CMD_COMMAND 0x00000003 +#define BF_APBH_CHn_CMD_COMMAND(v) \ + (((v) << 0) & BM_APBH_CHn_CMD_COMMAND) +#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER 0x0 +#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE 0x1 +#define BV_APBH_CHn_CMD_COMMAND__DMA_READ 0x2 +#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE 0x3 + +/* + * multi-register-define name HW_APBH_CHn_BAR + * base 0x00000130 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_BAR(n) (0x00000130 + (n) * 0x70) +#define BP_APBH_CHn_BAR_ADDRESS 0 +#define BM_APBH_CHn_BAR_ADDRESS 0xFFFFFFFF +#define BF_APBH_CHn_BAR_ADDRESS(v) (v) + +/* + * multi-register-define name HW_APBH_CHn_SEMA + * base 0x00000140 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_SEMA(n) (0x00000140 + (n) * 0x70) +#define BP_APBH_CHn_SEMA_RSVD2 24 +#define BM_APBH_CHn_SEMA_RSVD2 0xFF000000 +#define BF_APBH_CHn_SEMA_RSVD2(v) \ + (((v) << 24) & BM_APBH_CHn_SEMA_RSVD2) +#define BP_APBH_CHn_SEMA_PHORE 16 +#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000 +#define BF_APBH_CHn_SEMA_PHORE(v) \ + (((v) << 16) & BM_APBH_CHn_SEMA_PHORE) +#define BP_APBH_CHn_SEMA_RSVD1 8 +#define BM_APBH_CHn_SEMA_RSVD1 0x0000FF00 +#define BF_APBH_CHn_SEMA_RSVD1(v) \ + (((v) << 8) & BM_APBH_CHn_SEMA_RSVD1) +#define BP_APBH_CHn_SEMA_INCREMENT_SEMA 0 +#define BM_APBH_CHn_SEMA_INCREMENT_SEMA 0x000000FF +#define BF_APBH_CHn_SEMA_INCREMENT_SEMA(v) \ + (((v) << 0) & BM_APBH_CHn_SEMA_INCREMENT_SEMA) + +/* + * multi-register-define name HW_APBH_CHn_DEBUG1 + * base 0x00000150 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_DEBUG1(n) (0x00000150 + (n) * 0x70) +#define BM_APBH_CHn_DEBUG1_REQ 0x80000000 +#define BM_APBH_CHn_DEBUG1_BURST 0x40000000 +#define BM_APBH_CHn_DEBUG1_KICK 0x20000000 +#define BM_APBH_CHn_DEBUG1_END 0x10000000 +#define BM_APBH_CHn_DEBUG1_SENSE 0x08000000 +#define BM_APBH_CHn_DEBUG1_READY 0x04000000 +#define BM_APBH_CHn_DEBUG1_LOCK 0x02000000 +#define BM_APBH_CHn_DEBUG1_NEXTCMDADDRVALID 0x01000000 +#define BM_APBH_CHn_DEBUG1_RD_FIFO_EMPTY 0x00800000 +#define BM_APBH_CHn_DEBUG1_RD_FIFO_FULL 0x00400000 +#define BM_APBH_CHn_DEBUG1_WR_FIFO_EMPTY 0x00200000 +#define BM_APBH_CHn_DEBUG1_WR_FIFO_FULL 0x00100000 +#define BP_APBH_CHn_DEBUG1_RSVD1 5 +#define BM_APBH_CHn_DEBUG1_RSVD1 0x000FFFE0 +#define BF_APBH_CHn_DEBUG1_RSVD1(v) \ + (((v) << 5) & BM_APBH_CHn_DEBUG1_RSVD1) +#define BP_APBH_CHn_DEBUG1_STATEMACHINE 0 +#define BM_APBH_CHn_DEBUG1_STATEMACHINE 0x0000001F +#define BF_APBH_CHn_DEBUG1_STATEMACHINE(v) \ + (((v) << 0) & BM_APBH_CHn_DEBUG1_STATEMACHINE) +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__IDLE 0x00 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD1 0x01 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD3 0x02 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD2 0x03 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_DECODE 0x04 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_WAIT 0x05 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD4 0x06 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__PIO_REQ 0x07 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_FLUSH 0x08 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_WAIT 0x09 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE 0x0C +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_REQ 0x0D +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_CHAIN 0x0E +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_COMPLETE 0x0F +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__TERMINATE 0x14 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WAIT_END 0x15 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE_WAIT 0x1C +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__HALT_AFTER_TERM 0x1D +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_WAIT 0x1E +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WAIT_READY 0x1F + +/* + * multi-register-define name HW_APBH_CHn_DEBUG2 + * base 0x00000160 + * count 16 + * offset 0x70 + */ +#define HW_APBH_CHn_DEBUG2(n) (0x00000160 + (n) * 0x70) +#define BP_APBH_CHn_DEBUG2_APB_BYTES 16 +#define BM_APBH_CHn_DEBUG2_APB_BYTES 0xFFFF0000 +#define BF_APBH_CHn_DEBUG2_APB_BYTES(v) \ + (((v) << 16) & BM_APBH_CHn_DEBUG2_APB_BYTES) +#define BP_APBH_CHn_DEBUG2_AHB_BYTES 0 +#define BM_APBH_CHn_DEBUG2_AHB_BYTES 0x0000FFFF +#define BF_APBH_CHn_DEBUG2_AHB_BYTES(v) \ + (((v) << 0) & BM_APBH_CHn_DEBUG2_AHB_BYTES) + +#define HW_APBH_VERSION (0x00000800) + +#define BP_APBH_VERSION_MAJOR 24 +#define BM_APBH_VERSION_MAJOR 0xFF000000 +#define BF_APBH_VERSION_MAJOR(v) \ + (((v) << 24) & BM_APBH_VERSION_MAJOR) +#define BP_APBH_VERSION_MINOR 16 +#define BM_APBH_VERSION_MINOR 0x00FF0000 +#define BF_APBH_VERSION_MINOR(v) \ + (((v) << 16) & BM_APBH_VERSION_MINOR) +#define BP_APBH_VERSION_STEP 0 +#define BM_APBH_VERSION_STEP 0x0000FFFF +#define BF_APBH_VERSION_STEP(v) \ + (((v) << 0) & BM_APBH_VERSION_STEP) +#endif /* __ARCH_ARM___APBH_H */ diff --git a/arch/arm/mach-mx5/sdma_script_code_mx50.h b/arch/arm/mach-mx5/sdma_script_code_mx50.h new file mode 100644 index 000000000000..49a79213c54b --- /dev/null +++ b/arch/arm/mach-mx5/sdma_script_code_mx50.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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: "SDMA_CODEX.01.00.00" + +*******************************************************************************/ + +#ifndef SDMA_SCRIPT_CODE_MX50_H +#define SDMA_SCRIPT_CODE_MX50_H + + +/*! +* SDMA ROM scripts start addresses and sizes +*/ + +#define start_ADDR_MX50 0 +#define start_SIZE_MX50 18 + +#define core_ADDR_MX50 80 +#define core_SIZE_MX50 232 + +#define common_ADDR_MX50 312 +#define common_SIZE_MX50 330 + +#define ap_2_ap_ADDR_MX50 642 +#define ap_2_ap_SIZE_MX50 41 + +#define app_2_mcu_ADDR_MX50 683 +#define app_2_mcu_SIZE_MX50 64 + +#define mcu_2_app_ADDR_MX50 747 +#define mcu_2_app_SIZE_MX50 70 + +#define uart_2_mcu_ADDR_MX50 817 +#define uart_2_mcu_SIZE_MX50 74 + +#define shp_2_mcu_ADDR_MX50 891 +#define shp_2_mcu_SIZE_MX50 69 + +#define mcu_2_shp_ADDR_MX50 960 +#define mcu_2_shp_SIZE_MX50 72 + +#define uartsh_2_mcu_ADDR_MX50 1032 +#define uartsh_2_mcu_SIZE_MX50 68 + +#define loop_DMAs_routines_ADDR_MX50 1100 +#define loop_DMAs_routines_SIZE_MX50 227 + +#define test_ADDR_MX50 1327 +#define test_SIZE_MX50 63 + +#define signature_ADDR_MX50 1023 +#define signature_SIZE_MX50 1 + +/*! +* SDMA RAM scripts start addresses and sizes +*/ + +#define mcu_2_ssiapp_ADDR_MX50 6144 +#define mcu_2_ssiapp_SIZE_MX50 96 + +#define mcu_2_ssish_ADDR_MX50 6240 +#define mcu_2_ssish_SIZE_MX50 95 + +/*! +* SDMA RAM image start address and size +*/ + +#define RAM_CODE_START_ADDR_MX50 6144 +#define RAM_CODE_SIZE_MX50 191 + +/*! +* Buffer that holds the SDMA RAM image +*/ +__attribute__ ((__aligned__(4))) +static const short sdma_code_mx50[] = { +0xc1e3, 0x57db, 0x52f3, 0x6a01, 0x008f, 0x00d5, 0x7d01, 0x008d, +0x05a0, 0x5deb, 0x0478, 0x7d03, 0x0479, 0x7d2c, 0x7c36, 0x0479, +0x7c1f, 0x56ee, 0x0f00, 0x0660, 0x7d05, 0x6509, 0x7e43, 0x620a, +0x7e41, 0x981e, 0x620a, 0x7e3e, 0x6509, 0x7e3c, 0x0512, 0x0512, +0x02ad, 0x0760, 0x7d03, 0x55fb, 0x6dd3, 0x9829, 0x55fb, 0x1d04, +0x6dd3, 0x6ac8, 0x7f2f, 0x1f01, 0x2003, 0x4800, 0x7ce4, 0x9851, +0x55fb, 0x6dd7, 0x0015, 0x7805, 0x6209, 0x6ac8, 0x6209, 0x6ac8, +0x6dd7, 0x9850, 0x55fb, 0x6dd7, 0x0015, 0x0015, 0x7805, 0x620a, +0x6ac8, 0x620a, 0x6ac8, 0x6dd7, 0x9850, 0x55fb, 0x6dd7, 0x0015, +0x0015, 0x0015, 0x7805, 0x620b, 0x6ac8, 0x620b, 0x6ac8, 0x6dd7, +0x7c09, 0x6ddf, 0x7f07, 0x0000, 0x55eb, 0x4d00, 0x7d07, 0xc1fa, +0x57db, 0x9804, 0x0007, 0x68cc, 0x680c, 0xc213, 0xc20a, 0x9801, +0xc1d9, 0xc1e3, 0x57db, 0x52f3, 0x6a21, 0x008f, 0x00d5, 0x7d01, +0x008d, 0x05a0, 0x5deb, 0x56fb, 0x0478, 0x7d03, 0x0479, 0x7d32, +0x7c39, 0x0479, 0x7c28, 0x0b70, 0x0311, 0x53eb, 0x0f00, 0x0360, +0x7d05, 0x6509, 0x7e3f, 0x620a, 0x7e3d, 0x9882, 0x620a, 0x7e3a, +0x6509, 0x7e38, 0x0512, 0x0512, 0x02ad, 0x0760, 0x7d0a, 0x5a06, +0x7f31, 0x1f01, 0x2003, 0x4800, 0x7cea, 0x0b70, 0x0311, 0x5313, +0x98b3, 0x5a26, 0x7f27, 0x1f01, 0x2003, 0x4800, 0x7ce0, 0x0b70, +0x0311, 0x5313, 0x98b3, 0x0015, 0x7804, 0x6209, 0x5a06, 0x6209, +0x5a26, 0x98b2, 0x0015, 0x0015, 0x7804, 0x620a, 0x5a06, 0x620a, +0x5a26, 0x98b2, 0x0015, 0x0015, 0x0015, 0x7804, 0x620b, 0x5a06, +0x620b, 0x5a26, 0x7c07, 0x0000, 0x55eb, 0x4d00, 0x7d06, 0xc1fa, +0x57db, 0x9865, 0x0007, 0x680c, 0xc213, 0xc20a, 0x9862 +}; +#endif diff --git a/arch/arm/mach-mx5/sdma_script_code_mx51.h b/arch/arm/mach-mx5/sdma_script_code_mx51.h new file mode 100644 index 000000000000..9a396c92ebea --- /dev/null +++ b/arch/arm/mach-mx5/sdma_script_code_mx51.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2008-2010 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_ELVIS V1.1" + +*******************************************************************************/ + +#ifndef __SDMA_SCRIPT_CODE_H__ +#define __SDMA_SCRIPT_CODE_H__ + +/*! +* SDMA ROM scripts start addresses and sizes +*/ + +#define start_ADDR_MX51 0 +#define start_SIZE_MX51 24 + +#define core_ADDR_MX51 80 +#define core_SIZE_MX51 232 + +#define common_ADDR_MX51 312 +#define common_SIZE_MX51 330 + +#define ap_2_ap_ADDR_MX51 642 +#define ap_2_ap_SIZE_MX51 41 + +#define app_2_mcu_ADDR_MX51 683 +#define app_2_mcu_SIZE_MX51 64 + +#define mcu_2_app_ADDR_MX51 747 +#define mcu_2_app_SIZE_MX51 70 + +#define uart_2_mcu_ADDR_MX51 817 +#define uart_2_mcu_SIZE_MX51 75 + +#define shp_2_mcu_ADDR_MX51 892 +#define shp_2_mcu_SIZE_MX51 69 + +#define mcu_2_shp_ADDR_MX51 961 +#define mcu_2_shp_SIZE_MX51 72 + +#define app_2_per_ADDR_MX51 1033 +#define app_2_per_SIZE_MX51 66 + +#define per_2_app_ADDR_MX51 1099 +#define per_2_app_SIZE_MX51 74 + +#define per_2_shp_ADDR_MX51 1173 +#define per_2_shp_SIZE_MX51 78 + +#define shp_2_per_ADDR_MX51 1251 +#define shp_2_per_SIZE_MX51 72 + +#define uartsh_2_mcu_ADDR_MX51 1323 +#define uartsh_2_mcu_SIZE_MX51 69 + +#define mcu_2_ata_ADDR_MX51 1392 +#define mcu_2_ata_SIZE_MX51 81 + +#define ata_2_mcu_ADDR_MX51 1473 +#define ata_2_mcu_SIZE_MX51 96 + +#define loop_DMAs_routines_ADDR_MX51 1569 +#define loop_DMAs_routines_SIZE_MX51 227 + +#define test_ADDR_MX51 1796 +#define test_SIZE_MX51 63 + +#define signature_ADDR_MX51 1023 +#define signature_SIZE_MX51 1 + +/*! +* SDMA RAM scripts start addresses and sizes +*/ + +#define ext_mem__ipu_ram_ADDR_MX51 6144 +#define ext_mem__ipu_ram_SIZE_MX51 123 + +#define firi_2_mcu_ADDR_MX51 6267 +#define firi_2_mcu_SIZE_MX51 97 + +#define mcu_2_firi_ADDR_MX51 6364 +#define mcu_2_firi_SIZE_MX51 79 + +#define mcu_2_spdif_ADDR_MX51 6443 +#define mcu_2_spdif_SIZE_MX51 59 + +#define mcu_2_ssiapp_ADDR_MX51 6502 +#define mcu_2_ssiapp_SIZE_MX51 98 + +#define mcu_2_ssish_ADDR_MX51 6600 +#define mcu_2_ssish_SIZE_MX51 89 + +#define ssiapp_2_mcu_ADDR_MX51 6689 +#define ssiapp_2_mcu_SIZE_MX51 94 + +#define ssish_2_mcu_ADDR_MX51 6783 +#define ssish_2_mcu_SIZE_MX51 84 + +#define uart_2_per_ADDR_MX51 6867 +#define uart_2_per_SIZE_MX51 73 + +#define uartsh_2_per_ADDR_MX51 6940 +#define uartsh_2_per_SIZE_MX51 67 + +/*! +* SDMA RAM image start address and size +*/ + +#define RAM_CODE_START_ADDR_MX51 6144 +#define RAM_CODE_SIZE_MX51 863 + +/*! +* Buffer that holds the SDMA RAM image +*/ +__attribute__ ((__aligned__(4))) +#ifndef CONFIG_XIP_KERNEL +const +#endif +static const short sdma_code_mx51[] = { +0x0e70, 0x0611, 0x5616, 0xc13c, 0x7d2a, 0x5ade, 0x008e, 0xc14e, +0x7c26, 0x5be0, 0x5ef0, 0x5ce8, 0x0688, 0x08ff, 0x0011, 0x28ff, +0x00bc, 0x53f6, 0x05df, 0x7d0b, 0x6dc5, 0x03df, 0x7d03, 0x6bd5, +0xd84f, 0x982b, 0x6b05, 0xc681, 0x7e27, 0x7f29, 0x982b, 0x6d01, +0x03df, 0x7d05, 0x6bd5, 0xc6ab, 0x7e18, 0x7f1a, 0x982b, 0x6b05, +0xc621, 0x7e07, 0x7f06, 0x52de, 0x53e6, 0xc159, 0x7dd7, 0x0200, +0x9803, 0x0007, 0x6004, 0x680c, 0x53f6, 0x028e, 0x00a3, 0xc256, +0x048b, 0x0498, 0x0454, 0x068a, 0x982b, 0x0207, 0x680c, 0x6ddf, +0x0107, 0x68ff, 0x60d0, 0x9834, 0x0207, 0x68ff, 0x6d28, 0x0107, +0x6004, 0x680c, 0x9834, 0x0007, 0x68ff, 0x60d0, 0x9834, 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, 0x2618, 0x1e10, 0x0b70, 0x0311, 0x5313, +0x58d3, 0x008b, 0x5efb, 0xc13c, 0x7d55, 0x5ac0, 0x5bc8, 0xc14e, +0x7c51, 0x0388, 0x6d04, 0x0dff, 0x0511, 0x1dff, 0x05bc, 0x56fb, +0x6ec3, 0x62c8, 0x7e38, 0x0264, 0x7d0b, 0x0212, 0x3aff, 0x02df, +0x7c05, 0x008f, 0x05a0, 0x0015, 0x0015, 0xd8b5, 0x0400, 0x988f, +0x56fb, 0x6ec3, 0x62c8, 0x0212, 0x3aff, 0x008a, 0x4800, 0x7d02, +0x05a0, 0xd8c0, 0x6a28, 0x7f24, 0x008b, 0x52c0, 0x53c8, 0x04a5, +0xc159, 0x7dd4, 0x0401, 0x0200, 0x9886, 0x1e08, 0x6ec3, 0x7802, +0x62c8, 0x6a0b, 0x7e10, 0x6a28, 0x7f13, 0x0000, 0x2608, 0x0006, +0x1e08, 0x6ec1, 0x7802, 0x62c8, 0x6a09, 0x7e05, 0x6a28, 0x7f08, +0x0000, 0x2608, 0x0006, 0x0007, 0x68cc, 0x6a28, 0x7f01, 0x98d9, +0x0007, 0x6a0c, 0x6a0c, 0x6204, 0x6a04, 0x6a2b, 0x6a28, 0x0007, +0x680c, 0x0454, 0x0200, 0x9883, 0x0b70, 0x0311, 0x5313, 0x58d3, +0x008b, 0x5efb, 0xc13c, 0x7d45, 0x5ac0, 0x5bc8, 0xc14e, 0x56f8, +0x7c40, 0x6ed1, 0x0388, 0x6d00, 0x0dff, 0x0511, 0x1dff, 0x05bc, +0x4d00, 0x7d2f, 0x0e70, 0x0611, 0x522e, 0x02b9, 0x4a00, 0x7c09, +0x52fe, 0x50d3, 0x02b8, 0x4a00, 0x7c04, 0x62ff, 0x7e1c, 0x0400, +0x98f2, 0x008f, 0x00d5, 0x7d0b, 0x008d, 0x05a0, 0x56fb, 0x6ed1, +0x7802, 0x6209, 0x6ac8, 0x0000, 0x7e11, 0x7f0d, 0x98f0, 0x05a0, +0x0015, 0x0015, 0x56fb, 0x6ed3, 0x7802, 0x620b, 0x6ac8, 0x0000, +0x7e05, 0x7f01, 0x98f0, 0x0007, 0x68cc, 0x9920, 0x0007, 0x6a0c, +0x0454, 0x62ff, 0x7efb, 0x008b, 0x52c0, 0x53c8, 0xc159, 0x7dbd, +0x0401, 0x0200, 0x98e2, 0xc1d9, 0xc1e3, 0x57db, 0x52f3, 0x6a01, +0x008f, 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x56fb, 0x0478, +0x7d28, 0x0479, 0x7c16, 0x0015, 0x0015, 0x0388, 0x620a, 0x0808, +0x7801, 0x0217, 0x5a06, 0x7f1d, 0x620a, 0x0808, 0x7801, 0x0217, +0x5a26, 0x7f17, 0x2301, 0x4b00, 0x7cf1, 0x0b70, 0x0311, 0x5313, +0x995a, 0x0015, 0x0015, 0x0015, 0x7804, 0x620b, 0x5a06, 0x620b, +0x5a26, 0x7c07, 0x0000, 0x55eb, 0x4d00, 0x7d06, 0xc1fa, 0x57db, +0x9930, 0x0007, 0x680c, 0xc213, 0xc20a, 0x992d, 0xc1e3, 0x57db, +0x5fe3, 0x57e3, 0x52f3, 0x6a01, 0x008f, 0x00d5, 0x7d01, 0x008d, +0x05a0, 0x5deb, 0x0478, 0x7d03, 0x0479, 0x7d2c, 0x7c36, 0x0479, +0x7c1f, 0x56ee, 0x0f00, 0x0660, 0x7d05, 0x6509, 0x7e43, 0x620a, +0x7e41, 0x9986, 0x620a, 0x7e3e, 0x6509, 0x7e3c, 0x0512, 0x0512, +0x02ad, 0x0760, 0x7d03, 0x55fb, 0x6dd3, 0x9991, 0x55fb, 0x1d04, +0x6dd3, 0x6ac8, 0x7f2f, 0x1f01, 0x2003, 0x4800, 0x7ce4, 0x99b9, +0x55fb, 0x6dd7, 0x0015, 0x7805, 0x6209, 0x6ac8, 0x6209, 0x6ac8, +0x6dd7, 0x99b8, 0x55fb, 0x6dd7, 0x0015, 0x0015, 0x7805, 0x620a, +0x6ac8, 0x620a, 0x6ac8, 0x6dd7, 0x99b8, 0x55fb, 0x6dd7, 0x0015, +0x0015, 0x0015, 0x7805, 0x620b, 0x6ac8, 0x620b, 0x6ac8, 0x6dd7, +0x7c09, 0x6ddf, 0x7f07, 0x0000, 0x55eb, 0x4d00, 0x7d07, 0xc1fa, +0x57e3, 0x996c, 0x0007, 0x68cc, 0x680c, 0xc213, 0xc20a, 0x9969, +0xc1d9, 0xc1e3, 0x57db, 0x5fe3, 0x57e3, 0x52f3, 0x6a21, 0x008f, +0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x56fb, 0x0478, 0x7d03, +0x0479, 0x7d2a, 0x7c31, 0x0479, 0x7c20, 0x0b70, 0x0311, 0x53eb, +0x0f00, 0x0360, 0x7d05, 0x6509, 0x7e37, 0x620a, 0x7e35, 0x99ec, +0x620a, 0x7e32, 0x6509, 0x7e30, 0x0512, 0x0512, 0x02ad, 0x0760, +0x7c02, 0x5a06, 0x99f4, 0x5a26, 0x7f27, 0x1f01, 0x2003, 0x4800, +0x7ce8, 0x0b70, 0x0311, 0x5313, 0x9a15, 0x0015, 0x7804, 0x6209, +0x5a06, 0x6209, 0x5a26, 0x9a14, 0x0015, 0x0015, 0x7804, 0x620a, +0x5a06, 0x620a, 0x5a26, 0x9a14, 0x0015, 0x0015, 0x0015, 0x7804, +0x620b, 0x5a06, 0x620b, 0x5a26, 0x7c07, 0x0000, 0x55eb, 0x4d00, +0x7d06, 0xc1fa, 0x57e3, 0x99cf, 0x0007, 0x680c, 0xc213, 0xc20a, +0x99cc, 0xc1e3, 0x57db, 0x52fb, 0x6ac3, 0x52f3, 0x6a05, 0x008f, +0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x0478, 0x7d03, 0x0479, +0x7d2b, 0x7c1e, 0x0479, 0x7c33, 0x56ee, 0x0f00, 0x55fb, 0x0760, +0x7d02, 0x6dc3, 0x9a3d, 0x1d04, 0x6dc3, 0x62c8, 0x7e3c, 0x0660, +0x7d02, 0x0210, 0x0212, 0x6a09, 0x7f36, 0x0212, 0x6a09, 0x7f33, +0x0212, 0x6a09, 0x7f30, 0x1f01, 0x2003, 0x4800, 0x7ce7, 0x9a71, +0x55fb, 0x6dc7, 0x0015, 0x0015, 0x0015, 0x7805, 0x62c8, 0x6a0b, +0x62c8, 0x6a0b, 0x6dc7, 0x9a70, 0x55fb, 0x6dc7, 0x0015, 0x0015, +0x7805, 0x62c8, 0x6a0a, 0x62c8, 0x6a0a, 0x6dc7, 0x9a70, 0x55fb, +0x6dc7, 0x0015, 0x7805, 0x62c8, 0x6a09, 0x62c8, 0x6a09, 0x6dc7, +0x7c0a, 0x6a28, 0x57db, 0x7f07, 0x0000, 0x55eb, 0x4d00, 0x7d05, +0xc1fa, 0x57db, 0x9a27, 0xc277, 0x0454, 0xc20a, 0x9a22, 0xc1d9, +0xc1e3, 0x57db, 0x52f3, 0x6a05, 0x008f, 0x00d5, 0x7d01, 0x008d, +0x05a0, 0x56fb, 0x0478, 0x7d03, 0x0479, 0x7d29, 0x7c1f, 0x0479, +0x7c2e, 0x5de3, 0x0d70, 0x0511, 0x55ed, 0x0f00, 0x0760, 0x7d02, +0x5206, 0x9a9b, 0x5226, 0x7e33, 0x0560, 0x7d02, 0x0210, 0x0212, +0x6a09, 0x7f2d, 0x0212, 0x6a09, 0x7f2a, 0x0212, 0x6a09, 0x7f27, +0x1f01, 0x2003, 0x4800, 0x7cea, 0x55e3, 0x9ac6, 0x0015, 0x0015, +0x0015, 0x7804, 0x5206, 0x6a0b, 0x5226, 0x6a0b, 0x9ac5, 0x0015, +0x0015, 0x7804, 0x5206, 0x6a0a, 0x5226, 0x6a0a, 0x9ac5, 0x0015, +0x7804, 0x5206, 0x6a09, 0x5226, 0x6a09, 0x7c09, 0x6a28, 0x7f07, +0x0000, 0x57db, 0x4d00, 0x7d05, 0xc1fa, 0x57db, 0x9a84, 0xc277, +0x0454, 0xc20a, 0x9a81, 0xc1e3, 0x57db, 0x52f3, 0x6ad5, 0x56fb, +0x028e, 0x1a94, 0x6ac3, 0x62c8, 0x0269, 0x7d1e, 0x1e94, 0x6ee3, +0x62d0, 0x5aeb, 0x62c8, 0x0248, 0x6ed3, 0x6ac8, 0x2694, 0x52eb, +0x6ad5, 0x6ee3, 0x62c8, 0x026e, 0x7d27, 0x6ac8, 0x7f23, 0x2501, +0x4d00, 0x7d26, 0x028e, 0x1a98, 0x6ac3, 0x62c8, 0x6ec3, 0x0260, +0x7df1, 0x62d0, 0xc27a, 0x9b18, 0x6ee3, 0x008f, 0x2001, 0x00d5, +0x7d01, 0x008d, 0x05a0, 0x62c8, 0x026e, 0x7d0e, 0x6ac8, 0x7f0a, +0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d09, 0xc1fa, +0x57db, 0x9ad7, 0x0007, 0x6aff, 0x62d0, 0xc27a, 0x0458, 0x0454, +0x6add, 0x7ff8, 0xc20a, 0x9ad4, 0xc1d9, 0xc1e3, 0x57db, 0x52f3, +0x6ad5, 0x56fb, 0x028e, 0x1a94, 0x5202, 0x0269, 0x7d17, 0x1e94, +0x5206, 0x0248, 0x5a06, 0x2694, 0x5206, 0x026e, 0x7d26, 0x6ac8, +0x7f22, 0x2501, 0x4d00, 0x7d27, 0x028e, 0x1a98, 0x5202, 0x0260, +0x7df3, 0x6add, 0x7f18, 0x62d0, 0xc27a, 0x9b5b, 0x008f, 0x2001, +0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5206, 0x026e, 0x7d0e, 0x6ac8, +0x7f0a, 0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d0b, +0xc1fa, 0x57db, 0x9b21, 0x0007, 0x6aff, 0x6add, 0x7ffc, 0x62d0, +0xc27a, 0x0458, 0x0454, 0x6add, 0x7ff6, 0xc20a, 0x9b1e +}; +#endif + diff --git a/arch/arm/mach-mx5/sdma_script_code_mx53.h b/arch/arm/mach-mx5/sdma_script_code_mx53.h new file mode 100644 index 000000000000..bfdf74736dcb --- /dev/null +++ b/arch/arm/mach-mx5/sdma_script_code_mx53.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2010 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: "SDMA_RITA.01.01.00" + +*************************************************************************************/ + +#ifndef SDMA_SCRIPT_CODE_H +#define SDMA_SCRIPT_CODE_H + + +/*! +* SDMA ROM scripts start addresses and sizes +*/ + +#define start_ADDR_MX53 0 +#define start_SIZE_MX53 22 + +#define core_ADDR_MX53 80 +#define core_SIZE_MX53 232 + +#define common_ADDR_MX53 312 +#define common_SIZE_MX53 330 + +#define ap_2_ap_ADDR_MX53 642 +#define ap_2_ap_SIZE_MX53 41 + +#define app_2_mcu_ADDR_MX53 683 +#define app_2_mcu_SIZE_MX53 64 + +#define mcu_2_app_ADDR_MX53 747 +#define mcu_2_app_SIZE_MX53 70 + +#define uart_2_mcu_ADDR_MX53 817 +#define uart_2_mcu_SIZE_MX53 74 + +#define shp_2_mcu_ADDR_MX53 891 +#define shp_2_mcu_SIZE_MX53 69 + +#define mcu_2_shp_ADDR_MX53 960 +#define mcu_2_shp_SIZE_MX53 72 + +#define uartsh_2_mcu_ADDR_MX53 1032 +#define uartsh_2_mcu_SIZE_MX53 68 + +#define spdif_2_mcu_ADDR_MX53 1100 +#define spdif_2_mcu_SIZE_MX53 34 + +#define mcu_2_spdif_ADDR_MX53 1134 +#define mcu_2_spdif_SIZE_MX53 59 + +#define firi_2_mcu_ADDR_MX53 1193 +#define firi_2_mcu_SIZE_MX53 97 + +#define mcu_2_firi_ADDR_MX53 1290 +#define mcu_2_firi_SIZE_MX53 79 + +#define loop_DMAs_routines_ADDR_MX53 1369 +#define loop_DMAs_routines_SIZE_MX53 227 + +#define test_ADDR_MX53 1596 +#define test_SIZE_MX53 63 + +#define signature_ADDR_MX53 1023 +#define signature_SIZE_MX53 1 + +/*! +* SDMA RAM scripts start addresses and sizes +*/ + +#define mcu_2_ssiapp_ADDR_MX53 6144 +#define mcu_2_ssiapp_SIZE_MX53 98 + +#define mcu_2_ssish_ADDR_MX53 6242 +#define mcu_2_ssish_SIZE_MX53 89 + +#define p_2_p_ADDR_MX53 6331 +#define p_2_p_SIZE_MX53 254 + +#define ssiapp_2_mcu_ADDR_MX53 6585 +#define ssiapp_2_mcu_SIZE_MX53 94 + +#define ssish_2_mcu_ADDR_MX53 6679 +#define ssish_2_mcu_SIZE_MX53 84 + +/*! +* SDMA RAM image start address and size +*/ + +#define RAM_CODE_START_ADDR_MX53 6144 +#define RAM_CODE_SIZE_MX53 619 + +/*! +* Buffer that holds the SDMA RAM image +*/ +__attribute__ ((__aligned__(4))) +#ifndef CONFIG_XIP_KERNEL +const +#endif +static const short sdma_code_mx53[] = { +0xc1e3, 0x57db, 0x5fe3, 0x57e3, 0x52f3, 0x6a01, 0x008f, 0x00d5, +0x7d01, 0x008d, 0x05a0, 0x5deb, 0x0478, 0x7d03, 0x0479, 0x7d2c, +0x7c36, 0x0479, 0x7c1f, 0x56ee, 0x0f00, 0x0660, 0x7d05, 0x6509, +0x7e43, 0x620a, 0x7e41, 0x9820, 0x620a, 0x7e3e, 0x6509, 0x7e3c, +0x0512, 0x0512, 0x02ad, 0x0760, 0x7d03, 0x55fb, 0x6dd3, 0x982b, +0x55fb, 0x1d04, 0x6dd3, 0x6ac8, 0x7f2f, 0x1f01, 0x2003, 0x4800, +0x7ce4, 0x9853, 0x55fb, 0x6dd7, 0x0015, 0x7805, 0x6209, 0x6ac8, +0x6209, 0x6ac8, 0x6dd7, 0x9852, 0x55fb, 0x6dd7, 0x0015, 0x0015, +0x7805, 0x620a, 0x6ac8, 0x620a, 0x6ac8, 0x6dd7, 0x9852, 0x55fb, +0x6dd7, 0x0015, 0x0015, 0x0015, 0x7805, 0x620b, 0x6ac8, 0x620b, +0x6ac8, 0x6dd7, 0x7c09, 0x6ddf, 0x7f07, 0x0000, 0x55eb, 0x4d00, +0x7d07, 0xc1fa, 0x57e3, 0x9806, 0x0007, 0x68cc, 0x680c, 0xc213, +0xc20a, 0x9803, 0xc1d9, 0xc1e3, 0x57db, 0x5fe3, 0x57e3, 0x52f3, +0x6a21, 0x008f, 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x56fb, +0x0478, 0x7d03, 0x0479, 0x7d2a, 0x7c31, 0x0479, 0x7c20, 0x0b70, +0x0311, 0x53eb, 0x0f00, 0x0360, 0x7d05, 0x6509, 0x7e37, 0x620a, +0x7e35, 0x9886, 0x620a, 0x7e32, 0x6509, 0x7e30, 0x0512, 0x0512, +0x02ad, 0x0760, 0x7c02, 0x5a06, 0x988e, 0x5a26, 0x7f27, 0x1f01, +0x2003, 0x4800, 0x7ce8, 0x0b70, 0x0311, 0x5313, 0x98af, 0x0015, +0x7804, 0x6209, 0x5a06, 0x6209, 0x5a26, 0x98ae, 0x0015, 0x0015, +0x7804, 0x620a, 0x5a06, 0x620a, 0x5a26, 0x98ae, 0x0015, 0x0015, +0x0015, 0x7804, 0x620b, 0x5a06, 0x620b, 0x5a26, 0x7c07, 0x0000, +0x55eb, 0x4d00, 0x7d06, 0xc1fa, 0x57e3, 0x9869, 0x0007, 0x680c, +0xc213, 0xc20a, 0x9866, 0x0b70, 0x0311, 0x5313, 0x076c, 0x7c01, +0xc1d9, 0x5efb, 0x068a, 0x076b, 0x7c01, 0xc1d9, 0x5ef3, 0x59db, +0x58d3, 0x018f, 0x0110, 0x390f, 0x008b, 0xc13c, 0x7d2b, 0x5ac0, +0x5bc8, 0xc14e, 0x7c27, 0x0388, 0x0689, 0x5ce3, 0x0dff, 0x0511, +0x1dff, 0x05bc, 0x073e, 0x4d00, 0x7d18, 0x0870, 0x0011, 0x077e, +0x7d09, 0x077d, 0x7d02, 0x5228, 0x98e6, 0x52f8, 0x54db, 0x02bc, +0x02cc, 0x7c09, 0x077c, 0x7d02, 0x5228, 0x98ef, 0x52f8, 0x54d3, +0x02bc, 0x02cc, 0x7d09, 0x0400, 0x98dd, 0x008b, 0x52c0, 0x53c8, +0xc159, 0x7dd6, 0x0200, 0x98cd, 0x08ff, 0x00bf, 0x077f, 0x7d15, +0x0488, 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x028f, 0x0212, +0x0212, 0x3aff, 0x05da, 0x7c02, 0x073e, 0x9918, 0x02a4, 0x02dd, +0x7d02, 0x073e, 0x9918, 0x075e, 0x9918, 0x55eb, 0x0598, 0x5deb, +0x52f3, 0x54fb, 0x076a, 0x7d26, 0x076c, 0x7d01, 0x9955, 0x076b, +0x7c57, 0x0769, 0x7d04, 0x0768, 0x7d02, 0x0e01, 0x992f, 0x5893, +0x00d6, 0x7d01, 0x008e, 0x5593, 0x05a0, 0x5d93, 0x06a0, 0x7802, +0x5502, 0x5d04, 0x7c1d, 0x4e00, 0x7c08, 0x0769, 0x7d03, 0x5502, +0x7e17, 0x993c, 0x5d04, 0x7f14, 0x0689, 0x5093, 0x4800, 0x7d01, +0x9927, 0x99a0, 0x0015, 0x7806, 0x5502, 0x5d04, 0x074f, 0x5502, +0x5d24, 0x072f, 0x7c01, 0x99a0, 0x0017, 0x076f, 0x7c01, 0x2001, +0x5593, 0x009d, 0x0007, 0xd9a7, 0x98f5, 0x6cd3, 0x0769, 0x7d04, +0x0768, 0x7d02, 0x0e01, 0x9964, 0x5893, 0x00d6, 0x7d01, 0x008e, +0x5593, 0x05a0, 0x5d93, 0x06a0, 0x7802, 0x5502, 0x6dc8, 0x7c0f, +0x4e00, 0x7c08, 0x0769, 0x7d03, 0x5502, 0x7e09, 0x9971, 0x6dc8, +0x7f06, 0x0689, 0x5093, 0x4800, 0x7d01, 0x995c, 0x99a0, 0x999a, +0x6ac3, 0x0769, 0x7d04, 0x0768, 0x7d02, 0x0e01, 0x9987, 0x5893, +0x00d6, 0x7d01, 0x008e, 0x5593, 0x05a0, 0x5d93, 0x06a0, 0x7802, +0x65c8, 0x5d04, 0x7c0f, 0x4e00, 0x7c08, 0x0769, 0x7d03, 0x65c8, +0x7e09, 0x9994, 0x5d04, 0x7f06, 0x0689, 0x5093, 0x4800, 0x7d01, +0x997f, 0x99a0, 0x5593, 0x009d, 0x0007, 0x6cff, 0xd9a7, 0x98f5, +0x0000, 0x54e3, 0x55eb, 0x4d00, 0x7c01, 0x98f5, 0x98dd, 0x54e3, +0x55eb, 0x0aff, 0x0211, 0x1aff, 0x077f, 0x7c02, 0x05a0, 0x99b4, +0x009d, 0x058c, 0x05ba, 0x05a0, 0x0210, 0x04ba, 0x04ad, 0x0454, +0x0006, 0xc1e3, 0x57db, 0x52fb, 0x6ac3, 0x52f3, 0x6a05, 0x008f, +0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5deb, 0x0478, 0x7d03, 0x0479, +0x7d2b, 0x7c1e, 0x0479, 0x7c33, 0x56ee, 0x0f00, 0x55fb, 0x0760, +0x7d02, 0x6dc3, 0x99d5, 0x1d04, 0x6dc3, 0x62c8, 0x7e3c, 0x0660, +0x7d02, 0x0210, 0x0212, 0x6a09, 0x7f36, 0x0212, 0x6a09, 0x7f33, +0x0212, 0x6a09, 0x7f30, 0x1f01, 0x2003, 0x4800, 0x7ce7, 0x9a09, +0x55fb, 0x6dc7, 0x0015, 0x0015, 0x0015, 0x7805, 0x62c8, 0x6a0b, +0x62c8, 0x6a0b, 0x6dc7, 0x9a08, 0x55fb, 0x6dc7, 0x0015, 0x0015, +0x7805, 0x62c8, 0x6a0a, 0x62c8, 0x6a0a, 0x6dc7, 0x9a08, 0x55fb, +0x6dc7, 0x0015, 0x7805, 0x62c8, 0x6a09, 0x62c8, 0x6a09, 0x6dc7, +0x7c0a, 0x6a28, 0x57db, 0x7f07, 0x0000, 0x55eb, 0x4d00, 0x7d05, +0xc1fa, 0x57db, 0x99bf, 0xc277, 0x0454, 0xc20a, 0x99ba, 0xc1d9, +0xc1e3, 0x57db, 0x52f3, 0x6a05, 0x008f, 0x00d5, 0x7d01, 0x008d, +0x05a0, 0x56fb, 0x0478, 0x7d03, 0x0479, 0x7d29, 0x7c1f, 0x0479, +0x7c2e, 0x5de3, 0x0d70, 0x0511, 0x55ed, 0x0f00, 0x0760, 0x7d02, +0x5206, 0x9a33, 0x5226, 0x7e33, 0x0560, 0x7d02, 0x0210, 0x0212, +0x6a09, 0x7f2d, 0x0212, 0x6a09, 0x7f2a, 0x0212, 0x6a09, 0x7f27, +0x1f01, 0x2003, 0x4800, 0x7cea, 0x55e3, 0x9a5e, 0x0015, 0x0015, +0x0015, 0x7804, 0x5206, 0x6a0b, 0x5226, 0x6a0b, 0x9a5d, 0x0015, +0x0015, 0x7804, 0x5206, 0x6a0a, 0x5226, 0x6a0a, 0x9a5d, 0x0015, +0x7804, 0x5206, 0x6a09, 0x5226, 0x6a09, 0x7c09, 0x6a28, 0x7f07, +0x0000, 0x57db, 0x4d00, 0x7d05, 0xc1fa, 0x57db, 0x9a1c, 0xc277, +0x0454, 0xc20a, 0x9a19 +}; +#endif + diff --git a/arch/arm/mach-mx5/sdram_autogating.c b/arch/arm/mach-mx5/sdram_autogating.c new file mode 100644 index 000000000000..0b05d791c4f9 --- /dev/null +++ b/arch/arm/mach-mx5/sdram_autogating.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2009-2010 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 sdram_autogating.c + * + * @brief Enable auto clock gating of the EMI_FAST clock using M4IF. + * + * The APIs are for enabling and disabling automatic clock gating of EMI_FAST. + * + * @ingroup PM + */ +#include <asm/io.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/sdram_autogating.h> +#include "crm_regs.h" + +static struct device *sdram_autogating_dev; +#define M4IF_CNTL_REG0 0x8c +#define M4IF_CNTL_REG1 0x90 + +/* Flag used to indicate if SDRAM M4IF autoclock gating feature is active. */ +static int sdram_autogating_is_active; +static int sdram_autogating_paused; +static void __iomem *m4if_base; + +void start_sdram_autogating(void); +void stop_sdram_autogating(void); +int sdram_autogating_active(void); + +static void enable(void) +{ + u32 reg; + + /* Set the Fast arbitration Power saving timer */ + reg = __raw_readl(m4if_base + M4IF_CNTL_REG1); + reg &= ~0xFF; + reg |= 0x09; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG1); + /*Allow for automatic gating of the EMI internal clock. + * If this is done, emi_intr CCGR bits should be set to 11. + */ + reg = __raw_readl(m4if_base + M4IF_CNTL_REG0); + reg &= ~0x5; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG0); + + sdram_autogating_is_active = 1; +} + +static void disable(void) +{ + u32 reg; + + reg = __raw_readl(m4if_base + M4IF_CNTL_REG0); + reg |= 0x4; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG0); + sdram_autogating_is_active = 0; +} + +int sdram_autogating_active() +{ + return sdram_autogating_is_active; +} + +void start_sdram_autogating() +{ + if (cpu_is_mx50()) + return; + if (sdram_autogating_paused) { + enable(); + sdram_autogating_paused = 0; + } +} + +void stop_sdram_autogating() +{ + if (cpu_is_mx50()) + return; + + if (sdram_autogating_is_active) { + sdram_autogating_paused = 1; + disable(); + } +} + +static ssize_t sdram_autogating_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (sdram_autogating_is_active) + return sprintf(buf, + "M4IF autoclock gating for EMI_FAST enabled\n"); + else + return sprintf(buf, + "M4IF autoclock gating for EMI_FAST disabled\n"); +} + +static ssize_t sdram_autogating_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + if (strstr(buf, "1") != NULL) + enable(); + else if (strstr(buf, "0") != NULL) { + if (sdram_autogating_is_active) + disable(); + } + return size; +} + +static DEVICE_ATTR(enable, 0644, sdram_autogating_enable_show, + sdram_autogating_enable_store); + +/*! + * This is the probe routine for the auto clockgating of sdram driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit sdram_autogating_probe(struct platform_device *pdev) +{ + struct resource *res; + int err = 0; + + sdram_autogating_dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + return -ENOMEM; + } + m4if_base = ioremap(res->start, res->end - res->start + 1); + + err = sysfs_create_file(&sdram_autogating_dev->kobj, + &dev_attr_enable.attr); + if (err) { + printk(KERN_ERR + "Unable to register sysdev entry for sdram_autogating"); + return err; + } + + sdram_autogating_is_active = 0; + + return 0; +} + +static struct platform_driver sdram_autogating_driver = { + .driver = { + .name = "sdram_autogating", + }, + .probe = sdram_autogating_probe, +}; + +/*! + * Initialise the sdram_autogating_driver. + * + * @return The function always returns 0. + */ + +static int __init sdram_autogating_init(void) +{ + if (platform_driver_register(&sdram_autogating_driver) != 0) { + printk(KERN_ERR "sdram_autogating_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "sdram autogating driver module loaded\n"); + return 0; +} + +static void __exit sdram_autogating_cleanup(void) +{ + sysfs_remove_file(&sdram_autogating_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&sdram_autogating_driver); +} + +module_init(sdram_autogating_init); +module_exit(sdram_autogating_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("sdram_autogating driver"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/mach-mx5/serial.c b/arch/arm/mach-mx5/serial.c new file mode 100644 index 000000000000..18dfcfb6d696 --- /dev/null +++ b/arch/arm/mach-mx5/serial.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2008-2010 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-mx51/serial.c + * + * @brief This file contains the UART initiliazation. + * + * @ingroup MSL_MX51 + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <mach/hardware.h> +#include <mach/mxc_uart.h> +#include "serial.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 = { + .iotype = SERIAL_IO_MEM, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, + .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, + .dma_tx_id = MXC_DMA_UART1_TX, + .dma_rx_id = MXC_DMA_UART1_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [1] = { + .port = { + .iotype = SERIAL_IO_MEM, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, + .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, + .dma_tx_id = MXC_DMA_UART2_TX, + .dma_rx_id = MXC_DMA_UART2_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [2] = { + .port = { + .iotype = SERIAL_IO_MEM, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, + .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, + .dma_tx_id = MXC_DMA_UART3_TX, + .dma_rx_id = MXC_DMA_UART3_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [3] = { + .port = { + .iotype = SERIAL_IO_MEM, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 3, + }, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, + .cts_threshold = UART4_UCR4_CTSTL, + .dma_enabled = UART4_DMA_ENABLE, + .dma_rxbuf_size = UART4_DMA_RXBUFSIZE, + .rx_threshold = UART4_UFCR_RXTL, + .tx_threshold = UART4_UFCR_TXTL, + .dma_tx_id = MXC_DMA_UART4_TX, + .dma_rx_id = MXC_DMA_UART4_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, + [4] = { + .port = { + .iotype = SERIAL_IO_MEM, + .fifosize = 32, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 4, + }, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, + .cts_threshold = UART5_UCR4_CTSTL, + .dma_enabled = UART5_DMA_ENABLE, + .dma_rxbuf_size = UART5_DMA_RXBUFSIZE, + .rx_threshold = UART5_UFCR_RXTL, + .tx_threshold = UART5_UFCR_TXTL, + .dma_tx_id = MXC_DMA_UART5_TX, + .dma_rx_id = MXC_DMA_UART5_RX, + .rxd_mux = MXC_UART_RXDMUX, + }, +}; + +static struct resource mxc_uart_resources1[] = { + { + .start = UART1_BASE_ADDR, + .end = UART1_BASE_ADDR + 0x0B5, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_UART1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_uart_device1 = { + .name = "mxcintuart", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_uart_resources1), + .resource = mxc_uart_resources1, + .dev = { + .platform_data = &mxc_ports[0], + }, +}; + +static struct resource mxc_uart_resources2[] = { + { + .start = UART2_BASE_ADDR, + .end = UART2_BASE_ADDR + 0x0B5, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_UART2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_uart_device2 = { + .name = "mxcintuart", + .id = 1, + .num_resources = ARRAY_SIZE(mxc_uart_resources2), + .resource = mxc_uart_resources2, + .dev = { + .platform_data = &mxc_ports[1], + }, +}; + +static struct resource mxc_uart_resources3[] = { + { + .start = UART3_BASE_ADDR, + .end = UART3_BASE_ADDR + 0x0B5, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_UART3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_uart_device3 = { + .name = "mxcintuart", + .id = 2, + .num_resources = ARRAY_SIZE(mxc_uart_resources3), + .resource = mxc_uart_resources3, + .dev = { + .platform_data = &mxc_ports[2], + }, +}; + +static struct resource mxc_uart_resources4[] = { + { + .start = UART4_BASE_ADDR, + .end = UART4_BASE_ADDR + 0x0B5, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_UART4, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_uart_device4 = { + .name = "mxcintuart", + .id = 3, + .num_resources = ARRAY_SIZE(mxc_uart_resources4), + .resource = mxc_uart_resources4, + .dev = { + .platform_data = &mxc_ports[3], + }, +}; + +static struct resource mxc_uart_resources5[] = { + { + .start = UART5_BASE_ADDR, + .end = UART5_BASE_ADDR + 0x0B5, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_UART5, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mxc_uart_device5 = { + .name = "mxcintuart", + .id = 4, + .num_resources = ARRAY_SIZE(mxc_uart_resources5), + .resource = mxc_uart_resources5, + .dev = { + .platform_data = &mxc_ports[4], + }, +}; + +static int __init mxc_init_uart(void) +{ + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_uart_resources1[0].start -= 0x20000000; + mxc_uart_resources1[0].end -= 0x20000000; + mxc_uart_resources2[0].start -= 0x20000000; + mxc_uart_resources2[0].end -= 0x20000000; + mxc_uart_resources3[0].start -= 0x20000000; + mxc_uart_resources3[0].end -= 0x20000000; + mxc_uart_resources4[0].start -= 0x20000000; + mxc_uart_resources4[0].end -= 0x20000000; + mxc_uart_resources5[0].start -= 0x20000000; + mxc_uart_resources5[0].end -= 0x20000000; + } + + /* Register all the MXC UART platform device structures */ + platform_device_register(&mxc_uart_device1); + platform_device_register(&mxc_uart_device2); + platform_device_register(&mxc_uart_device3); + if (cpu_is_mx53()) { + platform_device_register(&mxc_uart_device4); + platform_device_register(&mxc_uart_device5); + } + return 0; +} + +#else +static int __init mxc_init_uart(void) +{ + return 0; +} +#endif + +arch_initcall(mxc_init_uart); diff --git a/arch/arm/mach-mx5/serial.h b/arch/arm/mach-mx5/serial.h new file mode 100644 index 000000000000..9fbb0b33e4eb --- /dev/null +++ b/arch/arm/mach-mx5/serial.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008-2011 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_MX51_SERIAL_H__ +#define __ARCH_ARM_MACH_MX51_SERIAL_H__ + +/* UART 1 configuration */ +/*! + * 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 +/*! + * 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 +#define UART1_DMA_ENABLE 0 +/* UART 2 configuration */ +#define UART2_UCR4_CTSTL -1 +#define UART2_DMA_ENABLE 1 +#define UART2_DMA_RXBUFSIZE 512 +#define UART2_UFCR_RXTL 16 +#define UART2_UFCR_TXTL 16 +/* UART 3 configuration */ +#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 4 configuration */ +#define UART4_UCR4_CTSTL -1 +#define UART4_DMA_ENABLE 0 +#define UART4_DMA_RXBUFSIZE 512 +#define UART4_UFCR_RXTL 16 +#define UART4_UFCR_TXTL 16 +/* UART 5 configuration */ +#define UART5_UCR4_CTSTL -1 +#define UART5_DMA_ENABLE 0 +#define UART5_DMA_RXBUFSIZE 512 +#define UART5_UFCR_RXTL 16 +#define UART5_UFCR_TXTL 16 + +#endif /* __ARCH_ARM_MACH_MX51_SERIAL_H__ */ diff --git a/arch/arm/mach-mx5/suspend.S b/arch/arm/mach-mx5/suspend.S new file mode 100644 index 000000000000..f5aa1cc2f668 --- /dev/null +++ b/arch/arm/mach-mx5/suspend.S @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008-2010 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/linkage.h> + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_CTRL_ICACHE 1 << 12 +#define ARM_AUXCR_L2EN 1 << 1 + + +/* + * cpu_do_suspend_workaround() + * + * Suspend the processor (eg, wait for interrupt). + * + * IRQs are already disabled. + */ +ENTRY(cpu_do_suspend_workaround) + stmfd sp!, {r4,r5,r6,r7,r9,r10,r11} @ Save registers + + mov r6, r0 @save iomux address + /* Disable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + bic r0, r0, #ARM_CTRL_ICACHE @ Disable ICache + bic r0, r0, #ARM_CTRL_DCACHE @ Disable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedClean + mov r10, #0 +Loop1Clean: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipClean @ No cache or only instruction cache at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index size (right aligned) +Loop2Clean: + mov r9, r4 @ R9 working copy of the max way size (right aligned) +Loop3Clean: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c14, 2 @ Clean and invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Clean + subs r7, r7, #1 @ Decrement the index + bge Loop2Clean +SkipClean: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Clean + +FinishedClean: + + /* Disable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + bic r0, r0, #ARM_AUXCR_L2EN @ Disable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + + /*Set the DDR drive strength to low */ + ldr r10, [r6] + and r10, r10, #0xF1 @ clear bits 2-1 + str r10, [r6] + + .long 0xe320f003 @ Opcode for WFI + + /*Set the DDR drive strength to max */ + orr r10, r10, #0x06 @ set bits 2-1 + str r10, [r6] + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Invalidate inst cache + + /* Invalidate data caches */ + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedInvalidate + mov r10, #0 +Loop1Invalidate: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipInvalidate @ No cache or only instruction cache at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index size (right aligned) +Loop2Invalidate: + mov r9, r4 @ R9 working copy of the max way size (right aligned) +Loop3Invalidate: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c6, 2 @ Invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Invalidate + subs r7, r7, #1 @ Decrement the index + bge Loop2Invalidate +SkipInvalidate: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Invalidate + +FinishedInvalidate: + + /* Enable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + orr r0, r0, #ARM_AUXCR_L2EN @ Enable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + + /* Enable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + orr r0, r0, #ARM_CTRL_ICACHE @ Enable ICache + orr r0, r0, #ARM_CTRL_DCACHE @ Enable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7,r9,r10,r11} + mov pc, lr + + .type cpu_do_suspend, #object +ENTRY(cpu_do_suspend) + .word cpu_do_suspend_workaround + .size cpu_do_suspend_workaround, . - cpu_do_suspend_workaround diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c new file mode 100644 index 000000000000..a04962f64275 --- /dev/null +++ b/arch/arm/mach-mx5/system.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2008-2010 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/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <asm/io.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <asm/proc-fns.h> +#include <asm/system.h> +#include "crm_regs.h" + +/*! + * @defgroup MSL_MX51 i.MX51 Machine Specific Layer (MSL) + */ + +/*! + * @file mach-mx51/system.c + * @brief This file contains idle and reset functions. + * + * @ingroup MSL_MX51 + */ + +extern int mxc_jtag_enabled; +extern int iram_ready; +extern int dvfs_core_is_active; +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern int low_bus_freq_mode; +extern void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); +extern void stop_dvfs(void); +extern void *wait_in_iram_base; +extern void __iomem *apll_base; + +static struct clk *gpc_dvfs_clk; +static struct regulator *vpll; +static struct clk *pll1_sw_clk; +static struct clk *osc; +static struct clk *pll1_main_clk; +static struct clk *ddr_clk ; +static int dvfs_core_paused; + +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +{ + u32 plat_lpc, arm_srpgcr, ccm_clpcr; + u32 empgc0, empgc1; + int stop_mode = 0; + + /* always allow platform to issue a deep sleep mode request */ + plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) & + ~(MXC_CORTEXA8_PLAT_LPC_DSM); + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_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_CORTEXA8_PLAT_LPC_DSM + | MXC_CORTEXA8_PLAT_LPC_DBG_DSM; + if (mode == WAIT_UNCLOCKED_POWER_OFF) { + ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); + ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + stop_mode = 0; + } 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; + stop_mode = 1; + } + + arm_srpgcr |= MXC_SRPGCR_PCR; + if (stop_mode) { + empgc0 |= MXC_SRPGCR_PCR; + empgc1 |= MXC_SRPGCR_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_CORTEXA8_PLAT_LPC); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + if (cpu_is_mx51() || (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) + || cpu_is_mx50_rev(CHIP_REV_1_1) >= 1) + __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); + /* Enable NEON SRPG for all but MX50TO1.0. */ + if (!(cpu_is_mx50_rev(CHIP_REV_1_0) == 1)) + __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); + if (stop_mode) { + __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); + } +} + +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)) { + if (ddr_clk == NULL) + ddr_clk = clk_get(NULL, "ddr_clk"); + 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); + mxc_cpu_lp_set(arch_idle_mode); + + if (cpu_is_mx50() && (clk_get_usecount(ddr_clk) == 0)) { + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + if (low_bus_freq_mode) { + u32 reg, cpu_podf; + + reg = __raw_readl(apll_base + 0x50); + reg = 0x120490; + __raw_writel(reg, apll_base + 0x50); + reg = __raw_readl(apll_base + 0x80); + reg |= 1; + __raw_writel(reg, apll_base + 0x80); + + /* Move ARM to be sourced from 24MHz XTAL. + * when ARM is in WFI. + */ + if (pll1_sw_clk == NULL) + pll1_sw_clk = clk_get(NULL, + "pll1_sw_clk"); + if (osc == NULL) + osc = clk_get(NULL, "lp_apm"); + if (pll1_main_clk == NULL) + pll1_main_clk = clk_get(NULL, + "pll1_main_clk"); + + clk_set_parent(pll1_sw_clk, osc); + /* Set the ARM-PODF divider to 1. */ + cpu_podf = __raw_readl(MXC_CCM_CACRR); + __raw_writel(0x01, MXC_CCM_CACRR); + + wait_in_iram(ccm_base, databahn_base); + + /* Set the ARM-POD divider back + * to the original. + */ + __raw_writel(cpu_podf, MXC_CCM_CACRR); + clk_set_parent(pll1_sw_clk, pll1_main_clk); + } else + wait_in_iram(ccm_base, databahn_base); + } else + cpu_do_idle(); + clk_disable(gpc_dvfs_clk); + clk_put(ddr_clk); + } +} + +static int __mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + u32 c; + int timeout; + + /* the process of software reset of IP block is done + in several steps: + + - clear SFTRST and wait for block is enabled; + - clear clock gating (CLKGATE bit); + - set the SFTRST again and wait for block is in reset; + - clear SFTRST and wait for reset completion. + */ + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= (1 << 31); /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & (1 << 30)) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling " + "after reset\n", __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 30)) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} + +int mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + int try = 10; + int r; + + while (try--) { + r = __mxs_reset_block(hwreg, just_enable); + if (!r) + break; + pr_debug("%s: try %d failed\n", __func__, 10 - try); + } + return r; +} + diff --git a/arch/arm/mach-mx5/usb.h b/arch/arm/mach-mx5/usb.h new file mode 100644 index 000000000000..6115d3375c05 --- /dev/null +++ b/arch/arm/mach-mx5/usb.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2010 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 <mach/common.h> +#include "devices.h" + +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 fsl_usb_host_init(struct platform_device *pdev); +extern void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata); +extern int gpio_usbotg_utmi_active(void); +extern void gpio_usbotg_utmi_inactive(void); + +extern void __init mx5_usb_dr_init(void); +extern void __init mx5_usbh1_init(void); +extern void __init mx5_usbh2_init(void); + +typedef void (*driver_vbus_func)(bool); +extern void mx5_set_host1_vbus_func(driver_vbus_func); +extern void mx5_set_otghost_vbus_func(driver_vbus_func); +/* + * 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 + diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c new file mode 100644 index 000000000000..d0dba3a3bf38 --- /dev/null +++ b/arch/arm/mach-mx5/usb_dr.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2005-2011 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/arc_otg.h> +#include <mach/hardware.h> +#include <asm/delay.h> +#include "usb.h" +static int usbotg_init_ext(struct platform_device *pdev); +static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata); +static void usbotg_clock_gate(bool on); + +static struct clk *usb_phy1_clk; +static struct clk *usb_oh3_clk; +static struct clk *usb_ahb_clk; +static void usbotg_wakeup_event_clear(void); +extern int clk_get_usecount(struct clk *clk); + +/* Beginning of Common operation for DR port */ + +/* + * 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 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_clock_gate, + .transceiver = "utmi", +}; + +/* Platform data for wakeup operation */ +static struct fsl_usb2_wakeup_platform_data dr_wakeup_config = { + .name = "DR wakeup", + .usb_clock_for_pm = usbotg_clock_gate, + .usb_wakeup_exhandle = usbotg_wakeup_event_clear, +}; +/* Notes: configure USB clock*/ +static int usbotg_init_ext(struct platform_device *pdev) +{ + struct clk *usb_clk; + + /* the usb_ahb_clk will be enabled in usb_otg_init */ + usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + usb_phy1_clk = usb_clk; + + return usbotg_init(pdev); +} + +static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) +{ + clk_disable(usb_phy1_clk); + clk_put(usb_phy1_clk); + + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + + /* usb_ahb_clk will be disabled at usb_common.c */ + usbotg_uninit(pdata); + clk_put(usb_ahb_clk); +} + +/* Below two macros are used at otg mode to indicate usb mode*/ +#define ENABLED_BY_HOST (0x1 << 0) +#define ENABLED_BY_DEVICE (0x1 << 1) +static u32 wakeup_irq_enable_src; /* only useful at otg mode */ +static void __wakeup_irq_enable(bool on, int source) + { + /* otg host and device share the OWIE bit, only when host and device + * all enable the wakeup irq, we can enable the OWIE bit + */ + if (on) { +#ifdef CONFIG_USB_OTG + wakeup_irq_enable_src |= source; + if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; + } +#else + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; +#endif + } else { + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + USBCTRL &= ~UCTRL_OWIE; + wakeup_irq_enable_src &= ~source; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static u32 low_power_enable_src; /* only useful at otg mode */ +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + low_power_enable_src |= source; +#ifdef CONFIG_USB_OTG + if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + pr_debug("phy lowpower enabled\n"); + UOG_PORTSC1 |= PORTSC_PHCD; + } +#else + UOG_PORTSC1 |= PORTSC_PHCD; +#endif + } else { + pr_debug("phy lowpower disable\n"); + UOG_PORTSC1 &= ~PORTSC_PHCD; + low_power_enable_src &= ~source; + } +} + +static void usbotg_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_ahb_clk); + clk_enable(usb_oh3_clk); + clk_enable(usb_phy1_clk); + } else { + clk_disable(usb_phy1_clk); + clk_disable(usb_oh3_clk); + clk_disable(usb_ahb_clk); + } + pr_debug("usb_ahb_ref_count:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_ahb_clk), clk_get_usecount(usb_phy1_clk)); +} + +void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus) +{ + dr_utmi_config.platform_driver_vbus = driver_vbus; +} + +/* The wakeup operation for DR port, it will clear the wakeup irq status + * and re-enable the wakeup + */ +static void usbotg_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_OWIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable OWIE to clear OWIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_OWIE; + udelay(100); + USBCTRL |= UCTRL_OWIE; + } +} +/* End of Common operation for DR port */ + + +#ifdef CONFIG_USB_EHCI_ARC_OTG +extern void fsl_usb_recover_hcd(struct platform_device *pdev); +/* Beginning of host related operation for DR port */ +static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_HOST); + /* host only care the ID change wakeup event */ + if (enable) { + pr_debug("host wakeup enable\n"); + USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN; + } else { + pr_debug("host wakeup disable\n"); + USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_HOST); +} + +static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_OWIR; + int otgsc = UOG_OTGSC; + + /* if ID change sts, it is a host wakeup event */ + if (wakeup_req && (otgsc & OTGSC_IS_USB_ID)) { + printk(KERN_INFO "otg host ID wakeup\n"); + /* if host ID wakeup, we must clear the b session change sts */ + UOG_OTGSC = otgsc & (~OTGSC_IS_USB_ID); + return WAKEUP_EVENT_ID; + } + if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) { + printk(KERN_INFO "otg host Remote wakeup\n"); + return WAKEUP_EVENT_DPDM; + } + + return WAKEUP_EVENT_INVALID; +} + +static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _host_wakeup_enable(pdata, false); + _host_phy_lowpower_suspend(pdata, false); + fsl_usb_recover_hcd(&mxc_usbdr_host_device); +} +/* End of host related operation for DR port */ +#endif /* CONFIG_USB_EHCI_ARC_OTG */ + + +#ifdef CONFIG_USB_GADGET_ARC +/* Beginning of device related operation for DR port */ +static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_DEVICE); + /* if udc is not used by any gadget, we can not enable the vbus wakeup */ + if (!pdata->port_enables) { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + return; + } + if (enable) { + pr_debug("device wakeup enable\n"); + USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; + } else { + pr_debug("device wakeup disable\n"); + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + } +} + +static void _device_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE); +} + +static enum usb_wakeup_event _is_device_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_OWIR; + + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_OTGSC & OTGSC_IS_B_SESSION_VALID)) { + printk(KERN_INFO "otg udc wakeup\n"); + return WAKEUP_EVENT_VBUS; + } + return WAKEUP_EVENT_INVALID; + +} + +static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _device_wakeup_enable(pdata, false); + _device_phy_lowpower_suspend(pdata, false); +} + +/* end of device related operation for DR port */ +#endif /* CONFIG_USB_GADGET_ARC */ + + +void __init mx5_usb_dr_init(void) +{ +#ifdef CONFIG_USB_OTG + /* wake_up_enalbe is useless, just for usb_register_remote_wakeup execution*/ + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.operating_mode = FSL_USB2_DR_OTG; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + platform_device_add_data(&mxc_usbdr_otg_device, &dr_utmi_config, sizeof(dr_utmi_config)); + platform_device_register(&mxc_usbdr_otg_device); + dr_wakeup_config.usb_pdata[0] = mxc_usbdr_otg_device.dev.platform_data; +#endif +#ifdef CONFIG_USB_EHCI_ARC_OTG + dr_utmi_config.operating_mode = DR_HOST_MODE; + dr_utmi_config.wake_up_enable = _host_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend; + dr_utmi_config.is_wakeup_event = _is_host_wakeup; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + dr_utmi_config.wakeup_handler = host_wakeup_handler; + platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config)); + platform_device_register(&mxc_usbdr_host_device); + dr_wakeup_config.usb_pdata[1] = mxc_usbdr_host_device.dev.platform_data; +#endif +#ifdef CONFIG_USB_GADGET_ARC + dr_utmi_config.operating_mode = DR_UDC_MODE; + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend; + dr_utmi_config.is_wakeup_event = _is_device_wakeup; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + dr_utmi_config.wakeup_handler = device_wakeup_handler; + platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config)); + platform_device_register(&mxc_usbdr_udc_device); + dr_wakeup_config.usb_pdata[2] = mxc_usbdr_udc_device.dev.platform_data; +#endif + mxc_register_device(&mxc_usbdr_wakeup_device, &dr_wakeup_config); +} diff --git a/arch/arm/mach-mx5/usb_h1.c b/arch/arm/mach-mx5/usb_h1.c new file mode 100644 index 000000000000..197947cfcb3c --- /dev/null +++ b/arch/arm/mach-mx5/usb_h1.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2005-2011 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/delay.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <asm/delay.h> +#include <mach/arc_otg.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include "usb.h" +#include "iomux.h" +#include "mx51_pins.h" +static struct clk *usb_phy2_clk; +static struct clk *usb_oh3_clk; +static struct clk *usb_ahb_clk; +extern int clk_get_usecount(struct clk *clk); + +#ifdef CONFIG_USB_EHCI_ARC +extern void fsl_usb_recover_hcd(struct platform_device *pdev); +#else +static void fsl_usb_recover_hcd(struct platform_device *pdev) +{; } +#endif +/* + * USB Host1 HS port + */ +static int gpio_usbh1_active(void) +{ + /* Set USBH1_STP to GPIO and toggle it */ + mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO | + IOMUX_CONFIG_SION); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), "usbh1_stp"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 1); + + /* Signal only used on MX51-3DS for reset to PHY.*/ + if (machine_is_mx51_3ds()) { + mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT1); + mxc_iomux_set_pad(MX51_PIN_EIM_D17, PAD_CTL_DRV_HIGH | + PAD_CTL_HYS_NONE | PAD_CTL_PUE_KEEPER | + PAD_CTL_100K_PU | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_D17), "eim_d17"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D17), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D17), 1); + } + + msleep(100); + + return 0; +} + +static void gpio_usbh1_inactive(void) +{ + /* Signal only used on MX51-3DS for reset to PHY.*/ + if (machine_is_mx51_3ds()) { + gpio_free(IOMUX_TO_GPIO(MX51_PIN_EIM_D17)); + mxc_free_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_GPIO); + } + + mxc_free_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO); + gpio_free(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP)); +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) + USBCTRL |= UCTRL_H1WIE; + else { + USBCTRL &= ~UCTRL_H1WIE; + /* The interrupt must be disabled for at least 3 + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) { + UH1_PORTSC1 |= PORTSC_PHCD; + } else { + UH1_PORTSC1 &= ~PORTSC_PHCD; + } +} + +static void usbh1_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_ahb_clk); + clk_enable(usb_oh3_clk); + clk_enable(usb_phy2_clk); + } else { + clk_disable(usb_phy2_clk); + clk_disable(usb_oh3_clk); + clk_disable(usb_ahb_clk); + } +} + +static enum usb_wakeup_event _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_H1WIR; + + if (wakeup_req) + return !WAKEUP_EVENT_INVALID; + + return WAKEUP_EVENT_INVALID; +} + +static void h1_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _wake_up_enable(pdata, false); + _phy_lowpower_suspend(pdata, false); + fsl_usb_recover_hcd(&mxc_usbh1_device); +} + +static void usbh1_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_H1WIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable H1WIE to clear H1WIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_H1WIE; + udelay(100); + USBCTRL |= UCTRL_H1WIE; + } +} +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret; + struct clk *usb_clk; + + /* the usb_ahb_clk will be enabled in usb_otg_init */ + usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_enable(usb_clk); + usb_phy2_clk = usb_clk; + } else if (cpu_is_mx50()) { + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_enable(usb_clk); + usb_phy2_clk = usb_clk; + } else if (cpu_is_mx51()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + } + + ret = fsl_usb_host_init(pdev); + if (ret) + return ret; + + if (cpu_is_mx51()) { + /* setback USBH1_STP to be function */ + mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_SRE_FAST | + PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | + PAD_CTL_HYS_ENABLE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW); + gpio_free(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP)); + } + + /* disable remote wakeup irq */ + USBCTRL &= ~UCTRL_H1WIE; + return 0; +} + +static void fsl_usb_host_uninit_ext(struct fsl_usb2_platform_data *pdata) +{ + if (cpu_is_mx53()) { + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + + clk_disable(usb_phy2_clk); + clk_put(usb_phy2_clk); + } else if (cpu_is_mx50()) { + clk_disable(usb_phy2_clk); + clk_put(usb_phy2_clk); + } else if (cpu_is_mx51()) { + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + } + + fsl_usb_host_uninit(pdata); + /* usb_ahb_clk will be disabled at usb_common.c */ + clk_put(usb_ahb_clk); +} + +static struct fsl_usb2_platform_data usbh1_config = { + .name = "Host 1", + .platform_init = fsl_usb_host_init_ext, + .platform_uninit = fsl_usb_host_uninit_ext, + .operating_mode = FSL_USB2_MPH_HOST, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = usbh1_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .is_wakeup_event = _is_usbh1_wakeup, + .wakeup_handler = h1_wakeup_handler, + .transceiver = "utmi", +}; +static struct fsl_usb2_wakeup_platform_data usbh1_wakeup_config = { + .name = "USBH1 wakeup", + .usb_clock_for_pm = usbh1_clock_gate, + .usb_pdata = {&usbh1_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh1_wakeup_event_clear, +}; + +void mx5_set_host1_vbus_func(driver_vbus_func driver_vbus) +{ + usbh1_config.platform_driver_vbus = driver_vbus; +} + +void __init mx5_usbh1_init(void) +{ + if (cpu_is_mx51()) { + usbh1_config.phy_mode = FSL_USB2_PHY_ULPI; + usbh1_config.transceiver = "isp1504"; + usbh1_config.gpio_usb_active = gpio_usbh1_active; + usbh1_config.gpio_usb_inactive = gpio_usbh1_inactive; + } + mxc_register_device(&mxc_usbh1_device, &usbh1_config); + usbh1_config.wakeup_pdata = &usbh1_wakeup_config; + mxc_register_device(&mxc_usbh1_wakeup_device, &usbh1_wakeup_config); +} + diff --git a/arch/arm/mach-mx5/usb_h2.c b/arch/arm/mach-mx5/usb_h2.c new file mode 100644 index 000000000000..516c62dea814 --- /dev/null +++ b/arch/arm/mach-mx5/usb_h2.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2005-2011 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/delay.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <mach/arc_otg.h> +#include "usb.h" +#include "iomux.h" +#include "mx51_pins.h" + +#ifdef CONFIG_USB_EHCI_ARC +extern void fsl_usb_recover_hcd(struct platform_device *pdev); +#else +static void fsl_usb_recover_hcd(struct platform_device *pdev) +{; } +#endif +/* + * USB Host2 HS port + */ +static int gpio_usbh2_active(void) +{ + /* Set USBH2_STP to GPIO and toggle it */ + mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_GPIO); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), "eim_a26"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 0); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 1); + + msleep(100); + + return 0; +} + +static void gpio_usbh2_inactive(void) +{ + gpio_free(IOMUX_TO_GPIO(MX51_PIN_EIM_A26)); + mxc_free_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_GPIO); +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + printk(KERN_DEBUG "host2, %s, enable is %d\n", __func__, enable); + if (enable) + USBCTRL_HOST2 |= UCTRL_H2WIE; + else { + USBCTRL_HOST2 &= ~UCTRL_H2WIE; + /* The interrupt must be disabled for at least 3 + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + printk(KERN_DEBUG "host2, %s, enable is %d\n", __func__, enable); + if (enable) { + UH2_PORTSC1 |= PORTSC_PHCD; + } else { + UH2_PORTSC1 &= ~PORTSC_PHCD; + } +} + +static void fsl_usbh2_clock_gate(bool on) +{ + struct clk *usb_clk; + if (on) { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } else { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } +} + +static enum usb_wakeup_event _is_usbh2_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_H2WIR; + + if (wakeup_req) + return !WAKEUP_EVENT_INVALID; + + return WAKEUP_EVENT_INVALID; +} + +static void h2_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _wake_up_enable(pdata, false); + _phy_lowpower_suspend(pdata, false); + fsl_usb_recover_hcd(&mxc_usbh2_device); +} + +static void usbh2_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_H2WIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable H2WIE to clear H2WIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_H2WIE; + udelay(100); + USBCTRL |= UCTRL_H2WIE; + } +} +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret = 0; + struct clk *usb_clk; + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + /* on mx53, there is a hardware limitation that when switch the host2's clk mode + * ,usb phy1 clk must be on, after finish switching this clk can be off */ + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } + + ret = fsl_usb_host_init(pdev); + + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } + + /* setback USBH2_STP to be function */ + mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2); + + return ret; +} + +static void fsl_usb_host_uninit_ext(struct fsl_usb2_platform_data *pdata) +{ + struct clk *usb_clk; + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + fsl_usb_host_uninit(pdata); +} + +static struct fsl_usb2_platform_data usbh2_config = { + .name = "Host 2", + .platform_init = fsl_usb_host_init_ext, + .platform_uninit = fsl_usb_host_uninit_ext, + .operating_mode = FSL_USB2_MPH_HOST, + .phy_mode = FSL_USB2_PHY_ULPI, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = fsl_usbh2_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .gpio_usb_active = gpio_usbh2_active, + .gpio_usb_inactive = gpio_usbh2_inactive, + .is_wakeup_event = _is_usbh2_wakeup, + .wakeup_handler = h2_wakeup_handler, + .transceiver = "isp1504", +}; +static struct fsl_usb2_wakeup_platform_data usbh2_wakeup_config = { + .name = "USBH2 wakeup", + .usb_clock_for_pm = fsl_usbh2_clock_gate, + .usb_pdata = {&usbh2_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh2_wakeup_event_clear, +}; +void __init mx5_usbh2_init(void) +{ + usbh2_config.wakeup_pdata = &usbh2_wakeup_config; + mxc_register_device(&mxc_usbh2_device, &usbh2_config); + mxc_register_device(&mxc_usbh2_wakeup_device, &usbh2_wakeup_config); +} diff --git a/arch/arm/mach-mx5/wfi.S b/arch/arm/mach-mx5/wfi.S new file mode 100644 index 000000000000..a6e373f4e08b --- /dev/null +++ b/arch/arm/mach-mx5/wfi.S @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2008-2010 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/linkage.h> + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_AUXCR_L2EN 1 << 1 +/* + * cpu_cortexa8_do_idle() + * + * Idle the processor (eg, wait for interrupt). + * + * IRQs are already disabled. + */ +ENTRY(cpu_cortexa8_do_idle) + + mrc p15, 0, r1, c1, c0, 1 @ R1 = auxiliary control reg + ands r2, r1, #ARM_AUXCR_L2EN @ Check if L2 is disabled + beq SkipL2Access + + mrc p15, 0, r2, c1, c0, 0 @ R2 = system control reg + bic r2, r2, #ARM_CTRL_DCACHE @ Disable DCache + mcr p15, 0, r2, c1, c0, 0 @ Update system control reg + + bic r1, r1, #ARM_AUXCR_L2EN @ Disable L2 cache + mcr p15, 0, r1, c1, c0, 1 @ Update aux control reg + + ldr r1, =(0x0 << 6) @ A[6] = 0 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x00] @ Save tag info + + ldr r1, =(0x1 << 6) @ A[6] = 1 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x04] @ Save tag info + + ldr r1, =(0x0 << 3) @ A[6:3] = b0000 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x08] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x0C] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x10] @ Store data info + + ldr r1, =(0x1 << 3) @ A[6:3] = b0001 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x14] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x18] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x1C] @ Store data info + + ldr r1, =(0x2 << 3) @ A[6:3] = b0010 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x20] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x24] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x28] @ Store data info + + ldr r1, =(0x3 << 3) @ A[6:3] = b0011 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x2C] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x30] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x34] @ Store data info + + ldr r1, =(0x4 << 3) @ A[6:3] = b0100 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x38] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x3C] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x40] @ Store data info + + ldr r1, =(0x5 << 3) @ A[6:3] = b0101 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x44] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x48] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x4C] @ Store data info + + ldr r1, =(0x6 << 3) @ A[6:3] = b0110 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x50] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x54] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x58] @ Store data info + + ldr r1, =(0x7 << 3) @ A[6:3] = b0111 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x5C] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x60] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x64] @ Store data info + + ldr r1, =(0x8 << 3) @ A[6:3] = b1000 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x68] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x6C] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x70] @ Store data info + + ldr r1, =(0x9 << 3) @ A[6:3] = b1001 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x74] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x78] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x7C] @ Store data info + + ldr r1, =(0xA << 3) @ A[6:3] = b1010 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x80] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x84] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x88] @ Store data info + + ldr r1, =(0xB << 3) @ A[6:3] = b1011 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x8C] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x90] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0x94] @ Store data info + + ldr r1, =(0xC << 3) @ A[6:3] = b1100 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0x98] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0x9C] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0xA0] @ Store data info + + ldr r1, =(0xD << 3) @ A[6:3] = b1101 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xA4] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0xA8] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0xAC] @ Store data info + + ldr r1, =(0xE << 3) @ A[6:3] = b1110 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xB0] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0xB4] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0xB8] @ Store data info + + ldr r1, =(0xF << 3) @ A[6:3] = b1111 + mcr p15, 0, r1, c15, c9, 3 @ Read L2 Data RAM into L2 data 0-2 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xBC] @ Store data info + mrc p15, 0, r2, c15, c8, 1 @ Move L2 data 1 register to R2 + str r2, [r0, #0xC0] @ Store data info + mrc p15, 0, r2, c15, c8, 5 @ Move L2 data 2 register to R2 + str r2, [r0, #0xC4] @ Store data info + + ldr r1, =(0x2 << 29) | (0x0 << 6) @ WAY = A[31:29] = 2, A[6] = 0 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xC8] @ Save tag info + + ldr r1, =(0x2 << 29) | (0x1 << 6) @ WAY = A[31:29] = 2, A[6] = 1 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xCC] @ Save tag info + + ldr r1, =(0x4 << 29) | (0x0 << 6) @ WAY = A[31:29] = 4, A[6] = 0 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xD0] @ Save tag info + + ldr r1, =(0x4 << 29) | (0x1 << 6) @ WAY = A[31:29] = 4, A[6] = 1 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xD4] @ Save tag info + + ldr r1, =(0x6 << 29) | (0x0 << 6) @ WAY = A[31:29] = 6, A[6] = 0 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xD8] @ Save tag info + + ldr r1, =(0x6 << 29) | (0x1 << 6) @ WAY = A[31:29] = 6, A[6] = 1 + mcr p15, 0, r1, c15, c9, 2 @ Read L2 tag RAM into L2 data 0 register + mrc p15, 0, r2, c15, c8, 0 @ Move L2 data 0 register to R2 + str r2, [r0, #0xDC] @ Save tag info + + .long 0xe320f003 @ Opcode for WFI + + ldr r1, =(0x0 << 6) @ A[6] = 0 + ldr r2, [r0, #0x00] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x1 << 6) @ A[6] = 1 + ldr r2, [r0, #0x04] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x0 << 3) @ A[6:3] = b0000 + ldr r2, [r0, #0x08] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x0C] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x10] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x1 << 3) @ A[6:3] = b0001 + ldr r2, [r0, #0x14] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x18] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x1C] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x2 << 3) @ A[6:3] = b0010 + ldr r2, [r0, #0x20] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x24] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x28] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x3 << 3) @ A[6:3] = b0011 + ldr r2, [r0, #0x2C] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x30] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x34] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x4 << 3) @ A[6:3] = b0100 + ldr r2, [r0, #0x38] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x3C] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x40] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x5 << 3) @ A[6:3] = b0101 + ldr r2, [r0, #0x44] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x48] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x4C] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x6 << 3) @ A[6:3] = b0110 + ldr r2, [r0, #0x50] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x54] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x58] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x7 << 3) @ A[6:3] = b0111 + ldr r2, [r0, #0x5C] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x60] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x64] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x8 << 3) @ A[6:3] = b1000 + ldr r2, [r0, #0x68] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x6C] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x70] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x9 << 3) @ A[6:3] = b1001 + ldr r2, [r0, #0x74] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x78] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x7C] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xA << 3) @ A[6:3] = b1010 + ldr r2, [r0, #0x80] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x84] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x88] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xB << 3) @ A[6:3] = b1011 + ldr r2, [r0, #0x8C] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x90] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0x94] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xC << 3) @ A[6:3] = b1100 + ldr r2, [r0, #0x98] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0x9C] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0xA0] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xD << 3) @ A[6:3] = b1101 + ldr r2, [r0, #0xA4] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0xA8] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0xAC] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xE << 3) @ A[6:3] = b1110 + ldr r2, [r0, #0xB0] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0xB4] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0xB8] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0xF << 3) @ A[6:3] = b1111 + ldr r2, [r0, #0xBC] @ Load data info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + ldr r2, [r0, #0xC0] @ Load data info + mcr p15, 0, r2, c15, c8, 1 @ Move R2 to L2 data 1 register + ldr r2, [r0, #0xC4] @ Load data info + mcr p15, 0, r2, c15, c8, 5 @ Move R2 to L2 data 2 register + mcr p15, 0, r1, c15, c8, 3 @ Write L2 data 0-2 registers to L2 data RAM + + ldr r1, =(0x2 << 29) | (0x0 << 6) @ WAY = A[31:29] = 2, A[6] = 0 + ldr r2, [r0, #0xC8] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x2 << 29) | (0x1 << 6) @ WAY = A[31:29] = 2, A[6] = 1 + ldr r2, [r0, #0xCC] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x4 << 29) | (0x0 << 6) @ WAY = A[31:29] = 4, A[6] = 0 + ldr r2, [r0, #0xD0] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x4 << 29) | (0x1 << 6) @ WAY = A[31:29] = 4, A[6] = 1 + ldr r2, [r0, #0xD4] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x6 << 29) | (0x0 << 6) @ WAY = A[31:29] = 6, A[6] = 0 + ldr r2, [r0, #0xD8] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + ldr r1, =(0x6 << 29) | (0x1 << 6) @ WAY = A[31:29] = 6, A[6] = 1 + ldr r2, [r0, #0xDC] @ Load tag info + mcr p15, 0, r2, c15, c8, 0 @ Move R2 to L2 data 0 register + mcr p15, 0, r1, c15, c8, 2 @ Write L2 data 0 register to L2 tag RAM + + mrc p15, 0, r1, c1, c0, 1 @ R1 = auxiliary control reg + orr r1, r1, #ARM_AUXCR_L2EN @ Enable L2 cache + mcr p15, 0, r1, c1, c0, 1 @ Update aux control reg + + mrc p15, 0, r2, c1, c0, 0 @ R2 = system control reg + orr r2, r2, #ARM_CTRL_DCACHE @ Enable DCache + mcr p15, 0, r2, c1, c0, 0 @ Update system control reg + + b Done + +SkipL2Access: + .long 0xe320f003 @ Opcode for WFI + +Done: + mov pc, lr + + .type cortexa8_idle_workaround, #object +ENTRY(cortexa8_idle_workaround) + .word cpu_cortexa8_do_idle + .size cortexa8_idle_workaround, . - cortexa8_idle_workaround |