diff options
Diffstat (limited to 'drivers/input/mouse/elan_i2c_core.c')
-rw-r--r-- | drivers/input/mouse/elan_i2c_core.c | 235 |
1 files changed, 121 insertions, 114 deletions
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 8a72c200ccb5..fee1796da3d0 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/string_choices.h> #include <linux/input.h> #include <linux/uaccess.h> #include <linux/jiffies.h> @@ -36,7 +37,7 @@ #include <linux/pm_wakeirq.h> #include <linux/property.h> #include <linux/regulator/consumer.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "elan_i2c.h" @@ -199,7 +200,7 @@ static int elan_set_power(struct elan_tp_data *data, bool on) } while (--repeat > 0); dev_err(&data->client->dev, "failed to set power %s: %d\n", - on ? "on" : "off", error); + str_on_off(on), error); return error; } @@ -541,7 +542,8 @@ static int elan_update_firmware(struct elan_tp_data *data, dev_dbg(&client->dev, "Starting firmware update....\n"); - disable_irq(client->irq); + guard(disable_irq)(&client->irq); + data->in_fw_update = true; retval = __elan_update_firmware(data, fw); @@ -555,7 +557,6 @@ static int elan_update_firmware(struct elan_tp_data *data, } data->in_fw_update = false; - enable_irq(client->irq); return retval; } @@ -621,8 +622,6 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, const char *buf, size_t count) { struct elan_tp_data *data = dev_get_drvdata(dev); - const struct firmware *fw; - char *fw_name; int error; const u8 *fw_signature; static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF}; @@ -631,15 +630,16 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, return -EINVAL; /* Look for a firmware with the product id appended. */ - fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id); + const char *fw_name __free(kfree) = + kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id); if (!fw_name) { dev_err(dev, "failed to allocate memory for firmware name\n"); return -ENOMEM; } dev_info(dev, "requesting fw '%s'\n", fw_name); + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_name, dev); - kfree(fw_name); if (error) { dev_err(dev, "failed to request firmware: %d\n", error); return error; @@ -651,46 +651,36 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", (int)sizeof(signature), signature, (int)sizeof(signature), fw_signature); - error = -EBADF; - goto out_release_fw; + return -EBADF; } - error = mutex_lock_interruptible(&data->sysfs_mutex); - if (error) - goto out_release_fw; - - error = elan_update_firmware(data, fw); - - mutex_unlock(&data->sysfs_mutex); + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_update_firmware(data, fw); + if (error) + return error; + } -out_release_fw: - release_firmware(fw); - return error ?: count; + return count; } -static ssize_t calibrate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int elan_calibrate(struct elan_tp_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct elan_tp_data *data = i2c_get_clientdata(client); + struct i2c_client *client = data->client; + struct device *dev = &client->dev; int tries = 20; int retval; int error; u8 val[ETP_CALIBRATE_MAX_LEN]; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; - - disable_irq(client->irq); + guard(disable_irq)(&client->irq); data->mode |= ETP_ENABLE_CALIBRATE; retval = data->ops->set_mode(client, data->mode); if (retval) { + data->mode &= ~ETP_ENABLE_CALIBRATE; dev_err(dev, "failed to enable calibration mode: %d\n", retval); - goto out; + return retval; } retval = data->ops->calibrate(client); @@ -728,10 +718,24 @@ out_disable_calibrate: if (!retval) retval = error; } -out: - enable_irq(client->irq); - mutex_unlock(&data->sysfs_mutex); - return retval ?: count; + return retval; +} + +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_calibrate(data); + if (error) + return error; + } + + return count; } static ssize_t elan_sysfs_read_mode(struct device *dev, @@ -743,16 +747,11 @@ static ssize_t elan_sysfs_read_mode(struct device *dev, int error; enum tp_mode mode; - error = mutex_lock_interruptible(&data->sysfs_mutex); - if (error) - return error; - - error = data->ops->iap_get_mode(data->client, &mode); - - mutex_unlock(&data->sysfs_mutex); - - if (error) - return error; + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = data->ops->iap_get_mode(data->client, &mode); + if (error) + return error; + } return sysfs_emit(buf, "%d\n", (int)mode); } @@ -783,44 +782,40 @@ static const struct attribute_group elan_sysfs_group = { .attrs = elan_sysfs_entries, }; -static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static int elan_acquire_baseline(struct elan_tp_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct elan_tp_data *data = i2c_get_clientdata(client); - int error; + struct i2c_client *client = data->client; + struct device *dev = &client->dev; int retval; + int error; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; - - disable_irq(client->irq); + guard(disable_irq)(&client->irq); data->baseline_ready = false; data->mode |= ETP_ENABLE_CALIBRATE; - retval = data->ops->set_mode(data->client, data->mode); + retval = data->ops->set_mode(client, data->mode); if (retval) { + data->mode &= ~ETP_ENABLE_CALIBRATE; dev_err(dev, "Failed to enable calibration mode to get baseline: %d\n", retval); - goto out; + return retval; } msleep(250); - retval = data->ops->get_baseline_data(data->client, true, + retval = data->ops->get_baseline_data(client, true, &data->max_baseline); if (retval) { - dev_err(dev, "Failed to read max baseline form device: %d\n", + dev_err(dev, "Failed to read max baseline from device: %d\n", retval); goto out_disable_calibrate; } - retval = data->ops->get_baseline_data(data->client, false, + retval = data->ops->get_baseline_data(client, false, &data->min_baseline); if (retval) { - dev_err(dev, "Failed to read min baseline form device: %d\n", + dev_err(dev, "Failed to read min baseline from device: %d\n", retval); goto out_disable_calibrate; } @@ -829,17 +824,31 @@ static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, out_disable_calibrate: data->mode &= ~ETP_ENABLE_CALIBRATE; - error = data->ops->set_mode(data->client, data->mode); + error = data->ops->set_mode(client, data->mode); if (error) { dev_err(dev, "Failed to disable calibration mode after acquiring baseline: %d\n", error); if (!retval) retval = error; } -out: - enable_irq(client->irq); - mutex_unlock(&data->sysfs_mutex); - return retval ?: count; + + return retval; +} + +static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_acquire_baseline(data); + if (error) + return error; + } + + return count; } static ssize_t min_show(struct device *dev, @@ -847,22 +856,15 @@ static ssize_t min_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int retval; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &data->sysfs_mutex) { + if (!data->baseline_ready) + return -ENODATA; - if (!data->baseline_ready) { - retval = -ENODATA; - goto out; + return sysfs_emit(buf, "%d", data->min_baseline); } - retval = sysfs_emit(buf, "%d", data->min_baseline); - -out: - mutex_unlock(&data->sysfs_mutex); - return retval; + return -EINTR; } static ssize_t max_show(struct device *dev, @@ -870,25 +872,17 @@ static ssize_t max_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int retval; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &data->sysfs_mutex) { + if (!data->baseline_ready) + return -ENODATA; - if (!data->baseline_ready) { - retval = -ENODATA; - goto out; + return sysfs_emit(buf, "%d", data->max_baseline); } - retval = sysfs_emit(buf, "%d", data->max_baseline); - -out: - mutex_unlock(&data->sysfs_mutex); - return retval; + return -EINTR; } - static DEVICE_ATTR_WO(acquire); static DEVICE_ATTR_RO(min); static DEVICE_ATTR_RO(max); @@ -1323,41 +1317,54 @@ static int elan_probe(struct i2c_client *client) return 0; } +static int __elan_suspend(struct elan_tp_data *data) +{ + struct i2c_client *client = data->client; + int error; + + if (device_may_wakeup(&client->dev)) + return elan_sleep(data); + + /* Touchpad is not a wakeup source */ + error = elan_set_power(data, false); + if (error) + return error; + + error = regulator_disable(data->vcc); + if (error) { + dev_err(&client->dev, + "failed to disable regulator when suspending: %d\n", + error); + /* Attempt to power the chip back up */ + elan_set_power(data, true); + return error; + } + + return 0; +} + static int elan_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int ret; + int error; /* * We are taking the mutex to make sure sysfs operations are * complete before we attempt to bring the device into low[er] * power mode. */ - ret = mutex_lock_interruptible(&data->sysfs_mutex); - if (ret) - return ret; - - disable_irq(client->irq); + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + disable_irq(client->irq); - if (device_may_wakeup(dev)) { - ret = elan_sleep(data); - } else { - ret = elan_set_power(data, false); - if (ret) - goto err; - - ret = regulator_disable(data->vcc); - if (ret) { - dev_err(dev, "error %d disabling regulator\n", ret); - /* Attempt to power the chip back up */ - elan_set_power(data, true); + error = __elan_suspend(data); + if (error) { + enable_irq(client->irq); + return error; } } -err: - mutex_unlock(&data->sysfs_mutex); - return ret; + return 0; } static int elan_resume(struct device *dev) @@ -1392,8 +1399,8 @@ err: static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume); static const struct i2c_device_id elan_id[] = { - { DRIVER_NAME, 0 }, - { }, + { DRIVER_NAME }, + { } }; MODULE_DEVICE_TABLE(i2c, elan_id); |