Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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