1/** 2 * max8925_onkey.c - MAX8925 ONKEY driver 3 * 4 * Copyright (C) 2009 Marvell International Ltd. 5 * Haojian Zhuang <haojian.zhuang@marvell.com> 6 * 7 * This file is subject to the terms and conditions of the GNU General 8 * Public License. See the file "COPYING" in the main directory of this 9 * archive for more details. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21#include <linux/kernel.h> 22#include <linux/module.h> 23#include <linux/platform_device.h> 24#include <linux/i2c.h> 25#include <linux/input.h> 26#include <linux/interrupt.h> 27#include <linux/mfd/max8925.h> 28#include <linux/slab.h> 29 30#define HARDRESET_EN (1 << 7) 31#define PWREN_EN (1 << 7) 32 33struct max8925_onkey_info { 34 struct input_dev *idev; 35 struct i2c_client *i2c; 36 int irq; 37}; 38 39/* 40 * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds. 41 * max8925_set_bits() operates I2C bus and may sleep. So implement 42 * it in thread IRQ handler. 43 */ 44static irqreturn_t max8925_onkey_handler(int irq, void *data) 45{ 46 struct max8925_onkey_info *info = data; 47 48 input_report_key(info->idev, KEY_POWER, 1); 49 input_sync(info->idev); 50 51 /* Enable hardreset to halt if system isn't shutdown on time */ 52 max8925_set_bits(info->i2c, MAX8925_SYSENSEL, 53 HARDRESET_EN, HARDRESET_EN); 54 55 return IRQ_HANDLED; 56} 57 58static int __devinit max8925_onkey_probe(struct platform_device *pdev) 59{ 60 struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); 61 struct max8925_onkey_info *info; 62 int error; 63 64 info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); 65 if (!info) 66 return -ENOMEM; 67 68 info->i2c = chip->i2c; 69 info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC; 70 71 info->idev = input_allocate_device(); 72 if (!info->idev) { 73 dev_err(chip->dev, "Failed to allocate input dev\n"); 74 error = -ENOMEM; 75 goto out_input; 76 } 77 78 info->idev->name = "max8925_on"; 79 info->idev->phys = "max8925_on/input0"; 80 info->idev->id.bustype = BUS_I2C; 81 info->idev->dev.parent = &pdev->dev; 82 info->idev->evbit[0] = BIT_MASK(EV_KEY); 83 info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 84 85 error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler, 86 IRQF_ONESHOT, "onkey", info); 87 if (error < 0) { 88 dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", 89 info->irq, error); 90 goto out_irq; 91 } 92 93 error = input_register_device(info->idev); 94 if (error) { 95 dev_err(chip->dev, "Can't register input device: %d\n", error); 96 goto out; 97 } 98 99 platform_set_drvdata(pdev, info); 100 101 return 0; 102 103out: 104 free_irq(info->irq, info); 105out_irq: 106 input_free_device(info->idev); 107out_input: 108 kfree(info); 109 return error; 110} 111 112static int __devexit max8925_onkey_remove(struct platform_device *pdev) 113{ 114 struct max8925_onkey_info *info = platform_get_drvdata(pdev); 115 116 free_irq(info->irq, info); 117 input_unregister_device(info->idev); 118 kfree(info); 119 120 platform_set_drvdata(pdev, NULL); 121 122 return 0; 123} 124 125static struct platform_driver max8925_onkey_driver = { 126 .driver = { 127 .name = "max8925-onkey", 128 .owner = THIS_MODULE, 129 }, 130 .probe = max8925_onkey_probe, 131 .remove = __devexit_p(max8925_onkey_remove), 132}; 133 134static int __init max8925_onkey_init(void) 135{ 136 return platform_driver_register(&max8925_onkey_driver); 137} 138module_init(max8925_onkey_init); 139 140static void __exit max8925_onkey_exit(void) 141{ 142 platform_driver_unregister(&max8925_onkey_driver); 143} 144module_exit(max8925_onkey_exit); 145 146MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver"); 147MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 148MODULE_LICENSE("GPL"); 149