Input: adp5589 - make keypad support optional

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>
This commit is contained in:
Lars-Peter Clausen 2019-10-23 13:52:23 -07:00 committed by Dmitry Torokhov
parent ee1b4b2e7c
commit cb3efd5a38
1 changed files with 98 additions and 73 deletions

View File

@ -857,70 +857,35 @@ static void adp5589_report_switch_state(struct adp5589_kpad *kpad)
input_sync(kpad->input); input_sync(kpad->input);
} }
static int adp5589_probe(struct i2c_client *client, static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
const struct i2c_device_id *id)
{ {
struct adp5589_kpad *kpad; struct i2c_client *client = kpad->client;
const struct adp5589_kpad_platform_data *pdata = const struct adp5589_kpad_platform_data *pdata =
dev_get_platdata(&client->dev); dev_get_platdata(&client->dev);
struct input_dev *input; struct input_dev *input;
unsigned int revid; unsigned int i;
int ret, i;
int error; 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) && if (!((pdata->keypad_en_mask & kpad->var->row_mask) &&
(pdata->keypad_en_mask >> kpad->var->col_shift)) || (pdata->keypad_en_mask >> kpad->var->col_shift)) ||
!pdata->keymap) { !pdata->keymap) {
dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
if (pdata->keymapsize != kpad->var->keymapsize) { if (pdata->keymapsize != kpad->var->keymapsize) {
dev_err(&client->dev, "invalid keymapsize\n"); dev_err(&client->dev, "invalid keymapsize\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
if (!pdata->gpimap && pdata->gpimapsize) { if (!pdata->gpimap && pdata->gpimapsize) {
dev_err(&client->dev, "invalid gpimap from pdata\n"); dev_err(&client->dev, "invalid gpimap from pdata\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
if (pdata->gpimapsize > kpad->var->gpimapsize_max) { if (pdata->gpimapsize > kpad->var->gpimapsize_max) {
dev_err(&client->dev, "invalid gpimapsize\n"); dev_err(&client->dev, "invalid gpimapsize\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
for (i = 0; i < pdata->gpimapsize; i++) { 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 || if (pin < kpad->var->gpi_pin_base ||
pin > kpad->var->gpi_pin_end) { pin > kpad->var->gpi_pin_end) {
dev_err(&client->dev, "invalid gpi pin data\n"); dev_err(&client->dev, "invalid gpi pin data\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
if ((1 << (pin - kpad->var->gpi_pin_row_base)) & if ((1 << (pin - kpad->var->gpi_pin_row_base)) &
pdata->keypad_en_mask) { pdata->keypad_en_mask) {
dev_err(&client->dev, "invalid gpi row/col data\n"); dev_err(&client->dev, "invalid gpi row/col data\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
} }
if (!client->irq) { if (!client->irq) {
dev_err(&client->dev, "no IRQ?\n"); dev_err(&client->dev, "no IRQ?\n");
error = -EINVAL; return -EINVAL;
goto err_free_mem;
} }
input = input_allocate_device(); input = input_allocate_device();
if (!input) { if (!input)
error = -ENOMEM; return -ENOMEM;
goto err_free_mem;
}
kpad->client = client;
kpad->input = input; 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->name = client->name;
input->phys = "adp5589-keys/input0"; input->phys = "adp5589-keys/input0";
input->dev.parent = &client->dev; input->dev.parent = &client->dev;
@ -1015,30 +966,99 @@ static int adp5589_probe(struct i2c_client *client,
goto err_unreg_dev; 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); error = adp5589_setup(kpad);
if (error) if (error)
goto err_free_irq; goto err_keypad_remove;
if (kpad->gpimapsize) if (kpad->gpimapsize)
adp5589_report_switch_state(kpad); adp5589_report_switch_state(kpad);
error = adp5589_gpio_add(kpad); error = adp5589_gpio_add(kpad);
if (error) if (error)
goto err_free_irq; goto err_keypad_remove;
device_init_wakeup(&client->dev, 1);
i2c_set_clientdata(client, kpad); 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: err_keypad_remove:
free_irq(client->irq, kpad); adp5589_keypad_remove(kpad);
err_unreg_dev:
input_unregister_device(input);
input = NULL;
err_free_input:
input_free_device(input);
err_free_mem: err_free_mem:
kfree(kpad); kfree(kpad);
@ -1050,8 +1070,7 @@ static int adp5589_remove(struct i2c_client *client)
struct adp5589_kpad *kpad = i2c_get_clientdata(client); struct adp5589_kpad *kpad = i2c_get_clientdata(client);
adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
free_irq(client->irq, kpad); adp5589_keypad_remove(kpad);
input_unregister_device(kpad->input);
adp5589_gpio_remove(kpad); adp5589_gpio_remove(kpad);
kfree(kpad); kfree(kpad);
@ -1064,6 +1083,9 @@ static int adp5589_suspend(struct device *dev)
struct adp5589_kpad *kpad = dev_get_drvdata(dev); struct adp5589_kpad *kpad = dev_get_drvdata(dev);
struct i2c_client *client = kpad->client; struct i2c_client *client = kpad->client;
if (!kpad->input)
return 0;
disable_irq(client->irq); disable_irq(client->irq);
if (device_may_wakeup(&client->dev)) 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 adp5589_kpad *kpad = dev_get_drvdata(dev);
struct i2c_client *client = kpad->client; struct i2c_client *client = kpad->client;
if (!kpad->input)
return 0;
if (device_may_wakeup(&client->dev)) if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq); disable_irq_wake(client->irq);