1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Texas Instruments' Palmas Power Button Input Driver 4 * 5 * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/ 6 * Girish S Ghongdemath 7 * Nishanth Menon 8 */ 9 10 #include <linux/bitfield.h> 11 #include <linux/init.h> 12 #include <linux/input.h> 13 #include <linux/interrupt.h> 14 #include <linux/kernel.h> 15 #include <linux/mfd/palmas.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/slab.h> 20 21 #define PALMAS_LPK_TIME_MASK 0x0c 22 #define PALMAS_PWRON_DEBOUNCE_MASK 0x03 23 #define PALMAS_PWR_KEY_Q_TIME_MS 20 24 25 /** 26 * struct palmas_pwron - Palmas power on data 27 * @palmas: pointer to palmas device 28 * @input_dev: pointer to input device 29 * @input_work: work for detecting release of key 30 * @irq: irq that we are hooked on to 31 */ 32 struct palmas_pwron { 33 struct palmas *palmas; 34 struct input_dev *input_dev; 35 struct delayed_work input_work; 36 int irq; 37 }; 38 39 /** 40 * struct palmas_pwron_config - configuration of palmas power on 41 * @long_press_time_val: value for long press h/w shutdown event 42 * @pwron_debounce_val: value for debounce of power button 43 */ 44 struct palmas_pwron_config { 45 u8 long_press_time_val; 46 u8 pwron_debounce_val; 47 }; 48 49 /** 50 * palmas_power_button_work() - Detects the button release event 51 * @work: work item to detect button release 52 */ 53 static void palmas_power_button_work(struct work_struct *work) 54 { 55 struct palmas_pwron *pwron = container_of(work, 56 struct palmas_pwron, 57 input_work.work); 58 struct input_dev *input_dev = pwron->input_dev; 59 unsigned int reg; 60 int error; 61 62 error = palmas_read(pwron->palmas, PALMAS_INTERRUPT_BASE, 63 PALMAS_INT1_LINE_STATE, ®); 64 if (error) { 65 dev_err(input_dev->dev.parent, 66 "Cannot read palmas PWRON status: %d\n", error); 67 } else if (reg & BIT(1)) { 68 /* The button is released, report event. */ 69 input_report_key(input_dev, KEY_POWER, 0); 70 input_sync(input_dev); 71 } else { 72 /* The button is still depressed, keep checking. */ 73 schedule_delayed_work(&pwron->input_work, 74 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS)); 75 } 76 } 77 78 /** 79 * pwron_irq() - button press isr 80 * @irq: irq 81 * @palmas_pwron: pwron struct 82 * 83 * Return: IRQ_HANDLED 84 */ 85 static irqreturn_t pwron_irq(int irq, void *palmas_pwron) 86 { 87 struct palmas_pwron *pwron = palmas_pwron; 88 struct input_dev *input_dev = pwron->input_dev; 89 90 input_report_key(input_dev, KEY_POWER, 1); 91 pm_wakeup_event(input_dev->dev.parent, 0); 92 input_sync(input_dev); 93 94 mod_delayed_work(system_wq, &pwron->input_work, 95 msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS)); 96 97 return IRQ_HANDLED; 98 } 99 100 /** 101 * palmas_pwron_params_ofinit() - device tree parameter parser 102 * @dev: palmas button device 103 * @config: configuration params that this fills up 104 */ 105 static void palmas_pwron_params_ofinit(struct device *dev, 106 struct palmas_pwron_config *config) 107 { 108 struct device_node *np; 109 u32 val; 110 int i, error; 111 static const u8 lpk_times[] = { 6, 8, 10, 12 }; 112 static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 }; 113 114 memset(config, 0, sizeof(*config)); 115 116 /* Default config parameters */ 117 config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1; 118 119 np = dev->of_node; 120 if (!np) 121 return; 122 123 error = of_property_read_u32(np, "ti,palmas-long-press-seconds", &val); 124 if (!error) { 125 for (i = 0; i < ARRAY_SIZE(lpk_times); i++) { 126 if (val <= lpk_times[i]) { 127 config->long_press_time_val = i; 128 break; 129 } 130 } 131 } 132 133 error = of_property_read_u32(np, 134 "ti,palmas-pwron-debounce-milli-seconds", 135 &val); 136 if (!error) { 137 for (i = 0; i < ARRAY_SIZE(pwr_on_deb_ms); i++) { 138 if (val <= pwr_on_deb_ms[i]) { 139 config->pwron_debounce_val = i; 140 break; 141 } 142 } 143 } 144 145 dev_info(dev, "h/w controlled shutdown duration=%d seconds\n", 146 lpk_times[config->long_press_time_val]); 147 } 148 149 /** 150 * palmas_pwron_probe() - probe 151 * @pdev: platform device for the button 152 * 153 * Return: 0 for successful probe else appropriate error 154 */ 155 static int palmas_pwron_probe(struct platform_device *pdev) 156 { 157 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); 158 struct device *dev = &pdev->dev; 159 struct input_dev *input_dev; 160 struct palmas_pwron *pwron; 161 struct palmas_pwron_config config; 162 int val; 163 int error; 164 165 palmas_pwron_params_ofinit(dev, &config); 166 167 pwron = kzalloc(sizeof(*pwron), GFP_KERNEL); 168 if (!pwron) 169 return -ENOMEM; 170 171 input_dev = input_allocate_device(); 172 if (!input_dev) { 173 dev_err(dev, "Can't allocate power button\n"); 174 error = -ENOMEM; 175 goto err_free_mem; 176 } 177 178 input_dev->name = "palmas_pwron"; 179 input_dev->phys = "palmas_pwron/input0"; 180 input_dev->dev.parent = dev; 181 182 input_set_capability(input_dev, EV_KEY, KEY_POWER); 183 184 /* 185 * Setup default hardware shutdown option (long key press) 186 * and debounce. 187 */ 188 val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) | 189 FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val); 190 error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, 191 PALMAS_LONG_PRESS_KEY, 192 PALMAS_LPK_TIME_MASK | 193 PALMAS_PWRON_DEBOUNCE_MASK, 194 val); 195 if (error) { 196 dev_err(dev, "LONG_PRESS_KEY_UPDATE failed: %d\n", error); 197 goto err_free_input; 198 } 199 200 pwron->palmas = palmas; 201 pwron->input_dev = input_dev; 202 203 INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work); 204 205 pwron->irq = platform_get_irq(pdev, 0); 206 if (pwron->irq < 0) { 207 error = pwron->irq; 208 goto err_free_input; 209 } 210 211 error = request_threaded_irq(pwron->irq, NULL, pwron_irq, 212 IRQF_TRIGGER_HIGH | 213 IRQF_TRIGGER_LOW | 214 IRQF_ONESHOT, 215 dev_name(dev), pwron); 216 if (error) { 217 dev_err(dev, "Can't get IRQ for pwron: %d\n", error); 218 goto err_free_input; 219 } 220 221 error = input_register_device(input_dev); 222 if (error) { 223 dev_err(dev, "Can't register power button: %d\n", error); 224 goto err_free_irq; 225 } 226 227 platform_set_drvdata(pdev, pwron); 228 device_init_wakeup(dev, true); 229 230 return 0; 231 232 err_free_irq: 233 cancel_delayed_work_sync(&pwron->input_work); 234 free_irq(pwron->irq, pwron); 235 err_free_input: 236 input_free_device(input_dev); 237 err_free_mem: 238 kfree(pwron); 239 return error; 240 } 241 242 /** 243 * palmas_pwron_remove() - Cleanup on removal 244 * @pdev: platform device for the button 245 * 246 * Return: 0 247 */ 248 static int palmas_pwron_remove(struct platform_device *pdev) 249 { 250 struct palmas_pwron *pwron = platform_get_drvdata(pdev); 251 252 free_irq(pwron->irq, pwron); 253 cancel_delayed_work_sync(&pwron->input_work); 254 255 input_unregister_device(pwron->input_dev); 256 kfree(pwron); 257 258 return 0; 259 } 260 261 /** 262 * palmas_pwron_suspend() - suspend handler 263 * @dev: power button device 264 * 265 * Cancel all pending work items for the power button, setup irq for wakeup 266 * 267 * Return: 0 268 */ 269 static int __maybe_unused palmas_pwron_suspend(struct device *dev) 270 { 271 struct platform_device *pdev = to_platform_device(dev); 272 struct palmas_pwron *pwron = platform_get_drvdata(pdev); 273 274 cancel_delayed_work_sync(&pwron->input_work); 275 276 if (device_may_wakeup(dev)) 277 enable_irq_wake(pwron->irq); 278 279 return 0; 280 } 281 282 /** 283 * palmas_pwron_resume() - resume handler 284 * @dev: power button device 285 * 286 * Just disable the wakeup capability of irq here. 287 * 288 * Return: 0 289 */ 290 static int __maybe_unused palmas_pwron_resume(struct device *dev) 291 { 292 struct platform_device *pdev = to_platform_device(dev); 293 struct palmas_pwron *pwron = platform_get_drvdata(pdev); 294 295 if (device_may_wakeup(dev)) 296 disable_irq_wake(pwron->irq); 297 298 return 0; 299 } 300 301 static SIMPLE_DEV_PM_OPS(palmas_pwron_pm, 302 palmas_pwron_suspend, palmas_pwron_resume); 303 304 #ifdef CONFIG_OF 305 static const struct of_device_id of_palmas_pwr_match[] = { 306 { .compatible = "ti,palmas-pwrbutton" }, 307 { }, 308 }; 309 310 MODULE_DEVICE_TABLE(of, of_palmas_pwr_match); 311 #endif 312 313 static struct platform_driver palmas_pwron_driver = { 314 .probe = palmas_pwron_probe, 315 .remove = palmas_pwron_remove, 316 .driver = { 317 .name = "palmas_pwrbutton", 318 .of_match_table = of_match_ptr(of_palmas_pwr_match), 319 .pm = &palmas_pwron_pm, 320 }, 321 }; 322 module_platform_driver(palmas_pwron_driver); 323 324 MODULE_ALIAS("platform:palmas-pwrbutton"); 325 MODULE_DESCRIPTION("Palmas Power Button"); 326 MODULE_LICENSE("GPL v2"); 327 MODULE_AUTHOR("Texas Instruments Inc."); 328