/* * Raspberry Pi Sense HAT joystick driver * http://raspberrypi.org * * Copyright (C) 2015 Raspberry Pi * * Author: Serge Schneider * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include #include #include static struct rpisense *rpisense; static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,}; static void keys_work_fn(struct work_struct *work) { int i; static s32 prev_keys; struct rpisense_js *rpisense_js = &rpisense->joystick; s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS); s32 changes = keys ^ prev_keys; prev_keys = keys; for (i = 0; i < 5; i++) { if (changes & 1) { input_report_key(rpisense_js->keys_dev, keymap[i], keys & 1); } changes >>= 1; keys >>= 1; } input_sync(rpisense_js->keys_dev); } static irqreturn_t keys_irq_handler(int irq, void *pdev) { struct rpisense_js *rpisense_js = &rpisense->joystick; schedule_work(&rpisense_js->keys_work_s); return IRQ_HANDLED; } static int rpisense_js_probe(struct platform_device *pdev) { int ret; int i; struct rpisense_js *rpisense_js; rpisense = rpisense_get_dev(); rpisense_js = &rpisense->joystick; INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn); rpisense_js->keys_dev = input_allocate_device(); if (!rpisense_js->keys_dev) { dev_err(&pdev->dev, "Could not allocate input device.\n"); return -ENOMEM; } rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY); for (i = 0; i < ARRAY_SIZE(keymap); i++) { set_bit(keymap[i], rpisense_js->keys_dev->keybit); } rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick"; rpisense_js->keys_dev->phys = "rpi-sense-joy/input0"; rpisense_js->keys_dev->id.bustype = BUS_I2C; rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); rpisense_js->keys_dev->keycode = keymap; rpisense_js->keys_dev->keycodesize = sizeof(unsigned char); rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap); ret = input_register_device(rpisense_js->keys_dev); if (ret) { dev_err(&pdev->dev, "Could not register input device.\n"); goto err_keys_alloc; } ret = gpiod_direction_input(rpisense_js->keys_desc); if (ret) { dev_err(&pdev->dev, "Could not set keys-int direction.\n"); goto err_keys_reg; } rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc); if (rpisense_js->keys_irq < 0) { dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n"); ret = rpisense_js->keys_irq; goto err_keys_reg; } ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq, keys_irq_handler, IRQF_TRIGGER_RISING, "keys", &pdev->dev); if (ret) { dev_err(&pdev->dev, "IRQ request failed.\n"); goto err_keys_reg; } return 0; err_keys_reg: input_unregister_device(rpisense_js->keys_dev); err_keys_alloc: input_free_device(rpisense_js->keys_dev); return ret; } static int rpisense_js_remove(struct platform_device *pdev) { struct rpisense_js *rpisense_js = &rpisense->joystick; input_unregister_device(rpisense_js->keys_dev); input_free_device(rpisense_js->keys_dev); return 0; } #ifdef CONFIG_OF static const struct of_device_id rpisense_js_id[] = { { .compatible = "rpi,rpi-sense-js" }, { }, }; MODULE_DEVICE_TABLE(of, rpisense_js_id); #endif static struct platform_device_id rpisense_js_device_id[] = { { .name = "rpi-sense-js" }, { }, }; MODULE_DEVICE_TABLE(platform, rpisense_js_device_id); static struct platform_driver rpisense_js_driver = { .probe = rpisense_js_probe, .remove = rpisense_js_remove, .driver = { .name = "rpi-sense-js", .owner = THIS_MODULE, }, }; module_platform_driver(rpisense_js_driver); MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver"); MODULE_AUTHOR("Serge Schneider "); MODULE_LICENSE("GPL");