diff options
Diffstat (limited to 'drivers/macintosh/smu.c')
-rw-r--r-- | drivers/macintosh/smu.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index f4516ca7aa3..090e40fc501 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -19,7 +19,6 @@ * the userland interface */ -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/device.h> @@ -76,9 +75,11 @@ struct smu_device { struct of_device *of_dev; int doorbell; /* doorbell gpio */ u32 __iomem *db_buf; /* doorbell buffer */ - int db_irq; + struct device_node *db_node; + unsigned int db_irq; int msg; - int msg_irq; + struct device_node *msg_node; + unsigned int msg_irq; struct smu_cmd_buf *cmd_buf; /* command buffer virtual */ u32 cmd_buf_abs; /* command buffer absolute */ struct list_head cmd_list; @@ -94,6 +95,7 @@ struct smu_device { */ static struct smu_device *smu; static DEFINE_MUTEX(smu_part_access); +static int smu_irq_inited; static void smu_i2c_retry(unsigned long data); @@ -258,6 +260,10 @@ int smu_queue_cmd(struct smu_cmd *cmd) smu_start_cmd(); spin_unlock_irqrestore(&smu->lock, flags); + /* Workaround for early calls when irq isn't available */ + if (!smu_irq_inited || smu->db_irq == NO_IRQ) + smu_spinwait_cmd(cmd); + return 0; } EXPORT_SYMBOL(smu_queue_cmd); @@ -448,7 +454,7 @@ EXPORT_SYMBOL(smu_present); int __init smu_init (void) { struct device_node *np; - u32 *data; + const u32 *data; np = of_find_node_by_type(NULL, "smu"); if (np == NULL) @@ -479,14 +485,15 @@ int __init smu_init (void) smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); - np = of_find_node_by_name(NULL, "smu-doorbell"); - if (np == NULL) { + smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); + if (smu->db_node == NULL) { printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n"); goto fail; } - data = (u32 *)get_property(np, "reg", NULL); + data = get_property(smu->db_node, "reg", NULL); if (data == NULL) { - of_node_put(np); + of_node_put(smu->db_node); + smu->db_node = NULL; printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n"); goto fail; } @@ -498,27 +505,21 @@ int __init smu_init (void) smu->doorbell = *data; if (smu->doorbell < 0x50) smu->doorbell += 0x50; - if (np->n_intrs > 0) - smu->db_irq = np->intrs[0].line; - - of_node_put(np); /* Now look for the smu-interrupt GPIO */ do { - np = of_find_node_by_name(NULL, "smu-interrupt"); - if (np == NULL) + smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt"); + if (smu->msg_node == NULL) break; - data = (u32 *)get_property(np, "reg", NULL); + data = get_property(smu->msg_node, "reg", NULL); if (data == NULL) { - of_node_put(np); + of_node_put(smu->msg_node); + smu->msg_node = NULL; break; } smu->msg = *data; if (smu->msg < 0x50) smu->msg += 0x50; - if (np->n_intrs > 0) - smu->msg_irq = np->intrs[0].line; - of_node_put(np); } while(0); /* Doorbell buffer is currently hard-coded, I didn't find a proper @@ -550,13 +551,26 @@ static int smu_late_init(void) smu->i2c_timer.function = smu_i2c_retry; smu->i2c_timer.data = (unsigned long)smu; + if (smu->db_node) { + smu->db_irq = irq_of_parse_and_map(smu->db_node, 0); + if (smu->db_irq == NO_IRQ) + printk(KERN_ERR "smu: failed to map irq for node %s\n", + smu->db_node->full_name); + } + if (smu->msg_node) { + smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0); + if (smu->msg_irq == NO_IRQ) + printk(KERN_ERR "smu: failed to map irq for node %s\n", + smu->msg_node->full_name); + } + /* * Try to request the interrupts */ if (smu->db_irq != NO_IRQ) { if (request_irq(smu->db_irq, smu_db_intr, - SA_SHIRQ, "SMU doorbell", smu) < 0) { + IRQF_SHARED, "SMU doorbell", smu) < 0) { printk(KERN_WARNING "SMU: can't " "request interrupt %d\n", smu->db_irq); @@ -566,7 +580,7 @@ static int smu_late_init(void) if (smu->msg_irq != NO_IRQ) { if (request_irq(smu->msg_irq, smu_msg_intr, - SA_SHIRQ, "SMU message", smu) < 0) { + IRQF_SHARED, "SMU message", smu) < 0) { printk(KERN_WARNING "SMU: can't " "request interrupt %d\n", smu->msg_irq); @@ -574,6 +588,7 @@ static int smu_late_init(void) } } + smu_irq_inited = 1; return 0; } /* This has to be before arch_initcall as the low i2c stuff relies on the @@ -745,6 +760,11 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) if (fail && --cmd->retries > 0) { DPRINTK("SMU: i2c failure, starting timer...\n"); BUG_ON(cmd != smu->cmd_i2c_cur); + if (!smu_irq_inited) { + mdelay(5); + smu_i2c_retry(0); + return; + } mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); return; } @@ -962,11 +982,11 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id) /* Note: Only allowed to return error code in pointers (using ERR_PTR) * when interruptible is 1 */ -struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, - int interruptible) +const struct smu_sdbp_header *__smu_get_sdb_partition(int id, + unsigned int *size, int interruptible) { char pname[32]; - struct smu_sdbp_header *part; + const struct smu_sdbp_header *part; if (!smu) return NULL; @@ -983,8 +1003,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, } else mutex_lock(&smu_part_access); - part = (struct smu_sdbp_header *)get_property(smu->of_node, - pname, size); + part = get_property(smu->of_node, pname, size); if (part == NULL) { DPRINTK("trying to extract from SMU ...\n"); part = smu_create_sdb_partition(id); @@ -995,7 +1014,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, return part; } -struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) +const struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) { return __smu_get_sdb_partition(id, size, 0); } @@ -1074,7 +1093,7 @@ static ssize_t smu_write(struct file *file, const char __user *buf, pp->mode = smu_file_events; return 0; } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) { - struct smu_sdbp_header *part; + const struct smu_sdbp_header *part; part = __smu_get_sdb_partition(hdr.cmd, NULL, 1); if (part == NULL) return -EINVAL; |