aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl6030-irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/twl6030-irq.c')
-rw-r--r--drivers/mfd/twl6030-irq.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index c6b456ad734..b76902f1e44 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -39,6 +39,8 @@
39#include <linux/i2c/twl.h> 39#include <linux/i2c/twl.h>
40#include <linux/platform_device.h> 40#include <linux/platform_device.h>
41#include <linux/suspend.h> 41#include <linux/suspend.h>
42#include <linux/of.h>
43#include <linux/irqdomain.h>
42 44
43#include "twl-core.h" 45#include "twl-core.h"
44 46
@@ -51,8 +53,8 @@
51 * 53 *
52 * We set up IRQs starting at a platform-specified base. An interrupt map table, 54 * We set up IRQs starting at a platform-specified base. An interrupt map table,
53 * specifies mapping between interrupt number and the associated module. 55 * specifies mapping between interrupt number and the associated module.
54 *
55 */ 56 */
57#define TWL6030_NR_IRQS 20
56 58
57static int twl6030_interrupt_mapping[24] = { 59static int twl6030_interrupt_mapping[24] = {
58 PWR_INTR_OFFSET, /* Bit 0 PWRON */ 60 PWR_INTR_OFFSET, /* Bit 0 PWRON */
@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
185 } 187 }
186 local_irq_enable(); 188 local_irq_enable();
187 } 189 }
188 ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, 190
189 REG_INT_STS_A, 3); /* clear INT_STS_A */ 191 /*
192 * NOTE:
193 * Simulation confirms that documentation is wrong w.r.t the
194 * interrupt status clear operation. A single *byte* write to
195 * any one of STS_A to STS_C register results in all three
196 * STS registers being reset. Since it does not matter which
197 * value is written, all three registers are cleared on a
198 * single byte write, so we just use 0x0 to clear.
199 */
200 ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
190 if (ret) 201 if (ret)
191 pr_warning("twl6030: I2C error in clearing PIH ISR\n"); 202 pr_warning("twl6030: I2C error in clearing PIH ISR\n");
192 203
@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
227#endif 238#endif
228} 239}
229 240
230int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) 241static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
231{ 242{
232 if (on) 243 if (on)
233 atomic_inc(&twl6030_wakeirqs); 244 atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
237 return 0; 248 return 0;
238} 249}
239 250
240/*----------------------------------------------------------------------*/
241
242static unsigned twl6030_irq_next;
243
244/*----------------------------------------------------------------------*/
245int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) 251int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
246{ 252{
247 int ret; 253 int ret;
@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
311 ret); 317 ret);
312 return ret; 318 return ret;
313 } 319 }
314 return 0; 320
321 return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
315} 322}
316EXPORT_SYMBOL(twl6030_mmc_card_detect_config); 323EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
317 324
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
340} 347}
341EXPORT_SYMBOL(twl6030_mmc_card_detect); 348EXPORT_SYMBOL(twl6030_mmc_card_detect);
342 349
343int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) 350int twl6030_init_irq(struct device *dev, int irq_num)
344{ 351{
345 352 struct device_node *node = dev->of_node;
346 int status = 0; 353 int nr_irqs, irq_base, irq_end;
347 int i;
348 struct task_struct *task; 354 struct task_struct *task;
349 int ret; 355 static struct irq_chip twl6030_irq_chip;
350 u8 mask[4]; 356 int status = 0;
357 int i;
358 u8 mask[4];
359
360 nr_irqs = TWL6030_NR_IRQS;
361
362 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
363 if (IS_ERR_VALUE(irq_base)) {
364 dev_err(dev, "Fail to allocate IRQ descs\n");
365 return irq_base;
366 }
367
368 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
369 &irq_domain_simple_ops, NULL);
370
371 irq_end = irq_base + nr_irqs;
351 372
352 static struct irq_chip twl6030_irq_chip;
353 mask[1] = 0xFF; 373 mask[1] = 0xFF;
354 mask[2] = 0xFF; 374 mask[2] = 0xFF;
355 mask[3] = 0xFF; 375 mask[3] = 0xFF;
356 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 376
357 REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ 377 /* mask all int lines */
358 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 378 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
359 REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ 379 /* mask all int sts */
360 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 380 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
361 REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ 381 /* clear INT_STS_A,B,C */
382 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
362 383
363 twl6030_irq_base = irq_base; 384 twl6030_irq_base = irq_base;
364 385
365 /* install an irq handler for each of the modules; 386 /*
387 * install an irq handler for each of the modules;
366 * clone dummy irq_chip since PIH can't *do* anything 388 * clone dummy irq_chip since PIH can't *do* anything
367 */ 389 */
368 twl6030_irq_chip = dummy_irq_chip; 390 twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
377 activate_irq(i); 399 activate_irq(i);
378 } 400 }
379 401
380 twl6030_irq_next = i; 402 dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
381 pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", 403 irq_num, irq_base, irq_end);
382 irq_num, irq_base, twl6030_irq_next - 1);
383 404
384 /* install an irq handler to demultiplex the TWL6030 interrupt */ 405 /* install an irq handler to demultiplex the TWL6030 interrupt */
385 init_completion(&irq_event); 406 init_completion(&irq_event);
386 407
387 status = request_irq(irq_num, handle_twl6030_pih, 0, 408 status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
388 "TWL6030-PIH", &irq_event); 409 &irq_event);
389 if (status < 0) { 410 if (status < 0) {
390 pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); 411 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
391 goto fail_irq; 412 goto fail_irq;
392 } 413 }
393 414
394 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); 415 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
395 if (IS_ERR(task)) { 416 if (IS_ERR(task)) {
396 pr_err("twl6030: could not create irq %d thread!\n", irq_num); 417 dev_err(dev, "could not create irq %d thread!\n", irq_num);
397 status = PTR_ERR(task); 418 status = PTR_ERR(task);
398 goto fail_kthread; 419 goto fail_kthread;
399 } 420 }
400 421
401 twl_irq = irq_num; 422 twl_irq = irq_num;
402 register_pm_notifier(&twl6030_irq_pm_notifier_block); 423 register_pm_notifier(&twl6030_irq_pm_notifier_block);
403 return status; 424 return irq_base;
404 425
405fail_kthread: 426fail_kthread:
406 free_irq(irq_num, &irq_event); 427 free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@ fail_kthread:
408fail_irq: 429fail_irq:
409 for (i = irq_base; i < irq_end; i++) 430 for (i = irq_base; i < irq_end; i++)
410 irq_set_chip_and_handler(i, NULL, NULL); 431 irq_set_chip_and_handler(i, NULL, NULL);
432
411 return status; 433 return status;
412} 434}
413 435