File Index
Files and directories
Sign in
FILE

adafruit-seesaw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/input/joystick/adafruit-seesaw.c C
  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");
~/ Read-only file preview.