diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 3 | ||||
-rw-r--r-- | drivers/input/keyboard/sh_keysc.c | 17 | ||||
-rw-r--r-- | drivers/input/touchscreen/migor_ts.c | 23 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 36 | ||||
-rw-r--r-- | drivers/sh/intc.c | 68 |
5 files changed, 144 insertions, 3 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 7783b42f691..1c92c39a53a 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -465,7 +465,6 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, ced->set_mode = sh_cmt_clock_event_mode; pr_info("sh_cmt: %s used for clock events\n", ced->name); - ced->mult = 1; /* work around misplaced WARN_ON() in clockevents.c */ clockevents_register_device(ced); } @@ -557,7 +556,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) cfg->clockevent_rating, cfg->clocksource_rating); err2: - free_irq(irq, p); + remove_irq(irq, &p->irqaction); err1: iounmap(p->mapbase); err0: diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index e1480fb11de..cea70e6a103 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -259,12 +259,15 @@ static int sh_keysc_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct sh_keysc_priv *priv = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); unsigned short value; value = ioread16(priv->iomem_base + KYCR1_OFFS); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { value |= 0x80; + enable_irq_wake(irq); + } else value &= ~0x80; @@ -272,8 +275,20 @@ static int sh_keysc_suspend(struct device *dev) return 0; } +static int sh_keysc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 0); + + if (device_may_wakeup(dev)) + disable_irq_wake(irq); + + return 0; +} + static struct dev_pm_ops sh_keysc_dev_pm_ops = { .suspend = sh_keysc_suspend, + .resume = sh_keysc_resume, }; struct platform_driver sh_keysc_device_driver = { diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 504ca11749a..141dd584330 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -198,6 +198,7 @@ static int migor_ts_probe(struct i2c_client *client, goto err2; } + device_init_wakeup(&client->dev, 1); return 0; err2: @@ -224,6 +225,26 @@ static int migor_ts_remove(struct i2c_client *client) return 0; } +static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(priv->irq); + + return 0; +} + +static int migor_ts_resume(struct i2c_client *client) +{ + struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(priv->irq); + + return 0; +} + static const struct i2c_device_id migor_ts_id[] = { { "migor_ts", 0 }, { } @@ -236,6 +257,8 @@ static struct i2c_driver migor_ts_driver = { }, .probe = migor_ts_probe, .remove = migor_ts_remove, + .suspend = migor_ts_suspend, + .resume = migor_ts_resume, .id_table = migor_ts_id, }; diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 4898f7fe851..9b1ff12bf94 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -795,10 +795,46 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) return 0; } + +static void sh_rtc_set_irq_wake(struct device *dev, int enabled) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + + set_irq_wake(rtc->periodic_irq, enabled); + if (rtc->carry_irq > 0) { + set_irq_wake(rtc->carry_irq, enabled); + set_irq_wake(rtc->alarm_irq, enabled); + } + +} + +static int sh_rtc_suspend(struct device *dev) +{ + if (device_may_wakeup(dev)) + sh_rtc_set_irq_wake(dev, 1); + + return 0; +} + +static int sh_rtc_resume(struct device *dev) +{ + if (device_may_wakeup(dev)) + sh_rtc_set_irq_wake(dev, 0); + + return 0; +} + +static struct dev_pm_ops sh_rtc_dev_pm_ops = { + .suspend = sh_rtc_suspend, + .resume = sh_rtc_resume, +}; + static struct platform_driver sh_rtc_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .pm = &sh_rtc_dev_pm_ops, }, .probe = sh_rtc_probe, .remove = __devexit_p(sh_rtc_remove), diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 2269fbcaa18..7fb9b5c4669 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -22,6 +22,8 @@ #include <linux/interrupt.h> #include <linux/bootmem.h> #include <linux/sh_intc.h> +#include <linux/sysdev.h> +#include <linux/list.h> #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ @@ -40,6 +42,8 @@ struct intc_handle_int { }; struct intc_desc_int { + struct list_head list; + struct sys_device sysdev; unsigned long *reg; #ifdef CONFIG_SMP unsigned long *smp; @@ -52,6 +56,8 @@ struct intc_desc_int { struct irq_chip chip; }; +static LIST_HEAD(intc_list); + #ifdef CONFIG_SMP #define IS_SMP(x) x.smp #define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) @@ -232,6 +238,11 @@ static void intc_disable(unsigned int irq) } } +static int intc_set_wake(unsigned int irq, unsigned int on) +{ + return 0; /* allow wakeup, but setup hardware in intc_suspend() */ +} + #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) static void intc_mask_ack(unsigned int irq) { @@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc) d = alloc_bootmem(sizeof(*d)); + INIT_LIST_HEAD(&d->list); + list_add(&d->list, &intc_list); + d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; @@ -707,7 +721,11 @@ void __init register_intc_controller(struct intc_desc *desc) d->chip.mask = intc_disable; d->chip.unmask = intc_enable; d->chip.mask_ack = intc_disable; + d->chip.enable = intc_enable; + d->chip.disable = intc_disable; + d->chip.shutdown = intc_disable; d->chip.set_type = intc_set_sense; + d->chip.set_wake = intc_set_wake; #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) if (desc->ack_regs) { @@ -758,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc) intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); } } + +static int intc_suspend(struct sys_device *dev, pm_message_t state) +{ + struct intc_desc_int *d; + struct irq_desc *desc; + int irq; + + /* get intc controller associated with this sysdev */ + d = container_of(dev, struct intc_desc_int, sysdev); + + /* enable wakeup irqs belonging to this intc controller */ + for_each_irq_desc(irq, desc) { + if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip)) + intc_enable(irq); + } + + return 0; +} + +static struct sysdev_class intc_sysdev_class = { + .name = "intc", + .suspend = intc_suspend, +}; + +/* register this intc as sysdev to allow suspend/resume */ +static int __init register_intc_sysdevs(void) +{ + struct intc_desc_int *d; + int error; + int id = 0; + + error = sysdev_class_register(&intc_sysdev_class); + if (!error) { + list_for_each_entry(d, &intc_list, list) { + d->sysdev.id = id; + d->sysdev.cls = &intc_sysdev_class; + error = sysdev_register(&d->sysdev); + if (error) + break; + id++; + } + } + + if (error) + pr_warning("intc: sysdev registration error\n"); + + return error; +} + +device_initcall(register_intc_sysdevs); |