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