// SPDX-License-Identifier: GPL-2.0-or-later /* * Raspberry Pi Sense HAT joystick driver * http://raspberrypi.org * * Copyright (C) 2015 Raspberry Pi * Copyright (C) 2021 Charles Mirabile, Mwesigwa Guma, Joel Savitz * * Original Author: Serge Schneider * Revised for upstream Linux by: Charles Mirabile, Mwesigwa Guma, Joel Savitz */ #include #include #include #include #include #include #include #define JOYSTICK_SMB_REG 0xf2 struct sensehat_joystick { struct platform_device *pdev; struct input_dev *keys_dev; unsigned long prev_states; struct regmap *regmap; }; static const unsigned int keymap[] = { BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT, }; static irqreturn_t sensehat_joystick_report(int irq, void *cookie) { struct sensehat_joystick *sensehat_joystick = cookie; unsigned long curr_states, changes; unsigned int keys; int error; int i; error = regmap_read(sensehat_joystick->regmap, JOYSTICK_SMB_REG, &keys); if (error < 0) { dev_err(&sensehat_joystick->pdev->dev, "Failed to read joystick state: %d", error); return IRQ_NONE; } curr_states = keys; bitmap_xor(&changes, &curr_states, &sensehat_joystick->prev_states, ARRAY_SIZE(keymap)); for_each_set_bit(i, &changes, ARRAY_SIZE(keymap)) input_report_key(sensehat_joystick->keys_dev, keymap[i], curr_states & BIT(i)); input_sync(sensehat_joystick->keys_dev); sensehat_joystick->prev_states = keys; return IRQ_HANDLED; } static int sensehat_joystick_probe(struct platform_device *pdev) { struct sensehat_joystick *sensehat_joystick; int error, i, irq; sensehat_joystick = devm_kzalloc(&pdev->dev, sizeof(*sensehat_joystick), GFP_KERNEL); if (!sensehat_joystick) return -ENOMEM; sensehat_joystick->pdev = pdev; sensehat_joystick->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!sensehat_joystick->regmap) { dev_err(&pdev->dev, "unable to get sensehat regmap"); return -ENODEV; } sensehat_joystick->keys_dev = devm_input_allocate_device(&pdev->dev); if (!sensehat_joystick->keys_dev) { dev_err(&pdev->dev, "Could not allocate input device"); return -ENOMEM; } sensehat_joystick->keys_dev->name = "Raspberry Pi Sense HAT Joystick"; sensehat_joystick->keys_dev->phys = "sensehat-joystick/input0"; sensehat_joystick->keys_dev->id.bustype = BUS_I2C; __set_bit(EV_KEY, sensehat_joystick->keys_dev->evbit); __set_bit(EV_REP, sensehat_joystick->keys_dev->evbit); for (i = 0; i < ARRAY_SIZE(keymap); i++) __set_bit(keymap[i], sensehat_joystick->keys_dev->keybit); error = input_register_device(sensehat_joystick->keys_dev); if (error) { dev_err(&pdev->dev, "Could not register input device"); return error; } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; error = devm_request_threaded_irq(&pdev->dev, irq, NULL, sensehat_joystick_report, IRQF_ONESHOT, "keys", sensehat_joystick); if (error) { dev_err(&pdev->dev, "IRQ request failed"); return error; } return 0; } static const struct of_device_id sensehat_joystick_device_id[] = { { .compatible = "raspberrypi,sensehat-joystick" }, {}, }; MODULE_DEVICE_TABLE(of, sensehat_joystick_device_id); static struct platform_driver sensehat_joystick_driver = { .probe = sensehat_joystick_probe, .driver = { .name = "sensehat-joystick", .of_match_table = sensehat_joystick_device_id, }, }; module_platform_driver(sensehat_joystick_driver); MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver"); MODULE_AUTHOR("Charles Mirabile "); MODULE_AUTHOR("Serge Schneider "); MODULE_LICENSE("GPL");