blob: ea9e0d5930e7a12a900e57fefa177b2c5bb38bee [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.
Taniya Das2e948192011-12-20 11:15:13 +05304 * Copyright (c) 2009-2012, 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 Das2e948192011-12-20 11:15:13 +053023#include <linux/platform_device.h>
Taniya Dasa187d122011-12-16 16:28:25 +053024#include <asm/mach/irq.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070025#include <mach/gpiomux.h>
Gregory Bean2783cc22010-09-10 15:03:36 -070026#include "gpio_hw.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include "proc_comm.h"
28#include "smd_private.h"
29
30enum {
31 GPIO_DEBUG_SLEEP = 1U << 0,
32};
33static int msm_gpio_debug_mask;
34module_param_named(debug_mask, msm_gpio_debug_mask, int,
35 S_IRUGO | S_IWUSR | S_IWGRP);
Gregory Bean2783cc22010-09-10 15:03:36 -070036
37#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
38
39#define MSM_GPIO_BANK(bank, first, last) \
40 { \
41 .regs = { \
42 .out = MSM_GPIO_OUT_##bank, \
43 .in = MSM_GPIO_IN_##bank, \
44 .int_status = MSM_GPIO_INT_STATUS_##bank, \
45 .int_clear = MSM_GPIO_INT_CLEAR_##bank, \
46 .int_en = MSM_GPIO_INT_EN_##bank, \
47 .int_edge = MSM_GPIO_INT_EDGE_##bank, \
48 .int_pos = MSM_GPIO_INT_POS_##bank, \
49 .oe = MSM_GPIO_OE_##bank, \
50 }, \
51 .chip = { \
52 .base = (first), \
53 .ngpio = (last) - (first) + 1, \
54 .get = msm_gpio_get, \
55 .set = msm_gpio_set, \
56 .direction_input = msm_gpio_direction_input, \
57 .direction_output = msm_gpio_direction_output, \
58 .to_irq = msm_gpio_to_irq, \
Gregory Bean26cc6662010-09-10 15:03:37 -070059 .request = msm_gpio_request, \
60 .free = msm_gpio_free, \
Gregory Bean2783cc22010-09-10 15:03:36 -070061 } \
62 }
63
64#define MSM_GPIO_BROKEN_INT_CLEAR 1
65
66struct msm_gpio_regs {
67 void __iomem *out;
68 void __iomem *in;
69 void __iomem *int_status;
70 void __iomem *int_clear;
71 void __iomem *int_en;
72 void __iomem *int_edge;
73 void __iomem *int_pos;
74 void __iomem *oe;
75};
76
77struct msm_gpio_chip {
78 spinlock_t lock;
79 struct gpio_chip chip;
80 struct msm_gpio_regs regs;
81#if MSM_GPIO_BROKEN_INT_CLEAR
82 unsigned int_status_copy;
83#endif
84 unsigned int both_edge_detect;
85 unsigned int int_enable[2]; /* 0: awake, 1: sleep */
86};
87
88static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
89 unsigned offset, unsigned on)
90{
91 unsigned mask = BIT(offset);
92 unsigned val;
93
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 val = __raw_readl(msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070095 if (on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 __raw_writel(val | mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070097 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 __raw_writel(val & ~mask, msm_chip->regs.out);
Gregory Bean2783cc22010-09-10 15:03:36 -070099 return 0;
100}
101
102static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
103{
104 int loop_limit = 100;
105 unsigned pol, val, val2, intstat;
106 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107 val = __raw_readl(msm_chip->regs.in);
108 pol = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700109 pol = (pol & ~msm_chip->both_edge_detect) |
110 (~val & msm_chip->both_edge_detect);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 __raw_writel(pol, msm_chip->regs.int_pos);
112 intstat = __raw_readl(msm_chip->regs.int_status);
113 val2 = __raw_readl(msm_chip->regs.in);
Gregory Bean2783cc22010-09-10 15:03:36 -0700114 if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
115 return;
116 } while (loop_limit-- > 0);
117 printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
118 "failed to reach stable state %x != %x\n", val, val2);
119}
120
121static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
122 unsigned offset)
123{
124 unsigned bit = BIT(offset);
125
126#if MSM_GPIO_BROKEN_INT_CLEAR
127 /* Save interrupts that already triggered before we loose them. */
128 /* Any interrupt that triggers between the read of int_status */
129 /* and the write to int_clear will still be lost though. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 msm_chip->int_status_copy |= __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700131 msm_chip->int_status_copy &= ~bit;
132#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 __raw_writel(bit, msm_chip->regs.int_clear);
Gregory Bean2783cc22010-09-10 15:03:36 -0700134 msm_gpio_update_both_edge_detect(msm_chip);
135 return 0;
136}
137
138static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
139{
140 struct msm_gpio_chip *msm_chip;
141 unsigned long irq_flags;
142
143 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
144 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 __raw_writel(__raw_readl(msm_chip->regs.oe) & ~BIT(offset),
146 msm_chip->regs.oe);
147 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700148 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
149 return 0;
150}
151
152static int
153msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
154{
155 struct msm_gpio_chip *msm_chip;
156 unsigned long irq_flags;
157
158 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
159 spin_lock_irqsave(&msm_chip->lock, irq_flags);
160 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 __raw_writel(__raw_readl(msm_chip->regs.oe) | BIT(offset),
162 msm_chip->regs.oe);
163 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700164 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
165 return 0;
166}
167
168static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
169{
170 struct msm_gpio_chip *msm_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 int rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700172
173 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 rc = (__raw_readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
175 mb();
176 return rc;
Gregory Bean2783cc22010-09-10 15:03:36 -0700177}
178
179static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
180{
181 struct msm_gpio_chip *msm_chip;
182 unsigned long irq_flags;
183
184 msm_chip = container_of(chip, struct msm_gpio_chip, chip);
185 spin_lock_irqsave(&msm_chip->lock, irq_flags);
186 msm_gpio_write(msm_chip, offset, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700188 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
189}
190
191static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
192{
193 return MSM_GPIO_TO_INT(chip->base + offset);
194}
195
Gregory Bean26cc6662010-09-10 15:03:37 -0700196#ifdef CONFIG_MSM_GPIOMUX
197static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
198{
199 return msm_gpiomux_get(chip->base + offset);
200}
201
202static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
203{
204 msm_gpiomux_put(chip->base + offset);
205}
206#else
207#define msm_gpio_request NULL
208#define msm_gpio_free NULL
209#endif
210
Gregory Bean2783cc22010-09-10 15:03:36 -0700211struct msm_gpio_chip msm_gpio_chips[] = {
212#if defined(CONFIG_ARCH_MSM7X00A)
213 MSM_GPIO_BANK(0, 0, 15),
214 MSM_GPIO_BANK(1, 16, 42),
215 MSM_GPIO_BANK(2, 43, 67),
216 MSM_GPIO_BANK(3, 68, 94),
217 MSM_GPIO_BANK(4, 95, 106),
218 MSM_GPIO_BANK(5, 107, 121),
219#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
220 MSM_GPIO_BANK(0, 0, 15),
221 MSM_GPIO_BANK(1, 16, 42),
222 MSM_GPIO_BANK(2, 43, 67),
223 MSM_GPIO_BANK(3, 68, 94),
224 MSM_GPIO_BANK(4, 95, 106),
225 MSM_GPIO_BANK(5, 107, 132),
226#elif defined(CONFIG_ARCH_MSM7X30)
227 MSM_GPIO_BANK(0, 0, 15),
228 MSM_GPIO_BANK(1, 16, 43),
229 MSM_GPIO_BANK(2, 44, 67),
230 MSM_GPIO_BANK(3, 68, 94),
231 MSM_GPIO_BANK(4, 95, 106),
232 MSM_GPIO_BANK(5, 107, 133),
233 MSM_GPIO_BANK(6, 134, 150),
234 MSM_GPIO_BANK(7, 151, 181),
235#elif defined(CONFIG_ARCH_QSD8X50)
236 MSM_GPIO_BANK(0, 0, 15),
237 MSM_GPIO_BANK(1, 16, 42),
238 MSM_GPIO_BANK(2, 43, 67),
239 MSM_GPIO_BANK(3, 68, 94),
240 MSM_GPIO_BANK(4, 95, 103),
241 MSM_GPIO_BANK(5, 104, 121),
242 MSM_GPIO_BANK(6, 122, 152),
243 MSM_GPIO_BANK(7, 153, 164),
244#endif
245};
246
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100247static void msm_gpio_irq_ack(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700248{
249 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700251 spin_lock_irqsave(&msm_chip->lock, irq_flags);
252 msm_gpio_clear_detect_status(msm_chip,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 d->irq - gpio_to_irq(msm_chip->chip.base));
Gregory Bean2783cc22010-09-10 15:03:36 -0700254 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
255}
256
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100257static void msm_gpio_irq_mask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700258{
259 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100261 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700262
263 spin_lock_irqsave(&msm_chip->lock, irq_flags);
264 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700266 msm_gpio_clear_detect_status(msm_chip, offset);
267 msm_chip->int_enable[0] &= ~BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
269 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700270 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
271}
272
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100273static void msm_gpio_irq_unmask(struct irq_data *d)
Gregory Bean2783cc22010-09-10 15:03:36 -0700274{
275 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100277 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700278
279 spin_lock_irqsave(&msm_chip->lock, irq_flags);
280 /* level triggered interrupts are also latched */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 if (!(__raw_readl(msm_chip->regs.int_edge) & BIT(offset)))
Gregory Bean2783cc22010-09-10 15:03:36 -0700282 msm_gpio_clear_detect_status(msm_chip, offset);
283 msm_chip->int_enable[0] |= BIT(offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 __raw_writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
285 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700286 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
287}
288
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100289static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Gregory Bean2783cc22010-09-10 15:03:36 -0700290{
291 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100293 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700294
295 spin_lock_irqsave(&msm_chip->lock, irq_flags);
296
297 if (on)
298 msm_chip->int_enable[1] |= BIT(offset);
299 else
300 msm_chip->int_enable[1] &= ~BIT(offset);
301
302 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
303 return 0;
304}
305
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100306static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
Gregory Bean2783cc22010-09-10 15:03:36 -0700307{
308 unsigned long irq_flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 struct msm_gpio_chip *msm_chip = irq_get_chip_data(d->irq);
Lennert Buytenhek0f86ee02010-11-29 10:37:34 +0100310 unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
Gregory Bean2783cc22010-09-10 15:03:36 -0700311 unsigned val, mask = BIT(offset);
312
313 spin_lock_irqsave(&msm_chip->lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 val = __raw_readl(msm_chip->regs.int_edge);
Gregory Bean2783cc22010-09-10 15:03:36 -0700315 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 __raw_writel(val | mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100317 __irq_set_handler_locked(d->irq, handle_edge_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700318 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 __raw_writel(val & ~mask, msm_chip->regs.int_edge);
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100320 __irq_set_handler_locked(d->irq, handle_level_irq);
Gregory Bean2783cc22010-09-10 15:03:36 -0700321 }
322 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
323 msm_chip->both_edge_detect |= mask;
324 msm_gpio_update_both_edge_detect(msm_chip);
325 } else {
326 msm_chip->both_edge_detect &= ~mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 val = __raw_readl(msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700328 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
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 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 __raw_writel(val & ~mask, msm_chip->regs.int_pos);
Gregory Bean2783cc22010-09-10 15:03:36 -0700332 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 mb();
Gregory Bean2783cc22010-09-10 15:03:36 -0700334 spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
335 return 0;
336}
337
338static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
339{
340 int i, j, mask;
341 unsigned val;
Taniya Dasa187d122011-12-16 16:28:25 +0530342 struct irq_chip *chip = irq_desc_get_chip(desc);
343
344 chained_irq_enter(chip, desc);
Gregory Bean2783cc22010-09-10 15:03:36 -0700345
346 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
347 struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 val = __raw_readl(msm_chip->regs.int_status);
Gregory Bean2783cc22010-09-10 15:03:36 -0700349 val &= msm_chip->int_enable[0];
350 while (val) {
351 mask = val & -val;
352 j = fls(mask) - 1;
353 /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
354 __func__, v, m, j, msm_chip->chip.start + j,
355 FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
356 val &= ~mask;
357 generic_handle_irq(FIRST_GPIO_IRQ +
358 msm_chip->chip.base + j);
359 }
360 }
Taniya Dasa187d122011-12-16 16:28:25 +0530361
362 chained_irq_exit(chip, desc);
Gregory Bean2783cc22010-09-10 15:03:36 -0700363}
364
365static struct irq_chip msm_gpio_irq_chip = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 .name = "msmgpio",
367 .irq_ack = msm_gpio_irq_ack,
368 .irq_mask = msm_gpio_irq_mask,
369 .irq_unmask = msm_gpio_irq_unmask,
370 .irq_set_wake = msm_gpio_irq_set_wake,
371 .irq_set_type = msm_gpio_irq_set_type,
Gregory Bean2783cc22010-09-10 15:03:36 -0700372};
373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374#define NUM_GPIO_SMEM_BANKS 6
375#define GPIO_SMEM_NUM_GROUPS 2
376#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
377struct tramp_gpio_smem {
378 uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
379 uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
380 uint32_t enabled[NUM_GPIO_SMEM_BANKS];
381 uint32_t detection[NUM_GPIO_SMEM_BANKS];
382 uint32_t polarity[NUM_GPIO_SMEM_BANKS];
383};
384
385static void msm_gpio_sleep_int(unsigned long arg)
386{
387 int i, j;
388 struct tramp_gpio_smem *smem_gpio;
389
390 BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32);
391
392 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
393 if (smem_gpio == NULL)
394 return;
395
396 local_irq_disable();
397 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
398 int count = smem_gpio->num_fired[i];
399 for (j = 0; j < count; j++) {
400 /* TODO: Check mask */
401 generic_handle_irq(
402 MSM_GPIO_TO_INT(smem_gpio->fired[i][j]));
403 }
404 }
405 local_irq_enable();
406}
407
408static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0);
409
410void msm_gpio_enter_sleep(int from_idle)
411{
412 int i;
413 struct tramp_gpio_smem *smem_gpio;
414
415 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
416
417 if (smem_gpio) {
418 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
419 smem_gpio->enabled[i] = 0;
420 smem_gpio->detection[i] = 0;
421 smem_gpio->polarity[i] = 0;
422 }
423 }
424
425 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
426 __raw_writel(msm_gpio_chips[i].int_enable[!from_idle],
427 msm_gpio_chips[i].regs.int_en);
428 if (smem_gpio) {
429 uint32_t tmp;
430 int start, index, shiftl, shiftr;
431 start = msm_gpio_chips[i].chip.base;
432 index = start / 32;
433 shiftl = start % 32;
434 shiftr = 32 - shiftl;
435 tmp = msm_gpio_chips[i].int_enable[!from_idle];
436 smem_gpio->enabled[index] |= tmp << shiftl;
437 smem_gpio->enabled[index+1] |= tmp >> shiftr;
438 smem_gpio->detection[index] |=
439 __raw_readl(msm_gpio_chips[i].regs.int_edge) <<
440 shiftl;
441 smem_gpio->detection[index+1] |=
442 __raw_readl(msm_gpio_chips[i].regs.int_edge) >>
443 shiftr;
444 smem_gpio->polarity[index] |=
445 __raw_readl(msm_gpio_chips[i].regs.int_pos) <<
446 shiftl;
447 smem_gpio->polarity[index+1] |=
448 __raw_readl(msm_gpio_chips[i].regs.int_pos) >>
449 shiftr;
450 }
451 }
452 mb();
453
454 if (smem_gpio) {
455 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
456 for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
457 printk("msm_gpio_enter_sleep gpio %d-%d: enable"
458 " %08x, edge %08x, polarity %08x\n",
459 i * 32, i * 32 + 31,
460 smem_gpio->enabled[i],
461 smem_gpio->detection[i],
462 smem_gpio->polarity[i]);
463 }
464 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
465 smem_gpio->num_fired[i] = 0;
466 }
467}
468
469void msm_gpio_exit_sleep(void)
470{
471 int i;
472 struct tramp_gpio_smem *smem_gpio;
473
474 smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
475
476 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
477 __raw_writel(msm_gpio_chips[i].int_enable[0],
478 msm_gpio_chips[i].regs.int_en);
479 }
480 mb();
481
482 if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) {
483 if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
484 printk(KERN_INFO "gpio: fired %x %x\n",
485 smem_gpio->num_fired[0], smem_gpio->num_fired[1]);
486 tasklet_schedule(&msm_gpio_sleep_int_tasklet);
487 }
488}
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490
491int gpio_tlmm_config(unsigned config, unsigned disable)
492{
493 return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
494}
495EXPORT_SYMBOL(gpio_tlmm_config);
496
497int msm_gpios_request_enable(const struct msm_gpio *table, int size)
498{
499 int rc = msm_gpios_request(table, size);
500 if (rc)
501 return rc;
502 rc = msm_gpios_enable(table, size);
503 if (rc)
504 msm_gpios_free(table, size);
505 return rc;
506}
507EXPORT_SYMBOL(msm_gpios_request_enable);
508
509void msm_gpios_disable_free(const struct msm_gpio *table, int size)
510{
511 msm_gpios_disable(table, size);
512 msm_gpios_free(table, size);
513}
514EXPORT_SYMBOL(msm_gpios_disable_free);
515
516int msm_gpios_request(const struct msm_gpio *table, int size)
517{
518 int rc;
519 int i;
520 const struct msm_gpio *g;
521 for (i = 0; i < size; i++) {
522 g = table + i;
523 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
524 if (rc) {
525 pr_err("gpio_request(%d) <%s> failed: %d\n",
526 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
527 goto err;
528 }
529 }
530 return 0;
531err:
532 msm_gpios_free(table, i);
533 return rc;
534}
535EXPORT_SYMBOL(msm_gpios_request);
536
537void msm_gpios_free(const struct msm_gpio *table, int size)
538{
539 int i;
540 const struct msm_gpio *g;
541 for (i = size-1; i >= 0; i--) {
542 g = table + i;
543 gpio_free(GPIO_PIN(g->gpio_cfg));
544 }
545}
546EXPORT_SYMBOL(msm_gpios_free);
547
548int msm_gpios_enable(const struct msm_gpio *table, int size)
549{
550 int rc;
551 int i;
552 const struct msm_gpio *g;
553 for (i = 0; i < size; i++) {
554 g = table + i;
555 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
556 if (rc) {
557 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE)"
558 " <%s> failed: %d\n",
559 g->gpio_cfg, g->label ?: "?", rc);
560 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
561 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
562 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
563 GPIO_DRVSTR(g->gpio_cfg));
564 goto err;
565 }
566 }
567 return 0;
568err:
569 msm_gpios_disable(table, i);
570 return rc;
571}
572EXPORT_SYMBOL(msm_gpios_enable);
573
574int msm_gpios_disable(const struct msm_gpio *table, int size)
575{
576 int rc = 0;
577 int i;
578 const struct msm_gpio *g;
579 for (i = size-1; i >= 0; i--) {
580 int tmp;
581 g = table + i;
582 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
583 if (tmp) {
584 pr_err("gpio_tlmm_config(0x%08x, GPIO_CFG_DISABLE)"
585 " <%s> failed: %d\n",
586 g->gpio_cfg, g->label ?: "?", rc);
587 pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
588 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
589 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
590 GPIO_DRVSTR(g->gpio_cfg));
591 if (!rc)
592 rc = tmp;
593 }
594 }
595
596 return rc;
597}
598EXPORT_SYMBOL(msm_gpios_disable);
599
600/* Locate the GPIO_OUT register for the given GPIO and return its address
601 * and the bit position of the gpio's bit within the register.
602 *
603 * This function is used by gpiomux-v1 in order to support output transitions.
604 */
605void msm_gpio_find_out(const unsigned gpio, void __iomem **out,
606 unsigned *offset)
607{
608 struct msm_gpio_chip *msm_chip = msm_gpio_chips;
609
610 while (gpio >= msm_chip->chip.base + msm_chip->chip.ngpio)
611 ++msm_chip;
612
613 *out = msm_chip->regs.out;
614 *offset = gpio - msm_chip->chip.base;
615}
Taniya Das2e948192011-12-20 11:15:13 +0530616
617static int __devinit msm_gpio_probe(struct platform_device *dev)
618{
619 int i, j = 0;
620 int grp_irq;
621
622 for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
623 if (i - FIRST_GPIO_IRQ >=
624 msm_gpio_chips[j].chip.base +
625 msm_gpio_chips[j].chip.ngpio)
626 j++;
627 irq_set_chip_data(i, &msm_gpio_chips[j]);
628 irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
629 handle_edge_irq);
630 set_irq_flags(i, IRQF_VALID);
631 }
632
633 for (i = 0; i < dev->num_resources; i++) {
634 grp_irq = platform_get_irq(dev, i);
635 if (grp_irq < 0)
636 return -ENXIO;
637
638 irq_set_chained_handler(grp_irq, msm_gpio_irq_handler);
639 irq_set_irq_wake(grp_irq, (i + 1));
640 }
641
642 for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
643 spin_lock_init(&msm_gpio_chips[i].lock);
644 __raw_writel(0, msm_gpio_chips[i].regs.int_en);
645 gpiochip_add(&msm_gpio_chips[i].chip);
646 }
647
648 mb();
649 return 0;
650}
651
652static struct platform_driver msm_gpio_driver = {
653 .probe = msm_gpio_probe,
654 .driver = {
655 .name = "msmgpio",
656 .owner = THIS_MODULE,
657 },
658};
659
660static int __init msm_gpio_init(void)
661{
662 return platform_driver_register(&msm_gpio_driver);
663}
664postcore_initcall(msm_gpio_init);