blob: 5539950b2bca82e23760dc9eefb7764c0ba37532 [file] [log] [blame]
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -07001/* Copyright (c) 2012, 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#include <linux/bitmap.h>
14#include <linux/bitops.h>
15#include <linux/gpio.h>
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19#include <linux/io.h>
20#include <linux/module.h>
21#include <linux/spinlock.h>
22#include <linux/syscore_ops.h>
23#include <linux/irqdomain.h>
24#include <linux/of.h>
25#include <linux/err.h>
26
27#include <asm/mach/irq.h>
28
29#include <mach/msm_iomap.h>
30#include <mach/gpiomux.h>
31#include <mach/mpm.h>
32#include "gpio-msm-common.h"
33
34enum msm_tlmm_register {
35 SDC4_HDRV_PULL_CTL = 0x20a0,
36 SDC3_HDRV_PULL_CTL = 0x20a4,
37 SDC1_HDRV_PULL_CTL = 0x20a0,
38};
39
40struct tlmm_field_cfg {
41 enum msm_tlmm_register reg;
42 u8 off;
43};
44
45static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
46 {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
47 {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
48 {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
49 {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
50 {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
51 {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
52 {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
53 {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
54 {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
55};
56
57static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
58 {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
59 {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
60 {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
61 {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
62 {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
63 {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
64 {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
65 {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
66};
67
68/*
69 * Supported arch specific irq extension.
70 * Default make them NULL.
71 */
72struct irq_chip msm_gpio_irq_extn = {
73 .irq_eoi = NULL,
74 .irq_mask = NULL,
75 .irq_unmask = NULL,
76 .irq_retrigger = NULL,
77 .irq_set_type = NULL,
78 .irq_set_wake = NULL,
79 .irq_disable = NULL,
80};
81
82/**
83 * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
84 *
85 * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
86 * keeping track of which gpios are unmasked as irq sources, we avoid
87 * having to do __raw_readl calls on hundreds of iomapped registers each time
88 * the summary interrupt fires in order to locate the active interrupts.
89 *
90 * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
91 * as wakeup sources. When the device is suspended, interrupts which are
92 * not wakeup sources are disabled.
93 *
94 * @dual_edge_irqs: a bitmap used to track which irqs are configured
95 * as dual-edge, as this is not supported by the hardware and requires
96 * some special handling in the driver.
97 */
98struct msm_gpio_dev {
99 struct gpio_chip gpio_chip;
100 DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
101 DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
102 DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700103 struct irq_domain *domain;
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700104};
105
106static DEFINE_SPINLOCK(tlmm_lock);
107
108static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
109{
110 return container_of(chip, struct msm_gpio_dev, gpio_chip);
111}
112
113static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
114{
115 int rc;
116 rc = __msm_gpio_get_inout(offset);
117 mb();
118 return rc;
119}
120
121static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
122{
123 __msm_gpio_set_inout(offset, val);
124 mb();
125}
126
127static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
128{
129 unsigned long irq_flags;
130
131 spin_lock_irqsave(&tlmm_lock, irq_flags);
132 __msm_gpio_set_config_direction(offset, 1, 0);
133 mb();
134 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
135 return 0;
136}
137
138static int msm_gpio_direction_output(struct gpio_chip *chip,
139 unsigned offset,
140 int val)
141{
142 unsigned long irq_flags;
143
144 spin_lock_irqsave(&tlmm_lock, irq_flags);
145 __msm_gpio_set_config_direction(offset, 0, val);
146 mb();
147 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
148 return 0;
149}
150
151#ifdef CONFIG_OF
152static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
153{
154 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700155 struct irq_domain *domain = g_dev->domain;
156 return irq_linear_revmap(domain, offset - chip->base);
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700157}
158
159static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
160{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700161 struct irq_data *irq_data = irq_get_irq_data(irq);
162 return irq_data->hwirq;
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700163}
164#else
165static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
166{
167 return MSM_GPIO_TO_INT(offset - chip->base);
168}
169
170static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
171{
172 return irq - MSM_GPIO_TO_INT(chip->base);
173}
174#endif
175
176static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
177{
178 return msm_gpiomux_get(chip->base + offset);
179}
180
181static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
182{
183 msm_gpiomux_put(chip->base + offset);
184}
185
186static struct msm_gpio_dev msm_gpio = {
187 .gpio_chip = {
188 .label = "msmgpio",
189 .base = 0,
190 .ngpio = NR_MSM_GPIOS,
191 .direction_input = msm_gpio_direction_input,
192 .direction_output = msm_gpio_direction_output,
193 .get = msm_gpio_get,
194 .set = msm_gpio_set,
195 .to_irq = msm_gpio_to_irq,
196 .request = msm_gpio_request,
197 .free = msm_gpio_free,
198 },
199};
200
201static void switch_mpm_config(struct irq_data *d, unsigned val)
202{
203 /* switch the configuration in the mpm as well */
204 if (!msm_gpio_irq_extn.irq_set_type)
205 return;
206
207 if (val)
208 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
209 else
210 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
211}
212
213/* For dual-edge interrupts in software, since the hardware has no
214 * such support:
215 *
216 * At appropriate moments, this function may be called to flip the polarity
217 * settings of both-edge irq lines to try and catch the next edge.
218 *
219 * The attempt is considered successful if:
220 * - the status bit goes high, indicating that an edge was caught, or
221 * - the input value of the gpio doesn't change during the attempt.
222 * If the value changes twice during the process, that would cause the first
223 * test to fail but would force the second, as two opposite
224 * transitions would cause a detection no matter the polarity setting.
225 *
226 * The do-loop tries to sledge-hammer closed the timing hole between
227 * the initial value-read and the polarity-write - if the line value changes
228 * during that window, an interrupt is lost, the new polarity setting is
229 * incorrect, and the first success test will fail, causing a retry.
230 *
231 * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
232 */
233static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
234{
235 int loop_limit = 100;
236 unsigned val, val2, intstat;
237
238 do {
239 val = __msm_gpio_get_inout(gpio);
240 __msm_gpio_set_polarity(gpio, val);
241 val2 = __msm_gpio_get_inout(gpio);
242 intstat = __msm_gpio_get_intr_status(gpio);
243 if (intstat || val == val2) {
244 switch_mpm_config(d, val);
245 return;
246 }
247 } while (loop_limit-- > 0);
248 pr_err("%s: dual-edge irq failed to stabilize, %#08x != %#08x\n",
249 __func__, val, val2);
250}
251
252static void msm_gpio_irq_ack(struct irq_data *d)
253{
254 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
255
256 __msm_gpio_set_intr_status(gpio);
257 if (test_bit(gpio, msm_gpio.dual_edge_irqs))
258 msm_gpio_update_dual_edge_pos(d, gpio);
259 mb();
260}
261
262static void msm_gpio_irq_mask(struct irq_data *d)
263{
264 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
265 unsigned long irq_flags;
266
267 spin_lock_irqsave(&tlmm_lock, irq_flags);
268 __msm_gpio_set_intr_cfg_enable(gpio, 0);
269 __clear_bit(gpio, msm_gpio.enabled_irqs);
270 mb();
271 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
272
273 if (msm_gpio_irq_extn.irq_mask)
274 msm_gpio_irq_extn.irq_mask(d);
275
276}
277
278static void msm_gpio_irq_unmask(struct irq_data *d)
279{
280 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
281 unsigned long irq_flags;
282
283 spin_lock_irqsave(&tlmm_lock, irq_flags);
284 __set_bit(gpio, msm_gpio.enabled_irqs);
285 __msm_gpio_set_intr_cfg_enable(gpio, 1);
286 mb();
287 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
288
289 if (msm_gpio_irq_extn.irq_mask)
290 msm_gpio_irq_extn.irq_unmask(d);
291}
292
293static void msm_gpio_irq_disable(struct irq_data *d)
294{
295 if (msm_gpio_irq_extn.irq_disable)
296 msm_gpio_irq_extn.irq_disable(d);
297}
298
299static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
300{
301 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
302 unsigned long irq_flags;
303
304 spin_lock_irqsave(&tlmm_lock, irq_flags);
305
306 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
307 __irq_set_handler_locked(d->irq, handle_edge_irq);
308 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
309 __set_bit(gpio, msm_gpio.dual_edge_irqs);
310 else
311 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
312 } else {
313 __irq_set_handler_locked(d->irq, handle_level_irq);
314 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
315 }
316
317 __msm_gpio_set_intr_cfg_type(gpio, flow_type);
318
319 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
320 msm_gpio_update_dual_edge_pos(d, gpio);
321
322 mb();
323 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
324
325 if (msm_gpio_irq_extn.irq_set_type)
326 msm_gpio_irq_extn.irq_set_type(d, flow_type);
327
328 return 0;
329}
330
331/*
332 * When the summary IRQ is raised, any number of GPIO lines may be high.
333 * It is the job of the summary handler to find all those GPIO lines
334 * which have been set as summary IRQ lines and which are triggered,
335 * and to call their interrupt handlers.
336 */
337static irqreturn_t msm_summary_irq_handler(int irq, void *data)
338{
339 unsigned long i;
340 struct irq_desc *desc = irq_to_desc(irq);
341 struct irq_chip *chip = irq_desc_get_chip(desc);
342
343 chained_irq_enter(chip, desc);
344
345 for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
346 i < NR_MSM_GPIOS;
347 i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
348 if (__msm_gpio_get_intr_status(i))
349 generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
350 i));
351 }
352
353 chained_irq_exit(chip, desc);
354 return IRQ_HANDLED;
355}
356
357static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
358{
359 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
360
361 if (on) {
362 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
363 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
364 set_bit(gpio, msm_gpio.wake_irqs);
365 } else {
366 clear_bit(gpio, msm_gpio.wake_irqs);
367 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
368 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
369 }
370
371 if (msm_gpio_irq_extn.irq_set_wake)
372 msm_gpio_irq_extn.irq_set_wake(d, on);
373
374 return 0;
375}
376
377static struct irq_chip msm_gpio_irq_chip = {
378 .name = "msmgpio",
379 .irq_mask = msm_gpio_irq_mask,
380 .irq_unmask = msm_gpio_irq_unmask,
381 .irq_ack = msm_gpio_irq_ack,
382 .irq_set_type = msm_gpio_irq_set_type,
383 .irq_set_wake = msm_gpio_irq_set_wake,
384 .irq_disable = msm_gpio_irq_disable,
385};
386
387/*
388 * This lock class tells lockdep that GPIO irqs are in a different
389 * category than their parent, so it won't report false recursion.
390 */
391static struct lock_class_key msm_gpio_lock_class;
392
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700393/* TODO: This should be a real platform_driver */
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700394static int __devinit msm_gpio_probe(void)
395{
396 int i, irq, ret;
397
398 spin_lock_init(&tlmm_lock);
399 bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
400 bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
401 bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
402 ret = gpiochip_add(&msm_gpio.gpio_chip);
403 if (ret < 0)
404 return ret;
405
406 for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
407 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
408 irq_set_lockdep_class(irq, &msm_gpio_lock_class);
409 irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
410 handle_level_irq);
411 set_irq_flags(irq, IRQF_VALID);
412 }
413
414 ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
415 IRQF_TRIGGER_HIGH, "msmgpio", NULL);
416 if (ret) {
417 pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
418 ret);
419 return ret;
420 }
421 return 0;
422}
423
424static int __devexit msm_gpio_remove(void)
425{
426 int ret = gpiochip_remove(&msm_gpio.gpio_chip);
427
428 if (ret < 0)
429 return ret;
430
431 irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
432
433 return 0;
434}
435
436#ifdef CONFIG_PM
437static int msm_gpio_suspend(void)
438{
439 unsigned long irq_flags;
440 unsigned long i;
441
442 spin_lock_irqsave(&tlmm_lock, irq_flags);
443 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
444 __msm_gpio_set_intr_cfg_enable(i, 0);
445
446 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
447 __msm_gpio_set_intr_cfg_enable(i, 1);
448 mb();
449 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
450 return 0;
451}
452
453void msm_gpio_show_resume_irq(void)
454{
455 unsigned long irq_flags;
456 int i, irq, intstat;
457
458 if (!msm_show_resume_irq_mask)
459 return;
460
461 spin_lock_irqsave(&tlmm_lock, irq_flags);
462 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
463 intstat = __msm_gpio_get_intr_status(i);
464 if (intstat) {
465 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
466 pr_warning("%s: %d triggered\n",
467 __func__, irq);
468 }
469 }
470 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
471}
472
473static void msm_gpio_resume(void)
474{
475 unsigned long irq_flags;
476 unsigned long i;
477
478 msm_gpio_show_resume_irq();
479
480 spin_lock_irqsave(&tlmm_lock, irq_flags);
481 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
482 __msm_gpio_set_intr_cfg_enable(i, 0);
483
484 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
485 __msm_gpio_set_intr_cfg_enable(i, 1);
486 mb();
487 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
488}
489#else
490#define msm_gpio_suspend NULL
491#define msm_gpio_resume NULL
492#endif
493
494static struct syscore_ops msm_gpio_syscore_ops = {
495 .suspend = msm_gpio_suspend,
496 .resume = msm_gpio_resume,
497};
498
499static int __init msm_gpio_init(void)
500{
501 msm_gpio_probe();
502 register_syscore_ops(&msm_gpio_syscore_ops);
503 return 0;
504}
505
506static void __exit msm_gpio_exit(void)
507{
508 unregister_syscore_ops(&msm_gpio_syscore_ops);
509 msm_gpio_remove();
510}
511
512postcore_initcall(msm_gpio_init);
513module_exit(msm_gpio_exit);
514
515static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
516 unsigned id, unsigned width, unsigned val)
517{
518 unsigned long irqflags;
519 u32 mask = (1 << width) - 1;
520 u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
521 u32 reg_val;
522
523 spin_lock_irqsave(&tlmm_lock, irqflags);
524 reg_val = __raw_readl(reg);
525 reg_val &= ~(mask << configs[id].off);
526 reg_val |= (val & mask) << configs[id].off;
527 __raw_writel(reg_val, reg);
528 mb();
529 spin_unlock_irqrestore(&tlmm_lock, irqflags);
530}
531
532void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
533{
534 msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
535}
536EXPORT_SYMBOL(msm_tlmm_set_hdrive);
537
538void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
539{
540 msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
541}
542EXPORT_SYMBOL(msm_tlmm_set_pull);
543
544int gpio_tlmm_config(unsigned config, unsigned disable)
545{
546 unsigned gpio = GPIO_PIN(config);
547
548 if (gpio > NR_MSM_GPIOS)
549 return -EINVAL;
550
551 __gpio_tlmm_config(config);
552 mb();
553
554 return 0;
555}
556EXPORT_SYMBOL(gpio_tlmm_config);
557
558int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
559 unsigned int input_polarity)
560{
561 unsigned long irq_flags;
562
563 if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
564 return -EINVAL;
565
566 spin_lock_irqsave(&tlmm_lock, irq_flags);
567 __msm_gpio_install_direct_irq(gpio, irq, input_polarity);
568 mb();
569 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
570
571 return 0;
572}
573EXPORT_SYMBOL(msm_gpio_install_direct_irq);
574
575#ifdef CONFIG_OF
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700576static int msm_gpio_irq_domain_xlate(struct irq_domain *d,
577 struct device_node *controller,
578 const u32 *intspec,
579 unsigned int intsize,
580 unsigned long *out_hwirq,
581 unsigned int *out_type)
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700582{
583 if (d->of_node != controller)
584 return -EINVAL;
585 if (intsize != 2)
586 return -EINVAL;
587
588 /* hwirq value */
589 *out_hwirq = intspec[0];
590
591 /* irq flags */
592 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
593 return 0;
594}
595
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700596/*
597 * TODO: this really should be doing all the things that msm_gpio_probe() does,
598 * but since the msm_gpio_probe is called unconditionally for DT and non-DT
599 * configs, we can't duplicate it here. This should be fixed.
600 */
601int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
602 irq_hw_number_t hwirq)
603{
604 return 0;
605}
606
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700607static struct irq_domain_ops msm_gpio_irq_domain_ops = {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700608 .xlate = msm_gpio_irq_domain_xlate,
609 .map = msm_gpio_irq_domain_map,
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700610};
611
612int __init msm_gpio_of_init(struct device_node *node,
613 struct device_node *parent)
614{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700615 msm_gpio.domain = irq_domain_add_linear(node, NR_MSM_GPIOS,
616 &msm_gpio_irq_domain_ops, &msm_gpio);
617 if (!msm_gpio.domain) {
618 WARN(1, "Cannot allocate irq_domain\n");
619 return -ENOMEM;
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700620 }
621
Sathish Ambleyd2ad0fa2012-03-23 11:23:47 -0700622 return 0;
623}
624#endif
625
626MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
627MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
628MODULE_LICENSE("GPL v2");
629MODULE_ALIAS("sysdev:msmgpio");