Commit | Line | Data |
---|---|---|
1963a2af GB |
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" | |
eda9dcfa | 20 | #include "proc_comm.h" |
1963a2af GB |
21 | |
22 | static DEFINE_SPINLOCK(gpiomux_lock); | |
23 | ||
eda9dcfa RV |
24 | static void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val) |
25 | { | |
26 | unsigned tlmm_config = (val & ~GPIOMUX_CTL_MASK) | | |
27 | ((gpio & 0x3ff) << 4); | |
28 | unsigned tlmm_disable = 0; | |
29 | int rc; | |
30 | ||
31 | rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, | |
32 | &tlmm_config, &tlmm_disable); | |
33 | if (rc) | |
34 | pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n", | |
35 | __func__, rc, tlmm_config, tlmm_disable); | |
36 | } | |
37 | ||
1963a2af GB |
38 | int msm_gpiomux_write(unsigned gpio, |
39 | gpiomux_config_t active, | |
40 | gpiomux_config_t suspended) | |
41 | { | |
42 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | |
43 | unsigned long irq_flags; | |
44 | gpiomux_config_t setting; | |
45 | ||
46 | if (gpio >= GPIOMUX_NGPIOS) | |
47 | return -EINVAL; | |
48 | ||
49 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | |
50 | ||
51 | if (active & GPIOMUX_VALID) | |
52 | cfg->active = active; | |
53 | ||
54 | if (suspended & GPIOMUX_VALID) | |
55 | cfg->suspended = suspended; | |
56 | ||
57 | setting = cfg->ref ? active : suspended; | |
58 | if (setting & GPIOMUX_VALID) | |
59 | __msm_gpiomux_write(gpio, setting); | |
60 | ||
61 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | |
62 | return 0; | |
63 | } | |
64 | EXPORT_SYMBOL(msm_gpiomux_write); | |
65 | ||
66 | int msm_gpiomux_get(unsigned gpio) | |
67 | { | |
68 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | |
69 | unsigned long irq_flags; | |
70 | ||
71 | if (gpio >= GPIOMUX_NGPIOS) | |
72 | return -EINVAL; | |
73 | ||
74 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | |
75 | if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID) | |
76 | __msm_gpiomux_write(gpio, cfg->active); | |
77 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | |
78 | return 0; | |
79 | } | |
80 | EXPORT_SYMBOL(msm_gpiomux_get); | |
81 | ||
82 | int msm_gpiomux_put(unsigned gpio) | |
83 | { | |
84 | struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio; | |
85 | unsigned long irq_flags; | |
86 | ||
87 | if (gpio >= GPIOMUX_NGPIOS) | |
88 | return -EINVAL; | |
89 | ||
90 | spin_lock_irqsave(&gpiomux_lock, irq_flags); | |
91 | BUG_ON(cfg->ref == 0); | |
92 | if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID) | |
93 | __msm_gpiomux_write(gpio, cfg->suspended); | |
94 | spin_unlock_irqrestore(&gpiomux_lock, irq_flags); | |
95 | return 0; | |
96 | } | |
97 | EXPORT_SYMBOL(msm_gpiomux_put); | |
98 | ||
99 | static int __init gpiomux_init(void) | |
100 | { | |
101 | unsigned n; | |
102 | ||
103 | for (n = 0; n < GPIOMUX_NGPIOS; ++n) { | |
104 | msm_gpiomux_configs[n].ref = 0; | |
105 | if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID)) | |
106 | continue; | |
107 | __msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended); | |
108 | } | |
109 | return 0; | |
110 | } | |
111 | postcore_initcall(gpiomux_init); |