diff options
Diffstat (limited to 'drivers/mfd/twl6030-irq.c')
-rw-r--r-- | drivers/mfd/twl6030-irq.c | 86 |
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 | ||
57 | static int twl6030_interrupt_mapping[24] = { | 59 | static 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 | ||
230 | int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) | 241 | static 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 | |||
242 | static unsigned twl6030_irq_next; | ||
243 | |||
244 | /*----------------------------------------------------------------------*/ | ||
245 | int twl6030_interrupt_unmask(u8 bit_mask, u8 offset) | 251 | int 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 | } |
316 | EXPORT_SYMBOL(twl6030_mmc_card_detect_config); | 323 | EXPORT_SYMBOL(twl6030_mmc_card_detect_config); |
317 | 324 | ||
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) | |||
340 | } | 347 | } |
341 | EXPORT_SYMBOL(twl6030_mmc_card_detect); | 348 | EXPORT_SYMBOL(twl6030_mmc_card_detect); |
342 | 349 | ||
343 | int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | 350 | int 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 | ||
405 | fail_kthread: | 426 | fail_kthread: |
406 | free_irq(irq_num, &irq_event); | 427 | free_irq(irq_num, &irq_event); |
@@ -408,6 +429,7 @@ fail_kthread: | |||
408 | fail_irq: | 429 | fail_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 | ||