blob: 3e14333a3aa8bc4248d1594797bf9c5291ce4fc6 [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
Michael Bohan115cf652012-01-05 14:32:59 -0800187static void qpnpint_irq_mask(struct irq_data *d)
188{
189 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
190 struct q_chip_data *chip_d = irq_d->chip_d;
191 struct q_perip_data *per_d = irq_d->per_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800192 int rc;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700193 uint8_t prev_int_en = per_d->int_en;
Michael Bohan115cf652012-01-05 14:32:59 -0800194
195 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
196
Michael Bohan0435bd62013-02-26 15:29:22 -0800197 if (!chip_d->cb) {
198 pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
199 chip_d->bus_nr, irq_d->spmi_slave,
200 irq_d->spmi_offset);
201 return;
Michael Bohan115cf652012-01-05 14:32:59 -0800202 }
203
204 per_d->int_en &= ~irq_d->mask_shift;
205
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700206 if (prev_int_en && !(per_d->int_en)) {
207 /*
208 * no interrupt on this peripheral is enabled
209 * ask the arbiter to ignore this peripheral
210 */
211 qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
212 }
213
Michael Bohan115cf652012-01-05 14:32:59 -0800214 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
215 (u8 *)&irq_d->mask_shift, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800216 if (rc) {
217 pr_err_ratelimited("spmi failure on irq %d\n", d->irq);
218 return;
219 }
220
221 pr_debug("done hwirq %lu irq: %d\n", d->hwirq, d->irq);
Michael Bohan115cf652012-01-05 14:32:59 -0800222}
223
224static void qpnpint_irq_mask_ack(struct irq_data *d)
225{
226 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
227 struct q_chip_data *chip_d = irq_d->chip_d;
228 struct q_perip_data *per_d = irq_d->per_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800229 int rc;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700230 uint8_t prev_int_en = per_d->int_en;
Michael Bohan115cf652012-01-05 14:32:59 -0800231
Michael Bohan0435bd62013-02-26 15:29:22 -0800232 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
Michael Bohan115cf652012-01-05 14:32:59 -0800233
Michael Bohan0435bd62013-02-26 15:29:22 -0800234 if (!chip_d->cb) {
235 pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
236 chip_d->bus_nr, irq_d->spmi_slave,
237 irq_d->spmi_offset);
238 return;
Michael Bohan115cf652012-01-05 14:32:59 -0800239 }
240
241 per_d->int_en &= ~irq_d->mask_shift;
242
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700243 if (prev_int_en && !(per_d->int_en)) {
244 /*
245 * no interrupt on this peripheral is enabled
246 * ask the arbiter to ignore this peripheral
247 */
248 qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
249 }
250
Michael Bohan115cf652012-01-05 14:32:59 -0800251 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
252 &irq_d->mask_shift, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800253 if (rc) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700254 pr_err("spmi failure on irq %d\n", d->irq);
Michael Bohan0435bd62013-02-26 15:29:22 -0800255 return;
256 }
Michael Bohan115cf652012-01-05 14:32:59 -0800257
258 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
259 &irq_d->mask_shift, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800260 if (rc) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700261 pr_err("spmi failure on irq %d\n", d->irq);
Michael Bohan0435bd62013-02-26 15:29:22 -0800262 return;
263 }
Michael Bohan115cf652012-01-05 14:32:59 -0800264}
265
266static void qpnpint_irq_unmask(struct irq_data *d)
267{
268 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
269 struct q_chip_data *chip_d = irq_d->chip_d;
270 struct q_perip_data *per_d = irq_d->per_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800271 int rc;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700272 uint8_t prev_int_en = per_d->int_en;
Michael Bohan115cf652012-01-05 14:32:59 -0800273
274 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
275
Michael Bohan0435bd62013-02-26 15:29:22 -0800276 if (!chip_d->cb) {
277 pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
278 chip_d->bus_nr, irq_d->spmi_slave,
279 irq_d->spmi_offset);
280 return;
Michael Bohan115cf652012-01-05 14:32:59 -0800281 }
282
283 per_d->int_en |= irq_d->mask_shift;
Abhijeet Dharmapurikar546804b2013-07-24 20:15:36 -0700284 if (!prev_int_en && per_d->int_en) {
285 /*
286 * no interrupt prior to this call was enabled for the
287 * peripheral. Ask the arbiter to enable interrupts for
288 * this peripheral
289 */
290 qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
291 }
Michael Bohan115cf652012-01-05 14:32:59 -0800292 rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
293 &irq_d->mask_shift, 1);
Michael Bohan0435bd62013-02-26 15:29:22 -0800294 if (rc) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700295 pr_err("spmi failure on irq %d\n", d->irq);
Michael Bohan0435bd62013-02-26 15:29:22 -0800296 return;
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
339 return 0;
Michael Bohan115cf652012-01-05 14:32:59 -0800340}
341
Jack Pham68576912013-02-28 14:21:14 -0800342static int qpnpint_irq_read_line(struct irq_data *d)
343{
344 struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
345 int rc;
346 u8 buf;
347
348 pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
349
350 rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_RT_STS, &buf, 1);
351 if (rc) {
352 pr_err("spmi failure on irq %d\n", d->irq);
353 return rc;
354 }
355
356 return (buf & irq_d->mask_shift) ? 1 : 0;
357}
358
Michael Bohanc86e2b72012-05-29 16:57:52 -0700359static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
360{
361 return 0;
362}
363
Michael Bohan115cf652012-01-05 14:32:59 -0800364static struct irq_chip qpnpint_chip = {
365 .name = "qpnp-int",
366 .irq_mask = qpnpint_irq_mask,
367 .irq_mask_ack = qpnpint_irq_mask_ack,
368 .irq_unmask = qpnpint_irq_unmask,
369 .irq_set_type = qpnpint_irq_set_type,
Jack Pham68576912013-02-28 14:21:14 -0800370 .irq_read_line = qpnpint_irq_read_line,
Michael Bohanc86e2b72012-05-29 16:57:52 -0700371 .irq_set_wake = qpnpint_irq_set_wake,
372 .flags = IRQCHIP_MASK_ON_SUSPEND,
Michael Bohan115cf652012-01-05 14:32:59 -0800373};
374
375static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
376 struct q_irq_data *irq_d,
377 unsigned long hwirq)
378{
379 struct qpnp_irq_spec q_spec;
380 int rc;
381
382 irq_d->mask_shift = 1 << (hwirq & 0x7);
383 rc = qpnpint_decode_hwirq(hwirq, &q_spec);
384 if (rc < 0)
385 return rc;
386 irq_d->spmi_slave = q_spec.slave;
387 irq_d->spmi_offset = q_spec.per << 8;
Michael Bohan115cf652012-01-05 14:32:59 -0800388 irq_d->chip_d = chip_d;
389
Michael Bohan0435bd62013-02-26 15:29:22 -0800390 irq_d->priv_d = QPNPINT_INVALID_DATA;
391
392 if (chip_d->cb && chip_d->cb->register_priv_data) {
393 rc = chip_d->cb->register_priv_data(chip_d->spmi_ctrl, &q_spec,
Michael Bohan115cf652012-01-05 14:32:59 -0800394 &irq_d->priv_d);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700395 if (rc)
396 return rc;
Michael Bohan0435bd62013-02-26 15:29:22 -0800397 }
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700398
399 irq_d->per_d->use_count++;
400 return 0;
Michael Bohan115cf652012-01-05 14:32:59 -0800401}
402
403static struct q_irq_data *qpnpint_alloc_irq_data(
404 struct q_chip_data *chip_d,
405 unsigned long hwirq)
406{
407 struct q_irq_data *irq_d;
408 struct q_perip_data *per_d;
Michael Bohan392006f2013-01-25 14:29:41 -0800409 int rc;
Michael Bohan115cf652012-01-05 14:32:59 -0800410
411 irq_d = kzalloc(sizeof(struct q_irq_data), GFP_KERNEL);
412 if (!irq_d)
413 return ERR_PTR(-ENOMEM);
414
415 /**
416 * The Peripheral Tree is keyed from the slave + per_id. We're
417 * ignoring the irq bits here since this peripheral structure
418 * should be common for all irqs on the same peripheral.
419 */
420 per_d = radix_tree_lookup(&chip_d->per_tree, (hwirq & ~0x7));
421 if (!per_d) {
422 per_d = kzalloc(sizeof(struct q_perip_data), GFP_KERNEL);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700423 if (!per_d) {
Michael Bohan392006f2013-01-25 14:29:41 -0800424 rc = -ENOMEM;
425 goto alloc_fail;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700426 }
Michael Bohan392006f2013-01-25 14:29:41 -0800427 rc = radix_tree_preload(GFP_KERNEL);
428 if (rc)
429 goto alloc_fail;
430 rc = radix_tree_insert(&chip_d->per_tree,
Michael Bohan115cf652012-01-05 14:32:59 -0800431 (hwirq & ~0x7), per_d);
Michael Bohan392006f2013-01-25 14:29:41 -0800432 if (rc)
433 goto alloc_fail;
434 radix_tree_preload_end();
Michael Bohan115cf652012-01-05 14:32:59 -0800435 }
436 irq_d->per_d = per_d;
437
438 return irq_d;
Michael Bohan392006f2013-01-25 14:29:41 -0800439
440alloc_fail:
441 kfree(per_d);
442 kfree(irq_d);
443 return ERR_PTR(rc);
Michael Bohan115cf652012-01-05 14:32:59 -0800444}
445
Michael Bohan115cf652012-01-05 14:32:59 -0800446static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
447 struct device_node *controller,
448 const u32 *intspec, unsigned int intsize,
449 unsigned long *out_hwirq,
450 unsigned int *out_type)
451{
452 struct qpnp_irq_spec addr;
Michael Bohan115cf652012-01-05 14:32:59 -0800453 int ret;
454
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700455 pr_debug("intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
456 intspec[0], intspec[1], intspec[2]);
Michael Bohan115cf652012-01-05 14:32:59 -0800457
458 if (d->of_node != controller)
459 return -EINVAL;
460 if (intsize != 3)
461 return -EINVAL;
462
463 addr.irq = intspec[2] & 0x7;
464 addr.per = intspec[1] & 0xFF;
465 addr.slave = intspec[0] & 0xF;
466
467 ret = qpnpint_encode_hwirq(&addr);
468 if (ret < 0) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700469 pr_err("invalid intspec\n");
Michael Bohan115cf652012-01-05 14:32:59 -0800470 return ret;
471 }
472 *out_hwirq = ret;
473 *out_type = IRQ_TYPE_NONE;
474
Michael Bohan0435bd62013-02-26 15:29:22 -0800475 pr_debug("out_hwirq = %lu\n", *out_hwirq);
476
Michael Bohan115cf652012-01-05 14:32:59 -0800477 return 0;
478}
479
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700480static void qpnpint_free_irq_data(struct q_irq_data *irq_d)
481{
482 if (irq_d->per_d->use_count == 1)
483 kfree(irq_d->per_d);
484 else
485 irq_d->per_d->use_count--;
486 kfree(irq_d);
487}
488
489static int qpnpint_irq_domain_map(struct irq_domain *d,
490 unsigned int virq, irq_hw_number_t hwirq)
491{
492 struct q_chip_data *chip_d = d->host_data;
493 struct q_irq_data *irq_d;
494 int rc;
495
496 pr_debug("hwirq = %lu\n", hwirq);
497
Michael Bohan0435bd62013-02-26 15:29:22 -0800498 if (hwirq < 0 || hwirq >= QPNPINT_NR_IRQS) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700499 pr_err("hwirq %lu out of bounds\n", hwirq);
500 return -EINVAL;
501 }
502
503 irq_radix_revmap_insert(d, virq, hwirq);
504
505 irq_d = qpnpint_alloc_irq_data(chip_d, hwirq);
506 if (IS_ERR(irq_d)) {
507 pr_err("failed to alloc irq data for hwirq %lu\n", hwirq);
508 return PTR_ERR(irq_d);
509 }
510
511 rc = qpnpint_init_irq_data(chip_d, irq_d, hwirq);
512 if (rc) {
513 pr_err("failed to init irq data for hwirq %lu\n", hwirq);
514 goto map_err;
515 }
516
517 irq_set_chip_and_handler(virq,
518 &qpnpint_chip,
519 handle_level_irq);
520 irq_set_chip_data(virq, irq_d);
521#ifdef CONFIG_ARM
522 set_irq_flags(virq, IRQF_VALID);
523#else
524 irq_set_noprobe(virq);
525#endif
526 return 0;
527
528map_err:
529 qpnpint_free_irq_data(irq_d);
530 return rc;
531}
532
533void qpnpint_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
534{
535 struct q_irq_data *irq_d = irq_get_chip_data(virq);
536
537 if (WARN_ON(!irq_d))
538 return;
539
540 qpnpint_free_irq_data(irq_d);
541}
542
Michael Bohan115cf652012-01-05 14:32:59 -0800543const struct irq_domain_ops qpnpint_irq_domain_ops = {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700544 .map = qpnpint_irq_domain_map,
545 .unmap = qpnpint_irq_domain_unmap,
546 .xlate = qpnpint_irq_domain_dt_translate,
Michael Bohan115cf652012-01-05 14:32:59 -0800547};
548
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700549int qpnpint_register_controller(struct device_node *node,
550 struct spmi_controller *ctrl,
Michael Bohan115cf652012-01-05 14:32:59 -0800551 struct qpnp_local_int *li_cb)
552{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700553 struct q_chip_data *chip_d;
Michael Bohan115cf652012-01-05 14:32:59 -0800554
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700555 if (!node || !ctrl || ctrl->nr >= QPNPINT_MAX_BUSSES)
556 return -EINVAL;
557
558 list_for_each_entry(chip_d, &qpnpint_chips, list)
559 if (node == chip_d->domain->of_node) {
Michael Bohan0435bd62013-02-26 15:29:22 -0800560 chip_d->cb = kmemdup(li_cb,
561 sizeof(*li_cb), GFP_ATOMIC);
562 if (!chip_d->cb)
563 return -ENOMEM;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700564 chip_d->spmi_ctrl = ctrl;
565 chip_lookup[ctrl->nr] = chip_d;
566 return 0;
567 }
568
569 return -ENOENT;
Michael Bohan115cf652012-01-05 14:32:59 -0800570}
571EXPORT_SYMBOL(qpnpint_register_controller);
572
Michael Bohan0435bd62013-02-26 15:29:22 -0800573int qpnpint_unregister_controller(struct device_node *node)
574{
575 struct q_chip_data *chip_d;
576
577 if (!node)
578 return -EINVAL;
579
580 list_for_each_entry(chip_d, &qpnpint_chips, list)
581 if (node == chip_d->domain->of_node) {
582 kfree(chip_d->cb);
583 chip_d->cb = NULL;
584 if (chip_d->spmi_ctrl)
585 chip_lookup[chip_d->spmi_ctrl->nr] = NULL;
586 chip_d->spmi_ctrl = NULL;
587 return 0;
588 }
589
590 return -ENOENT;
591}
592EXPORT_SYMBOL(qpnpint_unregister_controller);
593
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700594static int __qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
595 struct qpnp_irq_spec *spec,
596 bool show)
Michael Bohan115cf652012-01-05 14:32:59 -0800597{
598 struct irq_domain *domain;
599 unsigned long hwirq, busno;
600 int irq;
601
Zhenhua Huang30acf242013-07-11 01:52:36 +0800602 if (!spec || !spmi_ctrl)
603 return -EINVAL;
604
Michael Bohan115cf652012-01-05 14:32:59 -0800605 pr_debug("spec slave = %u per = %u irq = %u\n",
606 spec->slave, spec->per, spec->irq);
607
Michael Bohan115cf652012-01-05 14:32:59 -0800608 busno = spmi_ctrl->nr;
Zhenhua Huang30acf242013-07-11 01:52:36 +0800609 if (busno >= QPNPINT_MAX_BUSSES)
Michael Bohan115cf652012-01-05 14:32:59 -0800610 return -EINVAL;
611
612 hwirq = qpnpint_encode_hwirq(spec);
613 if (hwirq < 0) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700614 pr_err("invalid irq spec passed\n");
Michael Bohan115cf652012-01-05 14:32:59 -0800615 return -EINVAL;
616 }
617
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700618 domain = chip_lookup[busno]->domain;
619 irq = irq_radix_revmap_lookup(domain, hwirq);
Michael Bohan115cf652012-01-05 14:32:59 -0800620
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700621 if (show) {
622 struct irq_desc *desc;
623 const char *name = "null";
624
625 desc = irq_to_desc(irq);
626 if (desc == NULL)
627 name = "stray irq";
628 else if (desc->action && desc->action->name)
629 name = desc->action->name;
630
631 pr_warn("%d triggered [0x%01x, 0x%02x,0x%01x] %s\n",
632 irq, spec->slave, spec->per, spec->irq, name);
633 } else {
634 generic_handle_irq(irq);
635 }
Michael Bohan115cf652012-01-05 14:32:59 -0800636
637 return 0;
638}
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700639
640int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
641 struct qpnp_irq_spec *spec)
642{
643 return __qpnpint_handle_irq(spmi_ctrl, spec, false);
644}
645
Michael Bohan115cf652012-01-05 14:32:59 -0800646EXPORT_SYMBOL(qpnpint_handle_irq);
647
Abhijeet Dharmapurikared34f4b2013-08-09 18:44:13 -0700648int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
649 struct qpnp_irq_spec *spec)
650{
651 return __qpnpint_handle_irq(spmi_ctrl, spec, true);
652}
653EXPORT_SYMBOL(qpnpint_show_irq);
654
Michael Bohan115cf652012-01-05 14:32:59 -0800655int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
656{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700657 struct q_chip_data *chip_d;
658
659 chip_d = kzalloc(sizeof(struct q_chip_data), GFP_KERNEL);
660 if (!chip_d)
661 return -ENOMEM;
662
663 chip_d->domain = irq_domain_add_tree(node,
664 &qpnpint_irq_domain_ops, chip_d);
665 if (!chip_d->domain) {
666 pr_err("Unable to allocate irq_domain\n");
667 kfree(chip_d);
668 return -ENOMEM;
669 }
Michael Bohan115cf652012-01-05 14:32:59 -0800670
671 INIT_RADIX_TREE(&chip_d->per_tree, GFP_ATOMIC);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700672 list_add(&chip_d->list, &qpnpint_chips);
Michael Bohan115cf652012-01-05 14:32:59 -0800673
674 return 0;
675}
676EXPORT_SYMBOL(qpnpint_of_init);