Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 4dfd459b738cf1f65b3eac4e0a9b19bc93cc91c6 163 lines 4.3 kB view raw
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/kernel.h> 23#include <linux/errno.h> 24#include <linux/input.h> 25#include <linux/interrupt.h> 26#include <linux/platform_device.h> 27#include <linux/workqueue.h> 28#include <linux/mfd/wm831x/core.h> 29 30struct wm831x_on { 31 struct input_dev *dev; 32 struct delayed_work work; 33 struct wm831x *wm831x; 34}; 35 36/* 37 * The chip gives us an interrupt when the ON pin is asserted but we 38 * then need to poll to see when the pin is deasserted. 39 */ 40static void wm831x_poll_on(struct work_struct *work) 41{ 42 struct wm831x_on *wm831x_on = container_of(work, struct wm831x_on, 43 work.work); 44 struct wm831x *wm831x = wm831x_on->wm831x; 45 int poll, ret; 46 47 ret = wm831x_reg_read(wm831x, WM831X_ON_PIN_CONTROL); 48 if (ret >= 0) { 49 poll = !(ret & WM831X_ON_PIN_STS); 50 51 input_report_key(wm831x_on->dev, KEY_POWER, poll); 52 input_sync(wm831x_on->dev); 53 } else { 54 dev_err(wm831x->dev, "Failed to read ON status: %d\n", ret); 55 poll = 1; 56 } 57 58 if (poll) 59 schedule_delayed_work(&wm831x_on->work, 100); 60} 61 62static irqreturn_t wm831x_on_irq(int irq, void *data) 63{ 64 struct wm831x_on *wm831x_on = data; 65 66 schedule_delayed_work(&wm831x_on->work, 0); 67 68 return IRQ_HANDLED; 69} 70 71static int __devinit wm831x_on_probe(struct platform_device *pdev) 72{ 73 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 74 struct wm831x_on *wm831x_on; 75 int irq = platform_get_irq(pdev, 0); 76 int ret; 77 78 wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL); 79 if (!wm831x_on) { 80 dev_err(&pdev->dev, "Can't allocate data\n"); 81 return -ENOMEM; 82 } 83 84 wm831x_on->wm831x = wm831x; 85 INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on); 86 87 wm831x_on->dev = input_allocate_device(); 88 if (!wm831x_on->dev) { 89 dev_err(&pdev->dev, "Can't allocate input dev\n"); 90 ret = -ENOMEM; 91 goto err; 92 } 93 94 wm831x_on->dev->evbit[0] = BIT_MASK(EV_KEY); 95 wm831x_on->dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 96 wm831x_on->dev->name = "wm831x_on"; 97 wm831x_on->dev->phys = "wm831x_on/input0"; 98 wm831x_on->dev->dev.parent = &pdev->dev; 99 100 ret = wm831x_request_irq(wm831x, irq, wm831x_on_irq, 101 IRQF_TRIGGER_RISING, "wm831x_on", wm831x_on); 102 if (ret < 0) { 103 dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret); 104 goto err_input_dev; 105 } 106 ret = input_register_device(wm831x_on->dev); 107 if (ret) { 108 dev_dbg(&pdev->dev, "Can't register input device: %d\n", ret); 109 goto err_irq; 110 } 111 112 platform_set_drvdata(pdev, wm831x_on); 113 114 return 0; 115 116err_irq: 117 wm831x_free_irq(wm831x, irq, NULL); 118err_input_dev: 119 input_free_device(wm831x_on->dev); 120err: 121 kfree(wm831x_on); 122 return ret; 123} 124 125static int __devexit wm831x_on_remove(struct platform_device *pdev) 126{ 127 struct wm831x_on *wm831x_on = platform_get_drvdata(pdev); 128 int irq = platform_get_irq(pdev, 0); 129 130 wm831x_free_irq(wm831x_on->wm831x, irq, wm831x_on); 131 cancel_delayed_work_sync(&wm831x_on->work); 132 input_unregister_device(wm831x_on->dev); 133 kfree(wm831x_on); 134 135 return 0; 136} 137 138static struct platform_driver wm831x_on_driver = { 139 .probe = wm831x_on_probe, 140 .remove = __devexit_p(wm831x_on_remove), 141 .driver = { 142 .name = "wm831x-on", 143 .owner = THIS_MODULE, 144 }, 145}; 146 147static int __init wm831x_on_init(void) 148{ 149 return platform_driver_register(&wm831x_on_driver); 150} 151module_init(wm831x_on_init); 152 153static void __exit wm831x_on_exit(void) 154{ 155 platform_driver_unregister(&wm831x_on_driver); 156} 157module_exit(wm831x_on_exit); 158 159MODULE_ALIAS("platform:wm831x-on"); 160MODULE_DESCRIPTION("WM831x ON pin"); 161MODULE_LICENSE("GPL"); 162MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 163