Merge tag 'v5.15.57' into rpi-5.15.y
[platform/kernel/linux-rpi.git] / drivers / input / joystick / rpisense-js.c
1 /*
2  * Raspberry Pi Sense HAT joystick driver
3  * http://raspberrypi.org
4  *
5  * Copyright (C) 2015 Raspberry Pi
6  *
7  * Author: Serge Schneider
8  *
9  *  This program is free software; you can redistribute  it and/or modify it
10  *  under  the terms of  the GNU General  Public License as published by the
11  *  Free Software Foundation;  either version 2 of the  License, or (at your
12  *  option) any later version.
13  *
14  */
15
16 #include <linux/module.h>
17
18 #include <linux/mfd/rpisense/joystick.h>
19 #include <linux/mfd/rpisense/core.h>
20
21 static struct rpisense *rpisense;
22 static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
23
24 static void keys_work_fn(struct work_struct *work)
25 {
26         int i;
27         static s32 prev_keys;
28         struct rpisense_js *rpisense_js = &rpisense->joystick;
29         s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
30         s32 changes = keys ^ prev_keys;
31
32         prev_keys = keys;
33         for (i = 0; i < 5; i++) {
34                 if (changes & 1) {
35                         input_report_key(rpisense_js->keys_dev,
36                                          keymap[i], keys & 1);
37                 }
38                 changes >>= 1;
39                 keys >>= 1;
40         }
41         input_sync(rpisense_js->keys_dev);
42 }
43
44 static irqreturn_t keys_irq_handler(int irq, void *pdev)
45 {
46         struct rpisense_js *rpisense_js = &rpisense->joystick;
47
48         schedule_work(&rpisense_js->keys_work_s);
49         return IRQ_HANDLED;
50 }
51
52 static int rpisense_js_probe(struct platform_device *pdev)
53 {
54         int ret;
55         int i;
56         struct rpisense_js *rpisense_js;
57
58         rpisense = rpisense_get_dev();
59         rpisense_js = &rpisense->joystick;
60
61         INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
62
63         rpisense_js->keys_dev = input_allocate_device();
64         if (!rpisense_js->keys_dev) {
65                 dev_err(&pdev->dev, "Could not allocate input device.\n");
66                 return -ENOMEM;
67         }
68
69         rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
70         for (i = 0; i < ARRAY_SIZE(keymap); i++) {
71                 set_bit(keymap[i],
72                         rpisense_js->keys_dev->keybit);
73         }
74
75         rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
76         rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
77         rpisense_js->keys_dev->id.bustype = BUS_I2C;
78         rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
79         rpisense_js->keys_dev->keycode = keymap;
80         rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
81         rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
82
83         ret = input_register_device(rpisense_js->keys_dev);
84         if (ret) {
85                 dev_err(&pdev->dev, "Could not register input device.\n");
86                 goto err_keys_alloc;
87         }
88
89         ret = gpiod_direction_input(rpisense_js->keys_desc);
90         if (ret) {
91                 dev_err(&pdev->dev, "Could not set keys-int direction.\n");
92                 goto err_keys_reg;
93         }
94
95         rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
96         if (rpisense_js->keys_irq < 0) {
97                 dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
98                 ret = rpisense_js->keys_irq;
99                 goto err_keys_reg;
100         }
101
102         ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
103                                keys_irq_handler, IRQF_TRIGGER_RISING,
104                                "keys", &pdev->dev);
105         if (ret) {
106                 dev_err(&pdev->dev, "IRQ request failed.\n");
107                 goto err_keys_reg;
108         }
109         return 0;
110 err_keys_reg:
111         input_unregister_device(rpisense_js->keys_dev);
112 err_keys_alloc:
113         input_free_device(rpisense_js->keys_dev);
114         return ret;
115 }
116
117 static int rpisense_js_remove(struct platform_device *pdev)
118 {
119         struct rpisense_js *rpisense_js = &rpisense->joystick;
120
121         input_unregister_device(rpisense_js->keys_dev);
122         input_free_device(rpisense_js->keys_dev);
123         return 0;
124 }
125
126 #ifdef CONFIG_OF
127 static const struct of_device_id rpisense_js_id[] = {
128         { .compatible = "rpi,rpi-sense-js" },
129         { },
130 };
131 MODULE_DEVICE_TABLE(of, rpisense_js_id);
132 #endif
133
134 static struct platform_device_id rpisense_js_device_id[] = {
135         { .name = "rpi-sense-js" },
136         { },
137 };
138 MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
139
140 static struct platform_driver rpisense_js_driver = {
141         .probe = rpisense_js_probe,
142         .remove = rpisense_js_remove,
143         .driver = {
144                 .name = "rpi-sense-js",
145                 .owner = THIS_MODULE,
146         },
147 };
148
149 module_platform_driver(rpisense_js_driver);
150
151 MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
152 MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
153 MODULE_LICENSE("GPL");