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

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 <enric.balletbo@collabora.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20200805160520.456570-5-sebastian.reichel@collabora.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Sebastian Reichel and committed by
Dmitry Torokhov
d862a306 27aced19

+162 -1
+15
Documentation/ABI/testing/sysfs-driver-input-exc3000
··· 1 + What: /sys/bus/i2c/devices/xxx/fw_version 2 + Date: Aug 2020 3 + Contact: linux-input@vger.kernel.org 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 + Contact: linux-input@vger.kernel.org 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
+147 -1
drivers/input/touchscreen/exc3000.c
··· 27 27 #define EXC3000_LEN_FRAME 66 28 28 #define EXC3000_LEN_POINT 10 29 29 30 + #define EXC3000_LEN_MODEL_NAME 16 31 + #define EXC3000_LEN_FW_VERSION 16 32 + 30 33 #define EXC3000_MT1_EVENT 0x06 31 34 #define EXC3000_MT2_EVENT 0x18 32 35 ··· 74 71 struct gpio_desc *reset; 75 72 struct timer_list timer; 76 73 u8 buf[2 * EXC3000_LEN_FRAME]; 74 + struct completion wait_event; 75 + struct mutex query_lock; 76 + int query_result; 77 + char model[EXC3000_LEN_MODEL_NAME]; 78 + char fw_version[EXC3000_LEN_FW_VERSION]; 77 79 }; 78 80 79 81 static void exc3000_report_slots(struct input_dev *input, ··· 164 156 return 0; 165 157 } 166 158 159 + static int exc3000_query_interrupt(struct exc3000_data *data) 160 + { 161 + u8 *buf = data->buf; 162 + int error; 163 + 164 + error = i2c_master_recv(data->client, buf, EXC3000_LEN_FRAME); 165 + if (error < 0) 166 + return error; 167 + 168 + if (buf[0] != 'B') 169 + return -EPROTO; 170 + 171 + if (buf[4] == 'E') 172 + strlcpy(data->model, buf + 5, sizeof(data->model)); 173 + else if (buf[4] == 'D') 174 + strlcpy(data->fw_version, buf + 5, sizeof(data->fw_version)); 175 + else 176 + return -EPROTO; 177 + 178 + return 0; 179 + } 180 + 167 181 static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 168 182 { 169 183 struct exc3000_data *data = dev_id; ··· 193 163 u8 *buf = data->buf; 194 164 int slots, total_slots; 195 165 int error; 166 + 167 + if (mutex_is_locked(&data->query_lock)) { 168 + data->query_result = exc3000_query_interrupt(data); 169 + complete(&data->wait_event); 170 + goto out; 171 + } 196 172 197 173 error = exc3000_read_data(data, buf, &total_slots); 198 174 if (error) { ··· 227 191 return IRQ_HANDLED; 228 192 } 229 193 194 + static ssize_t fw_version_show(struct device *dev, 195 + struct device_attribute *attr, char *buf) 196 + { 197 + struct i2c_client *client = to_i2c_client(dev); 198 + struct exc3000_data *data = i2c_get_clientdata(client); 199 + static const u8 request[68] = { 200 + 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'D', 0x00 201 + }; 202 + int error; 203 + 204 + mutex_lock(&data->query_lock); 205 + 206 + data->query_result = -ETIMEDOUT; 207 + reinit_completion(&data->wait_event); 208 + 209 + error = i2c_master_send(client, request, sizeof(request)); 210 + if (error < 0) { 211 + mutex_unlock(&data->query_lock); 212 + return error; 213 + } 214 + 215 + wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 216 + mutex_unlock(&data->query_lock); 217 + 218 + if (data->query_result < 0) 219 + return data->query_result; 220 + 221 + return sprintf(buf, "%s\n", data->fw_version); 222 + } 223 + static DEVICE_ATTR_RO(fw_version); 224 + 225 + static ssize_t exc3000_get_model(struct exc3000_data *data) 226 + { 227 + static const u8 request[68] = { 228 + 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00 229 + }; 230 + struct i2c_client *client = data->client; 231 + int error; 232 + 233 + mutex_lock(&data->query_lock); 234 + data->query_result = -ETIMEDOUT; 235 + reinit_completion(&data->wait_event); 236 + 237 + error = i2c_master_send(client, request, sizeof(request)); 238 + if (error < 0) { 239 + mutex_unlock(&data->query_lock); 240 + return error; 241 + } 242 + 243 + wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 244 + mutex_unlock(&data->query_lock); 245 + 246 + return data->query_result; 247 + } 248 + 249 + static ssize_t model_show(struct device *dev, 250 + struct device_attribute *attr, char *buf) 251 + { 252 + struct i2c_client *client = to_i2c_client(dev); 253 + struct exc3000_data *data = i2c_get_clientdata(client); 254 + int error; 255 + 256 + error = exc3000_get_model(data); 257 + if (error < 0) 258 + return error; 259 + 260 + return sprintf(buf, "%s\n", data->model); 261 + } 262 + static DEVICE_ATTR_RO(model); 263 + 264 + static struct attribute *sysfs_attrs[] = { 265 + &dev_attr_fw_version.attr, 266 + &dev_attr_model.attr, 267 + NULL 268 + }; 269 + 270 + static struct attribute_group exc3000_attribute_group = { 271 + .attrs = sysfs_attrs 272 + }; 273 + 230 274 static int exc3000_probe(struct i2c_client *client) 231 275 { 232 276 struct exc3000_data *data; 233 277 struct input_dev *input; 234 - int error, max_xy; 278 + int error, max_xy, retry; 235 279 236 280 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 237 281 if (!data) ··· 325 209 data->info = &exc3000_info[eeti_dev_id]; 326 210 } 327 211 timer_setup(&data->timer, exc3000_timer, 0); 212 + init_completion(&data->wait_event); 213 + mutex_init(&data->query_lock); 328 214 329 215 data->reset = devm_gpiod_get_optional(&client->dev, "reset", 330 216 GPIOD_OUT_HIGH); ··· 344 226 return -ENOMEM; 345 227 346 228 data->input = input; 229 + input_set_drvdata(input, data); 347 230 348 231 input->name = data->info->name; 349 232 input->id.bustype = BUS_I2C; ··· 367 248 error = devm_request_threaded_irq(&client->dev, client->irq, 368 249 NULL, exc3000_interrupt, IRQF_ONESHOT, 369 250 client->name, data); 251 + if (error) 252 + return error; 253 + 254 + /* 255 + * I²C does not have built-in recovery, so retry on failure. This 256 + * ensures, that the device probe will not fail for temporary issues 257 + * on the bus. This is not needed for the sysfs calls (userspace 258 + * will receive the error code and can start another query) and 259 + * cannot be done for touch events (but that only means loosing one 260 + * or two touch events anyways). 261 + */ 262 + for (retry = 0; retry < 3; retry++) { 263 + error = exc3000_get_model(data); 264 + if (!error) 265 + break; 266 + dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n", 267 + retry + 1, error); 268 + } 269 + 270 + if (error) 271 + return error; 272 + 273 + dev_dbg(&client->dev, "TS Model: %s", data->model); 274 + 275 + i2c_set_clientdata(client, data); 276 + 277 + error = devm_device_add_group(&client->dev, &exc3000_attribute_group); 370 278 if (error) 371 279 return error; 372 280