mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
Input: iqs5xx - switch to using cleanup functions
Start using __free() and guard() primitives to simplify the code and error handling. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
f1324109d1
commit
582f32aa89
|
|
@ -356,7 +356,7 @@ static int iqs5xx_bl_open(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static int iqs5xx_bl_write(struct i2c_client *client,
|
||||
u16 bl_addr, u8 *pmap_data, u16 pmap_len)
|
||||
u16 bl_addr, const u8 *pmap_data, u16 pmap_len)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret, i;
|
||||
|
|
@ -395,7 +395,7 @@ static int iqs5xx_bl_write(struct i2c_client *client,
|
|||
}
|
||||
|
||||
static int iqs5xx_bl_verify(struct i2c_client *client,
|
||||
u16 bl_addr, u8 *pmap_data, u16 pmap_len)
|
||||
u16 bl_addr, const u8 *pmap_data, u16 pmap_len)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret, i;
|
||||
|
|
@ -446,27 +446,21 @@ static int iqs5xx_set_state(struct i2c_client *client, u8 state)
|
|||
if (!iqs5xx->dev_id_info.bl_status)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&iqs5xx->lock);
|
||||
guard(mutex)(&iqs5xx->lock);
|
||||
|
||||
/*
|
||||
* Addressing the device outside of a communication window prompts it
|
||||
* to assert the RDY output, so disable the interrupt line to prevent
|
||||
* the handler from servicing a false interrupt.
|
||||
*/
|
||||
disable_irq(client->irq);
|
||||
guard(disable_irq)(&client->irq);
|
||||
|
||||
error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state);
|
||||
error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
|
||||
|
||||
usleep_range(50, 100);
|
||||
enable_irq(client->irq);
|
||||
|
||||
mutex_unlock(&iqs5xx->lock);
|
||||
|
||||
if (error1)
|
||||
return error1;
|
||||
|
||||
return error2;
|
||||
return error1 ?: error2;
|
||||
}
|
||||
|
||||
static int iqs5xx_open(struct input_dev *input)
|
||||
|
|
@ -703,7 +697,6 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
|
|||
static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
||||
const char *fw_file, u8 *pmap)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct iqs5xx_ihex_rec *rec;
|
||||
size_t pos = 0;
|
||||
int error, i;
|
||||
|
|
@ -722,6 +715,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
* Because the ihex2fw tool tolerates neither (1) nor (2), the slightly
|
||||
* nonstandard ihex firmware is parsed directly by the driver.
|
||||
*/
|
||||
const struct firmware *fw __free(firmware) = NULL;
|
||||
error = request_firmware(&fw, fw_file, &client->dev);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to request firmware %s: %d\n",
|
||||
|
|
@ -732,8 +726,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
do {
|
||||
if (pos + sizeof(*rec) > fw->size) {
|
||||
dev_err(&client->dev, "Insufficient firmware size\n");
|
||||
error = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
rec = (struct iqs5xx_ihex_rec *)(fw->data + pos);
|
||||
pos += sizeof(*rec);
|
||||
|
|
@ -741,15 +734,14 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
if (rec->start != ':') {
|
||||
dev_err(&client->dev, "Invalid start at record %u\n",
|
||||
rec_num);
|
||||
error = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr));
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Invalid header at record %u\n",
|
||||
rec_num);
|
||||
break;
|
||||
return error;
|
||||
}
|
||||
|
||||
rec_len = *rec_hdr;
|
||||
|
|
@ -758,8 +750,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
|
||||
if (pos + rec_len * 2 > fw->size) {
|
||||
dev_err(&client->dev, "Insufficient firmware size\n");
|
||||
error = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
pos += (rec_len * 2);
|
||||
|
||||
|
|
@ -767,7 +758,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
if (error) {
|
||||
dev_err(&client->dev, "Invalid data at record %u\n",
|
||||
rec_num);
|
||||
break;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = hex2bin(&rec_chksm,
|
||||
|
|
@ -775,7 +766,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
if (error) {
|
||||
dev_err(&client->dev, "Invalid checksum at record %u\n",
|
||||
rec_num);
|
||||
break;
|
||||
return error;
|
||||
}
|
||||
|
||||
chksm = 0;
|
||||
|
|
@ -800,23 +791,22 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
dev_err(&client->dev,
|
||||
"Invalid address at record %u\n",
|
||||
rec_num);
|
||||
error = -EINVAL;
|
||||
} else {
|
||||
memcpy(pmap + rec_addr - IQS5XX_CHKSM,
|
||||
rec_data, rec_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(pmap + rec_addr - IQS5XX_CHKSM,
|
||||
rec_data, rec_len);
|
||||
break;
|
||||
|
||||
case IQS5XX_REC_TYPE_EOF:
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&client->dev, "Invalid type at record %u\n",
|
||||
rec_num);
|
||||
error = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (error)
|
||||
break;
|
||||
|
||||
rec_num++;
|
||||
while (pos < fw->size) {
|
||||
if (*(fw->data + pos) == ':')
|
||||
|
|
@ -825,33 +815,13 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
|
|||
}
|
||||
} while (rec_type != IQS5XX_REC_TYPE_EOF);
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
||||
static int iqs5xx_update_firmware(struct iqs5xx_private *iqs5xx, const u8 *pmap)
|
||||
{
|
||||
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
|
||||
int error, error_init = 0;
|
||||
u8 *pmap;
|
||||
|
||||
pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
|
||||
if (!pmap)
|
||||
return -ENOMEM;
|
||||
|
||||
error = iqs5xx_fw_file_parse(client, fw_file, pmap);
|
||||
if (error)
|
||||
goto err_kfree;
|
||||
|
||||
mutex_lock(&iqs5xx->lock);
|
||||
|
||||
/*
|
||||
* Disable the interrupt line in case the first attempt(s) to enter the
|
||||
* bootloader don't happen quickly enough, in which case the device may
|
||||
* assert the RDY output until the next attempt.
|
||||
*/
|
||||
disable_irq(client->irq);
|
||||
struct i2c_client *client = iqs5xx->client;
|
||||
int error;
|
||||
|
||||
iqs5xx->dev_id_info.bl_status = 0;
|
||||
|
||||
|
|
@ -859,22 +829,50 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
|||
if (error) {
|
||||
error = iqs5xx_bl_open(client);
|
||||
if (error)
|
||||
goto err_reset;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN);
|
||||
if (error)
|
||||
goto err_reset;
|
||||
return error;
|
||||
|
||||
error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0);
|
||||
if (error)
|
||||
goto err_reset;
|
||||
return error;
|
||||
|
||||
error = iqs5xx_bl_verify(client, IQS5XX_CSTM,
|
||||
pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN,
|
||||
IQS5XX_CSTM_LEN);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
||||
{
|
||||
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
|
||||
int error, error_init = 0;
|
||||
|
||||
u8 *pmap __free(kfree) = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
|
||||
if (!pmap)
|
||||
return -ENOMEM;
|
||||
|
||||
error = iqs5xx_fw_file_parse(client, fw_file, pmap);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
guard(mutex)(&iqs5xx->lock);
|
||||
|
||||
/*
|
||||
* Disable the interrupt line in case the first attempt(s) to enter the
|
||||
* bootloader don't happen quickly enough, in which case the device may
|
||||
* assert the RDY output until the next attempt.
|
||||
*/
|
||||
guard(disable_irq)(&client->irq);
|
||||
|
||||
error = iqs5xx_update_firmware(iqs5xx, pmap);
|
||||
|
||||
err_reset:
|
||||
iqs5xx_reset(client);
|
||||
usleep_range(15000, 15100);
|
||||
|
||||
|
|
@ -882,14 +880,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
|
|||
if (!iqs5xx->dev_id_info.bl_status)
|
||||
error_init = error_init ? : -EINVAL;
|
||||
|
||||
enable_irq(client->irq);
|
||||
|
||||
mutex_unlock(&iqs5xx->lock);
|
||||
|
||||
err_kfree:
|
||||
kfree(pmap);
|
||||
|
||||
return error ? : error_init;
|
||||
return error ?: error_init;
|
||||
}
|
||||
|
||||
static ssize_t fw_file_store(struct device *dev,
|
||||
|
|
@ -985,38 +976,30 @@ static int iqs5xx_suspend(struct device *dev)
|
|||
{
|
||||
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
|
||||
struct input_dev *input = iqs5xx->input;
|
||||
int error = 0;
|
||||
|
||||
if (!input || device_may_wakeup(dev))
|
||||
return error;
|
||||
|
||||
mutex_lock(&input->mutex);
|
||||
return 0;
|
||||
|
||||
guard(mutex)(&input->mutex);
|
||||
if (input_device_enabled(input))
|
||||
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
|
||||
return iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
|
||||
|
||||
mutex_unlock(&input->mutex);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iqs5xx_resume(struct device *dev)
|
||||
{
|
||||
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
|
||||
struct input_dev *input = iqs5xx->input;
|
||||
int error = 0;
|
||||
|
||||
if (!input || device_may_wakeup(dev))
|
||||
return error;
|
||||
|
||||
mutex_lock(&input->mutex);
|
||||
return 0;
|
||||
|
||||
guard(mutex)(&input->mutex);
|
||||
if (input_device_enabled(input))
|
||||
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
|
||||
return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
|
||||
|
||||
mutex_unlock(&input->mutex);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user