15fafed3eSFelipe Balbi /* 2722dc546SMarcin Niestroj * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver 35fafed3eSFelipe Balbi * 45fafed3eSFelipe Balbi * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ 55fafed3eSFelipe Balbi * Author: Felipe Balbi <balbi@ti.com> 6722dc546SMarcin Niestroj * Author: Marcin Niestroj <m.niestroj@grinn-global.com> 75fafed3eSFelipe Balbi * 85fafed3eSFelipe Balbi * This program is free software; you can redistribute it and/or modify 95fafed3eSFelipe Balbi * it under the terms of the GNU General Public License version 2 as 105fafed3eSFelipe Balbi * published by the Free Software Foundation. 115fafed3eSFelipe Balbi * 125fafed3eSFelipe Balbi * This program is distributed "as is" WITHOUT ANY WARRANTY of any 135fafed3eSFelipe Balbi * kind, whether express or implied; without even the implied warranty 145fafed3eSFelipe Balbi * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 155fafed3eSFelipe Balbi * GNU General Public License for more details. 165fafed3eSFelipe Balbi */ 175fafed3eSFelipe Balbi 185fafed3eSFelipe Balbi #include <linux/init.h> 195fafed3eSFelipe Balbi #include <linux/input.h> 205fafed3eSFelipe Balbi #include <linux/interrupt.h> 215fafed3eSFelipe Balbi #include <linux/kernel.h> 22722dc546SMarcin Niestroj #include <linux/mfd/tps65217.h> 235fafed3eSFelipe Balbi #include <linux/mfd/tps65218.h> 245fafed3eSFelipe Balbi #include <linux/module.h> 255fafed3eSFelipe Balbi #include <linux/of.h> 265fafed3eSFelipe Balbi #include <linux/platform_device.h> 27722dc546SMarcin Niestroj #include <linux/regmap.h> 285fafed3eSFelipe Balbi #include <linux/slab.h> 295fafed3eSFelipe Balbi 30722dc546SMarcin Niestroj struct tps6521x_data { 31722dc546SMarcin Niestroj unsigned int reg_status; 32722dc546SMarcin Niestroj unsigned int pb_mask; 33722dc546SMarcin Niestroj const char *name; 345fafed3eSFelipe Balbi }; 355fafed3eSFelipe Balbi 36722dc546SMarcin Niestroj static const struct tps6521x_data tps65217_data = { 37722dc546SMarcin Niestroj .reg_status = TPS65217_REG_STATUS, 38722dc546SMarcin Niestroj .pb_mask = TPS65217_STATUS_PB, 39722dc546SMarcin Niestroj .name = "tps65217_pwrbutton", 40722dc546SMarcin Niestroj }; 41722dc546SMarcin Niestroj 42722dc546SMarcin Niestroj static const struct tps6521x_data tps65218_data = { 43722dc546SMarcin Niestroj .reg_status = TPS65218_REG_STATUS, 44722dc546SMarcin Niestroj .pb_mask = TPS65218_STATUS_PB_STATE, 45722dc546SMarcin Niestroj .name = "tps65218_pwrbutton", 46722dc546SMarcin Niestroj }; 47722dc546SMarcin Niestroj 48722dc546SMarcin Niestroj struct tps6521x_pwrbutton { 49722dc546SMarcin Niestroj struct device *dev; 50722dc546SMarcin Niestroj struct regmap *regmap; 51722dc546SMarcin Niestroj struct input_dev *idev; 52722dc546SMarcin Niestroj const struct tps6521x_data *data; 53722dc546SMarcin Niestroj char phys[32]; 54722dc546SMarcin Niestroj }; 55722dc546SMarcin Niestroj 56722dc546SMarcin Niestroj static const struct of_device_id of_tps6521x_pb_match[] = { 57722dc546SMarcin Niestroj { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data }, 58722dc546SMarcin Niestroj { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data }, 59722dc546SMarcin Niestroj { }, 60722dc546SMarcin Niestroj }; 61722dc546SMarcin Niestroj MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match); 62722dc546SMarcin Niestroj 63722dc546SMarcin Niestroj static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr) 645fafed3eSFelipe Balbi { 65722dc546SMarcin Niestroj struct tps6521x_pwrbutton *pwr = _pwr; 66722dc546SMarcin Niestroj const struct tps6521x_data *tps_data = pwr->data; 675fafed3eSFelipe Balbi unsigned int reg; 685fafed3eSFelipe Balbi int error; 695fafed3eSFelipe Balbi 70722dc546SMarcin Niestroj error = regmap_read(pwr->regmap, tps_data->reg_status, ®); 715fafed3eSFelipe Balbi if (error) { 725fafed3eSFelipe Balbi dev_err(pwr->dev, "can't read register: %d\n", error); 735fafed3eSFelipe Balbi goto out; 745fafed3eSFelipe Balbi } 755fafed3eSFelipe Balbi 76722dc546SMarcin Niestroj if (reg & tps_data->pb_mask) { 775fafed3eSFelipe Balbi input_report_key(pwr->idev, KEY_POWER, 1); 785fafed3eSFelipe Balbi pm_wakeup_event(pwr->dev, 0); 795fafed3eSFelipe Balbi } else { 805fafed3eSFelipe Balbi input_report_key(pwr->idev, KEY_POWER, 0); 815fafed3eSFelipe Balbi } 825fafed3eSFelipe Balbi 835fafed3eSFelipe Balbi input_sync(pwr->idev); 845fafed3eSFelipe Balbi 855fafed3eSFelipe Balbi out: 865fafed3eSFelipe Balbi return IRQ_HANDLED; 875fafed3eSFelipe Balbi } 885fafed3eSFelipe Balbi 89722dc546SMarcin Niestroj static int tps6521x_pb_probe(struct platform_device *pdev) 905fafed3eSFelipe Balbi { 915fafed3eSFelipe Balbi struct device *dev = &pdev->dev; 92722dc546SMarcin Niestroj struct tps6521x_pwrbutton *pwr; 935fafed3eSFelipe Balbi struct input_dev *idev; 94722dc546SMarcin Niestroj const struct of_device_id *match; 955fafed3eSFelipe Balbi int error; 965fafed3eSFelipe Balbi int irq; 975fafed3eSFelipe Balbi 98722dc546SMarcin Niestroj match = of_match_node(of_tps6521x_pb_match, pdev->dev.of_node); 99722dc546SMarcin Niestroj if (!match) 100722dc546SMarcin Niestroj return -ENXIO; 101722dc546SMarcin Niestroj 1025fafed3eSFelipe Balbi pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); 1035fafed3eSFelipe Balbi if (!pwr) 1045fafed3eSFelipe Balbi return -ENOMEM; 1055fafed3eSFelipe Balbi 106722dc546SMarcin Niestroj pwr->data = match->data; 107722dc546SMarcin Niestroj 1085fafed3eSFelipe Balbi idev = devm_input_allocate_device(dev); 1095fafed3eSFelipe Balbi if (!idev) 1105fafed3eSFelipe Balbi return -ENOMEM; 1115fafed3eSFelipe Balbi 112722dc546SMarcin Niestroj idev->name = pwr->data->name; 113722dc546SMarcin Niestroj snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", 114722dc546SMarcin Niestroj pwr->data->name); 115722dc546SMarcin Niestroj idev->phys = pwr->phys; 1165fafed3eSFelipe Balbi idev->dev.parent = dev; 1175fafed3eSFelipe Balbi idev->id.bustype = BUS_I2C; 1185fafed3eSFelipe Balbi 1195fafed3eSFelipe Balbi input_set_capability(idev, EV_KEY, KEY_POWER); 1205fafed3eSFelipe Balbi 121722dc546SMarcin Niestroj pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL); 1225fafed3eSFelipe Balbi pwr->dev = dev; 1235fafed3eSFelipe Balbi pwr->idev = idev; 1245fafed3eSFelipe Balbi platform_set_drvdata(pdev, pwr); 1255fafed3eSFelipe Balbi device_init_wakeup(dev, true); 1265fafed3eSFelipe Balbi 1275fafed3eSFelipe Balbi irq = platform_get_irq(pdev, 0); 128722dc546SMarcin Niestroj if (irq < 0) { 129722dc546SMarcin Niestroj dev_err(dev, "No IRQ resource!\n"); 130722dc546SMarcin Niestroj return -EINVAL; 131722dc546SMarcin Niestroj } 132722dc546SMarcin Niestroj 133722dc546SMarcin Niestroj error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq, 1345fafed3eSFelipe Balbi IRQF_TRIGGER_RISING | 1355fafed3eSFelipe Balbi IRQF_TRIGGER_FALLING | 1365fafed3eSFelipe Balbi IRQF_ONESHOT, 137722dc546SMarcin Niestroj pwr->data->name, pwr); 1385fafed3eSFelipe Balbi if (error) { 1395fafed3eSFelipe Balbi dev_err(dev, "failed to request IRQ #%d: %d\n", 1405fafed3eSFelipe Balbi irq, error); 1415fafed3eSFelipe Balbi return error; 1425fafed3eSFelipe Balbi } 1435fafed3eSFelipe Balbi 1445fafed3eSFelipe Balbi error= input_register_device(idev); 1455fafed3eSFelipe Balbi if (error) { 1465fafed3eSFelipe Balbi dev_err(dev, "Can't register power button: %d\n", error); 1475fafed3eSFelipe Balbi return error; 1485fafed3eSFelipe Balbi } 1495fafed3eSFelipe Balbi 1505fafed3eSFelipe Balbi return 0; 1515fafed3eSFelipe Balbi } 1525fafed3eSFelipe Balbi 153722dc546SMarcin Niestroj static struct platform_driver tps6521x_pb_driver = { 154722dc546SMarcin Niestroj .probe = tps6521x_pb_probe, 1555fafed3eSFelipe Balbi .driver = { 156722dc546SMarcin Niestroj .name = "tps6521x_pwrbutton", 157722dc546SMarcin Niestroj .of_match_table = of_tps6521x_pb_match, 1585fafed3eSFelipe Balbi }, 1595fafed3eSFelipe Balbi }; 160722dc546SMarcin Niestroj module_platform_driver(tps6521x_pb_driver); 1615fafed3eSFelipe Balbi 162722dc546SMarcin Niestroj MODULE_DESCRIPTION("TPS6521X Power Button"); 1635fafed3eSFelipe Balbi MODULE_LICENSE("GPL v2"); 1645fafed3eSFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 165