aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-01-22 15:05:24 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-02-18 18:15:43 -0500
commit33237616771bfc29a97f17e74efe3799bb790343 (patch)
tree4ad660084434e190150dab67170d3b65cf2e8a3a
parenta3364409c4af8bae42d04def48dc11409787e503 (diff)
MFD: ucb1x00-core: add wakeup support
Add genirq wakeup support for the ucb1x00 device. This allows an attached gpio_keys driver to wakeup the system. Touchscreen is also possible. When there are no wakeup sources, ask the platform to assert the reset signal to avoid any unexpected behaviour; this also puts the reset signal at the right level when power is removed from the device. Acked-by: Jochen Friedrich <jochen@scram.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/mfd/ucb1x00-core.c59
-rw-r--r--include/linux/mfd/ucb1x00.h4
2 files changed, 63 insertions, 0 deletions
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 400604d38780..70f02daeb22a 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -362,12 +362,32 @@ static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
362 return 0; 362 return 0;
363} 363}
364 364
365static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
366{
367 struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
368 struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
369 unsigned mask = 1 << (data->irq - ucb->irq_base);
370
371 if (!pdata || !pdata->can_wakeup)
372 return -EINVAL;
373
374 raw_spin_lock(&ucb->irq_lock);
375 if (on)
376 ucb->irq_wake |= mask;
377 else
378 ucb->irq_wake &= ~mask;
379 raw_spin_unlock(&ucb->irq_lock);
380
381 return 0;
382}
383
365static struct irq_chip ucb1x00_irqchip = { 384static struct irq_chip ucb1x00_irqchip = {
366 .name = "ucb1x00", 385 .name = "ucb1x00",
367 .irq_ack = ucb1x00_irq_noop, 386 .irq_ack = ucb1x00_irq_noop,
368 .irq_mask = ucb1x00_irq_mask, 387 .irq_mask = ucb1x00_irq_mask,
369 .irq_unmask = ucb1x00_irq_unmask, 388 .irq_unmask = ucb1x00_irq_unmask,
370 .irq_set_type = ucb1x00_irq_set_type, 389 .irq_set_type = ucb1x00_irq_set_type,
390 .irq_set_wake = ucb1x00_irq_set_wake,
371}; 391};
372 392
373static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) 393static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
@@ -565,6 +585,9 @@ static int ucb1x00_probe(struct mcp *mcp)
565 585
566 mcp_set_drvdata(mcp, ucb); 586 mcp_set_drvdata(mcp, ucb);
567 587
588 if (pdata)
589 device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
590
568 INIT_LIST_HEAD(&ucb->devs); 591 INIT_LIST_HEAD(&ucb->devs);
569 mutex_lock(&ucb1x00_mutex); 592 mutex_lock(&ucb1x00_mutex);
570 list_add_tail(&ucb->node, &ucb1x00_devices); 593 list_add_tail(&ucb->node, &ucb1x00_devices);
@@ -648,6 +671,7 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
648 671
649static int ucb1x00_suspend(struct device *dev) 672static int ucb1x00_suspend(struct device *dev)
650{ 673{
674 struct ucb1x00_plat_data *pdata = dev->platform_data;
651 struct ucb1x00 *ucb = dev_get_drvdata(dev); 675 struct ucb1x00 *ucb = dev_get_drvdata(dev);
652 struct ucb1x00_dev *udev; 676 struct ucb1x00_dev *udev;
653 677
@@ -657,18 +681,53 @@ static int ucb1x00_suspend(struct device *dev)
657 udev->drv->suspend(udev); 681 udev->drv->suspend(udev);
658 } 682 }
659 mutex_unlock(&ucb1x00_mutex); 683 mutex_unlock(&ucb1x00_mutex);
684
685 if (ucb->irq_wake) {
686 unsigned long flags;
687
688 raw_spin_lock_irqsave(&ucb->irq_lock, flags);
689 ucb1x00_enable(ucb);
690 ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
691 ucb->irq_wake);
692 ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
693 ucb->irq_wake);
694 ucb1x00_disable(ucb);
695 raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
696
697 enable_irq_wake(ucb->irq);
698 } else if (pdata && pdata->reset)
699 pdata->reset(UCB_RST_SUSPEND);
700
660 return 0; 701 return 0;
661} 702}
662 703
663static int ucb1x00_resume(struct device *dev) 704static int ucb1x00_resume(struct device *dev)
664{ 705{
706 struct ucb1x00_plat_data *pdata = dev->platform_data;
665 struct ucb1x00 *ucb = dev_get_drvdata(dev); 707 struct ucb1x00 *ucb = dev_get_drvdata(dev);
666 struct ucb1x00_dev *udev; 708 struct ucb1x00_dev *udev;
667 709
710 if (!ucb->irq_wake && pdata && pdata->reset)
711 pdata->reset(UCB_RST_RESUME);
712
668 ucb1x00_enable(ucb); 713 ucb1x00_enable(ucb);
669 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 714 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
670 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); 715 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
716
717 if (ucb->irq_wake) {
718 unsigned long flags;
719
720 raw_spin_lock_irqsave(&ucb->irq_lock, flags);
721 ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
722 ucb->irq_mask);
723 ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
724 ucb->irq_mask);
725 raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
726
727 disable_irq_wake(ucb->irq);
728 }
671 ucb1x00_disable(ucb); 729 ucb1x00_disable(ucb);
730
672 mutex_lock(&ucb1x00_mutex); 731 mutex_lock(&ucb1x00_mutex);
673 list_for_each_entry(udev, &ucb->devs, dev_node) { 732 list_for_each_entry(udev, &ucb->devs, dev_node) {
674 if (udev->drv->resume) 733 if (udev->drv->resume)
diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
index 6fb907446c33..28af41756360 100644
--- a/include/linux/mfd/ucb1x00.h
+++ b/include/linux/mfd/ucb1x00.h
@@ -106,6 +106,8 @@
106 106
107enum ucb1x00_reset { 107enum ucb1x00_reset {
108 UCB_RST_PROBE, 108 UCB_RST_PROBE,
109 UCB_RST_RESUME,
110 UCB_RST_SUSPEND,
109 UCB_RST_REMOVE, 111 UCB_RST_REMOVE,
110 UCB_RST_PROBE_FAIL, 112 UCB_RST_PROBE_FAIL,
111}; 113};
@@ -114,6 +116,7 @@ struct ucb1x00_plat_data {
114 void (*reset)(enum ucb1x00_reset); 116 void (*reset)(enum ucb1x00_reset);
115 unsigned irq_base; 117 unsigned irq_base;
116 int gpio_base; 118 int gpio_base;
119 unsigned can_wakeup;
117}; 120};
118 121
119struct ucb1x00 { 122struct ucb1x00 {
@@ -130,6 +133,7 @@ struct ucb1x00 {
130 u16 irq_fal_enbl; 133 u16 irq_fal_enbl;
131 u16 irq_ris_enbl; 134 u16 irq_ris_enbl;
132 u16 irq_mask; 135 u16 irq_mask;
136 u16 irq_wake;
133 struct device dev; 137 struct device dev;
134 struct list_head node; 138 struct list_head node;
135 struct list_head devs; 139 struct list_head devs;