Input: adp5589 - make keypad support optional
authorLars-Peter Clausen <lars@metafoo.de>
Wed, 23 Oct 2019 20:52:23 +0000 (13:52 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 23 Oct 2019 23:24:13 +0000 (16:24 -0700)
On some platforms the adp5589 is used in GPIO only mode. On these platforms
we do not want to register a input device, so make that optional and only
create the input device if a keymap is supplied.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Link: https://lore.kernel.org/r/20191023070541.13940-1-alexandru.ardelean@analog.com
[dtor: dropped unnecessary changes related to passing pdata to various
 functions]
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/keyboard/adp5589-keys.c

index 4f96a4a99e5b867be06c10a80234166f2451f927..e7d58e7f0257c989c43b8d034af5efb77639ca80 100644 (file)
@@ -857,70 +857,35 @@ static void adp5589_report_switch_state(struct adp5589_kpad *kpad)
        input_sync(kpad->input);
 }
 
-static int adp5589_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
 {
-       struct adp5589_kpad *kpad;
+       struct i2c_client *client = kpad->client;
        const struct adp5589_kpad_platform_data *pdata =
                dev_get_platdata(&client->dev);
        struct input_dev *input;
-       unsigned int revid;
-       int ret, i;
+       unsigned int i;
        int error;
 
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
-               return -EIO;
-       }
-
-       if (!pdata) {
-               dev_err(&client->dev, "no platform data?\n");
-               return -EINVAL;
-       }
-
-       kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
-       if (!kpad)
-               return -ENOMEM;
-
-       switch (id->driver_data) {
-       case ADP5585_02:
-               kpad->support_row5 = true;
-               /* fall through */
-       case ADP5585_01:
-               kpad->is_adp5585 = true;
-               kpad->var = &const_adp5585;
-               break;
-       case ADP5589:
-               kpad->support_row5 = true;
-               kpad->var = &const_adp5589;
-               break;
-       }
-
        if (!((pdata->keypad_en_mask & kpad->var->row_mask) &&
                        (pdata->keypad_en_mask >> kpad->var->col_shift)) ||
                        !pdata->keymap) {
                dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
-               error = -EINVAL;
-               goto err_free_mem;
+               return -EINVAL;
        }
 
        if (pdata->keymapsize != kpad->var->keymapsize) {
                dev_err(&client->dev, "invalid keymapsize\n");
-               error = -EINVAL;
-               goto err_free_mem;
+               return -EINVAL;
        }
 
        if (!pdata->gpimap && pdata->gpimapsize) {
                dev_err(&client->dev, "invalid gpimap from pdata\n");
-               error = -EINVAL;
-               goto err_free_mem;
+               return -EINVAL;
        }
 
        if (pdata->gpimapsize > kpad->var->gpimapsize_max) {
                dev_err(&client->dev, "invalid gpimapsize\n");
-               error = -EINVAL;
-               goto err_free_mem;
+               return -EINVAL;
        }
 
        for (i = 0; i < pdata->gpimapsize; i++) {
@@ -929,41 +894,27 @@ static int adp5589_probe(struct i2c_client *client,
                if (pin < kpad->var->gpi_pin_base ||
                                pin > kpad->var->gpi_pin_end) {
                        dev_err(&client->dev, "invalid gpi pin data\n");
-                       error = -EINVAL;
-                       goto err_free_mem;
+                       return -EINVAL;
                }
 
                if ((1 << (pin - kpad->var->gpi_pin_row_base)) &
                                pdata->keypad_en_mask) {
                        dev_err(&client->dev, "invalid gpi row/col data\n");
-                       error = -EINVAL;
-                       goto err_free_mem;
+                       return -EINVAL;
                }
        }
 
        if (!client->irq) {
                dev_err(&client->dev, "no IRQ?\n");
-               error = -EINVAL;
-               goto err_free_mem;
+               return -EINVAL;
        }
 
        input = input_allocate_device();
-       if (!input) {
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       if (!input)
+               return -ENOMEM;
 
-       kpad->client = client;
        kpad->input = input;
 
-       ret = adp5589_read(client, ADP5589_5_ID);
-       if (ret < 0) {
-               error = ret;
-               goto err_free_input;
-       }
-
-       revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
-
        input->name = client->name;
        input->phys = "adp5589-keys/input0";
        input->dev.parent = &client->dev;
@@ -1015,30 +966,99 @@ static int adp5589_probe(struct i2c_client *client,
                goto err_unreg_dev;
        }
 
+       device_init_wakeup(&client->dev, 1);
+
+       return 0;
+
+err_unreg_dev:
+       input_unregister_device(input);
+       input = NULL;
+err_free_input:
+       input_free_device(input);
+
+       return error;
+}
+
+static void adp5589_keypad_remove(struct adp5589_kpad *kpad)
+{
+       if (kpad->input) {
+               free_irq(kpad->client->irq, kpad);
+               input_unregister_device(kpad->input);
+       }
+}
+
+static int adp5589_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct adp5589_kpad *kpad;
+       const struct adp5589_kpad_platform_data *pdata =
+               dev_get_platdata(&client->dev);
+       unsigned int revid;
+       int error, ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+       if (!kpad)
+               return -ENOMEM;
+
+       kpad->client = client;
+
+       switch (id->driver_data) {
+       case ADP5585_02:
+               kpad->support_row5 = true;
+               /* fall through */
+       case ADP5585_01:
+               kpad->is_adp5585 = true;
+               kpad->var = &const_adp5585;
+               break;
+       case ADP5589:
+               kpad->support_row5 = true;
+               kpad->var = &const_adp5589;
+               break;
+       }
+
+       ret = adp5589_read(client, ADP5589_5_ID);
+       if (ret < 0) {
+               error = ret;
+               goto err_free_mem;
+       }
+
+       revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
+
+       if (pdata->keymapsize) {
+               error = adp5589_keypad_add(kpad, revid);
+               if (error)
+                       goto err_free_mem;
+       }
+
        error = adp5589_setup(kpad);
        if (error)
-               goto err_free_irq;
+               goto err_keypad_remove;
 
        if (kpad->gpimapsize)
                adp5589_report_switch_state(kpad);
 
        error = adp5589_gpio_add(kpad);
        if (error)
-               goto err_free_irq;
+               goto err_keypad_remove;
 
-       device_init_wakeup(&client->dev, 1);
        i2c_set_clientdata(client, kpad);
 
        dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
        return 0;
 
-err_free_irq:
-       free_irq(client->irq, kpad);
-err_unreg_dev:
-       input_unregister_device(input);
-       input = NULL;
-err_free_input:
-       input_free_device(input);
+err_keypad_remove:
+       adp5589_keypad_remove(kpad);
 err_free_mem:
        kfree(kpad);
 
@@ -1050,8 +1070,7 @@ static int adp5589_remove(struct i2c_client *client)
        struct adp5589_kpad *kpad = i2c_get_clientdata(client);
 
        adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
-       free_irq(client->irq, kpad);
-       input_unregister_device(kpad->input);
+       adp5589_keypad_remove(kpad);
        adp5589_gpio_remove(kpad);
        kfree(kpad);
 
@@ -1064,6 +1083,9 @@ static int adp5589_suspend(struct device *dev)
        struct adp5589_kpad *kpad = dev_get_drvdata(dev);
        struct i2c_client *client = kpad->client;
 
+       if (!kpad->input)
+               return 0;
+
        disable_irq(client->irq);
 
        if (device_may_wakeup(&client->dev))
@@ -1077,6 +1099,9 @@ static int adp5589_resume(struct device *dev)
        struct adp5589_kpad *kpad = dev_get_drvdata(dev);
        struct i2c_client *client = kpad->client;
 
+       if (!kpad->input)
+               return 0;
+
        if (device_may_wakeup(&client->dev))
                disable_irq_wake(client->irq);