diff options
Diffstat (limited to 'arch/arm/plat-mxc')
-rw-r--r-- | arch/arm/plat-mxc/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/cpufreq.c | 206 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/devices/platform-gpio_keys.c | 27 | ||||
-rw-r--r-- | arch/arm/plat-mxc/gpio.c | 32 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/devices-common.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/iomux-mx51.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mx31.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mx35.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mxc.h | 13 |
11 files changed, 290 insertions, 5 deletions
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 06875b4dd70..37267095278 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MXC_USE_EPIT) += epit.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o +obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o obj-y += ssi-fiq-ksym.o diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c new file mode 100644 index 00000000000..039538e6879 --- /dev/null +++ b/arch/arm/plat-mxc/cpufreq.c @@ -0,0 +1,206 @@ +/* + * 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 + */ + +/* + * A driver for the Freescale Semiconductor i.MXC CPUfreq module. + * The CPUFREQ driver is for controling CPU frequency. It allows you to change + * the CPU clock speed on the fly. + */ + +#include <linux/cpufreq.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <mach/hardware.h> +#include <mach/clock.h> + +#define CLK32_FREQ 32768 +#define NANOSECOND (1000 * 1000 * 1000) + +struct cpu_op *(*get_cpu_op)(int *op); + +static int cpu_freq_khz_min; +static int cpu_freq_khz_max; + +static struct clk *cpu_clk; +static struct cpufreq_frequency_table *imx_freq_table; + +static int cpu_op_nr; +static struct cpu_op *cpu_op_tbl; + +static int set_cpu_freq(int freq) +{ + int ret = 0; + int org_cpu_rate; + + org_cpu_rate = clk_get_rate(cpu_clk); + if (org_cpu_rate == freq) + return ret; + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + return ret; + } + + return ret; +} + +static int mxc_verify_speed(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -EINVAL; + + return cpufreq_frequency_table_verify(policy, imx_freq_table); +} + +static unsigned int mxc_get_speed(unsigned int cpu) +{ + if (cpu) + return 0; + + return clk_get_rate(cpu_clk) / 1000; +} + +static int mxc_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + int freq_Hz; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, imx_freq_table, + target_freq, relation, &index); + freq_Hz = imx_freq_table[index].frequency * 1000; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = freq_Hz / 1000; + freqs.cpu = 0; + freqs.flags = 0; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + ret = set_cpu_freq(freq_Hz); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return ret; +} + +static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + int i; + + printk(KERN_INFO "i.MXC CPU frequency driver\n"); + + if (policy->cpu != 0) + return -EINVAL; + + if (!get_cpu_op) + return -EINVAL; + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); + return PTR_ERR(cpu_clk); + } + + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000; + cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000; + + imx_freq_table = kmalloc( + sizeof(struct cpufreq_frequency_table) * (cpu_op_nr + 1), + GFP_KERNEL); + if (!imx_freq_table) { + ret = -ENOMEM; + goto err1; + } + + for (i = 0; i < cpu_op_nr; i++) { + imx_freq_table[i].index = i; + imx_freq_table[i].frequency = cpu_op_tbl[i].cpu_rate / 1000; + + if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min) + cpu_freq_khz_min = cpu_op_tbl[i].cpu_rate / 1000; + + if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max) + cpu_freq_khz_max = cpu_op_tbl[i].cpu_rate / 1000; + } + + imx_freq_table[i].index = i; + 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 = 2 * NANOSECOND / CLK32_FREQ; + + ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); + + if (ret < 0) { + printk(KERN_ERR "%s: failed to register i.MXC CPUfreq \ + with error code %d\n", __func__, ret); + goto err; + } + + cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu); + return 0; +err: + kfree(imx_freq_table); +err1: + clk_put(cpu_clk); + return ret; +} + +static int mxc_cpufreq_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + + set_cpu_freq(cpu_freq_khz_max * 1000); + clk_put(cpu_clk); + kfree(imx_freq_table); + return 0; +} + +static struct cpufreq_driver mxc_driver = { + .flags = CPUFREQ_STICKY, + .verify = mxc_verify_speed, + .target = mxc_set_target, + .get = mxc_get_speed, + .init = mxc_cpufreq_init, + .exit = mxc_cpufreq_exit, + .name = "imx", +}; + +static int __devinit mxc_cpufreq_driver_init(void) +{ + return cpufreq_register_driver(&mxc_driver); +} + +static void mxc_cpufreq_driver_exit(void) +{ + cpufreq_unregister_driver(&mxc_driver); +} + +module_init(mxc_cpufreq_driver_init); +module_exit(mxc_cpufreq_driver_exit); + +MODULE_AUTHOR("Freescale Semiconductor Inc. Yong Shen <yong.shen@linaro.org>"); +MODULE_DESCRIPTION("CPUfreq driver for i.MX"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 404799487f1..9aa6f3ea901 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -6,9 +6,13 @@ config IMX_HAVE_PLATFORM_FEC default y if ARCH_MX25 || SOC_IMX27 || ARCH_MX35 || ARCH_MX51 config IMX_HAVE_PLATFORM_FLEXCAN - select HAVE_CAN_FLEXCAN + select HAVE_CAN_FLEXCAN if CAN bool +config IMX_HAVE_PLATFORM_GPIO_KEYS + bool + default y if ARCH_MX51 + config IMX_HAVE_PLATFORM_IMX_I2C bool diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 0a3c1f08941..45aefeb283b 100644 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o obj-y += platform-imx-dma.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o diff --git a/arch/arm/plat-mxc/devices/platform-gpio_keys.c b/arch/arm/plat-mxc/devices/platform-gpio_keys.c new file mode 100644 index 00000000000..1c53a532ea0 --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-gpio_keys.c @@ -0,0 +1,27 @@ +/* + * 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 <asm/sizes.h> +#include <mach/hardware.h> +#include <mach/devices-common.h> + +struct platform_device *__init imx_add_gpio_keys( + const struct gpio_keys_platform_data *pdata) +{ + return imx_add_platform_device("gpio-keys", -1, NULL, + 0, pdata, sizeof(*pdata)); +} diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 9d38da077ed..9c3e36232b5 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -20,6 +20,7 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/gpio.h> @@ -201,11 +202,42 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) } } +/* + * Set interrupt number "irq" in the GPIO as a wake-up source. + * While system is running, all registered GPIO interrupts need to have + * wake-up enabled. When system is suspended, only selected GPIO interrupts + * need to have wake-up enabled. + * @param irq interrupt source number + * @param enable enable as wake-up if equal to non-zero + * @return This function returns 0 on success. + */ +static int gpio_set_wake_irq(u32 irq, u32 enable) +{ + u32 gpio = irq_to_gpio(irq); + u32 gpio_idx = gpio & 0x1F; + struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32]; + + if (enable) { + if (port->irq_high && (gpio_idx >= 16)) + enable_irq_wake(port->irq_high); + else + enable_irq_wake(port->irq); + } else { + if (port->irq_high && (gpio_idx >= 16)) + disable_irq_wake(port->irq_high); + else + disable_irq_wake(port->irq); + } + + return 0; +} + static struct irq_chip gpio_irq_chip = { .ack = gpio_ack_irq, .mask = gpio_mask_irq, .unmask = gpio_unmask_irq, .set_type = gpio_set_irq_type, + .set_wake = gpio_set_wake_irq, }; static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index 86d7575a564..8c6896fd1e5 100644 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -29,6 +29,10 @@ struct platform_device *__init imx_add_flexcan(int id, resource_size_t irq, const struct flexcan_platform_data *pdata); +#include <linux/gpio_keys.h> +struct platform_device *__init imx_add_gpio_keys( + const struct gpio_keys_platform_data *pdata); + #include <mach/i2c.h> struct imx_imx_i2c_data { int id; diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h index e46b1c2836d..d7a41e9a260 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h @@ -45,6 +45,8 @@ typedef enum iomux_config { PAD_CTL_PKE | PAD_CTL_HYS) #define MX51_GPIO_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \ PAD_CTL_SRE_FAST) +#define MX51_GPIO_PAD_CTRL_2 (PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \ + PAD_CTL_PUS_100K_UP) #define MX51_ECSPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \ PAD_CTL_SRE_FAST) #define MX51_SDHCI_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \ diff --git a/arch/arm/plat-mxc/include/mach/mx31.h b/arch/arm/plat-mxc/include/mach/mx31.h index 03e2afabc9f..61cfe827498 100644 --- a/arch/arm/plat-mxc/include/mach/mx31.h +++ b/arch/arm/plat-mxc/include/mach/mx31.h @@ -240,7 +240,6 @@ static inline void mx31_setup_weimcs(size_t cs, #define MPEG4_ENC_BASE_ADDR MX31_MPEG4_ENC_BASE_ADDR #define MXC_INT_MPEG4_ENCODER MX31_INT_MPEG4_ENCODER #define MXC_INT_FIRI MX31_INT_FIRI -#define MXC_INT_MMC_SDHC1 MX31_INT_MMC_SDHC1 #define MXC_INT_MBX MX31_INT_MBX #define MXC_INT_CSPI3 MX31_INT_CSPI3 #define MXC_INT_SIM2 MX31_INT_SIM2 diff --git a/arch/arm/plat-mxc/include/mach/mx35.h b/arch/arm/plat-mxc/include/mach/mx35.h index ff905cb3245..6267cff6035 100644 --- a/arch/arm/plat-mxc/include/mach/mx35.h +++ b/arch/arm/plat-mxc/include/mach/mx35.h @@ -197,8 +197,6 @@ /* these should go away */ #define MXC_FEC_BASE_ADDR MX35_FEC_BASE_ADDR #define MXC_INT_OWIRE MX35_INT_OWIRE -#define MXC_INT_MMC_SDHC2 MX35_INT_MMC_SDHC2 -#define MXC_INT_MMC_SDHC3 MX35_INT_MMC_SDHC3 #define MXC_INT_GPU2D MX35_INT_GPU2D #define MXC_INT_ASRC MX35_INT_ASRC #define MXC_INT_USBHS MX35_INT_USBHS diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index a790bf21297..a42c7207082 100644 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) * * This program is free software; you can redistribute it and/or @@ -20,6 +20,8 @@ #ifndef __ASM_ARCH_MXC_H__ #define __ASM_ARCH_MXC_H__ +#include <linux/types.h> + #ifndef __ASM_ARCH_MXC_HARDWARE_H__ #error "Do not include directly." #endif @@ -133,6 +135,15 @@ extern unsigned int __mxc_cpu_type; # define cpu_is_mxc91231() (0) #endif +#ifndef __ASSEMBLY__ + +struct cpu_op { + u32 cpu_rate; +}; + +extern struct cpu_op *(*get_cpu_op)(int *op); +#endif + #if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2) /* These are deprecated, use mx[23][157]_setup_weimcs instead. */ #define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10)) |