blob: 4e21a86ed9be84cc65b86fc34433aea54e778dd0 [file] [log] [blame]
Michael Bohan5c943ff2012-01-17 09:51:50 -08001/* 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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/syscore_ops.h>
Michael Bohan5c943ff2012-01-17 09:51:50 -080023#include <linux/irqdomain.h>
24#include <linux/of.h>
Will Deacon03dd7652011-02-21 14:54:57 +000025
26#include <asm/mach/irq.h>
27
Gregory Bean0cc2fc12010-11-24 11:53:51 -080028#include <mach/msm_iomap.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070029#include <mach/gpiomux.h>
Subhash Jadavani909e04f2012-04-12 10:52:50 +053030#include <mach/mpm.h>
Gregory Bean0cc2fc12010-11-24 11:53:51 -080031
32/* Bits of interest in the GPIO_IN_OUT register.
33 */
34enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035 GPIO_IN_BIT = 0,
36 GPIO_OUT_BIT = 1
Gregory Bean70cc2c02010-11-24 11:53:52 -080037};
38
39/* Bits of interest in the GPIO_INTR_STATUS register.
40 */
41enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042 INTR_STATUS_BIT = 0,
Gregory Bean0cc2fc12010-11-24 11:53:51 -080043};
44
45/* Bits of interest in the GPIO_CFG register.
46 */
47enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048 GPIO_OE_BIT = 9,
Gregory Bean0cc2fc12010-11-24 11:53:51 -080049};
50
Gregory Bean70cc2c02010-11-24 11:53:52 -080051/* Bits of interest in the GPIO_INTR_CFG register.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052 */
53enum {
54 INTR_ENABLE_BIT = 0,
55 INTR_POL_CTL_BIT = 1,
56 INTR_DECT_CTL_BIT = 2,
57 INTR_RAW_STATUS_EN_BIT = 3,
58};
59
60/* Codes of interest in GPIO_INTR_CFG_SU.
61 */
62enum {
63 TARGET_PROC_SCORPION = 4,
64 TARGET_PROC_NONE = 7,
65};
66
67/*
68 * There is no 'DC_POLARITY_LO' because the GIC is incapable
69 * of asserting on falling edge or level-low conditions. Even though
70 * the registers allow for low-polarity inputs, the case can never arise.
71 */
72enum {
73 DC_POLARITY_HI = BIT(11),
74 DC_IRQ_ENABLE = BIT(3),
75};
76
77enum msm_tlmm_register {
78 SDC4_HDRV_PULL_CTL = 0x20a0,
79 SDC3_HDRV_PULL_CTL = 0x20a4,
80 SDC1_HDRV_PULL_CTL = 0x20a0,
81};
82
83struct tlmm_field_cfg {
84 enum msm_tlmm_register reg;
85 u8 off;
86};
87
88static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
89 {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
90 {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
91 {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
92 {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
93 {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
94 {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
95 {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
96 {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
97 {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
98};
99
100static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
101 {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
102 {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
103 {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
104 {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
105 {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
106 {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
107 {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
108 {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
109};
110
111/*
112 * Supported arch specific irq extension.
113 * Default make them NULL.
114 */
115struct irq_chip msm_gpio_irq_extn = {
116 .irq_eoi = NULL,
117 .irq_mask = NULL,
118 .irq_unmask = NULL,
119 .irq_retrigger = NULL,
120 .irq_set_type = NULL,
121 .irq_set_wake = NULL,
122 .irq_disable = NULL,
123};
124
125/*
Gregory Bean70cc2c02010-11-24 11:53:52 -0800126 * When a GPIO triggers, two separate decisions are made, controlled
127 * by two separate flags.
128 *
129 * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
130 * register for that GPIO will be updated to reflect the triggering of that
131 * gpio. If this bit is 0, this register will not be updated.
132 * - Second, INTR_ENABLE controls whether an interrupt is triggered.
133 *
134 * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
135 * can be triggered but the status register will not reflect it.
136 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137#define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
138#define INTR_ENABLE BIT(INTR_ENABLE_BIT)
139#define INTR_DECT_CTL_EDGE BIT(INTR_DECT_CTL_BIT)
140#define INTR_POL_CTL_HI BIT(INTR_POL_CTL_BIT)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800141
142#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143#define DIR_CONN_INTR_CFG_SU(irq) (MSM_TLMM_BASE + 0x0700 + (0x04 * (irq)))
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800144#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
145#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
Gregory Bean70cc2c02010-11-24 11:53:52 -0800146#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
147#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
148
149/**
150 * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
151 *
152 * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
153 * keeping track of which gpios are unmasked as irq sources, we avoid
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 * having to do __raw_readl calls on hundreds of iomapped registers each time
Gregory Bean70cc2c02010-11-24 11:53:52 -0800155 * the summary interrupt fires in order to locate the active interrupts.
156 *
157 * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
158 * as wakeup sources. When the device is suspended, interrupts which are
159 * not wakeup sources are disabled.
160 *
161 * @dual_edge_irqs: a bitmap used to track which irqs are configured
162 * as dual-edge, as this is not supported by the hardware and requires
163 * some special handling in the driver.
164 */
165struct msm_gpio_dev {
166 struct gpio_chip gpio_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167 DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
168 DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
169 DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
Michael Bohan5c943ff2012-01-17 09:51:50 -0800170 struct irq_domain domain;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800171};
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800172
173static DEFINE_SPINLOCK(tlmm_lock);
174
Gregory Bean70cc2c02010-11-24 11:53:52 -0800175static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
176{
177 return container_of(chip, struct msm_gpio_dev, gpio_chip);
178}
179
180static inline void set_gpio_bits(unsigned n, void __iomem *reg)
181{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 __raw_writel(__raw_readl(reg) | n, reg);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800183}
184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800186{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 __raw_writel(__raw_readl(reg) & ~n, reg);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800188}
189
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800190static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
191{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 int rc;
193 rc = __raw_readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
194 mb();
195 return rc;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800196}
197
198static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
199{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
201 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800202}
203
204static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
205{
206 unsigned long irq_flags;
207
208 spin_lock_irqsave(&tlmm_lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
210 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800211 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
212 return 0;
213}
214
215static int msm_gpio_direction_output(struct gpio_chip *chip,
216 unsigned offset,
217 int val)
218{
219 unsigned long irq_flags;
220
221 spin_lock_irqsave(&tlmm_lock, irq_flags);
222 msm_gpio_set(chip, offset, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
224 mb();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800225 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
226 return 0;
227}
228
Michael Bohan5c943ff2012-01-17 09:51:50 -0800229#ifdef CONFIG_OF
230static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
231{
232 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
233 struct irq_domain *domain = &g_dev->domain;
234 return domain->irq_base + (offset - chip->base);
235}
236
237static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
238{
239 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
240 struct irq_domain *domain = &g_dev->domain;
241 return irq - domain->irq_base;
242}
243#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
245{
246 return MSM_GPIO_TO_INT(offset - chip->base);
247}
248
249static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
250{
251 return irq - MSM_GPIO_TO_INT(chip->base);
252}
Michael Bohan5c943ff2012-01-17 09:51:50 -0800253#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800255static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
256{
257 return msm_gpiomux_get(chip->base + offset);
258}
259
260static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
261{
262 msm_gpiomux_put(chip->base + offset);
263}
264
Gregory Bean70cc2c02010-11-24 11:53:52 -0800265static struct msm_gpio_dev msm_gpio = {
266 .gpio_chip = {
Michael Bohanfedb2432011-10-07 16:11:38 -0700267 .label = "msmgpio",
Gregory Bean70cc2c02010-11-24 11:53:52 -0800268 .base = 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 .ngpio = NR_MSM_GPIOS,
Gregory Bean70cc2c02010-11-24 11:53:52 -0800270 .direction_input = msm_gpio_direction_input,
271 .direction_output = msm_gpio_direction_output,
272 .get = msm_gpio_get,
273 .set = msm_gpio_set,
274 .to_irq = msm_gpio_to_irq,
275 .request = msm_gpio_request,
276 .free = msm_gpio_free,
277 },
278};
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280static void switch_mpm_config(struct irq_data *d, unsigned val)
281{
282 /* switch the configuration in the mpm as well */
283 if (!msm_gpio_irq_extn.irq_set_type)
284 return;
285
286 if (val)
287 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
288 else
289 msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
290}
291
Gregory Bean70cc2c02010-11-24 11:53:52 -0800292/* For dual-edge interrupts in software, since the hardware has no
293 * such support:
294 *
295 * At appropriate moments, this function may be called to flip the polarity
296 * settings of both-edge irq lines to try and catch the next edge.
297 *
298 * The attempt is considered successful if:
299 * - the status bit goes high, indicating that an edge was caught, or
300 * - the input value of the gpio doesn't change during the attempt.
301 * If the value changes twice during the process, that would cause the first
302 * test to fail but would force the second, as two opposite
303 * transitions would cause a detection no matter the polarity setting.
304 *
305 * The do-loop tries to sledge-hammer closed the timing hole between
306 * the initial value-read and the polarity-write - if the line value changes
307 * during that window, an interrupt is lost, the new polarity setting is
308 * incorrect, and the first success test will fail, causing a retry.
309 *
310 * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
311 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800313{
314 int loop_limit = 100;
315 unsigned val, val2, intstat;
316
317 do {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 val = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800319 if (val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800321 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
323 val2 = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
324 intstat = __raw_readl(GPIO_INTR_STATUS(gpio)) &
325 BIT(INTR_STATUS_BIT);
326 if (intstat || val == val2) {
327 switch_mpm_config(d, val);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800328 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 }
Gregory Bean70cc2c02010-11-24 11:53:52 -0800330 } while (loop_limit-- > 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 pr_err("%s: dual-edge irq failed to stabilize, "
Gregory Bean70cc2c02010-11-24 11:53:52 -0800332 "interrupts dropped. %#08x != %#08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 __func__, val, val2);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800334}
335
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100336static void msm_gpio_irq_ack(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800337{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100338 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 __raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800341 if (test_bit(gpio, msm_gpio.dual_edge_irqs))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 msm_gpio_update_dual_edge_pos(d, gpio);
343 mb();
344}
345
346static void __msm_gpio_irq_mask(unsigned int gpio)
347{
348 __raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
349 clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800350}
351
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100352static void msm_gpio_irq_mask(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800353{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100354 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800355 unsigned long irq_flags;
356
357 spin_lock_irqsave(&tlmm_lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 __msm_gpio_irq_mask(gpio);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800359 __clear_bit(gpio, msm_gpio.enabled_irqs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800361 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 if (msm_gpio_irq_extn.irq_mask)
364 msm_gpio_irq_extn.irq_mask(d);
365
366}
367
368static void __msm_gpio_irq_unmask(unsigned int gpio)
369{
370 set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
371 __raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800372}
373
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100374static void msm_gpio_irq_unmask(struct irq_data *d)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800375{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100376 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800377 unsigned long irq_flags;
378
379 spin_lock_irqsave(&tlmm_lock, irq_flags);
380 __set_bit(gpio, msm_gpio.enabled_irqs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 __msm_gpio_irq_unmask(gpio);
382 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800383 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384
385 if (msm_gpio_irq_extn.irq_mask)
386 msm_gpio_irq_extn.irq_unmask(d);
387}
388
389static void msm_gpio_irq_disable(struct irq_data *d)
390{
391 if (msm_gpio_irq_extn.irq_disable)
392 msm_gpio_irq_extn.irq_disable(d);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800393}
394
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100395static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800396{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100397 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800398 unsigned long irq_flags;
399 uint32_t bits;
400
401 spin_lock_irqsave(&tlmm_lock, irq_flags);
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 bits = __raw_readl(GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800404
405 if (flow_type & IRQ_TYPE_EDGE_BOTH) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 bits |= INTR_DECT_CTL_EDGE;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100407 __irq_set_handler_locked(d->irq, handle_edge_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800408 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
409 __set_bit(gpio, msm_gpio.dual_edge_irqs);
410 else
411 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
412 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 bits &= ~INTR_DECT_CTL_EDGE;
Thomas Gleixner70c4fa22011-03-24 12:41:27 +0100414 __irq_set_handler_locked(d->irq, handle_level_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800415 __clear_bit(gpio, msm_gpio.dual_edge_irqs);
416 }
417
418 if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 bits |= INTR_POL_CTL_HI;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800420 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 bits &= ~INTR_POL_CTL_HI;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 __raw_writel(bits, GPIO_INTR_CFG(gpio));
Gregory Bean70cc2c02010-11-24 11:53:52 -0800424
425 if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 msm_gpio_update_dual_edge_pos(d, gpio);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 mb();
Gregory Bean70cc2c02010-11-24 11:53:52 -0800429 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431 if (msm_gpio_irq_extn.irq_set_type)
432 msm_gpio_irq_extn.irq_set_type(d, flow_type);
433
Gregory Bean70cc2c02010-11-24 11:53:52 -0800434 return 0;
435}
436
437/*
438 * When the summary IRQ is raised, any number of GPIO lines may be high.
439 * It is the job of the summary handler to find all those GPIO lines
440 * which have been set as summary IRQ lines and which are triggered,
441 * and to call their interrupt handlers.
442 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443static irqreturn_t msm_summary_irq_handler(int irq, void *data)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800444{
445 unsigned long i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 struct irq_desc *desc = irq_to_desc(irq);
Will Deacon03dd7652011-02-21 14:54:57 +0000447 struct irq_chip *chip = irq_desc_get_chip(desc);
448
449 chained_irq_enter(chip, desc);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
452 i < NR_MSM_GPIOS;
453 i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
454 if (__raw_readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS_BIT))
Gregory Bean70cc2c02010-11-24 11:53:52 -0800455 generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
456 i));
457 }
Will Deacon03dd7652011-02-21 14:54:57 +0000458
459 chained_irq_exit(chip, desc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 return IRQ_HANDLED;
Gregory Bean70cc2c02010-11-24 11:53:52 -0800461}
462
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100463static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Gregory Bean70cc2c02010-11-24 11:53:52 -0800464{
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100465 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800466
467 if (on) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
469 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800470 set_bit(gpio, msm_gpio.wake_irqs);
471 } else {
472 clear_bit(gpio, msm_gpio.wake_irqs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
474 irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800475 }
476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 if (msm_gpio_irq_extn.irq_set_wake)
478 msm_gpio_irq_extn.irq_set_wake(d, on);
479
Gregory Bean70cc2c02010-11-24 11:53:52 -0800480 return 0;
481}
482
483static struct irq_chip msm_gpio_irq_chip = {
484 .name = "msmgpio",
Thomas Gleixnercf8d1582011-03-24 11:58:31 +0100485 .irq_mask = msm_gpio_irq_mask,
486 .irq_unmask = msm_gpio_irq_unmask,
487 .irq_ack = msm_gpio_irq_ack,
488 .irq_set_type = msm_gpio_irq_set_type,
489 .irq_set_wake = msm_gpio_irq_set_wake,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 .irq_disable = msm_gpio_irq_disable,
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800491};
492
Stephen Boydbce344d2012-04-18 15:57:00 -0700493/*
494 * This lock class tells lockdep that GPIO irqs are in a different
495 * category than their parents, so it won't report false recursion.
496 */
497static struct lock_class_key msm_gpio_lock_class;
498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499static int __devinit msm_gpio_probe(void)
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800500{
Gregory Bean70cc2c02010-11-24 11:53:52 -0800501 int i, irq, ret;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 spin_lock_init(&tlmm_lock);
504 bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
505 bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
506 bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800507 ret = gpiochip_add(&msm_gpio.gpio_chip);
508 if (ret < 0)
509 return ret;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800510
Gregory Bean70cc2c02010-11-24 11:53:52 -0800511 for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
512 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
Stephen Boydbce344d2012-04-18 15:57:00 -0700513 irq_set_lockdep_class(irq, &msm_gpio_lock_class);
Thomas Gleixnerf38c02f2011-03-24 13:35:09 +0100514 irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
515 handle_level_irq);
Gregory Bean70cc2c02010-11-24 11:53:52 -0800516 set_irq_flags(irq, IRQF_VALID);
517 }
518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519 ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
520 IRQF_TRIGGER_HIGH, "msmgpio", NULL);
521 if (ret) {
522 pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
523 ret);
524 return ret;
525 }
Gregory Bean70cc2c02010-11-24 11:53:52 -0800526 return 0;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800527}
528
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529static int __devexit msm_gpio_remove(void)
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800530{
Gregory Bean70cc2c02010-11-24 11:53:52 -0800531 int ret = gpiochip_remove(&msm_gpio.gpio_chip);
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800532
533 if (ret < 0)
534 return ret;
535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536 irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800537
538 return 0;
539}
540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541#ifdef CONFIG_PM
542static int msm_gpio_suspend(void)
543{
544 unsigned long irq_flags;
545 unsigned long i;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 spin_lock_irqsave(&tlmm_lock, irq_flags);
548 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
549 __msm_gpio_irq_mask(i);
550
551 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
552 __msm_gpio_irq_unmask(i);
553 mb();
554 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
555 return 0;
556}
557
558extern int msm_show_resume_irq_mask;
559
560void msm_gpio_show_resume_irq(void)
561{
562 unsigned long irq_flags;
563 int i, irq, intstat;
564
565 if (!msm_show_resume_irq_mask)
566 return;
567
568 spin_lock_irqsave(&tlmm_lock, irq_flags);
569 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
570 intstat = __raw_readl(GPIO_INTR_STATUS(i)) &
571 BIT(INTR_STATUS_BIT);
572 if (intstat) {
573 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
574 pr_warning("%s: %d triggered\n",
575 __func__, irq);
576 }
577 }
578 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
579}
580
581static void msm_gpio_resume(void)
582{
583 unsigned long irq_flags;
584 unsigned long i;
585
586 msm_gpio_show_resume_irq();
587
588 spin_lock_irqsave(&tlmm_lock, irq_flags);
589 for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
590 __msm_gpio_irq_mask(i);
591
592 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
593 __msm_gpio_irq_unmask(i);
594 mb();
595 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
596}
597#else
598#define msm_gpio_suspend NULL
599#define msm_gpio_resume NULL
600#endif
601
602static struct syscore_ops msm_gpio_syscore_ops = {
603 .suspend = msm_gpio_suspend,
604 .resume = msm_gpio_resume,
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800605};
606
607static int __init msm_gpio_init(void)
608{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 msm_gpio_probe();
610 register_syscore_ops(&msm_gpio_syscore_ops);
611 return 0;
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800612}
613
614static void __exit msm_gpio_exit(void)
615{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 unregister_syscore_ops(&msm_gpio_syscore_ops);
617 msm_gpio_remove();
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800618}
619
620postcore_initcall(msm_gpio_init);
621module_exit(msm_gpio_exit);
622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
624 unsigned id, unsigned width, unsigned val)
625{
626 unsigned long irqflags;
627 u32 mask = (1 << width) - 1;
628 u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
629 u32 reg_val;
630
631 spin_lock_irqsave(&tlmm_lock, irqflags);
632 reg_val = __raw_readl(reg);
633 reg_val &= ~(mask << configs[id].off);
634 reg_val |= (val & mask) << configs[id].off;
635 __raw_writel(reg_val, reg);
636 mb();
637 spin_unlock_irqrestore(&tlmm_lock, irqflags);
638}
639
640void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
641{
642 msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
643}
644EXPORT_SYMBOL(msm_tlmm_set_hdrive);
645
646void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
647{
648 msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
649}
650EXPORT_SYMBOL(msm_tlmm_set_pull);
651
652int gpio_tlmm_config(unsigned config, unsigned disable)
653{
654 uint32_t flags;
655 unsigned gpio = GPIO_PIN(config);
656
657 if (gpio > NR_MSM_GPIOS)
658 return -EINVAL;
659
660 flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
661 ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
662 ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
663 ((GPIO_PULL(config) & 0x3));
664 __raw_writel(flags, GPIO_CONFIG(gpio));
665 mb();
666
667 return 0;
668}
669EXPORT_SYMBOL(gpio_tlmm_config);
670
671int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
672 unsigned int input_polarity)
673{
674 unsigned long irq_flags;
675 uint32_t bits;
676
677 if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
678 return -EINVAL;
679
680 spin_lock_irqsave(&tlmm_lock, irq_flags);
681
682 __raw_writel(__raw_readl(GPIO_CONFIG(gpio)) | BIT(GPIO_OE_BIT),
683 GPIO_CONFIG(gpio));
684 __raw_writel(__raw_readl(GPIO_INTR_CFG(gpio)) &
685 ~(INTR_RAW_STATUS_EN | INTR_ENABLE),
686 GPIO_INTR_CFG(gpio));
687 __raw_writel(DC_IRQ_ENABLE | TARGET_PROC_NONE,
688 GPIO_INTR_CFG_SU(gpio));
689
690 bits = TARGET_PROC_SCORPION | (gpio << 3);
691 if (input_polarity)
692 bits |= DC_POLARITY_HI;
693 __raw_writel(bits, DIR_CONN_INTR_CFG_SU(irq));
694
695 mb();
696 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
697
698 return 0;
699}
700EXPORT_SYMBOL(msm_gpio_install_direct_irq);
701
Michael Bohan5c943ff2012-01-17 09:51:50 -0800702#ifdef CONFIG_OF
703static int msm_gpio_domain_dt_translate(struct irq_domain *d,
704 struct device_node *controller,
705 const u32 *intspec,
706 unsigned int intsize,
707 unsigned long *out_hwirq,
708 unsigned int *out_type)
709{
710 if (d->of_node != controller)
711 return -EINVAL;
712 if (intsize != 2)
713 return -EINVAL;
714
715 /* hwirq value */
716 *out_hwirq = intspec[0];
717
718 /* irq flags */
719 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
720 return 0;
721}
722
723static struct irq_domain_ops msm_gpio_irq_domain_ops = {
724 .dt_translate = msm_gpio_domain_dt_translate,
725};
726
727int __init msm_gpio_of_init(struct device_node *node,
728 struct device_node *parent)
729{
730 struct irq_domain *domain = &msm_gpio.domain;
731
732 domain->irq_base = irq_domain_find_free_range(0, NR_MSM_GPIOS);
733 domain->nr_irq = NR_MSM_GPIOS;
734 domain->of_node = of_node_get(node);
735 domain->priv = &msm_gpio;
736 domain->ops = &msm_gpio_irq_domain_ops;
737 irq_domain_add(domain);
738 pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
739
740 return 0;
741}
742#endif
743
Gregory Bean0cc2fc12010-11-24 11:53:51 -0800744MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
745MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
746MODULE_LICENSE("GPL v2");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747MODULE_ALIAS("sysdev:msmgpio");