Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Cobalt button interface driver.
0004  *
0005  *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.org>
0006  */
0007 #include <linux/input.h>
0008 #include <linux/io.h>
0009 #include <linux/ioport.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 
0014 #define BUTTONS_POLL_INTERVAL   30  /* msec */
0015 #define BUTTONS_COUNT_THRESHOLD 3
0016 #define BUTTONS_STATUS_MASK 0xfe000000
0017 
0018 static const unsigned short cobalt_map[] = {
0019     KEY_RESERVED,
0020     KEY_RESTART,
0021     KEY_LEFT,
0022     KEY_UP,
0023     KEY_DOWN,
0024     KEY_RIGHT,
0025     KEY_ENTER,
0026     KEY_SELECT
0027 };
0028 
0029 struct buttons_dev {
0030     unsigned short keymap[ARRAY_SIZE(cobalt_map)];
0031     int count[ARRAY_SIZE(cobalt_map)];
0032     void __iomem *reg;
0033 };
0034 
0035 static void handle_buttons(struct input_dev *input)
0036 {
0037     struct buttons_dev *bdev = input_get_drvdata(input);
0038     uint32_t status;
0039     int i;
0040 
0041     status = ~readl(bdev->reg) >> 24;
0042 
0043     for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
0044         if (status & (1U << i)) {
0045             if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
0046                 input_event(input, EV_MSC, MSC_SCAN, i);
0047                 input_report_key(input, bdev->keymap[i], 1);
0048                 input_sync(input);
0049             }
0050         } else {
0051             if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
0052                 input_event(input, EV_MSC, MSC_SCAN, i);
0053                 input_report_key(input, bdev->keymap[i], 0);
0054                 input_sync(input);
0055             }
0056             bdev->count[i] = 0;
0057         }
0058     }
0059 }
0060 
0061 static int cobalt_buttons_probe(struct platform_device *pdev)
0062 {
0063     struct buttons_dev *bdev;
0064     struct input_dev *input;
0065     struct resource *res;
0066     int error, i;
0067 
0068     bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
0069     if (!bdev)
0070         return -ENOMEM;
0071 
0072     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0073     if (!res)
0074         return -EBUSY;
0075 
0076     bdev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
0077     if (!bdev->reg)
0078         return -ENOMEM;
0079 
0080     memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
0081 
0082     input = devm_input_allocate_device(&pdev->dev);
0083     if (!input)
0084         return -ENOMEM;
0085 
0086     input_set_drvdata(input, bdev);
0087 
0088     input->name = "Cobalt buttons";
0089     input->phys = "cobalt/input0";
0090     input->id.bustype = BUS_HOST;
0091 
0092     input->keycode = bdev->keymap;
0093     input->keycodemax = ARRAY_SIZE(bdev->keymap);
0094     input->keycodesize = sizeof(unsigned short);
0095 
0096     input_set_capability(input, EV_MSC, MSC_SCAN);
0097     __set_bit(EV_KEY, input->evbit);
0098     for (i = 0; i < ARRAY_SIZE(cobalt_map); i++)
0099         __set_bit(bdev->keymap[i], input->keybit);
0100     __clear_bit(KEY_RESERVED, input->keybit);
0101 
0102 
0103     error = input_setup_polling(input, handle_buttons);
0104     if (error)
0105         return error;
0106 
0107     input_set_poll_interval(input, BUTTONS_POLL_INTERVAL);
0108 
0109     error = input_register_device(input);
0110     if (error)
0111         return error;
0112 
0113     return 0;
0114 }
0115 
0116 MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
0117 MODULE_DESCRIPTION("Cobalt button interface driver");
0118 MODULE_LICENSE("GPL");
0119 /* work with hotplug and coldplug */
0120 MODULE_ALIAS("platform:Cobalt buttons");
0121 
0122 static struct platform_driver cobalt_buttons_driver = {
0123     .probe  = cobalt_buttons_probe,
0124     .driver = {
0125         .name   = "Cobalt buttons",
0126     },
0127 };
0128 module_platform_driver(cobalt_buttons_driver);