Skip to content

Commit 70a7681

Browse files
Marek Vasutdtor
authored andcommitted
Input: ili210x - export ili251x version details via sysfs
The ili251x firmware protocol permits readout of firmware version, protocol version, mcu version and current mode (application, boot loader, forced update). These information are useful when updating the firmware on the il251x, e.g. to avoid updating the same firmware into the device multiple times. The locking is now necessary to avoid races between interrupt handler and the sysfs readouts. Note that the protocol differs considerably between the ili2xxx devices, this patch therefore implements this functionality only for ili251x that I can test. Signed-off-by: Marek Vasut <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 235300e commit 70a7681

File tree

1 file changed

+162
-3
lines changed

1 file changed

+162
-3
lines changed

drivers/input/touchscreen/ili210x.c

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
/* Touchscreen commands */
2323
#define REG_TOUCHDATA 0x10
2424
#define REG_PANEL_INFO 0x20
25+
#define REG_FIRMWARE_VERSION 0x40
26+
#define REG_PROTOCOL_VERSION 0x42
27+
#define REG_KERNEL_VERSION 0x61
28+
#define REG_GET_MODE 0xc0
29+
#define REG_GET_MODE_AP 0x5a
30+
#define REG_GET_MODE_BL 0x55
2531
#define REG_CALIBRATE 0xcc
2632

2733
struct ili2xxx_chip {
@@ -45,6 +51,10 @@ struct ili210x {
4551
struct gpio_desc *reset_gpio;
4652
struct touchscreen_properties prop;
4753
const struct ili2xxx_chip *chip;
54+
u8 version_firmware[8];
55+
u8 version_kernel[5];
56+
u8 version_proto[2];
57+
u8 ic_mode[2];
4858
bool stop;
4959
};
5060

@@ -353,6 +363,69 @@ static int ili251x_firmware_update_resolution(struct device *dev)
353363
return 0;
354364
}
355365

366+
static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
367+
{
368+
struct i2c_client *client = to_i2c_client(dev);
369+
struct ili210x *priv = i2c_get_clientdata(client);
370+
int error;
371+
u8 fw[8];
372+
373+
/* Get firmware version */
374+
error = priv->chip->read_reg(client, REG_FIRMWARE_VERSION,
375+
&fw, sizeof(fw));
376+
if (!error)
377+
memcpy(priv->version_firmware, fw, sizeof(fw));
378+
379+
return error;
380+
}
381+
382+
static ssize_t ili251x_firmware_update_kernel_version(struct device *dev)
383+
{
384+
struct i2c_client *client = to_i2c_client(dev);
385+
struct ili210x *priv = i2c_get_clientdata(client);
386+
int error;
387+
u8 kv[5];
388+
389+
/* Get kernel version */
390+
error = priv->chip->read_reg(client, REG_KERNEL_VERSION,
391+
&kv, sizeof(kv));
392+
if (!error)
393+
memcpy(priv->version_kernel, kv, sizeof(kv));
394+
395+
return error;
396+
}
397+
398+
static ssize_t ili251x_firmware_update_protocol_version(struct device *dev)
399+
{
400+
struct i2c_client *client = to_i2c_client(dev);
401+
struct ili210x *priv = i2c_get_clientdata(client);
402+
int error;
403+
u8 pv[2];
404+
405+
/* Get protocol version */
406+
error = priv->chip->read_reg(client, REG_PROTOCOL_VERSION,
407+
&pv, sizeof(pv));
408+
if (!error)
409+
memcpy(priv->version_proto, pv, sizeof(pv));
410+
411+
return error;
412+
}
413+
414+
static ssize_t ili251x_firmware_update_ic_mode(struct device *dev)
415+
{
416+
struct i2c_client *client = to_i2c_client(dev);
417+
struct ili210x *priv = i2c_get_clientdata(client);
418+
int error;
419+
u8 md[2];
420+
421+
/* Get chip boot mode */
422+
error = priv->chip->read_reg(client, REG_GET_MODE, &md, sizeof(md));
423+
if (!error)
424+
memcpy(priv->ic_mode, md, sizeof(md));
425+
426+
return error;
427+
}
428+
356429
static int ili251x_firmware_update_cached_state(struct device *dev)
357430
{
358431
struct i2c_client *client = to_i2c_client(dev);
@@ -370,9 +443,83 @@ static int ili251x_firmware_update_cached_state(struct device *dev)
370443
if (error)
371444
return error;
372445

446+
error = ili251x_firmware_update_firmware_version(dev);
447+
if (error)
448+
return error;
449+
450+
error = ili251x_firmware_update_kernel_version(dev);
451+
if (error)
452+
return error;
453+
454+
error = ili251x_firmware_update_protocol_version(dev);
455+
if (error)
456+
return error;
457+
458+
error = ili251x_firmware_update_ic_mode(dev);
459+
if (error)
460+
return error;
461+
373462
return 0;
374463
}
375464

465+
static ssize_t ili251x_firmware_version_show(struct device *dev,
466+
struct device_attribute *attr,
467+
char *buf)
468+
{
469+
struct i2c_client *client = to_i2c_client(dev);
470+
struct ili210x *priv = i2c_get_clientdata(client);
471+
u8 *fw = priv->version_firmware;
472+
473+
return sysfs_emit(buf, "%02x%02x.%02x%02x.%02x%02x.%02x%02x\n",
474+
fw[0], fw[1], fw[2], fw[3],
475+
fw[4], fw[5], fw[6], fw[7]);
476+
}
477+
static DEVICE_ATTR(firmware_version, 0444, ili251x_firmware_version_show, NULL);
478+
479+
static ssize_t ili251x_kernel_version_show(struct device *dev,
480+
struct device_attribute *attr,
481+
char *buf)
482+
{
483+
struct i2c_client *client = to_i2c_client(dev);
484+
struct ili210x *priv = i2c_get_clientdata(client);
485+
u8 *kv = priv->version_kernel;
486+
487+
return sysfs_emit(buf, "%02x.%02x.%02x.%02x.%02x\n",
488+
kv[0], kv[1], kv[2], kv[3], kv[4]);
489+
}
490+
static DEVICE_ATTR(kernel_version, 0444, ili251x_kernel_version_show, NULL);
491+
492+
static ssize_t ili251x_protocol_version_show(struct device *dev,
493+
struct device_attribute *attr,
494+
char *buf)
495+
{
496+
struct i2c_client *client = to_i2c_client(dev);
497+
struct ili210x *priv = i2c_get_clientdata(client);
498+
u8 *pv = priv->version_proto;
499+
500+
return sysfs_emit(buf, "%02x.%02x\n", pv[0], pv[1]);
501+
}
502+
static DEVICE_ATTR(protocol_version, 0444, ili251x_protocol_version_show, NULL);
503+
504+
static ssize_t ili251x_mode_show(struct device *dev,
505+
struct device_attribute *attr, char *buf)
506+
{
507+
struct i2c_client *client = to_i2c_client(dev);
508+
struct ili210x *priv = i2c_get_clientdata(client);
509+
u8 *md = priv->ic_mode;
510+
char *mode = "AP";
511+
512+
if (md[0] == REG_GET_MODE_AP) /* Application Mode */
513+
mode = "AP";
514+
else if (md[0] == REG_GET_MODE_BL) /* BootLoader Mode */
515+
mode = "BL";
516+
else /* Unknown Mode */
517+
mode = "??";
518+
519+
return sysfs_emit(buf, "%02x.%02x:%s\n", md[0], md[1], mode);
520+
}
521+
static DEVICE_ATTR(mode, 0444, ili251x_mode_show, NULL);
522+
376523
static ssize_t ili210x_calibrate(struct device *dev,
377524
struct device_attribute *attr,
378525
const char *buf, size_t count)
@@ -401,22 +548,34 @@ static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
401548

402549
static struct attribute *ili210x_attributes[] = {
403550
&dev_attr_calibrate.attr,
551+
&dev_attr_firmware_version.attr,
552+
&dev_attr_kernel_version.attr,
553+
&dev_attr_protocol_version.attr,
554+
&dev_attr_mode.attr,
404555
NULL,
405556
};
406557

407-
static umode_t ili210x_calibrate_visible(struct kobject *kobj,
558+
static umode_t ili210x_attributes_visible(struct kobject *kobj,
408559
struct attribute *attr, int index)
409560
{
410561
struct device *dev = kobj_to_dev(kobj);
411562
struct i2c_client *client = to_i2c_client(dev);
412563
struct ili210x *priv = i2c_get_clientdata(client);
413564

414-
return priv->chip->has_calibrate_reg ? attr->mode : 0;
565+
/* Calibrate is present on all ILI2xxx which have calibrate register */
566+
if (attr == &dev_attr_calibrate.attr)
567+
return priv->chip->has_calibrate_reg ? attr->mode : 0;
568+
569+
/* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
570+
if (!priv->chip->has_firmware_proto)
571+
return 0;
572+
573+
return attr->mode;
415574
}
416575

417576
static const struct attribute_group ili210x_attr_group = {
418577
.attrs = ili210x_attributes,
419-
.is_visible = ili210x_calibrate_visible,
578+
.is_visible = ili210x_attributes_visible,
420579
};
421580

422581
static void ili210x_power_down(void *data)

0 commit comments

Comments
 (0)