| 
									
										
											  
											
												msm: add gpiomux api for gpio multiplex & configuration.
Add the 'gpiomux' api, which addresses the following shortcomings
of existing tlmm api:
- gpio power-collapse, which is managed by a peripheral processor on
  other targets, must be managed by the application processor on the 8x60.
- The enable/disable flag of the legacy gpio_tlmm_config api
  is not applicable on the 8x60, and causes confusion.
- The gpio 'direction' bits are meaningless for all func_sel
  configurations except for generic-gpio mode (func_sel 0), in which
  case the gpio_direction_* functions should be used.  Having these
  bits in the tlmm api leads to confusion and misuse of the gpiolib
  api, and they have been removed in gpiomux.
- The functional api of the legacy system ran contrary to the typical
  use-case, which is a single massive configuration at boot.  Rather
  than forcing hundreds of 'config' function calls, the new api
  allows data to be configured with a single table.
gpiomux_get and gpiomux_put are meant to be called automatically
when gpio_request and gpio_free are called, giving automatic
gpiomux/tlmm control to those drivers/lines with simple
power profiles - in the simplest cases, an entry in the gpiomux table
and the correct usage of gpiolib is all that is required to get proper
gpio power control.
Signed-off-by: Gregory Bean <gbean@codeaurora.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
											
										 
											2010-08-28 10:05:44 -07:00
										 |  |  | /* 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"
 | 
					
						
							| 
									
										
										
										
											2013-06-10 15:50:19 -07:00
										 |  |  | #include "proc_comm.h"
 | 
					
						
							| 
									
										
											  
											
												msm: add gpiomux api for gpio multiplex & configuration.
Add the 'gpiomux' api, which addresses the following shortcomings
of existing tlmm api:
- gpio power-collapse, which is managed by a peripheral processor on
  other targets, must be managed by the application processor on the 8x60.
- The enable/disable flag of the legacy gpio_tlmm_config api
  is not applicable on the 8x60, and causes confusion.
- The gpio 'direction' bits are meaningless for all func_sel
  configurations except for generic-gpio mode (func_sel 0), in which
  case the gpio_direction_* functions should be used.  Having these
  bits in the tlmm api leads to confusion and misuse of the gpiolib
  api, and they have been removed in gpiomux.
- The functional api of the legacy system ran contrary to the typical
  use-case, which is a single massive configuration at boot.  Rather
  than forcing hundreds of 'config' function calls, the new api
  allows data to be configured with a single table.
gpiomux_get and gpiomux_put are meant to be called automatically
when gpio_request and gpio_free are called, giving automatic
gpiomux/tlmm control to those drivers/lines with simple
power profiles - in the simplest cases, an entry in the gpiomux table
and the correct usage of gpiolib is all that is required to get proper
gpio power control.
Signed-off-by: Gregory Bean <gbean@codeaurora.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
											
										 
											2010-08-28 10:05:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static DEFINE_SPINLOCK(gpiomux_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-10 15:50:19 -07:00
										 |  |  | static void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) | | 
					
						
							|  |  |  | 				((gpio & 0x3ff) << 4); | 
					
						
							|  |  |  | 	unsigned tlmm_disable = 0; | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, | 
					
						
							|  |  |  | 			   &tlmm_config, &tlmm_disable); | 
					
						
							|  |  |  | 	if (rc) | 
					
						
							|  |  |  | 		pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n", | 
					
						
							|  |  |  | 		       __func__, rc, tlmm_config, tlmm_disable); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												msm: add gpiomux api for gpio multiplex & configuration.
Add the 'gpiomux' api, which addresses the following shortcomings
of existing tlmm api:
- gpio power-collapse, which is managed by a peripheral processor on
  other targets, must be managed by the application processor on the 8x60.
- The enable/disable flag of the legacy gpio_tlmm_config api
  is not applicable on the 8x60, and causes confusion.
- The gpio 'direction' bits are meaningless for all func_sel
  configurations except for generic-gpio mode (func_sel 0), in which
  case the gpio_direction_* functions should be used.  Having these
  bits in the tlmm api leads to confusion and misuse of the gpiolib
  api, and they have been removed in gpiomux.
- The functional api of the legacy system ran contrary to the typical
  use-case, which is a single massive configuration at boot.  Rather
  than forcing hundreds of 'config' function calls, the new api
  allows data to be configured with a single table.
gpiomux_get and gpiomux_put are meant to be called automatically
when gpio_request and gpio_free are called, giving automatic
gpiomux/tlmm control to those drivers/lines with simple
power profiles - in the simplest cases, an entry in the gpiomux table
and the correct usage of gpiolib is all that is required to get proper
gpio power control.
Signed-off-by: Gregory Bean <gbean@codeaurora.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
											
										 
											2010-08-28 10:05:44 -07:00
										 |  |  | 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); |