1d0a82132SDaniel Ribeiro /* 2d0a82132SDaniel Ribeiro * Input driver for PCAP events: 3d0a82132SDaniel Ribeiro * * Power key 4d0a82132SDaniel Ribeiro * * Headphone button 5d0a82132SDaniel Ribeiro * 6d0a82132SDaniel Ribeiro * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> 7d0a82132SDaniel Ribeiro * 8d0a82132SDaniel Ribeiro * This program is free software; you can redistribute it and/or modify 9d0a82132SDaniel Ribeiro * it under the terms of the GNU General Public License version 2 as 10d0a82132SDaniel Ribeiro * published by the Free Software Foundation. 11d0a82132SDaniel Ribeiro * 12d0a82132SDaniel Ribeiro */ 13d0a82132SDaniel Ribeiro 14d0a82132SDaniel Ribeiro #include <linux/module.h> 15d0a82132SDaniel Ribeiro #include <linux/init.h> 16d0a82132SDaniel Ribeiro #include <linux/interrupt.h> 17d0a82132SDaniel Ribeiro #include <linux/platform_device.h> 18d0a82132SDaniel Ribeiro #include <linux/input.h> 19d0a82132SDaniel Ribeiro #include <linux/mfd/ezx-pcap.h> 20*5a0e3ad6STejun Heo #include <linux/slab.h> 21d0a82132SDaniel Ribeiro 22d0a82132SDaniel Ribeiro struct pcap_keys { 23d0a82132SDaniel Ribeiro struct pcap_chip *pcap; 24d0a82132SDaniel Ribeiro struct input_dev *input; 25d0a82132SDaniel Ribeiro }; 26d0a82132SDaniel Ribeiro 27d0a82132SDaniel Ribeiro /* PCAP2 interrupts us on keypress */ 28d0a82132SDaniel Ribeiro static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) 29d0a82132SDaniel Ribeiro { 30d0a82132SDaniel Ribeiro struct pcap_keys *pcap_keys = _pcap_keys; 31d0a82132SDaniel Ribeiro int pirq = irq_to_pcap(pcap_keys->pcap, irq); 32d0a82132SDaniel Ribeiro u32 pstat; 33d0a82132SDaniel Ribeiro 34d0a82132SDaniel Ribeiro ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); 35d0a82132SDaniel Ribeiro pstat &= 1 << pirq; 36d0a82132SDaniel Ribeiro 37d0a82132SDaniel Ribeiro switch (pirq) { 38d0a82132SDaniel Ribeiro case PCAP_IRQ_ONOFF: 39d0a82132SDaniel Ribeiro input_report_key(pcap_keys->input, KEY_POWER, !pstat); 40d0a82132SDaniel Ribeiro break; 41d0a82132SDaniel Ribeiro case PCAP_IRQ_MIC: 42d0a82132SDaniel Ribeiro input_report_key(pcap_keys->input, KEY_HP, !pstat); 43d0a82132SDaniel Ribeiro break; 44d0a82132SDaniel Ribeiro } 45d0a82132SDaniel Ribeiro 46d0a82132SDaniel Ribeiro input_sync(pcap_keys->input); 47d0a82132SDaniel Ribeiro 48d0a82132SDaniel Ribeiro return IRQ_HANDLED; 49d0a82132SDaniel Ribeiro } 50d0a82132SDaniel Ribeiro 51d0a82132SDaniel Ribeiro static int __devinit pcap_keys_probe(struct platform_device *pdev) 52d0a82132SDaniel Ribeiro { 53d0a82132SDaniel Ribeiro int err = -ENOMEM; 54d0a82132SDaniel Ribeiro struct pcap_keys *pcap_keys; 55d0a82132SDaniel Ribeiro struct input_dev *input_dev; 56d0a82132SDaniel Ribeiro 57d0a82132SDaniel Ribeiro pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL); 58d0a82132SDaniel Ribeiro if (!pcap_keys) 59d0a82132SDaniel Ribeiro return err; 60d0a82132SDaniel Ribeiro 61d0a82132SDaniel Ribeiro pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); 62d0a82132SDaniel Ribeiro 63d0a82132SDaniel Ribeiro input_dev = input_allocate_device(); 64d0a82132SDaniel Ribeiro if (!input_dev) 65d0a82132SDaniel Ribeiro goto fail; 66d0a82132SDaniel Ribeiro 67d0a82132SDaniel Ribeiro pcap_keys->input = input_dev; 68d0a82132SDaniel Ribeiro 69d0a82132SDaniel Ribeiro platform_set_drvdata(pdev, pcap_keys); 70d0a82132SDaniel Ribeiro input_dev->name = pdev->name; 71d0a82132SDaniel Ribeiro input_dev->phys = "pcap-keys/input0"; 72d0a82132SDaniel Ribeiro input_dev->id.bustype = BUS_HOST; 73d0a82132SDaniel Ribeiro input_dev->dev.parent = &pdev->dev; 74d0a82132SDaniel Ribeiro 75d0a82132SDaniel Ribeiro __set_bit(EV_KEY, input_dev->evbit); 76d0a82132SDaniel Ribeiro __set_bit(KEY_POWER, input_dev->keybit); 77d0a82132SDaniel Ribeiro __set_bit(KEY_HP, input_dev->keybit); 78d0a82132SDaniel Ribeiro 79d0a82132SDaniel Ribeiro err = input_register_device(input_dev); 80d0a82132SDaniel Ribeiro if (err) 81d0a82132SDaniel Ribeiro goto fail_allocate; 82d0a82132SDaniel Ribeiro 83d0a82132SDaniel Ribeiro err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), 84d0a82132SDaniel Ribeiro pcap_keys_handler, 0, "Power key", pcap_keys); 85d0a82132SDaniel Ribeiro if (err) 86d0a82132SDaniel Ribeiro goto fail_register; 87d0a82132SDaniel Ribeiro 88d0a82132SDaniel Ribeiro err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), 89d0a82132SDaniel Ribeiro pcap_keys_handler, 0, "Headphone button", pcap_keys); 90d0a82132SDaniel Ribeiro if (err) 91d0a82132SDaniel Ribeiro goto fail_pwrkey; 92d0a82132SDaniel Ribeiro 93d0a82132SDaniel Ribeiro return 0; 94d0a82132SDaniel Ribeiro 95d0a82132SDaniel Ribeiro fail_pwrkey: 96d0a82132SDaniel Ribeiro free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); 97d0a82132SDaniel Ribeiro fail_register: 98d0a82132SDaniel Ribeiro input_unregister_device(input_dev); 99d0a82132SDaniel Ribeiro goto fail; 100d0a82132SDaniel Ribeiro fail_allocate: 101d0a82132SDaniel Ribeiro input_free_device(input_dev); 102d0a82132SDaniel Ribeiro fail: 103d0a82132SDaniel Ribeiro kfree(pcap_keys); 104d0a82132SDaniel Ribeiro return err; 105d0a82132SDaniel Ribeiro } 106d0a82132SDaniel Ribeiro 107d0a82132SDaniel Ribeiro static int __devexit pcap_keys_remove(struct platform_device *pdev) 108d0a82132SDaniel Ribeiro { 109d0a82132SDaniel Ribeiro struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); 110d0a82132SDaniel Ribeiro 111d0a82132SDaniel Ribeiro free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); 112d0a82132SDaniel Ribeiro free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); 113d0a82132SDaniel Ribeiro 114d0a82132SDaniel Ribeiro input_unregister_device(pcap_keys->input); 115d0a82132SDaniel Ribeiro kfree(pcap_keys); 116d0a82132SDaniel Ribeiro 117d0a82132SDaniel Ribeiro return 0; 118d0a82132SDaniel Ribeiro } 119d0a82132SDaniel Ribeiro 120d0a82132SDaniel Ribeiro static struct platform_driver pcap_keys_device_driver = { 121d0a82132SDaniel Ribeiro .probe = pcap_keys_probe, 122d0a82132SDaniel Ribeiro .remove = __devexit_p(pcap_keys_remove), 123d0a82132SDaniel Ribeiro .driver = { 124d0a82132SDaniel Ribeiro .name = "pcap-keys", 125d0a82132SDaniel Ribeiro .owner = THIS_MODULE, 126d0a82132SDaniel Ribeiro } 127d0a82132SDaniel Ribeiro }; 128d0a82132SDaniel Ribeiro 129d0a82132SDaniel Ribeiro static int __init pcap_keys_init(void) 130d0a82132SDaniel Ribeiro { 131d0a82132SDaniel Ribeiro return platform_driver_register(&pcap_keys_device_driver); 132d0a82132SDaniel Ribeiro }; 133d0a82132SDaniel Ribeiro 134d0a82132SDaniel Ribeiro static void __exit pcap_keys_exit(void) 135d0a82132SDaniel Ribeiro { 136d0a82132SDaniel Ribeiro platform_driver_unregister(&pcap_keys_device_driver); 137d0a82132SDaniel Ribeiro }; 138d0a82132SDaniel Ribeiro 139d0a82132SDaniel Ribeiro module_init(pcap_keys_init); 140d0a82132SDaniel Ribeiro module_exit(pcap_keys_exit); 141d0a82132SDaniel Ribeiro 142d0a82132SDaniel Ribeiro MODULE_DESCRIPTION("Motorola PCAP2 input events driver"); 143d0a82132SDaniel Ribeiro MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); 144d0a82132SDaniel Ribeiro MODULE_LICENSE("GPL"); 145d0a82132SDaniel Ribeiro MODULE_ALIAS("platform:pcap_keys"); 146