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 + | 
