Commit 45608827 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: adp5588-keys - switch to using managed resources

This simplifies error handling in probe() and reduces amount of explicit
code in remove().
Acked-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Link: https://lore.kernel.org/r/20220528045631.289821-3-dmitry.torokhov@gmail.comSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 2d115985
...@@ -50,7 +50,6 @@ struct adp5588_kpad { ...@@ -50,7 +50,6 @@ struct adp5588_kpad {
unsigned short gpimapsize; unsigned short gpimapsize;
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
unsigned char gpiomap[ADP5588_MAXGPIO]; unsigned char gpiomap[ADP5588_MAXGPIO];
bool export_gpio;
struct gpio_chip gc; struct gpio_chip gc;
struct mutex gpio_lock; /* Protect cached dir, dat_out */ struct mutex gpio_lock; /* Protect cached dir, dat_out */
u8 dat_out[3]; u8 dat_out[3];
...@@ -182,6 +181,21 @@ static int adp5588_build_gpiomap(struct adp5588_kpad *kpad, ...@@ -182,6 +181,21 @@ static int adp5588_build_gpiomap(struct adp5588_kpad *kpad,
return n_unused; return n_unused;
} }
static void adp5588_gpio_do_teardown(void *_kpad)
{
struct adp5588_kpad *kpad = _kpad;
struct device *dev = &kpad->client->dev;
const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
int error;
error = gpio_data->teardown(kpad->client,
kpad->gc.base, kpad->gc.ngpio,
gpio_data->context);
if (error)
dev_warn(&kpad->client->dev, "teardown failed %d\n", error);
}
static int adp5588_gpio_add(struct adp5588_kpad *kpad) static int adp5588_gpio_add(struct adp5588_kpad *kpad)
{ {
struct device *dev = &kpad->client->dev; struct device *dev = &kpad->client->dev;
...@@ -198,8 +212,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -198,8 +212,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
return 0; return 0;
} }
kpad->export_gpio = true;
kpad->gc.direction_input = adp5588_gpio_direction_input; kpad->gc.direction_input = adp5588_gpio_direction_input;
kpad->gc.direction_output = adp5588_gpio_direction_output; kpad->gc.direction_output = adp5588_gpio_direction_output;
kpad->gc.get = adp5588_gpio_get_value; kpad->gc.get = adp5588_gpio_get_value;
...@@ -213,9 +225,9 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -213,9 +225,9 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
mutex_init(&kpad->gpio_lock); mutex_init(&kpad->gpio_lock);
error = gpiochip_add_data(&kpad->gc, kpad); error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
if (error) { if (error) {
dev_err(dev, "gpiochip_add failed, err: %d\n", error); dev_err(dev, "gpiochip_add failed: %d\n", error);
return error; return error;
} }
...@@ -230,41 +242,24 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -230,41 +242,24 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.base, kpad->gc.ngpio, kpad->gc.base, kpad->gc.ngpio,
gpio_data->context); gpio_data->context);
if (error) if (error)
dev_warn(dev, "setup failed, %d\n", error); dev_warn(dev, "setup failed: %d\n", error);
} }
return 0;
}
static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
{
struct device *dev = &kpad->client->dev;
const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
int error;
if (!kpad->export_gpio)
return;
if (gpio_data->teardown) { if (gpio_data->teardown) {
error = gpio_data->teardown(kpad->client, error = devm_add_action(dev, adp5588_gpio_do_teardown, kpad);
kpad->gc.base, kpad->gc.ngpio,
gpio_data->context);
if (error) if (error)
dev_warn(dev, "teardown failed %d\n", error); dev_warn(dev, "failed to schedule teardown: %d\n",
error);
} }
gpiochip_remove(&kpad->gc); return 0;
} }
#else #else
static inline int adp5588_gpio_add(struct adp5588_kpad *kpad) static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
{ {
return 0; return 0;
} }
static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
{
}
#endif #endif
static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
...@@ -510,21 +505,20 @@ static int adp5588_probe(struct i2c_client *client, ...@@ -510,21 +505,20 @@ static int adp5588_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
} }
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL);
input = input_allocate_device(); if (!kpad)
if (!kpad || !input) { return -ENOMEM;
error = -ENOMEM;
goto err_free_mem; input = devm_input_allocate_device(&client->dev);
} if (!input)
return -ENOMEM;
kpad->client = client; kpad->client = client;
kpad->input = input; kpad->input = input;
ret = adp5588_read(client, DEV_ID); ret = adp5588_read(client, DEV_ID);
if (ret < 0) { if (ret < 0)
error = ret; return ret;
goto err_free_mem;
}
revid = (u8) ret & ADP5588_DEVICE_ID_MASK; revid = (u8) ret & ADP5588_DEVICE_ID_MASK;
if (WA_DELAYED_READOUT_REVID(revid)) if (WA_DELAYED_READOUT_REVID(revid))
...@@ -532,7 +526,6 @@ static int adp5588_probe(struct i2c_client *client, ...@@ -532,7 +526,6 @@ static int adp5588_probe(struct i2c_client *client,
input->name = client->name; input->name = client->name;
input->phys = "adp5588-keys/input0"; input->phys = "adp5588-keys/input0";
input->dev.parent = &client->dev;
input_set_drvdata(input, kpad); input_set_drvdata(input, kpad);
...@@ -569,58 +562,43 @@ static int adp5588_probe(struct i2c_client *client, ...@@ -569,58 +562,43 @@ static int adp5588_probe(struct i2c_client *client,
error = input_register_device(input); error = input_register_device(input);
if (error) { if (error) {
dev_err(&client->dev, "unable to register input device\n"); dev_err(&client->dev, "unable to register input device: %d\n",
goto err_free_mem; error);
return error;
} }
error = request_threaded_irq(client->irq, error = devm_request_threaded_irq(&client->dev, client->irq,
adp5588_hard_irq, adp5588_thread_irq, adp5588_hard_irq, adp5588_thread_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->dev.driver->name, kpad); client->dev.driver->name, kpad);
if (error) { if (error) {
dev_err(&client->dev, "irq %d busy?\n", client->irq); dev_err(&client->dev, "failed to request irq %d: %d\n",
goto err_unreg_dev; client->irq, error);
return error;
} }
error = adp5588_setup(client); error = adp5588_setup(client);
if (error) if (error)
goto err_free_irq; return error;
if (kpad->gpimapsize) if (kpad->gpimapsize)
adp5588_report_switch_state(kpad); adp5588_report_switch_state(kpad);
error = adp5588_gpio_add(kpad); error = adp5588_gpio_add(kpad);
if (error) if (error)
goto err_free_irq; return error;
device_init_wakeup(&client->dev, 1); device_init_wakeup(&client->dev, 1);
i2c_set_clientdata(client, kpad);
dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
return 0; return 0;
err_free_irq:
free_irq(client->irq, kpad);
err_unreg_dev:
input_unregister_device(input);
input = NULL;
err_free_mem:
input_free_device(input);
kfree(kpad);
return error;
} }
static int adp5588_remove(struct i2c_client *client) static int adp5588_remove(struct i2c_client *client)
{ {
struct adp5588_kpad *kpad = i2c_get_clientdata(client);
adp5588_write(client, CFG, 0); adp5588_write(client, CFG, 0);
free_irq(client->irq, kpad);
input_unregister_device(kpad->input);
adp5588_gpio_remove(kpad);
kfree(kpad);
/* all resources will be freed by devm */
return 0; return 0;
} }
......
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