1 /** 2 * wm831x-on.c - WM831X ON pin driver 3 * 4 * Copyright (C) 2009 Wolfson Microelectronics plc 5 * 6 * This file is subject to the terms and conditions of the GNU General 7 * Public License. See the file "COPYING" in the main directory of this 8 * archive for more details. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20 #include <linux/module.h> 21 #include <linux/init.h> 22 #include <linux/slab.h> 23 #include <linux/kernel.h> 24 #include <linux/errno.h> 25 #include <linux/input.h> 26 #include <linux/interrupt.h> 27 #include <linux/platform_device.h> 28 #include <linux/workqueue.h> 29 #include <linux/mfd/wm831x/core.h> 30 31 struct wm831x_on { 32 struct input_dev *dev; 33 struct delayed_work work; 34 struct wm831x *wm831x; 35 }; 36 37 /* 38 * The chip gives us an interrupt when the ON pin is asserted but we 39 * then need to poll to see when the pin is deasserted. 40 */ 41 static void wm831x_poll_on(struct work_struct *work) 42 { 43 struct wm831x_on *wm831x_on = container_of(work, struct wm831x_on, 44 work.work); 45 struct wm831x *wm831x = wm831x_on->wm831x; 46 int poll, ret; 47 48 ret = wm831x_reg_read(wm831x, WM831X_ON_PIN_CONTROL); 49 if (ret >= 0) { 50 poll = !(ret & WM831X_ON_PIN_STS); 51 52 input_report_key(wm831x_on->dev, KEY_POWER, poll); 53 input_sync(wm831x_on->dev); 54 } else { 55 dev_err(wm831x->dev, "Failed to read ON status: %d\n", ret); 56 poll = 1; 57 } 58 59 if (poll) 60 schedule_delayed_work(&wm831x_on->work, 100); 61 } 62 63 static irqreturn_t wm831x_on_irq(int irq, void *data) 64 { 65 struct wm831x_on *wm831x_on = data; 66 67 schedule_delayed_work(&wm831x_on->work, 0); 68 69 return IRQ_HANDLED; 70 } 71 72 static int __devinit wm831x_on_probe(struct platform_device *pdev) 73 { 74 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 75 struct wm831x_on *wm831x_on; 76 int irq = platform_get_irq(pdev, 0); 77 int ret; 78 79 wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL); 80 if (!wm831x_on) { 81 dev_err(&pdev->dev, "Can't allocate data\n"); 82 return -ENOMEM; 83 } 84 85 wm831x_on->wm831x = wm831x; 86 INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on); 87 88 wm831x_on->dev = input_allocate_device(); 89 if (!wm831x_on->dev) { 90 dev_err(&pdev->dev, "Can't allocate input dev\n"); 91 ret = -ENOMEM; 92 goto err; 93 } 94 95 wm831x_on->dev->evbit[0] = BIT_MASK(EV_KEY); 96 wm831x_on->dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 97 wm831x_on->dev->name = "wm831x_on"; 98 wm831x_on->dev->phys = "wm831x_on/input0"; 99 wm831x_on->dev->dev.parent = &pdev->dev; 100 101 ret = request_threaded_irq(irq, NULL, wm831x_on_irq, 102 IRQF_TRIGGER_RISING, "wm831x_on", 103 wm831x_on); 104 if (ret < 0) { 105 dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret); 106 goto err_input_dev; 107 } 108 ret = input_register_device(wm831x_on->dev); 109 if (ret) { 110 dev_dbg(&pdev->dev, "Can't register input device: %d\n", ret); 111 goto err_irq; 112 } 113 114 platform_set_drvdata(pdev, wm831x_on); 115 116 return 0; 117 118 err_irq: 119 free_irq(irq, wm831x_on); 120 err_input_dev: 121 input_free_device(wm831x_on->dev); 122 err: 123 kfree(wm831x_on); 124 return ret; 125 } 126 127 static int __devexit wm831x_on_remove(struct platform_device *pdev) 128 { 129 struct wm831x_on *wm831x_on = platform_get_drvdata(pdev); 130 int irq = platform_get_irq(pdev, 0); 131 132 free_irq(irq, wm831x_on); 133 cancel_delayed_work_sync(&wm831x_on->work); 134 input_unregister_device(wm831x_on->dev); 135 kfree(wm831x_on); 136 137 return 0; 138 } 139 140 static struct platform_driver wm831x_on_driver = { 141 .probe = wm831x_on_probe, 142 .remove = __devexit_p(wm831x_on_remove), 143 .driver = { 144 .name = "wm831x-on", 145 .owner = THIS_MODULE, 146 }, 147 }; 148 module_platform_driver(wm831x_on_driver); 149 150 MODULE_ALIAS("platform:wm831x-on"); 151 MODULE_DESCRIPTION("WM831x ON pin"); 152 MODULE_LICENSE("GPL"); 153 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 154 155