blob: b8045ed2209a44bd0c32351073cd2ea7ade5c91a [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, 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 */
13
14#include <linux/bitops.h>
15#include <linux/gpio.h>
16#include <linux/io.h>
17#include <linux/module.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070018#include <mach/gpiomux.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019#include "gpio_hw.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
21#define MSM_GPIO_BANK(bank, first, last) \
22 { \
23 .regs = { \
24 .out = MSM_GPIO_OUT_##bank, \
25 .in = MSM_GPIO_IN_##bank, \
26 .oe = MSM_GPIO_OE_##bank, \
27 }, \
28 .chip = { \
29 .base = (first), \
30 .ngpio = (last) - (first) + 1, \
31 .get = msm_gpio_get, \
32 .set = msm_gpio_set, \
33 .direction_input = msm_gpio_direction_input, \
34 .direction_output = msm_gpio_direction_output, \
35 .request = msm_gpio_request, \
36 .free = msm_gpio_free, \
37 } \
38 }
39
40struct msm_gpio_regs {
41 void __iomem *out;
42 void __iomem *in;
43 void __iomem *oe;
44};
45
46struct msm_gpio_chip {
47 spinlock_t lock;
48 struct gpio_chip chip;
49 struct msm_gpio_regs regs;
50};
51
52static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
53 unsigned offset, unsigned on)
54{
55 unsigned mask = BIT(offset);
56 unsigned val;
57
58 val = __raw_readl(msm_chip->regs.out);
59 if (on)
60 __raw_writel(val | mask, msm_chip->regs.out);
61 else
62 __raw_writel(val & ~mask, msm_chip->regs.out);
63 return 0;
64}
65
66static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
67{
68 struct msm_gpio_chip *msm_chip;
69 unsigned long irq_flags;
70
71 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
72 spin_lock_irqsave(&msm_chip->lock, irq_flags);
73 __raw_writel(__raw_readl(msm_chip->regs.oe) & ~BIT(offset),
74 msm_chip->regs.oe);
75 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
76 return 0;
77}
78
79static int
80msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
81{
82 struct msm_gpio_chip *msm_chip;
83 unsigned long irq_flags;
84
85 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
86 spin_lock_irqsave(&msm_chip->lock, irq_flags);
87 msm_gpio_write(msm_chip, offset, value);
88 __raw_writel(__raw_readl(msm_chip->regs.oe) | BIT(offset),
89 msm_chip->regs.oe);
90 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
91 return 0;
92}
93
94static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
95{
96 struct msm_gpio_chip *msm_chip;
97
98 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
99 return (__raw_readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
100}
101
102static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
103{
104 struct msm_gpio_chip *msm_chip;
105 unsigned long irq_flags;
106
107 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
108 spin_lock_irqsave(&msm_chip->lock, irq_flags);
109 msm_gpio_write(msm_chip, offset, value);
110 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
111}
112
113#ifdef CONFIG_MSM_GPIOMUX
114static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
115{
116 return msm_gpiomux_get(chip->base + offset);
117}
118
119static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
120{
121 msm_gpiomux_put(chip->base + offset);
122}
123#else
124#define msm_gpio_request NULL
125#define msm_gpio_free NULL
126#endif
127
128struct msm_gpio_chip msm_gpio_chips[] = {
129 MSM_GPIO_BANK(0, 0, 31),
130 MSM_GPIO_BANK(1, 32, 63),
131 MSM_GPIO_BANK(2, 64, 95),
132 MSM_GPIO_BANK(3, 96, 127),
133 MSM_GPIO_BANK(4, 128, 159),
134 MSM_GPIO_BANK(5, 160, 167),
135};
136
137void msm_gpio_enter_sleep(int from_idle)
138{
139 return;
140}
141
142void msm_gpio_exit_sleep(void)
143{
144 return;
145}
146
147static int __init msm_init_gpio(void)
148{
149 int i;
150
151 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
152 spin_lock_init(&msm_gpio_chips[i].lock);
153 gpiochip_add(&msm_gpio_chips[i].chip);
154 }
155
156 return 0;
157}
158
159postcore_initcall(msm_init_gpio);
160
161int gpio_tlmm_config(unsigned config, unsigned disable)
162{
163 uint32_t flags;
164 unsigned gpio = GPIO_PIN(config);
165
166 if (gpio > NR_MSM_GPIOS)
167 return -EINVAL;
168 flags = ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
169 ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
170 ((GPIO_PULL(config) & 0x3));
171 dsb();
172 __raw_writel(gpio, MSM_GPIO_PAGE);
173 dsb();
174 __raw_writel(flags, MSM_GPIO_CONFIG);
175
176 return 0;
177}
178EXPORT_SYMBOL(gpio_tlmm_config);
179
180int msm_gpios_request_enable(const struct msm_gpio *table, int size)
181{
182 int rc = msm_gpios_request(table, size);
183 if (rc)
184 return rc;
185 rc = msm_gpios_enable(table, size);
186 if (rc)
187 msm_gpios_free(table, size);
188 return rc;
189}
190EXPORT_SYMBOL(msm_gpios_request_enable);
191
192void msm_gpios_disable_free(const struct msm_gpio *table, int size)
193{
194 msm_gpios_disable(table, size);
195 msm_gpios_free(table, size);
196}
197EXPORT_SYMBOL(msm_gpios_disable_free);
198
199int msm_gpios_request(const struct msm_gpio *table, int size)
200{
201 int rc;
202 int i;
203 const struct msm_gpio *g;
204 for (i = 0; i < size; i++) {
205 g = table + i;
206 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
207 if (rc) {
208 pr_err("gpio_request(%d) <%s> failed: %d\n",
209 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
210 goto err;
211 }
212 }
213 return 0;
214err:
215 msm_gpios_free(table, i);
216 return rc;
217}
218EXPORT_SYMBOL(msm_gpios_request);
219
220void msm_gpios_free(const struct msm_gpio *table, int size)
221{
222 int i;
223 const struct msm_gpio *g;
224 for (i = size-1; i >= 0; i--) {
225 g = table + i;
226 gpio_free(GPIO_PIN(g->gpio_cfg));
227 }
228}
229EXPORT_SYMBOL(msm_gpios_free);
230
231int msm_gpios_enable(const struct msm_gpio *table, int size)
232{
233 int rc;
234 int i;
235 const struct msm_gpio *g;
236 for (i = 0; i < size; i++) {
237 g = table + i;
238 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
239 if (rc) {
240 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE)"
241 " <%s> failed: %d\n",
242 g->gpio_cfg, g->label ?: "?", rc);
243 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
244 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
245 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
246 GPIO_DRVSTR(g->gpio_cfg));
247 goto err;
248 }
249 }
250 return 0;
251err:
252 msm_gpios_disable(table, i);
253 return rc;
254}
255EXPORT_SYMBOL(msm_gpios_enable);
256
257int msm_gpios_disable(const struct msm_gpio *table, int size)
258{
259 int rc = 0;
260 int i;
261 const struct msm_gpio *g;
262 for (i = size-1; i >= 0; i--) {
263 int tmp;
264 g = table + i;
265 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
266 if (tmp) {
267 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
268 " <%s> failed: %d\n",
269 g->gpio_cfg, g->label ?: "?", rc);
270 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
271 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
272 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
273 GPIO_DRVSTR(g->gpio_cfg));
274 if (!rc)
275 rc = tmp;
276 }
277 }
278
279 return rc;
280}
281EXPORT_SYMBOL(msm_gpios_disable);
282