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 v6.18 330 lines 8.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2023 Anshul Dalal <anshulusr@gmail.com> 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 59static 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 64struct seesaw_gamepad { 65 struct input_dev *input_dev; 66 struct i2c_client *i2c_client; 67 u32 button_state; 68}; 69 70struct seesaw_data { 71 u16 x; 72 u16 y; 73 u32 button_state; 74}; 75 76static 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 86static 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 114static 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 130static 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 145static 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 182static 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 191static 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 223static 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 306static const struct i2c_device_id seesaw_id_table[] = { 307 { SEESAW_DEVICE_NAME }, 308 { /* Sentinel */ } 309}; 310MODULE_DEVICE_TABLE(i2c, seesaw_id_table); 311 312static const struct of_device_id seesaw_of_table[] = { 313 { .compatible = "adafruit,seesaw-gamepad"}, 314 { /* Sentinel */ } 315}; 316MODULE_DEVICE_TABLE(of, seesaw_of_table); 317 318static 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}; 326module_i2c_driver(seesaw_driver); 327 328MODULE_AUTHOR("Anshul Dalal <anshulusr@gmail.com>"); 329MODULE_DESCRIPTION("Adafruit Mini I2C Gamepad driver"); 330MODULE_LICENSE("GPL");