blob: a9428629b0e4416d2cad96e4c7f06e0bd61d29da [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>
Taniya Dasa187d122011-12-16 16:28:25 +053023#include <asm/mach/irq.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070024#include <mach/gpiomux.h>
Gregory Bean2783cc22010-09-10 15:03:36 -070025#include "gpio_hw.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include "proc_comm.h"
27#include "smd_private.h"
28
29enum {
30 GPIO_DEBUG_SLEEP = 1U << 0,
31};
32static int msm_gpio_debug_mask;
33module_param_named(debug_mask, msm_gpio_debug_mask, int,
34 S_IRUGO | S_IWUSR | S_IWGRP);
Gregory Bean2783cc22010-09-10 15:03:36 -070035
36#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
37
38#define MSM_GPIO_BANK(bank, first, last) \
39 { \
40 .regs = { \
41 .out = MSM_GPIO_OUT_##bank, \
42 .in = MSM_GPIO_IN_##bank, \
43 .int_status = MSM_GPIO_INT_STATUS_##bank, \
44 .int_clear = MSM_GPIO_INT_CLEAR_##bank, \
45 .int_en = MSM_GPIO_INT_EN_##bank, \
46 .int_edge = MSM_GPIO_INT_EDGE_##bank, \
47 .int_pos = MSM_GPIO_INT_POS_##bank, \
48 .oe = MSM_GPIO_OE_##bank, \
49 }, \
50 .chip = { \
51 .base = (first), \
52 .ngpio = (last) - (first) + 1, \
53 .get = msm_gpio_get, \
54 .set = msm_gpio_set, \
55 .direction_input = msm_gpio_direction_input, \
56 .direction_output = msm_gpio_direction_output, \
57 .to_irq = msm_gpio_to_irq, \
Gregory Bean26cc6662010-09-10 15:03:37 -070058 .request = msm_gpio_request, \
59 .free = msm_gpio_free, \
Gregory Bean2783cc22010-09-10 15:03:36 -070060 } \
61 }
62
63#define MSM_GPIO_BROKEN_INT_CLEAR 1
64
65struct msm_gpio_regs {
66 void __iomem *out;
67 void __iomem *in;
68 void __iomem *int_status;
69 void __iomem *int_clear;
70 void __iomem *int_en;
71 void __iomem *int_edge;
72 void __iomem *int_pos;
73 void __iomem *oe;
74};
75
76struct msm_gpio_chip {
77 spinlock_t lock;
78 struct gpio_chip chip;
79 struct msm_gpio_regs regs;
80#if MSM_GPIO_BROKEN_INT_CLEAR
81 unsigned int_status_copy;
82#endif
83 unsigned int both_edge_detect;
84 unsigned int int_enable[2]; /* 0: awake, 1: sleep */
85};
86
87static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
88 unsigned offset, unsigned on)
89{
90 unsigned mask = BIT(offset);
91 unsigned val;
92
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 val = __raw_readl(msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070094 if (on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070095 __raw_writel(val | mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070096 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 __raw_writel(val & ~mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070098 return 0;
99}
100
101static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
102{
103 int loop_limit = 100;
104 unsigned pol, val, val2, intstat;
105 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106 val = __raw_readl(msm_chip->regs.in);
107 pol = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700108 pol = (pol & ~msm_chip->both_edge_detect) |
109 (~val & msm_chip->both_edge_detect);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110 __raw_writel(pol, msm_chip->regs.int_pos);
111 intstat = __raw_readl(msm_chip->regs.int_status);
112 val2 = __raw_readl(msm_chip->regs.in);
Gregory Bean2783cc22010-09-10 15:03:36 -0700113 if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
114 return;
115 } while (loop_limit-- > 0);
116 printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
117 "failed to reach stable state %x != %x\n", val, val2);
118}
119
120static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
121 unsigned offset)
122{
123 unsigned bit = BIT(offset);
124
125#if MSM_GPIO_BROKEN_INT_CLEAR
126 /* Save interrupts that already triggered before we loose them. */
127 /* Any interrupt that triggers between the read of int_status */
128 /* and the write to int_clear will still be lost though. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 msm_chip->int_status_copy |= __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700130 msm_chip->int_status_copy &= ~bit;
131#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 __raw_writel(bit, msm_chip->regs.int_clear);
Gregory Bean2783cc22010-09-10 15:03:36 -0700133 msm_gpio_update_both_edge_detect(msm_chip);
134 return 0;
135}
136
137static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
138{
139 struct msm_gpio_chip *msm_chip;
140 unsigned long irq_flags;
141
142 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
143 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 __raw_writel(__raw_readl(msm_chip->regs.oe) & ~BIT(offset),
145 msm_chip->regs.oe);
146 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700147 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
148 return 0;
149}
150
151static int
152msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
153{
154 struct msm_gpio_chip *msm_chip;
155 unsigned long irq_flags;
156
157 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
158 spin_lock_irqsave(&msm_chip->lock, irq_flags);
159 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 __raw_writel(__raw_readl(msm_chip->regs.oe) | BIT(offset),
161 msm_chip->regs.oe);
162 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700163 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
164 return 0;
165}
166
167static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
168{
169 struct msm_gpio_chip *msm_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170 int rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700171
172 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 rc = (__raw_readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
174 mb();
175 return rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700176}
177
178static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
179{
180 struct msm_gpio_chip *msm_chip;
181 unsigned long irq_flags;
182
183 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
184 spin_lock_irqsave(&msm_chip->lock, irq_flags);
185 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700187 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
188}
189
190static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
191{
192 return MSM_GPIO_TO_INT(chip->base + offset);
193}
194
Gregory Bean26cc6662010-09-10 15:03:37 -0700195#ifdef CONFIG_MSM_GPIOMUX
196static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
197{
198 return msm_gpiomux_get(chip->base + offset);
199}
200
201static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
202{
203 msm_gpiomux_put(chip->base + offset);
204}
205#else
206#define msm_gpio_request NULL
207#define msm_gpio_free NULL
208#endif
209
Gregory Bean2783cc22010-09-10 15:03:36 -0700210struct msm_gpio_chip msm_gpio_chips[] = {
211#if defined(CONFIG_ARCH_MSM7X00A)
212 MSM_GPIO_BANK(0, 0, 15),
213 MSM_GPIO_BANK(1, 16, 42),
214 MSM_GPIO_BANK(2, 43, 67),
215 MSM_GPIO_BANK(3, 68, 94),
216 MSM_GPIO_BANK(4, 95, 106),
217 MSM_GPIO_BANK(5, 107, 121),
218#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
219 MSM_GPIO_BANK(0, 0, 15),
220 MSM_GPIO_BANK(1, 16, 42),
221 MSM_GPIO_BANK(2, 43, 67),
222 MSM_GPIO_BANK(3, 68, 94),
223 MSM_GPIO_BANK(4, 95, 106),
224 MSM_GPIO_BANK(5, 107, 132),
225#elif defined(CONFIG_ARCH_MSM7X30)
226 MSM_GPIO_BANK(0, 0, 15),
227 MSM_GPIO_BANK(1, 16, 43),
228 MSM_GPIO_BANK(2, 44, 67),
229 MSM_GPIO_BANK(3, 68, 94),
230 MSM_GPIO_BANK(4, 95, 106),
231 MSM_GPIO_BANK(5, 107, 133),
232 MSM_GPIO_BANK(6, 134, 150),
233 MSM_GPIO_BANK(7, 151, 181),
234#elif defined(CONFIG_ARCH_QSD8X50)
235 MSM_GPIO_BANK(0, 0, 15),
236 MSM_GPIO_BANK(1, 16, 42),
237 MSM_GPIO_BANK(2, 43, 67),
238 MSM_GPIO_BANK(3, 68, 94),
239 MSM_GPIO_BANK(4, 95, 103),
240 MSM_GPIO_BANK(5, 104, 121),
241 MSM_GPIO_BANK(6, 122, 152),
242 MSM_GPIO_BANK(7, 153, 164),
243#endif
244};
245
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100246static void msm_gpio_irq_ack(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700247{
248 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700250 spin_lock_irqsave(&msm_chip->lock, irq_flags);
251 msm_gpio_clear_detect_status(msm_chip,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 d->irq - gpio_to_irq(msm_chip->chip.base));
Gregory Bean2783cc22010-09-10 15:03:36 -0700253 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
254}
255
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100256static void msm_gpio_irq_mask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700257{
258 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100260 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700261
262 spin_lock_irqsave(&msm_chip->lock, irq_flags);
263 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700265 msm_gpio_clear_detect_status(msm_chip, offset);
266 msm_chip->int_enable[0] &= ~BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
268 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700269 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
270}
271
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100272static void msm_gpio_irq_unmask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700273{
274 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100276 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700277
278 spin_lock_irqsave(&msm_chip->lock, irq_flags);
279 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700281 msm_gpio_clear_detect_status(msm_chip, offset);
282 msm_chip->int_enable[0] |= BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
284 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700285 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
286}
287
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100288static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Gregory Bean2783cc22010-09-10 15:03:36 -0700289{
290 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100292 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700293
294 spin_lock_irqsave(&msm_chip->lock, irq_flags);
295
296 if (on)
297 msm_chip->int_enable[1] |= BIT(offset);
298 else
299 msm_chip->int_enable[1] &= ~BIT(offset);
300
301 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
302 return 0;
303}
304
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100305static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
Gregory Bean2783cc22010-09-10 15:03:36 -0700306{
307 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100309 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700310 unsigned val, mask = BIT(offset);
311
312 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313 val = __raw_readl(msm_chip->regs.int_edge);
Gregory Bean2783cc22010-09-10 15:03:36 -0700314 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 __raw_writel(val | mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100316 __irq_set_handler_locked(d->irq, handle_edge_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700317 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 __raw_writel(val & ~mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100319 __irq_set_handler_locked(d->irq, handle_level_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700320 }
321 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
322 msm_chip->both_edge_detect |= mask;
323 msm_gpio_update_both_edge_detect(msm_chip);
324 } else {
325 msm_chip->both_edge_detect &= ~mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 val = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700327 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 __raw_writel(val | mask, msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700329 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 __raw_writel(val & ~mask, msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700331 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700333 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
334 return 0;
335}
336
337static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
338{
339 int i, j, mask;
340 unsigned val;
Taniya Dasa187d122011-12-16 16:28:25 +0530341 struct irq_chip *chip = irq_desc_get_chip(desc);
342
343 chained_irq_enter(chip, desc);
Gregory Bean2783cc22010-09-10 15:03:36 -0700344
345 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
346 struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 val = __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700348 val &= msm_chip->int_enable[0];
349 while (val) {
350 mask = val & -val;
351 j = fls(mask) - 1;
352 /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
353 __func__, v, m, j, msm_chip->chip.start + j,
354 FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
355 val &= ~mask;
356 generic_handle_irq(FIRST_GPIO_IRQ +
357 msm_chip->chip.base + j);
358 }
359 }
Taniya Dasa187d122011-12-16 16:28:25 +0530360
361 chained_irq_exit(chip, desc);
Gregory Bean2783cc22010-09-10 15:03:36 -0700362}
363
364static struct irq_chip msm_gpio_irq_chip = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 .name = "msmgpio",
366 .irq_ack = msm_gpio_irq_ack,
367 .irq_mask = msm_gpio_irq_mask,
368 .irq_unmask = msm_gpio_irq_unmask,
369 .irq_set_wake = msm_gpio_irq_set_wake,
370 .irq_set_type = msm_gpio_irq_set_type,
Gregory Bean2783cc22010-09-10 15:03:36 -0700371};
372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373#define NUM_GPIO_SMEM_BANKS 6
374#define GPIO_SMEM_NUM_GROUPS 2
375#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
376struct tramp_gpio_smem {
377 uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
378 uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
379 uint32_t enabled[NUM_GPIO_SMEM_BANKS];
380 uint32_t detection[NUM_GPIO_SMEM_BANKS];
381 uint32_t polarity[NUM_GPIO_SMEM_BANKS];
382};
383
384static void msm_gpio_sleep_int(unsigned long arg)
385{
386 int i, j;
387 struct tramp_gpio_smem *smem_gpio;
388
389 BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32);
390
391 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
392 if (smem_gpio == NULL)
393 return;
394
395 local_irq_disable();
396 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
397 int count = smem_gpio->num_fired[i];
398 for (j = 0; j < count; j++) {
399 /* TODO: Check mask */
400 generic_handle_irq(
401 MSM_GPIO_TO_INT(smem_gpio->fired[i][j]));
402 }
403 }
404 local_irq_enable();
405}
406
407static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0);
408
409void msm_gpio_enter_sleep(int from_idle)
410{
411 int i;
412 struct tramp_gpio_smem *smem_gpio;
413
414 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
415
416 if (smem_gpio) {
417 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
418 smem_gpio->enabled[i] = 0;
419 smem_gpio->detection[i] = 0;
420 smem_gpio->polarity[i] = 0;
421 }
422 }
423
424 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
425 __raw_writel(msm_gpio_chips[i].int_enable[!from_idle],
426 msm_gpio_chips[i].regs.int_en);
427 if (smem_gpio) {
428 uint32_t tmp;
429 int start, index, shiftl, shiftr;
430 start = msm_gpio_chips[i].chip.base;
431 index = start / 32;
432 shiftl = start % 32;
433 shiftr = 32 - shiftl;
434 tmp = msm_gpio_chips[i].int_enable[!from_idle];
435 smem_gpio->enabled[index] |= tmp << shiftl;
436 smem_gpio->enabled[index+1] |= tmp >> shiftr;
437 smem_gpio->detection[index] |=
438 __raw_readl(msm_gpio_chips[i].regs.int_edge) <<
439 shiftl;
440 smem_gpio->detection[index+1] |=
441 __raw_readl(msm_gpio_chips[i].regs.int_edge) >>
442 shiftr;
443 smem_gpio->polarity[index] |=
444 __raw_readl(msm_gpio_chips[i].regs.int_pos) <<
445 shiftl;
446 smem_gpio->polarity[index+1] |=
447 __raw_readl(msm_gpio_chips[i].regs.int_pos) >>
448 shiftr;
449 }
450 }
451 mb();
452
453 if (smem_gpio) {
454 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
455 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
456 printk("msm_gpio_enter_sleep gpio %d-%d: enable"
457 " %08x, edge %08x, polarity %08x\n",
458 i * 32, i * 32 + 31,
459 smem_gpio->enabled[i],
460 smem_gpio->detection[i],
461 smem_gpio->polarity[i]);
462 }
463 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
464 smem_gpio->num_fired[i] = 0;
465 }
466}
467
468void msm_gpio_exit_sleep(void)
469{
470 int i;
471 struct tramp_gpio_smem *smem_gpio;
472
473 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
474
475 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
476 __raw_writel(msm_gpio_chips[i].int_enable[0],
477 msm_gpio_chips[i].regs.int_en);
478 }
479 mb();
480
481 if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) {
482 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
483 printk(KERN_INFO "gpio: fired %x %x\n",
484 smem_gpio->num_fired[0], smem_gpio->num_fired[1]);
485 tasklet_schedule(&msm_gpio_sleep_int_tasklet);
486 }
487}
488
Gregory Bean2783cc22010-09-10 15:03:36 -0700489static int __init msm_init_gpio(void)
490{
491 int i, j = 0;
492
493 for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
494 if (i - FIRST_GPIO_IRQ >=
495 msm_gpio_chips[j].chip.base +
496 msm_gpio_chips[j].chip.ngpio)
497 j++;
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100498 irq_set_chip_data(i, &msm_gpio_chips[j]);
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +0100499 irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
500 handle_edge_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700501 set_irq_flags(i, IRQF_VALID);
502 }
503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
505 irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
506
Gregory Bean2783cc22010-09-10 15:03:36 -0700507 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
508 spin_lock_init(&msm_gpio_chips[i].lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 __raw_writel(0, msm_gpio_chips[i].regs.int_en);
Gregory Bean2783cc22010-09-10 15:03:36 -0700510 gpiochip_add(&msm_gpio_chips[i].chip);
511 }
512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 mb();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100514 irq_set_irq_wake(INT_GPIO_GROUP1, 1);
515 irq_set_irq_wake(INT_GPIO_GROUP2, 2);
Gregory Bean2783cc22010-09-10 15:03:36 -0700516 return 0;
517}
518
519postcore_initcall(msm_init_gpio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520
521int gpio_tlmm_config(unsigned config, unsigned disable)
522{
523 return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
524}
525EXPORT_SYMBOL(gpio_tlmm_config);
526
527int msm_gpios_request_enable(const struct msm_gpio *table, int size)
528{
529 int rc = msm_gpios_request(table, size);
530 if (rc)
531 return rc;
532 rc = msm_gpios_enable(table, size);
533 if (rc)
534 msm_gpios_free(table, size);
535 return rc;
536}
537EXPORT_SYMBOL(msm_gpios_request_enable);
538
539void msm_gpios_disable_free(const struct msm_gpio *table, int size)
540{
541 msm_gpios_disable(table, size);
542 msm_gpios_free(table, size);
543}
544EXPORT_SYMBOL(msm_gpios_disable_free);
545
546int msm_gpios_request(const struct msm_gpio *table, int size)
547{
548 int rc;
549 int i;
550 const struct msm_gpio *g;
551 for (i = 0; i < size; i++) {
552 g = table + i;
553 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
554 if (rc) {
555 pr_err("gpio_request(%d) <%s> failed: %d\n",
556 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
557 goto err;
558 }
559 }
560 return 0;
561err:
562 msm_gpios_free(table, i);
563 return rc;
564}
565EXPORT_SYMBOL(msm_gpios_request);
566
567void msm_gpios_free(const struct msm_gpio *table, int size)
568{
569 int i;
570 const struct msm_gpio *g;
571 for (i = size-1; i >= 0; i--) {
572 g = table + i;
573 gpio_free(GPIO_PIN(g->gpio_cfg));
574 }
575}
576EXPORT_SYMBOL(msm_gpios_free);
577
578int msm_gpios_enable(const struct msm_gpio *table, int size)
579{
580 int rc;
581 int i;
582 const struct msm_gpio *g;
583 for (i = 0; i < size; i++) {
584 g = table + i;
585 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
586 if (rc) {
587 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE)"
588 " <%s> failed: %d\n",
589 g->gpio_cfg, g->label ?: "?", rc);
590 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
591 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
592 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
593 GPIO_DRVSTR(g->gpio_cfg));
594 goto err;
595 }
596 }
597 return 0;
598err:
599 msm_gpios_disable(table, i);
600 return rc;
601}
602EXPORT_SYMBOL(msm_gpios_enable);
603
604int msm_gpios_disable(const struct msm_gpio *table, int size)
605{
606 int rc = 0;
607 int i;
608 const struct msm_gpio *g;
609 for (i = size-1; i >= 0; i--) {
610 int tmp;
611 g = table + i;
612 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
613 if (tmp) {
614 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
615 " <%s> failed: %d\n",
616 g->gpio_cfg, g->label ?: "?", rc);
617 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
618 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
619 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
620 GPIO_DRVSTR(g->gpio_cfg));
621 if (!rc)
622 rc = tmp;
623 }
624 }
625
626 return rc;
627}
628EXPORT_SYMBOL(msm_gpios_disable);
629
630/* Locate the GPIO_OUT register for the given GPIO and return its address
631 * and the bit position of the gpio's bit within the register.
632 *
633 * This function is used by gpiomux-v1 in order to support output transitions.
634 */
635void msm_gpio_find_out(const unsigned gpio, void __iomem **out,
636 unsigned *offset)
637{
638 struct msm_gpio_chip *msm_chip = msm_gpio_chips;
639
640 while (gpio >= msm_chip->chip.base + msm_chip->chip.ngpio)
641 ++msm_chip;
642
643 *out = msm_chip->regs.out;
644 *offset = gpio - msm_chip->chip.base;
645}