blob: ad436e09dcea5419d21bf8fecdd2a2d099815d3f [file] [log] [blame]
Steve Mucklef132c6c2012-06-06 18:30:57 -07001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Gregory Bean0cc2fc12010-11-24 11:53:51 -08002 *
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 *
Gregory Bean0cc2fc12010-11-24 11:53:51 -080012 */
Gregory Bean70cc2c02010-11-24 11:53:52 -080013#include <linux/bitmap.h>
14#include <linux/bitops.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080015#include <linux/gpio.h>
Gregory Bean70cc2c02010-11-24 11:53:52 -080016#include <linux/init.h>
17#include <linux/interrupt.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080018#include <linux/irq.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070019#include <linux/io.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080020#include <linux/module.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080021#include <linux/spinlock.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070022#include <linux/syscore_ops.h>
23#include <linux/irqdomain.h>
24#include <linux/of.h>
25#include <linux/err.h>
Will Deacon03dd7652011-02-21 14:54:57 +000026
27#include <asm/mach/irq.h>
28
Gregory Bean0cc2fc12010-11-24 11:53:51 -080029#include <mach/msm_iomap.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070030#include <mach/gpiomux.h>
31#include <mach/mpm.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080032
33/* Bits of interest in the GPIO_IN_OUT register.
34 */
35enum {
Steve Mucklef132c6c2012-06-06 18:30:57 -070036 GPIO_IN_BIT = 0,
37 GPIO_OUT_BIT = 1
Gregory Bean70cc2c02010-11-24 11:53:52 -080038};
39
40/* Bits of interest in the GPIO_INTR_STATUS register.
41 */
42enum {
Steve Mucklef132c6c2012-06-06 18:30:57 -070043 INTR_STATUS_BIT = 0,
Gregory Bean0cc2fc12010-11-24 11:53:51 -080044};
45
46/* Bits of interest in the GPIO_CFG register.
47 */
48enum {
Steve Mucklef132c6c2012-06-06 18:30:57 -070049 GPIO_OE_BIT = 9,
Gregory Bean0cc2fc12010-11-24 11:53:51 -080050};
51
Gregory Bean70cc2c02010-11-24 11:53:52 -080052/* Bits of interest in the GPIO_INTR_CFG register.
Steve Mucklef132c6c2012-06-06 18:30:57 -070053 */
54enum {
55 INTR_ENABLE_BIT = 0,
56 INTR_POL_CTL_BIT = 1,
57 INTR_DECT_CTL_BIT = 2,
58 INTR_RAW_STATUS_EN_BIT = 3,
59};
60
61/* Codes of interest in GPIO_INTR_CFG_SU.
62 */
63enum {
64 TARGET_PROC_SCORPION = 4,
65 TARGET_PROC_NONE = 7,
66};
67
68/*
69 * There is no 'DC_POLARITY_LO' because the GIC is incapable
70 * of asserting on falling edge or level-low conditions. Even though
71 * the registers allow for low-polarity inputs, the case can never arise.
72 */
73enum {
74 DC_POLARITY_HI = BIT(11),
75 DC_IRQ_ENABLE = BIT(3),
76};
77
78enum msm_tlmm_register {
79 SDC4_HDRV_PULL_CTL = 0x20a0,
80 SDC3_HDRV_PULL_CTL = 0x20a4,
81 SDC1_HDRV_PULL_CTL = 0x20a0,
82};
83
84struct tlmm_field_cfg {
85 enum msm_tlmm_register reg;
86 u8 off;
87};
88
89static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
90 {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
91 {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
92 {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
93 {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
94 {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
95 {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
96 {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
97 {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
98 {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
99};
100
101static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
102 {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
103 {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
104 {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
105 {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
106 {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
107 {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
108 {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
109 {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
110};
111
112/*
113 * Supported arch specific irq extension.
114 * Default make them NULL.
115 */
116struct irq_chip msm_gpio_irq_extn = {
117 .irq_eoi = NULL,
118 .irq_mask = NULL,
119 .irq_unmask = NULL,
120 .irq_retrigger = NULL,
121 .irq_set_type = NULL,
122 .irq_set_wake = NULL,
123 .irq_disable = NULL,
124};
125
126/*
Gregory Bean70cc2c02010-11-24 11:53:52 -0800127 * When a GPIO triggers, two separate decisions are made, controlled
128 * by two separate flags.
129 *
130 * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
131 * register for that GPIO will be updated to reflect the triggering of that
132 * gpio. If this bit is 0, this register will not be updated.
133 * - Second, INTR_ENABLE controls whether an interrupt is triggered.
134 *
135 * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
136 * can be triggered but the status register will not reflect it.
137 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700138#define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
139#define INTR_ENABLE BIT(INTR_ENABLE_BIT)
140#define INTR_DECT_CTL_EDGE BIT(INTR_DECT_CTL_BIT)
141#define INTR_POL_CTL_HI BIT(INTR_POL_CTL_BIT)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800142
143#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
Steve Mucklef132c6c2012-06-06 18:30:57 -0700144#define DIR_CONN_INTR_CFG_SU(irq) (MSM_TLMM_BASE + 0x0700 + (0x04 * (irq)))
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800145#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
146#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
Gregory Bean70cc2c02010-11-24 11:53:52 -0800147#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
148#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
149
150/**
151 * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
152 *
153 * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
154 * keeping track of which gpios are unmasked as irq sources, we avoid
Steve Mucklef132c6c2012-06-06 18:30:57 -0700155 * having to do __raw_readl calls on hundreds of iomapped registers each time
Gregory Bean70cc2c02010-11-24 11:53:52 -0800156 * the summary interrupt fires in order to locate the active interrupts.
157 *
158 * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
159 * as wakeup sources. When the device is suspended, interrupts which are
160 * not wakeup sources are disabled.
161 *
162 * @dual_edge_irqs: a bitmap used to track which irqs are configured
163 * as dual-edge, as this is not supported by the hardware and requires
164 * some special handling in the driver.
165 */
166struct msm_gpio_dev {
167 struct gpio_chip gpio_chip;
Steve Mucklef132c6c2012-06-06 18:30:57 -0700168 DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
169 DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
170 DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
171 struct irq_domain domain;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800172};
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800173
174static DEFINE_SPINLOCK(tlmm_lock);
175
Gregory Bean70cc2c02010-11-24 11:53:52 -0800176static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
177{
178 return container_of(chip, struct msm_gpio_dev, gpio_chip);
179}
180
181static inline void set_gpio_bits(unsigned n, void __iomem *reg)
182{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700183 __raw_writel(__raw_readl(reg) | n, reg);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800184}
185
Steve Mucklef132c6c2012-06-06 18:30:57 -0700186static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800187{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700188 __raw_writel(__raw_readl(reg) & ~n, reg);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800189}
190
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800191static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
192{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700193 int rc;
194 rc = __raw_readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
195 mb();
196 return rc;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800197}
198
199static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
200{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700201 __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
202 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800203}
204
205static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
206{
207 unsigned long irq_flags;
208
209 spin_lock_irqsave(&tlmm_lock, irq_flags);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700210 clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
211 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800212 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
213 return 0;
214}
215
216static int msm_gpio_direction_output(struct gpio_chip *chip,
217 unsigned offset,
218 int val)
219{
220 unsigned long irq_flags;
221
222 spin_lock_irqsave(&tlmm_lock, irq_flags);
223 msm_gpio_set(chip, offset, val);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700224 set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
225 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800226 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
227 return 0;
228}
229
Steve Mucklef132c6c2012-06-06 18:30:57 -0700230#ifdef CONFIG_OF
231static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
232{
233 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
234 struct irq_domain *domain = &g_dev->domain;
235 return domain->irq_base + (offset - chip->base);
236}
237
238static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
239{
240 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
241 struct irq_domain *domain = &g_dev->domain;
242 return irq - domain->irq_base;
243}
244#else
245static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
246{
247 return MSM_GPIO_TO_INT(offset - chip->base);
248}
249
250static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
251{
252 return irq - MSM_GPIO_TO_INT(chip->base);
253}
254#endif
255
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800256static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
257{
258 return msm_gpiomux_get(chip->base + offset);
259}
260
261static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
262{
263 msm_gpiomux_put(chip->base + offset);
264}
265
Gregory Bean70cc2c02010-11-24 11:53:52 -0800266static struct msm_gpio_dev msm_gpio = {
267 .gpio_chip = {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700268 .label = "msmgpio",
Gregory Bean70cc2c02010-11-24 11:53:52 -0800269 .base = 0,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700270 .ngpio = NR_MSM_GPIOS,
Gregory Bean70cc2c02010-11-24 11:53:52 -0800271 .direction_input = msm_gpio_direction_input,
272 .direction_output = msm_gpio_direction_output,
273 .get = msm_gpio_get,
274 .set = msm_gpio_set,
275 .to_irq = msm_gpio_to_irq,
276 .request = msm_gpio_request,
277 .free = msm_gpio_free,
278 },
279};
280
Steve Mucklef132c6c2012-06-06 18:30:57 -0700281static void switch_mpm_config(struct irq_data *d, unsigned val)
282{
283 /* switch the configuration in the mpm as well */
284 if (!msm_gpio_irq_extn.irq_set_type)
285 return;
286
287 if (val)
288 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
289 else
290 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
291}
292
Gregory Bean70cc2c02010-11-24 11:53:52 -0800293/* For dual-edge interrupts in software, since the hardware has no
294 * such support:
295 *
296 * At appropriate moments, this function may be called to flip the polarity
297 * settings of both-edge irq lines to try and catch the next edge.
298 *
299 * The attempt is considered successful if:
300 * - the status bit goes high, indicating that an edge was caught, or
301 * - the input value of the gpio doesn't change during the attempt.
302 * If the value changes twice during the process, that would cause the first
303 * test to fail but would force the second, as two opposite
304 * transitions would cause a detection no matter the polarity setting.
305 *
306 * The do-loop tries to sledge-hammer closed the timing hole between
307 * the initial value-read and the polarity-write - if the line value changes
308 * during that window, an interrupt is lost, the new polarity setting is
309 * incorrect, and the first success test will fail, causing a retry.
310 *
311 * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
312 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700313static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800314{
315 int loop_limit = 100;
316 unsigned val, val2, intstat;
317
318 do {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700319 val = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800320 if (val)
Steve Mucklef132c6c2012-06-06 18:30:57 -0700321 clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800322 else
Steve Mucklef132c6c2012-06-06 18:30:57 -0700323 set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
324 val2 = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
325 intstat = __raw_readl(GPIO_INTR_STATUS(gpio)) &
326 BIT(INTR_STATUS_BIT);
327 if (intstat || val == val2) {
328 switch_mpm_config(d, val);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800329 return;
Steve Mucklef132c6c2012-06-06 18:30:57 -0700330 }
Gregory Bean70cc2c02010-11-24 11:53:52 -0800331 } while (loop_limit-- > 0);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700332 pr_err("%s: dual-edge irq failed to stabilize, "
Gregory Bean70cc2c02010-11-24 11:53:52 -0800333 "interrupts dropped. %#08x != %#08x\n",
Steve Mucklef132c6c2012-06-06 18:30:57 -0700334 __func__, val, val2);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800335}
336
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100337static void msm_gpio_irq_ack(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800338{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100339 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800340
Steve Mucklef132c6c2012-06-06 18:30:57 -0700341 __raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800342 if (test_bit(gpio, msm_gpio.dual_edge_irqs))
Steve Mucklef132c6c2012-06-06 18:30:57 -0700343 msm_gpio_update_dual_edge_pos(d, gpio);
344 mb();
345}
346
347static void __msm_gpio_irq_mask(unsigned int gpio)
348{
349 __raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
350 clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800351}
352
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100353static void msm_gpio_irq_mask(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800354{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100355 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800356 unsigned long irq_flags;
357
358 spin_lock_irqsave(&tlmm_lock, irq_flags);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700359 __msm_gpio_irq_mask(gpio);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800360 __clear_bit(gpio, msm_gpio.enabled_irqs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700361 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800362 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700363
364 if (msm_gpio_irq_extn.irq_mask)
365 msm_gpio_irq_extn.irq_mask(d);
366
367}
368
369static void __msm_gpio_irq_unmask(unsigned int gpio)
370{
371 set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
372 __raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800373}
374
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100375static void msm_gpio_irq_unmask(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800376{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100377 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800378 unsigned long irq_flags;
379
380 spin_lock_irqsave(&tlmm_lock, irq_flags);
381 __set_bit(gpio, msm_gpio.enabled_irqs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700382 __msm_gpio_irq_unmask(gpio);
383 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800384 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700385
386 if (msm_gpio_irq_extn.irq_mask)
387 msm_gpio_irq_extn.irq_unmask(d);
388}
389
390static void msm_gpio_irq_disable(struct irq_data *d)
391{
392 if (msm_gpio_irq_extn.irq_disable)
393 msm_gpio_irq_extn.irq_disable(d);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800394}
395
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100396static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800397{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100398 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800399 unsigned long irq_flags;
400 uint32_t bits;
401
402 spin_lock_irqsave(&tlmm_lock, irq_flags);
403
Steve Mucklef132c6c2012-06-06 18:30:57 -0700404 bits = __raw_readl(GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800405
406 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700407 bits |= INTR_DECT_CTL_EDGE;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100408 __irq_set_handler_locked(d->irq, handle_edge_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800409 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
410 __set_bit(gpio, msm_gpio.dual_edge_irqs);
411 else
412 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
413 } else {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700414 bits &= ~INTR_DECT_CTL_EDGE;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100415 __irq_set_handler_locked(d->irq, handle_level_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800416 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
417 }
418
419 if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
Steve Mucklef132c6c2012-06-06 18:30:57 -0700420 bits |= INTR_POL_CTL_HI;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800421 else
Steve Mucklef132c6c2012-06-06 18:30:57 -0700422 bits &= ~INTR_POL_CTL_HI;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800423
Steve Mucklef132c6c2012-06-06 18:30:57 -0700424 __raw_writel(bits, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800425
426 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
Steve Mucklef132c6c2012-06-06 18:30:57 -0700427 msm_gpio_update_dual_edge_pos(d, gpio);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800428
Steve Mucklef132c6c2012-06-06 18:30:57 -0700429 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800430 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
431
Steve Mucklef132c6c2012-06-06 18:30:57 -0700432 if (msm_gpio_irq_extn.irq_set_type)
433 msm_gpio_irq_extn.irq_set_type(d, flow_type);
434
Gregory Bean70cc2c02010-11-24 11:53:52 -0800435 return 0;
436}
437
438/*
439 * When the summary IRQ is raised, any number of GPIO lines may be high.
440 * It is the job of the summary handler to find all those GPIO lines
441 * which have been set as summary IRQ lines and which are triggered,
442 * and to call their interrupt handlers.
443 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700444static irqreturn_t msm_summary_irq_handler(int irq, void *data)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800445{
446 unsigned long i;
Steve Mucklef132c6c2012-06-06 18:30:57 -0700447 struct irq_desc *desc = irq_to_desc(irq);
Will Deacon03dd7652011-02-21 14:54:57 +0000448 struct irq_chip *chip = irq_desc_get_chip(desc);
449
450 chained_irq_enter(chip, desc);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800451
Steve Mucklef132c6c2012-06-06 18:30:57 -0700452 for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
453 i < NR_MSM_GPIOS;
454 i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
455 if (__raw_readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS_BIT))
Gregory Bean70cc2c02010-11-24 11:53:52 -0800456 generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
457 i));
458 }
Will Deacon03dd7652011-02-21 14:54:57 +0000459
460 chained_irq_exit(chip, desc);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700461 return IRQ_HANDLED;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800462}
463
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100464static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800465{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100466 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800467
468 if (on) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700469 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
470 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800471 set_bit(gpio, msm_gpio.wake_irqs);
472 } else {
473 clear_bit(gpio, msm_gpio.wake_irqs);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700474 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
475 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800476 }
477
Steve Mucklef132c6c2012-06-06 18:30:57 -0700478 if (msm_gpio_irq_extn.irq_set_wake)
479 msm_gpio_irq_extn.irq_set_wake(d, on);
480
Gregory Bean70cc2c02010-11-24 11:53:52 -0800481 return 0;
482}
483
484static struct irq_chip msm_gpio_irq_chip = {
485 .name = "msmgpio",
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100486 .irq_mask = msm_gpio_irq_mask,
487 .irq_unmask = msm_gpio_irq_unmask,
488 .irq_ack = msm_gpio_irq_ack,
489 .irq_set_type = msm_gpio_irq_set_type,
490 .irq_set_wake = msm_gpio_irq_set_wake,
Steve Mucklef132c6c2012-06-06 18:30:57 -0700491 .irq_disable = msm_gpio_irq_disable,
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800492};
493
Steve Mucklef132c6c2012-06-06 18:30:57 -0700494/*
495 * This lock class tells lockdep that GPIO irqs are in a different
496 * category than their parent, so it won't report false recursion.
497 */
498static struct lock_class_key msm_gpio_lock_class;
499
500static int __devinit msm_gpio_probe(void)
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800501{
Gregory Bean70cc2c02010-11-24 11:53:52 -0800502 int i, irq, ret;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800503
Steve Mucklef132c6c2012-06-06 18:30:57 -0700504 spin_lock_init(&tlmm_lock);
505 bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
506 bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
507 bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800508 ret = gpiochip_add(&msm_gpio.gpio_chip);
509 if (ret < 0)
510 return ret;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800511
Gregory Bean70cc2c02010-11-24 11:53:52 -0800512 for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
513 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
Steve Mucklef132c6c2012-06-06 18:30:57 -0700514 irq_set_lockdep_class(irq, &msm_gpio_lock_class);
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +0100515 irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
516 handle_level_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800517 set_irq_flags(irq, IRQF_VALID);
518 }
519
Steve Mucklef132c6c2012-06-06 18:30:57 -0700520 ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
521 IRQF_TRIGGER_HIGH, "msmgpio", NULL);
522 if (ret) {
523 pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
524 ret);
525 return ret;
526 }
Gregory Bean70cc2c02010-11-24 11:53:52 -0800527 return 0;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800528}
529
Steve Mucklef132c6c2012-06-06 18:30:57 -0700530static int __devexit msm_gpio_remove(void)
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800531{
Gregory Bean70cc2c02010-11-24 11:53:52 -0800532 int ret = gpiochip_remove(&msm_gpio.gpio_chip);
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800533
534 if (ret < 0)
535 return ret;
536
Steve Mucklef132c6c2012-06-06 18:30:57 -0700537 irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800538
539 return 0;
540}
541
Steve Mucklef132c6c2012-06-06 18:30:57 -0700542#ifdef CONFIG_PM
543static int msm_gpio_suspend(void)
544{
545 unsigned long irq_flags;
546 unsigned long i;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800547
Steve Mucklef132c6c2012-06-06 18:30:57 -0700548 spin_lock_irqsave(&tlmm_lock, irq_flags);
549 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
550 __msm_gpio_irq_mask(i);
551
552 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
553 __msm_gpio_irq_unmask(i);
554 mb();
555 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
556 return 0;
557}
558
559extern int msm_show_resume_irq_mask;
560
561void msm_gpio_show_resume_irq(void)
562{
563 unsigned long irq_flags;
564 int i, irq, intstat;
565
566 if (!msm_show_resume_irq_mask)
567 return;
568
569 spin_lock_irqsave(&tlmm_lock, irq_flags);
570 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
571 intstat = __raw_readl(GPIO_INTR_STATUS(i)) &
572 BIT(INTR_STATUS_BIT);
573 if (intstat) {
574 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
575 pr_warning("%s: %d triggered\n",
576 __func__, irq);
577 }
578 }
579 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
580}
581
582static void msm_gpio_resume(void)
583{
584 unsigned long irq_flags;
585 unsigned long i;
586
587 msm_gpio_show_resume_irq();
588
589 spin_lock_irqsave(&tlmm_lock, irq_flags);
590 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
591 __msm_gpio_irq_mask(i);
592
593 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
594 __msm_gpio_irq_unmask(i);
595 mb();
596 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
597}
598#else
599#define msm_gpio_suspend NULL
600#define msm_gpio_resume NULL
601#endif
602
603static struct syscore_ops msm_gpio_syscore_ops = {
604 .suspend = msm_gpio_suspend,
605 .resume = msm_gpio_resume,
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800606};
607
608static int __init msm_gpio_init(void)
609{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700610 msm_gpio_probe();
611 register_syscore_ops(&msm_gpio_syscore_ops);
612 return 0;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800613}
614
615static void __exit msm_gpio_exit(void)
616{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700617 unregister_syscore_ops(&msm_gpio_syscore_ops);
618 msm_gpio_remove();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800619}
620
621postcore_initcall(msm_gpio_init);
622module_exit(msm_gpio_exit);
623
Steve Mucklef132c6c2012-06-06 18:30:57 -0700624static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
625 unsigned id, unsigned width, unsigned val)
626{
627 unsigned long irqflags;
628 u32 mask = (1 << width) - 1;
629 u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
630 u32 reg_val;
631
632 spin_lock_irqsave(&tlmm_lock, irqflags);
633 reg_val = __raw_readl(reg);
634 reg_val &= ~(mask << configs[id].off);
635 reg_val |= (val & mask) << configs[id].off;
636 __raw_writel(reg_val, reg);
637 mb();
638 spin_unlock_irqrestore(&tlmm_lock, irqflags);
639}
640
641void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
642{
643 msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
644}
645EXPORT_SYMBOL(msm_tlmm_set_hdrive);
646
647void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
648{
649 msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
650}
651EXPORT_SYMBOL(msm_tlmm_set_pull);
652
653int gpio_tlmm_config(unsigned config, unsigned disable)
654{
655 uint32_t flags;
656 unsigned gpio = GPIO_PIN(config);
657
658 if (gpio > NR_MSM_GPIOS)
659 return -EINVAL;
660
661 flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
662 ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
663 ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
664 ((GPIO_PULL(config) & 0x3));
665 __raw_writel(flags, GPIO_CONFIG(gpio));
666 mb();
667
668 return 0;
669}
670EXPORT_SYMBOL(gpio_tlmm_config);
671
672int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
673 unsigned int input_polarity)
674{
675 unsigned long irq_flags;
676 uint32_t bits;
677
678 if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
679 return -EINVAL;
680
681 spin_lock_irqsave(&tlmm_lock, irq_flags);
682
683 __raw_writel(__raw_readl(GPIO_CONFIG(gpio)) | BIT(GPIO_OE_BIT),
684 GPIO_CONFIG(gpio));
685 __raw_writel(__raw_readl(GPIO_INTR_CFG(gpio)) &
686 ~(INTR_RAW_STATUS_EN | INTR_ENABLE),
687 GPIO_INTR_CFG(gpio));
688 __raw_writel(DC_IRQ_ENABLE | TARGET_PROC_NONE,
689 GPIO_INTR_CFG_SU(gpio));
690
691 bits = TARGET_PROC_SCORPION | (gpio << 3);
692 if (input_polarity)
693 bits |= DC_POLARITY_HI;
694 __raw_writel(bits, DIR_CONN_INTR_CFG_SU(irq));
695
696 mb();
697 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
698
699 return 0;
700}
701EXPORT_SYMBOL(msm_gpio_install_direct_irq);
702
703#ifdef CONFIG_OF
704static int msm_gpio_domain_dt_translate(struct irq_domain *d,
705 struct device_node *controller,
706 const u32 *intspec,
707 unsigned int intsize,
708 unsigned long *out_hwirq,
709 unsigned int *out_type)
710{
711 if (d->of_node != controller)
712 return -EINVAL;
713 if (intsize != 2)
714 return -EINVAL;
715
716 /* hwirq value */
717 *out_hwirq = intspec[0];
718
719 /* irq flags */
720 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
721 return 0;
722}
723
724static struct irq_domain_ops msm_gpio_irq_domain_ops = {
725 .dt_translate = msm_gpio_domain_dt_translate,
726};
727
728int __init msm_gpio_of_init(struct device_node *node,
729 struct device_node *parent)
730{
731 struct irq_domain *domain = &msm_gpio.domain;
732 int start;
733
734 start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
735 domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
736 numa_node_id());
737 if (IS_ERR_VALUE(domain->irq_base)) {
738 WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
739 return domain->irq_base;
740 }
741
742 domain->irq_base = irq_domain_find_free_range(0, NR_MSM_GPIOS);
743 domain->nr_irq = NR_MSM_GPIOS;
744 domain->of_node = of_node_get(node);
745 domain->priv = &msm_gpio;
746 domain->ops = &msm_gpio_irq_domain_ops;
747 irq_domain_add(domain);
748 pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
749
750 return 0;
751}
752#endif
753
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800754MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
755MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
756MODULE_LICENSE("GPL v2");
Steve Mucklef132c6c2012-06-06 18:30:57 -0700757MODULE_ALIAS("sysdev:msmgpio");