diff options
Diffstat (limited to 'arch/arm/plat-mxs')
-rw-r--r-- | arch/arm/plat-mxs/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxs/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxs/clock.c | 48 | ||||
-rw-r--r-- | arch/arm/plat-mxs/cpufreq.c | 62 | ||||
-rw-r--r-- | arch/arm/plat-mxs/device.c | 66 | ||||
-rw-r--r-- | arch/arm/plat-mxs/dmaengine.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxs/gpio.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-mxs/icoll.c | 6 | ||||
-rw-r--r-- | arch/arm/plat-mxs/include/mach/bus_freq.h | 11 | ||||
-rw-r--r-- | arch/arm/plat-mxs/include/mach/clock.h | 21 | ||||
-rw-r--r-- | arch/arm/plat-mxs/include/mach/device.h | 56 | ||||
-rw-r--r-- | arch/arm/plat-mxs/include/mach/system.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxs/include/mach/unique-id.h | 30 | ||||
-rw-r--r-- | arch/arm/plat-mxs/iram.c | 5 | ||||
-rw-r--r-- | arch/arm/plat-mxs/unique-id.c | 198 | ||||
-rw-r--r-- | arch/arm/plat-mxs/utmixc.c | 2 |
16 files changed, 425 insertions, 88 deletions
diff --git a/arch/arm/plat-mxs/Kconfig b/arch/arm/plat-mxs/Kconfig index dd6689ecf5d0..63768f85a327 100644 --- a/arch/arm/plat-mxs/Kconfig +++ b/arch/arm/plat-mxs/Kconfig @@ -19,6 +19,7 @@ config ARCH_MX28 config ARCH_MX23 bool "Freescale MX23" select CPU_ARM926T + select FIQ select ZONE_DMA select MXS_ICOLL select MXS_DMA_ENGINE diff --git a/arch/arm/plat-mxs/Makefile b/arch/arm/plat-mxs/Makefile index 2c271285bdfd..e252630479d9 100644 --- a/arch/arm/plat-mxs/Makefile +++ b/arch/arm/plat-mxs/Makefile @@ -8,6 +8,8 @@ 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 diff --git a/arch/arm/plat-mxs/clock.c b/arch/arm/plat-mxs/clock.c index 9fecdbde49ad..1b98b1e51164 100644 --- a/arch/arm/plat-mxs/clock.c +++ b/arch/arm/plat-mxs/clock.c @@ -29,6 +29,9 @@ #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); /* @@ -109,7 +112,11 @@ int clk_enable(struct clk *clk) return -EINVAL; spin_lock_irqsave(&clockfw_lock, flags); - pre_usage = clk->ref; + 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) @@ -133,7 +140,7 @@ void clk_disable(struct clk *clk) __clk_disable(clk); spin_unlock_irqrestore(&clockfw_lock, flags); if ((clk->flags & CPU_FREQ_TRIG_UPDATE) - && (clk->ref == 0)) { + && ((clk->ref & CLK_EN_MASK) == 0)) { cpufreq_trig_needed = 1; cpufreq_update_policy(0); } @@ -279,3 +286,40 @@ void clk_unregister(struct clk_lookup *lookup) 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/cpufreq.c b/arch/arm/plat-mxs/cpufreq.c index d36baa740dbc..a188b21d9bf4 100644 --- a/arch/arm/plat-mxs/cpufreq.c +++ b/arch/arm/plat-mxs/cpufreq.c @@ -40,6 +40,7 @@ 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; @@ -62,11 +63,19 @@ 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].index = end_index - i; imx_freq_table[end_index - 1 - i].frequency = profiles[i].cpu; @@ -135,8 +144,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) return 0; } - cpu_clk_set_pll_on(cpu_clk, freqs.new); - if (cpu_regulator && (freqs.old < freqs.new)) { ret = regulator_set_current_limit(cpu_regulator, profiles[i].cur, profiles[i].cur); @@ -149,10 +156,16 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) 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); - clk_set_rate(emi_clk, (profiles[i].emi) * 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, @@ -208,17 +221,18 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) 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); - if (freqs.old == 64000) - clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000); - if (freqs.old != 64000) - clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); + clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); clk_set_rate(emi_clk, (profiles[i].emi) * 1000); } - udelay(100); - cpu_clk_set_pll_off(cpu_clk, freqs.new); + 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); @@ -231,7 +245,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) if (high_freq_needed == 1) { high_freq_needed = 0; cur_freq_table_size = lcd_on_freq_table_size; - hbus_auto_slow_mode_disable(); set_freq_table(policy, cur_freq_table_size); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -293,11 +306,22 @@ static int mxs_target(struct cpufreq_policy *policy, 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; - hbus_auto_slow_mode_enable(); + /* 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; - hbus_auto_slow_mode_disable(); + clk_enable_h_autoslow(false); } set_freq_table(policy, cur_freq_table_size); @@ -354,6 +378,12 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy) 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); @@ -419,13 +449,13 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy) for (i = 0; i < ARRAY_SIZE(profiles); i++) { if ((profiles[i].cpu) == 0) { - lcd_off_freq_table_size = i + 1; + lcd_off_freq_table_size = i; break; } } if (i == ARRAY_SIZE(profiles)) - lcd_off_freq_table_size = i + 1; + lcd_off_freq_table_size = i; /* Set the current working point. */ set_freq_table(policy, lcd_on_freq_table_size); @@ -447,6 +477,8 @@ out_cur: clk_put(emi_clk); out_emi: + clk_put(x_clk); +out_x: clk_put(ahb_clk); out_ahb: clk_put(cpu_clk); diff --git a/arch/arm/plat-mxs/device.c b/arch/arm/plat-mxs/device.c index 00180846885b..027408950382 100644 --- a/arch/arm/plat-mxs/device.c +++ b/arch/arm/plat-mxs/device.c @@ -24,6 +24,7 @@ #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/gpmi-nfc.h> #include <mach/device.h> @@ -138,10 +139,10 @@ static struct platform_device mxs_i2c[] = { }; #endif -#if defined(CONFIG_MTD_NAND_GPMI1) || \ - defined(CONFIG_MTD_NAND_GPMI1_MODULE) -static struct platform_device mxs_gpmi = { - .name = "gpmi", +#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, @@ -175,6 +176,20 @@ static struct platform_device mxs_mmc[] = { }; #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", @@ -195,6 +210,25 @@ static struct platform_device mxs_fec[] = { .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 @@ -482,12 +516,12 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #endif -#if defined(CONFIG_MTD_NAND_GPMI1) || \ - defined(CONFIG_MTD_NAND_GPMI1_MODULE) +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) { - .name = "gpmi", + .name = GPMI_NFC_DRIVER_NAME, .size = 1, - .pdev = &mxs_gpmi, + .pdev = &gpmi_nfc, }, #endif @@ -500,6 +534,14 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #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", @@ -565,6 +607,14 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #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", diff --git a/arch/arm/plat-mxs/dmaengine.c b/arch/arm/plat-mxs/dmaengine.c index 453346e4057f..52330d3ea9e3 100644 --- a/arch/arm/plat-mxs/dmaengine.c +++ b/arch/arm/plat-mxs/dmaengine.c @@ -159,7 +159,7 @@ void mxs_dma_disable(int channel) pchan->flags &= ~MXS_DMA_FLAGS_BUSY; pchan->active_num = 0; pchan->pending_num = 0; - list_splice(&pchan->active, &pchan->done); + list_splice_init(&pchan->active, &pchan->done); spin_unlock_irqrestore(&pchan->lock, flags); mutex_unlock(&mxs_dma_mutex); } diff --git a/arch/arm/plat-mxs/gpio.c b/arch/arm/plat-mxs/gpio.c index f12d417b03e9..6c67c2bcfc5b 100644 --- a/arch/arm/plat-mxs/gpio.c +++ b/arch/arm/plat-mxs/gpio.c @@ -175,6 +175,8 @@ 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, }; diff --git a/arch/arm/plat-mxs/icoll.c b/arch/arm/plat-mxs/icoll.c index bb4e4c12cb23..1e0b55bd26a9 100644 --- a/arch/arm/plat-mxs/icoll.c +++ b/arch/arm/plat-mxs/icoll.c @@ -56,10 +56,16 @@ static void icoll_unmask_irq(unsigned int irq) 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) diff --git a/arch/arm/plat-mxs/include/mach/bus_freq.h b/arch/arm/plat-mxs/include/mach/bus_freq.h index a0254e84ca5c..0c41cd2205ff 100644 --- a/arch/arm/plat-mxs/include/mach/bus_freq.h +++ b/arch/arm/plat-mxs/include/mach/bus_freq.h @@ -33,13 +33,14 @@ struct profile { int cur; int vddio; int vdda; - int pll_off; + u16 xbus; + /* map of the upper 16 bits of HW_CLKCTRL_HBUS register */ + u16 h_autoslow_flags; }; -void hbus_auto_slow_mode_enable(void); -void hbus_auto_slow_mode_disable(void); -extern int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq); -extern int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq); +/* 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/clock.h b/arch/arm/plat-mxs/include/mach/clock.h index 744a031b42b6..b506468976b5 100644 --- a/arch/arm/plat-mxs/include/mach/clock.h +++ b/arch/arm/plat-mxs/include/mach/clock.h @@ -30,11 +30,12 @@ struct clk { struct clk *secondary; unsigned long flags; - __s8 ref; + 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; @@ -71,16 +72,24 @@ struct clk { 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); -static inline int clk_is_busy(struct clk *clk) -{ - return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits); -} +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; @@ -89,6 +98,8 @@ struct mxs_emi_scaling_data { 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; diff --git a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h index 7a99647ed0ff..9598ccdaa718 100644 --- a/arch/arm/plat-mxs/include/mach/device.h +++ b/arch/arm/plat-mxs/include/mach/device.h @@ -119,6 +119,11 @@ struct mxs_mma7450_platform_data { int int2; }; +struct mxs_spi_platform_data { + int (*hw_pin_init)(void); + int (*hw_pin_release)(void); +}; + struct flexcan_platform_data { char *core_reg; char *io_reg; @@ -169,57 +174,6 @@ struct mxs_audio_platform_data { void *priv; /* used by board specific functions */ }; -/** - * struct gpmi_platform_data - GPMI driver platform data. - * - * This structure communicates platform-specific information to the GPMI driver - * that can't be expressed as resources. - * - * @io_uA: The current limit, in uA. - * @min_prop_delay_in_ns: Minimum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @max_prop_delay_in_ns: Maximum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @pinmux_handler: A pointer to a function the driver will call to - * request the pins it needs. - * @boot_area_size_in_bytes: The amount of space reserved for use by the boot - * ROM on the first and second chips. If this value is - * zero, it indicates we're not reserving any space - * for the boot area. - * @partition_source_types: An array of strings that name sources of - * partitioning information (e.g., the boot loader, - * the kernel command line, etc.). The function - * parse_mtd_partitions() recognizes these names and - * applies the appropriate "plugins" to discover - * partitioning information. If any is found, it will - * be applied to the "general use" MTD (it will NOT - * override the boot area protection mechanism). - * @partitions: An optional pointer to an array of partition - * descriptions. If the driver finds no partitioning - * information elsewhere, it will apply these to the - * "general use" MTD (they do NOT override the boot - * area protection mechanism). - * @partition_count: The number of elements in the partitions array. - */ - -struct gpmi_platform_data { - - int io_uA; - - unsigned min_prop_delay_in_ns; - unsigned max_prop_delay_in_ns; - - int (*pinmux_handler)(void); - - uint32_t boot_area_size_in_bytes; - - const char **partition_source_types; - - struct mtd_partition *partitions; - unsigned partition_count; - -}; - struct mxs_persistent_bit_config { int reg; int start; diff --git a/arch/arm/plat-mxs/include/mach/system.h b/arch/arm/plat-mxs/include/mach/system.h index 63604de8d74a..faaa2ff3cf13 100644 --- a/arch/arm/plat-mxs/include/mach/system.h +++ b/arch/arm/plat-mxs/include/mach/system.h @@ -25,5 +25,6 @@ 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/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/iram.c b/arch/arm/plat-mxs/iram.c index 3d2a391bd2d1..c63b0a2a9a10 100644 --- a/arch/arm/plat-mxs/iram.c +++ b/arch/arm/plat-mxs/iram.c @@ -36,6 +36,11 @@ void *iram_alloc(unsigned int size, unsigned long *dma_addr) *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); diff --git a/arch/arm/plat-mxs/unique-id.c b/arch/arm/plat-mxs/unique-id.c new file mode 100644 index 000000000000..35c0fcdab605 --- /dev/null +++ b/arch/arm/plat-mxs/unique-id.c @@ -0,0 +1,198 @@ +/* + * 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 <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/utmixc.c b/arch/arm/plat-mxs/utmixc.c index 1e9015d6de3f..8ad6bd4f3654 100644 --- a/arch/arm/plat-mxs/utmixc.c +++ b/arch/arm/plat-mxs/utmixc.c @@ -45,7 +45,7 @@ static void set_vbus_draw(struct fsl_xcvr_ops *this, { #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) - & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) { + & 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 + |