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