0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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");