diff options
Diffstat (limited to 'drivers/macintosh/smu.c')
-rw-r--r-- | drivers/macintosh/smu.c | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index ff6d9bfdc3d2..00ef46898147 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c | |||
@@ -75,9 +75,11 @@ struct smu_device { | |||
75 | struct of_device *of_dev; | 75 | struct of_device *of_dev; |
76 | int doorbell; /* doorbell gpio */ | 76 | int doorbell; /* doorbell gpio */ |
77 | u32 __iomem *db_buf; /* doorbell buffer */ | 77 | u32 __iomem *db_buf; /* doorbell buffer */ |
78 | int db_irq; | 78 | struct device_node *db_node; |
79 | unsigned int db_irq; | ||
79 | int msg; | 80 | int msg; |
80 | int msg_irq; | 81 | struct device_node *msg_node; |
82 | unsigned int msg_irq; | ||
81 | struct smu_cmd_buf *cmd_buf; /* command buffer virtual */ | 83 | struct smu_cmd_buf *cmd_buf; /* command buffer virtual */ |
82 | u32 cmd_buf_abs; /* command buffer absolute */ | 84 | u32 cmd_buf_abs; /* command buffer absolute */ |
83 | struct list_head cmd_list; | 85 | struct list_head cmd_list; |
@@ -93,6 +95,7 @@ struct smu_device { | |||
93 | */ | 95 | */ |
94 | static struct smu_device *smu; | 96 | static struct smu_device *smu; |
95 | static DEFINE_MUTEX(smu_part_access); | 97 | static DEFINE_MUTEX(smu_part_access); |
98 | static int smu_irq_inited; | ||
96 | 99 | ||
97 | static void smu_i2c_retry(unsigned long data); | 100 | static void smu_i2c_retry(unsigned long data); |
98 | 101 | ||
@@ -257,6 +260,10 @@ int smu_queue_cmd(struct smu_cmd *cmd) | |||
257 | smu_start_cmd(); | 260 | smu_start_cmd(); |
258 | spin_unlock_irqrestore(&smu->lock, flags); | 261 | spin_unlock_irqrestore(&smu->lock, flags); |
259 | 262 | ||
263 | /* Workaround for early calls when irq isn't available */ | ||
264 | if (!smu_irq_inited || smu->db_irq == NO_IRQ) | ||
265 | smu_spinwait_cmd(cmd); | ||
266 | |||
260 | return 0; | 267 | return 0; |
261 | } | 268 | } |
262 | EXPORT_SYMBOL(smu_queue_cmd); | 269 | EXPORT_SYMBOL(smu_queue_cmd); |
@@ -478,14 +485,15 @@ int __init smu_init (void) | |||
478 | smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; | 485 | smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; |
479 | smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); | 486 | smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); |
480 | 487 | ||
481 | np = of_find_node_by_name(NULL, "smu-doorbell"); | 488 | smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); |
482 | if (np == NULL) { | 489 | if (smu->db_node == NULL) { |
483 | printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n"); | 490 | printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n"); |
484 | goto fail; | 491 | goto fail; |
485 | } | 492 | } |
486 | data = (u32 *)get_property(np, "reg", NULL); | 493 | data = (u32 *)get_property(smu->db_node, "reg", NULL); |
487 | if (data == NULL) { | 494 | if (data == NULL) { |
488 | of_node_put(np); | 495 | of_node_put(smu->db_node); |
496 | smu->db_node = NULL; | ||
489 | printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n"); | 497 | printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n"); |
490 | goto fail; | 498 | goto fail; |
491 | } | 499 | } |
@@ -497,27 +505,21 @@ int __init smu_init (void) | |||
497 | smu->doorbell = *data; | 505 | smu->doorbell = *data; |
498 | if (smu->doorbell < 0x50) | 506 | if (smu->doorbell < 0x50) |
499 | smu->doorbell += 0x50; | 507 | smu->doorbell += 0x50; |
500 | if (np->n_intrs > 0) | ||
501 | smu->db_irq = np->intrs[0].line; | ||
502 | |||
503 | of_node_put(np); | ||
504 | 508 | ||
505 | /* Now look for the smu-interrupt GPIO */ | 509 | /* Now look for the smu-interrupt GPIO */ |
506 | do { | 510 | do { |
507 | np = of_find_node_by_name(NULL, "smu-interrupt"); | 511 | smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt"); |
508 | if (np == NULL) | 512 | if (smu->msg_node == NULL) |
509 | break; | 513 | break; |
510 | data = (u32 *)get_property(np, "reg", NULL); | 514 | data = (u32 *)get_property(smu->msg_node, "reg", NULL); |
511 | if (data == NULL) { | 515 | if (data == NULL) { |
512 | of_node_put(np); | 516 | of_node_put(smu->msg_node); |
517 | smu->msg_node = NULL; | ||
513 | break; | 518 | break; |
514 | } | 519 | } |
515 | smu->msg = *data; | 520 | smu->msg = *data; |
516 | if (smu->msg < 0x50) | 521 | if (smu->msg < 0x50) |
517 | smu->msg += 0x50; | 522 | smu->msg += 0x50; |
518 | if (np->n_intrs > 0) | ||
519 | smu->msg_irq = np->intrs[0].line; | ||
520 | of_node_put(np); | ||
521 | } while(0); | 523 | } while(0); |
522 | 524 | ||
523 | /* Doorbell buffer is currently hard-coded, I didn't find a proper | 525 | /* Doorbell buffer is currently hard-coded, I didn't find a proper |
@@ -549,6 +551,19 @@ static int smu_late_init(void) | |||
549 | smu->i2c_timer.function = smu_i2c_retry; | 551 | smu->i2c_timer.function = smu_i2c_retry; |
550 | smu->i2c_timer.data = (unsigned long)smu; | 552 | smu->i2c_timer.data = (unsigned long)smu; |
551 | 553 | ||
554 | if (smu->db_node) { | ||
555 | smu->db_irq = irq_of_parse_and_map(smu->db_node, 0); | ||
556 | if (smu->db_irq == NO_IRQ) | ||
557 | printk(KERN_ERR "smu: failed to map irq for node %s\n", | ||
558 | smu->db_node->full_name); | ||
559 | } | ||
560 | if (smu->msg_node) { | ||
561 | smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0); | ||
562 | if (smu->msg_irq == NO_IRQ) | ||
563 | printk(KERN_ERR "smu: failed to map irq for node %s\n", | ||
564 | smu->msg_node->full_name); | ||
565 | } | ||
566 | |||
552 | /* | 567 | /* |
553 | * Try to request the interrupts | 568 | * Try to request the interrupts |
554 | */ | 569 | */ |
@@ -573,6 +588,7 @@ static int smu_late_init(void) | |||
573 | } | 588 | } |
574 | } | 589 | } |
575 | 590 | ||
591 | smu_irq_inited = 1; | ||
576 | return 0; | 592 | return 0; |
577 | } | 593 | } |
578 | /* This has to be before arch_initcall as the low i2c stuff relies on the | 594 | /* This has to be before arch_initcall as the low i2c stuff relies on the |
@@ -744,6 +760,11 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) | |||
744 | if (fail && --cmd->retries > 0) { | 760 | if (fail && --cmd->retries > 0) { |
745 | DPRINTK("SMU: i2c failure, starting timer...\n"); | 761 | DPRINTK("SMU: i2c failure, starting timer...\n"); |
746 | BUG_ON(cmd != smu->cmd_i2c_cur); | 762 | BUG_ON(cmd != smu->cmd_i2c_cur); |
763 | if (!smu_irq_inited) { | ||
764 | mdelay(5); | ||
765 | smu_i2c_retry(0); | ||
766 | return; | ||
767 | } | ||
747 | mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); | 768 | mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); |
748 | return; | 769 | return; |
749 | } | 770 | } |