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