Commit | Line | Data |
---|---|---|
552e4047 OK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2021 Oleh Kravchenko <oleg@kaa.org.ua> | |
4 | * | |
5 | * SparkFun Qwiic Joystick | |
6 | * Product page:https://www.sparkfun.com/products/15168 | |
7 | * Firmware and hardware sources:https://github.com/sparkfun/Qwiic_Joystick | |
8 | */ | |
9 | ||
10 | #include <linux/bits.h> | |
11 | #include <linux/i2c.h> | |
12 | #include <linux/input.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
15 | ||
16 | #define DRV_NAME "qwiic-joystick" | |
17 | ||
18 | #define QWIIC_JSK_REG_VERS 1 | |
19 | #define QWIIC_JSK_REG_DATA 3 | |
20 | ||
21 | #define QWIIC_JSK_MAX_AXIS GENMASK(9, 0) | |
22 | #define QWIIC_JSK_FUZZ 2 | |
23 | #define QWIIC_JSK_FLAT 2 | |
24 | #define QWIIC_JSK_POLL_INTERVAL 16 | |
25 | #define QWIIC_JSK_POLL_MIN 8 | |
26 | #define QWIIC_JSK_POLL_MAX 32 | |
27 | ||
28 | struct qwiic_jsk { | |
29 | char phys[32]; | |
30 | struct input_dev *dev; | |
31 | struct i2c_client *client; | |
32 | }; | |
33 | ||
34 | struct qwiic_ver { | |
35 | u8 major; | |
36 | u8 minor; | |
37 | }; | |
38 | ||
39 | struct qwiic_data { | |
40 | __be16 x; | |
41 | __be16 y; | |
42 | u8 thumb; | |
43 | }; | |
44 | ||
45 | static void qwiic_poll(struct input_dev *input) | |
46 | { | |
47 | struct qwiic_jsk *priv = input_get_drvdata(input); | |
48 | struct qwiic_data data; | |
49 | int err; | |
50 | ||
51 | err = i2c_smbus_read_i2c_block_data(priv->client, QWIIC_JSK_REG_DATA, | |
52 | sizeof(data), (u8 *)&data); | |
53 | if (err != sizeof(data)) | |
54 | return; | |
55 | ||
56 | input_report_abs(input, ABS_X, be16_to_cpu(data.x) >> 6); | |
57 | input_report_abs(input, ABS_Y, be16_to_cpu(data.y) >> 6); | |
58 | input_report_key(input, BTN_THUMBL, !data.thumb); | |
59 | input_sync(input); | |
60 | } | |
61 | ||
62 | static int qwiic_probe(struct i2c_client *client) | |
63 | { | |
64 | struct qwiic_jsk *priv; | |
65 | struct qwiic_ver vers; | |
66 | int err; | |
67 | ||
68 | err = i2c_smbus_read_i2c_block_data(client, QWIIC_JSK_REG_VERS, | |
69 | sizeof(vers), (u8 *)&vers); | |
70 | if (err < 0) | |
71 | return err; | |
72 | if (err != sizeof(vers)) | |
73 | return -EIO; | |
74 | ||
75 | dev_dbg(&client->dev, "SparkFun Qwiic Joystick, FW: %u.%u\n", | |
76 | vers.major, vers.minor); | |
77 | ||
78 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); | |
79 | if (!priv) | |
80 | return -ENOMEM; | |
81 | ||
82 | priv->client = client; | |
83 | snprintf(priv->phys, sizeof(priv->phys), | |
84 | "i2c/%s", dev_name(&client->dev)); | |
85 | i2c_set_clientdata(client, priv); | |
86 | ||
87 | priv->dev = devm_input_allocate_device(&client->dev); | |
88 | if (!priv->dev) | |
89 | return -ENOMEM; | |
90 | ||
91 | priv->dev->id.bustype = BUS_I2C; | |
92 | priv->dev->name = "SparkFun Qwiic Joystick"; | |
93 | priv->dev->phys = priv->phys; | |
94 | input_set_drvdata(priv->dev, priv); | |
95 | ||
96 | input_set_abs_params(priv->dev, ABS_X, 0, QWIIC_JSK_MAX_AXIS, | |
97 | QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT); | |
98 | input_set_abs_params(priv->dev, ABS_Y, 0, QWIIC_JSK_MAX_AXIS, | |
99 | QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT); | |
100 | input_set_capability(priv->dev, EV_KEY, BTN_THUMBL); | |
101 | ||
102 | err = input_setup_polling(priv->dev, qwiic_poll); | |
103 | if (err) { | |
104 | dev_err(&client->dev, "failed to set up polling: %d\n", err); | |
105 | return err; | |
106 | } | |
107 | input_set_poll_interval(priv->dev, QWIIC_JSK_POLL_INTERVAL); | |
108 | input_set_min_poll_interval(priv->dev, QWIIC_JSK_POLL_MIN); | |
109 | input_set_max_poll_interval(priv->dev, QWIIC_JSK_POLL_MAX); | |
110 | ||
111 | err = input_register_device(priv->dev); | |
112 | if (err) { | |
113 | dev_err(&client->dev, "failed to register joystick: %d\n", err); | |
114 | return err; | |
115 | } | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | #ifdef CONFIG_OF | |
121 | static const struct of_device_id of_qwiic_match[] = { | |
122 | { .compatible = "sparkfun,qwiic-joystick", }, | |
123 | { }, | |
124 | }; | |
125 | MODULE_DEVICE_TABLE(of, of_qwiic_match); | |
126 | #endif /* CONFIG_OF */ | |
127 | ||
128 | static const struct i2c_device_id qwiic_id_table[] = { | |
129 | { KBUILD_MODNAME, 0 }, | |
130 | { }, | |
131 | }; | |
132 | MODULE_DEVICE_TABLE(i2c, qwiic_id_table); | |
133 | ||
134 | static struct i2c_driver qwiic_driver = { | |
135 | .driver = { | |
136 | .name = DRV_NAME, | |
137 | .of_match_table = of_match_ptr(of_qwiic_match), | |
138 | }, | |
139 | .id_table = qwiic_id_table, | |
d8bde56d | 140 | .probe = qwiic_probe, |
552e4047 OK |
141 | }; |
142 | module_i2c_driver(qwiic_driver); | |
143 | ||
144 | MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>"); | |
145 | MODULE_DESCRIPTION("SparkFun Qwiic Joystick driver"); | |
146 | MODULE_LICENSE("GPL v2"); |