133965Sjdp// SPDX-License-Identifier: GPL-2.0-only 278828Sobrien/* 391041Sobrien * Input driver for PCAP events: 433965Sjdp * * Power key 533965Sjdp * * Headphone button 633965Sjdp * 733965Sjdp * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> 891041Sobrien */ 933965Sjdp 1091041Sobrien#include <linux/module.h> 1191041Sobrien#include <linux/interrupt.h> 1291041Sobrien#include <linux/platform_device.h> 1391041Sobrien#include <linux/input.h> 1433965Sjdp#include <linux/mfd/ezx-pcap.h> 1591041Sobrien#include <linux/slab.h> 1691041Sobrien 1791041Sobrienstruct pcap_keys { 1891041Sobrien struct pcap_chip *pcap; 1933965Sjdp struct input_dev *input; 2091041Sobrien}; 2191041Sobrien 2291041Sobrien/* PCAP2 interrupts us on keypress */ 2333965Sjdpstatic irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) 2433965Sjdp{ 2533965Sjdp struct pcap_keys *pcap_keys = _pcap_keys; 2633965Sjdp int pirq = irq_to_pcap(pcap_keys->pcap, irq); 2733965Sjdp u32 pstat; 2833965Sjdp 2933965Sjdp ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); 3033965Sjdp pstat &= 1 << pirq; 3133965Sjdp 3233965Sjdp switch (pirq) { 3333965Sjdp case PCAP_IRQ_ONOFF: 3433965Sjdp input_report_key(pcap_keys->input, KEY_POWER, !pstat); 3589857Sobrien break; 3633965Sjdp case PCAP_IRQ_MIC: 3789857Sobrien input_report_key(pcap_keys->input, KEY_HP, !pstat); 3889857Sobrien break; 3989857Sobrien } 4089857Sobrien 4189857Sobrien input_sync(pcap_keys->input); 4260484Sobrien 4333965Sjdp return IRQ_HANDLED; 4433965Sjdp} 4533965Sjdp 4633965Sjdpstatic int pcap_keys_probe(struct platform_device *pdev) 4789857Sobrien{ 4889857Sobrien int err = -ENOMEM; 4989857Sobrien struct pcap_keys *pcap_keys; 5033965Sjdp struct input_dev *input_dev; 5133965Sjdp 5233965Sjdp pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL); 5333965Sjdp if (!pcap_keys) 5489857Sobrien return err; 5589857Sobrien 5689857Sobrien pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); 5789857Sobrien 5889857Sobrien input_dev = input_allocate_device(); 5989857Sobrien if (!input_dev) 6089857Sobrien goto fail; 6189857Sobrien 6289857Sobrien pcap_keys->input = input_dev; 6389857Sobrien 6489857Sobrien platform_set_drvdata(pdev, pcap_keys); 6589857Sobrien input_dev->name = pdev->name; 6689857Sobrien input_dev->phys = "pcap-keys/input0"; 6789857Sobrien input_dev->id.bustype = BUS_HOST; 6889857Sobrien input_dev->dev.parent = &pdev->dev; 6989857Sobrien 7089857Sobrien __set_bit(EV_KEY, input_dev->evbit); 7189857Sobrien __set_bit(KEY_POWER, input_dev->keybit); 7289857Sobrien __set_bit(KEY_HP, input_dev->keybit); 7389857Sobrien 7489857Sobrien err = input_register_device(input_dev); 7589857Sobrien if (err) 7689857Sobrien goto fail_allocate; 7789857Sobrien 7889857Sobrien err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), 7989857Sobrien pcap_keys_handler, 0, "Power key", pcap_keys); 8089857Sobrien if (err) 8189857Sobrien goto fail_register; 8289857Sobrien 8389857Sobrien err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), 8489857Sobrien pcap_keys_handler, 0, "Headphone button", pcap_keys); 8589857Sobrien if (err) 8689857Sobrien goto fail_pwrkey; 8789857Sobrien 8833965Sjdp return 0; 8933965Sjdp 9033965Sjdpfail_pwrkey: 9133965Sjdp free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); 9289857Sobrienfail_register: 9389857Sobrien input_unregister_device(input_dev); 9489857Sobrien goto fail; 9589857Sobrienfail_allocate: 9689857Sobrien input_free_device(input_dev); 9789857Sobrienfail: 9889857Sobrien kfree(pcap_keys); 9989857Sobrien return err; 10089857Sobrien} 10189857Sobrien 10289857Sobrienstatic void pcap_keys_remove(struct platform_device *pdev) 10389857Sobrien{ 10489857Sobrien struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); 10589857Sobrien 10689857Sobrien free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); 10789857Sobrien free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); 10889857Sobrien 10989857Sobrien input_unregister_device(pcap_keys->input); 11089857Sobrien kfree(pcap_keys); 11189857Sobrien} 11289857Sobrien 11389857Sobrienstatic struct platform_driver pcap_keys_device_driver = { 11433965Sjdp .probe = pcap_keys_probe, 11533965Sjdp .remove_new = pcap_keys_remove, 11633965Sjdp .driver = { 11789857Sobrien .name = "pcap-keys", 11889857Sobrien } 11989857Sobrien}; 12089857Sobrienmodule_platform_driver(pcap_keys_device_driver); 12189857Sobrien 12289857SobrienMODULE_DESCRIPTION("Motorola PCAP2 input events driver"); 12389857SobrienMODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); 12489857SobrienMODULE_LICENSE("GPL"); 12533965SjdpMODULE_ALIAS("platform:pcap_keys"); 12633965Sjdp