]> Git Repo - J-linux.git/blob - drivers/input/joystick/adafruit-seesaw.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / input / joystick / adafruit-seesaw.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2023 Anshul Dalal <[email protected]>
4  *
5  * Driver for Adafruit Mini I2C Gamepad
6  *
7  * Based on the work of:
8  *      Oleh Kravchenko (Sparkfun Qwiic Joystick driver)
9  *
10  * Datasheet: https://cdn-learn.adafruit.com/downloads/pdf/gamepad-qt.pdf
11  * Product page: https://www.adafruit.com/product/5743
12  * Firmware and hardware sources: https://github.com/adafruit/Adafruit_Seesaw
13  *
14  * TODO:
15  *      - Add interrupt support
16  */
17
18 #include <linux/unaligned.h>
19 #include <linux/bits.h>
20 #include <linux/delay.h>
21 #include <linux/i2c.h>
22 #include <linux/input.h>
23 #include <linux/input/sparse-keymap.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26
27 #define SEESAW_DEVICE_NAME              "seesaw-gamepad"
28
29 #define SEESAW_ADC_BASE                 0x0900
30
31 #define SEESAW_GPIO_DIRCLR_BULK         0x0103
32 #define SEESAW_GPIO_BULK                0x0104
33 #define SEESAW_GPIO_BULK_SET            0x0105
34 #define SEESAW_GPIO_PULLENSET           0x010b
35
36 #define SEESAW_STATUS_HW_ID             0x0001
37 #define SEESAW_STATUS_SWRST             0x007f
38
39 #define SEESAW_ADC_OFFSET               0x07
40
41 #define SEESAW_BUTTON_A                 0x05
42 #define SEESAW_BUTTON_B                 0x01
43 #define SEESAW_BUTTON_X                 0x06
44 #define SEESAW_BUTTON_Y                 0x02
45 #define SEESAW_BUTTON_START             0x10
46 #define SEESAW_BUTTON_SELECT            0x00
47
48 #define SEESAW_ANALOG_X                 0x0e
49 #define SEESAW_ANALOG_Y                 0x0f
50
51 #define SEESAW_JOYSTICK_MAX_AXIS        1023
52 #define SEESAW_JOYSTICK_FUZZ            2
53 #define SEESAW_JOYSTICK_FLAT            4
54
55 #define SEESAW_GAMEPAD_POLL_INTERVAL_MS 16
56 #define SEESAW_GAMEPAD_POLL_MIN         8
57 #define SEESAW_GAMEPAD_POLL_MAX         32
58
59 static const u32 SEESAW_BUTTON_MASK =
60         BIT(SEESAW_BUTTON_A) | BIT(SEESAW_BUTTON_B) | BIT(SEESAW_BUTTON_X) |
61         BIT(SEESAW_BUTTON_Y) | BIT(SEESAW_BUTTON_START) |
62         BIT(SEESAW_BUTTON_SELECT);
63
64 struct seesaw_gamepad {
65         struct input_dev *input_dev;
66         struct i2c_client *i2c_client;
67         u32 button_state;
68 };
69
70 struct seesaw_data {
71         u16 x;
72         u16 y;
73         u32 button_state;
74 };
75
76 static const struct key_entry seesaw_buttons_new[] = {
77         { KE_KEY, SEESAW_BUTTON_A, .keycode = BTN_SOUTH },
78         { KE_KEY, SEESAW_BUTTON_B, .keycode = BTN_EAST },
79         { KE_KEY, SEESAW_BUTTON_X, .keycode = BTN_NORTH },
80         { KE_KEY, SEESAW_BUTTON_Y, .keycode = BTN_WEST },
81         { KE_KEY, SEESAW_BUTTON_START, .keycode = BTN_START },
82         { KE_KEY, SEESAW_BUTTON_SELECT, .keycode = BTN_SELECT },
83         { KE_END, 0 }
84 };
85
86 static int seesaw_register_read(struct i2c_client *client, u16 reg, void *buf,
87                                 int count)
88 {
89         __be16 register_buf = cpu_to_be16(reg);
90         struct i2c_msg message_buf[2] = {
91                 {
92                         .addr = client->addr,
93                         .flags = client->flags,
94                         .len = sizeof(register_buf),
95                         .buf = (u8 *)&register_buf,
96                 },
97                 {
98                         .addr = client->addr,
99                         .flags = client->flags | I2C_M_RD,
100                         .len = count,
101                         .buf = (u8 *)buf,
102                 },
103         };
104         int ret;
105
106         ret = i2c_transfer(client->adapter, message_buf,
107                            ARRAY_SIZE(message_buf));
108         if (ret < 0)
109                 return ret;
110
111         return 0;
112 }
113
114 static int seesaw_register_write_u8(struct i2c_client *client, u16 reg,
115                                     u8 value)
116 {
117         u8 write_buf[sizeof(reg) + sizeof(value)];
118         int ret;
119
120         put_unaligned_be16(reg, write_buf);
121         write_buf[sizeof(reg)] = value;
122
123         ret = i2c_master_send(client, write_buf, sizeof(write_buf));
124         if (ret < 0)
125                 return ret;
126
127         return 0;
128 }
129
130 static int seesaw_register_write_u32(struct i2c_client *client, u16 reg,
131                                      u32 value)
132 {
133         u8 write_buf[sizeof(reg) + sizeof(value)];
134         int ret;
135
136         put_unaligned_be16(reg, write_buf);
137         put_unaligned_be32(value, write_buf + sizeof(reg));
138         ret = i2c_master_send(client, write_buf, sizeof(write_buf));
139         if (ret < 0)
140                 return ret;
141
142         return 0;
143 }
144
145 static int seesaw_read_data(struct i2c_client *client, struct seesaw_data *data)
146 {
147         __be16 adc_data;
148         __be32 read_buf;
149         int err;
150
151         err = seesaw_register_read(client, SEESAW_GPIO_BULK,
152                                    &read_buf, sizeof(read_buf));
153         if (err)
154                 return err;
155
156         data->button_state = ~be32_to_cpu(read_buf);
157
158         err = seesaw_register_read(client,
159                                    SEESAW_ADC_BASE |
160                                         (SEESAW_ADC_OFFSET + SEESAW_ANALOG_X),
161                                    &adc_data, sizeof(adc_data));
162         if (err)
163                 return err;
164         /*
165          * ADC reads left as max and right as 0, must be reversed since kernel
166          * expects reports in opposite order.
167          */
168         data->x = SEESAW_JOYSTICK_MAX_AXIS - be16_to_cpu(adc_data);
169
170         err = seesaw_register_read(client,
171                                    SEESAW_ADC_BASE |
172                                         (SEESAW_ADC_OFFSET + SEESAW_ANALOG_Y),
173                                    &adc_data, sizeof(adc_data));
174         if (err)
175                 return err;
176
177         data->y = be16_to_cpu(adc_data);
178
179         return 0;
180 }
181
182 static int seesaw_open(struct input_dev *input)
183 {
184         struct seesaw_gamepad *private = input_get_drvdata(input);
185
186         private->button_state = 0;
187
188         return 0;
189 }
190
191 static void seesaw_poll(struct input_dev *input)
192 {
193         struct seesaw_gamepad *private = input_get_drvdata(input);
194         struct seesaw_data data;
195         unsigned long changed;
196         int err, i;
197
198         err = seesaw_read_data(private->i2c_client, &data);
199         if (err) {
200                 dev_err_ratelimited(&input->dev,
201                                     "failed to read joystick state: %d\n", err);
202                 return;
203         }
204
205         input_report_abs(input, ABS_X, data.x);
206         input_report_abs(input, ABS_Y, data.y);
207
208         data.button_state &= SEESAW_BUTTON_MASK;
209         changed = private->button_state ^ data.button_state;
210         private->button_state = data.button_state;
211
212         for_each_set_bit(i, &changed, fls(SEESAW_BUTTON_MASK)) {
213                 if (!sparse_keymap_report_event(input, i,
214                                                 data.button_state & BIT(i),
215                                                 false))
216                         dev_err_ratelimited(&input->dev,
217                                             "failed to report keymap event");
218         }
219
220         input_sync(input);
221 }
222
223 static int seesaw_probe(struct i2c_client *client)
224 {
225         struct seesaw_gamepad *seesaw;
226         u8 hardware_id;
227         int err;
228
229         err = seesaw_register_write_u8(client, SEESAW_STATUS_SWRST, 0xFF);
230         if (err)
231                 return err;
232
233         /* Wait for the registers to reset before proceeding */
234         usleep_range(10000, 15000);
235
236         seesaw = devm_kzalloc(&client->dev, sizeof(*seesaw), GFP_KERNEL);
237         if (!seesaw)
238                 return -ENOMEM;
239
240         err = seesaw_register_read(client, SEESAW_STATUS_HW_ID,
241                                    &hardware_id, sizeof(hardware_id));
242         if (err)
243                 return err;
244
245         dev_dbg(&client->dev, "Adafruit Seesaw Gamepad, Hardware ID: %02x\n",
246                 hardware_id);
247
248         /* Set Pin Mode to input and enable pull-up resistors */
249         err = seesaw_register_write_u32(client, SEESAW_GPIO_DIRCLR_BULK,
250                                         SEESAW_BUTTON_MASK);
251         if (err)
252                 return err;
253         err = seesaw_register_write_u32(client, SEESAW_GPIO_PULLENSET,
254                                         SEESAW_BUTTON_MASK);
255         if (err)
256                 return err;
257         err = seesaw_register_write_u32(client, SEESAW_GPIO_BULK_SET,
258                                         SEESAW_BUTTON_MASK);
259         if (err)
260                 return err;
261
262         seesaw->i2c_client = client;
263         seesaw->input_dev = devm_input_allocate_device(&client->dev);
264         if (!seesaw->input_dev)
265                 return -ENOMEM;
266
267         seesaw->input_dev->id.bustype = BUS_I2C;
268         seesaw->input_dev->name = "Adafruit Seesaw Gamepad";
269         seesaw->input_dev->phys = "i2c/" SEESAW_DEVICE_NAME;
270         seesaw->input_dev->open = seesaw_open;
271         input_set_drvdata(seesaw->input_dev, seesaw);
272         input_set_abs_params(seesaw->input_dev, ABS_X,
273                              0, SEESAW_JOYSTICK_MAX_AXIS,
274                              SEESAW_JOYSTICK_FUZZ, SEESAW_JOYSTICK_FLAT);
275         input_set_abs_params(seesaw->input_dev, ABS_Y,
276                              0, SEESAW_JOYSTICK_MAX_AXIS,
277                              SEESAW_JOYSTICK_FUZZ, SEESAW_JOYSTICK_FLAT);
278
279         err = sparse_keymap_setup(seesaw->input_dev, seesaw_buttons_new, NULL);
280         if (err) {
281                 dev_err(&client->dev,
282                         "failed to set up input device keymap: %d\n", err);
283                 return err;
284         }
285
286         err = input_setup_polling(seesaw->input_dev, seesaw_poll);
287         if (err) {
288                 dev_err(&client->dev, "failed to set up polling: %d\n", err);
289                 return err;
290         }
291
292         input_set_poll_interval(seesaw->input_dev,
293                                 SEESAW_GAMEPAD_POLL_INTERVAL_MS);
294         input_set_max_poll_interval(seesaw->input_dev, SEESAW_GAMEPAD_POLL_MAX);
295         input_set_min_poll_interval(seesaw->input_dev, SEESAW_GAMEPAD_POLL_MIN);
296
297         err = input_register_device(seesaw->input_dev);
298         if (err) {
299                 dev_err(&client->dev, "failed to register joystick: %d\n", err);
300                 return err;
301         }
302
303         return 0;
304 }
305
306 static const struct i2c_device_id seesaw_id_table[] = {
307         { SEESAW_DEVICE_NAME },
308         { /* Sentinel */ }
309 };
310 MODULE_DEVICE_TABLE(i2c, seesaw_id_table);
311
312 static const struct of_device_id seesaw_of_table[] = {
313         { .compatible = "adafruit,seesaw-gamepad"},
314         { /* Sentinel */ }
315 };
316 MODULE_DEVICE_TABLE(of, seesaw_of_table);
317
318 static struct i2c_driver seesaw_driver = {
319         .driver = {
320                 .name = SEESAW_DEVICE_NAME,
321                 .of_match_table = seesaw_of_table,
322         },
323         .id_table = seesaw_id_table,
324         .probe = seesaw_probe,
325 };
326 module_i2c_driver(seesaw_driver);
327
328 MODULE_AUTHOR("Anshul Dalal <[email protected]>");
329 MODULE_DESCRIPTION("Adafruit Mini I2C Gamepad driver");
330 MODULE_LICENSE("GPL");
This page took 0.043483 seconds and 4 git commands to generate.