1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Driver for TPS65219 Push Button 4 // 5 // Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/ 6 7 #include <linux/init.h> 8 #include <linux/input.h> 9 #include <linux/interrupt.h> 10 #include <linux/kernel.h> 11 #include <linux/mfd/tps65219.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/regmap.h> 16 #include <linux/slab.h> 17 18 struct tps65219_pwrbutton { 19 struct device *dev; 20 struct input_dev *idev; 21 char phys[32]; 22 }; 23 24 static irqreturn_t tps65219_pb_push_irq(int irq, void *_pwr) 25 { 26 struct tps65219_pwrbutton *pwr = _pwr; 27 28 input_report_key(pwr->idev, KEY_POWER, 1); 29 pm_wakeup_event(pwr->dev, 0); 30 input_sync(pwr->idev); 31 32 return IRQ_HANDLED; 33 } 34 35 static irqreturn_t tps65219_pb_release_irq(int irq, void *_pwr) 36 { 37 struct tps65219_pwrbutton *pwr = _pwr; 38 39 input_report_key(pwr->idev, KEY_POWER, 0); 40 input_sync(pwr->idev); 41 42 return IRQ_HANDLED; 43 } 44 45 static int tps65219_pb_probe(struct platform_device *pdev) 46 { 47 struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); 48 struct device *dev = &pdev->dev; 49 struct tps65219_pwrbutton *pwr; 50 struct input_dev *idev; 51 int error; 52 int push_irq; 53 int release_irq; 54 55 pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); 56 if (!pwr) 57 return -ENOMEM; 58 59 idev = devm_input_allocate_device(dev); 60 if (!idev) 61 return -ENOMEM; 62 63 idev->name = pdev->name; 64 snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", 65 pdev->name); 66 idev->phys = pwr->phys; 67 idev->id.bustype = BUS_I2C; 68 69 input_set_capability(idev, EV_KEY, KEY_POWER); 70 71 pwr->dev = dev; 72 pwr->idev = idev; 73 device_init_wakeup(dev, true); 74 75 push_irq = platform_get_irq(pdev, 0); 76 if (push_irq < 0) 77 return -EINVAL; 78 79 release_irq = platform_get_irq(pdev, 1); 80 if (release_irq < 0) 81 return -EINVAL; 82 83 error = devm_request_threaded_irq(dev, push_irq, NULL, 84 tps65219_pb_push_irq, 85 IRQF_ONESHOT, 86 dev->init_name, pwr); 87 if (error) { 88 dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq, 89 error); 90 return error; 91 } 92 93 error = devm_request_threaded_irq(dev, release_irq, NULL, 94 tps65219_pb_release_irq, 95 IRQF_ONESHOT, 96 dev->init_name, pwr); 97 if (error) { 98 dev_err(dev, "failed to request release IRQ #%d: %d\n", 99 release_irq, error); 100 return error; 101 } 102 103 error = input_register_device(idev); 104 if (error) { 105 dev_err(dev, "Can't register power button: %d\n", error); 106 return error; 107 } 108 109 /* Enable interrupts for the pushbutton */ 110 regmap_clear_bits(tps->regmap, TPS65219_REG_MASK_CONFIG, 111 TPS65219_REG_MASK_INT_FOR_PB_MASK); 112 113 /* Set PB/EN/VSENSE pin to be a pushbutton */ 114 regmap_update_bits(tps->regmap, TPS65219_REG_MFP_2_CONFIG, 115 TPS65219_MFP_2_EN_PB_VSENSE_MASK, TPS65219_MFP_2_PB); 116 117 return 0; 118 } 119 120 static void tps65219_pb_remove(struct platform_device *pdev) 121 { 122 struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); 123 int ret; 124 125 /* Disable interrupt for the pushbutton */ 126 ret = regmap_set_bits(tps->regmap, TPS65219_REG_MASK_CONFIG, 127 TPS65219_REG_MASK_INT_FOR_PB_MASK); 128 if (ret) 129 dev_warn(&pdev->dev, "Failed to disable irq (%pe)\n", ERR_PTR(ret)); 130 } 131 132 static const struct platform_device_id tps65219_pwrbtn_id_table[] = { 133 { "tps65219-pwrbutton", }, 134 { /* sentinel */ } 135 }; 136 MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table); 137 138 static struct platform_driver tps65219_pb_driver = { 139 .probe = tps65219_pb_probe, 140 .remove = tps65219_pb_remove, 141 .driver = { 142 .name = "tps65219_pwrbutton", 143 }, 144 .id_table = tps65219_pwrbtn_id_table, 145 }; 146 module_platform_driver(tps65219_pb_driver); 147 148 MODULE_DESCRIPTION("TPS65219 Power Button"); 149 MODULE_LICENSE("GPL"); 150 MODULE_AUTHOR("Markus Schneider-Pargmann <msp@baylibre.com"); 151