| Gregory Bean | 1963a2a | 2010-08-28 10:05:44 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 
|  | 2 | * | 
|  | 3 | * This program is free software; you can redistribute it and/or modify | 
|  | 4 | * it under the terms of the GNU General Public License version 2 and | 
|  | 5 | * only version 2 as published by the Free Software Foundation. | 
|  | 6 | * | 
|  | 7 | * This program is distributed in the hope that it will be useful, | 
|  | 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 10 | * GNU General Public License for more details. | 
|  | 11 | * | 
|  | 12 | * You should have received a copy of the GNU General Public License | 
|  | 13 | * along with this program; if not, write to the Free Software | 
|  | 14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 
|  | 15 | * 02110-1301, USA. | 
|  | 16 | */ | 
|  | 17 | #include <linux/module.h> | 
|  | 18 | #include <linux/spinlock.h> | 
|  | 19 | #include "gpiomux.h" | 
|  | 20 |  | 
|  | 21 | static DEFINE_SPINLOCK(gpiomux_lock); | 
|  | 22 |  | 
|  | 23 | int msm_gpiomux_write(unsigned gpio, | 
|  | 24 | gpiomux_config_t active, | 
|  | 25 | gpiomux_config_t suspended) | 
|  | 26 | { | 
|  | 27 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | 
|  | 28 | unsigned long irq_flags; | 
|  | 29 | gpiomux_config_t setting; | 
|  | 30 |  | 
|  | 31 | if (gpio >= GPIOMUX_NGPIOS) | 
|  | 32 | return -EINVAL; | 
|  | 33 |  | 
|  | 34 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | 
|  | 35 |  | 
|  | 36 | if (active & GPIOMUX_VALID) | 
|  | 37 | cfg->active = active; | 
|  | 38 |  | 
|  | 39 | if (suspended & GPIOMUX_VALID) | 
|  | 40 | cfg->suspended = suspended; | 
|  | 41 |  | 
|  | 42 | setting = cfg->ref ? active : suspended; | 
|  | 43 | if (setting & GPIOMUX_VALID) | 
|  | 44 | __msm_gpiomux_write(gpio, setting); | 
|  | 45 |  | 
|  | 46 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | 
|  | 47 | return 0; | 
|  | 48 | } | 
|  | 49 | EXPORT_SYMBOL(msm_gpiomux_write); | 
|  | 50 |  | 
|  | 51 | int msm_gpiomux_get(unsigned gpio) | 
|  | 52 | { | 
|  | 53 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | 
|  | 54 | unsigned long irq_flags; | 
|  | 55 |  | 
|  | 56 | if (gpio >= GPIOMUX_NGPIOS) | 
|  | 57 | return -EINVAL; | 
|  | 58 |  | 
|  | 59 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | 
|  | 60 | if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID) | 
|  | 61 | __msm_gpiomux_write(gpio, cfg->active); | 
|  | 62 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | 
|  | 63 | return 0; | 
|  | 64 | } | 
|  | 65 | EXPORT_SYMBOL(msm_gpiomux_get); | 
|  | 66 |  | 
|  | 67 | int msm_gpiomux_put(unsigned gpio) | 
|  | 68 | { | 
|  | 69 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | 
|  | 70 | unsigned long irq_flags; | 
|  | 71 |  | 
|  | 72 | if (gpio >= GPIOMUX_NGPIOS) | 
|  | 73 | return -EINVAL; | 
|  | 74 |  | 
|  | 75 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | 
|  | 76 | BUG_ON(cfg->ref == 0); | 
|  | 77 | if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID) | 
|  | 78 | __msm_gpiomux_write(gpio, cfg->suspended); | 
|  | 79 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | 
|  | 80 | return 0; | 
|  | 81 | } | 
|  | 82 | EXPORT_SYMBOL(msm_gpiomux_put); | 
|  | 83 |  | 
|  | 84 | static int __init gpiomux_init(void) | 
|  | 85 | { | 
|  | 86 | unsigned n; | 
|  | 87 |  | 
|  | 88 | for (n = 0; n < GPIOMUX_NGPIOS; ++n) { | 
|  | 89 | msm_gpiomux_configs[n].ref = 0; | 
|  | 90 | if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID)) | 
|  | 91 | continue; | 
|  | 92 | __msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended); | 
|  | 93 | } | 
|  | 94 | return 0; | 
|  | 95 | } | 
|  | 96 | postcore_initcall(gpiomux_init); |