Skip to content

Commit d862a30

Browse files
sredtor
authored andcommitted
Input: exc3000 - add support to query model and fw_version
Expose model and fw_version via sysfs. Also query the model in probe to make sure, that the I2C communication with the device works before successfully probing the driver. This is a bit complicated, since EETI devices do not have a sync interface. Sending the commands and directly reading does not work. Sending the command and waiting for some time is also not an option, since there might be touch events in the mean time. Last but not least we do not cache the results, since this interface can be used to check the I2C communication is still working as expected. Reviewed-by: Enric Balletbo i Serra <[email protected]> Signed-off-by: Sebastian Reichel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 27aced1 commit d862a30

File tree

2 files changed

+162
-1
lines changed

2 files changed

+162
-1
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
What: /sys/bus/i2c/devices/xxx/fw_version
2+
Date: Aug 2020
3+
4+
Description: Reports the firmware version provided by the touchscreen, for example "00_T6" on a EXC80H60
5+
6+
Access: Read
7+
Valid values: Represented as string
8+
9+
What: /sys/bus/i2c/devices/xxx/model
10+
Date: Aug 2020
11+
12+
Description: Reports the model identification provided by the touchscreen, for example "Orion_1320" on a EXC80H60
13+
14+
Access: Read
15+
Valid values: Represented as string

drivers/input/touchscreen/exc3000.c

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#define EXC3000_LEN_FRAME 66
2828
#define EXC3000_LEN_POINT 10
2929

30+
#define EXC3000_LEN_MODEL_NAME 16
31+
#define EXC3000_LEN_FW_VERSION 16
32+
3033
#define EXC3000_MT1_EVENT 0x06
3134
#define EXC3000_MT2_EVENT 0x18
3235

@@ -71,6 +74,11 @@ struct exc3000_data {
7174
struct gpio_desc *reset;
7275
struct timer_list timer;
7376
u8 buf[2 * EXC3000_LEN_FRAME];
77+
struct completion wait_event;
78+
struct mutex query_lock;
79+
int query_result;
80+
char model[EXC3000_LEN_MODEL_NAME];
81+
char fw_version[EXC3000_LEN_FW_VERSION];
7482
};
7583

7684
static void exc3000_report_slots(struct input_dev *input,
@@ -156,6 +164,28 @@ static int exc3000_read_data(struct exc3000_data *data,
156164
return 0;
157165
}
158166

167+
static int exc3000_query_interrupt(struct exc3000_data *data)
168+
{
169+
u8 *buf = data->buf;
170+
int error;
171+
172+
error = i2c_master_recv(data->client, buf, EXC3000_LEN_FRAME);
173+
if (error < 0)
174+
return error;
175+
176+
if (buf[0] != 'B')
177+
return -EPROTO;
178+
179+
if (buf[4] == 'E')
180+
strlcpy(data->model, buf + 5, sizeof(data->model));
181+
else if (buf[4] == 'D')
182+
strlcpy(data->fw_version, buf + 5, sizeof(data->fw_version));
183+
else
184+
return -EPROTO;
185+
186+
return 0;
187+
}
188+
159189
static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
160190
{
161191
struct exc3000_data *data = dev_id;
@@ -164,6 +194,12 @@ static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
164194
int slots, total_slots;
165195
int error;
166196

197+
if (mutex_is_locked(&data->query_lock)) {
198+
data->query_result = exc3000_query_interrupt(data);
199+
complete(&data->wait_event);
200+
goto out;
201+
}
202+
167203
error = exc3000_read_data(data, buf, &total_slots);
168204
if (error) {
169205
/* Schedule a timer to release "stuck" contacts */
@@ -191,11 +227,91 @@ static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
191227
return IRQ_HANDLED;
192228
}
193229

230+
static ssize_t fw_version_show(struct device *dev,
231+
struct device_attribute *attr, char *buf)
232+
{
233+
struct i2c_client *client = to_i2c_client(dev);
234+
struct exc3000_data *data = i2c_get_clientdata(client);
235+
static const u8 request[68] = {
236+
0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'D', 0x00
237+
};
238+
int error;
239+
240+
mutex_lock(&data->query_lock);
241+
242+
data->query_result = -ETIMEDOUT;
243+
reinit_completion(&data->wait_event);
244+
245+
error = i2c_master_send(client, request, sizeof(request));
246+
if (error < 0) {
247+
mutex_unlock(&data->query_lock);
248+
return error;
249+
}
250+
251+
wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ);
252+
mutex_unlock(&data->query_lock);
253+
254+
if (data->query_result < 0)
255+
return data->query_result;
256+
257+
return sprintf(buf, "%s\n", data->fw_version);
258+
}
259+
static DEVICE_ATTR_RO(fw_version);
260+
261+
static ssize_t exc3000_get_model(struct exc3000_data *data)
262+
{
263+
static const u8 request[68] = {
264+
0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00
265+
};
266+
struct i2c_client *client = data->client;
267+
int error;
268+
269+
mutex_lock(&data->query_lock);
270+
data->query_result = -ETIMEDOUT;
271+
reinit_completion(&data->wait_event);
272+
273+
error = i2c_master_send(client, request, sizeof(request));
274+
if (error < 0) {
275+
mutex_unlock(&data->query_lock);
276+
return error;
277+
}
278+
279+
wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ);
280+
mutex_unlock(&data->query_lock);
281+
282+
return data->query_result;
283+
}
284+
285+
static ssize_t model_show(struct device *dev,
286+
struct device_attribute *attr, char *buf)
287+
{
288+
struct i2c_client *client = to_i2c_client(dev);
289+
struct exc3000_data *data = i2c_get_clientdata(client);
290+
int error;
291+
292+
error = exc3000_get_model(data);
293+
if (error < 0)
294+
return error;
295+
296+
return sprintf(buf, "%s\n", data->model);
297+
}
298+
static DEVICE_ATTR_RO(model);
299+
300+
static struct attribute *sysfs_attrs[] = {
301+
&dev_attr_fw_version.attr,
302+
&dev_attr_model.attr,
303+
NULL
304+
};
305+
306+
static struct attribute_group exc3000_attribute_group = {
307+
.attrs = sysfs_attrs
308+
};
309+
194310
static int exc3000_probe(struct i2c_client *client)
195311
{
196312
struct exc3000_data *data;
197313
struct input_dev *input;
198-
int error, max_xy;
314+
int error, max_xy, retry;
199315

200316
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
201317
if (!data)
@@ -209,6 +325,8 @@ static int exc3000_probe(struct i2c_client *client)
209325
data->info = &exc3000_info[eeti_dev_id];
210326
}
211327
timer_setup(&data->timer, exc3000_timer, 0);
328+
init_completion(&data->wait_event);
329+
mutex_init(&data->query_lock);
212330

213331
data->reset = devm_gpiod_get_optional(&client->dev, "reset",
214332
GPIOD_OUT_HIGH);
@@ -226,6 +344,7 @@ static int exc3000_probe(struct i2c_client *client)
226344
return -ENOMEM;
227345

228346
data->input = input;
347+
input_set_drvdata(input, data);
229348

230349
input->name = data->info->name;
231350
input->id.bustype = BUS_I2C;
@@ -251,6 +370,33 @@ static int exc3000_probe(struct i2c_client *client)
251370
if (error)
252371
return error;
253372

373+
/*
374+
* I²C does not have built-in recovery, so retry on failure. This
375+
* ensures, that the device probe will not fail for temporary issues
376+
* on the bus. This is not needed for the sysfs calls (userspace
377+
* will receive the error code and can start another query) and
378+
* cannot be done for touch events (but that only means loosing one
379+
* or two touch events anyways).
380+
*/
381+
for (retry = 0; retry < 3; retry++) {
382+
error = exc3000_get_model(data);
383+
if (!error)
384+
break;
385+
dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n",
386+
retry + 1, error);
387+
}
388+
389+
if (error)
390+
return error;
391+
392+
dev_dbg(&client->dev, "TS Model: %s", data->model);
393+
394+
i2c_set_clientdata(client, data);
395+
396+
error = devm_device_add_group(&client->dev, &exc3000_attribute_group);
397+
if (error)
398+
return error;
399+
254400
return 0;
255401
}
256402

0 commit comments

Comments
 (0)