Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Raspberry Pi Sense HAT joystick driver
0004  * http://raspberrypi.org
0005  *
0006  * Copyright (C) 2015 Raspberry Pi
0007  * Copyright (C) 2021 Charles Mirabile, Mwesigwa Guma, Joel Savitz
0008  *
0009  * Original Author: Serge Schneider
0010  * Revised for upstream Linux by: Charles Mirabile, Mwesigwa Guma, Joel Savitz
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/input.h>
0015 #include <linux/i2c.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/regmap.h>
0019 #include <linux/property.h>
0020 
0021 #define JOYSTICK_SMB_REG 0xf2
0022 
0023 struct sensehat_joystick {
0024     struct platform_device *pdev;
0025     struct input_dev *keys_dev;
0026     unsigned long prev_states;
0027     struct regmap *regmap;
0028 };
0029 
0030 static const unsigned int keymap[] = {
0031     BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT,
0032 };
0033 
0034 static irqreturn_t sensehat_joystick_report(int irq, void *cookie)
0035 {
0036     struct sensehat_joystick *sensehat_joystick = cookie;
0037     unsigned long curr_states, changes;
0038     unsigned int keys;
0039     int error;
0040     int i;
0041 
0042     error = regmap_read(sensehat_joystick->regmap, JOYSTICK_SMB_REG, &keys);
0043     if (error < 0) {
0044         dev_err(&sensehat_joystick->pdev->dev,
0045             "Failed to read joystick state: %d", error);
0046         return IRQ_NONE;
0047     }
0048     curr_states = keys;
0049     bitmap_xor(&changes, &curr_states, &sensehat_joystick->prev_states,
0050            ARRAY_SIZE(keymap));
0051 
0052     for_each_set_bit(i, &changes, ARRAY_SIZE(keymap))
0053         input_report_key(sensehat_joystick->keys_dev, keymap[i],
0054                  curr_states & BIT(i));
0055 
0056     input_sync(sensehat_joystick->keys_dev);
0057     sensehat_joystick->prev_states = keys;
0058     return IRQ_HANDLED;
0059 }
0060 
0061 static int sensehat_joystick_probe(struct platform_device *pdev)
0062 {
0063     struct sensehat_joystick *sensehat_joystick;
0064     int error, i, irq;
0065 
0066     sensehat_joystick = devm_kzalloc(&pdev->dev, sizeof(*sensehat_joystick),
0067                      GFP_KERNEL);
0068     if (!sensehat_joystick)
0069         return -ENOMEM;
0070 
0071     sensehat_joystick->pdev = pdev;
0072 
0073     sensehat_joystick->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0074     if (!sensehat_joystick->regmap) {
0075         dev_err(&pdev->dev, "unable to get sensehat regmap");
0076         return -ENODEV;
0077     }
0078 
0079     sensehat_joystick->keys_dev = devm_input_allocate_device(&pdev->dev);
0080     if (!sensehat_joystick->keys_dev) {
0081         dev_err(&pdev->dev, "Could not allocate input device");
0082         return -ENOMEM;
0083     }
0084 
0085     sensehat_joystick->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
0086     sensehat_joystick->keys_dev->phys = "sensehat-joystick/input0";
0087     sensehat_joystick->keys_dev->id.bustype = BUS_I2C;
0088 
0089     __set_bit(EV_KEY, sensehat_joystick->keys_dev->evbit);
0090     __set_bit(EV_REP, sensehat_joystick->keys_dev->evbit);
0091     for (i = 0; i < ARRAY_SIZE(keymap); i++)
0092         __set_bit(keymap[i], sensehat_joystick->keys_dev->keybit);
0093 
0094     error = input_register_device(sensehat_joystick->keys_dev);
0095     if (error) {
0096         dev_err(&pdev->dev, "Could not register input device");
0097         return error;
0098     }
0099 
0100     irq = platform_get_irq(pdev, 0);
0101     if (irq < 0)
0102         return irq;
0103 
0104     error = devm_request_threaded_irq(&pdev->dev, irq,
0105                       NULL, sensehat_joystick_report,
0106                       IRQF_ONESHOT, "keys",
0107                       sensehat_joystick);
0108     if (error) {
0109         dev_err(&pdev->dev, "IRQ request failed");
0110         return error;
0111     }
0112 
0113     return 0;
0114 }
0115 
0116 static const struct of_device_id sensehat_joystick_device_id[] = {
0117     { .compatible = "raspberrypi,sensehat-joystick" },
0118     {},
0119 };
0120 MODULE_DEVICE_TABLE(of, sensehat_joystick_device_id);
0121 
0122 static struct platform_driver sensehat_joystick_driver = {
0123     .probe = sensehat_joystick_probe,
0124     .driver = {
0125         .name = "sensehat-joystick",
0126         .of_match_table = sensehat_joystick_device_id,
0127     },
0128 };
0129 
0130 module_platform_driver(sensehat_joystick_driver);
0131 
0132 MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
0133 MODULE_AUTHOR("Charles Mirabile <cmirabil@redhat.com>");
0134 MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
0135 MODULE_LICENSE("GPL");