1/* 2 * Texas Instruments' TPS65218 Power Button Input Driver 3 * 4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ 5 * Author: Felipe Balbi <balbi@ti.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12 * kind, whether express or implied; without even the implied warranty 13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/init.h> 18#include <linux/input.h> 19#include <linux/interrupt.h> 20#include <linux/kernel.h> 21#include <linux/mfd/tps65218.h> 22#include <linux/module.h> 23#include <linux/of.h> 24#include <linux/platform_device.h> 25#include <linux/slab.h> 26 27struct tps65218_pwrbutton { 28 struct device *dev; 29 struct tps65218 *tps; 30 struct input_dev *idev; 31}; 32 33static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) 34{ 35 struct tps65218_pwrbutton *pwr = _pwr; 36 unsigned int reg; 37 int error; 38 39 error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); 40 if (error) { 41 dev_err(pwr->dev, "can't read register: %d\n", error); 42 goto out; 43 } 44 45 if (reg & TPS65218_STATUS_PB_STATE) { 46 input_report_key(pwr->idev, KEY_POWER, 1); 47 pm_wakeup_event(pwr->dev, 0); 48 } else { 49 input_report_key(pwr->idev, KEY_POWER, 0); 50 } 51 52 input_sync(pwr->idev); 53 54out: 55 return IRQ_HANDLED; 56} 57 58static int tps65218_pwron_probe(struct platform_device *pdev) 59{ 60 struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); 61 struct device *dev = &pdev->dev; 62 struct tps65218_pwrbutton *pwr; 63 struct input_dev *idev; 64 int error; 65 int irq; 66 67 pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); 68 if (!pwr) 69 return -ENOMEM; 70 71 idev = devm_input_allocate_device(dev); 72 if (!idev) 73 return -ENOMEM; 74 75 idev->name = "tps65218_pwrbutton"; 76 idev->phys = "tps65218_pwrbutton/input0"; 77 idev->dev.parent = dev; 78 idev->id.bustype = BUS_I2C; 79 80 input_set_capability(idev, EV_KEY, KEY_POWER); 81 82 pwr->tps = tps; 83 pwr->dev = dev; 84 pwr->idev = idev; 85 platform_set_drvdata(pdev, pwr); 86 device_init_wakeup(dev, true); 87 88 irq = platform_get_irq(pdev, 0); 89 error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, 90 IRQF_TRIGGER_RISING | 91 IRQF_TRIGGER_FALLING | 92 IRQF_ONESHOT, 93 "tps65218-pwrbutton", pwr); 94 if (error) { 95 dev_err(dev, "failed to request IRQ #%d: %d\n", 96 irq, error); 97 return error; 98 } 99 100 error= input_register_device(idev); 101 if (error) { 102 dev_err(dev, "Can't register power button: %d\n", error); 103 return error; 104 } 105 106 return 0; 107} 108 109static const struct of_device_id of_tps65218_pwr_match[] = { 110 { .compatible = "ti,tps65218-pwrbutton" }, 111 { }, 112}; 113MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); 114 115static struct platform_driver tps65218_pwron_driver = { 116 .probe = tps65218_pwron_probe, 117 .driver = { 118 .name = "tps65218_pwrbutton", 119 .of_match_table = of_tps65218_pwr_match, 120 }, 121}; 122module_platform_driver(tps65218_pwron_driver); 123 124MODULE_DESCRIPTION("TPS65218 Power Button"); 125MODULE_LICENSE("GPL v2"); 126MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 127