linux/drivers/input/keyboard/ipaq-micro-keys.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 * h3600 atmel micro companion support, key subdevice
   5 * based on previous kernel 2.4 version
   6 * Author : Alessandro Gardich <gremlin@gremlin.it>
   7 * Author : Linus Walleij <linus.walleij@linaro.org>
   8 */
   9#include <linux/module.h>
  10#include <linux/init.h>
  11#include <linux/fs.h>
  12#include <linux/interrupt.h>
  13#include <linux/sched.h>
  14#include <linux/pm.h>
  15#include <linux/sysctl.h>
  16#include <linux/proc_fs.h>
  17#include <linux/delay.h>
  18#include <linux/device.h>
  19#include <linux/input.h>
  20#include <linux/platform_device.h>
  21#include <linux/mfd/ipaq-micro.h>
  22
  23struct ipaq_micro_keys {
  24        struct ipaq_micro *micro;
  25        struct input_dev *input;
  26        u16 *codes;
  27};
  28
  29static const u16 micro_keycodes[] = {
  30        KEY_RECORD,             /* 1:  Record button                    */
  31        KEY_CALENDAR,           /* 2:  Calendar                         */
  32        KEY_ADDRESSBOOK,        /* 3:  Contacts (looks like Outlook)    */
  33        KEY_MAIL,               /* 4:  Envelope (Q on older iPAQs)      */
  34        KEY_HOMEPAGE,           /* 5:  Start (looks like swoopy arrow)  */
  35        KEY_UP,                 /* 6:  Up                               */
  36        KEY_RIGHT,              /* 7:  Right                            */
  37        KEY_LEFT,               /* 8:  Left                             */
  38        KEY_DOWN,               /* 9:  Down                             */
  39};
  40
  41static void micro_key_receive(void *data, int len, unsigned char *msg)
  42{
  43        struct ipaq_micro_keys *keys = data;
  44        int key, down;
  45
  46        down = 0x80 & msg[0];
  47        key  = 0x7f & msg[0];
  48
  49        if (key < ARRAY_SIZE(micro_keycodes)) {
  50                input_report_key(keys->input, keys->codes[key], down);
  51                input_sync(keys->input);
  52        }
  53}
  54
  55static void micro_key_start(struct ipaq_micro_keys *keys)
  56{
  57        spin_lock(&keys->micro->lock);
  58        keys->micro->key = micro_key_receive;
  59        keys->micro->key_data = keys;
  60        spin_unlock(&keys->micro->lock);
  61}
  62
  63static void micro_key_stop(struct ipaq_micro_keys *keys)
  64{
  65        spin_lock(&keys->micro->lock);
  66        keys->micro->key = NULL;
  67        keys->micro->key_data = NULL;
  68        spin_unlock(&keys->micro->lock);
  69}
  70
  71static int micro_key_open(struct input_dev *input)
  72{
  73        struct ipaq_micro_keys *keys = input_get_drvdata(input);
  74
  75        micro_key_start(keys);
  76
  77        return 0;
  78}
  79
  80static void micro_key_close(struct input_dev *input)
  81{
  82        struct ipaq_micro_keys *keys = input_get_drvdata(input);
  83
  84        micro_key_stop(keys);
  85}
  86
  87static int micro_key_probe(struct platform_device *pdev)
  88{
  89        struct ipaq_micro_keys *keys;
  90        int error;
  91        int i;
  92
  93        keys = devm_kzalloc(&pdev->dev, sizeof(*keys), GFP_KERNEL);
  94        if (!keys)
  95                return -ENOMEM;
  96
  97        keys->micro = dev_get_drvdata(pdev->dev.parent);
  98
  99        keys->input = devm_input_allocate_device(&pdev->dev);
 100        if (!keys->input)
 101                return -ENOMEM;
 102
 103        keys->input->keycodesize = sizeof(micro_keycodes[0]);
 104        keys->input->keycodemax = ARRAY_SIZE(micro_keycodes);
 105        keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes,
 106                           keys->input->keycodesize * keys->input->keycodemax,
 107                           GFP_KERNEL);
 108        keys->input->keycode = keys->codes;
 109
 110        __set_bit(EV_KEY, keys->input->evbit);
 111        for (i = 0; i < ARRAY_SIZE(micro_keycodes); i++)
 112                __set_bit(micro_keycodes[i], keys->input->keybit);
 113
 114        keys->input->name = "h3600 micro keys";
 115        keys->input->open = micro_key_open;
 116        keys->input->close = micro_key_close;
 117        input_set_drvdata(keys->input, keys);
 118
 119        error = input_register_device(keys->input);
 120        if (error)
 121                return error;
 122
 123        platform_set_drvdata(pdev, keys);
 124        return 0;
 125}
 126
 127static int __maybe_unused micro_key_suspend(struct device *dev)
 128{
 129        struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
 130
 131        micro_key_stop(keys);
 132
 133        return 0;
 134}
 135
 136static int __maybe_unused micro_key_resume(struct device *dev)
 137{
 138        struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
 139        struct input_dev *input = keys->input;
 140
 141        mutex_lock(&input->mutex);
 142
 143        if (input->users)
 144                micro_key_start(keys);
 145
 146        mutex_unlock(&input->mutex);
 147
 148        return 0;
 149}
 150
 151static SIMPLE_DEV_PM_OPS(micro_key_dev_pm_ops,
 152                         micro_key_suspend, micro_key_resume);
 153
 154static struct platform_driver micro_key_device_driver = {
 155        .driver = {
 156                .name    = "ipaq-micro-keys",
 157                .pm     = &micro_key_dev_pm_ops,
 158        },
 159        .probe   = micro_key_probe,
 160};
 161module_platform_driver(micro_key_device_driver);
 162
 163MODULE_LICENSE("GPL");
 164MODULE_DESCRIPTION("driver for iPAQ Atmel micro keys");
 165MODULE_ALIAS("platform:ipaq-micro-keys");
 166