Commit b1cfa7b4 authored by Dudley Du's avatar Dudley Du Committed by Dmitry Torokhov

Input: cyapa - switch to using managed resources

Use of managed resources simplifies error handling and device removal code.
Signed-off-by: default avatarDudley Du <dudl@cypress.com>
[Dmitry: added open/close methods so cyapa_remove is no longer needed.]
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent bd447b61
...@@ -577,10 +577,13 @@ static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode) ...@@ -577,10 +577,13 @@ static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
power = ret & ~PWR_MODE_MASK; power = ret & ~PWR_MODE_MASK;
power |= power_mode & PWR_MODE_MASK; power |= power_mode & PWR_MODE_MASK;
ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
if (ret < 0) if (ret < 0) {
dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
power_mode, ret); power_mode, ret);
return ret; return ret;
}
return 0;
} }
static int cyapa_get_query_data(struct cyapa *cyapa) static int cyapa_get_query_data(struct cyapa *cyapa)
...@@ -753,16 +756,40 @@ static u8 cyapa_check_adapter_functionality(struct i2c_client *client) ...@@ -753,16 +756,40 @@ static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
return ret; return ret;
} }
static int cyapa_open(struct input_dev *input)
{
struct cyapa *cyapa = input_get_drvdata(input);
struct i2c_client *client = cyapa->client;
int error;
error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
if (error) {
dev_err(&client->dev, "set active power failed: %d\n", error);
return error;
}
enable_irq(client->irq);
return 0;
}
static void cyapa_close(struct input_dev *input)
{
struct cyapa *cyapa = input_get_drvdata(input);
disable_irq(cyapa->client->irq);
cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
}
static int cyapa_create_input_dev(struct cyapa *cyapa) static int cyapa_create_input_dev(struct cyapa *cyapa)
{ {
struct device *dev = &cyapa->client->dev; struct device *dev = &cyapa->client->dev;
int ret;
struct input_dev *input; struct input_dev *input;
int error;
if (!cyapa->physical_size_x || !cyapa->physical_size_y) if (!cyapa->physical_size_x || !cyapa->physical_size_y)
return -EINVAL; return -EINVAL;
input = cyapa->input = input_allocate_device(); input = devm_input_allocate_device(dev);
if (!input) { if (!input) {
dev_err(dev, "allocate memory for input device failed\n"); dev_err(dev, "allocate memory for input device failed\n");
return -ENOMEM; return -ENOMEM;
...@@ -775,6 +802,9 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) ...@@ -775,6 +802,9 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
input->id.product = 0; /* means any product in eventcomm. */ input->id.product = 0; /* means any product in eventcomm. */
input->dev.parent = &cyapa->client->dev; input->dev.parent = &cyapa->client->dev;
input->open = cyapa_open;
input->close = cyapa_close;
input_set_drvdata(input, cyapa); input_set_drvdata(input, cyapa);
__set_bit(EV_ABS, input->evbit); __set_bit(EV_ABS, input->evbit);
...@@ -802,34 +832,24 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) ...@@ -802,34 +832,24 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit); __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
/* handle pointer emulation and unused slots in core */ /* handle pointer emulation and unused slots in core */
ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
if (ret) { if (error) {
dev_err(dev, "allocate memory for MT slots failed, %d\n", ret); dev_err(dev, "failed to initialize MT slots: %d\n", error);
goto err_free_device; return error;
} }
/* Register the device in input subsystem */ cyapa->input = input;
ret = input_register_device(input);
if (ret) {
dev_err(dev, "input device register failed, %d\n", ret);
goto err_free_device;
}
return 0; return 0;
err_free_device:
input_free_device(input);
cyapa->input = NULL;
return ret;
} }
static int cyapa_probe(struct i2c_client *client, static int cyapa_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id) const struct i2c_device_id *dev_id)
{ {
int ret;
u8 adapter_func;
struct cyapa *cyapa;
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct cyapa *cyapa;
u8 adapter_func;
int error;
adapter_func = cyapa_check_adapter_functionality(client); adapter_func = cyapa_check_adapter_functionality(client);
if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) { if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
...@@ -837,11 +857,9 @@ static int cyapa_probe(struct i2c_client *client, ...@@ -837,11 +857,9 @@ static int cyapa_probe(struct i2c_client *client,
return -EIO; return -EIO;
} }
cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL); cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL);
if (!cyapa) { if (!cyapa)
dev_err(dev, "allocate memory for cyapa failed\n");
return -ENOMEM; return -ENOMEM;
}
cyapa->gen = CYAPA_GEN3; cyapa->gen = CYAPA_GEN3;
cyapa->client = client; cyapa->client = client;
...@@ -852,66 +870,61 @@ static int cyapa_probe(struct i2c_client *client, ...@@ -852,66 +870,61 @@ static int cyapa_probe(struct i2c_client *client,
/* i2c isn't supported, use smbus */ /* i2c isn't supported, use smbus */
if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
cyapa->smbus = true; cyapa->smbus = true;
cyapa->state = CYAPA_STATE_NO_DEVICE; cyapa->state = CYAPA_STATE_NO_DEVICE;
ret = cyapa_check_is_operational(cyapa);
if (ret) {
dev_err(dev, "device not operational, %d\n", ret);
goto err_mem_free;
}
ret = cyapa_create_input_dev(cyapa); error = cyapa_check_is_operational(cyapa);
if (ret) { if (error) {
dev_err(dev, "create input_dev instance failed, %d\n", ret); dev_err(dev, "device not operational, %d\n", error);
goto err_mem_free; return error;
} }
ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); /* Power down the device until we need it */
if (ret) { error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
dev_err(dev, "set active power failed, %d\n", ret); if (error) {
goto err_unregister_device; dev_err(dev, "failed to quiesce the device: %d\n", error);
return error;
} }
cyapa->irq = client->irq; error = cyapa_create_input_dev(cyapa);
ret = request_threaded_irq(cyapa->irq, if (error)
NULL, return error;
cyapa_irq,
error = devm_request_threaded_irq(dev, client->irq,
NULL, cyapa_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"cyapa", "cyapa", cyapa);
cyapa); if (error) {
if (ret) { dev_err(dev, "IRQ request failed: %d\n, ", error);
dev_err(dev, "IRQ request failed: %d\n, ", ret); return error;
goto err_unregister_device;
} }
return 0; /* Disable IRQ until the device is opened */
disable_irq(client->irq);
err_unregister_device:
input_unregister_device(cyapa->input);
err_mem_free:
kfree(cyapa);
return ret;
}
static int cyapa_remove(struct i2c_client *client) /* Register the device in input subsystem */
{ error = input_register_device(cyapa->input);
struct cyapa *cyapa = i2c_get_clientdata(client); if (error) {
dev_err(dev, "failed to register input device: %d\n", error);
free_irq(cyapa->irq, cyapa); return error;
input_unregister_device(cyapa->input); }
cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
kfree(cyapa);
return 0; return 0;
} }
static int __maybe_unused cyapa_suspend(struct device *dev) static int __maybe_unused cyapa_suspend(struct device *dev)
{ {
int ret; struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = i2c_get_clientdata(client);
struct input_dev *input = cyapa->input;
u8 power_mode; u8 power_mode;
struct cyapa *cyapa = dev_get_drvdata(dev); int error;
disable_irq(cyapa->irq); error = mutex_lock_interruptible(&input->mutex);
if (error)
return error;
disable_irq(client->irq);
/* /*
* Set trackpad device to idle mode if wakeup is allowed, * Set trackpad device to idle mode if wakeup is allowed,
...@@ -919,28 +932,42 @@ static int __maybe_unused cyapa_suspend(struct device *dev) ...@@ -919,28 +932,42 @@ static int __maybe_unused cyapa_suspend(struct device *dev)
*/ */
power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
: PWR_MODE_OFF; : PWR_MODE_OFF;
ret = cyapa_set_power_mode(cyapa, power_mode); error = cyapa_set_power_mode(cyapa, power_mode);
if (ret < 0) if (error)
dev_err(dev, "set power mode failed, %d\n", ret); dev_err(dev, "resume: set power mode to %d failed: %d\n",
power_mode, error);
if (device_may_wakeup(dev)) if (device_may_wakeup(dev))
cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0); cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0);
mutex_unlock(&input->mutex);
return 0; return 0;
} }
static int __maybe_unused cyapa_resume(struct device *dev) static int __maybe_unused cyapa_resume(struct device *dev)
{ {
int ret; struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = dev_get_drvdata(dev); struct cyapa *cyapa = i2c_get_clientdata(client);
struct input_dev *input = cyapa->input;
u8 power_mode;
int error;
mutex_lock(&input->mutex);
if (device_may_wakeup(dev) && cyapa->irq_wake) if (device_may_wakeup(dev) && cyapa->irq_wake)
disable_irq_wake(cyapa->irq); disable_irq_wake(cyapa->irq);
ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF;
if (ret) error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
dev_warn(dev, "resume active power failed, %d\n", ret); if (error)
dev_warn(dev, "resume: set power mode to %d failed: %d\n",
power_mode, error);
enable_irq(cyapa->irq); enable_irq(cyapa->irq);
mutex_unlock(&input->mutex);
return 0; return 0;
} }
...@@ -960,7 +987,6 @@ static struct i2c_driver cyapa_driver = { ...@@ -960,7 +987,6 @@ static struct i2c_driver cyapa_driver = {
}, },
.probe = cyapa_probe, .probe = cyapa_probe,
.remove = cyapa_remove,
.id_table = cyapa_id_table, .id_table = cyapa_id_table,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment