tps65218-pwrbutton.c (4274B)
1/* 2 * Texas Instruments' TPS65217 and 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 * Author: Marcin Niestroj <m.niestroj@grinn-global.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 13 * kind, whether express or implied; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/init.h> 19#include <linux/input.h> 20#include <linux/interrupt.h> 21#include <linux/kernel.h> 22#include <linux/mfd/tps65217.h> 23#include <linux/mfd/tps65218.h> 24#include <linux/module.h> 25#include <linux/of.h> 26#include <linux/platform_device.h> 27#include <linux/regmap.h> 28#include <linux/slab.h> 29 30struct tps6521x_data { 31 unsigned int reg_status; 32 unsigned int pb_mask; 33 const char *name; 34}; 35 36static const struct tps6521x_data tps65217_data = { 37 .reg_status = TPS65217_REG_STATUS, 38 .pb_mask = TPS65217_STATUS_PB, 39 .name = "tps65217_pwrbutton", 40}; 41 42static const struct tps6521x_data tps65218_data = { 43 .reg_status = TPS65218_REG_STATUS, 44 .pb_mask = TPS65218_STATUS_PB_STATE, 45 .name = "tps65218_pwrbutton", 46}; 47 48struct tps6521x_pwrbutton { 49 struct device *dev; 50 struct regmap *regmap; 51 struct input_dev *idev; 52 const struct tps6521x_data *data; 53 char phys[32]; 54}; 55 56static const struct of_device_id of_tps6521x_pb_match[] = { 57 { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data }, 58 { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data }, 59 { }, 60}; 61MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match); 62 63static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr) 64{ 65 struct tps6521x_pwrbutton *pwr = _pwr; 66 const struct tps6521x_data *tps_data = pwr->data; 67 unsigned int reg; 68 int error; 69 70 error = regmap_read(pwr->regmap, tps_data->reg_status, ®); 71 if (error) { 72 dev_err(pwr->dev, "can't read register: %d\n", error); 73 goto out; 74 } 75 76 if (reg & tps_data->pb_mask) { 77 input_report_key(pwr->idev, KEY_POWER, 1); 78 pm_wakeup_event(pwr->dev, 0); 79 } else { 80 input_report_key(pwr->idev, KEY_POWER, 0); 81 } 82 83 input_sync(pwr->idev); 84 85out: 86 return IRQ_HANDLED; 87} 88 89static int tps6521x_pb_probe(struct platform_device *pdev) 90{ 91 struct device *dev = &pdev->dev; 92 struct tps6521x_pwrbutton *pwr; 93 struct input_dev *idev; 94 const struct of_device_id *match; 95 int error; 96 int irq; 97 98 match = of_match_node(of_tps6521x_pb_match, dev->of_node); 99 if (!match) 100 return -ENXIO; 101 102 pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); 103 if (!pwr) 104 return -ENOMEM; 105 106 pwr->data = match->data; 107 108 idev = devm_input_allocate_device(dev); 109 if (!idev) 110 return -ENOMEM; 111 112 idev->name = pwr->data->name; 113 snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", 114 pwr->data->name); 115 idev->phys = pwr->phys; 116 idev->dev.parent = dev; 117 idev->id.bustype = BUS_I2C; 118 119 input_set_capability(idev, EV_KEY, KEY_POWER); 120 121 pwr->regmap = dev_get_regmap(dev->parent, NULL); 122 pwr->dev = dev; 123 pwr->idev = idev; 124 device_init_wakeup(dev, true); 125 126 irq = platform_get_irq(pdev, 0); 127 if (irq < 0) 128 return -EINVAL; 129 130 error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq, 131 IRQF_TRIGGER_RISING | 132 IRQF_TRIGGER_FALLING | 133 IRQF_ONESHOT, 134 pwr->data->name, pwr); 135 if (error) { 136 dev_err(dev, "failed to request IRQ #%d: %d\n", irq, error); 137 return error; 138 } 139 140 error= input_register_device(idev); 141 if (error) { 142 dev_err(dev, "Can't register power button: %d\n", error); 143 return error; 144 } 145 146 return 0; 147} 148 149static const struct platform_device_id tps6521x_pwrbtn_id_table[] = { 150 { "tps65218-pwrbutton", }, 151 { "tps65217-pwrbutton", }, 152 { /* sentinel */ } 153}; 154MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table); 155 156static struct platform_driver tps6521x_pb_driver = { 157 .probe = tps6521x_pb_probe, 158 .driver = { 159 .name = "tps6521x_pwrbutton", 160 .of_match_table = of_tps6521x_pb_match, 161 }, 162 .id_table = tps6521x_pwrbtn_id_table, 163}; 164module_platform_driver(tps6521x_pb_driver); 165 166MODULE_DESCRIPTION("TPS6521X Power Button"); 167MODULE_LICENSE("GPL v2"); 168MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");