97 lines
		
	
	
	
		
			2.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			97 lines
		
	
	
	
		
			2.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /* Copyright (c) 2010, Code Aurora Forum. 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 version 2 and | ||
|  |  * only version 2 as published by the Free Software Foundation. | ||
|  |  * | ||
|  |  * 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/spinlock.h>
 | ||
|  | #include "gpiomux.h"
 | ||
|  | 
 | ||
|  | static DEFINE_SPINLOCK(gpiomux_lock); | ||
|  | 
 | ||
|  | int msm_gpiomux_write(unsigned gpio, | ||
|  | 		      gpiomux_config_t active, | ||
|  | 		      gpiomux_config_t suspended) | ||
|  | { | ||
|  | 	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | ||
|  | 	unsigned long irq_flags; | ||
|  | 	gpiomux_config_t setting; | ||
|  | 
 | ||
|  | 	if (gpio >= GPIOMUX_NGPIOS) | ||
|  | 		return -EINVAL; | ||
|  | 
 | ||
|  | 	spin_lock_irqsave(&gpiomux_lock, irq_flags); | ||
|  | 
 | ||
|  | 	if (active & GPIOMUX_VALID) | ||
|  | 		cfg->active = active; | ||
|  | 
 | ||
|  | 	if (suspended & GPIOMUX_VALID) | ||
|  | 		cfg->suspended = suspended; | ||
|  | 
 | ||
|  | 	setting = cfg->ref ? active : suspended; | ||
|  | 	if (setting & GPIOMUX_VALID) | ||
|  | 		__msm_gpiomux_write(gpio, setting); | ||
|  | 
 | ||
|  | 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | ||
|  | 	return 0; | ||
|  | } | ||
|  | EXPORT_SYMBOL(msm_gpiomux_write); | ||
|  | 
 | ||
|  | int msm_gpiomux_get(unsigned gpio) | ||
|  | { | ||
|  | 	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | ||
|  | 	unsigned long irq_flags; | ||
|  | 
 | ||
|  | 	if (gpio >= GPIOMUX_NGPIOS) | ||
|  | 		return -EINVAL; | ||
|  | 
 | ||
|  | 	spin_lock_irqsave(&gpiomux_lock, irq_flags); | ||
|  | 	if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID) | ||
|  | 		__msm_gpiomux_write(gpio, cfg->active); | ||
|  | 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | ||
|  | 	return 0; | ||
|  | } | ||
|  | EXPORT_SYMBOL(msm_gpiomux_get); | ||
|  | 
 | ||
|  | int msm_gpiomux_put(unsigned gpio) | ||
|  | { | ||
|  | 	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | ||
|  | 	unsigned long irq_flags; | ||
|  | 
 | ||
|  | 	if (gpio >= GPIOMUX_NGPIOS) | ||
|  | 		return -EINVAL; | ||
|  | 
 | ||
|  | 	spin_lock_irqsave(&gpiomux_lock, irq_flags); | ||
|  | 	BUG_ON(cfg->ref == 0); | ||
|  | 	if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID) | ||
|  | 		__msm_gpiomux_write(gpio, cfg->suspended); | ||
|  | 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | ||
|  | 	return 0; | ||
|  | } | ||
|  | EXPORT_SYMBOL(msm_gpiomux_put); | ||
|  | 
 | ||
|  | static int __init gpiomux_init(void) | ||
|  | { | ||
|  | 	unsigned n; | ||
|  | 
 | ||
|  | 	for (n = 0; n < GPIOMUX_NGPIOS; ++n) { | ||
|  | 		msm_gpiomux_configs[n].ref = 0; | ||
|  | 		if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID)) | ||
|  | 			continue; | ||
|  | 		__msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended); | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | postcore_initcall(gpiomux_init); |