X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmacintosh%2Fvia-pmu.c;h=ebec663d5d3708d74a8197ddfe16e7e761e71c87;hb=76c072b48e39e9291fbf02d6c912cf27d65e093d;hp=bb9f4044c74deaf0cae595581e3f6cb574bfbcdf;hpb=b16eeb47292597a8bf3ad53fdaf1f727f57bd8e4;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index bb9f404..ebec663 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -10,18 +10,14 @@ * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. * Copyright (C) 2001-2002 Benjamin Herrenschmidt + * Copyright (C) 2006-2007 Johannes Berg * * THIS DRIVER IS BECOMING A TOTAL MESS ! * - Cleanup atomically disabling reply to PMU events after * a sleep or a freq. switch - * - Move sleep code out of here to pmac_pm, merge into new - * common PM infrastructure - * - Move backlight code out as well - * - Save/Restore PCI space properly * */ #include -#include #include #include #include @@ -35,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -44,8 +39,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -55,18 +51,18 @@ #include #include #include +#include +#include #include #include #include #include -#ifdef CONFIG_PMAC_BACKLIGHT #include -#endif + +#include "via-pmu-event.h" /* Some compile options */ -#undef SUSPEND_USES_PMU -#define DEBUG_SLEEP -#undef HACKED_PCI_SAVE +#undef DEBUG_SLEEP /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -138,23 +134,22 @@ static int data_index; static int data_len; static volatile int adb_int_pending; static volatile int disable_poll; -static struct adb_request bright_req_1, bright_req_2; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; -static int pmu_fully_inited = 0; +static int pmu_fully_inited; static int pmu_has_adb; -static unsigned char __iomem *gpio_reg = NULL; -static int gpio_irq = -1; +static struct device_node *gpio_node; +static unsigned char __iomem *gpio_reg; +static int gpio_irq = NO_IRQ; static int gpio_irq_enabled = -1; -static volatile int pmu_suspended = 0; +static volatile int pmu_suspended; static spinlock_t pmu_lock; static u8 pmu_intr_mask; static int pmu_version; static int drop_interrupts; -#ifdef CONFIG_PMAC_PBOOK +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) static int option_lid_wakeup = 1; -static int sleep_in_progress; -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ static unsigned long async_req_locks; static unsigned int pmu_irq_stats[11]; @@ -164,26 +159,19 @@ static struct proc_dir_entry *proc_pmu_irqstats; static struct proc_dir_entry *proc_pmu_options; static int option_server_mode; -#ifdef CONFIG_PMAC_PBOOK int pmu_battery_count; int pmu_cur_battery; -unsigned int pmu_power_flags; +unsigned int pmu_power_flags = PMU_PWR_AC_PRESENT; struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; static int query_batt_timer = BATTERY_POLLING_COUNT; static struct adb_request batt_req; static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; -#endif /* CONFIG_PMAC_PBOOK */ - -#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) -extern int disable_kernel_backlight; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ int __fake_sleep; int asleep; -struct notifier_block *sleep_notifier_list; #ifdef CONFIG_ADB -static int adb_dev_map = 0; +static int adb_dev_map; static int pmu_adb_flags; static int pmu_probe(void); @@ -194,23 +182,16 @@ static int pmu_adb_reset_bus(void); #endif /* CONFIG_ADB */ static int init_pmu(void); -static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); -static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); -static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static irqreturn_t via_pmu_interrupt(int irq, void *arg); +static irqreturn_t gpio1_interrupt(int irq, void *arg); static int proc_get_info(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_get_irqstats(char *page, char **start, off_t off, int count, int *eof, void *data); -#ifdef CONFIG_PMAC_BACKLIGHT -static int pmu_set_backlight_level(int level, void* data); -static int pmu_set_backlight_enable(int on, int level, void* data); -#endif /* CONFIG_PMAC_BACKLIGHT */ -#ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); static int proc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data); -#endif /* CONFIG_PMAC_PBOOK */ static int proc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_write_options(struct file *file, const char __user *buffer, @@ -234,7 +215,7 @@ extern void enable_kernel_fp(void); #ifdef DEBUG_SLEEP int pmu_polled_request(struct adb_request *req); -int pmu_wink(struct adb_request *req); +void pmu_blink(int n); #endif /* @@ -244,7 +225,7 @@ int pmu_wink(struct adb_request *req); * - the number of response bytes which the PMU will return, or * -1 if it will send a length byte. */ -static const s8 pmu_data_len[256][2] __openfirmwaredata = { +static const s8 pmu_data_len[256][2] = { /* 0 1 2 3 4 5 6 7 */ /*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, @@ -288,29 +269,26 @@ static char *pbook_type[] = { "Core99" }; -#ifdef CONFIG_PMAC_BACKLIGHT -static struct backlight_controller pmu_backlight_controller = { - pmu_set_backlight_enable, - pmu_set_backlight_level -}; -#endif /* CONFIG_PMAC_BACKLIGHT */ - -int __openfirmware -find_via_pmu(void) +int __init find_via_pmu(void) { + u64 taddr; + const u32 *reg; + if (via != 0) return 1; - vias = find_devices("via-pmu"); - if (vias == 0) + vias = of_find_node_by_name(NULL, "via-pmu"); + if (vias == NULL) return 0; - if (vias->next != 0) - printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); - if (vias->n_addrs < 1 || vias->n_intrs < 1) { - printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", - vias->n_addrs, vias->n_intrs); - if (vias->n_addrs < 1 || vias->n_intrs < 1) - return 0; + reg = of_get_property(vias, "reg", NULL); + if (reg == NULL) { + printk(KERN_ERR "via-pmu: No \"reg\" property !\n"); + goto fail; + } + taddr = of_translate_address(vias, reg); + if (taddr == OF_BAD_ADDR) { + printk(KERN_ERR "via-pmu: Can't translate address !\n"); + goto fail; } spin_lock_init(&pmu_lock); @@ -323,37 +301,48 @@ find_via_pmu(void) PMU_INT_TICK; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) - || device_is_compatible(vias->parent, "ohare"))) + || of_device_is_compatible(vias->parent, "ohare"))) pmu_kind = PMU_OHARE_BASED; - else if (device_is_compatible(vias->parent, "paddington")) + else if (of_device_is_compatible(vias->parent, "paddington")) pmu_kind = PMU_PADDINGTON_BASED; - else if (device_is_compatible(vias->parent, "heathrow")) + else if (of_device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; - else if (device_is_compatible(vias->parent, "Keylargo") - || device_is_compatible(vias->parent, "K2-Keylargo")) { - struct device_node *gpio, *gpiop; + else if (of_device_is_compatible(vias->parent, "Keylargo") + || of_device_is_compatible(vias->parent, "K2-Keylargo")) { + struct device_node *gpiop; + struct device_node *adbp; + u64 gaddr = OF_BAD_ADDR; pmu_kind = PMU_KEYLARGO_BASED; - pmu_has_adb = (find_type_devices("adb") != NULL); + adbp = of_find_node_by_type(NULL, "adb"); + pmu_has_adb = (adbp != NULL); + of_node_put(adbp); pmu_intr_mask = PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | PMU_INT_TICK | PMU_INT_ENVIRONMENT; - gpiop = find_devices("gpio"); - if (gpiop && gpiop->n_addrs) { - gpio_reg = ioremap(gpiop->addrs->address, 0x10); - gpio = find_devices("extint-gpio1"); - if (gpio == NULL) - gpio = find_devices("pmu-interrupt"); - if (gpio && gpio->parent == gpiop && gpio->n_intrs) - gpio_irq = gpio->intrs[0].line; + gpiop = of_find_node_by_name(NULL, "gpio"); + if (gpiop) { + reg = of_get_property(gpiop, "reg", NULL); + if (reg) + gaddr = of_translate_address(gpiop, reg); + if (gaddr != OF_BAD_ADDR) + gpio_reg = ioremap(gaddr, 0x10); + } + if (gpio_reg == NULL) { + printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n"); + goto fail_gpio; } } else pmu_kind = PMU_UNKNOWN; - via = ioremap(vias->addrs->address, 0x2000); + via = ioremap(taddr, 0x2000); + if (via == NULL) { + printk(KERN_ERR "via-pmu: Can't map address !\n"); + goto fail; + } out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ out_8(&via[IFR], 0x7f); /* clear IFR */ @@ -365,23 +354,28 @@ find_via_pmu(void) return 0; } - printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n", + printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n", PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); sys_ctrler = SYS_CTRLER_PMU; return 1; + fail: + of_node_put(vias); + iounmap(gpio_reg); + gpio_reg = NULL; + fail_gpio: + vias = NULL; + return 0; } #ifdef CONFIG_ADB -static int __openfirmware -pmu_probe(void) +static int pmu_probe(void) { return vias == NULL? -ENODEV: 0; } -static int __init -pmu_init(void) +static int __init pmu_init(void) { if (vias == NULL) return -ENODEV; @@ -398,26 +392,39 @@ pmu_init(void) */ static int __init via_pmu_start(void) { + unsigned int irq; + if (vias == NULL) return -ENODEV; - bright_req_1.complete = 1; - bright_req_2.complete = 1; -#ifdef CONFIG_PMAC_PBOOK batt_req.complete = 1; -#endif - if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", - (void *)0)) { - printk(KERN_ERR "VIA-PMU: can't get irq %d\n", - vias->intrs[0].line); - return -EAGAIN; + irq = irq_of_parse_and_map(vias, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR "via-pmu: can't map interrupt\n"); + return -ENODEV; + } + if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { + printk(KERN_ERR "via-pmu: can't request irq %d\n", irq); + return -ENODEV; } - if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { - if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0)) - printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); - gpio_irq_enabled = 1; + if (pmu_kind == PMU_KEYLARGO_BASED) { + gpio_node = of_find_node_by_name(NULL, "extint-gpio1"); + if (gpio_node == NULL) + gpio_node = of_find_node_by_name(NULL, + "pmu-interrupt"); + if (gpio_node) + gpio_irq = irq_of_parse_and_map(gpio_node, 0); + + if (gpio_irq != NO_IRQ) { + if (request_irq(gpio_irq, gpio1_interrupt, 0, + "GPIO1 ADB", (void *)0)) + printk(KERN_ERR "pmu: can't get irq %d" + " (GPIO1)\n", gpio_irq); + else + gpio_irq_enabled = 1; + } } /* Enable interrupts */ @@ -450,15 +457,12 @@ static int __init via_pmu_dev_init(void) if (vias == NULL) return -ENODEV; -#ifndef CONFIG_PPC64 - request_OF_resource(vias, 0, NULL); -#endif #ifdef CONFIG_PMAC_BACKLIGHT - /* Enable backlight */ - register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); -#endif /* CONFIG_PMAC_BACKLIGHT */ + /* Initialize backlight */ + pmu_backlight_init(); +#endif -#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_PPC32 if (machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500")) { int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, @@ -474,10 +478,11 @@ static int __init via_pmu_dev_init(void) pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } else { - struct device_node* prim = find_devices("power-mgt"); - u32 *prim_info = NULL; + struct device_node* prim = + of_find_node_by_name(NULL, "power-mgt"); + const u32 *prim_info = NULL; if (prim) - prim_info = (u32 *)get_property(prim, "prim-info", NULL); + prim_info = of_get_property(prim, "prim-info", NULL); if (prim_info) { /* Other stuffs here yet unknown */ pmu_battery_count = (prim_info[6] >> 16) & 0xff; @@ -485,21 +490,21 @@ static int __init via_pmu_dev_init(void) if (pmu_battery_count > 1) pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } + of_node_put(prim); } -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_PPC32 */ + /* Create /proc/pmu */ proc_pmu_root = proc_mkdir("pmu", NULL); if (proc_pmu_root) { -#ifdef CONFIG_PMAC_PBOOK - int i; + long i; for (i=0; inlink = 1; proc_pmu_options->read_proc = proc_read_options; proc_pmu_options->write_proc = proc_write_options; } @@ -517,7 +521,7 @@ static int __init via_pmu_dev_init(void) device_initcall(via_pmu_dev_init); -static int __openfirmware +static int init_pmu(void) { int timeout; @@ -547,7 +551,7 @@ init_pmu(void) } if (pmu_state == idle) adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); udelay(10); } @@ -585,17 +589,6 @@ pmu_get_model(void) return pmu_kind; } -#ifndef CONFIG_PPC64 -static inline void wakeup_decrementer(void) -{ - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - * so use get_tbl, not native - */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); -} -#endif - static void pmu_set_server_mode(int server_mode) { struct adb_request req; @@ -619,12 +612,10 @@ static void pmu_set_server_mode(int server_mode) pmu_wait_complete(&req); } -#ifdef CONFIG_PMAC_PBOOK - /* This new version of the code for 2400/3400/3500 powerbooks * is inspired from the implementation in gkrellm-pmu */ -static void __pmac +static void done_battery_state_ohare(struct adb_request* req) { /* format: @@ -712,7 +703,7 @@ done_battery_state_ohare(struct adb_request* req) clear_bit(0, &async_req_locks); } -static void __pmac +static void done_battery_state_smart(struct adb_request* req) { /* format: @@ -790,7 +781,7 @@ done_battery_state_smart(struct adb_request* req) clear_bit(0, &async_req_locks); } -static void __pmac +static void query_battery_state(void) { if (test_and_set_bit(0, &async_req_locks)) @@ -803,9 +794,7 @@ query_battery_state(void) 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); } -#endif /* CONFIG_PMAC_PBOOK */ - -static int __pmac +static int proc_get_info(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -813,16 +802,14 @@ proc_get_info(char *page, char **start, off_t off, p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION); p += sprintf(p, "PMU firmware version : %02x\n", pmu_version); -#ifdef CONFIG_PMAC_PBOOK p += sprintf(p, "AC Power : %d\n", - ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0)); + ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0) || pmu_battery_count == 0); p += sprintf(p, "Battery count : %d\n", pmu_battery_count); -#endif /* CONFIG_PMAC_PBOOK */ return p - page; } -static int __pmac +static int proc_get_irqstats(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -849,12 +836,11 @@ proc_get_irqstats(char *page, char **start, off_t off, return p - page; } -#ifdef CONFIG_PMAC_PBOOK -static int __pmac +static int proc_get_batt(char *page, char **start, off_t off, int count, int *eof, void *data) { - int batnum = (int)data; + long batnum = (long)data; char *p = page; p += sprintf(p, "\n"); @@ -873,26 +859,25 @@ proc_get_batt(char *page, char **start, off_t off, return p - page; } -#endif /* CONFIG_PMAC_PBOOK */ -static int __pmac +static int proc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data) { char *p = page; -#ifdef CONFIG_PMAC_PBOOK +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) if (pmu_kind == PMU_KEYLARGO_BASED && pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); -#endif /* CONFIG_PMAC_PBOOK */ +#endif if (pmu_kind == PMU_KEYLARGO_BASED) p += sprintf(p, "server_mode=%d\n", option_server_mode); return p - page; } -static int __pmac +static int proc_write_options(struct file *file, const char __user *buffer, unsigned long count, void *data) { @@ -922,12 +907,12 @@ proc_write_options(struct file *file, const char __user *buffer, *(val++) = 0; while(*val == ' ') val++; -#ifdef CONFIG_PMAC_PBOOK +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) if (pmu_kind == PMU_KEYLARGO_BASED && pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) if (!strcmp(label, "lid_wakeup")) option_lid_wakeup = ((*val) == '1'); -#endif /* CONFIG_PMAC_PBOOK */ +#endif if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) { int new_value; new_value = ((*val) == '1'); @@ -939,7 +924,7 @@ proc_write_options(struct file *file, const char __user *buffer, #ifdef CONFIG_ADB /* Send an ADB command */ -static int __pmac +static int pmu_send_request(struct adb_request *req, int sync) { int i, ret; @@ -1019,7 +1004,7 @@ pmu_send_request(struct adb_request *req, int sync) } /* Enable/disable autopolling */ -static int __pmac +static int pmu_adb_autopoll(int devs) { struct adb_request req; @@ -1042,7 +1027,7 @@ pmu_adb_autopoll(int devs) } /* Reset the ADB bus */ -static int __pmac +static int pmu_adb_reset_bus(void) { struct adb_request req; @@ -1077,7 +1062,7 @@ pmu_adb_reset_bus(void) #endif /* CONFIG_ADB */ /* Construct and send a pmu request */ -int __openfirmware +int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...) { @@ -1103,7 +1088,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *), return pmu_queue_request(req); } -int __pmac +int pmu_queue_request(struct adb_request *req) { unsigned long flags; @@ -1195,7 +1180,7 @@ pmu_done(struct adb_request *req) (*done)(req); } -static void __pmac +static void pmu_start(void) { struct adb_request *req; @@ -1219,17 +1204,17 @@ pmu_start(void) send_byte(req->data[0]); } -void __openfirmware +void pmu_poll(void) { if (!via) return; if (disable_poll) return; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } -void __openfirmware +void pmu_poll_adb(void) { if (!via) @@ -1239,18 +1224,18 @@ pmu_poll_adb(void) /* Kicks ADB read when PMU is suspended */ adb_int_pending = 1; do { - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } while (pmu_suspended && (adb_int_pending || pmu_state != idle || req_awaiting_reply)); } -void __openfirmware +void pmu_wait_complete(struct adb_request *req) { if (!via) return; while((pmu_state != idle && pmu_state != locked) || !req->complete) - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); } /* This function loops until the PMU is idle and prevents it from @@ -1258,13 +1243,11 @@ pmu_wait_complete(struct adb_request *req) * This is done to avoid spurrious shutdowns when we know we'll have * interrupts switched off for a long time */ -void __openfirmware +void pmu_suspend(void) { unsigned long flags; -#ifdef SUSPEND_USES_PMU - struct adb_request *req; -#endif + if (!via) return; @@ -1279,26 +1262,19 @@ pmu_suspend(void) spin_unlock_irqrestore(&pmu_lock, flags); if (req_awaiting_reply) adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); spin_lock_irqsave(&pmu_lock, flags); if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { -#ifdef SUSPEND_USES_PMU - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); - spin_unlock_irqrestore(&pmu_lock, flags); - while(!req.complete) - pmu_poll(); -#else /* SUSPEND_USES_PMU */ if (gpio_irq >= 0) disable_irq_nosync(gpio_irq); out_8(&via[IER], CB1_INT | IER_CLR); spin_unlock_irqrestore(&pmu_lock, flags); -#endif /* SUSPEND_USES_PMU */ break; } } while (1); } -void __openfirmware +void pmu_resume(void) { unsigned long flags; @@ -1313,23 +1289,16 @@ pmu_resume(void) return; } adb_int_pending = 1; -#ifdef SUSPEND_USES_PMU - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); - spin_unlock_irqrestore(&pmu_lock, flags); - while(!req.complete) - pmu_poll(); -#else /* SUSPEND_USES_PMU */ if (gpio_irq >= 0) enable_irq(gpio_irq); out_8(&via[IER], CB1_INT | IER_SET); spin_unlock_irqrestore(&pmu_lock, flags); pmu_poll(); -#endif /* SUSPEND_USES_PMU */ } /* Interrupt data could be the result data from an ADB cmd */ -static void __pmac -pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) +static void +pmu_handle_data(unsigned char *data, int len) { unsigned char ints, pirq; int i = 0; @@ -1387,7 +1356,6 @@ next: } pmu_done(req); } else { -#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64) if (len == 4 && data[1] == 0x2c) { extern int xmon_wants_key, xmon_adb_keycode; if (xmon_wants_key) { @@ -1395,7 +1363,6 @@ next: return; } } -#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */ #ifdef CONFIG_ADB /* * XXX On the [23]400 the PMU gives us an up @@ -1406,7 +1373,7 @@ next: if (!(pmu_kind == PMU_OHARE_BASED && len == 4 && data[1] == 0x2c && data[3] == 0xff && (data[2] & ~1) == 0xf4)) - adb_input(data+1, len-1, regs, 1); + adb_input(data+1, len-1, 1); #endif /* CONFIG_ADB */ } } @@ -1414,15 +1381,11 @@ next: else if ((1 << pirq) & PMU_INT_SNDBRT) { #ifdef CONFIG_PMAC_BACKLIGHT if (len == 3) -#ifdef CONFIG_INPUT_ADBHID - if (!disable_kernel_backlight) -#endif /* CONFIG_INPUT_ADBHID */ - set_backlight_level(data[1] >> 4); -#endif /* CONFIG_PMAC_BACKLIGHT */ + pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4); +#endif } /* Tick interrupt */ else if ((1 << pirq) & PMU_INT_TICK) { -#ifdef CONFIG_PMAC_PBOOK /* Environement or tick interrupt, query batteries */ if (pmu_battery_count) { if ((--query_batt_timer) == 0) { @@ -1435,15 +1398,20 @@ next: if (pmu_battery_count) query_battery_state(); pmu_pass_intr(data, len); + /* len == 6 is probably a bad check. But how do I + * know what PMU versions send what events here? */ + if (len == 6) { + via_pmu_event(PMU_EVT_POWER, !!(data[1]&8)); + via_pmu_event(PMU_EVT_LID, data[1]&1); + } } else { pmu_pass_intr(data, len); -#endif /* CONFIG_PMAC_PBOOK */ } goto next; } -static struct adb_request* __pmac -pmu_sr_intr(struct pt_regs *regs) +static struct adb_request* +pmu_sr_intr(void) { struct adb_request *req; int bite = 0; @@ -1528,7 +1496,7 @@ pmu_sr_intr(struct pt_regs *regs) req = current_req; /* * For PMU sleep and freq change requests, we lock the - * PMU until it's explicitely unlocked. This avoids any + * PMU until it's explicitly unlocked. This avoids any * spurrious event polling getting in */ current_req = req->next; @@ -1548,8 +1516,8 @@ pmu_sr_intr(struct pt_regs *regs) return NULL; } -static irqreturn_t __pmac -via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t +via_pmu_interrupt(int irq, void *arg) { unsigned long flags; int intr; @@ -1579,7 +1547,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) pmu_irq_stats[0]++; } if (intr & SR_INT) { - req = pmu_sr_intr(regs); + req = pmu_sr_intr(); if (req) break; } @@ -1625,7 +1593,7 @@ no_free_slot: /* Deal with interrupt datas outside of the lock */ if (int_data >= 0) { - pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs); + pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]); spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; int_data_state[int_data] = int_data_empty; @@ -1636,7 +1604,7 @@ no_free_slot: return IRQ_RETVAL(handled); } -void __pmac +void pmu_unlock(void) { unsigned long flags; @@ -1649,8 +1617,8 @@ pmu_unlock(void) } -static irqreturn_t __pmac -gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) +static irqreturn_t +gpio1_interrupt(int irq, void *arg) { unsigned long flags; @@ -1663,68 +1631,13 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) pmu_irq_stats[1]++; adb_int_pending = 1; spin_unlock_irqrestore(&pmu_lock, flags); - via_pmu_interrupt(0, NULL, NULL); + via_pmu_interrupt(0, NULL); return IRQ_HANDLED; } return IRQ_NONE; } -#ifdef CONFIG_PMAC_BACKLIGHT -static int backlight_to_bright[] __pmacdata = { - 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, - 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e -}; - -static int __openfirmware -pmu_set_backlight_enable(int on, int level, void* data) -{ - struct adb_request req; - - if (vias == NULL) - return -ENODEV; - - if (on) { - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - backlight_to_bright[level]); - pmu_wait_complete(&req); - } - pmu_request(&req, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); - pmu_wait_complete(&req); - - return 0; -} - -static void __openfirmware -pmu_bright_complete(struct adb_request *req) -{ - if (req == &bright_req_1) - clear_bit(1, &async_req_locks); - if (req == &bright_req_2) - clear_bit(2, &async_req_locks); -} - -static int __openfirmware -pmu_set_backlight_level(int level, void* data) -{ - if (vias == NULL) - return -ENODEV; - - if (test_and_set_bit(1, &async_req_locks)) - return -EAGAIN; - pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT, - backlight_to_bright[level]); - if (test_and_set_bit(2, &async_req_locks)) - return -EAGAIN; - pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ? - PMU_POW_ON : PMU_POW_OFF)); - - return 0; -} -#endif /* CONFIG_PMAC_BACKLIGHT */ - -void __pmac +void pmu_enable_irled(int on) { struct adb_request req; @@ -1739,7 +1652,7 @@ pmu_enable_irled(int on) pmu_wait_complete(&req); } -void __pmac +void pmu_restart(void) { struct adb_request req; @@ -1764,7 +1677,7 @@ pmu_restart(void) ; } -void __pmac +void pmu_shutdown(void) { struct adb_request req; @@ -1800,493 +1713,14 @@ pmu_present(void) return via != 0; } -struct pmu_i2c_hdr { - u8 bus; - u8 mode; - u8 bus2; - u8 address; - u8 sub_addr; - u8 comb_addr; - u8 count; -}; - -int -pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_COMBINED; - hdr->bus2 = 0; - hdr->sub_addr = subaddr; - hdr->comb_addr = addr | 1; - hdr->count = len; - - req.nbytes = sizeof(struct pmu_i2c_hdr) + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) { - memcpy(data, &req.reply[1], req.reply_len - 1); - return req.reply_len - 1; - } - } - return -1; -} - -int -pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_STDSUB; - hdr->bus2 = 0; - hdr->sub_addr = subaddr; - hdr->comb_addr = addr & 0xfe; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len); - req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - return len; - } - return -1; -} - -int -pmu_i2c_simple_read(int bus, int addr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr | 1; - hdr->mode = PMU_I2C_MODE_SIMPLE; - hdr->bus2 = 0; - hdr->sub_addr = 0; - hdr->comb_addr = 0; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - req.nbytes = sizeof(struct pmu_i2c_hdr) + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) { - memcpy(data, &req.reply[1], req.reply_len - 1); - return req.reply_len - 1; - } - } - return -1; -} - -int -pmu_i2c_simple_write(int bus, int addr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_SIMPLE; - hdr->bus2 = 0; - hdr->sub_addr = 0; - hdr->comb_addr = 0; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len); - req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - return len; - } - return -1; -} - -#ifdef CONFIG_PMAC_PBOOK - -static LIST_HEAD(sleep_notifiers); - -int -pmu_register_sleep_notifier(struct pmu_sleep_notifier *n) -{ - struct list_head *list; - struct pmu_sleep_notifier *notifier; - - for (list = sleep_notifiers.next; list != &sleep_notifiers; - list = list->next) { - notifier = list_entry(list, struct pmu_sleep_notifier, list); - if (n->priority > notifier->priority) - break; - } - __list_add(&n->list, list->prev, list); - return 0; -} - -int -pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) -{ - if (n->list.next == 0) - return -ENOENT; - list_del(&n->list); - n->list.next = NULL; - return 0; -} - -/* Sleep is broadcast last-to-first */ -static int __pmac -broadcast_sleep(int when, int fallback) -{ - int ret = PBOOK_SLEEP_OK; - struct list_head *list; - struct pmu_sleep_notifier *notifier; - - for (list = sleep_notifiers.prev; list != &sleep_notifiers; - list = list->prev) { - notifier = list_entry(list, struct pmu_sleep_notifier, list); - ret = notifier->notifier_call(notifier, when); - if (ret != PBOOK_SLEEP_OK) { - printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n", - when, notifier, notifier->notifier_call); - for (; list != &sleep_notifiers; list = list->next) { - notifier = list_entry(list, struct pmu_sleep_notifier, list); - notifier->notifier_call(notifier, fallback); - } - return ret; - } - } - return ret; -} - -/* Wake is broadcast first-to-last */ -static int __pmac -broadcast_wake(void) -{ - int ret = PBOOK_SLEEP_OK; - struct list_head *list; - struct pmu_sleep_notifier *notifier; - - for (list = sleep_notifiers.next; list != &sleep_notifiers; - list = list->next) { - notifier = list_entry(list, struct pmu_sleep_notifier, list); - notifier->notifier_call(notifier, PBOOK_WAKE); - } - return ret; -} - -/* - * This struct is used to store config register values for - * PCI devices which may get powered off when we sleep. - */ -static struct pci_save { -#ifndef HACKED_PCI_SAVE - u16 command; - u16 cache_lat; - u16 intr; - u32 rom_address; -#else - u32 config[16]; -#endif -} *pbook_pci_saves; -static int pbook_npci_saves; - -static void __pmac -pbook_alloc_pci_save(void) -{ - int npci; - struct pci_dev *pd = NULL; - - npci = 0; - while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { - ++npci; - } - if (npci == 0) - return; - pbook_pci_saves = (struct pci_save *) - kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL); - pbook_npci_saves = npci; -} - -static void __pmac -pbook_free_pci_save(void) -{ - if (pbook_pci_saves == NULL) - return; - kfree(pbook_pci_saves); - pbook_pci_saves = NULL; - pbook_npci_saves = 0; -} - -static void __pmac -pbook_pci_save(void) -{ - struct pci_save *ps = pbook_pci_saves; - struct pci_dev *pd = NULL; - int npci = pbook_npci_saves; - - if (ps == NULL) - return; - - while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { - if (npci-- == 0) - return; -#ifndef HACKED_PCI_SAVE - pci_read_config_word(pd, PCI_COMMAND, &ps->command); - pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); - pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); - pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); -#else - int i; - for (i=1;i<16;i++) - pci_read_config_dword(pd, i<<4, &ps->config[i]); -#endif - ++ps; - } -} - -/* For this to work, we must take care of a few things: If gmac was enabled - * during boot, it will be in the pci dev list. If it's disabled at this point - * (and it will probably be), then you can't access it's config space. - */ -static void __pmac -pbook_pci_restore(void) -{ - u16 cmd; - struct pci_save *ps = pbook_pci_saves - 1; - struct pci_dev *pd = NULL; - int npci = pbook_npci_saves; - int j; - - while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { -#ifdef HACKED_PCI_SAVE - int i; - if (npci-- == 0) - return; - ps++; - for (i=2;i<16;i++) - pci_write_config_dword(pd, i<<4, ps->config[i]); - pci_write_config_dword(pd, 4, ps->config[1]); -#else - if (npci-- == 0) - return; - ps++; - if (ps->command == 0) - continue; - pci_read_config_word(pd, PCI_COMMAND, &cmd); - if ((ps->command & ~cmd) == 0) - continue; - switch (pd->hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - for (j = 0; j < 6; ++j) - pci_write_config_dword(pd, - PCI_BASE_ADDRESS_0 + j*4, - pd->resource[j].start); - pci_write_config_dword(pd, PCI_ROM_ADDRESS, - ps->rom_address); - pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, - ps->cache_lat); - pci_write_config_word(pd, PCI_INTERRUPT_LINE, - ps->intr); - pci_write_config_word(pd, PCI_COMMAND, ps->command); - break; - } -#endif - } -} - -#ifdef DEBUG_SLEEP -/* N.B. This doesn't work on the 3400 */ -void __pmac -pmu_blink(int n) -{ - struct adb_request req; - - memset(&req, 0, sizeof(req)); - - for (; n > 0; --n) { - req.nbytes = 4; - req.done = NULL; - req.data[0] = 0xee; - req.data[1] = 4; - req.data[2] = 0; - req.data[3] = 1; - req.reply[0] = ADB_RET_OK; - req.reply_len = 1; - req.reply_expected = 0; - pmu_polled_request(&req); - mdelay(50); - req.nbytes = 4; - req.done = NULL; - req.data[0] = 0xee; - req.data[1] = 4; - req.data[2] = 0; - req.data[3] = 0; - req.reply[0] = ADB_RET_OK; - req.reply_len = 1; - req.reply_expected = 0; - pmu_polled_request(&req); - mdelay(50); - } - mdelay(50); -} -#endif - +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) /* * Put the powerbook to sleep. */ -static u32 save_via[8] __pmacdata; +static u32 save_via[8]; -static void __pmac +static void save_via_state(void) { save_via[0] = in_8(&via[ANH]); @@ -2298,7 +1732,7 @@ save_via_state(void) save_via[6] = in_8(&via[T1CL]); save_via[7] = in_8(&via[T1CH]); } -static void __pmac +static void restore_via_state(void) { out_8(&via[ANH], save_via[0]); @@ -2314,154 +1748,22 @@ restore_via_state(void) out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } -static int __pmac -pmac_suspend_devices(void) -{ - int ret; - - pm_prepare_console(); - - /* Notify old-style device drivers & userland */ - ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); - if (ret != PBOOK_SLEEP_OK) { - printk(KERN_ERR "Sleep rejected by drivers\n"); - return -EBUSY; - } - - /* Sync the disks. */ - /* XXX It would be nice to have some way to ensure that - * nobody is dirtying any new buffers while we wait. That - * could be achieved using the refrigerator for processes - * that swsusp uses - */ - sys_sync(); - - /* Sleep can fail now. May not be very robust but useful for debugging */ - ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); - if (ret != PBOOK_SLEEP_OK) { - printk(KERN_ERR "Driver sleep failed\n"); - return -EBUSY; - } - - /* Send suspend call to devices, hold the device core's dpm_sem */ - ret = device_suspend(PMSG_SUSPEND); - if (ret) { - broadcast_wake(); - printk(KERN_ERR "Driver sleep failed\n"); - return -EBUSY; - } - - /* Disable clock spreading on some machines */ - pmac_tweak_clock_spreading(0); - - /* Stop preemption */ - preempt_disable(); - - /* Make sure the decrementer won't interrupt us */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - /* Make sure any pending DEC interrupt occurring while we did - * the above didn't re-enable the DEC */ - mb(); - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - - /* We can now disable MSR_EE. This code of course works properly only - * on UP machines... For SMP, if we ever implement sleep, we'll have to - * stop the "other" CPUs way before we do all that stuff. - */ - local_irq_disable(); - - /* Broadcast power down irq - * This isn't that useful in most cases (only directly wired devices can - * use this but still... This will take care of sysdev's as well, so - * we exit from here with local irqs disabled and PIC off. - */ - ret = device_power_down(PMSG_SUSPEND); - if (ret) { - wakeup_decrementer(); - local_irq_enable(); - preempt_enable(); - device_resume(); - broadcast_wake(); - printk(KERN_ERR "Driver powerdown failed\n"); - return -EBUSY; - } - - /* Wait for completion of async backlight requests */ - while (!bright_req_1.complete || !bright_req_2.complete || - !batt_req.complete) - pmu_poll(); - - /* Giveup the lazy FPU & vec so we don't have to back them - * up from the low level code - */ - enable_kernel_fp(); - -#ifdef CONFIG_ALTIVEC - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - enable_kernel_altivec(); -#endif /* CONFIG_ALTIVEC */ - - return 0; -} - -static int __pmac -pmac_wakeup_devices(void) -{ - mdelay(100); - - /* Power back up system devices (including the PIC) */ - device_power_up(); - - /* Force a poll of ADB interrupts */ - adb_int_pending = 1; - via_pmu_interrupt(0, NULL, NULL); - - /* Restart jiffies & scheduling */ - wakeup_decrementer(); - - /* Re-enable local CPU interrupts */ - local_irq_enable(); - mdelay(10); - preempt_enable(); - - /* Re-enable clock spreading on some machines */ - pmac_tweak_clock_spreading(1); - - /* Resume devices */ - device_resume(); - - /* Notify old style drivers */ - broadcast_wake(); - - pm_restore_console(); - - return 0; -} - #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) #define GRACKLE_SLEEP (1<<3) -int __pmac -powerbook_sleep_grackle(void) +static int powerbook_sleep_grackle(void) { unsigned long save_l2cr; unsigned short pmcr1; struct adb_request req; - int ret; struct pci_dev *grackle; - grackle = pci_find_slot(0, 0); + grackle = pci_get_bus_and_slot(0, 0); if (!grackle) return -ENODEV; - ret = pmac_suspend_devices(); - if (ret) { - printk(KERN_ERR "Sleep rejected by devices\n"); - return ret; - } - /* Turn off various things. Darwin does some retry tests here... */ pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE); pmu_wait_complete(&req); @@ -2500,6 +1802,8 @@ powerbook_sleep_grackle(void) pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); pci_write_config_word(grackle, 0x70, pmcr1); + pci_dev_put(grackle); + /* Make sure the PMU is idle */ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); @@ -2509,7 +1813,7 @@ powerbook_sleep_grackle(void) _set_L2CR(save_l2cr); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); /* Power things up */ pmu_unlock(); @@ -2522,18 +1826,15 @@ powerbook_sleep_grackle(void) PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); pmu_wait_complete(&req); - pmac_wakeup_devices(); - return 0; } -static int __pmac +static int powerbook_sleep_Core99(void) { unsigned long save_l2cr; unsigned long save_l3cr; struct adb_request req; - int ret; if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) { printk(KERN_ERR "Sleep mode not supported on this machine\n"); @@ -2543,12 +1844,6 @@ powerbook_sleep_Core99(void) if (num_online_cpus() > 1 || cpu_is_offline(0)) return -EAGAIN; - ret = pmac_suspend_devices(); - if (ret) { - printk(KERN_ERR "Sleep rejected by devices\n"); - return ret; - } - /* Stop environment and ADB interrupts */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); pmu_wait_complete(&req); @@ -2593,6 +1888,9 @@ powerbook_sleep_Core99(void) /* Restore VIA */ restore_via_state(); + /* tweak LPJ before cpufreq is there */ + loops_per_jiffy *= 2; + /* Restore video */ pmac_call_early_video_resume(); @@ -2604,7 +1902,7 @@ powerbook_sleep_Core99(void) _set_L3CR(save_l3cr); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); /* Tell PMU we are ready */ pmu_unlock(); @@ -2613,7 +1911,8 @@ powerbook_sleep_Core99(void) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_wait_complete(&req); - pmac_wakeup_devices(); + /* Restore LPJ, cpufreq will adjust the cpu frequency */ + loops_per_jiffy /= 2; return 0; } @@ -2621,36 +1920,27 @@ powerbook_sleep_Core99(void) #define PB3400_MEM_CTRL 0xf8000000 #define PB3400_MEM_CTRL_SLEEP 0x70 -static int __pmac -powerbook_sleep_3400(void) +static void __iomem *pb3400_mem_ctrl; + +static void powerbook_sleep_init_3400(void) { - int ret, i, x; + /* map in the memory controller registers */ + pb3400_mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100); + if (pb3400_mem_ctrl == NULL) + printk(KERN_WARNING "ioremap failed: sleep won't be possible"); +} + +static int powerbook_sleep_3400(void) +{ + int i, x; unsigned int hid0; - unsigned long p; + unsigned long msr; struct adb_request sleep_req; - void __iomem *mem_ctrl; unsigned int __iomem *mem_ctrl_sleep; - /* first map in the memory controller registers */ - mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100); - if (mem_ctrl == NULL) { - printk("powerbook_sleep_3400: ioremap failed\n"); + if (pb3400_mem_ctrl == NULL) return -ENOMEM; - } - mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP; - - /* Allocate room for PCI save */ - pbook_alloc_pci_save(); - - ret = pmac_suspend_devices(); - if (ret) { - pbook_free_pci_save(); - printk(KERN_ERR "Sleep rejected by devices\n"); - return ret; - } - - /* Save the state of PCI config space for some slots */ - pbook_pci_save(); + mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP; /* Set the memory controller to keep the memory refreshed while we're asleep */ @@ -2665,40 +1955,35 @@ powerbook_sleep_3400(void) /* Ask the PMU to put us to sleep */ pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) - mb(); + pmu_wait_complete(&sleep_req); + pmu_unlock(); - pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); + pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1); - /* displacement-flush the L2 cache - necessary? */ - for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) - i = *(volatile int *)p; asleep = 1; /* Put the CPU into sleep mode */ - asm volatile("mfspr %0,1008" : "=r" (hid0) :); + hid0 = mfspr(SPRN_HID0); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; - asm volatile("mtspr 1008,%0" : : "r" (hid0)); - _nmask_and_or_msr(0, MSR_POW | MSR_EE); - udelay(10); + mtspr(SPRN_HID0, hid0); + local_irq_enable(); + msr = mfmsr() | MSR_POW; + while (asleep) { + mb(); + mtmsr(msr); + isync(); + } + local_irq_disable(); /* OK, we're awake again, start restoring things */ out_be32(mem_ctrl_sleep, 0x3f); - pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); - pbook_pci_restore(); - pmu_unlock(); - - /* wait for the PMU interrupt sequence to complete */ - while (asleep) - mb(); - - pmac_wakeup_devices(); - pbook_free_pci_save(); - iounmap(mem_ctrl); + pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0); return 0; } +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ + /* * Support for /dev/pmu device */ @@ -2715,13 +2000,13 @@ struct pmu_private { spinlock_t lock; #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) int backlight_locker; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif }; static LIST_HEAD(all_pmu_pvt); -static DEFINE_SPINLOCK(all_pvt_lock __pmacdata); +static DEFINE_SPINLOCK(all_pvt_lock); -static void __pmac +static void pmu_pass_intr(unsigned char *data, int len) { struct pmu_private *pp; @@ -2750,7 +2035,7 @@ pmu_pass_intr(unsigned char *data, int len) spin_unlock_irqrestore(&all_pvt_lock, flags); } -static int __pmac +static int pmu_open(struct inode *inode, struct file *file) { struct pmu_private *pp; @@ -2765,14 +2050,14 @@ pmu_open(struct inode *inode, struct file *file) spin_lock_irqsave(&all_pvt_lock, flags); #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) pp->backlight_locker = 0; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; return 0; } -static ssize_t __pmac +static ssize_t pmu_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -2824,14 +2109,14 @@ pmu_read(struct file *file, char __user *buf, return ret; } -static ssize_t __pmac +static ssize_t pmu_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { return 0; } -static unsigned int __pmac +static unsigned int pmu_fpoll(struct file *filp, poll_table *wait) { struct pmu_private *pp = filp->private_data; @@ -2848,112 +2133,180 @@ pmu_fpoll(struct file *filp, poll_table *wait) return mask; } -static int __pmac +static int pmu_release(struct inode *inode, struct file *file) { struct pmu_private *pp = file->private_data; unsigned long flags; - lock_kernel(); if (pp != 0) { file->private_data = NULL; spin_lock_irqsave(&all_pvt_lock, flags); list_del(&pp->list); spin_unlock_irqrestore(&all_pvt_lock, flags); + #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) - if (pp->backlight_locker) { - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight--; - spin_unlock_irqrestore(&pmu_lock, flags); - } -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ + if (pp->backlight_locker) + pmac_backlight_enable(); +#endif + kfree(pp); } - unlock_kernel(); return 0; } -/* Note: removed __openfirmware here since it causes link errors */ -static int __pmac +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) +static void pmac_suspend_disable_irqs(void) +{ + /* Call platform functions marked "on sleep" */ + pmac_pfunc_i2c_suspend(); + pmac_pfunc_base_suspend(); +} + +static int powerbook_sleep(suspend_state_t state) +{ + int error = 0; + + /* Wait for completion of async requests */ + while (!batt_req.complete) + pmu_poll(); + + /* Giveup the lazy FPU & vec so we don't have to back them + * up from the low level code + */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + switch (pmu_kind) { + case PMU_OHARE_BASED: + error = powerbook_sleep_3400(); + break; + case PMU_HEATHROW_BASED: + case PMU_PADDINGTON_BASED: + error = powerbook_sleep_grackle(); + break; + case PMU_KEYLARGO_BASED: + error = powerbook_sleep_Core99(); + break; + default: + return -ENOSYS; + } + + if (error) + return error; + + mdelay(100); + + return 0; +} + +static void pmac_suspend_enable_irqs(void) +{ + /* Force a poll of ADB interrupts */ + adb_int_pending = 1; + via_pmu_interrupt(0, NULL); + + mdelay(10); + + /* Call platform functions marked "on wake" */ + pmac_pfunc_base_resume(); + pmac_pfunc_i2c_resume(); +} + +static int pmu_sleep_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM + && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0); +} + +static struct platform_suspend_ops pmu_pm_ops = { + .enter = powerbook_sleep, + .valid = pmu_sleep_valid, +}; + +static int register_pmu_pm_ops(void) +{ + if (pmu_kind == PMU_OHARE_BASED) + powerbook_sleep_init_3400(); + ppc_md.suspend_disable_irqs = pmac_suspend_disable_irqs; + ppc_md.suspend_enable_irqs = pmac_suspend_enable_irqs; + suspend_set_ops(&pmu_pm_ops); + + return 0; +} + +device_initcall(register_pmu_pm_ops); +#endif + +static int pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { - struct pmu_private *pp = filp->private_data; __u32 __user *argp = (__u32 __user *)arg; - int error; + int error = -EINVAL; switch (cmd) { case PMU_IOC_SLEEP: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (sleep_in_progress) - return -EBUSY; - sleep_in_progress = 1; - switch (pmu_kind) { - case PMU_OHARE_BASED: - error = powerbook_sleep_3400(); - break; - case PMU_HEATHROW_BASED: - case PMU_PADDINGTON_BASED: - error = powerbook_sleep_grackle(); - break; - case PMU_KEYLARGO_BASED: - error = powerbook_sleep_Core99(); - break; - default: - error = -ENOSYS; - } - sleep_in_progress = 0; - return error; + return pm_suspend(PM_SUSPEND_MEM); case PMU_IOC_CAN_SLEEP: - if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) + if (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) < 0) return put_user(0, argp); else return put_user(1, argp); -#ifdef CONFIG_PMAC_BACKLIGHT - /* Backlight should have its own device or go via - * the fbdev - */ +#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY + /* Compatibility ioctl's for backlight */ case PMU_IOC_GET_BACKLIGHT: - if (sleep_in_progress) - return -EBUSY; - error = get_backlight_level(); - if (error < 0) - return error; - return put_user(error, argp); + { + int brightness; + + brightness = pmac_backlight_get_legacy_brightness(); + if (brightness < 0) + return brightness; + else + return put_user(brightness, argp); + + } case PMU_IOC_SET_BACKLIGHT: { - __u32 value; - if (sleep_in_progress) - return -EBUSY; - error = get_user(value, argp); - if (!error) - error = set_backlight_level(value); - return error; + int brightness; + + error = get_user(brightness, argp); + if (error) + return error; + + return pmac_backlight_set_legacy_brightness(brightness); } #ifdef CONFIG_INPUT_ADBHID case PMU_IOC_GRAB_BACKLIGHT: { - unsigned long flags; + struct pmu_private *pp = filp->private_data; + if (pp->backlight_locker) return 0; + pp->backlight_locker = 1; - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight++; - spin_unlock_irqrestore(&pmu_lock, flags); + pmac_backlight_disable(); + return 0; } #endif /* CONFIG_INPUT_ADBHID */ -#endif /* CONFIG_PMAC_BACKLIGHT */ +#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */ + case PMU_IOC_GET_MODEL: return put_user(pmu_kind, argp); case PMU_IOC_HAS_ADB: return put_user(pmu_has_adb, argp); } - return -EINVAL; + return error; } -static struct file_operations pmu_device_fops __pmacdata = { +static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, @@ -2962,21 +2315,23 @@ static struct file_operations pmu_device_fops __pmacdata = { .release = pmu_release, }; -static struct miscdevice pmu_device __pmacdata = { +static struct miscdevice pmu_device = { PMU_MINOR, "pmu", &pmu_device_fops }; -void pmu_device_init(void) +static int pmu_device_init(void) { if (!via) - return; + return 0; if (misc_register(&pmu_device) < 0) printk(KERN_ERR "via-pmu: cannot register misc device.\n"); + return 0; } -#endif /* CONFIG_PMAC_PBOOK */ +device_initcall(pmu_device_init); + #ifdef DEBUG_SLEEP -static inline void __pmac +static inline void polled_handshake(volatile unsigned char __iomem *via) { via[B] &= ~TREQ; eieio(); @@ -2987,7 +2342,7 @@ polled_handshake(volatile unsigned char __iomem *via) ; } -static inline void __pmac +static inline void polled_send_byte(volatile unsigned char __iomem *via, int x) { via[ACR] |= SR_OUT | SR_EXT; eieio(); @@ -2995,7 +2350,7 @@ polled_send_byte(volatile unsigned char __iomem *via, int x) polled_handshake(via); } -static inline int __pmac +static inline int polled_recv_byte(volatile unsigned char __iomem *via) { int x; @@ -3007,7 +2362,7 @@ polled_recv_byte(volatile unsigned char __iomem *via) return x; } -int __pmac +int pmu_polled_request(struct adb_request *req) { unsigned long flags; @@ -3046,26 +2401,59 @@ pmu_polled_request(struct adb_request *req) local_irq_restore(flags); return 0; } -#endif /* DEBUG_SLEEP */ +/* N.B. This doesn't work on the 3400 */ +void pmu_blink(int n) +{ + struct adb_request req; -/* FIXME: This is a temporary set of callbacks to enable us - * to do suspend-to-disk. - */ + memset(&req, 0, sizeof(req)); -#ifdef CONFIG_PM + for (; n > 0; --n) { + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 1; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 0; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); + } + mdelay(50); +} +#endif /* DEBUG_SLEEP */ -static int pmu_sys_suspended = 0; +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) +int pmu_sys_suspended; static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) { - if (state != PM_SUSPEND_DISK || pmu_sys_suspended) + if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended) return 0; - /* Suspend PMU event interrupts */ + /* Suspend PMU event interrupts */\ pmu_suspend(); - pmu_sys_suspended = 1; + +#ifdef CONFIG_PMAC_BACKLIGHT + /* Tell backlight code not to muck around with the chip anymore */ + pmu_backlight_set_sleep(1); +#endif + return 0; } @@ -3080,30 +2468,32 @@ static int pmu_sys_resume(struct sys_device *sysdev) pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); pmu_wait_complete(&req); +#ifdef CONFIG_PMAC_BACKLIGHT + /* Tell backlight code it can use the chip again */ + pmu_backlight_set_sleep(0); +#endif /* Resume PMU event interrupts */ pmu_resume(); - pmu_sys_suspended = 0; return 0; } -#endif /* CONFIG_PM */ +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ static struct sysdev_class pmu_sysclass = { - set_kset_name("pmu"), + .name = "pmu", }; static struct sys_device device_pmu = { - .id = 0, .cls = &pmu_sysclass, }; static struct sysdev_driver driver_pmu = { -#ifdef CONFIG_PM +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) .suspend = &pmu_sys_suspend, .resume = &pmu_sys_resume, -#endif /* CONFIG_PM */ +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ }; static int __init init_pmu_sysfs(void) @@ -3131,22 +2521,17 @@ static int __init init_pmu_sysfs(void) subsys_initcall(init_pmu_sysfs); EXPORT_SYMBOL(pmu_request); +EXPORT_SYMBOL(pmu_queue_request); EXPORT_SYMBOL(pmu_poll); EXPORT_SYMBOL(pmu_poll_adb); EXPORT_SYMBOL(pmu_wait_complete); EXPORT_SYMBOL(pmu_suspend); EXPORT_SYMBOL(pmu_resume); EXPORT_SYMBOL(pmu_unlock); -EXPORT_SYMBOL(pmu_i2c_combined_read); -EXPORT_SYMBOL(pmu_i2c_stdsub_write); -EXPORT_SYMBOL(pmu_i2c_simple_read); -EXPORT_SYMBOL(pmu_i2c_simple_write); -#ifdef CONFIG_PMAC_PBOOK -EXPORT_SYMBOL(pmu_register_sleep_notifier); -EXPORT_SYMBOL(pmu_unregister_sleep_notifier); +#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); EXPORT_SYMBOL(pmu_batteries); EXPORT_SYMBOL(pmu_power_flags); -#endif /* CONFIG_PMAC_PBOOK */ +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */