blob: 9fc729949c2b25ab549bbc0c8e38bcc4a4a3a1b2 [file] [log] [blame]
Michael Bohan0435bd62013-02-26 15:29:22 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Michael Bohan115cf652012-01-05 14:32:59 -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 */
12
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/list.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/of_irq.h>
23#include <linux/irqdomain.h>
24#include <linux/interrupt.h>
25#include <linux/spmi.h>
26#include <linux/radix-tree.h>
27#include <linux/slab.h>
28#include <linux/printk.h>
Michael Bohan0435bd62013-02-26 15:29:22 -080029#include <linux/ratelimit.h>
Michael Bohan115cf652012-01-05 14:32:59 -080030
31#include <asm/irq.h>
32#include <asm/mach/irq.h>
33#include <mach/qpnp-int.h>
34
Michael Bohan115cf652012-01-05 14:32:59 -080035/* 16 slave_ids, 256 per_ids per slave, and 8 ints per per_id */
Michael Bohan0435bd62013-02-26 15:29:22 -080036#define QPNPINT_NR_IRQS (16 * 256 * 8)
37/* This value is guaranteed not to be valid for private data */
38#define QPNPINT_INVALID_DATA 0x80000000
Michael Bohan115cf652012-01-05 14:32:59 -080039
40enum qpnpint_regs {
41 QPNPINT_REG_RT_STS = 0x10,
42 QPNPINT_REG_SET_TYPE = 0x11,
43 QPNPINT_REG_POLARITY_HIGH = 0x12,
44 QPNPINT_REG_POLARITY_LOW = 0x13,
45 QPNPINT_REG_LATCHED_CLR = 0x14,
46 QPNPINT_REG_EN_SET = 0x15,
47 QPNPINT_REG_EN_CLR = 0x16,
48 QPNPINT_REG_LATCHED_STS = 0x18,
49};
50
51struct q_perip_data {
52 uint8_t type; /* bitmap */
53 uint8_t pol_high; /* bitmap */
54 uint8_t pol_low; /* bitmap */
55 uint8_t int_en; /* bitmap */
56 uint8_t use_count;
57};
58
59struct q_irq_data {
60 uint32_t priv_d; /* data to optimize arbiter interactions */
61 struct q_chip_data *chip_d;
62 struct q_perip_data *per_d;
63 uint8_t mask_shift;
64 uint8_t spmi_slave;
65 uint16_t spmi_offset;
66};
67
68struct q_chip_data {
69 int bus_nr;
Michael Bohanbb6b30f2012-06-01 13:33:51 -070070 struct irq_domain *domain;
Michael Bohan0435bd62013-02-26 15:29:22 -080071 struct qpnp_local_int *cb;
Michael Bohan115cf652012-01-05 14:32:59 -080072 struct spmi_controller *spmi_ctrl;
73 struct radix_tree_root per_tree;
Michael Bohanbb6b30f2012-06-01 13:33:51 -070074 struct list_head list;
Michael Bohan115cf652012-01-05 14:32:59 -080075};
76
Michael Bohanbb6b30f2012-06-01 13:33:51 -070077static LIST_HEAD(qpnpint_chips);
78static DEFINE_MUTEX(qpnpint_chips_mutex);
79
80#define QPNPINT_MAX_BUSSES 4
81struct q_chip_data *chip_lookup[QPNPINT_MAX_BUSSES];
Michael Bohan115cf652012-01-05 14:32:59 -080082
83/**
84 * qpnpint_encode_hwirq - translate between qpnp_irq_spec and
85 * hwirq representation.
86 *
87 * slave_offset = (addr->slave * 256 * 8);
88 * perip_offset = slave_offset + (addr->perip * 8);
89 * return perip_offset + addr->irq;
90 */
91static inline int qpnpint_encode_hwirq(struct qpnp_irq_spec *spec)
92{
93 uint32_t hwirq;
94
95 if (spec->slave > 15 || spec->irq > 7)
96 return -EINVAL;
97
98 hwirq = (spec->slave << 11);
99 hwirq |= (spec->per << 3);
100 hwirq |= spec->irq;
101
102 return hwirq;
103}
104/**
105 * qpnpint_decode_hwirq - translate between hwirq and
106 * qpnp_irq_spec representation.
107 */
108static inline int qpnpint_decode_hwirq(unsigned long hwirq,
109 struct qpnp_irq_spec *spec)
110{
111 if (hwirq > 65535)
112 return -EINVAL;
113
114 spec->slave = (hwirq >> 11) & 0xF;
115 spec->per = (hwirq >> 3) & 0xFF;
116 spec->irq = hwirq & 0x7;
117 return 0;
118}
119
Jack Pham68576912013-02-28 14:21:14 -0800120static int qpnpint_spmi_read(struct q_irq_data *irq_d, uint8_t reg,
121 void *buf, uint32_t len)
122{
123 struct q_chip_data *chip_d = irq_d->chip_d;
124
125 if (!chip_d->spmi_ctrl)
126 return -ENODEV;
127
128 return spmi_ext_register_readl(chip_d->spmi_ctrl, irq_d->spmi_slave,
129 irq_d->spmi_offset + reg, buf, len);
130}
131
Michael Bohan115cf652012-01-05 14:32:59 -0800132static int qpnpint_spmi_write(struct q_irq_data *irq_d, uint8_t reg,
133 void *buf, uint32_t len)
134{
135 struct q_chip_data *chip_d = irq_d->chip_d;
136 int rc;
137
138 if (!chip_d->spmi_ctrl)
139 return -ENODEV;
140
141 rc = spmi_ext_register_writel(chip_d->spmi_ctrl, irq_d->spmi_slave,
142 irq_d->spmi_offset + reg, buf, len);
143 return rc;
144}
145
Michael Bohan0435bd62013-02-26 15:29:22 -0800146static int qpnpint_arbiter_op(struct irq_data *d,
147 struct q_irq_data *irq_d,
148 int (*arb_op)(struct spmi_controller *,
149 struct qpnp_irq_spec *,
150 uint32_t))
151
152{
153 struct q_chip_data *chip_d = irq_d->chip_d;
154 struct qpnp_irq_spec q_spec;
155 int rc;
156
157 if (!arb_op)
158 return 0;
159
160 if (!chip_d->cb->register_priv_data) {
161 pr_warn_ratelimited("No ability to register arbiter registration data\n");
162 return -ENODEV;
163 }
164
165 rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
166 if (rc) {
167 pr_err_ratelimited("%s: decode failed on hwirq %lu\n",
168 __func__, d->hwirq);
169 return rc;
Michael Bohan0435bd62013-02-26 15:29:22 -0800170 }
171
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700172 if (irq_d->priv_d == QPNPINT_INVALID_DATA) {
173 rc = chip_d->cb->register_priv_data(chip_d->spmi_ctrl,
174 &q_spec, &irq_d->priv_d);
175 if (rc) {
176 pr_err_ratelimited(
177 "%s: decode failed on hwirq %lu rc = %d\n",
178 __func__, d->hwirq, rc);
179 return rc;
180 }
181 }
182 arb_op(chip_d->spmi_ctrl, &q_spec, irq_d->priv_d);
183
Michael Bohan0435bd62013-02-26 15:29:22 -0800184 return 0;
185}
186
David Collinsaefd38a2013-11-26 14:28:27 -0800187static void qpnpint_irq_ack(struct irq_data *d)
188{
189 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
190 int rc;
191
192 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
193
194 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
195 &irq_d->mask_shift, 1);
196 if (rc) {
197 pr_err_ratelimited("spmi write failure on irq %d, rc=%d\n",
198 d->irq, rc);
199 return;
200 }
201}
202
Michael Bohan115cf652012-01-05 14:32:59 -0800203static void qpnpint_irq_mask(struct irq_data *d)
204{
205 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
206 struct q_chip_data *chip_d = irq_d->chip_d;
207 struct q_perip_data *per_d = irq_d->per_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800208 int rc;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700209 uint8_t prev_int_en = per_d->int_en;
Michael Bohan115cf652012-01-05 14:32:59 -0800210
211 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
212
Michael Bohan0435bd62013-02-26 15:29:22 -0800213 if (!chip_d->cb) {
214 pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
215 chip_d->bus_nr, irq_d->spmi_slave,
216 irq_d->spmi_offset);
217 return;
Michael Bohan115cf652012-01-05 14:32:59 -0800218 }
219
220 per_d->int_en &= ~irq_d->mask_shift;
221
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700222 if (prev_int_en && !(per_d->int_en)) {
223 /*
224 * no interrupt on this peripheral is enabled
225 * ask the arbiter to ignore this peripheral
226 */
227 qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
228 }
229
Michael Bohan115cf652012-01-05 14:32:59 -0800230 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
231 (u8 *)&irq_d->mask_shift, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800232 if (rc) {
233 pr_err_ratelimited("spmi failure on irq %d\n", d->irq);
234 return;
235 }
236
237 pr_debug("done hwirq %lu irq: %d\n", d->hwirq, d->irq);
Michael Bohan115cf652012-01-05 14:32:59 -0800238}
239
240static void qpnpint_irq_mask_ack(struct irq_data *d)
241{
Michael Bohan0435bd62013-02-26 15:29:22 -0800242 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
Michael Bohan115cf652012-01-05 14:32:59 -0800243
David Collinsaefd38a2013-11-26 14:28:27 -0800244 qpnpint_irq_mask(d);
245 qpnpint_irq_ack(d);
Michael Bohan115cf652012-01-05 14:32:59 -0800246}
247
248static void qpnpint_irq_unmask(struct irq_data *d)
249{
250 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
251 struct q_chip_data *chip_d = irq_d->chip_d;
252 struct q_perip_data *per_d = irq_d->per_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800253 int rc;
David Collinsb2446772013-11-05 09:31:16 -0800254 uint8_t buf[2];
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700255 uint8_t prev_int_en = per_d->int_en;
Michael Bohan115cf652012-01-05 14:32:59 -0800256
257 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
258
Michael Bohan0435bd62013-02-26 15:29:22 -0800259 if (!chip_d->cb) {
260 pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
261 chip_d->bus_nr, irq_d->spmi_slave,
262 irq_d->spmi_offset);
263 return;
Michael Bohan115cf652012-01-05 14:32:59 -0800264 }
265
266 per_d->int_en |= irq_d->mask_shift;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700267 if (!prev_int_en && per_d->int_en) {
268 /*
269 * no interrupt prior to this call was enabled for the
270 * peripheral. Ask the arbiter to enable interrupts for
271 * this peripheral
272 */
273 qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
274 }
David Collinsb2446772013-11-05 09:31:16 -0800275
276 /* Check the current state of the interrupt enable bit. */
277 rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_EN_SET, buf, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800278 if (rc) {
David Collinsb2446772013-11-05 09:31:16 -0800279 pr_err("SPMI read failure for IRQ %d, rc=%d\n", d->irq, rc);
Michael Bohan0435bd62013-02-26 15:29:22 -0800280 return;
281 }
David Collinsb2446772013-11-05 09:31:16 -0800282
283 if (!(buf[0] & irq_d->mask_shift)) {
284 /*
285 * Since the interrupt is currently disabled, write to both the
286 * LATCHED_CLR and EN_SET registers so that a spurious interrupt
287 * cannot be triggered when the interrupt is enabled.
288 */
289 buf[0] = irq_d->mask_shift;
290 buf[1] = irq_d->mask_shift;
291 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR, buf, 2);
292 if (rc) {
293 pr_err("SPMI write failure for IRQ %d, rc=%d\n", d->irq,
294 rc);
295 return;
296 }
297 }
Michael Bohan115cf652012-01-05 14:32:59 -0800298}
299
300static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
301{
302 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
303 struct q_perip_data *per_d = irq_d->per_d;
304 int rc;
305 u8 buf[3];
306
307 pr_debug("hwirq %lu irq: %d flow: 0x%x\n", d->hwirq,
308 d->irq, flow_type);
309
310 per_d->pol_high &= ~irq_d->mask_shift;
311 per_d->pol_low &= ~irq_d->mask_shift;
312 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
313 per_d->type |= irq_d->mask_shift; /* edge trig */
314 if (flow_type & IRQF_TRIGGER_RISING)
315 per_d->pol_high |= irq_d->mask_shift;
316 if (flow_type & IRQF_TRIGGER_FALLING)
317 per_d->pol_low |= irq_d->mask_shift;
318 } else {
319 if ((flow_type & IRQF_TRIGGER_HIGH) &&
320 (flow_type & IRQF_TRIGGER_LOW))
321 return -EINVAL;
322 per_d->type &= ~irq_d->mask_shift; /* level trig */
323 if (flow_type & IRQF_TRIGGER_HIGH)
324 per_d->pol_high |= irq_d->mask_shift;
325 else
Michael Bohan69701d32012-06-07 17:05:41 -0700326 per_d->pol_low |= irq_d->mask_shift;
Michael Bohan115cf652012-01-05 14:32:59 -0800327 }
328
329 buf[0] = per_d->type;
330 buf[1] = per_d->pol_high;
331 buf[2] = per_d->pol_low;
332
333 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_SET_TYPE, &buf, 3);
Michael Bohan0435bd62013-02-26 15:29:22 -0800334 if (rc) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700335 pr_err("spmi failure on irq %d\n", d->irq);
Michael Bohan0435bd62013-02-26 15:29:22 -0800336 return rc;
337 }
338
Abhijeet Dharmapurikarcdbc60b2013-11-25 11:34:10 -0800339 if (flow_type & IRQ_TYPE_EDGE_BOTH)
340 __irq_set_handler_locked(d->irq, handle_edge_irq);
341 else
342 __irq_set_handler_locked(d->irq, handle_level_irq);
343
Michael Bohan0435bd62013-02-26 15:29:22 -0800344 return 0;
Michael Bohan115cf652012-01-05 14:32:59 -0800345}
346
Jack Pham68576912013-02-28 14:21:14 -0800347static int qpnpint_irq_read_line(struct irq_data *d)
348{
349 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
350 int rc;
351 u8 buf;
352
353 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
354
355 rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_RT_STS, &buf, 1);
356 if (rc) {
357 pr_err("spmi failure on irq %d\n", d->irq);
358 return rc;
359 }
360
361 return (buf & irq_d->mask_shift) ? 1 : 0;
362}
363
Michael Bohanc86e2b72012-05-29 16:57:52 -0700364static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
365{
366 return 0;
367}
368
Michael Bohan115cf652012-01-05 14:32:59 -0800369static struct irq_chip qpnpint_chip = {
370 .name = "qpnp-int",
David Collinsaefd38a2013-11-26 14:28:27 -0800371 .irq_ack = qpnpint_irq_ack,
Michael Bohan115cf652012-01-05 14:32:59 -0800372 .irq_mask = qpnpint_irq_mask,
373 .irq_mask_ack = qpnpint_irq_mask_ack,
374 .irq_unmask = qpnpint_irq_unmask,
375 .irq_set_type = qpnpint_irq_set_type,
Jack Pham68576912013-02-28 14:21:14 -0800376 .irq_read_line = qpnpint_irq_read_line,
Michael Bohanc86e2b72012-05-29 16:57:52 -0700377 .irq_set_wake = qpnpint_irq_set_wake,
378 .flags = IRQCHIP_MASK_ON_SUSPEND,
Michael Bohan115cf652012-01-05 14:32:59 -0800379};
380
381static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
382 struct q_irq_data *irq_d,
383 unsigned long hwirq)
384{
385 struct qpnp_irq_spec q_spec;
386 int rc;
387
388 irq_d->mask_shift = 1 << (hwirq & 0x7);
389 rc = qpnpint_decode_hwirq(hwirq, &q_spec);
390 if (rc < 0)
391 return rc;
392 irq_d->spmi_slave = q_spec.slave;
393 irq_d->spmi_offset = q_spec.per << 8;
Michael Bohan115cf652012-01-05 14:32:59 -0800394 irq_d->chip_d = chip_d;
395
Michael Bohan0435bd62013-02-26 15:29:22 -0800396 irq_d->priv_d = QPNPINT_INVALID_DATA;
397
398 if (chip_d->cb && chip_d->cb->register_priv_data) {
399 rc = chip_d->cb->register_priv_data(chip_d->spmi_ctrl, &q_spec,
Michael Bohan115cf652012-01-05 14:32:59 -0800400 &irq_d->priv_d);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700401 if (rc)
402 return rc;
Michael Bohan0435bd62013-02-26 15:29:22 -0800403 }
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700404
405 irq_d->per_d->use_count++;
406 return 0;
Michael Bohan115cf652012-01-05 14:32:59 -0800407}
408
409static struct q_irq_data *qpnpint_alloc_irq_data(
410 struct q_chip_data *chip_d,
411 unsigned long hwirq)
412{
413 struct q_irq_data *irq_d;
414 struct q_perip_data *per_d;
Michael Bohan392006f2013-01-25 14:29:41 -0800415 int rc;
Michael Bohan115cf652012-01-05 14:32:59 -0800416
417 irq_d = kzalloc(sizeof(struct q_irq_data), GFP_KERNEL);
418 if (!irq_d)
419 return ERR_PTR(-ENOMEM);
420
421 /**
422 * The Peripheral Tree is keyed from the slave + per_id. We're
423 * ignoring the irq bits here since this peripheral structure
424 * should be common for all irqs on the same peripheral.
425 */
426 per_d = radix_tree_lookup(&chip_d->per_tree, (hwirq & ~0x7));
427 if (!per_d) {
428 per_d = kzalloc(sizeof(struct q_perip_data), GFP_KERNEL);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700429 if (!per_d) {
Michael Bohan392006f2013-01-25 14:29:41 -0800430 rc = -ENOMEM;
431 goto alloc_fail;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700432 }
Michael Bohan392006f2013-01-25 14:29:41 -0800433 rc = radix_tree_preload(GFP_KERNEL);
434 if (rc)
435 goto alloc_fail;
436 rc = radix_tree_insert(&chip_d->per_tree,
Michael Bohan115cf652012-01-05 14:32:59 -0800437 (hwirq & ~0x7), per_d);
Michael Bohan392006f2013-01-25 14:29:41 -0800438 if (rc)
439 goto alloc_fail;
440 radix_tree_preload_end();
Michael Bohan115cf652012-01-05 14:32:59 -0800441 }
442 irq_d->per_d = per_d;
443
444 return irq_d;
Michael Bohan392006f2013-01-25 14:29:41 -0800445
446alloc_fail:
447 kfree(per_d);
448 kfree(irq_d);
449 return ERR_PTR(rc);
Michael Bohan115cf652012-01-05 14:32:59 -0800450}
451
Michael Bohan115cf652012-01-05 14:32:59 -0800452static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
453 struct device_node *controller,
454 const u32 *intspec, unsigned int intsize,
455 unsigned long *out_hwirq,
456 unsigned int *out_type)
457{
458 struct qpnp_irq_spec addr;
Michael Bohan115cf652012-01-05 14:32:59 -0800459 int ret;
460
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700461 pr_debug("intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
462 intspec[0], intspec[1], intspec[2]);
Michael Bohan115cf652012-01-05 14:32:59 -0800463
464 if (d->of_node != controller)
465 return -EINVAL;
466 if (intsize != 3)
467 return -EINVAL;
468
469 addr.irq = intspec[2] & 0x7;
470 addr.per = intspec[1] & 0xFF;
471 addr.slave = intspec[0] & 0xF;
472
473 ret = qpnpint_encode_hwirq(&addr);
474 if (ret < 0) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700475 pr_err("invalid intspec\n");
Michael Bohan115cf652012-01-05 14:32:59 -0800476 return ret;
477 }
478 *out_hwirq = ret;
479 *out_type = IRQ_TYPE_NONE;
480
Michael Bohan0435bd62013-02-26 15:29:22 -0800481 pr_debug("out_hwirq = %lu\n", *out_hwirq);
482
Michael Bohan115cf652012-01-05 14:32:59 -0800483 return 0;
484}
485
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700486static void qpnpint_free_irq_data(struct q_irq_data *irq_d)
487{
488 if (irq_d->per_d->use_count == 1)
489 kfree(irq_d->per_d);
490 else
491 irq_d->per_d->use_count--;
492 kfree(irq_d);
493}
494
495static int qpnpint_irq_domain_map(struct irq_domain *d,
496 unsigned int virq, irq_hw_number_t hwirq)
497{
498 struct q_chip_data *chip_d = d->host_data;
499 struct q_irq_data *irq_d;
500 int rc;
501
502 pr_debug("hwirq = %lu\n", hwirq);
503
Michael Bohan0435bd62013-02-26 15:29:22 -0800504 if (hwirq < 0 || hwirq >= QPNPINT_NR_IRQS) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700505 pr_err("hwirq %lu out of bounds\n", hwirq);
506 return -EINVAL;
507 }
508
509 irq_radix_revmap_insert(d, virq, hwirq);
510
511 irq_d = qpnpint_alloc_irq_data(chip_d, hwirq);
512 if (IS_ERR(irq_d)) {
513 pr_err("failed to alloc irq data for hwirq %lu\n", hwirq);
514 return PTR_ERR(irq_d);
515 }
516
517 rc = qpnpint_init_irq_data(chip_d, irq_d, hwirq);
518 if (rc) {
519 pr_err("failed to init irq data for hwirq %lu\n", hwirq);
520 goto map_err;
521 }
522
523 irq_set_chip_and_handler(virq,
524 &qpnpint_chip,
525 handle_level_irq);
526 irq_set_chip_data(virq, irq_d);
527#ifdef CONFIG_ARM
528 set_irq_flags(virq, IRQF_VALID);
529#else
530 irq_set_noprobe(virq);
531#endif
532 return 0;
533
534map_err:
535 qpnpint_free_irq_data(irq_d);
536 return rc;
537}
538
539void qpnpint_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
540{
541 struct q_irq_data *irq_d = irq_get_chip_data(virq);
542
543 if (WARN_ON(!irq_d))
544 return;
545
546 qpnpint_free_irq_data(irq_d);
547}
548
Michael Bohan115cf652012-01-05 14:32:59 -0800549const struct irq_domain_ops qpnpint_irq_domain_ops = {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700550 .map = qpnpint_irq_domain_map,
551 .unmap = qpnpint_irq_domain_unmap,
552 .xlate = qpnpint_irq_domain_dt_translate,
Michael Bohan115cf652012-01-05 14:32:59 -0800553};
554
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700555int qpnpint_register_controller(struct device_node *node,
556 struct spmi_controller *ctrl,
Michael Bohan115cf652012-01-05 14:32:59 -0800557 struct qpnp_local_int *li_cb)
558{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700559 struct q_chip_data *chip_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800560
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700561 if (!node || !ctrl || ctrl->nr >= QPNPINT_MAX_BUSSES)
562 return -EINVAL;
563
564 list_for_each_entry(chip_d, &qpnpint_chips, list)
565 if (node == chip_d->domain->of_node) {
Michael Bohan0435bd62013-02-26 15:29:22 -0800566 chip_d->cb = kmemdup(li_cb,
567 sizeof(*li_cb), GFP_ATOMIC);
568 if (!chip_d->cb)
569 return -ENOMEM;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700570 chip_d->spmi_ctrl = ctrl;
571 chip_lookup[ctrl->nr] = chip_d;
572 return 0;
573 }
574
575 return -ENOENT;
Michael Bohan115cf652012-01-05 14:32:59 -0800576}
577EXPORT_SYMBOL(qpnpint_register_controller);
578
Michael Bohan0435bd62013-02-26 15:29:22 -0800579int qpnpint_unregister_controller(struct device_node *node)
580{
581 struct q_chip_data *chip_d;
582
583 if (!node)
584 return -EINVAL;
585
586 list_for_each_entry(chip_d, &qpnpint_chips, list)
587 if (node == chip_d->domain->of_node) {
588 kfree(chip_d->cb);
589 chip_d->cb = NULL;
590 if (chip_d->spmi_ctrl)
591 chip_lookup[chip_d->spmi_ctrl->nr] = NULL;
592 chip_d->spmi_ctrl = NULL;
593 return 0;
594 }
595
596 return -ENOENT;
597}
598EXPORT_SYMBOL(qpnpint_unregister_controller);
599
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700600static int __qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
601 struct qpnp_irq_spec *spec,
602 bool show)
Michael Bohan115cf652012-01-05 14:32:59 -0800603{
604 struct irq_domain *domain;
605 unsigned long hwirq, busno;
606 int irq;
607
Zhenhua Huang30acf242013-07-11 01:52:36 +0800608 if (!spec || !spmi_ctrl)
609 return -EINVAL;
610
Michael Bohan115cf652012-01-05 14:32:59 -0800611 pr_debug("spec slave = %u per = %u irq = %u\n",
612 spec->slave, spec->per, spec->irq);
613
Michael Bohan115cf652012-01-05 14:32:59 -0800614 busno = spmi_ctrl->nr;
Zhenhua Huang30acf242013-07-11 01:52:36 +0800615 if (busno >= QPNPINT_MAX_BUSSES)
Michael Bohan115cf652012-01-05 14:32:59 -0800616 return -EINVAL;
617
618 hwirq = qpnpint_encode_hwirq(spec);
619 if (hwirq < 0) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700620 pr_err("invalid irq spec passed\n");
Michael Bohan115cf652012-01-05 14:32:59 -0800621 return -EINVAL;
622 }
623
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700624 domain = chip_lookup[busno]->domain;
625 irq = irq_radix_revmap_lookup(domain, hwirq);
Michael Bohan115cf652012-01-05 14:32:59 -0800626
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700627 if (show) {
628 struct irq_desc *desc;
629 const char *name = "null";
630
631 desc = irq_to_desc(irq);
632 if (desc == NULL)
633 name = "stray irq";
634 else if (desc->action && desc->action->name)
635 name = desc->action->name;
636
637 pr_warn("%d triggered [0x%01x, 0x%02x,0x%01x] %s\n",
638 irq, spec->slave, spec->per, spec->irq, name);
639 } else {
640 generic_handle_irq(irq);
641 }
Michael Bohan115cf652012-01-05 14:32:59 -0800642
643 return 0;
644}
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700645
646int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
647 struct qpnp_irq_spec *spec)
648{
649 return __qpnpint_handle_irq(spmi_ctrl, spec, false);
650}
651
Michael Bohan115cf652012-01-05 14:32:59 -0800652EXPORT_SYMBOL(qpnpint_handle_irq);
653
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700654int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
655 struct qpnp_irq_spec *spec)
656{
657 return __qpnpint_handle_irq(spmi_ctrl, spec, true);
658}
659EXPORT_SYMBOL(qpnpint_show_irq);
660
Michael Bohan115cf652012-01-05 14:32:59 -0800661int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
662{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700663 struct q_chip_data *chip_d;
664
665 chip_d = kzalloc(sizeof(struct q_chip_data), GFP_KERNEL);
666 if (!chip_d)
667 return -ENOMEM;
668
669 chip_d->domain = irq_domain_add_tree(node,
670 &qpnpint_irq_domain_ops, chip_d);
671 if (!chip_d->domain) {
672 pr_err("Unable to allocate irq_domain\n");
673 kfree(chip_d);
674 return -ENOMEM;
675 }
Michael Bohan115cf652012-01-05 14:32:59 -0800676
677 INIT_RADIX_TREE(&chip_d->per_tree, GFP_ATOMIC);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700678 list_add(&chip_d->list, &qpnpint_chips);
Michael Bohan115cf652012-01-05 14:32:59 -0800679
680 return 0;
681}
682EXPORT_SYMBOL(qpnpint_of_init);