1*5a729246SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25fafed3eSFelipe Balbi /*
3722dc546SMarcin Niestroj * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver
45fafed3eSFelipe Balbi *
55fafed3eSFelipe Balbi * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
65fafed3eSFelipe Balbi * Author: Felipe Balbi <balbi@ti.com>
7722dc546SMarcin Niestroj * Author: Marcin Niestroj <m.niestroj@grinn-global.com>
85fafed3eSFelipe Balbi */
95fafed3eSFelipe Balbi
105fafed3eSFelipe Balbi #include <linux/init.h>
115fafed3eSFelipe Balbi #include <linux/input.h>
125fafed3eSFelipe Balbi #include <linux/interrupt.h>
135fafed3eSFelipe Balbi #include <linux/kernel.h>
14722dc546SMarcin Niestroj #include <linux/mfd/tps65217.h>
155fafed3eSFelipe Balbi #include <linux/mfd/tps65218.h>
165fafed3eSFelipe Balbi #include <linux/module.h>
175fafed3eSFelipe Balbi #include <linux/of.h>
185fafed3eSFelipe Balbi #include <linux/platform_device.h>
19722dc546SMarcin Niestroj #include <linux/regmap.h>
205fafed3eSFelipe Balbi #include <linux/slab.h>
215fafed3eSFelipe Balbi
22722dc546SMarcin Niestroj struct tps6521x_data {
23722dc546SMarcin Niestroj unsigned int reg_status;
24722dc546SMarcin Niestroj unsigned int pb_mask;
25722dc546SMarcin Niestroj const char *name;
265fafed3eSFelipe Balbi };
275fafed3eSFelipe Balbi
28722dc546SMarcin Niestroj static const struct tps6521x_data tps65217_data = {
29722dc546SMarcin Niestroj .reg_status = TPS65217_REG_STATUS,
30722dc546SMarcin Niestroj .pb_mask = TPS65217_STATUS_PB,
31722dc546SMarcin Niestroj .name = "tps65217_pwrbutton",
32722dc546SMarcin Niestroj };
33722dc546SMarcin Niestroj
34722dc546SMarcin Niestroj static const struct tps6521x_data tps65218_data = {
35722dc546SMarcin Niestroj .reg_status = TPS65218_REG_STATUS,
36722dc546SMarcin Niestroj .pb_mask = TPS65218_STATUS_PB_STATE,
37722dc546SMarcin Niestroj .name = "tps65218_pwrbutton",
38722dc546SMarcin Niestroj };
39722dc546SMarcin Niestroj
40722dc546SMarcin Niestroj struct tps6521x_pwrbutton {
41722dc546SMarcin Niestroj struct device *dev;
42722dc546SMarcin Niestroj struct regmap *regmap;
43722dc546SMarcin Niestroj struct input_dev *idev;
44722dc546SMarcin Niestroj const struct tps6521x_data *data;
45722dc546SMarcin Niestroj char phys[32];
46722dc546SMarcin Niestroj };
47722dc546SMarcin Niestroj
48722dc546SMarcin Niestroj static const struct of_device_id of_tps6521x_pb_match[] = {
49722dc546SMarcin Niestroj { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data },
50722dc546SMarcin Niestroj { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data },
51722dc546SMarcin Niestroj { },
52722dc546SMarcin Niestroj };
53722dc546SMarcin Niestroj MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match);
54722dc546SMarcin Niestroj
tps6521x_pb_irq(int irq,void * _pwr)55722dc546SMarcin Niestroj static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr)
565fafed3eSFelipe Balbi {
57722dc546SMarcin Niestroj struct tps6521x_pwrbutton *pwr = _pwr;
58722dc546SMarcin Niestroj const struct tps6521x_data *tps_data = pwr->data;
595fafed3eSFelipe Balbi unsigned int reg;
605fafed3eSFelipe Balbi int error;
615fafed3eSFelipe Balbi
62722dc546SMarcin Niestroj error = regmap_read(pwr->regmap, tps_data->reg_status, ®);
635fafed3eSFelipe Balbi if (error) {
645fafed3eSFelipe Balbi dev_err(pwr->dev, "can't read register: %d\n", error);
655fafed3eSFelipe Balbi goto out;
665fafed3eSFelipe Balbi }
675fafed3eSFelipe Balbi
68722dc546SMarcin Niestroj if (reg & tps_data->pb_mask) {
695fafed3eSFelipe Balbi input_report_key(pwr->idev, KEY_POWER, 1);
705fafed3eSFelipe Balbi pm_wakeup_event(pwr->dev, 0);
715fafed3eSFelipe Balbi } else {
725fafed3eSFelipe Balbi input_report_key(pwr->idev, KEY_POWER, 0);
735fafed3eSFelipe Balbi }
745fafed3eSFelipe Balbi
755fafed3eSFelipe Balbi input_sync(pwr->idev);
765fafed3eSFelipe Balbi
775fafed3eSFelipe Balbi out:
785fafed3eSFelipe Balbi return IRQ_HANDLED;
795fafed3eSFelipe Balbi }
805fafed3eSFelipe Balbi
tps6521x_pb_probe(struct platform_device * pdev)81722dc546SMarcin Niestroj static int tps6521x_pb_probe(struct platform_device *pdev)
825fafed3eSFelipe Balbi {
835fafed3eSFelipe Balbi struct device *dev = &pdev->dev;
84722dc546SMarcin Niestroj struct tps6521x_pwrbutton *pwr;
855fafed3eSFelipe Balbi struct input_dev *idev;
86722dc546SMarcin Niestroj const struct of_device_id *match;
875fafed3eSFelipe Balbi int error;
885fafed3eSFelipe Balbi int irq;
895fafed3eSFelipe Balbi
908ace98dfSGuenter Roeck match = of_match_node(of_tps6521x_pb_match, dev->of_node);
91722dc546SMarcin Niestroj if (!match)
92722dc546SMarcin Niestroj return -ENXIO;
93722dc546SMarcin Niestroj
945fafed3eSFelipe Balbi pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
955fafed3eSFelipe Balbi if (!pwr)
965fafed3eSFelipe Balbi return -ENOMEM;
975fafed3eSFelipe Balbi
98722dc546SMarcin Niestroj pwr->data = match->data;
99722dc546SMarcin Niestroj
1005fafed3eSFelipe Balbi idev = devm_input_allocate_device(dev);
1015fafed3eSFelipe Balbi if (!idev)
1025fafed3eSFelipe Balbi return -ENOMEM;
1035fafed3eSFelipe Balbi
104722dc546SMarcin Niestroj idev->name = pwr->data->name;
105722dc546SMarcin Niestroj snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
106722dc546SMarcin Niestroj pwr->data->name);
107722dc546SMarcin Niestroj idev->phys = pwr->phys;
1085fafed3eSFelipe Balbi idev->dev.parent = dev;
1095fafed3eSFelipe Balbi idev->id.bustype = BUS_I2C;
1105fafed3eSFelipe Balbi
1115fafed3eSFelipe Balbi input_set_capability(idev, EV_KEY, KEY_POWER);
1125fafed3eSFelipe Balbi
1138ace98dfSGuenter Roeck pwr->regmap = dev_get_regmap(dev->parent, NULL);
1145fafed3eSFelipe Balbi pwr->dev = dev;
1155fafed3eSFelipe Balbi pwr->idev = idev;
1165fafed3eSFelipe Balbi device_init_wakeup(dev, true);
1175fafed3eSFelipe Balbi
1185fafed3eSFelipe Balbi irq = platform_get_irq(pdev, 0);
1190bec8b7eSStephen Boyd if (irq < 0)
120722dc546SMarcin Niestroj return -EINVAL;
121722dc546SMarcin Niestroj
122722dc546SMarcin Niestroj error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq,
1235fafed3eSFelipe Balbi IRQF_TRIGGER_RISING |
1245fafed3eSFelipe Balbi IRQF_TRIGGER_FALLING |
1255fafed3eSFelipe Balbi IRQF_ONESHOT,
126722dc546SMarcin Niestroj pwr->data->name, pwr);
1275fafed3eSFelipe Balbi if (error) {
1288ace98dfSGuenter Roeck dev_err(dev, "failed to request IRQ #%d: %d\n", irq, error);
1295fafed3eSFelipe Balbi return error;
1305fafed3eSFelipe Balbi }
1315fafed3eSFelipe Balbi
1325fafed3eSFelipe Balbi error= input_register_device(idev);
1335fafed3eSFelipe Balbi if (error) {
1345fafed3eSFelipe Balbi dev_err(dev, "Can't register power button: %d\n", error);
1355fafed3eSFelipe Balbi return error;
1365fafed3eSFelipe Balbi }
1375fafed3eSFelipe Balbi
1385fafed3eSFelipe Balbi return 0;
1395fafed3eSFelipe Balbi }
1405fafed3eSFelipe Balbi
14177aa9926SKeerthy static const struct platform_device_id tps6521x_pwrbtn_id_table[] = {
14277aa9926SKeerthy { "tps65218-pwrbutton", },
14377aa9926SKeerthy { "tps65217-pwrbutton", },
14477aa9926SKeerthy { /* sentinel */ }
14577aa9926SKeerthy };
14677aa9926SKeerthy MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table);
14777aa9926SKeerthy
148722dc546SMarcin Niestroj static struct platform_driver tps6521x_pb_driver = {
149722dc546SMarcin Niestroj .probe = tps6521x_pb_probe,
1505fafed3eSFelipe Balbi .driver = {
151722dc546SMarcin Niestroj .name = "tps6521x_pwrbutton",
152722dc546SMarcin Niestroj .of_match_table = of_tps6521x_pb_match,
1535fafed3eSFelipe Balbi },
15477aa9926SKeerthy .id_table = tps6521x_pwrbtn_id_table,
1555fafed3eSFelipe Balbi };
156722dc546SMarcin Niestroj module_platform_driver(tps6521x_pb_driver);
1575fafed3eSFelipe Balbi
158722dc546SMarcin Niestroj MODULE_DESCRIPTION("TPS6521X Power Button");
1595fafed3eSFelipe Balbi MODULE_LICENSE("GPL v2");
1605fafed3eSFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
161