diff options
Diffstat (limited to 'arch/arm/plat-mxs')
47 files changed, 9194 insertions, 0 deletions
diff --git a/arch/arm/plat-mxs/Kconfig b/arch/arm/plat-mxs/Kconfig new file mode 100644 index 000000000000..831a24b53789 --- /dev/null +++ b/arch/arm/plat-mxs/Kconfig @@ -0,0 +1,179 @@ +if ARCH_MXS + +menu "Freescale i.MXS implementations" + +choice + prompt "Select i.MXS chip family" + +config ARCH_MX28 + bool "Freescale MX28" + select CPU_ARM926T + select FIQ + select ZONE_DMA + select MXS_ICOLL + select MXS_DMA_ENGINE + select MXS_AUART_DMA_SUPPORT + select ARCH_HAS_CPUFREQ + ---help--- + Support Freescale MX28 chips + +config ARCH_MX23 + bool "Freescale MX23" + select CPU_ARM926T + select FIQ + select ZONE_DMA + select MXS_ICOLL + select MXS_DMA_ENGINE + select MXS_AUART_DMA_SUPPORT + select ARCH_HAS_CPUFREQ + ---help--- + Support Freescale MX23 chips + +endchoice + +if ARCH_MX28 +source arch/arm/mach-mx28/Kconfig +endif + +if ARCH_MX23 +source arch/arm/mach-mx23/Kconfig +endif + +config DMA_ZONE_SIZE + int "DMA memory zone size" + range 0 32 + default 16 + help + This is the size in MB for the DMA zone. The DMA zone is used for + dedicated memory for large contiguous video buffers +endmenu + +config MXS_ICOLL + bool + +config MXS_EARLY_CONSOLE + bool "Enable console early" + default y + help + Enable console early for kernel debug. + +config MXS_DMA_ENGINE + bool "Enable DMA ENGINE support" + default y + help + Support DMA controller on AHB-APBH and AHB-APBX Bridge + +config MXS_LRADC + bool "Low Resolution ADC support" + default y + depends on ARCH_MXS + help + Enable LRADC support + +config MXS_PWM_CHANNELS + int + default 8 + help + The number of pwm channel on Freescale MXS platform. + +menu "Freescale Application UART:" + +config MXS_AUART_DMA_SUPPORT + bool + depends on MXS_DMA_ENGINE + default y + +config MXS_AUART_PORTS + int + default 5 + +config MXS_AUART0_DEVICE_ENABLE + bool "Application uart 0 enabled" + default y + help + Enable applicatoin uart 0 + +config MXS_AUART0_DMA_ENABLE + bool "Set application uart 0 to dma mode" + default n + depends on MXS_AUART_DMA_SUPPORT + help + Set application uart 0 to dma mode + +config MXS_AUART1_DEVICE_ENABLE + bool "Application uart 1 enabled" + default y + help + Enable applicatoin uart 1 + +config MXS_AUART1_DMA_ENABLE + bool "Set application uart 1 to dma mode" + default n + depends on MXS_AUART_DMA_SUPPORT + help + Set application uart 1 to dma mode + +config MXS_AUART2_DEVICE_ENABLE + bool "Application uart 2 enabled" + default y + help + Enable applicatoin uart 2 + +config MXS_AUART2_DMA_ENABLE + bool "Set application uart 2 to dma mode" + default n + depends on MXS_AUART_DMA_SUPPORT + help + Set application uart 2 to dma mode + +config MXS_AUART3_DEVICE_ENABLE + bool "Application uart 3 enabled" + default y + help + Enable applicatoin uart 3 + +config MXS_AUART3_DMA_ENABLE + bool "Set application uart 3 to dma mode" + default n + depends on MXS_AUART_DMA_SUPPORT + help + Set application uart 3 to dma mode + +config MXS_AUART4_DEVICE_ENABLE + bool "Application uart 4 enabled" + default y + help + Enable applicatoin uart 4 + +config MXS_AUART4_DMA_ENABLE + bool "Set application uart 4 to dma mode" + default n + depends on MXS_AUART_DMA_SUPPORT + help + Set application uart 4 to dma mode + +config MXS_RAM_FREQ_SCALING + bool "RAM frequency scaling support" + depends on ARCH_MXS + default y + +choice + prompt "Select MXS RAM chip" + depends on MXS_RAM_FREQ_SCALING + +config MXS_RAM_MDDR + bool "mDDR SDRAM" + depends on ARCH_MX23 +config MXS_RAM_DDR + bool "DDR SDRAM" + depends on ARCH_MX23 + +endchoice + +config IRAM_ALLOC + bool + default y + select GENERIC_ALLOCATOR +endmenu + +endif diff --git a/arch/arm/plat-mxs/Makefile b/arch/arm/plat-mxs/Makefile new file mode 100644 index 000000000000..b583737fe254 --- /dev/null +++ b/arch/arm/plat-mxs/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for the linux kernel. +# +# Object file lists. +obj-y += core.o clock.o pinctrl.o device.o timer-nomatch.o usb_common.o usb_wakeup.o + +obj-$(CONFIG_MXS_TIMER_WITH_MACH) += timer-match.o +obj-$(CONFIG_IRAM_ALLOC) += iram.o +obj-$(CONFIG_GENERIC_GPIO) += gpio.o + +obj-$(CONFIG_MXS_UNIQUE_ID) += unique-id.o + +obj-$(CONFIG_MXS_ICOLL) += icoll.o + +obj-$(CONFIG_MXS_DMA_ENGINE) += dmaengine.o dma-apbh.o dma-apbx.o + +obj-$(CONFIG_USB_SUPPORT) += utmixc.o + +obj-$(CONFIG_MXS_LRADC) += lradc.o +# Power Management +obj-$(CONFIG_CPU_FREQ) += cpufreq.o + +# charging/current limitation testing + diff --git a/arch/arm/plat-mxs/clock.c b/arch/arm/plat-mxs/clock.c new file mode 100644 index 000000000000..1b98b1e51164 --- /dev/null +++ b/arch/arm/plat-mxs/clock.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2009-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/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/cpufreq.h> + +#include <mach/clock.h> + +extern int cpufreq_trig_needed; +static bool (*mxs_enable_h_autoslow)(bool enable); +static void (*mxs_set_h_autoslow_flags)(u16 flags); + +static DEFINE_SPINLOCK(clockfw_lock); + +/* + *------------------------------------------------------------------------- + * Standard clock functions defined in include/linux/clk.h + *------------------------------------------------------------------------- + */ +int __clk_get(struct clk *clk) +{ + if (clk->ref < CLK_REF_LIMIT) + clk->ref += CLK_REF_UNIT; + return clk->ref < CLK_REF_LIMIT; +} + +void __clk_put(struct clk *clk) +{ + if (clk->ref & CLK_REF_LIMIT) + clk->ref -= CLK_REF_UNIT; +} + +static void default_clk_disable(struct clk *clk) +{ + if (clk->enable_reg) + __raw_writel(clk->enable_bits, clk->enable_reg + SET_REGISTER); +} + +static int default_clk_enable(struct clk *clk) +{ + if (clk->enable_reg) + __raw_writel(clk->enable_bits, clk->enable_reg + CLR_REGISTER); + return 0; +} + +static unsigned long default_get_rate(struct clk *clk) +{ + if (clk->parent && clk->parent->get_rate) + return clk->parent->get_rate(clk->parent); + return 0L; +} + +static void __clk_disable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->ref) + return; + + if ((--clk->ref) & CLK_EN_MASK) + return; + + if (clk->disable) + clk->disable(clk); + __clk_disable(clk->secondary); + __clk_disable(clk->parent); +} + +static int __clk_enable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if ((clk->ref++) & CLK_EN_MASK) + return 0; + if (clk->parent) + __clk_enable(clk->parent); + if (clk->secondary) + __clk_enable(clk->secondary); + if (clk->enable) + clk->enable(clk); + return 0; +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + int ret = 0; + int pre_usage; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clockfw_lock, flags); + pre_usage = (clk->ref & CLK_EN_MASK); + + if (clk->set_sys_dependent_parent) + clk->set_sys_dependent_parent(clk); + + ret = __clk_enable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && (pre_usage == 0)) { + cpufreq_trig_needed = 1; + cpufreq_update_policy(0); + } + return ret; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + if (clk->flags & ALWAYS_ENABLED) + return; + spin_lock_irqsave(&clockfw_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && ((clk->ref & CLK_EN_MASK) == 0)) { + cpufreq_trig_needed = 1; + cpufreq_update_policy(0); + } +} +EXPORT_SYMBOL(clk_disable); + +int clk_get_usecount(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return 0; + + return clk->ref & CLK_EN_MASK; +} +EXPORT_SYMBOL(clk_get_usecount); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long flags, rate; + if (clk == NULL || IS_ERR(clk) || clk->get_rate == NULL) + return 0UL; + + spin_lock_irqsave(&clockfw_lock, flags); + rate = clk->get_rate(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk == NULL || IS_ERR(clk) || !clk->round_rate) + return 0; + + if (clk->flags & RATE_FIXED) + return 0; + + if (clk->round_rate) + return clk->round_rate(clk, rate); + return 0; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) + return ret; + + if (clk->flags & RATE_FIXED) + return ret; + + spin_lock_irqsave(&clockfw_lock, flags); + ret = clk->set_rate(clk, rate); + spin_unlock_irqrestore(&clockfw_lock, flags); + return ret; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + int ret = -EINVAL; + struct clk *prev_parent; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || + IS_ERR(parent) || clk->set_parent == NULL || + parent->get_rate == NULL) + return ret; + + if (clk->ref & CLK_EN_MASK) + clk_enable(parent); + + spin_lock_irqsave(&clockfw_lock, flags); + prev_parent = clk->parent; + ret = clk->set_parent(clk, parent); + if (ret) { + spin_unlock_irqrestore(&clockfw_lock, flags); + if (clk->ref & CLK_EN_MASK) + clk_disable(parent); + return ret; + } + + clk->parent = parent; + + spin_unlock_irqrestore(&clockfw_lock, flags); + + if (clk->ref & CLK_EN_MASK) + clk_disable(prev_parent); + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + struct clk *ret = NULL; + + if (clk == NULL || IS_ERR(clk)) + return ret; + + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_register(struct clk_lookup *lookup) +{ + if (lookup == NULL || IS_ERR(lookup) || + lookup->clk == NULL || IS_ERR(lookup->clk)) + return -EINVAL; + + if (lookup->clk->ref & CLK_REF_LIMIT) + return -EEXIST; + + if (!(lookup->clk->enable)) + lookup->clk->enable = default_clk_enable; + if (!(lookup->clk->disable)) + lookup->clk->disable = default_clk_disable; + if (!(lookup->clk->get_rate)) + lookup->clk->get_rate = default_get_rate; + + clkdev_add(lookup); + + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk_lookup *lookup) +{ + if (lookup == NULL || IS_ERR(lookup) || + lookup->clk == NULL || IS_ERR(lookup->clk)) + return; + + if (lookup->clk->ref & CLK_REF_LIMIT) + return; + + clkdev_drop(lookup); + if (lookup->clk->enable == default_clk_enable) + lookup->clk->enable = NULL; + if (lookup->clk->disable == default_clk_disable) + lookup->clk->disable = NULL; + if (lookup->clk->get_rate == default_get_rate) + lookup->clk->get_rate = NULL; +} +EXPORT_SYMBOL(clk_unregister); + +bool clk_enable_h_autoslow(bool enable) +{ + unsigned long flags; + bool ret = false; + + if (mxs_enable_h_autoslow == NULL) + return ret; + + spin_lock_irqsave(&clockfw_lock, flags); + ret = mxs_enable_h_autoslow(enable); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return ret; +} +EXPORT_SYMBOL(clk_enable_h_autoslow); + +void clk_set_h_autoslow_flags(u16 mask) +{ + unsigned long flags; + + if (mxs_set_h_autoslow_flags == NULL) + return; + + spin_lock_irqsave(&clockfw_lock, flags); + mxs_set_h_autoslow_flags(mask); + spin_unlock_irqrestore(&clockfw_lock, flags); +} +EXPORT_SYMBOL(clk_set_h_autoslow_flags); + +void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool), + void (*set_func)(u16)) +{ + mxs_enable_h_autoslow = enable_func; + mxs_set_h_autoslow_flags = set_func; +} +EXPORT_SYMBOL(clk_en_public_h_asm_ctrl); diff --git a/arch/arm/plat-mxs/core.c b/arch/arm/plat-mxs/core.c new file mode 100644 index 000000000000..b804a579397c --- /dev/null +++ b/arch/arm/plat-mxs/core.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2009-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/io.h> +#include <linux/err.h> + +#include <asm/proc-fns.h> + +#include <mach/hardware.h> +#include <mach/regs-rtc.h> + +void (*machine_arch_reset) (char mode, const char *cmd); + +void arch_idle(void) +{ + cpu_do_idle(); +} + +void arch_reset(char mode, const char *cmd) +{ + if (machine_arch_reset) + machine_arch_reset(mode, cmd); + else { + void *base = IO_ADDRESS(RTC_PHYS_ADDR); + + __raw_writel(1, base + HW_RTC_WATCHDOG); + __raw_writel(0x80000000, base + HW_RTC_PERSISTENT1_SET); + __raw_writel(BM_RTC_CTRL_WATCHDOGEN, base + HW_RTC_CTRL_SET); + } + cpu_reset(0); +} + +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/plat-mxs/cpufreq.c b/arch/arm/plat-mxs/cpufreq.c new file mode 100644 index 000000000000..a188b21d9bf4 --- /dev/null +++ b/arch/arm/plat-mxs/cpufreq.c @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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 <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/notifier.h> + +#include <mach/hardware.h> +#include <linux/io.h> +#include <asm/system.h> +#include <mach/regulator.h> +#include <mach/power.h> +#include <mach/clock.h> +#include <mach/bus_freq.h> + +static struct regulator *cpu_regulator; +static struct clk *cpu_clk; +static struct clk *ahb_clk; +static struct clk *x_clk; +static struct clk *emi_clk; +static struct regulator *vddd; +static struct regulator *vdddbo; +static struct regulator *vddio; +static struct regulator *vdda; +static struct cpufreq_frequency_table imx_freq_table[7]; +int cpu_freq_khz_min; +int cpu_freq_khz_max; +int cpufreq_trig_needed; +int cur_freq_table_size; +int lcd_on_freq_table_size; +int lcd_off_freq_table_size; +int high_freq_needed; + +extern char *ahb_clk_id; +extern struct profile profiles[OPERATION_WP_SUPPORTED]; +extern int low_freq_used(void); + +static int set_freq_table(struct cpufreq_policy *policy, int end_index) +{ + int ret = 0; + int i; + int zero_no = 0; + + for (i = 0; i < end_index; i++) { + if (profiles[i].cpu == 0) + zero_no++; + } + + end_index -= zero_no; + + cpu_freq_khz_min = profiles[0].cpu; + cpu_freq_khz_max = profiles[0].cpu; + for (i = 0; i < end_index; i++) { + imx_freq_table[end_index - 1 - i].index = end_index - i; + imx_freq_table[end_index - 1 - i].frequency = + profiles[i].cpu; + + if ((profiles[i].cpu) < cpu_freq_khz_min) + cpu_freq_khz_min = profiles[i].cpu; + + if ((profiles[i].cpu) > cpu_freq_khz_max) + cpu_freq_khz_max = profiles[i].cpu; + } + + imx_freq_table[i].index = 0; + imx_freq_table[i].frequency = CPUFREQ_TABLE_END; + + policy->cur = clk_get_rate(cpu_clk) / 1000; + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; + policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; + + /* Manual states, that PLL stabilizes in two CLK32 periods */ + policy->cpuinfo.transition_latency = 1000; + + ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); + + if (ret < 0) { + printk(KERN_ERR "%s: failed to register i.MXC CPUfreq\n", + __func__); + return ret; + } + + cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu); + + return ret; +} + +static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) +{ + struct cpufreq_freqs freqs; + int ret = 0, i; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.cpu = 0; + +/* work around usb problem when in updater firmare mode*/ +#ifdef CONFIG_MXS_UTP + return 0; +#endif + for (i = cur_freq_table_size - 1; i > 0; i--) { + if (profiles[i].cpu <= target_freq && + target_freq < profiles[i - 1].cpu) { + freqs.new = profiles[i].cpu; + break; + } + + if (!vddd && profiles[i].cpu > freqs.old) { + /* can't safely set more than now */ + freqs.new = profiles[i + 1].cpu; + break; + } + } + + if (i == 0) + freqs.new = profiles[i].cpu; + + if ((freqs.old / 1000) == (freqs.new / 1000)) { + if (regulator_get_voltage(vddd) == profiles[i].vddd) + return 0; + } + + if (cpu_regulator && (freqs.old < freqs.new)) { + ret = regulator_set_current_limit(cpu_regulator, + profiles[i].cur, profiles[i].cur); + if (ret) + return ret; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + if (freqs.old > freqs.new) { + int ss = profiles[i].ss; + + /* change emi while cpu is fastest to minimize + * time spent changing emiclk + */ + clk_set_rate(emi_clk, (profiles[i].emi) * 1000); + clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000); + clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); + /* x_clk order doesn't really matter */ + clk_set_rate(x_clk, (profiles[i].xbus) * 1000); + timing_ctrl_rams(ss); + + if (vddd && vdddbo && vddio && vdda) { + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + if (ret) + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + regulator_set_voltage(vdddbo, + profiles[i].vddd_bo, + profiles[i].vddd_bo); + + ret = regulator_set_voltage(vddio, + profiles[i].vddio, + profiles[i].vddio); + if (ret) + ret = regulator_set_voltage(vddio, + profiles[i].vddio, + profiles[i].vddio); + ret = regulator_set_voltage(vdda, + profiles[i].vdda, + profiles[i].vdda); + if (ret) + ret = regulator_set_voltage(vdda, + profiles[i].vdda, + profiles[i].vdda); + } + } else { + int ss = profiles[i].ss; + if (vddd && vdddbo && vddio && vdda) { + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + if (ret) + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + regulator_set_voltage(vdddbo, + profiles[i].vddd_bo, + profiles[i].vddd_bo); + ret = regulator_set_voltage(vddio, + profiles[i].vddio, + profiles[i].vddio); + if (ret) + ret = regulator_set_voltage(vddio, + profiles[i].vddio, + profiles[i].vddio); + ret = regulator_set_voltage(vdda, + profiles[i].vdda, + profiles[i].vdda); + if (ret) + ret = regulator_set_voltage(vdda, + profiles[i].vdda, + profiles[i].vdda); + } + /* x_clk order doesn't really matter */ + clk_set_rate(x_clk, (profiles[i].xbus) * 1000); + timing_ctrl_rams(ss); + clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000); + clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); + clk_set_rate(emi_clk, (profiles[i].emi) * 1000); + } + + if (is_hclk_autoslow_ok()) + clk_set_h_autoslow_flags(profiles[i].h_autoslow_flags); + else + clk_enable_h_autoslow(false); + + if (high_freq_needed == 0) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + if (cpu_regulator && (freqs.old > freqs.new)) /* will not fail */ + regulator_set_current_limit(cpu_regulator, + profiles[i].cur, + profiles[i].cur); + + if (high_freq_needed == 1) { + high_freq_needed = 0; + cur_freq_table_size = lcd_on_freq_table_size; + set_freq_table(policy, cur_freq_table_size); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return ret; +} + +static int calc_frequency_khz(int target, unsigned int relation) +{ + int i; + + if (target * 1000 == clk_get_rate(cpu_clk)) + return target; + + if (relation == CPUFREQ_RELATION_H) { + for (i = cur_freq_table_size - 1; i >= 0; i--) { + if (imx_freq_table[i].frequency <= target) + return imx_freq_table[i].frequency; + } + } else if (relation == CPUFREQ_RELATION_L) { + for (i = 0; i < cur_freq_table_size; i++) { + if (imx_freq_table[i].frequency >= target) + return imx_freq_table[i].frequency; + } +} + + printk(KERN_ERR "Error: No valid cpufreq relation\n"); + return cpu_freq_khz_max; +} + +static int mxs_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + int freq_KHz; + struct cpufreq_freqs freqs; + int low_freq_bus_ready = 0; + + if (cpufreq_trig_needed == 1) { + /* Set the current working point. */ + cpufreq_trig_needed = 0; + target_freq = clk_get_rate(cpu_clk) / 1000; + low_freq_bus_ready = low_freq_used(); + + if ((target_freq < LCD_ON_CPU_FREQ_KHZ) && + (low_freq_bus_ready == 0)) { + high_freq_needed = 1; + target_freq = LCD_ON_CPU_FREQ_KHZ; + goto change_freq; + } + + target_freq = clk_get_rate(cpu_clk) / 1000; + freq_KHz = calc_frequency_khz(target_freq, relation); + + freqs.old = target_freq; + freqs.new = freq_KHz; + freqs.cpu = 0; + freqs.flags = 0; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + low_freq_bus_ready = low_freq_used(); + if (low_freq_bus_ready) { + int i; + cur_freq_table_size = lcd_off_freq_table_size; + /* find current table index to get + * hbus autoslow flags and enable hbus autoslow. + */ + for (i = cur_freq_table_size - 1; i > 0; i--) { + if (profiles[i].cpu <= target_freq && + target_freq < profiles[i - 1].cpu) { + clk_set_h_autoslow_flags( + profiles[i].h_autoslow_flags); + break; + } + } + } else { + cur_freq_table_size = lcd_on_freq_table_size; + clk_enable_h_autoslow(false); + } + + set_freq_table(policy, cur_freq_table_size); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return 0; +} + + /* + * Some governors do not respects CPU and policy lower limits + * which leads to bad things (division by zero etc), ensure + * that such things do not happen. + */ +change_freq: if (target_freq < policy->cpuinfo.min_freq) + target_freq = policy->cpuinfo.min_freq; + + if (target_freq < policy->min) + target_freq = policy->min; + + freq_KHz = calc_frequency_khz(target_freq, relation); + return set_op(policy, freq_KHz); + } + +static unsigned int mxs_getspeed(unsigned int cpu) +{ + if (cpu) + return 0; + + return clk_get_rate(cpu_clk) / 1000; +} + + +static int mxs_verify_speed(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -EINVAL; + + return cpufreq_frequency_table_verify(policy, imx_freq_table); +} + +static int __init mxs_cpu_init(struct cpufreq_policy *policy) +{ + int ret = 0; + int i; + + cpu_clk = clk_get(NULL, "cpu"); + if (IS_ERR(cpu_clk)) { + ret = PTR_ERR(cpu_clk); + goto out_cpu; + } + + ahb_clk = clk_get(NULL, "h"); + if (IS_ERR(ahb_clk)) { + ret = PTR_ERR(ahb_clk); + goto out_ahb; + } + + x_clk = clk_get(NULL, "x"); + if (IS_ERR(ahb_clk)) { + ret = PTR_ERR(x_clk); + goto out_x; + } + + emi_clk = clk_get(NULL, "emi"); + if (IS_ERR(emi_clk)) { + ret = PTR_ERR(emi_clk); + goto out_emi; + } + + if (policy->cpu != 0) + return -EINVAL; + + cpu_regulator = regulator_get(NULL, "cpufreq-1"); + if (IS_ERR(cpu_regulator)) { + printk(KERN_ERR "%s: failed to get CPU regulator\n", __func__); + cpu_regulator = NULL; + ret = PTR_ERR(cpu_regulator); + goto out_cur; + } + + vddd = regulator_get(NULL, "vddd"); + if (IS_ERR(vddd)) { + printk(KERN_ERR "%s: failed to get vddd regulator\n", __func__); + vddd = NULL; + ret = PTR_ERR(vddd); + goto out_cur; + } + + vdddbo = regulator_get(NULL, "vddd_bo"); + if (IS_ERR(vdddbo)) { + vdddbo = NULL; + pr_warning("unable to get vdddbo"); + ret = PTR_ERR(vdddbo); + goto out_cur; + } + + vddio = regulator_get(NULL, "vddio"); + if (IS_ERR(vddio)) { + vddio = NULL; + pr_warning("unable to get vddio"); + ret = PTR_ERR(vddio); + goto out_cur; + } + + vdda = regulator_get(NULL, "vdda"); + if (IS_ERR(vdda)) { + vdda = NULL; + pr_warning("unable to get vdda"); + ret = PTR_ERR(vdda); + goto out_cur; + } + + for (i = 0; i < ARRAY_SIZE(profiles); i++) { + if ((profiles[i].cpu) == LCD_ON_CPU_FREQ_KHZ) { + lcd_on_freq_table_size = i + 1; + break; + } + } + + if (i == ARRAY_SIZE(profiles)) { + pr_warning("unable to find frequency for LCD on"); + printk(KERN_ERR "lcd_on_freq_table_size=%d\n", + lcd_on_freq_table_size); + goto out_cur; + } + + for (i = 0; i < ARRAY_SIZE(profiles); i++) { + if ((profiles[i].cpu) == 0) { + lcd_off_freq_table_size = i; + break; + } + } + + if (i == ARRAY_SIZE(profiles)) + lcd_off_freq_table_size = i; + + /* Set the current working point. */ + set_freq_table(policy, lcd_on_freq_table_size); + cpufreq_trig_needed = 0; + high_freq_needed = 0; + cur_freq_table_size = lcd_on_freq_table_size; + + printk(KERN_INFO "%s: cpufreq init finished\n", __func__); + return 0; +out_cur: + if (cpu_regulator) + regulator_put(cpu_regulator); + if (vddd) + regulator_put(vddd); + if (vddio) + regulator_put(vddio); + if (vdda) + regulator_put(vdda); + + clk_put(emi_clk); +out_emi: + clk_put(x_clk); +out_x: + clk_put(ahb_clk); +out_ahb: + clk_put(cpu_clk); +out_cpu: + return ret; +} + +static int mxs_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + + /* Reset CPU to 392MHz */ + set_op(policy, profiles[1].cpu); + + clk_put(cpu_clk); + regulator_put(cpu_regulator); + return 0; +} + +static struct cpufreq_driver mxs_driver = { + .flags = CPUFREQ_STICKY, + .verify = mxs_verify_speed, + .target = mxs_target, + .get = mxs_getspeed, + .init = mxs_cpu_init, + .exit = mxs_cpu_exit, + .name = "mxs", +}; + +static int __devinit mxs_cpufreq_init(void) +{ + return cpufreq_register_driver(&mxs_driver); +} + +static void mxs_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&mxs_driver); +} + +module_init(mxs_cpufreq_init); +module_exit(mxs_cpufreq_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("CPUfreq driver for i.MX"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/plat-mxs/device.c b/arch/arm/plat-mxs/device.c new file mode 100644 index 000000000000..87a38fa8c3d8 --- /dev/null +++ b/arch/arm/plat-mxs/device.c @@ -0,0 +1,831 @@ +/* + * Copyright (C) 2009-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/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/gpmi-nfc.h> + +#include <mach/device.h> + +static int mxs_device_num; +static int mxs_device_done; +static DEFINE_MUTEX(device_mutex); +static struct list_head mxs_device_level[] = { + LIST_HEAD_INIT(mxs_device_level[0]), + LIST_HEAD_INIT(mxs_device_level[1]), + LIST_HEAD_INIT(mxs_device_level[2]), + LIST_HEAD_INIT(mxs_device_level[3]), +}; + +static u64 common_dmamask = DMA_BIT_MASK(32); + +void mxs_nop_release(struct device *dev) +{ + /* Nothing */ +} + +int mxs_add_devices(struct platform_device *pdev, int num, int level) +{ + int i, ret = -ENOMEM; + if (pdev == NULL || IS_ERR(pdev) || num <= 0) + return -EINVAL; + + if (level < 0) + level = 0; + else if (level >= ARRAY_SIZE(mxs_device_level)) + level = ARRAY_SIZE(mxs_device_level) - 1; + + mutex_lock(&device_mutex); + if (mxs_device_done) { + ret = 0; + for (i = 0; i < num; i++) + ret |= platform_device_register(pdev + i); + goto out; + } + + if ((mxs_device_num + num) > MXS_MAX_DEVICES) + goto out; + mxs_device_num += num; + for (i = 0; i < num; i++) + list_add_tail(&pdev[i].dev.devres_head, + &mxs_device_level[level]); + ret = 0; +out: + mutex_unlock(&device_mutex); + return ret; +} + +int mxs_add_device(struct platform_device *pdev, int level) +{ + return mxs_add_devices(pdev, 1, level); +} + +#if defined(CONFIG_SERIAL_MXS_DUART) || \ + defined(CONFIG_SERIAL_MXS_DUART_MODULE) +static struct platform_device mxs_duart = { + .name = "mxs-duart", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_MXS_DMA_ENGINE) +static struct platform_device mxs_dma[] = { + { + .name = "mxs-dma-apbh", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, + { + .name = "mxs-dma-apbx", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_I2C_MXS) || \ + defined(CONFIG_I2C_MXS_MODULE) +static struct platform_device mxs_i2c[] = { +#if defined(CONFIG_I2C_MXS_SELECT0) + { + .name = "mxs-i2c", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, +#endif +#if defined(CONFIG_I2C_MXS_SELECT1) + { + .name = "mxs-i2c", + .id = 1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, +#endif +}; +#endif + +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) +static struct platform_device gpmi_nfc = { + .name = GPMI_NFC_DRIVER_NAME, + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_MMC_MXS) || \ + defined(CONFIG_MMC_MXS_MODULE) +static struct platform_device mxs_mmc[] = { + { + .name = "mxs-mmc", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, + { + .name = "mxs-mmc", + .id = 1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct platform_device mxs_spi[] = { + { + .name = "mxs-spi", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE) +static struct platform_device mxs_wdt = { + .name = "mxs-wdt", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_FEC) || \ + defined(CONFIG_FEC_MODULE) +static struct platform_device mxs_fec[] = { + { + .name = "fec", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, + { + .name = "fec", + .id = 1, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_FEC_L2SWITCH) +static struct platform_device mxs_l2switch[] = { + { + .name = "mxs-l2switch", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_FB_MXS) || defined(CONFIG_FB_MXS_MODULE) +static struct platform_device mxs_fb = { + .name = "mxs-fb", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_BACKLIGHT_MXS) || \ + defined(CONFIG_BACKLIGHT_MXS_MODULE) +struct platform_device mxs_bl = { + .name = "mxs-bl", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_VIDEO_MXS_PXP) || \ + defined(CONFIG_VIDEO_MXS_PXP_MODULE) +static struct platform_device mxs_pxp = { + .name = "mxs-pxp", + .id = 0, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif + +#if defined(CONFIG_RTC_DRV_MXS) || defined(CONFIG_RTC_DRV_MXS_MODULE) +static struct platform_device mxs_rtc = { + .name = "mxs-rtc", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#ifdef CONFIG_MXS_LRADC +static struct platform_device mxs_lradc = { + .name = "mxs-lradc", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_KEYBOARD_MXS) || defined(CONFIG_KEYBOARD_MXS_MODULE) +static struct platform_device mxs_kbd = { + .name = "mxs-kbd", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_TOUCHSCREEN_MXS) || defined(CONFIG_TOUCHSCREEN_MXS_MODULE) +static struct platform_device mxs_ts = { + .name = "mxs-ts", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_SERIAL_MXS_AUART) || defined(CONFIG_SERIAL_MXS_AUART_MODULE) +static struct platform_device mxs_auart[] = { +#ifdef CONFIG_MXS_AUART0_DEVICE_ENABLE + { + .name = "mxs-auart", + .id = 0, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +#endif +#ifdef CONFIG_MXS_AUART1_DEVICE_ENABLE + { + .name = "mxs-auart", + .id = 1, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +#endif +#ifdef CONFIG_MXS_AUART2_DEVICE_ENABLE + { + .name = "mxs-auart", + .id = 2, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +#endif +#ifdef CONFIG_MXS_AUART3_DEVICE_ENABLE + { + .name = "mxs-auart", + .id = 3, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +#endif +#ifdef CONFIG_MXS_AUART4_DEVICE_ENABLE + { + .name = "mxs-auart", + .id = 4, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, +#endif +}; +#endif + +#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE) +static struct platform_device mxs_led = { + .name = "mxs-leds", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_CAN_FLEXCAN) || \ + defined(CONFIG_CAN_FLEXCAN_MODULE) +static struct platform_device mxs_flexcan[] = { + { + .name = "FlexCAN", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, + { + .name = "FlexCAN", + .id = 1, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_CRYPTO_DEV_DCP) +static struct platform_device mxs_dcp = { + .name = "dcp", + .id = 0, + .dev = { + .release = mxs_nop_release, + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif + +#if defined(CONFIG_BATTERY_MXS) +static struct platform_device mxs_battery = { + .name = "mxs-battery", + .id = 0, + .dev = { + .release = mxs_nop_release, + } , +}; +#endif + +#if defined(CONFIG_SND_SOC_SGTL5000) || \ + defined(CONFIG_SND_SOC_SGTL5000_MODULE) +static struct platform_device mxs_sgtl5000[] = { + { + .name = "mxs-sgtl5000", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_MXS_VIIM) || defined(CONFIG_MXS_VIIM_MODULE) +struct platform_device mxs_viim = { + .name = "mxs_viim", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \ + defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE) +static struct platform_device mxs_spdif[] = { + { + .name = "mxs-spdif", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_SND_MXS_SOC_ADC) || \ + defined(CONFIG_SND_MXS_SOC_ADC_MODULE) +static struct platform_device mxs_adc = { + .name = "mxs-adc-audio", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +static struct platform_device busfreq_device = { + .name = "busfreq", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; + +#ifdef CONFIG_MXS_PERSISTENT +static struct platform_device mxs_persistent = { + .name = "mxs-persistent", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#ifdef CONFIG_MXS_PERFMON +static struct platform_device mxs_perfmon = { + .name = "mxs-perfmon", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +#ifdef CONFIG_FSL_OTP +static struct platform_device otp_device = { + .name = "ocotp", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + +static inline void mxs_init_busfreq(void) +{ + (void)platform_device_register(&busfreq_device); +} + +static struct mxs_dev_lookup dev_lookup[] = { +#if defined(CONFIG_SERIAL_MXS_DUART) || \ + defined(CONFIG_SERIAL_MXS_DUART_MODULE) + { + .name = "mxs-duart", + .size = 1, + .pdev = &mxs_duart, + }, +#endif +#if defined(CONFIG_MXS_DMA_ENGINE) + { + .name = "mxs-dma", + .size = ARRAY_SIZE(mxs_dma), + .pdev = mxs_dma, + }, +#endif + +#if defined(CONFIG_I2C_MXS) || \ + defined(CONFIG_I2C_MXS_MODULE) + { + .name = "mxs-i2c", + .size = ARRAY_SIZE(mxs_i2c), + .pdev = mxs_i2c, + }, +#endif + +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) + { + .name = GPMI_NFC_DRIVER_NAME, + .size = 1, + .pdev = &gpmi_nfc, + }, +#endif + +#if defined(CONFIG_MMC_MXS) || \ + defined(CONFIG_MMC_MXS_MODULE) + { + .name = "mxs-mmc", + .size = ARRAY_SIZE(mxs_mmc), + .pdev = mxs_mmc, + }, +#endif + +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) + { + .name = "mxs-spi", + .size = ARRAY_SIZE(mxs_spi), + .pdev = mxs_spi, + }, +#endif + +#if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE) + { + .name = "mxs-wdt", + .size = 1, + .pdev = &mxs_wdt, + }, +#endif + +#if defined(CONFIG_RTC_DRV_MXS) || defined(CONFIG_RTC_DRV_MXS_MODULE) + { + .name = "mxs-rtc", + .size = 1, + .pdev = &mxs_rtc, + }, +#endif + +#if defined(CONFIG_MXS_PERSISTENT) + { + .name = "mxs-persistent", + .size = 1, + .pdev = &mxs_persistent, + }, +#endif + +#if defined(CONFIG_MXS_PERFMON) + { + .name = "mxs-perfmon", + .size = 1, + .pdev = &mxs_perfmon, + }, +#endif + +#if defined(CONFIG_FSL_OTP) + { + .name = "ocotp", + .size = 1, + .pdev = &otp_device, + }, +#endif + +#if defined(CONFIG_FB_MXS) || defined(CONFIG_FB_MXS_MODULE) + { + .name = "mxs-fb", + .size = 1, + .pdev = &mxs_fb, + }, +#endif +#if defined(CONFIG_BACKLIGHT_MXS) || \ + defined(CONFIG_BACKLIGHT_MXS_MODULE) + { + .name = "mxs-bl", + .size = 1, + .pdev = &mxs_bl, + }, +#endif + +#if defined(CONFIG_VIDEO_MXS_PXP) || \ + defined(CONFIG_VIDEO_MXS_PXP_MODULE) + { + .name = "mxs-pxp", + .size = 1, + .pdev = &mxs_pxp, + }, +#endif + +#if defined(CONFIG_MXS_VIIM) || defined(CONFIG_MXS_VIIM_MODULE) + { + .name = "mxs_viim", + .size = 1, + .pdev = &mxs_viim, + }, +#endif + +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) + { + .name = "mxs-fec", + .size = ARRAY_SIZE(mxs_fec), + .pdev = mxs_fec, + }, +#endif + +#if defined(CONFIG_FEC_L2SWITCH) + { + .name = "mxs-l2switch", + .size = ARRAY_SIZE(mxs_l2switch), + .pdev = mxs_l2switch, + }, +#endif + +#ifdef CONFIG_MXS_LRADC + { + .name = "mxs-lradc", + .size = 1, + .pdev = &mxs_lradc, + }, +#endif + +#if defined(CONFIG_KEYBOARD_MXS) || defined(CONFIG_KEYBOARD_MXS_MODULE) + { + .name = "mxs-kbd", + .size = 1, + .pdev = &mxs_kbd, + }, +#endif + +#if defined(CONFIG_TOUCHSCREEN_MXS) || defined(CONFIG_TOUCHSCREEN_MXS_MODULE) + { + .name = "mxs-ts", + .size = 1, + .pdev = &mxs_ts, + }, +#endif + +#if defined(CONFIG_SERIAL_MXS_AUART) || defined(CONFIG_SERIAL_MXS_AUART_MODULE) + { + .name = "mxs-auart", + .size = ARRAY_SIZE(mxs_auart), + .pdev = mxs_auart, + }, +#endif + +#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE) + { + .name = "mxs-leds", + .size = 1, + .pdev = &mxs_led, + }, +#endif + +#if defined(CONFIG_CAN_FLEXCAN) || \ + defined(CONFIG_CAN_FLEXCAN_MODULE) + { + .name = "FlexCAN", + .size = ARRAY_SIZE(mxs_flexcan), + .pdev = mxs_flexcan, + }, +#endif + +#if defined(CONFIG_CRYPTO_DEV_DCP) + { + .name = "dcp", + .size = 1, + .pdev = &mxs_dcp, + }, +#endif + +#if defined(CONFIG_BATTERY_MXS) + { + .name = "mxs-battery", + .size = 1, + .pdev = &mxs_battery, + }, +#endif + +#if defined(CONFIG_SND_SOC_SGTL5000) || \ + defined(CONFIG_SND_SOC_SGTL5000_MODULE) + { + .name = "mxs-sgtl5000", + .size = ARRAY_SIZE(mxs_sgtl5000), + .pdev = mxs_sgtl5000, + }, +#endif + +#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \ + defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE) + { + .name = "mxs-spdif", + .size = ARRAY_SIZE(mxs_spdif), + .pdev = mxs_spdif, + }, +#endif + +#if defined(CONFIG_SND_MXS_SOC_ADC) || \ + defined(CONFIG_SND_MXS_SOC_ADC_MODULE) + { + .name = "mxs-adc", + .size = 1, + .pdev = &mxs_adc, + }, +#endif + +}; + +struct platform_device *mxs_get_device(char *name, int id) +{ + int i, j; + struct mxs_dev_lookup *lookup; + struct platform_device *pdev = (struct platform_device *)-ENODEV; + if (name == NULL || id < 0 || IS_ERR(name)) + return (struct platform_device *)-EINVAL; + + mutex_lock(&device_mutex); + for (i = 0; i < ARRAY_SIZE(dev_lookup); i++) { + lookup = &dev_lookup[i]; + if (!strcmp(name, lookup->name)) { + if (test_bit(0, &lookup->lock)) { + pdev = (struct platform_device *)-EBUSY; + break; + } + + if (id >= lookup->size) + break; + for (j = 0; j < lookup->size; j++) { + if (id == (lookup->pdev[j]).id) { + pdev = &lookup->pdev[j]; + break; + } + } + break; + } + + } + mutex_unlock(&device_mutex); + return pdev; +} + +struct mxs_dev_lookup *mxs_get_devices(char *name) +{ + int i; + struct mxs_dev_lookup *lookup; + if (name == NULL || IS_ERR(name)) + return (struct mxs_dev_lookup *)-EINVAL; + + mutex_lock(&device_mutex); + for (i = 0; i < ARRAY_SIZE(dev_lookup); i++) { + lookup = &dev_lookup[i]; + if (!strcmp(name, lookup->name)) { + if (test_and_set_bit(0, &lookup->lock)) + lookup = (struct mxs_dev_lookup *)-EBUSY; + mutex_unlock(&device_mutex); + return lookup; + } + + } + mutex_unlock(&device_mutex); + return (struct mxs_dev_lookup *)-ENODEV; +} + +int mxs_device_init(void) +{ + int i, ret = 0; + struct list_head *p, *n; + struct device *dev; + struct platform_device *pdev; + mutex_lock(&device_mutex); + mxs_device_done = 1; + mutex_unlock(&device_mutex); + + for (i = 0; i < ARRAY_SIZE(mxs_device_level); i++) { + list_for_each_safe(p, n, mxs_device_level + i) { + dev = list_entry(p, struct device, devres_head); + list_del(p); + pdev = container_of(dev, struct platform_device, dev); + ret |= platform_device_register(pdev); + } + } + +#if defined(CONFIG_BACKLIGHT_MXS) || \ + defined(CONFIG_BACKLIGHT_MXS_MODULE) + platform_device_register(&mxs_bl); +#endif + + mxs_init_busfreq(); + return ret; +} + +device_initcall(mxs_device_init); diff --git a/arch/arm/plat-mxs/dma-apbh.c b/arch/arm/plat-mxs/dma-apbh.c new file mode 100644 index 000000000000..e7fb96003f6e --- /dev/null +++ b/arch/arm/plat-mxs/dma-apbh.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2009-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/device.h> +#include <mach/dmaengine.h> + +#include <mach/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) +{ +#ifdef CONFIG_ARCH_MX28 + __raw_writel(1 << (chan + BP_APBH_CHANNEL_CTRL_RESET_CHANNEL), + pdev->base + HW_APBH_CHANNEL_CTRL_SET); +#endif + +#ifdef CONFIG_ARCH_MX23 + __raw_writel(1 << (chan + BP_APBH_CTRL0_RESET_CHANNEL), + pdev->base + HW_APBH_CTRL0_SET); +#endif +} + +static void mxs_dma_apbh_freeze(struct mxs_dma_device *pdev, unsigned int chan) +{ +#ifdef CONFIG_ARCH_MX28 + __raw_writel(1 << chan, pdev->base + HW_APBH_CHANNEL_CTRL_SET); +#endif + +#ifdef CONFIG_ARCH_MX23 + __raw_writel(1 << (chan + BP_APBH_CTRL0_FREEZE_CHANNEL), + pdev->base + HW_APBH_CTRL0_SET); +#endif +} + +static void +mxs_dma_apbh_unfreeze(struct mxs_dma_device *pdev, unsigned int chan) +{ +#ifdef CONFIG_ARCH_MX28 + __raw_writel(1 << chan, pdev->base + HW_APBH_CHANNEL_CTRL_CLR); +#endif + +#ifdef CONFIG_ARCH_MX23 + __raw_writel(1 << (chan + BP_APBH_CTRL0_FREEZE_CHANNEL), + pdev->base + HW_APBH_CTRL0_CLR); +#endif + +} + +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 = IO_ADDRESS(res->start); + __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) +{ + 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/plat-mxs/dma-apbx.c b/arch/arm/plat-mxs/dma-apbx.c new file mode 100644 index 000000000000..6d77a6933d98 --- /dev/null +++ b/arch/arm/plat-mxs/dma-apbx.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2009-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/device.h> +#include <mach/dmaengine.h> + +#include "regs-apbx.h" + +static int mxs_dma_apbx_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_APBX_CHn_SEMA(chan)); + sem = (sem & BM_APBX_CHn_SEMA_PHORE) >> BP_APBX_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_APBX_CHn_NXTCMDAR(chan)); + } + sem = pchan->pending_num; + pchan->pending_num = 0; + __raw_writel(BF_APBX_CHn_SEMA_INCREMENT_SEMA(sem), + pdev->base + HW_APBX_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_APBX_CHn_NXTCMDAR(chan)); + __raw_writel(pchan->active_num, pdev->base + HW_APBX_CHn_SEMA(chan)); + return 0; +} + +static void mxs_dma_apbx_disable(struct mxs_dma_chan *pchan, unsigned int chan) +{ + struct mxs_dma_device *pdev = pchan->dma; + __raw_writel(0, pdev->base + HW_APBX_CHn_SEMA(chan)); +} + +static void mxs_dma_apbx_reset(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << (chan + BP_APBX_CHANNEL_CTRL_RESET_CHANNEL), + pdev->base + HW_APBX_CHANNEL_CTRL_SET); +} + +static void mxs_dma_apbx_freeze(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBX_CHANNEL_CTRL_SET); +} + +static void +mxs_dma_apbx_unfreeze(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBX_CHANNEL_CTRL_CLR); +} + +static void mxs_dma_apbx_info(struct mxs_dma_device *pdev, + unsigned int chan, struct mxs_dma_info *info) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBX_CTRL2); + info->status = reg >> chan; + info->buf_addr = __raw_readl(pdev->base + HW_APBX_CHn_BAR(chan)); + reg = __raw_readl(pdev->base + HW_APBX_CHn_CMD(chan)); + info->xfer_count = (reg & BM_APBX_CHn_CMD_XFER_COUNT) >> \ + BP_APBX_CHn_CMD_XFER_COUNT; +} + +static int +mxs_dma_apbx_read_semaphore(struct mxs_dma_device *pdev, unsigned int chan) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBX_CHn_SEMA(chan)); + return (reg & BM_APBX_CHn_SEMA_PHORE) >> BP_APBX_CHn_SEMA_PHORE; +} + +static void +mxs_dma_apbx_enable_irq(struct mxs_dma_device *pdev, + unsigned int chan, int enable) +{ + if (enable) { + __raw_writel(1 << (chan + 16), pdev->base + HW_APBX_CTRL1_SET); + } else { + __raw_writel(1 << (chan + 16), pdev->base + HW_APBX_CTRL1_CLR); + } +} + +static int +mxs_dma_apbx_irq_is_pending(struct mxs_dma_device *pdev, unsigned int chan) +{ + unsigned int reg; + reg = __raw_readl(pdev->base + HW_APBX_CTRL1); + reg |= __raw_readl(pdev->base + HW_APBX_CTRL2); + return reg & (1 << chan); +} + +static void mxs_dma_apbx_ack_irq(struct mxs_dma_device *pdev, unsigned int chan) +{ + __raw_writel(1 << chan, pdev->base + HW_APBX_CTRL1_CLR); + __raw_writel(1 << chan, pdev->base + HW_APBX_CTRL2_CLR); +} + +static struct mxs_dma_device mxs_dma_apbx = { + .name = "mxs-dma-apbx", + .enable = mxs_dma_apbx_enable, + .disable = mxs_dma_apbx_disable, + .reset = mxs_dma_apbx_reset, + .freeze = mxs_dma_apbx_freeze, + .unfreeze = mxs_dma_apbx_unfreeze, + .info = mxs_dma_apbx_info, + .read_semaphore = mxs_dma_apbx_read_semaphore, + .enable_irq = mxs_dma_apbx_enable_irq, + .irq_is_pending = mxs_dma_apbx_irq_is_pending, + .ack_irq = mxs_dma_apbx_ack_irq, +}; + +static int __devinit dma_apbx_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_apbx.base = IO_ADDRESS(res->start); + __raw_writel(BM_APBX_CTRL0_SFTRST, + mxs_dma_apbx.base + HW_APBX_CTRL0_CLR); + for (i = 0; i < 10000; i++) { + if (!(__raw_readl(mxs_dma_apbx.base + HW_APBX_CTRL0_CLR) & + BM_APBX_CTRL0_SFTRST)) + break; + udelay(2); + } + if (i >= 10000) + return -ETIME; + __raw_writel(BM_APBX_CTRL0_CLKGATE, + mxs_dma_apbx.base + HW_APBX_CTRL0_CLR); + + plat = (struct mxs_dma_plat_data *)pdev->dev.platform_data; + if (!plat) + return -ENODEV; + + mxs_dma_apbx.pdev = pdev; + mxs_dma_apbx.chan_base = plat->chan_base; + mxs_dma_apbx.chan_num = plat->chan_num; + platform_set_drvdata(pdev, &mxs_dma_apbx); + return mxs_dma_device_register(&mxs_dma_apbx); +} + +static int __devexit dma_apbx_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver dma_apbx_driver = { + .probe = dma_apbx_probe, + .remove = __devexit_p(dma_apbx_remove), + .driver = { + .name = "mxs-dma-apbx"}, +}; + +static int __init mxs_dma_apbx_init(void) +{ + return platform_driver_register(&dma_apbx_driver); +} + +fs_initcall(mxs_dma_apbx_init); diff --git a/arch/arm/plat-mxs/dmaengine.c b/arch/arm/plat-mxs/dmaengine.c new file mode 100644 index 000000000000..2a41644d2669 --- /dev/null +++ b/arch/arm/plat-mxs/dmaengine.c @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2009-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/dma.h> +#include <mach/dmaengine.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[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 >= 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 >= 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 >= MAX_DMA_CHANNELS)) + return -EINVAL; + pchan = mxs_dma_channels + channel; + if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) + return -EINVAL; + + /* + * neednot mutex lock, this function will be called in irq context. + * The mutex may cause process schedule. + */ + 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 >= 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; + /* + * neednot mutex lock, this function will be called in irq context. + * The mutex may cause process schedule. + */ + 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; + + if (!info) + return -EINVAL; + if ((channel < 0) || (channel >= 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); + 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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); + if (pdesc->cmd.cmd.bits.dec_sem != last->cmd.cmd.bits.dec_sem) { + ret = -EFAULT; + goto out; + } + if (!pdesc->cmd.cmd.bits.dec_sem) { + pdesc->flags &= ~MXS_DMA_DESC_FIRST; + last->flags &= ~MXS_DMA_DESC_LAST; + } + pdesc->cmd.next = last->cmd.next; + 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); +out: + 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 >= 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 >= 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 >= MAX_DMA_CHANNELS) || + ((pdev->chan_base + pdev->chan_num) > 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 >= 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 >= 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) +{ + struct mxs_dma_chan *pchan; + struct mxs_dma_device *pdev; + + if (data == NULL) + return 0; + + pchan = (struct mxs_dma_chan *)data; + pdev = pchan->dma; + if (pdev == NULL) + return 0; + + return seq_printf(file, "%s-channel%-d (%s)\n", + pdev->name, + pchan - mxs_dma_channels, + pchan->name ? pchan->name : "idle"); +} + +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/plat-mxs/gpio.c b/arch/arm/plat-mxs/gpio.c new file mode 100644 index 000000000000..6c67c2bcfc5b --- /dev/null +++ b/arch/arm/plat-mxs/gpio.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2009-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/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/gpio.h> +#include <linux/list.h> +#include <linux/irq.h> + +#include <mach/hardware.h> +#include <mach/pinctrl.h> + +#if MXS_ARCH_NR_GPIOS % PINS_PER_BANK +#error "MXS_ARCH_NR_GPIOS must be multipled of PINS_PER_BANK" +#endif + +static struct mxs_gpio_port *mxs_gpios[MXS_ARCH_NR_GPIOS / PINS_PER_BANK]; + +static inline int mxs_valid_gpio(struct mxs_gpio_port *port) +{ + struct mxs_gpio_chip *chip = port->chip; + + if (port->id >= (MXS_ARCH_NR_GPIOS / PINS_PER_BANK)) + return -EINVAL; + + if (port->irq < 0 && port->child_irq > 0) + return -EINVAL; + if (chip->get == NULL || chip->set == NULL || chip->set_dir == NULL) + return -EINVAL; + if (port->child_irq > 0) { + if (chip->get_irq_stat == NULL) + return -EINVAL; + if (chip->mask_irq == NULL || chip->unmask_irq == NULL) + return -EINVAL; + } + return 0; +} + +static int mxs_gpio_request(struct gpio_chip *chip, unsigned int pin) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + return mxs_request_pin(MXS_PIN_ENCODE(port->id, pin), + PIN_GPIO, GPIO_ID_NAME); +} + +static void mxs_gpio_free(struct gpio_chip *chip, unsigned int pin) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + return mxs_release_pin(MXS_PIN_ENCODE(port->id, pin), GPIO_ID_NAME); +} + +static int mxs_gpio_to_irq(struct gpio_chip *chip, unsigned int index) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + if (port->child_irq < 0) + return -ENXIO; + return port->child_irq + index; +} + +static int mxs_gpio_get(struct gpio_chip *chip, unsigned int index) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + return port->chip->get(port, index); +} + +static void mxs_gpio_set(struct gpio_chip *chip, unsigned int index, int v) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + port->chip->set(port, index, v); +} + +static int mxs_gpio_output(struct gpio_chip *chip, unsigned int index, int v) +{ + int ret; + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + ret = port->chip->set_dir(port, index, 0); + if (!ret) + port->chip->set(port, index, v); + return ret; +} + +static int mxs_gpio_input(struct gpio_chip *chip, unsigned int index) +{ + struct mxs_gpio_port *port; + port = container_of(chip, struct mxs_gpio_port, port); + return port->chip->set_dir(port, index, 1); +} + +static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) +{ + struct mxs_gpio_port *port = get_irq_data(irq); + int gpio_irq = port->child_irq; + u32 irq_stat = port->chip->get_irq_stat(port); + + desc->chip->mask(irq); + + while (irq_stat) { + if (irq_stat & 1) + generic_handle_irq(gpio_irq); + gpio_irq++; + irq_stat >>= 1; + } + + desc->chip->ack(irq); + desc->chip->unmask(irq); +} + +static int mxs_gpio_set_irq_type(unsigned int irq, unsigned int type) +{ + struct mxs_gpio_port *port; + unsigned int gpio = irq_to_gpio(irq); + port = mxs_gpios[GPIO_TO_BANK(gpio)]; + if (port->child_irq < 0) + return -ENXIO; + if (port->chip->set_irq_type) + return port->chip->set_irq_type(port, GPIO_TO_PINS(gpio), type); + return -ENODEV; +} + +static void mxs_gpio_ack_irq(unsigned int irq) +{ + struct mxs_gpio_port *port; + unsigned int gpio = irq_to_gpio(irq); + port = mxs_gpios[GPIO_TO_BANK(gpio)]; + if (port->child_irq < 0) + return; + if (port->chip->ack_irq) + port->chip->ack_irq(port, GPIO_TO_PINS(gpio)); +} + +static void mxs_gpio_mask_irq(unsigned int irq) +{ + struct mxs_gpio_port *port; + unsigned int gpio = irq_to_gpio(irq); + port = mxs_gpios[GPIO_TO_BANK(gpio)]; + if (port->child_irq < 0) + return; + port->chip->mask_irq(port, GPIO_TO_PINS(gpio)); +} + +static void mxs_gpio_unmask_irq(unsigned int irq) +{ + struct mxs_gpio_port *port; + unsigned int gpio = irq_to_gpio(irq); + port = mxs_gpios[GPIO_TO_BANK(gpio)]; + if (port->child_irq < 0) + return; + port->chip->unmask_irq(port, GPIO_TO_PINS(gpio)); +} + +static struct irq_chip gpio_irq_chip = { + .ack = mxs_gpio_ack_irq, + .mask = mxs_gpio_mask_irq, + .unmask = mxs_gpio_unmask_irq, + .enable = mxs_gpio_unmask_irq, + .disable = mxs_gpio_mask_irq, + .set_type = mxs_gpio_set_irq_type, +}; + +int __init mxs_add_gpio_port(struct mxs_gpio_port *port) +{ + int i, ret; + if (!(port && port->chip)) + return -EINVAL; + + if (mxs_valid_gpio(port)) + return -EINVAL; + + if (mxs_gpios[port->id]) + return -EBUSY; + + mxs_gpios[port->id] = port; + + port->port.base = port->id * PINS_PER_BANK; + port->port.ngpio = PINS_PER_BANK; + port->port.can_sleep = 1; + port->port.exported = 1; + port->port.to_irq = mxs_gpio_to_irq; + port->port.direction_input = mxs_gpio_input; + port->port.direction_output = mxs_gpio_output; + port->port.get = mxs_gpio_get; + port->port.set = mxs_gpio_set; + port->port.request = mxs_gpio_request; + port->port.free = mxs_gpio_free; + port->port.owner = THIS_MODULE; + ret = gpiochip_add(&port->port); + if (ret < 0) + return ret; + + if (port->child_irq < 0) + return 0; + + for (i = 0; i < PINS_PER_BANK; i++) { + gpio_irq_chip.mask(port->child_irq + i); + set_irq_chip(port->child_irq + i, &gpio_irq_chip); + set_irq_handler(port->child_irq + i, handle_level_irq); + set_irq_flags(port->child_irq + i, IRQF_VALID); + } + set_irq_chained_handler(port->irq, mxs_gpio_irq_handler); + set_irq_data(port->irq, port); + return ret; +}; diff --git a/arch/arm/plat-mxs/icoll.c b/arch/arm/plat-mxs/icoll.c new file mode 100644 index 000000000000..1e0b55bd26a9 --- /dev/null +++ b/arch/arm/plat-mxs/icoll.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2009-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/irq.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <mach/device.h> +#include <mach/irqs.h> + +#include "regs-icoll.h" + +void __iomem *g_icoll_base; + +/* + * IRQ handling + */ +static void icoll_ack_irq(unsigned int irq) +{ + __raw_writel(0, g_icoll_base + HW_ICOLL_VECTOR); + + /* ACK current interrupt */ + __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0, + g_icoll_base + HW_ICOLL_LEVELACK); + + /* Barrier */ + (void)__raw_readl(g_icoll_base + HW_ICOLL_STAT); +} + +static void icoll_mask_irq(unsigned int irq) +{ + __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, + g_icoll_base + HW_ICOLL_INTERRUPTn_CLR(irq)); +} + +static void icoll_unmask_irq(unsigned int irq) +{ + __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, + g_icoll_base + HW_ICOLL_INTERRUPTn_SET(irq)); +} + +static int icoll_set_wake_irq(unsigned int irq, unsigned int enabled) +{ + return 0; +} + +static struct irq_chip icoll_chip = { + .ack = icoll_ack_irq, + .mask = icoll_mask_irq, + .unmask = icoll_unmask_irq, + .set_wake = icoll_set_wake_irq, +}; + +void __init avic_init_irq(void __iomem *base, int nr_irqs) +{ + int i; + g_icoll_base = base; + + /* Reset icoll */ + __raw_writel(BM_ICOLL_CTRL_SFTRST, g_icoll_base + HW_ICOLL_CTRL_CLR); + + for (i = 0; i < 100000; i++) { + if (!(__raw_readl(g_icoll_base + HW_ICOLL_CTRL) & + BM_ICOLL_CTRL_SFTRST)) + break; + udelay(2); + } + if (i >= 100000) { + printk(KERN_ERR "%s:%d timeout when enableing\n", + __func__, __LINE__); + return; + } + __raw_writel(BM_ICOLL_CTRL_CLKGATE, g_icoll_base + HW_ICOLL_CTRL_CLR); + + for (i = 0; i < nr_irqs; i++) { + __raw_writel(0, g_icoll_base + HW_ICOLL_INTERRUPTn(i)); + set_irq_chip(i, &icoll_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + + __raw_writel(BF_ICOLL_LEVELACK_IRQLEVELACK + (BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0), + g_icoll_base + HW_ICOLL_LEVELACK); + __raw_writel(BF_ICOLL_LEVELACK_IRQLEVELACK + (BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL1), + g_icoll_base + HW_ICOLL_LEVELACK); + __raw_writel(BF_ICOLL_LEVELACK_IRQLEVELACK + (BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL2), + g_icoll_base + HW_ICOLL_LEVELACK); + __raw_writel(BF_ICOLL_LEVELACK_IRQLEVELACK + (BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL3), + g_icoll_base + HW_ICOLL_LEVELACK); + + __raw_writel(0, g_icoll_base + HW_ICOLL_VECTOR); + /* Barrier */ + (void)__raw_readl(g_icoll_base + HW_ICOLL_STAT); +} + +void mxs_set_irq_fiq(unsigned int irq, unsigned int type) +{ + if (type == 0) + __raw_writel(BM_ICOLL_INTERRUPTn_ENFIQ, + g_icoll_base + + HW_ICOLL_INTERRUPTn_CLR(irq)); + else + __raw_writel(BM_ICOLL_INTERRUPTn_ENFIQ, + g_icoll_base + + HW_ICOLL_INTERRUPTn_SET(irq)); +} +EXPORT_SYMBOL(mxs_set_irq_fiq); + +void mxs_enable_fiq_functionality(int enable) +{ + if (enable) + __raw_writel(BM_ICOLL_CTRL_FIQ_FINAL_ENABLE, + g_icoll_base + HW_ICOLL_CTRL_SET); + else + __raw_writel(BM_ICOLL_CTRL_FIQ_FINAL_ENABLE, + g_icoll_base + HW_ICOLL_CTRL_CLR); + +} +EXPORT_SYMBOL(mxs_enable_fiq_functionality); + diff --git a/arch/arm/plat-mxs/include/mach/arc_otg.h b/arch/arm/plat-mxs/include/mach/arc_otg.h new file mode 100644 index 000000000000..5ba352f90fbe --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/arc_otg.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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_MXC_ARC_OTG_H__ +#define __ASM_ARCH_MXC_ARC_OTG_H__ + +#include "../../regs-usbphy.h" +#if defined(CONFIG_USB_STATIC_IRAM) \ + || defined(CONFIG_USB_STATIC_IRAM_PPH) +#define USB_IRAM_SIZE SZ_8K +#else +#define USB_IRAM_SIZE 0 +#endif + +#define OTG_BASE_ADDR USBCTRL0_PHYS_ADDR +#define USB_OTGREGS_BASE (OTG_BASE_ADDR + 0x000) +/* + * OTG registers + */ +#define UOG_ID (0x00) /* Host ID */ +#define UOG_HWGENERAL (0x04) /* Host General */ +#define UOG_HWHOST (0x08) /* Host h/w params */ +#define UOG_HWTXBUF (0x10) /* TX buffer h/w params */ +#define UOG_HWRXBUF (0x14) /* RX buffer h/w params */ +#define UOG_CAPLENGTH (0x100) /* Capability register length */ +#define UOG_HCIVERSION (0x102) /* Host Interface version */ +#define UOG_HCSPARAMS (0x104) /* Host control structural params */ +#define UOG_HCCPARAMS (0x108) /* control capability params */ +#define UOG_DCIVERSION (0x120) /* device interface version */ +/* start EHCI registers: */ +#define UOG_USBCMD (0x140) /* USB command register */ +#define UOG_USBSTS (0x144) /* USB status register */ +#define UOG_USBINTR (0x148) /* interrupt enable register */ +#define UOG_FRINDEX (0x14c) /* USB frame index */ +/* segment (0x150) addr bits 63:32 if needed */ +#define UOG_PERIODICLISTBASE (0x154) /* host crtlr frame list base addr */ +#define UOG_DEVICEADDR (0x154) /* device crtlr device address */ +#define UOG_ASYNCLISTADDR (0x158) /* host ctrlr next async addr */ +#define UOG_EPLISTADDR (0x158) /* device ctrlr endpoint list addr */ +#define UOG_BURSTSIZE (0x160) /* host ctrlr embedded TT + async buf status */ +#define UOG_TXFILLTUNING (0x164) /* TX FIFO fill tuning */ +#define UOG_ULPIVIEW (0x170) /* ULPI viewport */ +#define UOG_CFGFLAG (0x180) /* configflag (supports HS) */ +#define UOG_PORTSC1 (0x184) /* port status and control */ +/* end EHCI registers: */ +#define UOG_OTGSC (0x1a4) /* OTG status and control */ +#define UOG_USBMODE (0x1a8) /* USB device mode */ +#define UOG_ENDPTSETUPSTAT (0x1ac) /* endpoint setup status */ +#define UOG_ENDPTPRIME (0x1b0) /* endpoint initialization */ +#define UOG_ENDPTFLUSH (0x1b4) /* endpoint de-initialize */ +#define UOG_ENDPTSTAT (0x1b8) /* endpoint status */ +#define UOG_ENDPTCOMPLETE (0x1bc) /* endpoint complete */ +#define UOG_EPCTRL0 (0x1c0) /* endpoint control0 */ +/* + * register bits + */ + +/* x_PORTSCx */ +#define PORTSC_PTS_MASK (3 << 30) /* parallel xcvr mask */ +#define PORTSC_PTS_UTMI (0 << 30) /* UTMI/UTMI+ */ +#define PORTSC_PTS_PHILIPS (1 << 30) /* Philips classic */ +#define PORTSC_PTS_ULPI (2 << 30) /* ULPI */ +#define PORTSC_PTS_SERIAL (3 << 30) /* serial */ +#define PORTSC_STS (1 << 29) /* serial xcvr select */ +#define PORTSC_PTW (1 << 28) /* UTMI width */ +#define PORTSC_PHCD (1 << 23) /* Low Power Suspend */ +#define PORTSC_PORT_POWER (1 << 12) /* port power */ +#define PORTSC_LS_MASK (3 << 10) /* Line State mask */ +#define PORTSC_LS_SE0 (0 << 10) /* SE0 */ +#define PORTSC_LS_K_STATE (1 << 10) /* K-state */ +#define PORTSC_LS_J_STATE (2 << 10) /* J-state */ +#define PORTSC_PORT_RESET (1 << 8) /* Port reset */ +#define PORTSC_PORT_SUSPEND (1 << 7) /* Suspend */ +#define PORTSC_PORT_FORCE_RESUME (1 << 6) /* Force port resume */ +#define PORTSC_OVER_CURRENT_CHG (1 << 5) /* over current change */ +#define PORTSC_OVER_CURRENT_ACT (1 << 4) /* over currrent active */ +#define PORTSC_PORT_EN_DIS_CHANGE (1 << 3) /* port change */ +#define PORTSC_PORT_ENABLE (1 << 2) /* port enabled */ +#define PORTSC_CONNECT_STATUS_CHANGE (1 << 1) /* connect status change */ +#define PORTSC_CURRENT_CONNECT_STATUS (1 << 0) /* current connect status */ + +#define PORTSC_W1C_BITS \ + (PORTSC_CONNECT_STATUS_CHANGE | \ + PORTSC_PORT_EN_DIS_CHANGE | \ + PORTSC_OVER_CURRENT_CHG) + +/* UOG_OTGSC Register Bits */ +/* control bits: */ +#define OTGSC_CTRL_VBUS_DISCHARGE (1 << 0) +#define OTGSC_CTRL_VBUS_CHARGE (1 << 1) +/* controls DM pulldown */ +#define OTGSC_CTRL_OTG_TERM (1 << 3) +#define OTGSC_CTRL_DATA_PULSING (1 << 4) +#define OTGSC_CTRL_USB_ID_PU (1 << 5) +/* current status: (R/O) */ +/* 0=A-device 1=B-device */ +#define OTGSC_STS_USB_ID (1 << 8) +#define OTGSC_STS_A_VBUS_VALID (1 << 9) +#define OTGSC_STS_A_SESSION_VALID (1 << 10) +#define OTGSC_STS_B_SESSION_VALID (1 << 11) +#define OTGSC_STS_B_SESSION_END (1 << 12) +#define OTGSC_STS_1ms_TIMER (1 << 13) +#define OTGSC_STS_DATA_PULSE (1 << 14) +/* interrupt status: (write to clear) */ +#define OTGSC_IS_MASK (0x7f << 16) +#define OTGSC_IS_USB_ID (1 << 16) +#define OTGSC_IS_A_VBUS_VALID (1 << 17) +#define OTGSC_IS_A_SESSION_VALID (1 << 18) +#define OTGSC_IS_B_SESSION_VALID (1 << 19) +#define OTGSC_IS_B_SESSION_END (1 << 20) +#define OTGSC_IS_1ms_TIMER (1 << 21) +#define OTGSC_IS_DATA_PULSE (1 << 22) +/* interrupt enables: */ +#define OTGSC_IE_MASK (0x7f << 24) +#define OTGSC_IE_USB_ID (1 << 24) +#define OTGSC_IE_A_VBUS_VALID (1 << 25) +#define OTGSC_IE_A_SESSION_VALID (1 << 26) +#define OTGSC_IE_B_SESSION_VALID (1 << 27) +#define OTGSC_IE_B_SESSION_END (1 << 28) +#define OTGSC_IE_1ms_TIMER (1 << 29) +#define OTGSC_IE_DATA_PULSE (1 << 30) + +#if 1 /* FIXME these here for compatibility between my names and Leo's */ +/* OTG interrupt enable bit masks */ +#define OTGSC_INTERRUPT_ENABLE_BITS_MASK OTGSC_IE_MASK +#define OTGSC_INTSTS_MASK OTGSC_IS_MASK + +/* OTG interrupt status bit masks */ +#define OTGSC_INTERRUPT_STATUS_BITS_MASK OTGSC_IS_MASK +#endif + +/* x_USBMODE */ +#define USBMODE_SLOM (1 << 3) /* setup lockout mode */ +#define USBMODE_ES (1 << 2) /* (big) endian select */ +#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */ +#define USBMODE_CM_HOST (3 << 0) /* host */ +#define USBMODE_CM_DEVICE (2 << 0) /* device */ +#define USBMODE_CM_reserved (1 << 0) /* reserved */ + +/* USBCMD */ +#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ +#define UCMD_RESET (1 << 1) /* controller reset */ +#define UCMD_ITC_NO_THRESHOLD (~(0xff << 16)) /* Interrupt Threshold */ + +/* OTG_MIRROR */ +#define OTGM_SESEND (1 << 4) /* B device session end */ +#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */ +#define OTGM_BSESVLD (1 << 2) /* B session Valid */ +#define OTGM_ASESVLD (1 << 1) /* A session Valid */ +#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */ + /* 1=high: Operate as B-device */ + /* 0=low : Operate as A-device */ + +#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */ + +extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata); +#endif diff --git a/arch/arm/plat-mxs/include/mach/bus_freq.h b/arch/arm/plat-mxs/include/mach/bus_freq.h new file mode 100644 index 000000000000..0c41cd2205ff --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/bus_freq.h @@ -0,0 +1,46 @@ +/* + * 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 BUS_FREQ_H__ +#define BUS_FREQ_H__ + +#define VERY_HI_RATE 2000000000 +#define LCD_ON_CPU_FREQ_KHZ 261818 +#define OPERATION_WP_SUPPORTED 6 + +struct profile { + int cpu; + int ahb; + int emi; + int ss; + int vddd; + int vddd_bo; + int cur; + int vddio; + int vdda; + u16 xbus; + /* map of the upper 16 bits of HW_CLKCTRL_HBUS register */ + u16 h_autoslow_flags; +}; + +/* map of the upper 16 bits of HW_CLKCTRL_HBUS register */ +int is_hclk_autoslow_ok(void); + +extern int timing_ctrl_rams(int ss); + +#endif diff --git a/arch/arm/plat-mxs/include/mach/clkdev.h b/arch/arm/plat-mxs/include/mach/clkdev.h new file mode 100644 index 000000000000..d6a82c8d5782 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/clkdev.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009-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_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +extern int __clk_get(struct clk *clk); +extern void __clk_put(struct clk *clk); + +#endif diff --git a/arch/arm/plat-mxs/include/mach/clock.h b/arch/arm/plat-mxs/include/mach/clock.h new file mode 100644 index 000000000000..b506468976b5 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/clock.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_CLOCK_H +#define __ASM_ARM_ARCH_CLOCK_H + +#ifndef __ASSEMBLER__ + +#include <linux/list.h> +#include <asm/clkdev.h> + +struct clk { + int id; + struct clk *parent; + struct clk *secondary; + unsigned long flags; + + int ref; + unsigned int scale_bits; + unsigned int enable_bits; + unsigned int bypass_bits; + unsigned int busy_bits; + unsigned int xtal_busy_bits; + + unsigned int wait:1; + unsigned int invert:1; + + void __iomem *enable_reg; + void __iomem *scale_reg; + void __iomem *bypass_reg; + void __iomem *busy_reg; + + /* + * Function ptr to set the clock to a new rate. The rate must match a + * supported rate returned from round_rate. Leave blank if clock is not + * programmable + */ + int (*set_rate) (struct clk *, unsigned long); + /* + * Function ptr to get the clock rate. + */ + unsigned long (*get_rate) (struct clk *); + /* + * Function ptr to round the requested clock rate to the nearest + * supported rate that is less than or equal to the requested rate. + */ + unsigned long (*round_rate) (struct clk *, unsigned long); + /* + * Function ptr to enable the clock. Leave blank if clock can not + * be gated. + */ + int (*enable) (struct clk *); + /* + * Function ptr to disable the clock. Leave blank if clock can not + * be gated. + */ + void (*disable) (struct clk *); + /* Function ptr to set the parent clock of the clock. */ + int (*set_parent) (struct clk *, struct clk *); + + /* Function ptr to change the parent clock depending + * the system configuration at that time. Will only + * change the parent clock if the ref count is 0 (the clock + * is not being used) + */ + int (*set_sys_dependent_parent) (struct clk *); + +}; + +int clk_get_usecount(struct clk *clk); +extern int clk_register(struct clk_lookup *lookup); +extern void clk_unregister(struct clk_lookup *lookup); + +bool clk_enable_h_autoslow(bool enable); +void clk_set_h_autoslow_flags(u16 mask); +void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool), + void (*set_func)(u16)); + +struct mxs_emi_scaling_data { + u32 emi_div; + u32 frac_div; + u32 cur_freq; + u32 new_freq; +}; + + + +#ifdef CONFIG_MXS_RAM_FREQ_SCALING +extern int mxs_ram_freq_scale(struct mxs_emi_scaling_data *); +extern u32 mxs_ram_funcs_sz; +#else +static inline int mxs_ram_freq_scale(struct mxs_emi_scaling_data *p) +{ +} +static u32 mxs_ram_funcs_sz; +#endif + +/* Clock flags */ +/* 0 ~ 16 attribute flags */ +#define ALWAYS_ENABLED (1 << 0) /* Clock cannot be disabled */ +#define RATE_FIXED (1 << 1) /* Fixed clock rate */ +#define CPU_FREQ_TRIG_UPDATE (1 << 2) /* CPUFREQ trig update */ + +/* 16 ~ 23 reservied */ +/* 24 ~ 31 run time flags */ + +#define CLK_REF_UNIT 0x00010000 +#define CLK_REF_LIMIT 0xFFFF0000 +#define CLK_EN_MASK 0x0000FFFF +#endif /* __ASSEMBLER__ */ + +#endif diff --git a/arch/arm/plat-mxs/include/mach/ddi_bc.h b/arch/arm/plat-mxs/include/mach/ddi_bc.h new file mode 100644 index 000000000000..21ca9217cdaa --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/ddi_bc.h @@ -0,0 +1,715 @@ +/* + * 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 + */ + +#ifndef _DDI_BC_H +#define _DDI_BC_H + +#include <linux/types.h> + +#define DDI_BC_MAX_RESTART_CYCLES 100 + +#define DDI_BC_LIION_CHARGING_VOLTAGE 4200 +#define DDI_BC_ALKALINE_NIMH_CHARGING_VOLTAGE 1750 + +/* brief Defines battery charger states. */ +typedef enum _ddi_bc_State { + /* brief TBD */ + DDI_BC_STATE_UNINITIALIZED = 0, + /* brief TBD */ + DDI_BC_STATE_BROKEN = 1, + /* brief TBD */ + DDI_BC_STATE_DISABLED = 2, + /* brief TBD */ + DDI_BC_STATE_WAITING_TO_CHARGE = 3, + /* brief TBD */ + DDI_BC_STATE_CONDITIONING = 4, + /* brief TBD */ + DDI_BC_STATE_CHARGING = 5, + /* brief TBD */ + DDI_BC_STATE_TOPPING_OFF = 6, + /* brief TBD */ + DDI_BC_STATE_DCDC_MODE_WAITING_TO_CHARGE = 7, + +} ddi_bc_State_t; + +typedef enum _ddi_bc_BrokenReason { + /* brief TBD */ + DDI_BC_BROKEN_UNINITIALIZED = 0, + /* brief TBD */ + DDI_BC_BROKEN_CHARGING_TIMEOUT = 1, + /* brief TBD */ + DDI_BC_BROKEN_FORCED_BY_APPLICATION = 2, + /* brief TBD */ + DDI_BC_BROKEN_EXTERNAL_BATTERY_VOLTAGE_DETECTED = 3, + /* brief TBD */ + DDI_BC_BROKEN_NO_BATTERY_DETECTED = 4, + +} ddi_bc_BrokenReason_t; + +/* brief Defines the battery charger configuration. */ +typedef struct _ddi_bc_Cfg { + /* brief Units in milliseconds. */ + /* */ + /* This field configures the expected period between calls to */ + /* ddi_bc_StateMachine. If die temperature monitoring is */ + /* enabled, then the data sheet recommends the period be around */ + /* 100ms or less. */ + /* */ + /* Note that this period defines the minimum time resolution of */ + /* the battery charger. */ + + uint32_t u32StateMachinePeriod; + + /* brief Units in mA/s. */ + /* */ + /* This field configures the slope of the current ramp. Any */ + /* time the battery charger increases its current draw, it will */ + /* ramp up the current no faster than this rate. */ + /* */ + /* Note that the minimum time resolution of the battery charger */ + /* is the configured period between calls to advance the state */ + /* machine. Also, the hardware has a minimum current resolution */ + /* of 10mA. If the given ramp slope cannot be expressed */ + /* exactly, then the largest expressible smaller slope will be */ + /* the result. If the actual period between calls to */ + /* ddi_bc_StateMachine is irregular, the current may ramp faster */ + /* than indicated. */ + + uint16_t u16CurrentRampSlope; + + /* brief Units in millivolts. */ + /* */ + /* This field configures the threshold conditioning voltage. If */ + /* the battery's voltage is below this value, it will be */ + /* conditioned until its voltage rises above the maximum */ + /* conditioning voltage. After that, the battery will be */ + /* charged normally. */ + /* */ + /* Note that the hardware has a minimum resolution of 8mV. If */ + /* the given voltage cannot be expressed exactly, then the */ + /* smallest expressible larger value will be used. */ + + uint16_t u16ConditioningThresholdVoltage; + + /* brief Units in millivolts. */ + /* */ + /* This field configures the maximum conditioning voltage. If */ + /* the battery charger is conditioning a battery, normal */ + /* charging begins when the voltage rises above this value. */ + /* */ + /* This value should be slightly higher than the threshold */ + /* conditioning voltage because it is measured while a */ + /* conditioning current is actually flowing to the battery. */ + /* With a conditioning current of 0.1C, reasonable values for */ + /* the threshold and maximum conditioning voltages are 2.9V */ + /* and 3.0V respectively. */ + /* */ + /* Note that the hardware has a minimum resolution of 8mV. If */ + /* the given voltage cannot be expressed exactly, then the */ + /* smallest expressible larger value will be used. */ + + uint16_t u16ConditioningMaxVoltage; + + /* brief Units in milliamps. */ + /* */ + /* This field configures the maximum conditioning current. */ + /* This is the maximum current that will be offered to a */ + /* battery while it is being conditioned. A typical value is */ + /* 0.1C. */ + /* */ + /* Note that the hardware has a minimum resolution of 10mA */ + /* (see the data sheet for details). If the given current */ + /* cannot be expressed exactly, then the largest expressible */ + /* smaller value will be used. */ + + uint16_t u16ConditioningCurrent; + + /* brief Units in milliseconds. */ + /* */ + /* This field configures the conditioning time-out. This is */ + /* the maximum amount of time that a battery will be */ + /* conditioned before the battery charger declares it to be */ + /* broken. */ + /* */ + /* Note that the minimum time resolution of the battery */ + /* charger is the configured period between calls to advance */ + /* the state machine. If the given time-out cannot be */ + /* expressed exactly, then the shortest expressible longer */ + /* value will be used. */ + + uint32_t u32ConditioningTimeout; + + /* brief Units in millivolts. */ + /* */ + /* This field configures the final charging voltage. At this */ + /* writing, only two values are permitted: 4100 or 4200. */ + + uint16_t u16ChargingVoltage; + + /* brief Units in milliamps. */ + /* */ + /* This field configures the maximum current offered to a */ + /* charging battery. */ + /* */ + /* Note that the hardware has a minimum resolution of 10mA */ + /* (see the data sheet for details). If the given current */ + /* cannot be expressed exactly, then the largest expressible */ + /* smaller value will be used. */ + + uint16_t u16ChargingCurrent; + + /* brief Units in milliamps. */ + /* */ + /* This field configures the current flow below which a */ + /* charging battery is regarded as fully charged (typical */ + /* 0.1C). At this point, the battery will be topped off. */ + /* */ + /* Note that the hardware has a minimum resolution of 10mA */ + /* (see the data sheet for details). If the given current */ + /* cannot be expressed exactly, then the largest expressible */ + /* smaller value will be used. */ + + uint16_t u16ChargingThresholdCurrent; + + /* brief Units in milliamps. */ + /* */ + /* When charging while the DCDC converter's are enabled, the charger */ + /* is suppling current to both the battery and the Vbat input of the */ + /* DCDC converter. Once the total battery charger current falls */ + /* below this level, the charger will then stop charging until the */ + /* the battery voltage reaches the BC_LOW_DCDCMODE_BATTERY_VOLTAGE */ + /* threshold or until the DCDCs are no longer enabled. */ + /* */ + /* Typically, this value should be left at 180 to avoid the risk */ + /* of topping off the battery too long in DCDC mode and avoid */ + /* exceeding the BC_CHARGING_TIMEOUT time which would put the charger */ + /* driver in the broken state and completely disable charging. */ + /* */ + /* Note that the hardware has a minimum resolution of 10mA */ + /* (see the data sheet for details). If the given current */ + /* cannot be expressed exactly, then the largest expressible */ + /* smaller value will be used. */ + uint16_t u16DdcdModeChargingThresholdCurrent; + + /* brief Units in milliseconds. */ + /* */ + /* This field configures the charging time-out. This is the */ + /* maximum amount of time that a battery will be charged */ + /* before the battery charger declares it to be broken. */ + /* */ + /* Note that the minimum time resolution of the battery */ + /* charger is the configured period between calls to advance */ + /* the state machine. If the given time-out cannot be */ + /* expressed exactly, then the shortest expressible longer */ + /* value will be used. */ + + uint32_t u32ChargingTimeout; + + /* brief Units in milliseconds. */ + /* */ + /* This field configures the top-off period. This is the */ + /* amount of time a battery will be held in the Topping Off */ + /* state before it is declared fully charged. */ + /* */ + /* Note that the minimum time resolution of the battery */ + /* charger is the configured period between calls to advance */ + /* the state machine. If the given time-out cannot be */ + /* expressed exactly, then the shortest expressible longer */ + /* value will be used. */ + + uint32_t u32TopOffPeriod; + + /* brief Units in milliseconds. */ + /* */ + /* This field configures the top-off period when the DCDC */ + /* converters are enabled. To avoid topping off the LiIon */ + /* battery too long and reducing it's long term capacity, */ + /* This time should be kept failry short. */ + /* */ + /* Note that the minimum time resolution of the battery */ + /* charger is the configured period between calls to advance */ + /* the state machine. If the given time-out cannot be */ + /* expressed exactly, then the shortest expressible longer */ + /* value will be used. */ + uint32_t u32DcdcModeTopOffPeriod; + + /* brief Causes the battery charger to use an externally generated bias current */ + /* */ + /* If cleared, this causes the battery charger to use an */ + /* externally generated bias current, which is expected to be */ + /* quite precise. Otherwise, the battery charger will */ + /* generate a lesser-quality bias current internally. */ + + uint8_t useInternalBias:1; + + /* brief Indicates that the battery charger is to monitor the die temperature. */ + /* */ + /* If set, this field indicates that the battery charger is to */ + /* monitor the die temperature. See below for fields that */ + /* configure the details. */ + + uint8_t monitorDieTemp:1; + + /* brief Indicates that the battery charger is to monitor the battery temperature. */ + /* */ + /* If set, this field indicates that the battery charger is to */ + /* monitor the battery temperature. See below for fields that */ + /* configure the details. */ + + uint8_t monitorBatteryTemp:1; + + /* brief Units in degrees centigrade. */ + /* */ + /* Note that the hardware reports die temperature in ranges of */ + /* 10 degree resolution minimum (see the data sheet for */ + /* details). If the battery charger is monitoring the die */ + /* temperature, and it rises to a range that includes a */ + /* temperature greater than or equal to this value, the */ + /* charging current will be clamped to the safe current. */ + + int8_t u8DieTempHigh; + + /* brief Units in degrees centigrade. */ + /* */ + /* Note that the hardware reports die temperature in ranges of */ + /* 10 degrees minimum (see the data sheet for details). If the */ + /* charging current is being clamped because of a high die */ + /* temperature, and it falls to a range that doesn't include a */ + /* temperatures greater than or equal to this value, the */ + /* charging current clamp will be released. */ + + int8_t u8DieTempLow; + + /* brief Units in milliamps. */ + /* */ + /* If the battery charger detects a high die temperature, it */ + /* will clamp the charging current at or below this value. */ + + uint16_t u16DieTempSafeCurrent; + + /* brief If the battery charger is monitoring the battery */ + /* temperature, this field indicates the LRADC channel to */ + /* read. */ + + uint8_t u8BatteryTempChannel; + + /* brief If the battery charger is monitoring the battery */ + /* temperature, and it rises to a measurement greater than or */ + /* equal to this value, the charging current will be clamped */ + /* to the corresponding safe current. */ + + uint16_t u16BatteryTempHigh; + + /* brief If the charging current is being clamped because of a high */ + /* battery temperature, and it falls below this value, the */ + /* charging current clamp will be released. */ + + uint16_t u16BatteryTempLow; + + /* brief Units in milliamps. */ + /* */ + /* If the battery charger detects a high battery temperature, */ + /* it will clamp the charging current at or below this value. */ + + uint16_t u16BatteryTempSafeCurrent; + + /* brief Units in millivolts. */ + /* */ + /* In the WaitingToCharge state, if we are in DCDC */ + /* operating modes, if the battery voltage measurement */ + /* is below this value, we immediately proceed with charging. */ + /* the low criteria for this value is that it must be high */ + /* to not risk the battery voltage getting too low. The */ + /* upper criteria is that you do not want the IR voltage */ + /* drop under heavy loads to make you start charging too soon */ + /* because the goal in DCDC operating mode is to not be constantly */ + /* topping off the battery which can shorten its life */ + + uint16_t u16LowDcdcBatteryVoltage_mv; + + uint32_t u32StateMachineNonChargingPeriod; +} ddi_bc_Cfg_t; + +/* Status returned by Battery Charger functions. */ + +typedef enum _ddi_bc_Status { + /* brief TBD */ + DDI_BC_STATUS_SUCCESS = 0, + /* brief TBD */ + DDI_BC_STATUS_HARDWARE_DISABLED, + /* brief TBD */ + DDI_BC_STATUS_BAD_BATTERY_MODE, + /* brief TBD */ + DDI_BC_STATUS_CLOCK_GATE_CLOSED, + /* brief TBD */ + DDI_BC_STATUS_NOT_INITIALIZED, + /* brief TBD */ + DDI_BC_STATUS_ALREADY_INITIALIZED, + /* brief TBD */ + DDI_BC_STATUS_BROKEN, + /* brief TBD */ + DDI_BC_STATUS_NOT_BROKEN, + /* brief TBD */ + DDI_BC_STATUS_NOT_DISABLED, + /* brief TBD */ + DDI_BC_STATUS_BAD_ARGUMENT, + /* brief TBD */ + DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL, + /* brief TBD */ + DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE, +} ddi_bc_Status_t; + + +/* BCM Event Codes */ + +/* These are the codes that might be published to PMI Subscribers. */ + + +#define DDI_BC_EVENT_GROUP (11<<10) + +/* brief TBD */ +/* todo [PUBS] Add definition(s)... */ +typedef enum { + /* Use the error code group value to make events unique for the EOI */ + /* brief TBD */ + ddi_bc_MinEventCode = DDI_BC_EVENT_GROUP, + /* brief TBD */ + ddi_bc_WaitingToChargeCode, + /* brief TBD */ + ddi_bc_State_ConditioningCode, + /* brief TBD */ + ddi_bc_State_Topping_OffCode, + /* brief TBD */ + ddi_bc_State_BrokenCode, + /* brief TBD */ + ddi_bc_SettingChargeCode, + /* brief TBD */ + ddi_bc_RaisingDieTempAlarmCode, + /* brief TBD */ + ddi_bc_DroppingDieTempAlarmCode, + + /* brief TBD */ + ddi_bc_MaxEventCode, + /* brief TBD */ + ddi_bc_DcdcModeWaitingToChargeCode +} ddi_bc_Event_t; + + +/* Prototypes */ + + + +/* brief Initialize the Battery Charger. */ +/* */ +/* fntype Function */ +/* */ +/* This function initializes the Battery Charger. */ +/* */ +/* param[in] pCfg A pointer to the new configuration. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS */ +/* If the operation succeeded. */ +/* retval DDI_BC_STATUS_ALREADY_INITIALIZED */ +/* If the Battery Charger is already initialized. */ +/* retval DDI_BC_STATUS_HARDWARE_DISABLED */ +/* If the Battery Charger hardware is disabled by a laser fuse. */ +/* retval DDI_BC_STATUS_BAD_BATTERY_MODE */ +/* If the power supply is set up for a non-rechargeable battery. */ +/* retval DDI_BC_STATUS_CLOCK_GATE_CLOSED */ +/* If the clock gate for the power supply registers is closed. */ +/* retval DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE */ +/* If the charging voltage is not either 4100 or 4200. */ +/* retval DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL */ +/* If the LRADC channel number for monitoring battery temperature */ +/* is bad. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_init.c. */ + +extern ddi_bc_Status_t ddi_bc_Init(ddi_bc_Cfg_t *pCfg); + +/* */ +/* brief Report the Battery Charger configuration. */ +/* */ +/* fntype Function */ +/* */ +/* This function reports the Battery Charger configuration. */ +/* */ +/* Note that, if the Battery Charger has not yet been initialized, the data */ +/* returned by this function is unknown. */ +/* */ +/* param[in,out] pCfg A pointer to a structure that will receive the data. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern void ddi_bc_QueryCfg(ddi_bc_Cfg_t *pCfg); + +/* */ +/* brief Shut down the Battery Charger. */ +/* */ +/* fntype Function */ +/* */ +/* This function immediately shuts down the Battery Charger hardware and */ +/* returns the state machine to the Uninitialized state. Use this function to */ +/* safely mummify the battery charger before retiring it from memory. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern void ddi_bc_ShutDown(void); + +/* */ +/* brief Advances the state machine. */ +/* */ +/* fntype Function */ +/* */ +/* This function advances the state machine. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS If all goes well */ +/* retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* retval DDI_BC_STATUS_BROKEN If the battery violated a time-out */ +/* and has been declared broken. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_Status_t ddi_bc_StateMachine(void); + +/* */ +/* brief Get the Battery Charger's current state. */ +/* */ +/* fntype Function */ +/* */ +/* This function returns the current state. */ +/* */ +/* retval The current state. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_State_t ddi_bc_GetState(void); + +/* */ +/* brief Disable the Battery Charger. */ +/* */ +/* fntype Function */ +/* */ +/* This function forces the Battery Charger into the Disabled state. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS If all goes well */ +/* retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_Status_t ddi_bc_SetDisable(void); + +/* */ +/* brief Enable the Battery Charger. */ +/* */ +/* fntype Function */ +/* */ +/* If the Battery Charger is in the Disabled state, this function moves it to */ +/* the Waiting to Charge state. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS If all goes well */ +/* retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* retval DDI_BC_STATUS_NOT_DISABLED If the Battery Charger is not */ +/* disabled. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_Status_t ddi_bc_SetEnable(void); + +/* */ +/* brief Declare the battery to be broken. */ +/* */ +/* fntype Function */ +/* */ +/* This function forces the Battery Charger into the Broken state. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS If all goes well */ +/* retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_Status_t ddi_bc_SetBroken(void); + +/* */ +/* brief Declare the battery to be fixed. */ +/* */ +/* fntype Function */ +/* */ +/* If the Battery Charger is in the Broken state, this function moves it to */ +/* the Disabled state. */ +/* */ +/* retval DDI_BC_STATUS_SUCCESS If all goes well */ +/* retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* retval DDI_BC_STATUS_NOT_BROKEN If the Battery Charger is not broken. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern ddi_bc_Status_t ddi_bc_SetFixed(void); + +/* */ +/* brief Set the current limit. */ +/* */ +/* fntype Function */ +/* */ +/* This function applies a limit to the current that the Battery Charger can */ +/* draw. */ +/* */ +/* param[in] u16Limit The maximum current the Battery Charger can draw */ +/* (in mA). */ +/* */ +/* retval The expressible version of the limit. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern uint16_t ddi_bc_SetCurrentLimit(uint16_t u16Limit); + + +/* */ +/* brief Report the current limit. */ +/* */ +/* fntype Function */ +/* */ +/* This function reports the limit to the current that the Battery Charger can */ +/* draw. */ +/* */ +/* retval The current limit. */ +/* */ +/* internal */ +/* see To view the function definition, see ddi_bc_api.c. */ + +extern uint16_t ddi_bc_GetCurrentLimit(void); + + +/* */ +/* brief Set the current threshold. */ +/* */ +/* fntype Function */ +/* */ +/* */ +/* param[in] u16Current Current threshold where charger deactivates (in mA). */ +/* */ +/* */ + +extern uint16_t ddi_bc_SetCurrentThreshold(uint16_t u16Current); + + +/* */ +/* brief Set the battery charger state machine period. */ +/* */ +/* fntype Function */ +/* */ +/* This function sets a new state machine period. The Period and Slope should */ +/* be coordinated to achieve the minimal ramp step current which will minimize */ +/* transients on the system. */ +/* */ +/* param[in] u32StateMachinePeriod (in milliseconds) */ +/* param[in] u16CurrentRampSlope (in mA/s) */ +/* */ +/* retval SUCCESS If all goes well */ +/* retval ERROR_DDI_BCM_NOT_INITIALIZED If the Battery Charger is not yet */ +/* initialized. */ +/* */ + +extern ddi_bc_Status_t ddi_bc_SetNewPeriodAndSlope(uint32_t + u32StateMachinePeriod, + uint16_t + u16CurrentRampSlope); + + +/* */ +/* brief Report the state machine period. */ +/* */ +/* fntype Function */ +/* */ +/* This function reports the battery charger period. */ +/* */ +/* retval The battery charger period (in milliseconds). */ +/* */ + +extern uint32_t ddi_bc_GetStateMachinePeriod(void); + + +/* */ +/* brief Report the current ramp slope. */ +/* */ +/* fntype Function */ +/* */ +/* This function reports the current ramp slope. */ +/* */ +/* retval The current ramp slope (in mA/s). */ +/* */ + +extern uint32_t ddi_bc_GetCurrentRampSlope(void); + + +/* */ +/* brief Report the time spent in the present state (milliseconds) */ +/* */ +/* fntype Function */ +/* */ +/* This function reports the time spent in the present charging state. Note that */ +/* for the states that actually charge the battery, this time does not include the */ +/* time spent under alarm conditions such as die termperature alarm or battery */ +/* temperature alarm. */ +/* */ +/* retval The time spent in the current state in milliseconds. */ +/* */ + +uint32_t ddi_bc_GetStateTime(void); + + +/* */ +/* brief Report the reason for being in the broken state */ +/* */ +/* fntype Function */ +/* */ +/* */ +/* retval ddi_bc_BrokenReason_t enumeration */ +/* */ + +ddi_bc_BrokenReason_t ddi_bc_GetBrokenReason(void); + + +/* */ +/* brief Restart the charge cycle */ +/* */ +/* fntype Function */ +/* */ +/* retval SUCCESS */ +/* */ + +ddi_bc_Status_t ddi_bc_ForceChargingToStart(void); + +void fsl_enable_usb_plugindetect(void); + +int fsl_is_usb_plugged(void); + +/* End of file */ + +#endif /* _DDI_BC_H */ +/* @} */ diff --git a/arch/arm/plat-mxs/include/mach/debug-macro.S b/arch/arm/plat-mxs/include/mach/debug-macro.S new file mode 100644 index 000000000000..147cda360cb3 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/debug-macro.S @@ -0,0 +1,42 @@ +/* + * Debugging macro include header + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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/hardware.h> + + .macro addruart,rx,tmp + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =MXS_LL_UART_PADDR @ physical + ldrne \rx, =MXS_LL_UART_VADDR @ virtual + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #0] @ data register at 0 + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm diff --git a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h new file mode 100644 index 000000000000..080add7d8fa2 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/device.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_DEVICE_H +#define __ASM_ARM_ARCH_DEVICE_H + +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/leds.h> + +#include <asm/mach/time.h> + +#define MXS_MAX_DEVICES 128 + +struct mxs_sys_timer { + struct sys_timer timer; + unsigned char id; + unsigned char clk_sel; + unsigned char resv[2]; + int irq; + struct clk *clk; + void __iomem *base; +}; + +struct mxs_dev_lookup { + char *name; + unsigned long lock; + int size; + struct platform_device *pdev; +}; + +/* Define the Platform special structure for each device type*/ +struct mxs_dma_plat_data { + unsigned int burst8:1; + unsigned int burst:1; + unsigned int chan_base; + unsigned int chan_num; +}; + +struct fsl_otp_data { + char **fuse_name; + char *regulator_name; + unsigned int fuse_num; +}; + +struct mxs_i2c_plat_data { + unsigned int pioqueue_mode:1; +}; + +struct mxs_lradc_plat_data { + unsigned int vddio_voltage; + unsigned int battery_voltage; +}; + +struct mxskbd_keypair { + int raw; + int kcode; +}; + +struct mxs_kbd_plat_data { + struct mxskbd_keypair *keypair; + int channel; + unsigned int btn_enable; /* detect enable bits */ + unsigned int btn_irq_stat; /* detect irq status bits */ + unsigned int btn_irq_ctrl; /* detect irq enable bits */ +}; + +struct mxs_touchscreen_plat_data { + u8 x_plus_chan; + u8 x_minus_chan; + u8 y_plus_chan; + u8 y_minus_chan; + unsigned int x_plus_val; + unsigned int x_minus_val; + unsigned int y_plus_val; + unsigned int y_minus_val; + unsigned int x_plus_mask; + unsigned int x_minus_mask; + unsigned int y_plus_mask; + unsigned int y_minus_mask; +}; + +struct mxs_auart_plat_data { + unsigned int fifo_size:6; + unsigned int dma_mode:1; + unsigned int timeout; + unsigned int dma_rx_buffer_size; + const char *clk; +}; + +struct mxs_pwm_led { + struct led_classdev dev; + const char *name; + unsigned int pwm; +}; + +struct mxs_pwm_leds_plat_data { + unsigned int num; + struct mxs_pwm_led *leds; +}; + +struct mxs_mma7450_platform_data { + char *reg_dvdd_io; + char *reg_avdd; + void (*gpio_pin_get) (void); + void (*gpio_pin_put) (void); + int int1; + int int2; +}; + +struct mxs_spi_platform_data { + int (*hw_pin_init)(void); + int (*hw_pin_release)(void); + + char *clk; +}; + +struct mxs_audio_platform_data { + int intr_id_hp; + int ext_ram; + struct clk *saif_mclock; + + int hp_irq; + int (*hp_status) (void); + + int sysclk; + + int (*init) (void); /* board specific init */ + int (*amp_enable) (int enable); + int (*finit) (void); /* board specific finit */ + void *priv; /* used by board specific functions */ +}; + +struct mxs_persistent_bit_config { + int reg; + int start; + int width; + const char *name; +}; + +struct mxs_platform_persistent_data { + const struct mxs_persistent_bit_config *bit_config_tab; + int bit_config_cnt; +}; + +extern void mxs_timer_init(struct mxs_sys_timer *timer); +extern void mxs_nomatch_timer_init(struct mxs_sys_timer *timer); + +extern void mxs_nop_release(struct device *dev); +extern int mxs_add_devices(struct platform_device *, int num, int level); +extern int mxs_add_device(struct platform_device *, int level); +extern struct platform_device *mxs_get_device(char *name, int id); +extern struct mxs_dev_lookup *mxs_get_devices(char *name); + +extern int iram_init(unsigned long base, unsigned long size); + +/* mxs ssp sd/mmc data definitons */ +struct mxs_mmc_platform_data { + int (*hw_init)(void); + void (*hw_release)(void); + void (*cmd_pullup)(int enable); + int (*get_wp)(void); + unsigned long (*setclock)(unsigned long hz); + unsigned int caps; + unsigned int min_clk; + unsigned int max_clk; + int read_uA; + int write_uA; + char *power_mmc; + char *clock_mmc; +}; +/* end of mxs ssp sd/mmc data definitions */ + +#ifdef CONFIG_MXS_ICOLL +extern void __init avic_init_irq(void __iomem *base, int nr_irqs); +#endif + +#endif diff --git a/arch/arm/plat-mxs/include/mach/dmaengine.h b/arch/arm/plat-mxs/include/mach/dmaengine.h new file mode 100644 index 000000000000..1600d9762a9e --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/dmaengine.h @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_DMA_H +#define __ASM_ARM_ARCH_DMA_H + +#ifndef ARCH_DMA_PIO_WORDS +#define DMA_PIO_WORDS 15 +#else +#define DMA_PIO_WORDS ARCH_DMA_PIO_WORDS +#endif + +#define MXS_DMA_ALIGNMENT 8 + +/** + * struct mxs_dma_cmd_bits - MXS DMA hardware command bits. + * + * This structure describes the in-memory layout of the command bits in a DMA + * command. See the appropriate reference manual for a detailed description + * of what these bits mean to the DMA hardware. + */ +struct mxs_dma_cmd_bits { + unsigned int command:2; +#define NO_DMA_XFER 0x00 +#define DMA_WRITE 0x01 +#define DMA_READ 0x02 +#define DMA_SENSE 0x03 + + unsigned int chain:1; + unsigned int irq:1; + unsigned int nand_lock:1; + unsigned int nand_wait_4_ready:1; + unsigned int dec_sem:1; + unsigned int wait4end:1; + unsigned int halt_on_terminate:1; + unsigned int terminate_flush:1; + unsigned int resv2:2; + unsigned int pio_words:4; + unsigned int bytes:16; +}; + +/* fill the word 1 of the DMA channel command structure */ +#define fill_dma_word1(cmdp, _cmd, _chain, _irq, _lock, _wait_ready, _dec_sem,\ + _wait4end, _halt_on_term, _term_flush, _pio_words, _bytes)\ + do { \ + struct mxs_dma_cmd_bits *bits = &(cmdp)->bits; \ + \ + /* reset all the fields first */ \ + (cmdp)->data = 0; \ + \ + bits->command = _cmd; \ + bits->chain = _chain; \ + bits->irq = _irq; \ + bits->nand_lock = _lock; \ + bits->nand_wait_4_ready = _wait_ready; \ + bits->dec_sem = _dec_sem; \ + bits->wait4end = _wait4end; \ + bits->halt_on_terminate = _halt_on_term; \ + bits->terminate_flush = _term_flush; \ + bits->pio_words = _pio_words; \ + bits->bytes = _bytes; \ + } while (0) + +/** + * struct mxs_dma_cmd - MXS DMA hardware command. + * + * This structure describes the in-memory layout of an entire DMA command, + * including space for the maximum number of PIO accesses. See the appropriate + * reference manual for a detailed description of what these fields mean to the + * DMA hardware. + */ +struct mxs_dma_cmd { + unsigned long next; + union { + unsigned long data; + struct mxs_dma_cmd_bits bits; + } cmd; + union { + dma_addr_t address; + unsigned long alternate; + }; + unsigned long pio_words[DMA_PIO_WORDS]; +}; + +/** + * struct mxs_dma_desc - MXS DMA command descriptor. + * + * This structure incorporates an MXS DMA hardware command structure, along + * with metadata. + * + * @cmd: The MXS DMA hardware command block. + * @flags: Flags that represent the state of this DMA descriptor. + * @address: The physical address of this descriptor. + * @buffer: A convenient place for software to put the virtual address of the + * associated data buffer (the physical address of the buffer + * appears in the DMA command). The MXS platform DMA software doesn't + * use this field -- it is provided as a convenience. + * @node: Links this structure into a list. + */ +struct mxs_dma_desc { + struct mxs_dma_cmd cmd; + unsigned int flags; +#define MXS_DMA_DESC_READY 0x80000000 +#define MXS_DMA_DESC_FIRST 0x00000001 +#define MXS_DMA_DESC_LAST 0x00000002 + dma_addr_t address; + void *buffer; + struct list_head node; +}; + +struct mxs_dma_info { + unsigned int status; +#define MXS_DMA_INFO_ERR 0x00000001 +#define MXS_DMA_INFO_ERR_STAT 0x00010000 + unsigned int buf_addr; + unsigned int xfer_count; +}; + +/** + * struct mxs_dma_chan - MXS DMA channel + * + * This structure represents a single DMA channel. The MXS platform code + * maintains an array of these structures to represent every DMA channel in the + * system (see mxs_dma_channels). + * + * @name: A human-readable string that describes how this channel is + * being used or what software "owns" it. This field is set when + * when the channel is reserved by mxs_dma_request(). + * @dev: A pointer to a struct device *, cast to an unsigned long, and + * representing the software that "owns" the channel. This field + * is set when when the channel is reserved by mxs_dma_request(). + * @lock: Arbitrates access to this channel. + * @dma: A pointer to a struct mxs_dma_device representing the driver + * code that operates this channel. + * @flags: Flag bits that represent the state of this channel. + * @active_num: If the channel is not busy, this value is zero. If the channel + * is busy, this field contains the number of DMA command + * descriptors at the head of the active list that the hardware + * has been told to process. This value is set at the moment the + * channel is enabled by mxs_dma_enable(). More descriptors may + * arrive after the channel is enabled, so the number of + * descriptors on the active list may be greater than this value. + * In fact, it should always be active_num + pending_num. + * @pending_num: The number of DMA command descriptors at the tail of the + * active list that the hardware has not been told to process. + * @active: The list of DMA command descriptors either currently being + * processed by the hardware or waiting to be processed. + * Descriptors being processed appear at the head of the list, + * while pending descriptors appear at the tail. The total number + * should always be active_num + pending_num. + * @done: The list of DMA command descriptors that have either been + * processed by the DMA hardware or aborted by a call to + * mxs_dma_disable(). + */ +struct mxs_dma_chan { + const char *name; + unsigned long dev; + spinlock_t lock; + struct mxs_dma_device *dma; + unsigned int flags; +#define MXS_DMA_FLAGS_IDLE 0x00000000 +#define MXS_DMA_FLAGS_BUSY 0x00000001 +#define MXS_DMA_FLAGS_FREE 0x00000000 +#define MXS_DMA_FLAGS_ALLOCATED 0x00010000 +#define MXS_DMA_FLAGS_VALID 0x80000000 + unsigned int active_num; + unsigned int pending_num; + struct list_head active; + struct list_head done; +}; + +/** + * struct mxs_dma_device - DMA channel driver interface. + * + * This structure represents the driver that operates a DMA channel. Every + * struct mxs_dma_chan contains a pointer to a structure of this type, which is + * installed when the driver registers to "own" the channel (see + * mxs_dma_device_register()). + */ +struct mxs_dma_device { + struct list_head node; + const char *name; + void __iomem *base; + unsigned int chan_base; + unsigned int chan_num; + unsigned int data; + struct platform_device *pdev; + + /* operations */ + int (*enable) (struct mxs_dma_chan *, unsigned int); + void (*disable) (struct mxs_dma_chan *, unsigned int); + void (*reset) (struct mxs_dma_device *, unsigned int); + void (*freeze) (struct mxs_dma_device *, unsigned int); + void (*unfreeze) (struct mxs_dma_device *, unsigned int); + int (*read_semaphore) (struct mxs_dma_device *, unsigned int); + void (*add_semaphore) (struct mxs_dma_device *, unsigned int, unsigned); + void (*info)(struct mxs_dma_device *, + unsigned int, struct mxs_dma_info *info); + void (*enable_irq) (struct mxs_dma_device *, unsigned int, int); + int (*irq_is_pending) (struct mxs_dma_device *, unsigned int); + void (*ack_irq) (struct mxs_dma_device *, unsigned int); + + void (*set_target) (struct mxs_dma_device *, unsigned int, int); +}; + +/** + * mxs_dma_device_register - Register a DMA driver. + * + * This function registers a driver for a contiguous group of DMA channels (the + * ordering of DMA channels is specified by the globally unique DMA channel + * numbers given in mach/dma.h). + * + * @pdev: A pointer to a structure that represents the driver. This structure + * contains fields that specify the first DMA channel number and the + * number of channels. + */ +extern int mxs_dma_device_register(struct mxs_dma_device *pdev); + +/** + * mxs_dma_request - Request to reserve a DMA channel. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @dev: A pointer to a struct device representing the channel "owner." + * @name: A human-readable string that identifies the channel owner or the + * purpose of the channel. + */ +extern int mxs_dma_request(int channel, struct device *dev, const char *name); + +/** + * mxs_dma_release - Release a DMA channel. + * + * This function releases a DMA channel from its current owner. + * + * The channel will NOT be released if it's marked "busy" (see + * mxs_dma_enable()). + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @dev: A pointer to a struct device representing the channel "owner." If + * this doesn't match the owner given to mxs_dma_request(), the + * channel will NOT be released. + */ +extern void mxs_dma_release(int channel, struct device *dev); + +/** + * mxs_dma_enable - Enable a DMA channel. + * + * If the given channel has any DMA descriptors on its active list, this + * function causes the DMA hardware to begin processing them. + * + * This function marks the DMA channel as "busy," whether or not there are any + * descriptors to process. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern int mxs_dma_enable(int channel); + +/** + * mxs_dma_disable - Disable a DMA channel. + * + * This function shuts down a DMA channel and marks it as "not busy." Any + * descriptors on the active list are immediately moved to the head of the + * "done" list, whether or not they have actually been processed by the + * hardware. The "ready" flags of these descriptors are NOT cleared, so they + * still appear to be active. + * + * This function immediately shuts down a DMA channel's hardware, aborting any + * I/O that may be in progress, potentially leaving I/O hardware in an undefined + * state. It is unwise to call this function if there is ANY chance the hardware + * is still processing a command. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern void mxs_dma_disable(int channel); + +/** + * mxs_dma_reset - Resets the DMA channel hardware. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern void mxs_dma_reset(int channel); + +/** + * mxs_dma_freeze - Freeze a DMA channel. + * + * This function causes the channel to continuously fail arbitration for bus + * access, which halts all forward progress without losing any state. A call to + * mxs_dma_unfreeze() will cause the channel to continue its current operation + * with no ill effect. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern void mxs_dma_freeze(int channel); + +/** + * mxs_dma_unfreeze - Unfreeze a DMA channel. + * + * This function reverses the effect of mxs_dma_freeze(), enabling the DMA + * channel to continue from where it was frozen. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ + +extern void mxs_dma_unfreeze(int channel); + +/* get dma channel information */ +extern int mxs_dma_get_info(int channel, struct mxs_dma_info *info); + +/** + * mxs_dma_cooked - Clean up processed DMA descriptors. + * + * This function removes processed DMA descriptors from the "active" list. Pass + * in a non-NULL list head to get the descriptors moved to your list. Pass NULL + * to get the descriptors moved to the channel's "done" list. Descriptors on + * the "done" list can be retrieved with mxs_dma_get_cooked(). + * + * This function marks the DMA channel as "not busy" if no unprocessed + * descriptors remain on the "active" list. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @head: If this is not NULL, it is the list to which the processed + * descriptors should be moved. If this list is NULL, the descriptors + * will be moved to the "done" list. + */ +extern int mxs_dma_cooked(int channel, struct list_head *head); + +/** + * mxs_dma_read_semaphore - Read a DMA channel's hardware semaphore. + * + * As used by the MXS platform's DMA software, the DMA channel's hardware + * semaphore reflects the number of DMA commands the hardware will process, but + * has not yet finished. This is a volatile value read directly from hardware, + * so it must be be viewed as immediately stale. + * + * If the channel is not marked busy, or has finished processing all its + * commands, this value should be zero. + * + * See mxs_dma_append() for details on how DMA command blocks must be configured + * to maintain the expected behavior of the semaphore's value. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern int mxs_dma_read_semaphore(int channel); + +/** + * mxs_dma_irq_is_pending - Check if a DMA interrupt is pending. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern int mxs_dma_irq_is_pending(int channel); + +/** + * mxs_dma_enable_irq - Enable or disable DMA interrupt. + * + * This function enables the given DMA channel to interrupt the CPU. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @en: True if the interrupt for this channel should be enabled. False + * otherwise. + */ +extern void mxs_dma_enable_irq(int channel, int en); + +/** + * mxs_dma_ack_irq - Clear DMA interrupt. + * + * The software that is using the DMA channel must register to receive its + * interrupts and, when they arrive, must call this function to clear them. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + */ +extern void mxs_dma_ack_irq(int channel); + +/** + * mxs_dma_set_target - Set the target for a DMA channel. + * + * This function is NOT used on the i.MX28. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @target: Indicates the target for the channel. + */ +extern void mxs_dma_set_target(int channel, int target); + +/* mxs dma utility functions */ +extern struct mxs_dma_desc *mxs_dma_alloc_desc(void); +extern void mxs_dma_free_desc(struct mxs_dma_desc *); + +/** + * mxs_dma_cmd_address - Return the address of the command within a descriptor. + * + * @desc: The DMA descriptor of interest. + */ +static inline unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc) +{ + return desc->address += offsetof(struct mxs_dma_desc, cmd); +} + +/** + * mxs_dma_desc_pending - Check if descriptor is on a channel's active list. + * + * This function returns the state of a descriptor's "ready" flag. This flag is + * usually set only if the descriptor appears on a channel's active list. The + * descriptor may or may not have already been processed by the hardware. + * + * The "ready" flag is set when the descriptor is submitted to a channel by a + * call to mxs_dma_append() or mxs_dma_append_list(). The "ready" flag is + * cleared when a processed descriptor is moved off the active list by a call + * to mxs_dma_cooked(). The "ready" flag is NOT cleared if the descriptor is + * aborted by a call to mxs_dma_disable(). + * + * @desc: The DMA descriptor of interest. + */ +static inline int mxs_dma_desc_pending(struct mxs_dma_desc *pdesc) +{ + return pdesc->flags & MXS_DMA_DESC_READY; +} + +/** + * mxs_dma_desc_append - Add a DMA descriptor to a channel. + * + * If the descriptor list for this channel is not empty, this function sets the + * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so + * it will chain to the new descriptor's command. + * + * Then, this function marks the new descriptor as "ready," adds it to the end + * of the active descriptor list, and increments the count of pending + * descriptors. + * + * The MXS platform DMA software imposes some rules on DMA commands to maintain + * important invariants. These rules are NOT checked, but they must be carefully + * applied by software that uses MXS DMA channels. + * + * Invariant: + * The DMA channel's hardware semaphore must reflect the number of DMA + * commands the hardware will process, but has not yet finished. + * + * Explanation: + * A DMA channel begins processing commands when its hardware semaphore is + * written with a value greater than zero, and it stops processing commands + * when the semaphore returns to zero. + * + * When a channel finishes a DMA command, it will decrement its semaphore if + * the DECREMENT_SEMAPHORE bit is set in that command's flags bits. + * + * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set, + * unless it suits the purposes of the software. For example, one could + * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE + * bit set only in the last one. Then, setting the DMA channel's hardware + * semaphore to one would cause the entire series of five commands to be + * processed. However, this example would violate the invariant given above. + * + * Rule: + * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA + * channel's hardware semaphore will be decremented EVERY time a command is + * processed. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @pdesc: A pointer to the new descriptor. + */ +extern int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc); + +/** + * mxs_dma_desc_add_list - Add a list of DMA descriptors to a channel. + * + * This function marks all the new descriptors as "ready," adds them to the end + * of the active descriptor list, and adds the length of the list to the count + * of pending descriptors. + * + * See mxs_dma_desc_append() for important rules that apply to incoming DMA + * descriptors. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @head: A pointer to the head of the list of DMA descriptors to add. + */ +extern int mxs_dma_desc_add_list(int channel, struct list_head *head); + +/** + * mxs_dma_desc_get_cooked - Retrieve processed DMA descriptors. + * + * This function moves all the descriptors from the DMA channel's "done" list to + * the head of the given list. + * + * @channel: The channel number. This is one of the globally unique DMA channel + * numbers given in mach/dma.h. + * @head: A pointer to the head of the list that will receive the + * descriptors on the "done" list. + */ +extern int mxs_dma_get_cooked(int channel, struct list_head *head); + +#endif diff --git a/arch/arm/plat-mxs/include/mach/entry-macro.S b/arch/arm/plat-mxs/include/mach/entry-macro.S new file mode 100644 index 000000000000..353a7b2cc8fd --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/entry-macro.S @@ -0,0 +1,36 @@ +/* + * Low-level IRQ helper macros for Freescale MXS-based + * + * Copyright (C) 2009-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. + */ + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =g_icoll_base + ldr \base, [\base] + ldr \irqnr, [\base, #0x70] + cmp \irqnr, #0x7F + moveqs \irqnr, #0 + .endm + + .macro get_irqnr_preamble, base, tmp + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm diff --git a/arch/arm/plat-mxs/include/mach/fsl_usb.h b/arch/arm/plat-mxs/include/mach/fsl_usb.h new file mode 100644 index 000000000000..f88324856fc7 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/fsl_usb.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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. + */ + +/* + * USB Host side, platform-specific functionality. + */ + +#include <linux/usb/fsl_xcvr.h> +#include <mach/arc_otg.h> + +/* ehci_arc_hc_driver.flags value */ +#define FSL_PLATFORM_HC_FLAGS (HCD_USB2 | HCD_MEMORY) + +static void fsl_setup_phy(struct ehci_hcd *ehci, + enum fsl_usb2_phy_modes phy_mode, + int port_offset); + +static inline void fsl_platform_usb_setup(struct ehci_hcd *ehci) +{ + struct fsl_usb2_platform_data *pdata; + + pdata = ehci_to_hcd(ehci)->self.controller->platform_data; + fsl_setup_phy(ehci, pdata->phy_mode, 0); +} + +static inline void fsl_platform_set_host_mode(struct usb_hcd *hcd) +{ + unsigned int temp; + struct fsl_usb2_platform_data *pdata; + + pdata = hcd->self.controller->platform_data; + + if (pdata->xcvr_ops && pdata->xcvr_ops->set_host) + pdata->xcvr_ops->set_host(); + + /* set host mode */ + temp = readl(hcd->regs + UOG_USBMODE); + writel(temp | USBMODE_CM_HOST, hcd->regs + UOG_USBMODE); +} + +/* Needed for i2c/serial transceivers */ +static inline void +fsl_platform_set_vbus_power(struct fsl_usb2_platform_data *pdata, int on) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) + pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on); +} + +/* Set USB AHB burst length for host */ +static inline void fsl_platform_set_ahb_burst(struct usb_hcd *hcd) +{ +} + +void fsl_phy_usb_utmi_init(struct fsl_xcvr_ops *this); +void fsl_phy_usb_utmi_uninit(struct fsl_xcvr_ops *this); +void fsl_phy_set_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on); + diff --git a/arch/arm/plat-mxs/include/mach/fsl_usb_gadget.h b/arch/arm/plat-mxs/include/mach/fsl_usb_gadget.h new file mode 100644 index 000000000000..767b344d7e95 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/fsl_usb_gadget.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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. + */ + +/* + * USB Gadget side, platform-specific functionality. + */ + +#include <linux/usb/fsl_xcvr.h> + +/* Needed for i2c/serial transceivers */ +static inline void +fsl_platform_set_device_mode(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_device) + pdata->xcvr_ops->set_device(); +} + +static inline void +fsl_platform_pullup_enable(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->pullup) + pdata->xcvr_ops->pullup(1); +} + +static inline void +fsl_platform_pullup_disable(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->pullup) + pdata->xcvr_ops->pullup(0); +} diff --git a/arch/arm/plat-mxs/include/mach/gpio.h b/arch/arm/plat-mxs/include/mach/gpio.h new file mode 100644 index 000000000000..7b634149ec23 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/gpio.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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_GPIO_H__ +#define __ASM_ARCH_GPIO_H__ + +#include <mach/hardware.h> +#include <asm-generic/gpio.h> + +#define GPIO_ID_NAME "gpio" +/* use gpiolib dispatchers */ +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq +#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START) + +struct mxs_gpio_port; +struct mxs_gpio_chip { + int (*set_dir) (struct mxs_gpio_port *, int, unsigned int); + int (*get) (struct mxs_gpio_port *, int); + void (*set) (struct mxs_gpio_port *, int, int); + unsigned int (*get_irq_stat) (struct mxs_gpio_port *); + int (*set_irq_type) (struct mxs_gpio_port *, int, unsigned int); + void (*unmask_irq) (struct mxs_gpio_port *, int); + void (*mask_irq) (struct mxs_gpio_port *, int); + void (*ack_irq) (struct mxs_gpio_port *, int); +}; + +struct mxs_gpio_port { + int id; + int irq; + int child_irq; + struct mxs_gpio_chip *chip; + struct gpio_chip port; +}; + +extern int mxs_add_gpio_port(struct mxs_gpio_port *port); + +static inline void +mxs_set_gpio_chip(struct mxs_gpio_port *port, struct mxs_gpio_chip *chip) +{ + if (port && chip) + port->chip = chip; +} + +#endif /* __ASM_ARCH_GPIO_H__ */ diff --git a/arch/arm/plat-mxs/include/mach/hardware.h b/arch/arm/plat-mxs/include/mach/hardware.h new file mode 100644 index 000000000000..c7dd8fe1d31b --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/hardware.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_HARDWARE_H +#define __ASM_ARM_ARCH_HARDWARE_H + +#ifdef CONFIG_ARCH_MX28 +# include <mach/mx28.h> +# define cpu_is_mx28() 1 +# else +# define cpu_is_mx28() 0 +#endif + +#ifdef CONFIG_ARCH_MX23 +# include <mach/mx23.h> +# define cpu_is_mx23() 1 +# else +# define cpu_is_mx23() 0 +#endif + +#ifndef MXS_EXTEND_IRQS +#define MXS_EXTEND_IRQS 0 +#endif + +#ifndef MXS_ARCH_NR_GPIOS +#define MXS_ARCH_NR_GPIOS 160 +#endif + +#ifndef MXS_EXTEND_NR_GPIOS +#define MXS_EXTEND_NR_GPIOS 0 +#endif + +#define ARCH_NR_GPIOS (MXS_ARCH_NR_GPIOS + MXS_EXTEND_NR_GPIOS) + +#define MXS_GPIO_IRQ_START ARCH_NR_IRQS +#define MXS_EXTEND_IRQ_START (ARCH_NR_IRQS + ARCH_NR_GPIOS) + +#endif /* __ASM_ARM_ARCH_HARDWARE_H */ diff --git a/arch/arm/plat-mxs/include/mach/io.h b/arch/arm/plat-mxs/include/mach/io.h new file mode 100644 index 000000000000..7dff55ef7f12 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/io.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#define SET_REGISTER 0x4 +#define CLR_REGISTER 0x8 +#define TOG_REGISTER 0xC + +struct mxs_io_bank { + unsigned int raw; + unsigned int set; + unsigned int clr; + unsigned int tog; +}; +#endif diff --git a/arch/arm/plat-mxs/include/mach/irqs.h b/arch/arm/plat-mxs/include/mach/irqs.h new file mode 100644 index 000000000000..62165e12a60c --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/irqs.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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_IRQS_H__ +#define __ASM_ARCH_IRQS_H__ + +#include <mach/hardware.h> + +#define NR_IRQS (ARCH_NR_IRQS + ARCH_NR_GPIOS + MXS_EXTEND_IRQS) + +#ifndef __ASSEMBLY__ +struct irq_ic_info { + unsigned int id_val; + unsigned int id_mask; + const char *name; + unsigned int base; +}; + +#define __irq_ic_info_attr __attribute__((__section__(".irq_ic_info.array"))) + +extern struct irq_ic_info *current_irq_ic_info; + +void mxs_set_irq_fiq(unsigned int irq, unsigned int type); +void mxs_enable_fiq_functionality(int enable); + +#endif + +#endif /* __ASM_ARCH_SYSTEM_H__ */ diff --git a/arch/arm/plat-mxs/include/mach/lradc.h b/arch/arm/plat-mxs/include/mach/lradc.h new file mode 100644 index 000000000000..c2c0a7deb0b4 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/lradc.h @@ -0,0 +1,61 @@ +/* + * Freescale STMP37XX/STMP378X LRADC helper interface + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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_PLAT_LRADC_H +#define __ASM_PLAT_LRADC_H + +int hw_lradc_use_channel(int); +int hw_lradc_unuse_channel(int); +extern u32 hw_lradc_vddio(void); +void hw_lradc_set_delay_trigger_kick(int trigger, int value); +void hw_lradc_configure_channel(int channel, int enable_div2, + int enable_acc, int samples); +int hw_lradc_present(int channel); +int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling); +int hw_lradc_stop_ladder(int channel, int trigger); +void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers, u32 loops, u32 delays); +void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers); + + +#define LRADC_CH0 0 +#define LRADC_CH1 1 +#define LRADC_CH2 2 +#define LRADC_CH3 3 +#define LRADC_CH4 4 +#define LRADC_CH5 5 +#define LRADC_CH6 6 +#define LRADC_CH7 7 +#define LRADC_TOUCH_X_PLUS LRADC_CH2 +#define LRADC_TOUCH_Y_PLUS LRADC_CH3 +#define LRADC_TOUCH_X_MINUS LRADC_CH4 +#define LRADC_TOUCH_Y_MINUS LRADC_CH5 +#define VDDIO_VOLTAGE_CH LRADC_CH6 +#define BATTERY_VOLTAGE_CH LRADC_CH7 + +#define LRADC_CLOCK_6MHZ 0 +#define LRADC_CLOCK_4MHZ 1 +#define LRADC_CLOCK_3MHZ 2 +#define LRADC_CLOCK_2MHZ 3 + +#define LRADC_DELAY_TRIGGER_BUTTON 0 +#define LRADC_DELAY_TRIGGER_BATTERY 1 +#define LRADC_DELAY_TRIGGER_TOUCHSCREEN 2 +#define LRADC_DELAY_TRIGGER_DIE 3 + +#endif /* __ASM_PLAT_LRADC_H */ diff --git a/arch/arm/plat-mxs/include/mach/memory.h b/arch/arm/plat-mxs/include/mach/memory.h new file mode 100644 index 000000000000..051b1608cca4 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/memory.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009-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_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#include <asm/page.h> +#include <asm/sizes.h> + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET UL(0x40000000) + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_DMA_ZONE_SIZE +#define MXS_DMA_ZONE_SIZE ((CONFIG_DMA_ZONE_SIZE * SZ_1M) >> PAGE_SHIFT) +#else +#define MXS_DMA_ZONE_SIZE ((12 * SZ_1M) >> PAGE_SHIFT) +#endif + +static inline void __arch_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + if (node != 0) + return; + /* Create separate zone to reserve memory for DMA */ + zone_size[1] = zone_size[0] - MXS_DMA_ZONE_SIZE; + zone_size[0] = MXS_DMA_ZONE_SIZE; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +#define arch_adjust_zones(node, size, holes) \ + __arch_adjust_zones(node, size, holes) + +#endif + +#define ISA_DMA_THRESHOLD (0x0003ffffULL) + +#define CONSISTENT_DMA_SIZE SZ_32M + +#endif diff --git a/arch/arm/plat-mxs/include/mach/pinctrl.h b/arch/arm/plat-mxs/include/mach/pinctrl.h new file mode 100644 index 000000000000..6e02149f5ca6 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/pinctrl.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2009-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_ARM_ARCH_PINCTRL_H +#define __ASM_ARM_ARCH_PINCTRL_H + +#include <linux/types.h> +#include <linux/gpio.h> + +#define PINS_PER_BANK 32 +#define GPIO_TO_PINS(gpio) ((gpio) % 32) +#define GPIO_TO_BANK(gpio) ((gpio) / 32) + +#define MXS_PIN_TO_GPIO(p) (((p) & MXS_PIN_PINID_MAX) |\ + ((((p) >> MXS_PIN_BANK_BIT) &\ + MXS_PIN_BANK_MAX) * PINS_PER_BANK)) + +#define MXS_PIN_BANK_BIT 24 +#define MXS_PIN_BANK_MAX (0x7FFFFFFF >> (MXS_PIN_BANK_BIT - 1)) +#define MXS_PIN_PINID_MAX ((1 << MXS_PIN_BANK_BIT) - 1) +#define MXS_PIN_TO_BANK(p) (((p) >> MXS_PIN_BANK_BIT) & MXS_PIN_BANK_MAX) +#define MXS_PIN_TO_PINID(p) ((p) & MXS_PIN_PINID_MAX) + +#define MXS_PIN_ENCODE(b, p) \ + ((((b) & MXS_PIN_BANK_MAX) << MXS_PIN_BANK_BIT) |\ + ((p) & MXS_PIN_PINID_MAX)) + +#define MXS_GPIO_MASK 0x7FFFFFFF +#define MXS_NON_GPIO 0x80000000 +/* + * Each pin may be routed up to four different HW interfaces + * including GPIO + */ +enum pin_fun { + PIN_FUN1 = 0, + PIN_FUN2, + PIN_FUN3, + PIN_GPIO, +}; + +/* + * Each pin may have different output drive strength in range from + * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths. + */ +enum pad_strength { + PAD_4MA = 0, + PAD_8MA, + PAD_12MA, + PAD_RESV, + PAD_CLEAR = PAD_RESV, +}; + +/* + * Each pin can be programmed for 1.8V or 3.3V + */ +enum pad_voltage { + PAD_1_8V = 0, + PAD_3_3V, +}; + +/** + * struct pin_desc - Describes the configuration of a pin. + * + * @name: A human-readable name that identifies the pin. + * @id: A number that identifies the pin (use a macro from a chip- + * specific header file -- e.g., "PINID_PWM0"). + * @fun: The function for which to configure this pin. + * @strength: The drive strength for this pin. Note that this field should be + * ignored and the driver hardware should *not* be configured if the + * "drive" field is not set. + * @voltage: The voltage rail for this pin. Note that this field should be + * ignored and the driver hardware should *not* be configured if the + * "drive" field is not set. + * @pullup: If set, indicates whether the pullup is enabled. Note that this + * field should be ignored and the pullup should *not* be configured + * if the "pull" field is not set. + * @drive: If set, indicates that the driver hardware for this pin should be + * configured. This field does *not* indicate *how* the driver + * hardware should be configured -- only whether or not it should + * be. See the "strength" and "voltage" fields for information about + * how to configure the driver hardware. + * @pull: If set, indicates that the pullup for this pin should be + * configured. This field does *not* indicate *how* the pullup + * should be configured -- only whether or not it should be. See the + * "pullup" field for information about how to configure the pullup. + * @input: For GPIO pins only, this indicates whether the pin is an input. + * @data: The data field is used when the pin is configured to GPIO output + * mode. When data is 0, the pin's output will be 0. + */ +struct pin_desc { + char *name; + unsigned int id; + enum pin_fun fun; + enum pad_strength strength; + enum pad_voltage voltage; + unsigned pullup:1; + unsigned drive:1; + unsigned pull:1; + unsigned output:1; + unsigned data:1; +}; + +struct pin_bank { + const char *label[sizeof(long) * 8]; + unsigned long id; + struct pinctrl_chip *chip; + unsigned long bitmap; + unsigned long gpio_port; +}; + +struct pinctrl_chip { + char *name; + unsigned int nouse; + unsigned int bank_size; + struct pin_bank *banks; + /* OPS */ + int (*pin2id) (struct pinctrl_chip *, unsigned int, unsigned int *); + unsigned int (*get_gpio) (struct pin_bank *, unsigned int); + void (*set_strength) (struct pin_bank *, unsigned int, + enum pad_strength); + void (*set_voltage) (struct pin_bank *, unsigned int, enum pad_voltage); + void (*set_pullup) (struct pin_bank *, unsigned int, int); + void (*set_type) (struct pin_bank *, unsigned int, enum pin_fun); + int (*get_type) (struct pin_bank *, unsigned int); +}; + +extern int __init mxs_set_pinctrl_chip(struct pinctrl_chip *); + +extern unsigned int mxs_pin2gpio(unsigned int); +extern int mxs_request_pin(unsigned int, enum pin_fun, const char *); +extern int mxs_set_type(unsigned int, enum pin_fun, const char *); +extern int mxs_get_type(unsigned int); +extern int mxs_set_strength(unsigned int, enum pad_strength, const char *); +extern int mxs_set_voltage(unsigned int, enum pad_voltage, const char *); +extern int mxs_set_pullup(unsigned int, int, const char *); +extern void mxs_release_pin(unsigned int, const char *); +#endif diff --git a/arch/arm/plat-mxs/include/mach/power.h b/arch/arm/plat-mxs/include/mach/power.h new file mode 100644 index 000000000000..28ee9fa2696d --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/power.h @@ -0,0 +1,64 @@ +/* + * Freescale MXS voltage regulator structure declarations + * + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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 __VOLTAGE_H +#define __VOLTAGE_H +#include <linux/completion.h> +#include <linux/regulator/driver.h> + +struct mxs_regulator { + struct regulator_desc regulator; + struct mxs_regulator *parent; + struct mxs_platform_regulator_data *rdata; + struct completion done; + + spinlock_t lock; + wait_queue_head_t wait_q; + struct notifier_block nb; + + int mode; + int cur_voltage; + int cur_current; + int next_current; +}; + + +struct mxs_platform_regulator_data { + char name[80]; + char *parent_name; + int (*reg_register)(struct mxs_regulator *sreg); + int (*set_voltage)(struct mxs_regulator *sreg, int uv); + int (*get_voltage)(struct mxs_regulator *sreg); + int (*set_current)(struct mxs_regulator *sreg, int uA); + int (*get_current)(struct mxs_regulator *sreg); + int (*enable)(struct mxs_regulator *sreg); + int (*disable)(struct mxs_regulator *sreg); + int (*is_enabled)(struct mxs_regulator *sreg); + int (*set_mode)(struct mxs_regulator *sreg, int mode); + int (*get_mode)(struct mxs_regulator *sreg); + int (*get_optimum_mode)(struct mxs_regulator *sreg, + int input_uV, int output_uV, int load_uA); + u32 control_reg; + int min_voltage; + int max_voltage; + int max_current; + struct regulation_constraints *cnstraints; +}; + +int mxs_register_regulator( + struct mxs_regulator *reg_data, int reg, + struct regulator_init_data *initdata); + +#endif /* __VOLTAGE_H */ diff --git a/arch/arm/plat-mxs/include/mach/system.h b/arch/arm/plat-mxs/include/mach/system.h new file mode 100644 index 000000000000..faaa2ff3cf13 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/system.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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_SYSTEM_H__ +#define __ASM_ARCH_SYSTEM_H__ + +extern void arch_idle(void); + +void arch_reset(char mode, const char *cmd); +extern void (*machine_arch_reset)(char mode, const char *cmd); +int mxs_reset_block(void __iomem *hwreg, int just_enable); +int get_evk_board_version(void); + +#endif /* __ASM_ARCH_SYSTEM_H__ */ diff --git a/arch/arm/plat-mxs/include/mach/timex.h b/arch/arm/plat-mxs/include/mach/timex.h new file mode 100644 index 000000000000..d622dda141f2 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/timex.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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. + */ + +/* + * System time clock is sourced from the 32k clock + */ +#define CLOCK_TICK_RATE 32000 diff --git a/arch/arm/plat-mxs/include/mach/uncompress.h b/arch/arm/plat-mxs/include/mach/uncompress.h new file mode 100644 index 000000000000..fd4e4f845472 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/uncompress.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-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_PLAT_UNCOMPRESS_H +#define __ASM_PLAT_UNCOMPRESS_H + +#include <mach/hardware.h> + +/* + * Register includes are for when the MMU enabled; we need to define our + * own stuff here for pre-MMU use + */ +#define UART_PORT_BASE DUART_PHYS_ADDR +#define UART(c) (((volatile unsigned *)UART_PORT_BASE)[c]) + +/* + * This does not append a newline + */ +static void putc(char c) +{ + /* Wait for TX fifo empty */ + while ((UART(6) & (1 << 7)) == 0) + continue; + + /* Write byte */ + UART(0) = c; + + /* Wait for last bit to exit the UART */ + while (UART(6) & (1 << 3)) + continue; +} + +#define flush() do { } while (0) +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif /* __ASM_PLAT_UNCOMPRESS_H */ diff --git a/arch/arm/plat-mxs/include/mach/unique-id.h b/arch/arm/plat-mxs/include/mach/unique-id.h new file mode 100644 index 000000000000..de5e04342ef5 --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/unique-id.h @@ -0,0 +1,30 @@ +/* + * Unique ID interface for ID storage providers + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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 __UNIQUE_ID_H +#define __UNIQUE_ID_H + +struct uid_ops { + ssize_t (*id_show)(void *context, char *page, int ascii); + ssize_t (*id_store)(void *context, const char *page, + size_t count, int ascii); +}; + +struct kobject *uid_provider_init(const char *name, + struct uid_ops *ops, void *context); +void uid_provider_remove(const char *name); +#endif diff --git a/arch/arm/plat-mxs/include/mach/vmalloc.h b/arch/arm/plat-mxs/include/mach/vmalloc.h new file mode 100644 index 000000000000..cc6d5cf3133a --- /dev/null +++ b/arch/arm/plat-mxs/include/mach/vmalloc.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2009-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. + */ + +#define VMALLOC_END (0xF0000000) diff --git a/arch/arm/plat-mxs/iram.c b/arch/arm/plat-mxs/iram.c new file mode 100644 index 000000000000..c63b0a2a9a10 --- /dev/null +++ b/arch/arm/plat-mxs/iram.c @@ -0,0 +1,67 @@ +/* + * 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/io.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/genalloc.h> + +static unsigned long iram_phys_base; +static __iomem void *iram_virt_base; +static struct gen_pool *iram_pool; + +#define iram_phys_to_virt(p) (iram_virt_base + ((p) - iram_phys_base)) + +void *iram_alloc(unsigned int size, unsigned long *dma_addr) +{ + if (!iram_pool) + return NULL; + + *dma_addr = gen_pool_alloc(iram_pool, size); + pr_debug("iram alloc - %dB@0x%p\n", size, (void *)*dma_addr); + + WARN_ON(!*dma_addr); + if (!*dma_addr) + return NULL; + + return iram_phys_to_virt(*dma_addr); +} +EXPORT_SYMBOL(iram_alloc); + +void iram_free(unsigned long addr, unsigned int size) +{ + if (!iram_pool) + return; + + gen_pool_free(iram_pool, addr, size); +} +EXPORT_SYMBOL(iram_free); + +int __init iram_init(unsigned long base, unsigned long size) +{ + iram_phys_base = base; + + iram_pool = gen_pool_create(12, -1); + gen_pool_add(iram_pool, base, size, -1); + iram_virt_base = ioremap(iram_phys_base, size); + + pr_info("i.MX IRAM pool: %ld KB@0x%p\n", size / 1024, iram_virt_base); + return 0; +} diff --git a/arch/arm/plat-mxs/lradc.c b/arch/arm/plat-mxs/lradc.c new file mode 100644 index 000000000000..3d9089e3ef25 --- /dev/null +++ b/arch/arm/plat-mxs/lradc.c @@ -0,0 +1,385 @@ +/* + * Freescale STMP37XX/STMP378X LRADC helper routines + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sysdev.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <mach/device.h> +#include <mach/regs-lradc.h> +#include <mach/lradc.h> + +struct lradc_device { + struct sys_device sys; + unsigned int base; + unsigned int vddio_voltage; + unsigned int battery_voltage; +}; + +static int channels[8]; + +static __refdata struct lradc_device mxs_lradc; + +int hw_lradc_use_channel(int channel) +{ + if (channel < 0 || channel > 7) + return -EINVAL; + channels[channel]++; + return 0; +} +EXPORT_SYMBOL(hw_lradc_use_channel); + +int hw_lradc_unuse_channel(int channel) +{ + if (channel < 0 || channel > 7) + return -EINVAL; + channels[channel]--; + return 0; +} +EXPORT_SYMBOL(hw_lradc_unuse_channel); + +void hw_lradc_reinit(int enable_ground_ref, unsigned freq) +{ + __raw_writel(BM_LRADC_CTRL0_SFTRST, + mxs_lradc.base + HW_LRADC_CTRL0_SET); + udelay(1); + __raw_writel(BM_LRADC_CTRL0_SFTRST, + mxs_lradc.base + HW_LRADC_CTRL0_CLR); + + /* Clear the Clock Gate for normal operation */ + __raw_writel(BM_LRADC_CTRL0_CLKGATE, + mxs_lradc.base + HW_LRADC_CTRL0_CLR); + + if (enable_ground_ref) + __raw_writel(BM_LRADC_CTRL0_ONCHIP_GROUNDREF, + mxs_lradc.base + HW_LRADC_CTRL0_SET); + else + __raw_writel(BM_LRADC_CTRL0_ONCHIP_GROUNDREF, + mxs_lradc.base + HW_LRADC_CTRL0_CLR); + + __raw_writel(BM_LRADC_CTRL3_CYCLE_TIME, + mxs_lradc.base + HW_LRADC_CTRL3_CLR); + __raw_writel(BF_LRADC_CTRL3_CYCLE_TIME(freq), + mxs_lradc.base + HW_LRADC_CTRL3_SET); + + __raw_writel(BM_LRADC_CTRL4_LRADC6SELECT | BM_LRADC_CTRL4_LRADC7SELECT, + mxs_lradc.base + HW_LRADC_CTRL4_CLR); + __raw_writel(BF_LRADC_CTRL4_LRADC6SELECT(mxs_lradc.vddio_voltage), + mxs_lradc.base + HW_LRADC_CTRL4_SET); + __raw_writel(BF_LRADC_CTRL4_LRADC7SELECT(mxs_lradc.battery_voltage), + mxs_lradc.base + HW_LRADC_CTRL4_SET); +} + +int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling) +{ + /* + * check if the lradc channel is present in this product + */ + if (!hw_lradc_present(channel)) + return -ENODEV; + + hw_lradc_configure_channel(channel, !0 /* div2 */ , + 0 /* acc */ , + 0 /* num_samples */); + + /* Setup the trigger loop forever */ + hw_lradc_set_delay_trigger(trigger, 1 << channel, + 1 << trigger, 0, sampling); + + /* Clear the accumulator & NUM_SAMPLES */ + __raw_writel(0xFFFFFFFF, mxs_lradc.base + HW_LRADC_CHn_CLR(channel)); + return 0; +} + +EXPORT_SYMBOL(hw_lradc_init_ladder); + +int hw_lradc_stop_ladder(int channel, int trigger) +{ + /* + * check if the lradc channel is present in this product + */ + if (!hw_lradc_present(channel)) + return -ENODEV; + hw_lradc_clear_delay_trigger(trigger, 1 << channel, 1 << trigger); + return 0; +} + +EXPORT_SYMBOL(hw_lradc_stop_ladder); + +int hw_lradc_present(int channel) +{ + if (channel < 0 || channel > 7) + return 0; + return __raw_readl(mxs_lradc.base + HW_LRADC_STATUS) + & (1 << (16 + channel)); +} + +EXPORT_SYMBOL(hw_lradc_present); + +void hw_lradc_configure_channel(int channel, int enable_div2, + int enable_acc, int samples) +{ + if (enable_div2) + __raw_writel(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1 << channel), + mxs_lradc.base + HW_LRADC_CTRL2_SET); + else + __raw_writel(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1 << channel), + mxs_lradc.base + HW_LRADC_CTRL2_CLR); + + /* Clear the accumulator & NUM_SAMPLES */ + __raw_writel(0xFFFFFFFF, mxs_lradc.base + HW_LRADC_CHn_CLR(channel)); + + /* Sets NUM_SAMPLES bitfield of HW_LRADC_CHn register. */ + __raw_writel(BM_LRADC_CHn_NUM_SAMPLES, + mxs_lradc.base + HW_LRADC_CHn_CLR(channel)); + __raw_writel(BF_LRADC_CHn_NUM_SAMPLES(samples), + mxs_lradc.base + HW_LRADC_CHn_SET(channel)); + + if (enable_acc) + __raw_writel(BM_LRADC_CHn_ACCUMULATE, + mxs_lradc.base + HW_LRADC_CHn_SET(channel)); + else + __raw_writel(BM_LRADC_CHn_ACCUMULATE, + mxs_lradc.base + HW_LRADC_CHn_CLR(channel)); +} + +EXPORT_SYMBOL(hw_lradc_configure_channel); + +void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers, u32 loops, u32 delays) +{ + /* set TRIGGER_LRADCS in HW_LRADC_DELAYn */ + __raw_writel(BF_LRADC_DELAYn_TRIGGER_LRADCS(trigger_lradc), + mxs_lradc.base + HW_LRADC_DELAYn_SET(trigger)); + __raw_writel(BF_LRADC_DELAYn_TRIGGER_DELAYS(delay_triggers), + mxs_lradc.base + HW_LRADC_DELAYn_SET(trigger)); + + __raw_writel(BM_LRADC_DELAYn_LOOP_COUNT | BM_LRADC_DELAYn_DELAY, + mxs_lradc.base + HW_LRADC_DELAYn_CLR(trigger)); + __raw_writel(BF_LRADC_DELAYn_LOOP_COUNT(loops), + mxs_lradc.base + HW_LRADC_DELAYn_SET(trigger)); + __raw_writel(BF_LRADC_DELAYn_DELAY(delays), + mxs_lradc.base + HW_LRADC_DELAYn_SET(trigger)); +} + +EXPORT_SYMBOL(hw_lradc_set_delay_trigger); + +void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers) +{ + __raw_writel(BF_LRADC_DELAYn_TRIGGER_LRADCS(trigger_lradc), + mxs_lradc.base + HW_LRADC_DELAYn_CLR(trigger)); + __raw_writel(BF_LRADC_DELAYn_TRIGGER_DELAYS(delay_triggers), + mxs_lradc.base + HW_LRADC_DELAYn_CLR(trigger)); +} + +EXPORT_SYMBOL(hw_lradc_clear_delay_trigger); + +void hw_lradc_set_delay_trigger_kick(int trigger, int value) +{ + if (value) + __raw_writel(BM_LRADC_DELAYn_KICK, + mxs_lradc.base + HW_LRADC_DELAYn_SET(trigger)); + else + __raw_writel(BM_LRADC_DELAYn_KICK, + mxs_lradc.base + HW_LRADC_DELAYn_CLR(trigger)); +} + +EXPORT_SYMBOL(hw_lradc_set_delay_trigger_kick); + +u32 hw_lradc_vddio(void) +{ + /* Clear the Soft Reset and Clock Gate for normal operation */ + __raw_writel(BM_LRADC_CTRL0_SFTRST | BM_LRADC_CTRL0_CLKGATE, + mxs_lradc.base + HW_LRADC_CTRL0_CLR); + + /* + * Clear the divide by two for channel 6 since + * it has a HW divide-by-two built in. + */ + __raw_writel(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1 << VDDIO_VOLTAGE_CH), + mxs_lradc.base + HW_LRADC_CTRL2_CLR); + + /* Clear the accumulator & NUM_SAMPLES */ + __raw_writel(0xFFFFFFFF, + mxs_lradc.base + HW_LRADC_CHn_CLR(VDDIO_VOLTAGE_CH)); + + /* Clear the interrupt flag */ + __raw_writel(BM_LRADC_CTRL1_LRADC6_IRQ, + mxs_lradc.base + HW_LRADC_CTRL1_CLR); + + /* + * Get VddIO; this is the max scale value for the button resistor + * ladder. + * schedule ch 6: + */ + __raw_writel(BF_LRADC_CTRL0_SCHEDULE(1 << VDDIO_VOLTAGE_CH), + mxs_lradc.base + HW_LRADC_CTRL0_SET); + + /* wait for completion */ + while ((__raw_readl(mxs_lradc.base + HW_LRADC_CTRL1) + & BM_LRADC_CTRL1_LRADC6_IRQ) != BM_LRADC_CTRL1_LRADC6_IRQ) + cpu_relax(); + + /* Clear the interrupt flag */ + __raw_writel(BM_LRADC_CTRL1_LRADC6_IRQ, + mxs_lradc.base + HW_LRADC_CTRL1_CLR); + + /* read ch 6 value. */ + return __raw_readl(mxs_lradc.base + HW_LRADC_CHn(VDDIO_VOLTAGE_CH)) & + BM_LRADC_CHn_VALUE; +} + +EXPORT_SYMBOL(hw_lradc_vddio); + +#ifdef CONFIG_PM +static u32 lradc_registers[0x16]; +static int do_gate; + +static int hw_lradc_suspend(struct sys_device *dev, pm_message_t state) +{ + int i; + + do_gate = 1; + for (i = 0; i < ARRAY_SIZE(channels); i++) + if (channels[i] > 0) { + do_gate = 0; + break; + } + + for (i = 0; i < ARRAY_SIZE(lradc_registers); i++) + lradc_registers[i] = __raw_readl(mxs_lradc.base + (i << 4)); + + if (do_gate) + __raw_writel(BM_LRADC_CTRL0_CLKGATE, + mxs_lradc.base + HW_LRADC_CTRL0_SET); + return 0; +} + +static int hw_lradc_resume(struct sys_device *dev) +{ + int i; + + if (do_gate) { + __raw_writel(BM_LRADC_CTRL0_SFTRST, + mxs_lradc.base + HW_LRADC_CTRL0_SET); + udelay(10); + __raw_writel(BM_LRADC_CTRL0_SFTRST | + BM_LRADC_CTRL0_CLKGATE, + mxs_lradc.base + HW_LRADC_CTRL0_CLR); + } + for (i = 0; i < ARRAY_SIZE(lradc_registers); i++) + __raw_writel(lradc_registers[i], mxs_lradc.base + (i << 4)); + return 0; +} + +#endif + +static struct sysdev_class mxs_lradc_sysclass = { + .name = "mxs-lradc", +#ifdef CONFIG_PM + .suspend = hw_lradc_suspend, + .resume = hw_lradc_resume, +#endif +}; + +static int lradc_freq = LRADC_CLOCK_6MHZ; + +static int __init lradc_freq_setup(char *str) +{ + long freq; + + if (strict_strtol(str, 0, &freq) < 0) + return 0; + + if (freq < 0) + return 0; + if (freq >= 6) + lradc_freq = LRADC_CLOCK_6MHZ; + else if (freq >= 4) + lradc_freq = LRADC_CLOCK_4MHZ; + else if (freq >= 3) + lradc_freq = LRADC_CLOCK_3MHZ; + else if (freq >= 2) + lradc_freq = LRADC_CLOCK_2MHZ; + else + return 0; + return 1; +} + +__setup("lradc_freq=", lradc_freq_setup); + +static int __devinit mxs_lradc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mxs_lradc_plat_data *plat_data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENODEV; + + plat_data = (struct mxs_lradc_plat_data *)(pdev->dev.platform_data); + if (plat_data == NULL) + return -EFAULT; + + mxs_lradc.base = (unsigned int)IO_ADDRESS(res->start); + mxs_lradc.sys.id = -1; + mxs_lradc.sys.cls = &mxs_lradc_sysclass; + mxs_lradc.vddio_voltage = plat_data->vddio_voltage; + mxs_lradc.battery_voltage = plat_data->battery_voltage; + hw_lradc_reinit(0, lradc_freq); + return sysdev_register(&mxs_lradc.sys); +} + +static int __devexit mxs_lradc_remove(struct platform_device *pdev) +{ + sysdev_unregister(&mxs_lradc.sys); + return 0; +} + +static __refdata struct platform_driver mxs_lradc_drv = { + .probe = mxs_lradc_probe, + .remove = __devexit_p(mxs_lradc_remove), + .driver = { + .name = "mxs-lradc", + .owner = THIS_MODULE, + } +}; + +static int __init hw_lradc_init(void) +{ + sysdev_class_register(&mxs_lradc_sysclass); + platform_driver_register(&mxs_lradc_drv); + return 0; +} + +static void __exit hw_lradc_exit(void) +{ + platform_driver_unregister(&mxs_lradc_drv); + sysdev_class_unregister(&mxs_lradc_sysclass); +} + +subsys_initcall(hw_lradc_init); +module_exit(hw_lradc_exit); diff --git a/arch/arm/plat-mxs/pinctrl.c b/arch/arm/plat-mxs/pinctrl.c new file mode 100644 index 000000000000..cdef3e02d495 --- /dev/null +++ b/arch/arm/plat-mxs/pinctrl.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2009-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/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/irq.h> + +#include <mach/pinctrl.h> + +static struct pinctrl_chip *g_chip; + +int mxs_request_pin(unsigned int pin, enum pin_fun fun, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + if (test_and_set_bit(index, &pb->bitmap)) + return -EBUSY; + pb->label[index] = lab; + if (g_chip->set_type) + g_chip->set_type(pb, index, fun); + return 0; +} +EXPORT_SYMBOL(mxs_request_pin); + +int mxs_get_type(unsigned int pin) +{ + int bank, index; + struct pin_bank *pb; + int ret = 0; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + if (g_chip->get_type) + ret = g_chip->get_type(pb, index); + return ret; +} +EXPORT_SYMBOL(mxs_get_type); + +int mxs_set_type(unsigned int pin, enum pin_fun fun, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + + if (!test_bit(index, &pb->bitmap)) + return -ENOLCK; + if (lab != pb->label[index]) /* label is const string */ + return -EINVAL; + if (g_chip->set_type) + g_chip->set_type(pb, index, fun); + return 0; +} +EXPORT_SYMBOL(mxs_set_type); + +int mxs_set_strength(unsigned int pin, enum pad_strength cfg, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + + if (!test_bit(index, &pb->bitmap)) + return -ENOLCK; + if (lab != pb->label[index]) /* label is const string */ + return -EINVAL; + if (g_chip->set_strength) + g_chip->set_strength(pb, index, cfg); + return 0; +} +EXPORT_SYMBOL(mxs_set_strength); + +int mxs_set_voltage(unsigned int pin, enum pad_voltage cfg, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + + if (!test_bit(index, &pb->bitmap)) + return -ENOLCK; + if (lab != pb->label[index]) /* label is const string */ + return -EINVAL; + if (g_chip->set_voltage) + g_chip->set_voltage(pb, index, cfg); + return 0; +} +EXPORT_SYMBOL(mxs_set_voltage); + +int mxs_set_pullup(unsigned int pin, int en, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + + if (!test_bit(index, &pb->bitmap)) + return -ENOLCK; + if (lab != pb->label[index]) /* label is const string */ + return -EINVAL; + if (g_chip->set_pullup) + g_chip->set_pullup(pb, index, en); + return 0; +} +EXPORT_SYMBOL(mxs_set_pullup); + +void mxs_release_pin(unsigned int pin, const char *lab) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return; + + pb = g_chip->banks + bank; + + if (!test_bit(index, &pb->bitmap)) + return; + if (lab != pb->label[index]) /* label is const string */ + return; + pb->label[index] = NULL; + + clear_bit(index, &pb->bitmap); +} +EXPORT_SYMBOL(mxs_release_pin); + +unsigned int mxs_pin2gpio(unsigned int pin) +{ + int bank, index; + struct pin_bank *pb; + if (g_chip == NULL) + return -ENODEV; + + if (!g_chip->get_gpio) + return -ENODEV; + + bank = g_chip->pin2id(g_chip, pin, &index); + if (bank < 0 || index < 0 || bank >= g_chip->bank_size) + return -EFAULT; + + pb = g_chip->banks + bank; + + return g_chip->get_gpio(pb, index); +} + +int __init mxs_set_pinctrl_chip(struct pinctrl_chip *chip) +{ + if (!(chip && chip->banks && chip->bank_size && + chip->get_gpio && chip->pin2id)) + return -EINVAL; + + if (g_chip) + return -EEXIST; + g_chip = chip; + return 0; +}; diff --git a/arch/arm/plat-mxs/regs-apbx.h b/arch/arm/plat-mxs/regs-apbx.h new file mode 100644 index 000000000000..f788f1303ece --- /dev/null +++ b/arch/arm/plat-mxs/regs-apbx.h @@ -0,0 +1,433 @@ +/* + * Freescale APBX 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.30 + * Template revision: 26195 + */ + +#ifndef __ARCH_ARM___APBX_H +#define __ARCH_ARM___APBX_H + +#define HW_APBX_CTRL0 (0x00000000) +#define HW_APBX_CTRL0_SET (0x00000004) +#define HW_APBX_CTRL0_CLR (0x00000008) +#define HW_APBX_CTRL0_TOG (0x0000000c) + +#define BM_APBX_CTRL0_SFTRST 0x80000000 +#define BM_APBX_CTRL0_CLKGATE 0x40000000 +#define BP_APBX_CTRL0_RSVD0 0 +#define BM_APBX_CTRL0_RSVD0 0x3FFFFFFF +#define BF_APBX_CTRL0_RSVD0(v) \ + (((v) << 0) & BM_APBX_CTRL0_RSVD0) + +#define HW_APBX_CTRL1 (0x00000010) +#define HW_APBX_CTRL1_SET (0x00000014) +#define HW_APBX_CTRL1_CLR (0x00000018) +#define HW_APBX_CTRL1_TOG (0x0000001c) + +#define BM_APBX_CTRL1_CH15_CMDCMPLT_IRQ_EN 0x80000000 +#define BM_APBX_CTRL1_CH14_CMDCMPLT_IRQ_EN 0x40000000 +#define BM_APBX_CTRL1_CH13_CMDCMPLT_IRQ_EN 0x20000000 +#define BM_APBX_CTRL1_CH12_CMDCMPLT_IRQ_EN 0x10000000 +#define BM_APBX_CTRL1_CH11_CMDCMPLT_IRQ_EN 0x08000000 +#define BM_APBX_CTRL1_CH10_CMDCMPLT_IRQ_EN 0x04000000 +#define BM_APBX_CTRL1_CH9_CMDCMPLT_IRQ_EN 0x02000000 +#define BM_APBX_CTRL1_CH8_CMDCMPLT_IRQ_EN 0x01000000 +#define BM_APBX_CTRL1_CH7_CMDCMPLT_IRQ_EN 0x00800000 +#define BM_APBX_CTRL1_CH6_CMDCMPLT_IRQ_EN 0x00400000 +#define BM_APBX_CTRL1_CH5_CMDCMPLT_IRQ_EN 0x00200000 +#define BM_APBX_CTRL1_CH4_CMDCMPLT_IRQ_EN 0x00100000 +#define BM_APBX_CTRL1_CH3_CMDCMPLT_IRQ_EN 0x00080000 +#define BM_APBX_CTRL1_CH2_CMDCMPLT_IRQ_EN 0x00040000 +#define BM_APBX_CTRL1_CH1_CMDCMPLT_IRQ_EN 0x00020000 +#define BM_APBX_CTRL1_CH0_CMDCMPLT_IRQ_EN 0x00010000 +#define BM_APBX_CTRL1_CH15_CMDCMPLT_IRQ 0x00008000 +#define BM_APBX_CTRL1_CH14_CMDCMPLT_IRQ 0x00004000 +#define BM_APBX_CTRL1_CH13_CMDCMPLT_IRQ 0x00002000 +#define BM_APBX_CTRL1_CH12_CMDCMPLT_IRQ 0x00001000 +#define BM_APBX_CTRL1_CH11_CMDCMPLT_IRQ 0x00000800 +#define BM_APBX_CTRL1_CH10_CMDCMPLT_IRQ 0x00000400 +#define BM_APBX_CTRL1_CH9_CMDCMPLT_IRQ 0x00000200 +#define BM_APBX_CTRL1_CH8_CMDCMPLT_IRQ 0x00000100 +#define BM_APBX_CTRL1_CH7_CMDCMPLT_IRQ 0x00000080 +#define BM_APBX_CTRL1_CH6_CMDCMPLT_IRQ 0x00000040 +#define BM_APBX_CTRL1_CH5_CMDCMPLT_IRQ 0x00000020 +#define BM_APBX_CTRL1_CH4_CMDCMPLT_IRQ 0x00000010 +#define BM_APBX_CTRL1_CH3_CMDCMPLT_IRQ 0x00000008 +#define BM_APBX_CTRL1_CH2_CMDCMPLT_IRQ 0x00000004 +#define BM_APBX_CTRL1_CH1_CMDCMPLT_IRQ 0x00000002 +#define BM_APBX_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001 + +#define HW_APBX_CTRL2 (0x00000020) +#define HW_APBX_CTRL2_SET (0x00000024) +#define HW_APBX_CTRL2_CLR (0x00000028) +#define HW_APBX_CTRL2_TOG (0x0000002c) + +#define BM_APBX_CTRL2_CH15_ERROR_STATUS 0x80000000 +#define BV_APBX_CTRL2_CH15_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH15_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH14_ERROR_STATUS 0x40000000 +#define BV_APBX_CTRL2_CH14_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH14_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH13_ERROR_STATUS 0x20000000 +#define BV_APBX_CTRL2_CH13_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH13_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH12_ERROR_STATUS 0x10000000 +#define BV_APBX_CTRL2_CH12_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH12_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH11_ERROR_STATUS 0x08000000 +#define BV_APBX_CTRL2_CH11_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH11_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH10_ERROR_STATUS 0x04000000 +#define BV_APBX_CTRL2_CH10_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH10_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH9_ERROR_STATUS 0x02000000 +#define BV_APBX_CTRL2_CH9_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH9_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH8_ERROR_STATUS 0x01000000 +#define BV_APBX_CTRL2_CH8_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH8_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH7_ERROR_STATUS 0x00800000 +#define BV_APBX_CTRL2_CH7_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH7_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH6_ERROR_STATUS 0x00400000 +#define BV_APBX_CTRL2_CH6_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH6_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH5_ERROR_STATUS 0x00200000 +#define BV_APBX_CTRL2_CH5_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH5_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH4_ERROR_STATUS 0x00100000 +#define BV_APBX_CTRL2_CH4_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH4_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH3_ERROR_STATUS 0x00080000 +#define BV_APBX_CTRL2_CH3_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH3_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH2_ERROR_STATUS 0x00040000 +#define BV_APBX_CTRL2_CH2_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH2_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH1_ERROR_STATUS 0x00020000 +#define BV_APBX_CTRL2_CH1_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH1_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH0_ERROR_STATUS 0x00010000 +#define BV_APBX_CTRL2_CH0_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH0_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH15_ERROR_IRQ 0x00008000 +#define BM_APBX_CTRL2_CH14_ERROR_IRQ 0x00004000 +#define BM_APBX_CTRL2_CH13_ERROR_IRQ 0x00002000 +#define BM_APBX_CTRL2_CH12_ERROR_IRQ 0x00001000 +#define BM_APBX_CTRL2_CH11_ERROR_IRQ 0x00000800 +#define BM_APBX_CTRL2_CH10_ERROR_IRQ 0x00000400 +#define BM_APBX_CTRL2_CH9_ERROR_IRQ 0x00000200 +#define BM_APBX_CTRL2_CH8_ERROR_IRQ 0x00000100 +#define BM_APBX_CTRL2_CH7_ERROR_IRQ 0x00000080 +#define BM_APBX_CTRL2_CH6_ERROR_IRQ 0x00000040 +#define BM_APBX_CTRL2_CH5_ERROR_IRQ 0x00000020 +#define BM_APBX_CTRL2_CH4_ERROR_IRQ 0x00000010 +#define BM_APBX_CTRL2_CH3_ERROR_IRQ 0x00000008 +#define BM_APBX_CTRL2_CH2_ERROR_IRQ 0x00000004 +#define BM_APBX_CTRL2_CH1_ERROR_IRQ 0x00000002 +#define BM_APBX_CTRL2_CH0_ERROR_IRQ 0x00000001 + +#define HW_APBX_CHANNEL_CTRL (0x00000030) +#define HW_APBX_CHANNEL_CTRL_SET (0x00000034) +#define HW_APBX_CHANNEL_CTRL_CLR (0x00000038) +#define HW_APBX_CHANNEL_CTRL_TOG (0x0000003c) + +#define BP_APBX_CHANNEL_CTRL_RESET_CHANNEL 16 +#define BM_APBX_CHANNEL_CTRL_RESET_CHANNEL 0xFFFF0000 +#define BF_APBX_CHANNEL_CTRL_RESET_CHANNEL(v) \ + (((v) << 16) & BM_APBX_CHANNEL_CTRL_RESET_CHANNEL) +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART4_RX 0x0001 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART4_TX 0x0002 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SPDIF_TX 0x0004 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SAIF0 0x0010 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SAIF1 0x0020 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__I2C0 0x0040 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__I2C1 0x0080 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART0_RX 0x0100 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART0_TX 0x0200 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART1_RX 0x0400 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART1_TX 0x0800 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART2_RX 0x1000 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART2_TX 0x2000 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART3_RX 0x4000 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART3_TX 0x8000 +#define BP_APBX_CHANNEL_CTRL_FREEZE_CHANNEL 0 +#define BM_APBX_CHANNEL_CTRL_FREEZE_CHANNEL 0x0000FFFF +#define BF_APBX_CHANNEL_CTRL_FREEZE_CHANNEL(v) \ + (((v) << 0) & BM_APBX_CHANNEL_CTRL_FREEZE_CHANNEL) +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART4_RX 0x0001 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART4_TX 0x0002 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SPDIF_TX 0x0004 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SAIF0 0x0010 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SAIF1 0x0020 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__I2C0 0x0040 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__I2C1 0x0080 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART0_RX 0x0100 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART0_TX 0x0200 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART1_RX 0x0400 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART1_TX 0x0800 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART2_RX 0x1000 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART2_TX 0x2000 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART3_RX 0x4000 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART3_TX 0x8000 + +#define HW_APBX_DEVSEL (0x00000040) +#define HW_APBX_DEVSEL_SET (0x00000044) +#define HW_APBX_DEVSEL_CLR (0x00000048) +#define HW_APBX_DEVSEL_TOG (0x0000004c) + +#define BP_APBX_DEVSEL_CH15 30 +#define BM_APBX_DEVSEL_CH15 0xC0000000 +#define BF_APBX_DEVSEL_CH15(v) \ + (((v) << 30) & BM_APBX_DEVSEL_CH15) +#define BP_APBX_DEVSEL_CH14 28 +#define BM_APBX_DEVSEL_CH14 0x30000000 +#define BF_APBX_DEVSEL_CH14(v) \ + (((v) << 28) & BM_APBX_DEVSEL_CH14) +#define BP_APBX_DEVSEL_CH13 26 +#define BM_APBX_DEVSEL_CH13 0x0C000000 +#define BF_APBX_DEVSEL_CH13(v) \ + (((v) << 26) & BM_APBX_DEVSEL_CH13) +#define BP_APBX_DEVSEL_CH12 24 +#define BM_APBX_DEVSEL_CH12 0x03000000 +#define BF_APBX_DEVSEL_CH12(v) \ + (((v) << 24) & BM_APBX_DEVSEL_CH12) +#define BP_APBX_DEVSEL_CH11 22 +#define BM_APBX_DEVSEL_CH11 0x00C00000 +#define BF_APBX_DEVSEL_CH11(v) \ + (((v) << 22) & BM_APBX_DEVSEL_CH11) +#define BP_APBX_DEVSEL_CH10 20 +#define BM_APBX_DEVSEL_CH10 0x00300000 +#define BF_APBX_DEVSEL_CH10(v) \ + (((v) << 20) & BM_APBX_DEVSEL_CH10) +#define BP_APBX_DEVSEL_CH9 18 +#define BM_APBX_DEVSEL_CH9 0x000C0000 +#define BF_APBX_DEVSEL_CH9(v) \ + (((v) << 18) & BM_APBX_DEVSEL_CH9) +#define BP_APBX_DEVSEL_CH8 16 +#define BM_APBX_DEVSEL_CH8 0x00030000 +#define BF_APBX_DEVSEL_CH8(v) \ + (((v) << 16) & BM_APBX_DEVSEL_CH8) +#define BP_APBX_DEVSEL_CH7 14 +#define BM_APBX_DEVSEL_CH7 0x0000C000 +#define BF_APBX_DEVSEL_CH7(v) \ + (((v) << 14) & BM_APBX_DEVSEL_CH7) +#define BP_APBX_DEVSEL_CH6 12 +#define BM_APBX_DEVSEL_CH6 0x00003000 +#define BF_APBX_DEVSEL_CH6(v) \ + (((v) << 12) & BM_APBX_DEVSEL_CH6) +#define BP_APBX_DEVSEL_CH5 10 +#define BM_APBX_DEVSEL_CH5 0x00000C00 +#define BF_APBX_DEVSEL_CH5(v) \ + (((v) << 10) & BM_APBX_DEVSEL_CH5) +#define BP_APBX_DEVSEL_CH4 8 +#define BM_APBX_DEVSEL_CH4 0x00000300 +#define BF_APBX_DEVSEL_CH4(v) \ + (((v) << 8) & BM_APBX_DEVSEL_CH4) +#define BP_APBX_DEVSEL_CH3 6 +#define BM_APBX_DEVSEL_CH3 0x000000C0 +#define BF_APBX_DEVSEL_CH3(v) \ + (((v) << 6) & BM_APBX_DEVSEL_CH3) +#define BP_APBX_DEVSEL_CH2 4 +#define BM_APBX_DEVSEL_CH2 0x00000030 +#define BF_APBX_DEVSEL_CH2(v) \ + (((v) << 4) & BM_APBX_DEVSEL_CH2) +#define BP_APBX_DEVSEL_CH1 2 +#define BM_APBX_DEVSEL_CH1 0x0000000C +#define BF_APBX_DEVSEL_CH1(v) \ + (((v) << 2) & BM_APBX_DEVSEL_CH1) +#define BP_APBX_DEVSEL_CH0 0 +#define BM_APBX_DEVSEL_CH0 0x00000003 +#define BF_APBX_DEVSEL_CH0(v) \ + (((v) << 0) & BM_APBX_DEVSEL_CH0) + +/* + * multi-register-define name HW_APBX_CHn_CURCMDAR + * base 0x00000100 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_CURCMDAR(n) (0x00000100 + (n) * 0x70) +#define BP_APBX_CHn_CURCMDAR_CMD_ADDR 0 +#define BM_APBX_CHn_CURCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBX_CHn_CURCMDAR_CMD_ADDR(v) (v) + +/* + * multi-register-define name HW_APBX_CHn_NXTCMDAR + * base 0x00000110 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_NXTCMDAR(n) (0x00000110 + (n) * 0x70) +#define BP_APBX_CHn_NXTCMDAR_CMD_ADDR 0 +#define BM_APBX_CHn_NXTCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBX_CHn_NXTCMDAR_CMD_ADDR(v) (v) + +/* + * multi-register-define name HW_APBX_CHn_CMD + * base 0x00000120 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_CMD(n) (0x00000120 + (n) * 0x70) +#define BP_APBX_CHn_CMD_XFER_COUNT 16 +#define BM_APBX_CHn_CMD_XFER_COUNT 0xFFFF0000 +#define BF_APBX_CHn_CMD_XFER_COUNT(v) \ + (((v) << 16) & BM_APBX_CHn_CMD_XFER_COUNT) +#define BP_APBX_CHn_CMD_CMDWORDS 12 +#define BM_APBX_CHn_CMD_CMDWORDS 0x0000F000 +#define BF_APBX_CHn_CMD_CMDWORDS(v) \ + (((v) << 12) & BM_APBX_CHn_CMD_CMDWORDS) +#define BP_APBX_CHn_CMD_RSVD1 10 +#define BM_APBX_CHn_CMD_RSVD1 0x00000C00 +#define BF_APBX_CHn_CMD_RSVD1(v) \ + (((v) << 10) & BM_APBX_CHn_CMD_RSVD1) +#define BM_APBX_CHn_CMD_TERMINATEFLUSH 0x00000200 +#define BM_APBX_CHn_CMD_HALTONTERMINATE 0x00000100 +#define BM_APBX_CHn_CMD_WAIT4ENDCMD 0x00000080 +#define BM_APBX_CHn_CMD_SEMAPHORE 0x00000040 +#define BP_APBX_CHn_CMD_RSVD0 4 +#define BM_APBX_CHn_CMD_RSVD0 0x00000030 +#define BF_APBX_CHn_CMD_RSVD0(v) \ + (((v) << 4) & BM_APBX_CHn_CMD_RSVD0) +#define BM_APBX_CHn_CMD_IRQONCMPLT 0x00000008 +#define BM_APBX_CHn_CMD_CHAIN 0x00000004 +#define BP_APBX_CHn_CMD_COMMAND 0 +#define BM_APBX_CHn_CMD_COMMAND 0x00000003 +#define BF_APBX_CHn_CMD_COMMAND(v) \ + (((v) << 0) & BM_APBX_CHn_CMD_COMMAND) +#define BV_APBX_CHn_CMD_COMMAND__NO_DMA_XFER 0x0 +#define BV_APBX_CHn_CMD_COMMAND__DMA_WRITE 0x1 +#define BV_APBX_CHn_CMD_COMMAND__DMA_READ 0x2 + +/* + * multi-register-define name HW_APBX_CHn_BAR + * base 0x00000130 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_BAR(n) (0x00000130 + (n) * 0x70) +#define BP_APBX_CHn_BAR_ADDRESS 0 +#define BM_APBX_CHn_BAR_ADDRESS 0xFFFFFFFF +#define BF_APBX_CHn_BAR_ADDRESS(v) (v) + +/* + * multi-register-define name HW_APBX_CHn_SEMA + * base 0x00000140 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_SEMA(n) (0x00000140 + (n) * 0x70) +#define BP_APBX_CHn_SEMA_RSVD2 24 +#define BM_APBX_CHn_SEMA_RSVD2 0xFF000000 +#define BF_APBX_CHn_SEMA_RSVD2(v) \ + (((v) << 24) & BM_APBX_CHn_SEMA_RSVD2) +#define BP_APBX_CHn_SEMA_PHORE 16 +#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000 +#define BF_APBX_CHn_SEMA_PHORE(v) \ + (((v) << 16) & BM_APBX_CHn_SEMA_PHORE) +#define BP_APBX_CHn_SEMA_RSVD1 8 +#define BM_APBX_CHn_SEMA_RSVD1 0x0000FF00 +#define BF_APBX_CHn_SEMA_RSVD1(v) \ + (((v) << 8) & BM_APBX_CHn_SEMA_RSVD1) +#define BP_APBX_CHn_SEMA_INCREMENT_SEMA 0 +#define BM_APBX_CHn_SEMA_INCREMENT_SEMA 0x000000FF +#define BF_APBX_CHn_SEMA_INCREMENT_SEMA(v) \ + (((v) << 0) & BM_APBX_CHn_SEMA_INCREMENT_SEMA) + +/* + * multi-register-define name HW_APBX_CHn_DEBUG1 + * base 0x00000150 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_DEBUG1(n) (0x00000150 + (n) * 0x70) +#define BM_APBX_CHn_DEBUG1_REQ 0x80000000 +#define BM_APBX_CHn_DEBUG1_BURST 0x40000000 +#define BM_APBX_CHn_DEBUG1_KICK 0x20000000 +#define BM_APBX_CHn_DEBUG1_END 0x10000000 +#define BP_APBX_CHn_DEBUG1_RSVD2 25 +#define BM_APBX_CHn_DEBUG1_RSVD2 0x0E000000 +#define BF_APBX_CHn_DEBUG1_RSVD2(v) \ + (((v) << 25) & BM_APBX_CHn_DEBUG1_RSVD2) +#define BM_APBX_CHn_DEBUG1_NEXTCMDADDRVALID 0x01000000 +#define BM_APBX_CHn_DEBUG1_RD_FIFO_EMPTY 0x00800000 +#define BM_APBX_CHn_DEBUG1_RD_FIFO_FULL 0x00400000 +#define BM_APBX_CHn_DEBUG1_WR_FIFO_EMPTY 0x00200000 +#define BM_APBX_CHn_DEBUG1_WR_FIFO_FULL 0x00100000 +#define BP_APBX_CHn_DEBUG1_RSVD1 5 +#define BM_APBX_CHn_DEBUG1_RSVD1 0x000FFFE0 +#define BF_APBX_CHn_DEBUG1_RSVD1(v) \ + (((v) << 5) & BM_APBX_CHn_DEBUG1_RSVD1) +#define BP_APBX_CHn_DEBUG1_STATEMACHINE 0 +#define BM_APBX_CHn_DEBUG1_STATEMACHINE 0x0000001F +#define BF_APBX_CHn_DEBUG1_STATEMACHINE(v) \ + (((v) << 0) & BM_APBX_CHn_DEBUG1_STATEMACHINE) +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__IDLE 0x00 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD1 0x01 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD3 0x02 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD2 0x03 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__XFER_DECODE 0x04 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_WAIT 0x05 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD4 0x06 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__PIO_REQ 0x07 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_FLUSH 0x08 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_WAIT 0x09 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WRITE 0x0C +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_REQ 0x0D +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__CHECK_CHAIN 0x0E +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__XFER_COMPLETE 0x0F +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WAIT_END 0x15 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WRITE_WAIT 0x1C +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__CHECK_WAIT 0x1E + +/* + * multi-register-define name HW_APBX_CHn_DEBUG2 + * base 0x00000160 + * count 16 + * offset 0x70 + */ +#define HW_APBX_CHn_DEBUG2(n) (0x00000160 + (n) * 0x70) +#define BP_APBX_CHn_DEBUG2_APB_BYTES 16 +#define BM_APBX_CHn_DEBUG2_APB_BYTES 0xFFFF0000 +#define BF_APBX_CHn_DEBUG2_APB_BYTES(v) \ + (((v) << 16) & BM_APBX_CHn_DEBUG2_APB_BYTES) +#define BP_APBX_CHn_DEBUG2_AHB_BYTES 0 +#define BM_APBX_CHn_DEBUG2_AHB_BYTES 0x0000FFFF +#define BF_APBX_CHn_DEBUG2_AHB_BYTES(v) \ + (((v) << 0) & BM_APBX_CHn_DEBUG2_AHB_BYTES) + +#define HW_APBX_VERSION (0x00000800) + +#define BP_APBX_VERSION_MAJOR 24 +#define BM_APBX_VERSION_MAJOR 0xFF000000 +#define BF_APBX_VERSION_MAJOR(v) \ + (((v) << 24) & BM_APBX_VERSION_MAJOR) +#define BP_APBX_VERSION_MINOR 16 +#define BM_APBX_VERSION_MINOR 0x00FF0000 +#define BF_APBX_VERSION_MINOR(v) \ + (((v) << 16) & BM_APBX_VERSION_MINOR) +#define BP_APBX_VERSION_STEP 0 +#define BM_APBX_VERSION_STEP 0x0000FFFF +#define BF_APBX_VERSION_STEP(v) \ + (((v) << 0) & BM_APBX_VERSION_STEP) +#endif /* __ARCH_ARM___APBX_H */ diff --git a/arch/arm/plat-mxs/regs-icoll.h b/arch/arm/plat-mxs/regs-icoll.h new file mode 100644 index 000000000000..f06ac0d4720b --- /dev/null +++ b/arch/arm/plat-mxs/regs-icoll.h @@ -0,0 +1,293 @@ +/* + * Freescale ICOLL 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.50 + * Template revision: 26195 + */ + +#ifndef __ARCH_ARM___ICOLL_H +#define __ARCH_ARM___ICOLL_H + +#define HW_ICOLL_VECTOR (0x00000000) +#define HW_ICOLL_VECTOR_SET (0x00000004) +#define HW_ICOLL_VECTOR_CLR (0x00000008) +#define HW_ICOLL_VECTOR_TOG (0x0000000c) + +#define BP_ICOLL_VECTOR_IRQVECTOR 2 +#define BM_ICOLL_VECTOR_IRQVECTOR 0xFFFFFFFC +#define BF_ICOLL_VECTOR_IRQVECTOR(v) \ + (((v) << 2) & BM_ICOLL_VECTOR_IRQVECTOR) +#define BP_ICOLL_VECTOR_RSRVD1 0 +#define BM_ICOLL_VECTOR_RSRVD1 0x00000003 +#define BF_ICOLL_VECTOR_RSRVD1(v) \ + (((v) << 0) & BM_ICOLL_VECTOR_RSRVD1) + +#define HW_ICOLL_LEVELACK (0x00000010) + +#define BP_ICOLL_LEVELACK_RSRVD1 4 +#define BM_ICOLL_LEVELACK_RSRVD1 0xFFFFFFF0 +#define BF_ICOLL_LEVELACK_RSRVD1(v) \ + (((v) << 4) & BM_ICOLL_LEVELACK_RSRVD1) +#define BP_ICOLL_LEVELACK_IRQLEVELACK 0 +#define BM_ICOLL_LEVELACK_IRQLEVELACK 0x0000000F +#define BF_ICOLL_LEVELACK_IRQLEVELACK(v) \ + (((v) << 0) & BM_ICOLL_LEVELACK_IRQLEVELACK) +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL1 0x2 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL2 0x4 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL3 0x8 + +#define HW_ICOLL_CTRL (0x00000020) +#define HW_ICOLL_CTRL_SET (0x00000024) +#define HW_ICOLL_CTRL_CLR (0x00000028) +#define HW_ICOLL_CTRL_TOG (0x0000002c) + +#define BM_ICOLL_CTRL_SFTRST 0x80000000 +#define BV_ICOLL_CTRL_SFTRST__RUN 0x0 +#define BV_ICOLL_CTRL_SFTRST__IN_RESET 0x1 +#define BM_ICOLL_CTRL_CLKGATE 0x40000000 +#define BV_ICOLL_CTRL_CLKGATE__RUN 0x0 +#define BV_ICOLL_CTRL_CLKGATE__NO_CLOCKS 0x1 +#define BP_ICOLL_CTRL_RSRVD3 24 +#define BM_ICOLL_CTRL_RSRVD3 0x3F000000 +#define BF_ICOLL_CTRL_RSRVD3(v) \ + (((v) << 24) & BM_ICOLL_CTRL_RSRVD3) +#define BP_ICOLL_CTRL_VECTOR_PITCH 21 +#define BM_ICOLL_CTRL_VECTOR_PITCH 0x00E00000 +#define BF_ICOLL_CTRL_VECTOR_PITCH(v) \ + (((v) << 21) & BM_ICOLL_CTRL_VECTOR_PITCH) +#define BV_ICOLL_CTRL_VECTOR_PITCH__DEFAULT_BY4 0x0 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY4 0x1 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY8 0x2 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY12 0x3 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY16 0x4 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY20 0x5 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY24 0x6 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY28 0x7 +#define BM_ICOLL_CTRL_BYPASS_FSM 0x00100000 +#define BV_ICOLL_CTRL_BYPASS_FSM__NORMAL 0x0 +#define BV_ICOLL_CTRL_BYPASS_FSM__BYPASS 0x1 +#define BM_ICOLL_CTRL_NO_NESTING 0x00080000 +#define BV_ICOLL_CTRL_NO_NESTING__NORMAL 0x0 +#define BV_ICOLL_CTRL_NO_NESTING__NO_NEST 0x1 +#define BM_ICOLL_CTRL_ARM_RSE_MODE 0x00040000 +#define BM_ICOLL_CTRL_FIQ_FINAL_ENABLE 0x00020000 +#define BV_ICOLL_CTRL_FIQ_FINAL_ENABLE__DISABLE 0x0 +#define BV_ICOLL_CTRL_FIQ_FINAL_ENABLE__ENABLE 0x1 +#define BM_ICOLL_CTRL_IRQ_FINAL_ENABLE 0x00010000 +#define BV_ICOLL_CTRL_IRQ_FINAL_ENABLE__DISABLE 0x0 +#define BV_ICOLL_CTRL_IRQ_FINAL_ENABLE__ENABLE 0x1 +#define BP_ICOLL_CTRL_RSRVD1 0 +#define BM_ICOLL_CTRL_RSRVD1 0x0000FFFF +#define BF_ICOLL_CTRL_RSRVD1(v) \ + (((v) << 0) & BM_ICOLL_CTRL_RSRVD1) + +#define HW_ICOLL_VBASE (0x00000040) +#define HW_ICOLL_VBASE_SET (0x00000044) +#define HW_ICOLL_VBASE_CLR (0x00000048) +#define HW_ICOLL_VBASE_TOG (0x0000004c) + +#define BP_ICOLL_VBASE_TABLE_ADDRESS 2 +#define BM_ICOLL_VBASE_TABLE_ADDRESS 0xFFFFFFFC +#define BF_ICOLL_VBASE_TABLE_ADDRESS(v) \ + (((v) << 2) & BM_ICOLL_VBASE_TABLE_ADDRESS) +#define BP_ICOLL_VBASE_RSRVD1 0 +#define BM_ICOLL_VBASE_RSRVD1 0x00000003 +#define BF_ICOLL_VBASE_RSRVD1(v) \ + (((v) << 0) & BM_ICOLL_VBASE_RSRVD1) + +#define HW_ICOLL_STAT (0x00000070) + +#define BP_ICOLL_STAT_RSRVD1 7 +#define BM_ICOLL_STAT_RSRVD1 0xFFFFFF80 +#define BF_ICOLL_STAT_RSRVD1(v) \ + (((v) << 7) & BM_ICOLL_STAT_RSRVD1) +#define BP_ICOLL_STAT_VECTOR_NUMBER 0 +#define BM_ICOLL_STAT_VECTOR_NUMBER 0x0000007F +#define BF_ICOLL_STAT_VECTOR_NUMBER(v) \ + (((v) << 0) & BM_ICOLL_STAT_VECTOR_NUMBER) + +/* + * multi-register-define name HW_ICOLL_RAWn + * base 0x000000A0 + * count 4 + * offset 0x10 + */ +#define HW_ICOLL_RAWn(n) (0x000000a0 + (n) * 0x10) +#define HW_ICOLL_RAWn_SET(n) (0x000000a4 + (n) * 0x10) +#define HW_ICOLL_RAWn_CLR(n) (0x000000a8 + (n) * 0x10) +#define HW_ICOLL_RAWn_TOG(n) (0x000000ac + (n) * 0x10) +#define BP_ICOLL_RAWn_RAW_IRQS 0 +#define BM_ICOLL_RAWn_RAW_IRQS 0xFFFFFFFF +#define BF_ICOLL_RAWn_RAW_IRQS(v) (v) + +/* + * multi-register-define name HW_ICOLL_INTERRUPTn + * base 0x00000120 + * count 128 + * offset 0x10 + */ +#define HW_ICOLL_INTERRUPTn(n) (0x00000120 + (n) * 0x10) +#define HW_ICOLL_INTERRUPTn_SET(n) (0x00000124 + (n) * 0x10) +#define HW_ICOLL_INTERRUPTn_CLR(n) (0x00000128 + (n) * 0x10) +#define HW_ICOLL_INTERRUPTn_TOG(n) (0x0000012c + (n) * 0x10) +#define BP_ICOLL_INTERRUPTn_RSRVD1 5 +#define BM_ICOLL_INTERRUPTn_RSRVD1 0xFFFFFFE0 +#define BF_ICOLL_INTERRUPTn_RSRVD1(v) \ + (((v) << 5) & BM_ICOLL_INTERRUPTn_RSRVD1) +#define BM_ICOLL_INTERRUPTn_ENFIQ 0x00000010 +#define BV_ICOLL_INTERRUPTn_ENFIQ__DISABLE 0x0 +#define BV_ICOLL_INTERRUPTn_ENFIQ__ENABLE 0x1 +#define BM_ICOLL_INTERRUPTn_SOFTIRQ 0x00000008 +#define BV_ICOLL_INTERRUPTn_SOFTIRQ__NO_INTERRUPT 0x0 +#define BV_ICOLL_INTERRUPTn_SOFTIRQ__FORCE_INTERRUPT 0x1 +#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004 +#define BV_ICOLL_INTERRUPTn_ENABLE__DISABLE 0x0 +#define BV_ICOLL_INTERRUPTn_ENABLE__ENABLE 0x1 +#define BP_ICOLL_INTERRUPTn_PRIORITY 0 +#define BM_ICOLL_INTERRUPTn_PRIORITY 0x00000003 +#define BF_ICOLL_INTERRUPTn_PRIORITY(v) \ + (((v) << 0) & BM_ICOLL_INTERRUPTn_PRIORITY) +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL0 0x0 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL1 0x1 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL2 0x2 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL3 0x3 + +#define HW_ICOLL_DEBUG (0x00001120) +#define HW_ICOLL_DEBUG_SET (0x00001124) +#define HW_ICOLL_DEBUG_CLR (0x00001128) +#define HW_ICOLL_DEBUG_TOG (0x0000112c) + +#define BP_ICOLL_DEBUG_INSERVICE 28 +#define BM_ICOLL_DEBUG_INSERVICE 0xF0000000 +#define BF_ICOLL_DEBUG_INSERVICE(v) \ + (((v) << 28) & BM_ICOLL_DEBUG_INSERVICE) +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL3 0x8 +#define BP_ICOLL_DEBUG_LEVEL_REQUESTS 24 +#define BM_ICOLL_DEBUG_LEVEL_REQUESTS 0x0F000000 +#define BF_ICOLL_DEBUG_LEVEL_REQUESTS(v) \ + (((v) << 24) & BM_ICOLL_DEBUG_LEVEL_REQUESTS) +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL3 0x8 +#define BP_ICOLL_DEBUG_REQUESTS_BY_LEVEL 20 +#define BM_ICOLL_DEBUG_REQUESTS_BY_LEVEL 0x00F00000 +#define BF_ICOLL_DEBUG_REQUESTS_BY_LEVEL(v) \ + (((v) << 20) & BM_ICOLL_DEBUG_REQUESTS_BY_LEVEL) +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL3 0x8 +#define BP_ICOLL_DEBUG_RSRVD2 18 +#define BM_ICOLL_DEBUG_RSRVD2 0x000C0000 +#define BF_ICOLL_DEBUG_RSRVD2(v) \ + (((v) << 18) & BM_ICOLL_DEBUG_RSRVD2) +#define BM_ICOLL_DEBUG_FIQ 0x00020000 +#define BV_ICOLL_DEBUG_FIQ__NO_FIQ_REQUESTED 0x0 +#define BV_ICOLL_DEBUG_FIQ__FIQ_REQUESTED 0x1 +#define BM_ICOLL_DEBUG_IRQ 0x00010000 +#define BV_ICOLL_DEBUG_IRQ__NO_IRQ_REQUESTED 0x0 +#define BV_ICOLL_DEBUG_IRQ__IRQ_REQUESTED 0x1 +#define BP_ICOLL_DEBUG_RSRVD1 10 +#define BM_ICOLL_DEBUG_RSRVD1 0x0000FC00 +#define BF_ICOLL_DEBUG_RSRVD1(v) \ + (((v) << 10) & BM_ICOLL_DEBUG_RSRVD1) +#define BP_ICOLL_DEBUG_VECTOR_FSM 0 +#define BM_ICOLL_DEBUG_VECTOR_FSM 0x000003FF +#define BF_ICOLL_DEBUG_VECTOR_FSM(v) \ + (((v) << 0) & BM_ICOLL_DEBUG_VECTOR_FSM) +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_IDLE 0x000 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE1 0x001 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE2 0x002 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_PENDING 0x004 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE3 0x008 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE4 0x010 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING1 0x020 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING2 0x040 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING3 0x080 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE5 0x100 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE6 0x200 + +#define HW_ICOLL_DBGREAD0 (0x00001130) +#define HW_ICOLL_DBGREAD0_SET (0x00001134) +#define HW_ICOLL_DBGREAD0_CLR (0x00001138) +#define HW_ICOLL_DBGREAD0_TOG (0x0000113c) + +#define BP_ICOLL_DBGREAD0_VALUE 0 +#define BM_ICOLL_DBGREAD0_VALUE 0xFFFFFFFF +#define BF_ICOLL_DBGREAD0_VALUE(v) (v) + +#define HW_ICOLL_DBGREAD1 (0x00001140) +#define HW_ICOLL_DBGREAD1_SET (0x00001144) +#define HW_ICOLL_DBGREAD1_CLR (0x00001148) +#define HW_ICOLL_DBGREAD1_TOG (0x0000114c) + +#define BP_ICOLL_DBGREAD1_VALUE 0 +#define BM_ICOLL_DBGREAD1_VALUE 0xFFFFFFFF +#define BF_ICOLL_DBGREAD1_VALUE(v) (v) + +#define HW_ICOLL_DBGFLAG (0x00001150) +#define HW_ICOLL_DBGFLAG_SET (0x00001154) +#define HW_ICOLL_DBGFLAG_CLR (0x00001158) +#define HW_ICOLL_DBGFLAG_TOG (0x0000115c) + +#define BP_ICOLL_DBGFLAG_RSRVD1 16 +#define BM_ICOLL_DBGFLAG_RSRVD1 0xFFFF0000 +#define BF_ICOLL_DBGFLAG_RSRVD1(v) \ + (((v) << 16) & BM_ICOLL_DBGFLAG_RSRVD1) +#define BP_ICOLL_DBGFLAG_FLAG 0 +#define BM_ICOLL_DBGFLAG_FLAG 0x0000FFFF +#define BF_ICOLL_DBGFLAG_FLAG(v) \ + (((v) << 0) & BM_ICOLL_DBGFLAG_FLAG) + +/* + * multi-register-define name HW_ICOLL_DBGREQUESTn + * base 0x00001160 + * count 4 + * offset 0x10 + */ +#define HW_ICOLL_DBGREQUESTn(n) (0x00001160 + (n) * 0x10) +#define HW_ICOLL_DBGREQUESTn_SET(n) (0x00001164 + (n) * 0x10) +#define HW_ICOLL_DBGREQUESTn_CLR(n) (0x00001168 + (n) * 0x10) +#define HW_ICOLL_DBGREQUESTn_TOG(n) (0x0000116c + (n) * 0x10) +#define BP_ICOLL_DBGREQUESTn_BITS 0 +#define BM_ICOLL_DBGREQUESTn_BITS 0xFFFFFFFF +#define BF_ICOLL_DBGREQUESTn_BITS(v) (v) + +#define HW_ICOLL_VERSION (0x000011e0) + +#define BP_ICOLL_VERSION_MAJOR 24 +#define BM_ICOLL_VERSION_MAJOR 0xFF000000 +#define BF_ICOLL_VERSION_MAJOR(v) \ + (((v) << 24) & BM_ICOLL_VERSION_MAJOR) +#define BP_ICOLL_VERSION_MINOR 16 +#define BM_ICOLL_VERSION_MINOR 0x00FF0000 +#define BF_ICOLL_VERSION_MINOR(v) \ + (((v) << 16) & BM_ICOLL_VERSION_MINOR) +#define BP_ICOLL_VERSION_STEP 0 +#define BM_ICOLL_VERSION_STEP 0x0000FFFF +#define BF_ICOLL_VERSION_STEP(v) \ + (((v) << 0) & BM_ICOLL_VERSION_STEP) +#endif /* __ARCH_ARM___ICOLL_H */ diff --git a/arch/arm/plat-mxs/regs-usbphy.h b/arch/arm/plat-mxs/regs-usbphy.h new file mode 100644 index 000000000000..cf64bfdab0e6 --- /dev/null +++ b/arch/arm/plat-mxs/regs-usbphy.h @@ -0,0 +1,323 @@ +/* + * Freescale USBPHY 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.52 + * Template revision: 26195 + */ + +#ifndef __ARCH_ARM___USBPHY_H +#define __ARCH_ARM___USBPHY_H + + +#define HW_USBPHY_PWD (0x00000000) +#define HW_USBPHY_PWD_SET (0x00000004) +#define HW_USBPHY_PWD_CLR (0x00000008) +#define HW_USBPHY_PWD_TOG (0x0000000c) + +#define BP_USBPHY_PWD_RSVD2 21 +#define BM_USBPHY_PWD_RSVD2 0xFFE00000 +#define BF_USBPHY_PWD_RSVD2(v) \ + (((v) << 21) & BM_USBPHY_PWD_RSVD2) +#define BM_USBPHY_PWD_RXPWDRX 0x00100000 +#define BM_USBPHY_PWD_RXPWDDIFF 0x00080000 +#define BM_USBPHY_PWD_RXPWD1PT1 0x00040000 +#define BM_USBPHY_PWD_RXPWDENV 0x00020000 +#define BP_USBPHY_PWD_RSVD1 13 +#define BM_USBPHY_PWD_RSVD1 0x0001E000 +#define BF_USBPHY_PWD_RSVD1(v) \ + (((v) << 13) & BM_USBPHY_PWD_RSVD1) +#define BM_USBPHY_PWD_TXPWDV2I 0x00001000 +#define BM_USBPHY_PWD_TXPWDIBIAS 0x00000800 +#define BM_USBPHY_PWD_TXPWDFS 0x00000400 +#define BP_USBPHY_PWD_RSVD0 0 +#define BM_USBPHY_PWD_RSVD0 0x000003FF +#define BF_USBPHY_PWD_RSVD0(v) \ + (((v) << 0) & BM_USBPHY_PWD_RSVD0) + +#define HW_USBPHY_TX (0x00000010) +#define HW_USBPHY_TX_SET (0x00000014) +#define HW_USBPHY_TX_CLR (0x00000018) +#define HW_USBPHY_TX_TOG (0x0000001c) + +#define BP_USBPHY_TX_RSVD5 29 +#define BM_USBPHY_TX_RSVD5 0xE0000000 +#define BF_USBPHY_TX_RSVD5(v) \ + (((v) << 29) & BM_USBPHY_TX_RSVD5) +#define BP_USBPHY_TX_USBPHY_TX_EDGECTRL 26 +#define BM_USBPHY_TX_USBPHY_TX_EDGECTRL 0x1C000000 +#define BF_USBPHY_TX_USBPHY_TX_EDGECTRL(v) \ + (((v) << 26) & BM_USBPHY_TX_USBPHY_TX_EDGECTRL) +#define BM_USBPHY_TX_USBPHY_TX_SYNC_INVERT 0x02000000 +#define BM_USBPHY_TX_USBPHY_TX_SYNC_MUX 0x01000000 +#define BP_USBPHY_TX_RSVD4 22 +#define BM_USBPHY_TX_RSVD4 0x00C00000 +#define BF_USBPHY_TX_RSVD4(v) \ + (((v) << 22) & BM_USBPHY_TX_RSVD4) +#define BM_USBPHY_TX_TXENCAL45DP 0x00200000 +#define BM_USBPHY_TX_RSVD3 0x00100000 +#define BP_USBPHY_TX_TXCAL45DP 16 +#define BM_USBPHY_TX_TXCAL45DP 0x000F0000 +#define BF_USBPHY_TX_TXCAL45DP(v) \ + (((v) << 16) & BM_USBPHY_TX_TXCAL45DP) +#define BP_USBPHY_TX_RSVD2 14 +#define BM_USBPHY_TX_RSVD2 0x0000C000 +#define BF_USBPHY_TX_RSVD2(v) \ + (((v) << 14) & BM_USBPHY_TX_RSVD2) +#define BM_USBPHY_TX_TXENCAL45DN 0x00002000 +#define BM_USBPHY_TX_RSVD1 0x00001000 +#define BP_USBPHY_TX_TXCAL45DN 8 +#define BM_USBPHY_TX_TXCAL45DN 0x00000F00 +#define BF_USBPHY_TX_TXCAL45DN(v) \ + (((v) << 8) & BM_USBPHY_TX_TXCAL45DN) +#define BP_USBPHY_TX_RSVD0 4 +#define BM_USBPHY_TX_RSVD0 0x000000F0 +#define BF_USBPHY_TX_RSVD0(v) \ + (((v) << 4) & BM_USBPHY_TX_RSVD0) +#define BP_USBPHY_TX_D_CAL 0 +#define BM_USBPHY_TX_D_CAL 0x0000000F +#define BF_USBPHY_TX_D_CAL(v) \ + (((v) << 0) & BM_USBPHY_TX_D_CAL) + +#define HW_USBPHY_RX (0x00000020) +#define HW_USBPHY_RX_SET (0x00000024) +#define HW_USBPHY_RX_CLR (0x00000028) +#define HW_USBPHY_RX_TOG (0x0000002c) + +#define BP_USBPHY_RX_RSVD2 23 +#define BM_USBPHY_RX_RSVD2 0xFF800000 +#define BF_USBPHY_RX_RSVD2(v) \ + (((v) << 23) & BM_USBPHY_RX_RSVD2) +#define BM_USBPHY_RX_RXDBYPASS 0x00400000 +#define BP_USBPHY_RX_RSVD1 7 +#define BM_USBPHY_RX_RSVD1 0x003FFF80 +#define BF_USBPHY_RX_RSVD1(v) \ + (((v) << 7) & BM_USBPHY_RX_RSVD1) +#define BP_USBPHY_RX_DISCONADJ 4 +#define BM_USBPHY_RX_DISCONADJ 0x00000070 +#define BF_USBPHY_RX_DISCONADJ(v) \ + (((v) << 4) & BM_USBPHY_RX_DISCONADJ) +#define BM_USBPHY_RX_RSVD0 0x00000008 +#define BP_USBPHY_RX_ENVADJ 0 +#define BM_USBPHY_RX_ENVADJ 0x00000007 +#define BF_USBPHY_RX_ENVADJ(v) \ + (((v) << 0) & BM_USBPHY_RX_ENVADJ) + +#define HW_USBPHY_CTRL (0x00000030) +#define HW_USBPHY_CTRL_SET (0x00000034) +#define HW_USBPHY_CTRL_CLR (0x00000038) +#define HW_USBPHY_CTRL_TOG (0x0000003c) + +#define BM_USBPHY_CTRL_SFTRST 0x80000000 +#define BM_USBPHY_CTRL_CLKGATE 0x40000000 +#define BM_USBPHY_CTRL_UTMI_SUSPENDM 0x20000000 +#define BM_USBPHY_CTRL_HOST_FORCE_LS_SE0 0x10000000 +#define BM_USBPHY_CTRL_RSVD3 0x08000000 +#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS 0x04000000 +#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE 0x02000000 +#define BM_USBPHY_CTRL_FSDLL_RST_EN 0x01000000 +#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP 0x00800000 +#define BM_USBPHY_CTRL_ENIDCHG_WKUP 0x00400000 +#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP 0x00200000 +#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD 0x00100000 +#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE 0x00080000 +#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL 0x00040000 +#define BM_USBPHY_CTRL_WAKEUP_IRQ 0x00020000 +#define BM_USBPHY_CTRL_ENIRQWAKEUP 0x00010000 +#define BM_USBPHY_CTRL_ENUTMILEVEL3 0x00008000 +#define BM_USBPHY_CTRL_ENUTMILEVEL2 0x00004000 +#define BM_USBPHY_CTRL_DATA_ON_LRADC 0x00002000 +#define BM_USBPHY_CTRL_DEVPLUGIN_IRQ 0x00001000 +#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800 +#define BM_USBPHY_CTRL_RESUME_IRQ 0x00000400 +#define BM_USBPHY_CTRL_ENIRQRESUMEDETECT 0x00000200 +#define BM_USBPHY_CTRL_RESUMEIRQSTICKY 0x00000100 +#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080 +#define BM_USBPHY_CTRL_RSVD1 0x00000040 +#define BM_USBPHY_CTRL_DEVPLUGIN_POLARITY 0x00000020 +#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010 +#define BM_USBPHY_CTRL_HOSTDISCONDETECT_IRQ 0x00000008 +#define BM_USBPHY_CTRL_ENIRQHOSTDISCON 0x00000004 +#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002 +#define BM_USBPHY_CTRL_RSVD0 0x00000001 + +#define HW_USBPHY_STATUS (0x00000040) + +#define BP_USBPHY_STATUS_RSVD4 11 +#define BM_USBPHY_STATUS_RSVD4 0xFFFFF800 +#define BF_USBPHY_STATUS_RSVD4(v) \ + (((v) << 11) & BM_USBPHY_STATUS_RSVD4) +#define BM_USBPHY_STATUS_RESUME_STATUS 0x00000400 +#define BM_USBPHY_STATUS_RSVD3 0x00000200 +#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100 +#define BM_USBPHY_STATUS_RSVD2 0x00000080 +#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040 +#define BP_USBPHY_STATUS_RSVD1 4 +#define BM_USBPHY_STATUS_RSVD1 0x00000030 +#define BF_USBPHY_STATUS_RSVD1(v) \ + (((v) << 4) & BM_USBPHY_STATUS_RSVD1) +#define BM_USBPHY_STATUS_HOSTDISCONDETECT_STATUS 0x00000008 +#define BP_USBPHY_STATUS_RSVD0 0 +#define BM_USBPHY_STATUS_RSVD0 0x00000007 +#define BF_USBPHY_STATUS_RSVD0(v) \ + (((v) << 0) & BM_USBPHY_STATUS_RSVD0) + +#define HW_USBPHY_DEBUG (0x00000050) +#define HW_USBPHY_DEBUG_SET (0x00000054) +#define HW_USBPHY_DEBUG_CLR (0x00000058) +#define HW_USBPHY_DEBUG_TOG (0x0000005c) + +#define BM_USBPHY_DEBUG_RSVD3 0x80000000 +#define BM_USBPHY_DEBUG_CLKGATE 0x40000000 +#define BM_USBPHY_DEBUG_HOST_RESUME_DEBUG 0x20000000 +#define BP_USBPHY_DEBUG_SQUELCHRESETLENGTH 25 +#define BM_USBPHY_DEBUG_SQUELCHRESETLENGTH 0x1E000000 +#define BF_USBPHY_DEBUG_SQUELCHRESETLENGTH(v) \ + (((v) << 25) & BM_USBPHY_DEBUG_SQUELCHRESETLENGTH) +#define BM_USBPHY_DEBUG_ENSQUELCHRESET 0x01000000 +#define BP_USBPHY_DEBUG_RSVD2 21 +#define BM_USBPHY_DEBUG_RSVD2 0x00E00000 +#define BF_USBPHY_DEBUG_RSVD2(v) \ + (((v) << 21) & BM_USBPHY_DEBUG_RSVD2) +#define BP_USBPHY_DEBUG_SQUELCHRESETCOUNT 16 +#define BM_USBPHY_DEBUG_SQUELCHRESETCOUNT 0x001F0000 +#define BF_USBPHY_DEBUG_SQUELCHRESETCOUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG_SQUELCHRESETCOUNT) +#define BP_USBPHY_DEBUG_RSVD1 13 +#define BM_USBPHY_DEBUG_RSVD1 0x0000E000 +#define BF_USBPHY_DEBUG_RSVD1(v) \ + (((v) << 13) & BM_USBPHY_DEBUG_RSVD1) +#define BM_USBPHY_DEBUG_ENTX2RXCOUNT 0x00001000 +#define BP_USBPHY_DEBUG_TX2RXCOUNT 8 +#define BM_USBPHY_DEBUG_TX2RXCOUNT 0x00000F00 +#define BF_USBPHY_DEBUG_TX2RXCOUNT(v) \ + (((v) << 8) & BM_USBPHY_DEBUG_TX2RXCOUNT) +#define BP_USBPHY_DEBUG_RSVD0 6 +#define BM_USBPHY_DEBUG_RSVD0 0x000000C0 +#define BF_USBPHY_DEBUG_RSVD0(v) \ + (((v) << 6) & BM_USBPHY_DEBUG_RSVD0) +#define BP_USBPHY_DEBUG_ENHSTPULLDOWN 4 +#define BM_USBPHY_DEBUG_ENHSTPULLDOWN 0x00000030 +#define BF_USBPHY_DEBUG_ENHSTPULLDOWN(v) \ + (((v) << 4) & BM_USBPHY_DEBUG_ENHSTPULLDOWN) +#define BP_USBPHY_DEBUG_HSTPULLDOWN 2 +#define BM_USBPHY_DEBUG_HSTPULLDOWN 0x0000000C +#define BF_USBPHY_DEBUG_HSTPULLDOWN(v) \ + (((v) << 2) & BM_USBPHY_DEBUG_HSTPULLDOWN) +#define BM_USBPHY_DEBUG_DEBUG_INTERFACE_HOLD 0x00000002 +#define BM_USBPHY_DEBUG_OTGIDPIOLOCK 0x00000001 + +#define HW_USBPHY_DEBUG0_STATUS (0x00000060) + +#define BP_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 26 +#define BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 0xFC000000 +#define BF_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT(v) \ + (((v) << 26) & BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 16 +#define BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 0x03FF0000 +#define BF_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0 +#define BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0x0000FFFF +#define BF_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT(v) \ + (((v) << 0) & BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT) + +#define HW_USBPHY_DEBUG1 (0x00000070) +#define HW_USBPHY_DEBUG1_SET (0x00000074) +#define HW_USBPHY_DEBUG1_CLR (0x00000078) +#define HW_USBPHY_DEBUG1_TOG (0x0000007c) + +#define BP_USBPHY_DEBUG1_RSVD1 15 +#define BM_USBPHY_DEBUG1_RSVD1 0xFFFF8000 +#define BF_USBPHY_DEBUG1_RSVD1(v) \ + (((v) << 15) & BM_USBPHY_DEBUG1_RSVD1) +#define BP_USBPHY_DEBUG1_ENTAILADJVD 13 +#define BM_USBPHY_DEBUG1_ENTAILADJVD 0x00006000 +#define BF_USBPHY_DEBUG1_ENTAILADJVD(v) \ + (((v) << 13) & BM_USBPHY_DEBUG1_ENTAILADJVD) +#define BM_USBPHY_DEBUG1_ENTX2TX 0x00001000 +#define BP_USBPHY_DEBUG1_RSVD0 4 +#define BM_USBPHY_DEBUG1_RSVD0 0x00000FF0 +#define BF_USBPHY_DEBUG1_RSVD0(v) \ + (((v) << 4) & BM_USBPHY_DEBUG1_RSVD0) +#define BP_USBPHY_DEBUG1_DBG_ADDRESS 0 +#define BM_USBPHY_DEBUG1_DBG_ADDRESS 0x0000000F +#define BF_USBPHY_DEBUG1_DBG_ADDRESS(v) \ + (((v) << 0) & BM_USBPHY_DEBUG1_DBG_ADDRESS) + +#define HW_USBPHY_VERSION (0x00000080) + +#define BP_USBPHY_VERSION_MAJOR 24 +#define BM_USBPHY_VERSION_MAJOR 0xFF000000 +#define BF_USBPHY_VERSION_MAJOR(v) \ + (((v) << 24) & BM_USBPHY_VERSION_MAJOR) +#define BP_USBPHY_VERSION_MINOR 16 +#define BM_USBPHY_VERSION_MINOR 0x00FF0000 +#define BF_USBPHY_VERSION_MINOR(v) \ + (((v) << 16) & BM_USBPHY_VERSION_MINOR) +#define BP_USBPHY_VERSION_STEP 0 +#define BM_USBPHY_VERSION_STEP 0x0000FFFF +#define BF_USBPHY_VERSION_STEP(v) \ + (((v) << 0) & BM_USBPHY_VERSION_STEP) + +#define HW_USBPHY_IP (0x00000090) +#define HW_USBPHY_IP_SET (0x00000094) +#define HW_USBPHY_IP_CLR (0x00000098) +#define HW_USBPHY_IP_TOG (0x0000009c) + +#define BP_USBPHY_IP_RSVD1 25 +#define BM_USBPHY_IP_RSVD1 0xFE000000 +#define BF_USBPHY_IP_RSVD1(v) \ + (((v) << 25) & BM_USBPHY_IP_RSVD1) +#define BP_USBPHY_IP_DIV_SEL 23 +#define BM_USBPHY_IP_DIV_SEL 0x01800000 +#define BF_USBPHY_IP_DIV_SEL(v) \ + (((v) << 23) & BM_USBPHY_IP_DIV_SEL) +#define BV_USBPHY_IP_DIV_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_DIV_SEL__LOWER 0x1 +#define BV_USBPHY_IP_DIV_SEL__LOWEST 0x2 +#define BV_USBPHY_IP_DIV_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_LFR_SEL 21 +#define BM_USBPHY_IP_LFR_SEL 0x00600000 +#define BF_USBPHY_IP_LFR_SEL(v) \ + (((v) << 21) & BM_USBPHY_IP_LFR_SEL) +#define BV_USBPHY_IP_LFR_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_LFR_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_LFR_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_LFR_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_CP_SEL 19 +#define BM_USBPHY_IP_CP_SEL 0x00180000 +#define BF_USBPHY_IP_CP_SEL(v) \ + (((v) << 19) & BM_USBPHY_IP_CP_SEL) +#define BV_USBPHY_IP_CP_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_CP_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_CP_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_CP_SEL__UNDEFINED 0x3 +#define BM_USBPHY_IP_TSTI_TX_DP 0x00040000 +#define BM_USBPHY_IP_TSTI_TX_DM 0x00020000 +#define BM_USBPHY_IP_ANALOG_TESTMODE 0x00010000 +#define BP_USBPHY_IP_RSVD0 3 +#define BM_USBPHY_IP_RSVD0 0x0000FFF8 +#define BF_USBPHY_IP_RSVD0(v) \ + (((v) << 3) & BM_USBPHY_IP_RSVD0) +#define BM_USBPHY_IP_EN_USB_CLKS 0x00000004 +#define BM_USBPHY_IP_PLL_LOCKED 0x00000002 +#define BM_USBPHY_IP_PLL_POWER 0x00000001 +#endif /* __ARCH_ARM___USBPHY_H */ diff --git a/arch/arm/plat-mxs/timer-match.c b/arch/arm/plat-mxs/timer-match.c new file mode 100644 index 000000000000..d6429e6955e6 --- /dev/null +++ b/arch/arm/plat-mxs/timer-match.c @@ -0,0 +1,164 @@ +/* + * System timer for Freescale i.MXS + * + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * 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/spinlock.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +#include <asm/mach/time.h> + +#include <mach/device.h> +#include <mach/regs-timrot.h> + +static struct mxs_sys_timer *online_timer; + +static irqreturn_t mxs_timer_handler(int irq, void *dev_id); + +static cycle_t mxs_get_cycles(struct clocksource *cs) +{ + return ~__raw_readl(online_timer->base + + HW_TIMROT_RUNNING_COUNTn(online_timer->id)); +} + +static int mxs_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + unsigned int match; + match = __raw_readl(online_timer->base + + HW_TIMROT_RUNNING_COUNTn(online_timer->id)) - delta; + __raw_writel(match, online_timer->base + + HW_TIMROT_MATCH_COUNTn(online_timer->id)); + return (int)(match - + __raw_readl(online_timer->base + + HW_TIMROT_RUNNING_COUNTn(online_timer->id))) + > 0 ? -ETIME : 0; +} + + +static void mxs_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ, + online_timer->base + HW_TIMROT_TIMCTRLn_CLR(0)); + break; + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_ONESHOT: + __raw_writel(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE, + online_timer->base + HW_TIMROT_ROTCTRL_CLR); + __raw_writel(BF_TIMROT_TIMCTRLn_SELECT(online_timer->clk_sel) | + BM_TIMROT_TIMCTRLn_IRQ_EN | + BM_TIMROT_TIMCTRLn_MATCH_MODE, + online_timer->base + HW_TIMROT_TIMCTRLn(online_timer->id)); + break; + default: + break; + } +} + +static struct clock_event_device mxs_clockevent = { + .name = "mxs tick timer ", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .set_next_event = mxs_set_next_event, + .set_mode = mxs_set_mode, + .rating = 200, +}; + +static struct clocksource mxs_clocksource = { + .name = "mxs clock source", + .rating = 250, + .read = mxs_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS +}; + +static struct irqaction mxs_timer_irq = { + .name = "i.MX/mxs Timer Tick", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = mxs_timer_handler, + .dev_id = &mxs_clockevent, +}; + +static int __init mxs_clocksource_init(struct clk *timer_clk) +{ + unsigned int c = clk_get_rate(timer_clk); + + mxs_clocksource.mult = clocksource_hz2mult(c, mxs_clocksource.shift); + clocksource_register(&mxs_clocksource); + return 0; +} + +static int __init mxs_clockevent_init(struct clk *timer_clk) +{ + unsigned int c = clk_get_rate(timer_clk); + + mxs_clockevent.mult = div_sc(c, NSEC_PER_SEC, mxs_clockevent.shift); + mxs_clockevent.min_delta_ns = clockevent_delta2ns(0xF, &mxs_clockevent); + mxs_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFFFFF0, + &mxs_clockevent); + mxs_clockevent.cpumask = cpumask_of(0); + + clockevents_register_device(&mxs_clockevent); + return 0; +} + +static irqreturn_t mxs_timer_handler(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + if (__raw_readl(online_timer->base + + HW_TIMROT_TIMCTRLn(online_timer->id)) & + BM_TIMROT_TIMCTRLn_IRQ) { + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, + online_timer->base + + HW_TIMROT_TIMCTRLn_CLR(online_timer->id)); + c->event_handler(c); + } + return IRQ_HANDLED; +} + +void mxs_timer_init(struct mxs_sys_timer *timer) +{ + if (!timer->base || !timer->clk || IS_ERR(timer->clk)) + return; + if (online_timer) + return; + online_timer = timer; + clk_enable(online_timer->clk); + __raw_writel(BF_TIMROT_TIMCTRLn_SELECT(online_timer->clk_sel) | + BM_TIMROT_TIMCTRLn_IRQ_EN | + BM_TIMROT_TIMCTRLn_MATCH_MODE, + online_timer->base + HW_TIMROT_TIMCTRLn(online_timer->id)); + mxs_clocksource_init(online_timer->clk); + mxs_clockevent_init(online_timer->clk); + setup_irq(online_timer->irq, &mxs_timer_irq); +} + + diff --git a/arch/arm/plat-mxs/timer-nomatch.c b/arch/arm/plat-mxs/timer-nomatch.c new file mode 100644 index 000000000000..db8906192f16 --- /dev/null +++ b/arch/arm/plat-mxs/timer-nomatch.c @@ -0,0 +1,195 @@ +/* + * System timer for Freescale STMP37XX/STMP378X + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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/spinlock.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +#include <asm/mach/time.h> +#include <mach/hardware.h> +#include <mach/device.h> +#include <mach/regs-timrot.h> + +#ifndef HW_TIMROT_TIMCOUNTn +#define HW_TIMROT_TIMCOUNTn HW_TIMROT_RUNNING_COUNTn +#endif +static struct mxs_sys_timer *online_timer; + +static irqreturn_t +mxs_nomatch_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + /* timer 0 */ + if (__raw_readl(online_timer->base + HW_TIMROT_TIMCTRLn(0)) & + BM_TIMROT_TIMCTRLn_IRQ) { + + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, + online_timer->base + HW_TIMROT_TIMCTRLn_CLR(0)); + c->event_handler(c); + } + + /* timer 1 */ + else if (__raw_readl(online_timer->base + HW_TIMROT_TIMCTRLn(1)) + & BM_TIMROT_TIMCTRLn_IRQ) { + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, + online_timer->base + HW_TIMROT_TIMCTRLn_CLR(1)); + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, + online_timer->base + HW_TIMROT_TIMCTRLn_CLR(1)); + __raw_writel(0xFFFF, + online_timer->base + HW_TIMROT_TIMCOUNTn(1)); + } + + return IRQ_HANDLED; +} + +static cycle_t mxs_nomatch_clock_read(struct clocksource *cs) +{ + return ~((__raw_readl(online_timer->base + HW_TIMROT_TIMCOUNTn(1)) + & 0xFFFF0000) >> 16); +} + +static int +mxs_nomatch_timrot_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + /* reload the timer */ + __raw_writel(delta, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); + return 0; +} + +static void +mxs_nomatch_timrot_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ +} + +static struct clock_event_device ckevt_timrot = { + .name = "timrot", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .set_next_event = mxs_nomatch_timrot_set_next_event, + .set_mode = mxs_nomatch_timrot_set_mode, +}; + +static struct clocksource cksrc_mxs_nomatch = { + .name = "mxs clock source", + .rating = 250, + .read = mxs_nomatch_clock_read, + .mask = CLOCKSOURCE_MASK(16), + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static struct irqaction mxs_nomatch_timer_irq = { + .name = "mxs_nomatch_timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = mxs_nomatch_timer_interrupt, + .dev_id = &ckevt_timrot, +}; + + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void mxs_nomatch_timer_init(struct mxs_sys_timer *timer) +{ + + if (online_timer) + return; + + online_timer = timer; + + cksrc_mxs_nomatch.mult = clocksource_hz2mult(clk_get_rate(timer->clk), + cksrc_mxs_nomatch.shift); + ckevt_timrot.mult = div_sc(clk_get_rate(timer->clk), NSEC_PER_SEC, + ckevt_timrot.shift); + ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot); + ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot); + ckevt_timrot.cpumask = cpumask_of(0); + + /* clear two timers */ + __raw_writel(0, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); + __raw_writel(0, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); + + /* configure them */ + __raw_writel( + (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN, + online_timer->base + HW_TIMROT_TIMCTRLn(0)); + __raw_writel( + (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN, + online_timer->base + HW_TIMROT_TIMCTRLn(1)); + + __raw_writel(clk_get_rate(timer->clk) / HZ - 1, + online_timer->base + HW_TIMROT_TIMCOUNTn(0)); + __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); + + setup_irq(IRQ_TIMER0, &mxs_nomatch_timer_irq); + + clocksource_register(&cksrc_mxs_nomatch); + clockevents_register_device(&ckevt_timrot); +} + +#ifdef CONFIG_PM + +void mxs_nomatch_suspend_timer(void) +{ + __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ, + online_timer->base + HW_TIMROT_TIMCTRLn_CLR(0)); + __raw_writel(BM_TIMROT_ROTCTRL_CLKGATE, + online_timer->base + HW_TIMROT_ROTCTRL_SET); +} + +void mxs_nomatch_resume_timer(void) +{ + __raw_writel(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE, + online_timer->base + HW_TIMROT_ROTCTRL_CLR); + __raw_writel( + 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN, + online_timer->base + HW_TIMROT_TIMCTRLn(0)); + __raw_writel( + 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN, + online_timer->base + HW_TIMROT_TIMCTRLn(1)); + __raw_writel(clk_get_rate(online_timer->clk) / HZ - 1, + online_timer->base + HW_TIMROT_TIMCOUNTn(0)); + __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); +} + +#else + +#define mxs_nomatch_suspend_timer NULL +#define mxs_nomatch_resume_timer NULL + +#endif /* CONFIG_PM */ diff --git a/arch/arm/plat-mxs/unique-id.c b/arch/arm/plat-mxs/unique-id.c new file mode 100644 index 000000000000..adb8286230cc --- /dev/null +++ b/arch/arm/plat-mxs/unique-id.c @@ -0,0 +1,199 @@ +/* + * Unique ID manipulation sysfs access generic functions + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, 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/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/err.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <linux/slab.h> + +#include <mach/unique-id.h> + +static int unlock; +static spinlock_t u_lock; +static const unsigned long UID_AUTOLOCK_TIMEOUT = HZ * 60 * 3; +static struct timer_list u_timer; + +static void uid_timer_autolock(unsigned long param) +{ + struct timer_list *tmr = (struct timer_list *)param; + + if (spin_trylock(&u_lock)) { + if (unlock) + pr_debug("%s: locked down.\n", __func__); + unlock = 0; + spin_unlock(&u_lock); + } + mod_timer(tmr, jiffies + UID_AUTOLOCK_TIMEOUT); +} + +static LIST_HEAD(uid_provider_list); + +struct uid_provider { + struct kobject *kobj; + struct list_head list; + struct uid_ops *ops; + void *context; +}; + +static struct uid_provider *uid_provider_find(const char *name); + +#define UID_FWD_SYSFS_FILE(var, file, param) \ + static ssize_t var##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + struct uid_provider *p = \ + uid_provider_find(kobject_name(kobj)); \ + ssize_t r; \ + BUG_ON(p == NULL); \ + r = (p->ops && p->ops->file##_show) ? \ + p->ops->file##_show(p->context, buf, param) : 0;\ + return r; \ + } \ + \ + static ssize_t var##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, const char *buf, \ + size_t count) \ + { \ + struct uid_provider *p = \ + uid_provider_find(kobject_name(kobj)); \ + ssize_t r; \ + int ul; \ + BUG_ON(p == NULL); \ + spin_lock(&u_lock); \ + ul = unlock; \ + spin_unlock(&u_lock); \ + if (ul) \ + r = (p->ops && p->ops->file##_store) ? \ + p->ops->file##_store(p->context, buf, count, param) \ + : count; \ + else \ + r = -EACCES; \ + return r; \ + } + +struct kobject *uid_kobj; + +#define UID_ATTR(_name, _varname) \ + static struct kobj_attribute _varname##_attr = \ + __ATTR(_name, 0644, _varname##_show, _varname##_store) + +UID_FWD_SYSFS_FILE(id, id, 1); +UID_FWD_SYSFS_FILE(id_bin, id, 0); +UID_ATTR(id, id); +UID_ATTR(id.bin, id_bin); + +static struct attribute *uid_attrs[] = { + &id_attr.attr, + &id_bin_attr.attr, + NULL +}; + +static struct attribute_group uid_attr_group = { + .attrs = uid_attrs, +}; + +struct kobject *uid_provider_init(const char *name, + struct uid_ops *ops, void *context) +{ + struct uid_provider *new; + int err; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + err = -ENOMEM; + goto out; + } + + new->kobj = kobject_create_and_add(name, uid_kobj); + if (!new->kobj) { + err = -ENOMEM; + goto out; + } + new->ops = ops; + new->context = context; + + err = sysfs_create_group(new->kobj, &uid_attr_group); + if (err) + goto out2; + + list_add_tail(&new->list, &uid_provider_list); + return new->kobj; +out2: + kobject_del(new->kobj); +out: + kfree(new); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(uid_provider_init); + +static struct uid_provider *uid_provider_find(const char *name) +{ + struct uid_provider *p; + + list_for_each_entry(p, &uid_provider_list, list) { + if (strcmp(kobject_name(p->kobj), name) == 0) + return p; + } + return NULL; +} + +void uid_provider_remove(const char *name) +{ + struct uid_provider *p; + + p = uid_provider_find(name); + if (!p) + return; + kobject_del(p->kobj); + list_del(&p->list); + kfree(p); +} +EXPORT_SYMBOL_GPL(uid_provider_remove); + +static int uid_sysfs_init(void) +{ + int error; + + uid_kobj = kobject_create_and_add("uid", NULL); + if (!uid_kobj) { + error = -ENOMEM; + goto out1; + } + + spin_lock_init(&u_lock); + setup_timer(&u_timer, uid_timer_autolock, (unsigned long)&u_timer); + + /* try to lock each 3 minutes */ + mod_timer(&u_timer, jiffies + UID_AUTOLOCK_TIMEOUT); + return 0; + +out1: + printk(KERN_ERR"%s failed, error %d.", __func__, error); + return error; +} + +module_param(unlock, int, 0600) +core_initcall(uid_sysfs_init); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_DESCRIPTION("Unique ID simple framework"); diff --git a/arch/arm/plat-mxs/usb_common.c b/arch/arm/plat-mxs/usb_common.c new file mode 100644 index 000000000000..16ef4736b4d0 --- /dev/null +++ b/arch/arm/plat-mxs/usb_common.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2009-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. + */ + +/*! + *@defgroup USB ARC OTG USB Driver + */ + +/*! + * @file usb_common.c + * + * @brief platform related part of usb driver. + * @ingroup USB + */ + +/*! + *Include files + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/usb/otg.h> +#include <linux/usb/fsl_xcvr.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include <linux/io.h> +#define MXC_NUMBER_USB_TRANSCEIVER 6 +struct fsl_xcvr_ops *g_xc_ops[MXC_NUMBER_USB_TRANSCEIVER] = { NULL }; + +void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops) +{ + int i; + + pr_debug("%s\n", __func__); + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (g_xc_ops[i] == NULL) { + g_xc_ops[i] = xcvr_ops; + return; + } + } + + pr_debug("Failed %s\n", __func__); +} +EXPORT_SYMBOL(fsl_usb_xcvr_register); + +void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops) +{ + int i; + + pr_debug("%s\n", __func__); + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (g_xc_ops[i] == xcvr_ops) { + g_xc_ops[i] = NULL; + return; + } + } + + pr_debug("Failed %s\n", __func__); +} +EXPORT_SYMBOL(fsl_usb_xcvr_unregister); + +void fsl_platform_set_test_mode( + struct fsl_usb2_platform_data *pdata, + enum usb_test_mode mode) +{ +} +EXPORT_SYMBOL(fsl_platform_set_test_mode); + +/* enable/disable high-speed disconnect detector of phy ctrl */ +void fsl_platform_set_usb_phy_dis(struct fsl_usb2_platform_data *pdata, + bool enable) +{ + if (enable) + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_SET); + else + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_CLR); +} +EXPORT_SYMBOL(fsl_platform_set_usb_phy_dis); + + +#if defined(CONFIG_USB_OTG) +static struct resource *otg_resources; + +struct resource *otg_get_resources(void) +{ + pr_debug("otg_get_resources\n"); + return otg_resources; +} +EXPORT_SYMBOL(otg_get_resources); + +int otg_set_resources(struct resource *resources) +{ + otg_resources = resources; + return 0; +} +EXPORT_SYMBOL(otg_set_resources); +#endif + +/*! + * Register remote wakeup by this usb controller + * + * @param pdev: platform_device for this usb controller + * + * @return 0 or negative error code in case not supportted. + */ +static int usb_register_remote_wakeup(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + int irq; + + pr_debug("%s: pdev=0x%p \n", __func__, pdev); + if (!(pdata->wake_up_enable)) + return -ECANCELED; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + irq = res->start; + pdev->dev.power.can_wakeup = 1; + enable_irq_wake(irq); + + return 0; +} + +static struct fsl_xcvr_ops *fsl_usb_get_xcvr(char *name) +{ + int i; + + pr_debug("%s\n", __func__); + if (name == NULL) { + printk(KERN_ERR "get_xcvr(): No tranceiver name\n"); + return NULL; + } + + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (strcmp(g_xc_ops[i]->name, name) == 0) + return g_xc_ops[i]; + } + pr_debug("Failed %s\n", __func__); + return NULL; +} + +/* The dmamask must be set for EHCI to work */ +static u64 ehci_dmamask = ~(u32) 0; + +static int instance_id = ~(u32) 0; +struct platform_device *host_pdev_register(struct resource *res, int n_res, + struct fsl_usb2_platform_data + *config) +{ + struct platform_device *pdev; + int rc; + + pr_debug("register host res=0x%p, size=%d\n", res, n_res); + + pdev = platform_device_register_simple("fsl-ehci", + instance_id, res, n_res); + if (IS_ERR(pdev)) { + pr_debug("can't register %s Host, %ld\n", + config->name, PTR_ERR(pdev)); + return NULL; + } + + pdev->dev.coherent_dma_mask = 0xffffffff; + pdev->dev.dma_mask = &ehci_dmamask; + + /* + * platform_device_add_data() makes a copy of + * the platform_data passed in. That makes it + * impossible to share the same config struct for + * all OTG devices (host,gadget,otg). So, just + * set the platorm_data pointer ourselves. + */ + rc = platform_device_add_data(pdev, config, + sizeof(struct fsl_usb2_platform_data)); + if (rc) { + platform_device_unregister(pdev); + return NULL; + } + + pr_debug(KERN_INFO "usb: %s host (%s) registered\n", config->name, + config->transceiver); + pr_debug("pdev=0x%p dev=0x%p resources=0x%p pdata=0x%p\n", + pdev, &pdev->dev, pdev->resource, pdev->dev.platform_data); + + instance_id++; + + return pdev; +} + +int usb_phy_enable(struct fsl_usb2_platform_data *pdata) +{ + u32 tmp; + void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs); + void __iomem *usb_reg = pdata->regs; + void __iomem *usbcmd, *phy_ctrl, *portsc; + + /* Reset USB IP */ + usbcmd = usb_reg + UOG_USBCMD; + tmp = __raw_readl(usbcmd); /* usb command */ + tmp &= ~UCMD_RUN_STOP; + __raw_writel(tmp, usbcmd); + while (__raw_readl(usbcmd) & UCMD_RUN_STOP) + ; + + tmp |= UCMD_RESET; + __raw_writel(tmp, usbcmd); + while (__raw_readl(usbcmd) & UCMD_RESET) + ; + mdelay(10); + + /* Reset USBPHY module */ + phy_ctrl = phy_reg + HW_USBPHY_CTRL; + tmp = __raw_readl(phy_ctrl); + tmp |= BM_USBPHY_CTRL_SFTRST; + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + tmp = __raw_readl(phy_ctrl); + tmp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST); + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* set UTMI xcvr */ + /* Workaround an IC issue for ehci driver: + * when turn off root hub port power, EHCI set + * PORTSC reserved bits to be 0, but PTW with 0 + * means 8 bits tranceiver width, here change + * it back to be 16 bits and do PHY diable and + * then enable. + */ + portsc = usb_reg + UOG_PORTSC1; + tmp = __raw_readl(portsc); + tmp &= ~PORTSC_PTS_MASK; + tmp |= (PORTSC_PTS_UTMI | PORTSC_PTW); + __raw_writel(tmp, portsc); + + /* Power up the PHY */ + __raw_writel(0, phy_reg + HW_USBPHY_PWD); + + return 0; +} +EXPORT_SYMBOL(usb_phy_enable); + +static int otg_used; + +int usbotg_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_xcvr_ops *xops; + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __func__, pdev, pdata); + + xops = fsl_usb_get_xcvr(pdata->transceiver); + if (!xops) { + printk(KERN_ERR "DR transceiver ops missing\n"); + return -EINVAL; + } + pdata->xcvr_ops = xops; + pdata->xcvr_type = xops->xcvr_type; + pdata->pdev = pdev; + + if (!otg_used) { + pr_debug("%s: grab pins\n", __func__); + if (xops->init) + xops->init(xops); + usb_phy_enable(pdata); + } + + if ((pdata->operating_mode == FSL_USB2_DR_HOST) || + (pdata->operating_mode == FSL_USB2_DR_OTG)) { + /* enable FS/LS device */ + __raw_writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3 + , IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_SET); + } + + if (usb_register_remote_wakeup(pdev)) + pr_debug("%s port is not a wakeup source.\n", pdata->name); + + otg_used++; + pr_debug("%s: success\n", __func__); + return 0; +} +EXPORT_SYMBOL(usbotg_init); + +void usbotg_uninit(struct fsl_usb2_platform_data *pdata) +{ + pr_debug("%s\n", __func__); + + if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) + pdata->xcvr_ops->uninit(pdata->xcvr_ops); + + pdata->regs = NULL; + otg_used--; +} +EXPORT_SYMBOL(usbotg_uninit); + +int fsl_usb_host_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_xcvr_ops *xops; + u32 tmp; + void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs); + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __func__, pdev, pdata); + + xops = fsl_usb_get_xcvr(pdata->transceiver); + if (!xops) { + printk(KERN_ERR "%s transceiver ops missing\n", pdata->name); + return -EINVAL; + } + pdata->xcvr_ops = xops; + pdata->xcvr_type = xops->xcvr_type; + pdata->pdev = pdev; + + if (xops->init) + xops->init(xops); + usb_phy_enable(pdata); + /* enable FS/LS device */ + tmp = __raw_readl(phy_reg + HW_USBPHY_CTRL); + tmp |= (BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3); + __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL); + + if (usb_register_remote_wakeup(pdev)) + pr_debug("%s port is not a wakeup source.\n", pdata->name); + + pr_debug("%s: %s success\n", __func__, pdata->name); + return 0; +} +EXPORT_SYMBOL(fsl_usb_host_init); + +void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata) +{ + pr_debug("%s\n", __func__); + + if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) + pdata->xcvr_ops->uninit(pdata->xcvr_ops); + + pdata->regs = NULL; +} +EXPORT_SYMBOL(fsl_usb_host_uninit); + +/* + * This function is used to debounce the reading value for id/vbus at + * the register of otgsc + */ +void usb_debounce_id_vbus(void) +{ + mdelay(3); +} +EXPORT_SYMBOL(usb_debounce_id_vbus); + +int usb_host_wakeup_irq(struct device *wkup_dev) +{ + return 0; +} +EXPORT_SYMBOL(usb_host_wakeup_irq); + +void usb_host_set_wakeup(struct device *wkup_dev, bool para) +{ + struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data; + if (pdata->wake_up_enable) + pdata->wake_up_enable(pdata, para); +} +EXPORT_SYMBOL(usb_host_set_wakeup); + +#ifdef CONFIG_ARCH_MX28 +#define USBPHY_PHYS_ADDR USBPHY0_PHYS_ADDR +#endif + +int usb_event_is_otg_wakeup(void) +{ + u32 wakeup_irq_bits; + wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ; + + if (__raw_readl(IO_ADDRESS(USBPHY_PHYS_ADDR) + HW_USBPHY_STATUS) && wakeup_irq_bits) { + return true; + } + return false; +} +EXPORT_SYMBOL(usb_event_is_otg_wakeup); + +int fsl_is_usb_plugged(void) +{ + return __raw_readl(IO_ADDRESS(USBPHY_PHYS_ADDR) + HW_USBPHY_STATUS) & \ + BM_USBPHY_STATUS_DEVPLUGIN_STATUS; +} +EXPORT_SYMBOL(fsl_is_usb_plugged); + +void fsl_enable_usb_plugindetect(void) +{ + __raw_writel(BM_USBPHY_CTRL_ENDEVPLUGINDETECT, + IO_ADDRESS(USBPHY_PHYS_ADDR) + HW_USBPHY_CTRL_SET); +} +EXPORT_SYMBOL(fsl_enable_usb_plugindetect); + diff --git a/arch/arm/plat-mxs/usb_wakeup.c b/arch/arm/plat-mxs/usb_wakeup.c new file mode 100644 index 000000000000..a020e85445f1 --- /dev/null +++ b/arch/arm/plat-mxs/usb_wakeup.c @@ -0,0 +1,222 @@ +/* + * 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/sched.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/kthread.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/fsl_devices.h> +#include <linux/suspend.h> +#include <linux/io.h> +#include <mach/arc_otg.h> + +struct wakeup_ctrl { + int wakeup_irq; + int usb_irq; + struct fsl_usb2_wakeup_platform_data *pdata; + struct task_struct *thread; + struct completion event; +}; +static struct wakeup_ctrl *g_ctrl; + +extern int usb_event_is_otg_wakeup(void); +extern void usb_debounce_id_vbus(void); + +static void wakeup_clk_gate(struct fsl_usb2_wakeup_platform_data *pdata, bool on) +{ + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(on); +} + +static bool usb2_is_in_lowpower(struct wakeup_ctrl *ctrl) +{ + int i; + struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata; + /* all the usb module related the wakeup is in lowpower mode */ + for (i = 0; i < 3; i++) { + if (pdata->usb_pdata[i]) { + if (pdata->usb_pdata[i]->phy_lowpower_suspend && !pdata->usb_pdata[i]->lowpower) + return false; + } + } + + return true; +} + +static void delay_process_wakeup(struct wakeup_ctrl *ctrl) +{ + struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata; + disable_irq_nosync(ctrl->wakeup_irq); + if ((ctrl->usb_irq > 0) && (ctrl->wakeup_irq != ctrl->usb_irq)) + disable_irq_nosync(ctrl->usb_irq); + + pdata->usb_wakeup_is_pending = true; + complete(&ctrl->event); +} + +static irqreturn_t usb_wakeup_handler(int irq, void *_dev) +{ + struct wakeup_ctrl *ctrl = (struct wakeup_ctrl *)_dev; + irqreturn_t ret = IRQ_NONE; + if (usb2_is_in_lowpower(ctrl)) { + pr_debug("usb wakeup is here\n"); + delay_process_wakeup(ctrl); + ret = IRQ_HANDLED; + } + return ret; +} + +static enum usb_wakeup_event is_wakeup(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->is_wakeup_event) + return pdata->is_wakeup_event(pdata); + else + return WAKEUP_EVENT_INVALID; +} + +static void wakeup_event_handler(struct wakeup_ctrl *ctrl) +{ + struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata; + int already_waked = 0; + enum usb_wakeup_event wakeup_evt; + int i; + + wakeup_clk_gate(ctrl->pdata, true); + + /* In order to get the real id/vbus value */ + if (usb_event_is_otg_wakeup()) + usb_debounce_id_vbus(); + + for (i = 0; i < 3; i++) { + struct fsl_usb2_platform_data *usb_pdata = pdata->usb_pdata[i]; + if (usb_pdata) { + wakeup_evt = is_wakeup(usb_pdata); + if (wakeup_evt != WAKEUP_EVENT_INVALID) { + if (usb2_is_in_lowpower(ctrl)) + if (usb_pdata->usb_clock_for_pm) + usb_pdata->usb_clock_for_pm(true); + usb_pdata->lowpower = 0; + already_waked = 1; + if (usb_pdata->wakeup_handler) { + usb_pdata->wakeup_handler(usb_pdata); + } + } + } + } + + /* If nothing to wakeup, clear wakeup event */ + if ((already_waked == 0) && pdata->usb_wakeup_exhandle) + pdata->usb_wakeup_exhandle(); + + wakeup_clk_gate(ctrl->pdata, false); + pdata->usb_wakeup_is_pending = false; + wake_up(&pdata->wq); +} + +static int wakeup_event_thread(void *param) +{ + struct wakeup_ctrl *ctrl = (struct wakeup_ctrl *)param; + struct sched_param sch_param = {.sched_priority = 1}; + + sched_setscheduler(current, SCHED_RR, &sch_param); + while (1) { + wait_for_completion_interruptible(&ctrl->event); + if (kthread_should_stop()) + break; + wakeup_event_handler(ctrl); + enable_irq(ctrl->wakeup_irq); + if ((ctrl->usb_irq > 0) && (ctrl->wakeup_irq != ctrl->usb_irq)) + enable_irq(ctrl->usb_irq); + } + return 0; +} + +static int wakeup_dev_probe(struct platform_device *pdev) +{ + struct fsl_usb2_wakeup_platform_data *pdata; + struct wakeup_ctrl *ctrl = NULL; + int status; + unsigned long interrupt_flag; + + printk(KERN_INFO "IMX usb wakeup probe\n"); + + if (!pdev || !pdev->dev.platform_data) + return -ENODEV; + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + pdata = pdev->dev.platform_data; + ctrl->pdata = pdata; + init_waitqueue_head(&pdata->wq); + pdata->usb_wakeup_is_pending = false; + + init_completion(&ctrl->event); + ctrl->wakeup_irq = platform_get_irq(pdev, 0); + ctrl->usb_irq = platform_get_irq(pdev, 1); + if (ctrl->wakeup_irq != ctrl->wakeup_irq) + interrupt_flag = IRQF_DISABLED; + else + interrupt_flag = IRQF_SHARED; + status = request_irq(ctrl->wakeup_irq, usb_wakeup_handler, interrupt_flag, "usb_wakeup", (void *)ctrl); + if (status) + goto error1; + + ctrl->thread = kthread_run(wakeup_event_thread, (void *)ctrl, "usb_wakeup thread"); + status = IS_ERR(ctrl->thread) ? -1 : 0; + if (status) + goto error2; + g_ctrl = ctrl; + + printk(KERN_DEBUG "the wakeup pdata is 0x%p\n", pdata); + return 0; +error2: + free_irq(ctrl->wakeup_irq, (void *)ctrl); +error1: + kfree(ctrl); + return status; +} + +static int wakeup_dev_exit(struct platform_device *pdev) +{ + if (g_ctrl->thread) { + complete(&g_ctrl->event); + kthread_stop(g_ctrl->thread); + } + free_irq(g_ctrl->wakeup_irq, (void *)g_ctrl); + kfree(g_ctrl); + return 0; +} +static struct platform_driver wakeup_d = { + .probe = wakeup_dev_probe, + .remove = wakeup_dev_exit, + .driver = { + .name = "usb_wakeup", + }, +}; + +static int __init wakeup_dev_init(void) +{ + return platform_driver_register(&wakeup_d); +} +static void __exit wakeup_dev_uninit(void) +{ + platform_driver_unregister(&wakeup_d); +} + +subsys_initcall(wakeup_dev_init); +module_exit(wakeup_dev_uninit); + diff --git a/arch/arm/plat-mxs/utmixc.c b/arch/arm/plat-mxs/utmixc.c new file mode 100644 index 000000000000..8e842840e87a --- /dev/null +++ b/arch/arm/plat-mxs/utmixc.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009-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/kernel.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/usb/fsl_xcvr.h> +#include <linux/pmic_external.h> + +#include <mach/hardware.h> +#include <mach/arc_otg.h> +#include <asm/mach-types.h> + +extern void fsl_phy_usb_utmi_init(struct fsl_xcvr_ops *this); +extern void fsl_phy_usb_utmi_uninit(struct fsl_xcvr_ops *this); +extern void fsl_phy_set_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on); +#include <mach/regs-power.h> +#include <asm/io.h> + + +static void set_vbus_draw(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, unsigned mA) +{ +#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW + if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) + & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) { + printk(KERN_INFO "USB enumeration done,current limitation release\r\n"); + __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) | + BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT, REGS_POWER_BASE + + HW_POWER_5VCTRL); + } +#endif +} +static struct fsl_xcvr_ops utmi_ops = { + .name = "utmi", + .xcvr_type = PORTSC_PTS_UTMI, + .init = fsl_phy_usb_utmi_init, + .uninit = fsl_phy_usb_utmi_uninit, + .set_vbus_power = fsl_phy_set_power, + .set_vbus_draw = set_vbus_draw, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); + +static int __init utmixc_init(void) +{ + fsl_usb_xcvr_register(&utmi_ops); + return 0; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +static void __exit utmixc_exit(void) +{ + fsl_usb_xcvr_unregister(&utmi_ops); +} + +#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW + fs_initcall(utmixc_init); +#else + subsys_initcall(utmixc_init); +#endif +module_exit(utmixc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("utmi xcvr driver"); +MODULE_LICENSE("GPL"); |