1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* NXP PCF50633 Input Driver 3 * 4 * (C) 2006-2008 by Openmoko, Inc. 5 * Author: Balaji Rao <balajirrao@openmoko.org> 6 * All rights reserved. 7 * 8 * Broken down from monstrous PCF50633 driver mainly by 9 * Harald Welte, Andy Green and Werner Almesberger 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/device.h> 15 #include <linux/platform_device.h> 16 #include <linux/input.h> 17 #include <linux/slab.h> 18 19 #include <linux/mfd/pcf50633/core.h> 20 21 #define PCF50633_OOCSTAT_ONKEY 0x01 22 #define PCF50633_REG_OOCSTAT 0x12 23 #define PCF50633_REG_OOCMODE 0x10 24 25 struct pcf50633_input { 26 struct pcf50633 *pcf; 27 struct input_dev *input_dev; 28 }; 29 30 static void 31 pcf50633_input_irq(int irq, void *data) 32 { 33 struct pcf50633_input *input; 34 int onkey_released; 35 36 input = data; 37 38 /* We report only one event depending on the key press status */ 39 onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT) 40 & PCF50633_OOCSTAT_ONKEY; 41 42 if (irq == PCF50633_IRQ_ONKEYF && !onkey_released) 43 input_report_key(input->input_dev, KEY_POWER, 1); 44 else if (irq == PCF50633_IRQ_ONKEYR && onkey_released) 45 input_report_key(input->input_dev, KEY_POWER, 0); 46 47 input_sync(input->input_dev); 48 } 49 50 static int pcf50633_input_probe(struct platform_device *pdev) 51 { 52 struct pcf50633_input *input; 53 struct input_dev *input_dev; 54 int ret; 55 56 57 input = kzalloc(sizeof(*input), GFP_KERNEL); 58 if (!input) 59 return -ENOMEM; 60 61 input_dev = input_allocate_device(); 62 if (!input_dev) { 63 kfree(input); 64 return -ENOMEM; 65 } 66 67 platform_set_drvdata(pdev, input); 68 input->pcf = dev_to_pcf50633(pdev->dev.parent); 69 input->input_dev = input_dev; 70 71 input_dev->name = "PCF50633 PMU events"; 72 input_dev->id.bustype = BUS_I2C; 73 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR); 74 set_bit(KEY_POWER, input_dev->keybit); 75 76 ret = input_register_device(input_dev); 77 if (ret) { 78 input_free_device(input_dev); 79 kfree(input); 80 return ret; 81 } 82 pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR, 83 pcf50633_input_irq, input); 84 pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF, 85 pcf50633_input_irq, input); 86 87 return 0; 88 } 89 90 static void pcf50633_input_remove(struct platform_device *pdev) 91 { 92 struct pcf50633_input *input = platform_get_drvdata(pdev); 93 94 pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR); 95 pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF); 96 97 input_unregister_device(input->input_dev); 98 kfree(input); 99 } 100 101 static struct platform_driver pcf50633_input_driver = { 102 .driver = { 103 .name = "pcf50633-input", 104 }, 105 .probe = pcf50633_input_probe, 106 .remove_new = pcf50633_input_remove, 107 }; 108 module_platform_driver(pcf50633_input_driver); 109 110 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); 111 MODULE_DESCRIPTION("PCF50633 input driver"); 112 MODULE_LICENSE("GPL"); 113 MODULE_ALIAS("platform:pcf50633-input"); 114