blob: 5ad62265546375473b12c9bb9655a6fdfc4c1ee2 [file] [log] [blame]
Gregory Bean2783cc22010-09-10 15:03:36 -07001/* linux/arch/arm/mach-msm/gpio.c
2 *
3 * Copyright (C) 2007 Google, Inc.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
Gregory Bean2783cc22010-09-10 15:03:36 -07005 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/bitops.h>
18#include <linux/gpio.h>
19#include <linux/interrupt.h>
20#include <linux/io.h>
21#include <linux/irq.h>
22#include <linux/module.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070023#include <mach/gpiomux.h>
Gregory Bean2783cc22010-09-10 15:03:36 -070024#include "gpio_hw.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include "proc_comm.h"
26#include "smd_private.h"
27
28enum {
29 GPIO_DEBUG_SLEEP = 1U << 0,
30};
31static int msm_gpio_debug_mask;
32module_param_named(debug_mask, msm_gpio_debug_mask, int,
33 S_IRUGO | S_IWUSR | S_IWGRP);
Gregory Bean2783cc22010-09-10 15:03:36 -070034
35#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
36
37#define MSM_GPIO_BANK(bank, first, last) \
38 { \
39 .regs = { \
40 .out = MSM_GPIO_OUT_##bank, \
41 .in = MSM_GPIO_IN_##bank, \
42 .int_status = MSM_GPIO_INT_STATUS_##bank, \
43 .int_clear = MSM_GPIO_INT_CLEAR_##bank, \
44 .int_en = MSM_GPIO_INT_EN_##bank, \
45 .int_edge = MSM_GPIO_INT_EDGE_##bank, \
46 .int_pos = MSM_GPIO_INT_POS_##bank, \
47 .oe = MSM_GPIO_OE_##bank, \
48 }, \
49 .chip = { \
50 .base = (first), \
51 .ngpio = (last) - (first) + 1, \
52 .get = msm_gpio_get, \
53 .set = msm_gpio_set, \
54 .direction_input = msm_gpio_direction_input, \
55 .direction_output = msm_gpio_direction_output, \
56 .to_irq = msm_gpio_to_irq, \
Gregory Bean26cc6662010-09-10 15:03:37 -070057 .request = msm_gpio_request, \
58 .free = msm_gpio_free, \
Gregory Bean2783cc22010-09-10 15:03:36 -070059 } \
60 }
61
62#define MSM_GPIO_BROKEN_INT_CLEAR 1
63
64struct msm_gpio_regs {
65 void __iomem *out;
66 void __iomem *in;
67 void __iomem *int_status;
68 void __iomem *int_clear;
69 void __iomem *int_en;
70 void __iomem *int_edge;
71 void __iomem *int_pos;
72 void __iomem *oe;
73};
74
75struct msm_gpio_chip {
76 spinlock_t lock;
77 struct gpio_chip chip;
78 struct msm_gpio_regs regs;
79#if MSM_GPIO_BROKEN_INT_CLEAR
80 unsigned int_status_copy;
81#endif
82 unsigned int both_edge_detect;
83 unsigned int int_enable[2]; /* 0: awake, 1: sleep */
84};
85
86static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
87 unsigned offset, unsigned on)
88{
89 unsigned mask = BIT(offset);
90 unsigned val;
91
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 val = __raw_readl(msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070093 if (on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 __raw_writel(val | mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070095 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 __raw_writel(val & ~mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070097 return 0;
98}
99
100static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
101{
102 int loop_limit = 100;
103 unsigned pol, val, val2, intstat;
104 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 val = __raw_readl(msm_chip->regs.in);
106 pol = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700107 pol = (pol & ~msm_chip->both_edge_detect) |
108 (~val & msm_chip->both_edge_detect);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 __raw_writel(pol, msm_chip->regs.int_pos);
110 intstat = __raw_readl(msm_chip->regs.int_status);
111 val2 = __raw_readl(msm_chip->regs.in);
Gregory Bean2783cc22010-09-10 15:03:36 -0700112 if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
113 return;
114 } while (loop_limit-- > 0);
115 printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
116 "failed to reach stable state %x != %x\n", val, val2);
117}
118
119static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
120 unsigned offset)
121{
122 unsigned bit = BIT(offset);
123
124#if MSM_GPIO_BROKEN_INT_CLEAR
125 /* Save interrupts that already triggered before we loose them. */
126 /* Any interrupt that triggers between the read of int_status */
127 /* and the write to int_clear will still be lost though. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 msm_chip->int_status_copy |= __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700129 msm_chip->int_status_copy &= ~bit;
130#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 __raw_writel(bit, msm_chip->regs.int_clear);
Gregory Bean2783cc22010-09-10 15:03:36 -0700132 msm_gpio_update_both_edge_detect(msm_chip);
133 return 0;
134}
135
136static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
137{
138 struct msm_gpio_chip *msm_chip;
139 unsigned long irq_flags;
140
141 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
142 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 __raw_writel(__raw_readl(msm_chip->regs.oe) & ~BIT(offset),
144 msm_chip->regs.oe);
145 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700146 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
147 return 0;
148}
149
150static int
151msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
152{
153 struct msm_gpio_chip *msm_chip;
154 unsigned long irq_flags;
155
156 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
157 spin_lock_irqsave(&msm_chip->lock, irq_flags);
158 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 __raw_writel(__raw_readl(msm_chip->regs.oe) | BIT(offset),
160 msm_chip->regs.oe);
161 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700162 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
163 return 0;
164}
165
166static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
167{
168 struct msm_gpio_chip *msm_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 int rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700170
171 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172 rc = (__raw_readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
173 mb();
174 return rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700175}
176
177static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
178{
179 struct msm_gpio_chip *msm_chip;
180 unsigned long irq_flags;
181
182 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
183 spin_lock_irqsave(&msm_chip->lock, irq_flags);
184 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700186 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
187}
188
189static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
190{
191 return MSM_GPIO_TO_INT(chip->base + offset);
192}
193
Gregory Bean26cc6662010-09-10 15:03:37 -0700194#ifdef CONFIG_MSM_GPIOMUX
195static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
196{
197 return msm_gpiomux_get(chip->base + offset);
198}
199
200static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
201{
202 msm_gpiomux_put(chip->base + offset);
203}
204#else
205#define msm_gpio_request NULL
206#define msm_gpio_free NULL
207#endif
208
Gregory Bean2783cc22010-09-10 15:03:36 -0700209struct msm_gpio_chip msm_gpio_chips[] = {
210#if defined(CONFIG_ARCH_MSM7X00A)
211 MSM_GPIO_BANK(0, 0, 15),
212 MSM_GPIO_BANK(1, 16, 42),
213 MSM_GPIO_BANK(2, 43, 67),
214 MSM_GPIO_BANK(3, 68, 94),
215 MSM_GPIO_BANK(4, 95, 106),
216 MSM_GPIO_BANK(5, 107, 121),
217#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
218 MSM_GPIO_BANK(0, 0, 15),
219 MSM_GPIO_BANK(1, 16, 42),
220 MSM_GPIO_BANK(2, 43, 67),
221 MSM_GPIO_BANK(3, 68, 94),
222 MSM_GPIO_BANK(4, 95, 106),
223 MSM_GPIO_BANK(5, 107, 132),
224#elif defined(CONFIG_ARCH_MSM7X30)
225 MSM_GPIO_BANK(0, 0, 15),
226 MSM_GPIO_BANK(1, 16, 43),
227 MSM_GPIO_BANK(2, 44, 67),
228 MSM_GPIO_BANK(3, 68, 94),
229 MSM_GPIO_BANK(4, 95, 106),
230 MSM_GPIO_BANK(5, 107, 133),
231 MSM_GPIO_BANK(6, 134, 150),
232 MSM_GPIO_BANK(7, 151, 181),
233#elif defined(CONFIG_ARCH_QSD8X50)
234 MSM_GPIO_BANK(0, 0, 15),
235 MSM_GPIO_BANK(1, 16, 42),
236 MSM_GPIO_BANK(2, 43, 67),
237 MSM_GPIO_BANK(3, 68, 94),
238 MSM_GPIO_BANK(4, 95, 103),
239 MSM_GPIO_BANK(5, 104, 121),
240 MSM_GPIO_BANK(6, 122, 152),
241 MSM_GPIO_BANK(7, 153, 164),
242#endif
243};
244
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100245static void msm_gpio_irq_ack(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700246{
247 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700249 spin_lock_irqsave(&msm_chip->lock, irq_flags);
250 msm_gpio_clear_detect_status(msm_chip,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 d->irq - gpio_to_irq(msm_chip->chip.base));
Gregory Bean2783cc22010-09-10 15:03:36 -0700252 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
253}
254
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100255static void msm_gpio_irq_mask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700256{
257 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100259 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700260
261 spin_lock_irqsave(&msm_chip->lock, irq_flags);
262 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700264 msm_gpio_clear_detect_status(msm_chip, offset);
265 msm_chip->int_enable[0] &= ~BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
267 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700268 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
269}
270
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100271static void msm_gpio_irq_unmask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700272{
273 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100275 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700276
277 spin_lock_irqsave(&msm_chip->lock, irq_flags);
278 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700280 msm_gpio_clear_detect_status(msm_chip, offset);
281 msm_chip->int_enable[0] |= BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
283 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700284 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
285}
286
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100287static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Gregory Bean2783cc22010-09-10 15:03:36 -0700288{
289 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100291 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700292
293 spin_lock_irqsave(&msm_chip->lock, irq_flags);
294
295 if (on)
296 msm_chip->int_enable[1] |= BIT(offset);
297 else
298 msm_chip->int_enable[1] &= ~BIT(offset);
299
300 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
301 return 0;
302}
303
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100304static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
Gregory Bean2783cc22010-09-10 15:03:36 -0700305{
306 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100308 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700309 unsigned val, mask = BIT(offset);
310
311 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 val = __raw_readl(msm_chip->regs.int_edge);
Gregory Bean2783cc22010-09-10 15:03:36 -0700313 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 __raw_writel(val | mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100315 __irq_set_handler_locked(d->irq, handle_edge_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700316 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 __raw_writel(val & ~mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100318 __irq_set_handler_locked(d->irq, handle_level_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700319 }
320 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
321 msm_chip->both_edge_detect |= mask;
322 msm_gpio_update_both_edge_detect(msm_chip);
323 } else {
324 msm_chip->both_edge_detect &= ~mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 val = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700326 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 __raw_writel(val | mask, msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700328 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 __raw_writel(val & ~mask, msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700330 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700332 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
333 return 0;
334}
335
336static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
337{
338 int i, j, mask;
339 unsigned val;
340
341 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
342 struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 val = __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700344 val &= msm_chip->int_enable[0];
345 while (val) {
346 mask = val & -val;
347 j = fls(mask) - 1;
348 /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
349 __func__, v, m, j, msm_chip->chip.start + j,
350 FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
351 val &= ~mask;
352 generic_handle_irq(FIRST_GPIO_IRQ +
353 msm_chip->chip.base + j);
354 }
355 }
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100356 desc->irq_data.chip->irq_ack(&desc->irq_data);
Gregory Bean2783cc22010-09-10 15:03:36 -0700357}
358
359static struct irq_chip msm_gpio_irq_chip = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 .name = "msmgpio",
361 .irq_ack = msm_gpio_irq_ack,
362 .irq_mask = msm_gpio_irq_mask,
363 .irq_unmask = msm_gpio_irq_unmask,
364 .irq_set_wake = msm_gpio_irq_set_wake,
365 .irq_set_type = msm_gpio_irq_set_type,
Gregory Bean2783cc22010-09-10 15:03:36 -0700366};
367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368#define NUM_GPIO_SMEM_BANKS 6
369#define GPIO_SMEM_NUM_GROUPS 2
370#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
371struct tramp_gpio_smem {
372 uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
373 uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
374 uint32_t enabled[NUM_GPIO_SMEM_BANKS];
375 uint32_t detection[NUM_GPIO_SMEM_BANKS];
376 uint32_t polarity[NUM_GPIO_SMEM_BANKS];
377};
378
379static void msm_gpio_sleep_int(unsigned long arg)
380{
381 int i, j;
382 struct tramp_gpio_smem *smem_gpio;
383
384 BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32);
385
386 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
387 if (smem_gpio == NULL)
388 return;
389
390 local_irq_disable();
391 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
392 int count = smem_gpio->num_fired[i];
393 for (j = 0; j < count; j++) {
394 /* TODO: Check mask */
395 generic_handle_irq(
396 MSM_GPIO_TO_INT(smem_gpio->fired[i][j]));
397 }
398 }
399 local_irq_enable();
400}
401
402static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0);
403
404void msm_gpio_enter_sleep(int from_idle)
405{
406 int i;
407 struct tramp_gpio_smem *smem_gpio;
408
409 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
410
411 if (smem_gpio) {
412 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
413 smem_gpio->enabled[i] = 0;
414 smem_gpio->detection[i] = 0;
415 smem_gpio->polarity[i] = 0;
416 }
417 }
418
419 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
420 __raw_writel(msm_gpio_chips[i].int_enable[!from_idle],
421 msm_gpio_chips[i].regs.int_en);
422 if (smem_gpio) {
423 uint32_t tmp;
424 int start, index, shiftl, shiftr;
425 start = msm_gpio_chips[i].chip.base;
426 index = start / 32;
427 shiftl = start % 32;
428 shiftr = 32 - shiftl;
429 tmp = msm_gpio_chips[i].int_enable[!from_idle];
430 smem_gpio->enabled[index] |= tmp << shiftl;
431 smem_gpio->enabled[index+1] |= tmp >> shiftr;
432 smem_gpio->detection[index] |=
433 __raw_readl(msm_gpio_chips[i].regs.int_edge) <<
434 shiftl;
435 smem_gpio->detection[index+1] |=
436 __raw_readl(msm_gpio_chips[i].regs.int_edge) >>
437 shiftr;
438 smem_gpio->polarity[index] |=
439 __raw_readl(msm_gpio_chips[i].regs.int_pos) <<
440 shiftl;
441 smem_gpio->polarity[index+1] |=
442 __raw_readl(msm_gpio_chips[i].regs.int_pos) >>
443 shiftr;
444 }
445 }
446 mb();
447
448 if (smem_gpio) {
449 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
450 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
451 printk("msm_gpio_enter_sleep gpio %d-%d: enable"
452 " %08x, edge %08x, polarity %08x\n",
453 i * 32, i * 32 + 31,
454 smem_gpio->enabled[i],
455 smem_gpio->detection[i],
456 smem_gpio->polarity[i]);
457 }
458 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
459 smem_gpio->num_fired[i] = 0;
460 }
461}
462
463void msm_gpio_exit_sleep(void)
464{
465 int i;
466 struct tramp_gpio_smem *smem_gpio;
467
468 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
469
470 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
471 __raw_writel(msm_gpio_chips[i].int_enable[0],
472 msm_gpio_chips[i].regs.int_en);
473 }
474 mb();
475
476 if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) {
477 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
478 printk(KERN_INFO "gpio: fired %x %x\n",
479 smem_gpio->num_fired[0], smem_gpio->num_fired[1]);
480 tasklet_schedule(&msm_gpio_sleep_int_tasklet);
481 }
482}
483
Gregory Bean2783cc22010-09-10 15:03:36 -0700484static int __init msm_init_gpio(void)
485{
486 int i, j = 0;
487
488 for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
489 if (i - FIRST_GPIO_IRQ >=
490 msm_gpio_chips[j].chip.base +
491 msm_gpio_chips[j].chip.ngpio)
492 j++;
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100493 irq_set_chip_data(i, &msm_gpio_chips[j]);
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +0100494 irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
495 handle_edge_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700496 set_irq_flags(i, IRQF_VALID);
497 }
498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
500 irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
501
Gregory Bean2783cc22010-09-10 15:03:36 -0700502 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
503 spin_lock_init(&msm_gpio_chips[i].lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 __raw_writel(0, msm_gpio_chips[i].regs.int_en);
Gregory Bean2783cc22010-09-10 15:03:36 -0700505 gpiochip_add(&msm_gpio_chips[i].chip);
506 }
507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 mb();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100509 irq_set_irq_wake(INT_GPIO_GROUP1, 1);
510 irq_set_irq_wake(INT_GPIO_GROUP2, 2);
Gregory Bean2783cc22010-09-10 15:03:36 -0700511 return 0;
512}
513
514postcore_initcall(msm_init_gpio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515
516int gpio_tlmm_config(unsigned config, unsigned disable)
517{
518 return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
519}
520EXPORT_SYMBOL(gpio_tlmm_config);
521
522int msm_gpios_request_enable(const struct msm_gpio *table, int size)
523{
524 int rc = msm_gpios_request(table, size);
525 if (rc)
526 return rc;
527 rc = msm_gpios_enable(table, size);
528 if (rc)
529 msm_gpios_free(table, size);
530 return rc;
531}
532EXPORT_SYMBOL(msm_gpios_request_enable);
533
534void msm_gpios_disable_free(const struct msm_gpio *table, int size)
535{
536 msm_gpios_disable(table, size);
537 msm_gpios_free(table, size);
538}
539EXPORT_SYMBOL(msm_gpios_disable_free);
540
541int msm_gpios_request(const struct msm_gpio *table, int size)
542{
543 int rc;
544 int i;
545 const struct msm_gpio *g;
546 for (i = 0; i < size; i++) {
547 g = table + i;
548 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
549 if (rc) {
550 pr_err("gpio_request(%d) <%s> failed: %d\n",
551 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
552 goto err;
553 }
554 }
555 return 0;
556err:
557 msm_gpios_free(table, i);
558 return rc;
559}
560EXPORT_SYMBOL(msm_gpios_request);
561
562void msm_gpios_free(const struct msm_gpio *table, int size)
563{
564 int i;
565 const struct msm_gpio *g;
566 for (i = size-1; i >= 0; i--) {
567 g = table + i;
568 gpio_free(GPIO_PIN(g->gpio_cfg));
569 }
570}
571EXPORT_SYMBOL(msm_gpios_free);
572
573int msm_gpios_enable(const struct msm_gpio *table, int size)
574{
575 int rc;
576 int i;
577 const struct msm_gpio *g;
578 for (i = 0; i < size; i++) {
579 g = table + i;
580 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
581 if (rc) {
582 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE)"
583 " <%s> failed: %d\n",
584 g->gpio_cfg, g->label ?: "?", rc);
585 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
586 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
587 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
588 GPIO_DRVSTR(g->gpio_cfg));
589 goto err;
590 }
591 }
592 return 0;
593err:
594 msm_gpios_disable(table, i);
595 return rc;
596}
597EXPORT_SYMBOL(msm_gpios_enable);
598
599int msm_gpios_disable(const struct msm_gpio *table, int size)
600{
601 int rc = 0;
602 int i;
603 const struct msm_gpio *g;
604 for (i = size-1; i >= 0; i--) {
605 int tmp;
606 g = table + i;
607 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
608 if (tmp) {
609 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
610 " <%s> failed: %d\n",
611 g->gpio_cfg, g->label ?: "?", rc);
612 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
613 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
614 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
615 GPIO_DRVSTR(g->gpio_cfg));
616 if (!rc)
617 rc = tmp;
618 }
619 }
620
621 return rc;
622}
623EXPORT_SYMBOL(msm_gpios_disable);
624
625/* Locate the GPIO_OUT register for the given GPIO and return its address
626 * and the bit position of the gpio's bit within the register.
627 *
628 * This function is used by gpiomux-v1 in order to support output transitions.
629 */
630void msm_gpio_find_out(const unsigned gpio, void __iomem **out,
631 unsigned *offset)
632{
633 struct msm_gpio_chip *msm_chip = msm_gpio_chips;
634
635 while (gpio >= msm_chip->chip.base + msm_chip->chip.ngpio)
636 ++msm_chip;
637
638 *out = msm_chip->regs.out;
639 *offset = gpio - msm_chip->chip.base;
640}