1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * PlayStation 1/2 joypads via SPI interface Driver |
4 | * |
5 | * Copyright (C) 2017 Tomohiro Yoshidomi <sylph23k@gmail.com> |
6 | * |
7 | * PlayStation 1/2 joypad's plug (not socket) |
8 | * 123 456 789 |
9 | * (...|...|...) |
10 | * |
11 | * 1: DAT -> MISO (pullup with 1k owm to 3.3V) |
12 | * 2: CMD -> MOSI |
13 | * 3: 9V (for motor, if not use N.C.) |
14 | * 4: GND |
15 | * 5: 3.3V |
16 | * 6: Attention -> CS(SS) |
17 | * 7: SCK -> SCK |
18 | * 8: N.C. |
19 | * 9: ACK -> N.C. |
20 | */ |
21 | |
22 | #include <linux/kernel.h> |
23 | #include <linux/device.h> |
24 | #include <linux/input.h> |
25 | #include <linux/module.h> |
26 | #include <linux/spi/spi.h> |
27 | #include <linux/types.h> |
28 | #include <linux/pm.h> |
29 | #include <linux/pm_runtime.h> |
30 | |
31 | #define REVERSE_BIT(x) ((((x) & 0x80) >> 7) | (((x) & 0x40) >> 5) | \ |
32 | (((x) & 0x20) >> 3) | (((x) & 0x10) >> 1) | (((x) & 0x08) << 1) | \ |
33 | (((x) & 0x04) << 3) | (((x) & 0x02) << 5) | (((x) & 0x01) << 7)) |
34 | |
35 | /* PlayStation 1/2 joypad command and response are LSBFIRST. */ |
36 | |
37 | /* |
38 | * 0x01, 0x42, 0x00, 0x00, 0x00, |
39 | * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
40 | * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
41 | */ |
42 | static const u8 PSX_CMD_POLL[] = { |
43 | 0x80, 0x42, 0x00, 0x00, 0x00, |
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
46 | }; |
47 | |
48 | #ifdef CONFIG_JOYSTICK_PSXPAD_SPI_FF |
49 | /* 0x01, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 */ |
50 | static const u8 PSX_CMD_ENTER_CFG[] = { |
51 | 0x80, 0xC2, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 |
52 | }; |
53 | /* 0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A */ |
54 | static const u8 PSX_CMD_EXIT_CFG[] = { |
55 | 0x80, 0xC2, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A |
56 | }; |
57 | /* 0x01, 0x4D, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF */ |
58 | static const u8 PSX_CMD_ENABLE_MOTOR[] = { |
59 | 0x80, 0xB2, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF |
60 | }; |
61 | #endif /* CONFIG_JOYSTICK_PSXPAD_SPI_FF */ |
62 | |
63 | struct psxpad { |
64 | struct spi_device *spi; |
65 | struct input_dev *idev; |
66 | char phys[0x20]; |
67 | bool motor1enable; |
68 | bool motor2enable; |
69 | u8 motor1level; |
70 | u8 motor2level; |
71 | u8 sendbuf[0x20] ____cacheline_aligned; |
72 | u8 response[sizeof(PSX_CMD_POLL)] ____cacheline_aligned; |
73 | }; |
74 | |
75 | static int psxpad_command(struct psxpad *pad, const u8 sendcmdlen) |
76 | { |
77 | struct spi_transfer xfers = { |
78 | .tx_buf = pad->sendbuf, |
79 | .rx_buf = pad->response, |
80 | .len = sendcmdlen, |
81 | }; |
82 | int err; |
83 | |
84 | err = spi_sync_transfer(spi: pad->spi, xfers: &xfers, num_xfers: 1); |
85 | if (err) { |
86 | dev_err(&pad->spi->dev, |
87 | "%s: failed to SPI xfers mode: %d\n" , |
88 | __func__, err); |
89 | return err; |
90 | } |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | #ifdef CONFIG_JOYSTICK_PSXPAD_SPI_FF |
96 | static void psxpad_control_motor(struct psxpad *pad, |
97 | bool motor1enable, bool motor2enable) |
98 | { |
99 | int err; |
100 | |
101 | pad->motor1enable = motor1enable; |
102 | pad->motor2enable = motor2enable; |
103 | |
104 | memcpy(pad->sendbuf, PSX_CMD_ENTER_CFG, sizeof(PSX_CMD_ENTER_CFG)); |
105 | err = psxpad_command(pad, sendcmdlen: sizeof(PSX_CMD_ENTER_CFG)); |
106 | if (err) { |
107 | dev_err(&pad->spi->dev, |
108 | "%s: failed to enter config mode: %d\n" , |
109 | __func__, err); |
110 | return; |
111 | } |
112 | |
113 | memcpy(pad->sendbuf, PSX_CMD_ENABLE_MOTOR, |
114 | sizeof(PSX_CMD_ENABLE_MOTOR)); |
115 | pad->sendbuf[3] = pad->motor1enable ? 0x00 : 0xFF; |
116 | pad->sendbuf[4] = pad->motor2enable ? 0x80 : 0xFF; |
117 | err = psxpad_command(pad, sendcmdlen: sizeof(PSX_CMD_ENABLE_MOTOR)); |
118 | if (err) { |
119 | dev_err(&pad->spi->dev, |
120 | "%s: failed to enable motor mode: %d\n" , |
121 | __func__, err); |
122 | return; |
123 | } |
124 | |
125 | memcpy(pad->sendbuf, PSX_CMD_EXIT_CFG, sizeof(PSX_CMD_EXIT_CFG)); |
126 | err = psxpad_command(pad, sendcmdlen: sizeof(PSX_CMD_EXIT_CFG)); |
127 | if (err) { |
128 | dev_err(&pad->spi->dev, |
129 | "%s: failed to exit config mode: %d\n" , |
130 | __func__, err); |
131 | return; |
132 | } |
133 | } |
134 | |
135 | static void psxpad_set_motor_level(struct psxpad *pad, |
136 | u8 motor1level, u8 motor2level) |
137 | { |
138 | pad->motor1level = motor1level ? 0xFF : 0x00; |
139 | pad->motor2level = REVERSE_BIT(motor2level); |
140 | } |
141 | |
142 | static int psxpad_spi_play_effect(struct input_dev *idev, |
143 | void *data, struct ff_effect *effect) |
144 | { |
145 | struct psxpad *pad = input_get_drvdata(dev: idev); |
146 | |
147 | switch (effect->type) { |
148 | case FF_RUMBLE: |
149 | psxpad_set_motor_level(pad, |
150 | motor1level: (effect->u.rumble.weak_magnitude >> 8) & 0xFFU, |
151 | motor2level: (effect->u.rumble.strong_magnitude >> 8) & 0xFFU); |
152 | break; |
153 | } |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | static int psxpad_spi_init_ff(struct psxpad *pad) |
159 | { |
160 | int err; |
161 | |
162 | input_set_capability(dev: pad->idev, EV_FF, FF_RUMBLE); |
163 | |
164 | err = input_ff_create_memless(dev: pad->idev, NULL, play_effect: psxpad_spi_play_effect); |
165 | if (err) { |
166 | dev_err(&pad->spi->dev, |
167 | "input_ff_create_memless() failed: %d\n" , err); |
168 | return err; |
169 | } |
170 | |
171 | return 0; |
172 | } |
173 | |
174 | #else /* CONFIG_JOYSTICK_PSXPAD_SPI_FF */ |
175 | |
176 | static void psxpad_control_motor(struct psxpad *pad, |
177 | bool motor1enable, bool motor2enable) |
178 | { |
179 | } |
180 | |
181 | static void psxpad_set_motor_level(struct psxpad *pad, |
182 | u8 motor1level, u8 motor2level) |
183 | { |
184 | } |
185 | |
186 | static inline int psxpad_spi_init_ff(struct psxpad *pad) |
187 | { |
188 | return 0; |
189 | } |
190 | #endif /* CONFIG_JOYSTICK_PSXPAD_SPI_FF */ |
191 | |
192 | static int psxpad_spi_poll_open(struct input_dev *input) |
193 | { |
194 | struct psxpad *pad = input_get_drvdata(dev: input); |
195 | |
196 | pm_runtime_get_sync(dev: &pad->spi->dev); |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | static void psxpad_spi_poll_close(struct input_dev *input) |
202 | { |
203 | struct psxpad *pad = input_get_drvdata(dev: input); |
204 | |
205 | pm_runtime_put_sync(dev: &pad->spi->dev); |
206 | } |
207 | |
208 | static void psxpad_spi_poll(struct input_dev *input) |
209 | { |
210 | struct psxpad *pad = input_get_drvdata(dev: input); |
211 | u8 b_rsp3, b_rsp4; |
212 | int err; |
213 | |
214 | psxpad_control_motor(pad, motor1enable: true, motor2enable: true); |
215 | |
216 | memcpy(pad->sendbuf, PSX_CMD_POLL, sizeof(PSX_CMD_POLL)); |
217 | pad->sendbuf[3] = pad->motor1enable ? pad->motor1level : 0x00; |
218 | pad->sendbuf[4] = pad->motor2enable ? pad->motor2level : 0x00; |
219 | err = psxpad_command(pad, sendcmdlen: sizeof(PSX_CMD_POLL)); |
220 | if (err) { |
221 | dev_err(&pad->spi->dev, |
222 | "%s: poll command failed mode: %d\n" , __func__, err); |
223 | return; |
224 | } |
225 | |
226 | switch (pad->response[1]) { |
227 | case 0xCE: /* 0x73 : analog 1 */ |
228 | /* button data is inverted */ |
229 | b_rsp3 = ~pad->response[3]; |
230 | b_rsp4 = ~pad->response[4]; |
231 | |
232 | input_report_abs(dev: input, ABS_X, REVERSE_BIT(pad->response[7])); |
233 | input_report_abs(dev: input, ABS_Y, REVERSE_BIT(pad->response[8])); |
234 | input_report_abs(dev: input, ABS_RX, REVERSE_BIT(pad->response[5])); |
235 | input_report_abs(dev: input, ABS_RY, REVERSE_BIT(pad->response[6])); |
236 | input_report_key(dev: input, BTN_DPAD_UP, value: b_rsp3 & BIT(3)); |
237 | input_report_key(dev: input, BTN_DPAD_DOWN, value: b_rsp3 & BIT(1)); |
238 | input_report_key(dev: input, BTN_DPAD_LEFT, value: b_rsp3 & BIT(0)); |
239 | input_report_key(dev: input, BTN_DPAD_RIGHT, value: b_rsp3 & BIT(2)); |
240 | input_report_key(dev: input, BTN_X, value: b_rsp4 & BIT(3)); |
241 | input_report_key(dev: input, BTN_A, value: b_rsp4 & BIT(2)); |
242 | input_report_key(dev: input, BTN_B, value: b_rsp4 & BIT(1)); |
243 | input_report_key(dev: input, BTN_Y, value: b_rsp4 & BIT(0)); |
244 | input_report_key(dev: input, BTN_TL, value: b_rsp4 & BIT(5)); |
245 | input_report_key(dev: input, BTN_TR, value: b_rsp4 & BIT(4)); |
246 | input_report_key(dev: input, BTN_TL2, value: b_rsp4 & BIT(7)); |
247 | input_report_key(dev: input, BTN_TR2, value: b_rsp4 & BIT(6)); |
248 | input_report_key(dev: input, BTN_THUMBL, value: b_rsp3 & BIT(6)); |
249 | input_report_key(dev: input, BTN_THUMBR, value: b_rsp3 & BIT(5)); |
250 | input_report_key(dev: input, BTN_SELECT, value: b_rsp3 & BIT(7)); |
251 | input_report_key(dev: input, BTN_START, value: b_rsp3 & BIT(4)); |
252 | break; |
253 | |
254 | case 0x82: /* 0x41 : digital */ |
255 | /* button data is inverted */ |
256 | b_rsp3 = ~pad->response[3]; |
257 | b_rsp4 = ~pad->response[4]; |
258 | |
259 | input_report_abs(dev: input, ABS_X, value: 0x80); |
260 | input_report_abs(dev: input, ABS_Y, value: 0x80); |
261 | input_report_abs(dev: input, ABS_RX, value: 0x80); |
262 | input_report_abs(dev: input, ABS_RY, value: 0x80); |
263 | input_report_key(dev: input, BTN_DPAD_UP, value: b_rsp3 & BIT(3)); |
264 | input_report_key(dev: input, BTN_DPAD_DOWN, value: b_rsp3 & BIT(1)); |
265 | input_report_key(dev: input, BTN_DPAD_LEFT, value: b_rsp3 & BIT(0)); |
266 | input_report_key(dev: input, BTN_DPAD_RIGHT, value: b_rsp3 & BIT(2)); |
267 | input_report_key(dev: input, BTN_X, value: b_rsp4 & BIT(3)); |
268 | input_report_key(dev: input, BTN_A, value: b_rsp4 & BIT(2)); |
269 | input_report_key(dev: input, BTN_B, value: b_rsp4 & BIT(1)); |
270 | input_report_key(dev: input, BTN_Y, value: b_rsp4 & BIT(0)); |
271 | input_report_key(dev: input, BTN_TL, value: b_rsp4 & BIT(5)); |
272 | input_report_key(dev: input, BTN_TR, value: b_rsp4 & BIT(4)); |
273 | input_report_key(dev: input, BTN_TL2, value: b_rsp4 & BIT(7)); |
274 | input_report_key(dev: input, BTN_TR2, value: b_rsp4 & BIT(6)); |
275 | input_report_key(dev: input, BTN_THUMBL, value: false); |
276 | input_report_key(dev: input, BTN_THUMBR, value: false); |
277 | input_report_key(dev: input, BTN_SELECT, value: b_rsp3 & BIT(7)); |
278 | input_report_key(dev: input, BTN_START, value: b_rsp3 & BIT(4)); |
279 | break; |
280 | } |
281 | |
282 | input_sync(dev: input); |
283 | } |
284 | |
285 | static int psxpad_spi_probe(struct spi_device *spi) |
286 | { |
287 | struct psxpad *pad; |
288 | struct input_dev *idev; |
289 | int err; |
290 | |
291 | pad = devm_kzalloc(dev: &spi->dev, size: sizeof(struct psxpad), GFP_KERNEL); |
292 | if (!pad) |
293 | return -ENOMEM; |
294 | |
295 | idev = devm_input_allocate_device(&spi->dev); |
296 | if (!idev) { |
297 | dev_err(&spi->dev, "failed to allocate input device\n" ); |
298 | return -ENOMEM; |
299 | } |
300 | |
301 | /* input poll device settings */ |
302 | pad->idev = idev; |
303 | pad->spi = spi; |
304 | |
305 | /* input device settings */ |
306 | input_set_drvdata(dev: idev, data: pad); |
307 | |
308 | idev->name = "PlayStation 1/2 joypad" ; |
309 | snprintf(buf: pad->phys, size: sizeof(pad->phys), fmt: "%s/input" , dev_name(dev: &spi->dev)); |
310 | idev->id.bustype = BUS_SPI; |
311 | |
312 | idev->open = psxpad_spi_poll_open; |
313 | idev->close = psxpad_spi_poll_close; |
314 | |
315 | /* key/value map settings */ |
316 | input_set_abs_params(dev: idev, ABS_X, min: 0, max: 255, fuzz: 0, flat: 0); |
317 | input_set_abs_params(dev: idev, ABS_Y, min: 0, max: 255, fuzz: 0, flat: 0); |
318 | input_set_abs_params(dev: idev, ABS_RX, min: 0, max: 255, fuzz: 0, flat: 0); |
319 | input_set_abs_params(dev: idev, ABS_RY, min: 0, max: 255, fuzz: 0, flat: 0); |
320 | input_set_capability(dev: idev, EV_KEY, BTN_DPAD_UP); |
321 | input_set_capability(dev: idev, EV_KEY, BTN_DPAD_DOWN); |
322 | input_set_capability(dev: idev, EV_KEY, BTN_DPAD_LEFT); |
323 | input_set_capability(dev: idev, EV_KEY, BTN_DPAD_RIGHT); |
324 | input_set_capability(dev: idev, EV_KEY, BTN_A); |
325 | input_set_capability(dev: idev, EV_KEY, BTN_B); |
326 | input_set_capability(dev: idev, EV_KEY, BTN_X); |
327 | input_set_capability(dev: idev, EV_KEY, BTN_Y); |
328 | input_set_capability(dev: idev, EV_KEY, BTN_TL); |
329 | input_set_capability(dev: idev, EV_KEY, BTN_TR); |
330 | input_set_capability(dev: idev, EV_KEY, BTN_TL2); |
331 | input_set_capability(dev: idev, EV_KEY, BTN_TR2); |
332 | input_set_capability(dev: idev, EV_KEY, BTN_THUMBL); |
333 | input_set_capability(dev: idev, EV_KEY, BTN_THUMBR); |
334 | input_set_capability(dev: idev, EV_KEY, BTN_SELECT); |
335 | input_set_capability(dev: idev, EV_KEY, BTN_START); |
336 | |
337 | err = psxpad_spi_init_ff(pad); |
338 | if (err) |
339 | return err; |
340 | |
341 | /* SPI settings */ |
342 | spi->mode = SPI_MODE_3; |
343 | spi->bits_per_word = 8; |
344 | /* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */ |
345 | spi->master->min_speed_hz = 125000; |
346 | spi->master->max_speed_hz = 125000; |
347 | spi_setup(spi); |
348 | |
349 | /* pad settings */ |
350 | psxpad_set_motor_level(pad, motor1level: 0, motor2level: 0); |
351 | |
352 | |
353 | err = input_setup_polling(dev: idev, poll_fn: psxpad_spi_poll); |
354 | if (err) { |
355 | dev_err(&spi->dev, "failed to set up polling: %d\n" , err); |
356 | return err; |
357 | } |
358 | |
359 | /* poll interval is about 60fps */ |
360 | input_set_poll_interval(dev: idev, interval: 16); |
361 | input_set_min_poll_interval(dev: idev, interval: 8); |
362 | input_set_max_poll_interval(dev: idev, interval: 32); |
363 | |
364 | /* register input poll device */ |
365 | err = input_register_device(idev); |
366 | if (err) { |
367 | dev_err(&spi->dev, |
368 | "failed to register input device: %d\n" , err); |
369 | return err; |
370 | } |
371 | |
372 | pm_runtime_enable(dev: &spi->dev); |
373 | |
374 | return 0; |
375 | } |
376 | |
377 | static int psxpad_spi_suspend(struct device *dev) |
378 | { |
379 | struct spi_device *spi = to_spi_device(dev); |
380 | struct psxpad *pad = spi_get_drvdata(spi); |
381 | |
382 | psxpad_set_motor_level(pad, motor1level: 0, motor2level: 0); |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | static DEFINE_SIMPLE_DEV_PM_OPS(psxpad_spi_pm, psxpad_spi_suspend, NULL); |
388 | |
389 | static const struct spi_device_id psxpad_spi_id[] = { |
390 | { "psxpad-spi" , 0 }, |
391 | { } |
392 | }; |
393 | MODULE_DEVICE_TABLE(spi, psxpad_spi_id); |
394 | |
395 | static struct spi_driver psxpad_spi_driver = { |
396 | .driver = { |
397 | .name = "psxpad-spi" , |
398 | .pm = pm_sleep_ptr(&psxpad_spi_pm), |
399 | }, |
400 | .id_table = psxpad_spi_id, |
401 | .probe = psxpad_spi_probe, |
402 | }; |
403 | |
404 | module_spi_driver(psxpad_spi_driver); |
405 | |
406 | MODULE_AUTHOR("Tomohiro Yoshidomi <sylph23k@gmail.com>" ); |
407 | MODULE_DESCRIPTION("PlayStation 1/2 joypads via SPI interface Driver" ); |
408 | MODULE_LICENSE("GPL" ); |
409 | |