mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-04 16:15:11 +00:00
Input: iqs5xx - expose firmware revision to user space
Add the read-only 'fw_info' attribute which reports information about the device's firmware in the following format: a.b.c.d:e.f Where: a = Product number (e.g. 40 for IQS550) b = Project number (e.g. 15) c = Firmware revision (major) d = Firmware revision (minor) e = Customer-assigned exported file version (major) f = Customer-assigned exported file version (minor) As part of the corresponding rework to uses of 'bl_status', the IQS5XX_BL_STATUS_RESET definition is dropped with 0 used in its place instead. Signed-off-by: Jeff LaBundy <jeff@labundy.com> Link: https://lore.kernel.org/r/20210313191236.4366-4-jeff@labundy.com Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
40c3efdc0b
commit
509c008313
1 changed files with 40 additions and 16 deletions
|
@ -63,6 +63,7 @@
|
|||
#define IQS5XX_SYS_CFG1 0x058F
|
||||
#define IQS5XX_X_RES 0x066E
|
||||
#define IQS5XX_Y_RES 0x0670
|
||||
#define IQS5XX_EXP_FILE 0x0677
|
||||
#define IQS5XX_CHKSM 0x83C0
|
||||
#define IQS5XX_APP 0x8400
|
||||
#define IQS5XX_CSTM 0xBE00
|
||||
|
@ -86,22 +87,12 @@
|
|||
#define IQS5XX_BL_CMD_CRC 0x03
|
||||
#define IQS5XX_BL_BLK_LEN_MAX 64
|
||||
#define IQS5XX_BL_ID 0x0200
|
||||
#define IQS5XX_BL_STATUS_RESET 0x00
|
||||
#define IQS5XX_BL_STATUS_AVAIL 0xA5
|
||||
#define IQS5XX_BL_STATUS_NONE 0xEE
|
||||
#define IQS5XX_BL_CRC_PASS 0x00
|
||||
#define IQS5XX_BL_CRC_FAIL 0x01
|
||||
#define IQS5XX_BL_ATTEMPTS 3
|
||||
|
||||
struct iqs5xx_private {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct touchscreen_properties prop;
|
||||
struct mutex lock;
|
||||
u8 bl_status;
|
||||
};
|
||||
|
||||
struct iqs5xx_dev_id_info {
|
||||
__be16 prod_num;
|
||||
__be16 proj_num;
|
||||
|
@ -133,6 +124,16 @@ struct iqs5xx_status {
|
|||
struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
|
||||
} __packed;
|
||||
|
||||
struct iqs5xx_private {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct touchscreen_properties prop;
|
||||
struct mutex lock;
|
||||
struct iqs5xx_dev_id_info dev_id_info;
|
||||
u8 exp_file[2];
|
||||
};
|
||||
|
||||
static int iqs5xx_read_burst(struct i2c_client *client,
|
||||
u16 reg, void *val, u16 len)
|
||||
{
|
||||
|
@ -445,7 +446,7 @@ static int iqs5xx_set_state(struct i2c_client *client, u8 state)
|
|||
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
|
||||
int error1, error2;
|
||||
|
||||
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
|
||||
if (!iqs5xx->dev_id_info.bl_status)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&iqs5xx->lock);
|
||||
|
@ -615,6 +616,11 @@ static int iqs5xx_dev_init(struct i2c_client *client)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = iqs5xx_read_burst(client, IQS5XX_EXP_FILE,
|
||||
iqs5xx->exp_file, sizeof(iqs5xx->exp_file));
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = iqs5xx_axis_init(client);
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -638,7 +644,7 @@ static int iqs5xx_dev_init(struct i2c_client *client)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
iqs5xx->bl_status = dev_id_info->bl_status;
|
||||
iqs5xx->dev_id_info = *dev_id_info;
|
||||
|
||||
/*
|
||||
* The following delay allows ATI to complete before the open and close
|
||||
|
@ -664,7 +670,7 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
|
|||
* RDY output during bootloader mode. If the device operates outside of
|
||||
* bootloader mode, the input device is guaranteed to be allocated.
|
||||
*/
|
||||
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
|
||||
if (!iqs5xx->dev_id_info.bl_status)
|
||||
return IRQ_NONE;
|
||||
|
||||
error = iqs5xx_read_burst(client, IQS5XX_SYS_INFO0,
|
||||
|
@ -853,7 +859,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
|||
int error, error_bl = 0;
|
||||
u8 *pmap;
|
||||
|
||||
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
|
||||
if (iqs5xx->dev_id_info.bl_status == IQS5XX_BL_STATUS_NONE)
|
||||
return -EPERM;
|
||||
|
||||
pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
|
||||
|
@ -873,7 +879,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
|||
*/
|
||||
disable_irq(client->irq);
|
||||
|
||||
iqs5xx->bl_status = IQS5XX_BL_STATUS_RESET;
|
||||
iqs5xx->dev_id_info.bl_status = 0;
|
||||
|
||||
error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
|
||||
if (error) {
|
||||
|
@ -906,7 +912,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
|||
|
||||
error_bl = error;
|
||||
error = iqs5xx_dev_init(client);
|
||||
if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
|
||||
if (!error && !iqs5xx->dev_id_info.bl_status)
|
||||
error = -EINVAL;
|
||||
|
||||
enable_irq(client->irq);
|
||||
|
@ -966,10 +972,28 @@ static ssize_t fw_file_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t fw_info_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
|
||||
|
||||
if (!iqs5xx->dev_id_info.bl_status)
|
||||
return -ENODATA;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
|
||||
be16_to_cpu(iqs5xx->dev_id_info.prod_num),
|
||||
be16_to_cpu(iqs5xx->dev_id_info.proj_num),
|
||||
iqs5xx->dev_id_info.major_ver,
|
||||
iqs5xx->dev_id_info.minor_ver,
|
||||
iqs5xx->exp_file[0], iqs5xx->exp_file[1]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WO(fw_file);
|
||||
static DEVICE_ATTR_RO(fw_info);
|
||||
|
||||
static struct attribute *iqs5xx_attrs[] = {
|
||||
&dev_attr_fw_file.attr,
|
||||
&dev_attr_fw_info.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue