diff options
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/smu.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index f139a74696fe..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,25 +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 | smu->db_irq = irq_of_parse_and_map(np, 0); | ||
501 | |||
502 | of_node_put(np); | ||
503 | 508 | ||
504 | /* Now look for the smu-interrupt GPIO */ | 509 | /* Now look for the smu-interrupt GPIO */ |
505 | do { | 510 | do { |
506 | np = of_find_node_by_name(NULL, "smu-interrupt"); | 511 | smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt"); |
507 | if (np == NULL) | 512 | if (smu->msg_node == NULL) |
508 | break; | 513 | break; |
509 | data = (u32 *)get_property(np, "reg", NULL); | 514 | data = (u32 *)get_property(smu->msg_node, "reg", NULL); |
510 | if (data == NULL) { | 515 | if (data == NULL) { |
511 | of_node_put(np); | 516 | of_node_put(smu->msg_node); |
517 | smu->msg_node = NULL; | ||
512 | break; | 518 | break; |
513 | } | 519 | } |
514 | smu->msg = *data; | 520 | smu->msg = *data; |
515 | if (smu->msg < 0x50) | 521 | if (smu->msg < 0x50) |
516 | smu->msg += 0x50; | 522 | smu->msg += 0x50; |
517 | smu->msg_irq = irq_of_parse_and_map(np, 0); | ||
518 | of_node_put(np); | ||
519 | } while(0); | 523 | } while(0); |
520 | 524 | ||
521 | /* 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 |
@@ -547,6 +551,19 @@ static int smu_late_init(void) | |||
547 | smu->i2c_timer.function = smu_i2c_retry; | 551 | smu->i2c_timer.function = smu_i2c_retry; |
548 | smu->i2c_timer.data = (unsigned long)smu; | 552 | smu->i2c_timer.data = (unsigned long)smu; |
549 | 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 | |||
550 | /* | 567 | /* |
551 | * Try to request the interrupts | 568 | * Try to request the interrupts |
552 | */ | 569 | */ |
@@ -571,6 +588,7 @@ static int smu_late_init(void) | |||
571 | } | 588 | } |
572 | } | 589 | } |
573 | 590 | ||
591 | smu_irq_inited = 1; | ||
574 | return 0; | 592 | return 0; |
575 | } | 593 | } |
576 | /* 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 |
@@ -742,6 +760,11 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) | |||
742 | if (fail && --cmd->retries > 0) { | 760 | if (fail && --cmd->retries > 0) { |
743 | DPRINTK("SMU: i2c failure, starting timer...\n"); | 761 | DPRINTK("SMU: i2c failure, starting timer...\n"); |
744 | 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 | } | ||
745 | mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); | 768 | mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); |
746 | return; | 769 | return; |
747 | } | 770 | } |