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