diff options
Diffstat (limited to 'drivers/input/misc/kxtj9.c')
| -rw-r--r-- | drivers/input/misc/kxtj9.c | 291 |
1 files changed, 84 insertions, 207 deletions
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index efaffcc57e36..eb9788ea5215 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Kionix, Inc. * Written by Chris Hudson <chudson@kionix.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include <linux/delay.h> @@ -24,7 +11,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/input/kxtj9.h> -#include <linux/input-polldev.h> #define NAME "kxtj9" #define G_MAX 8000 @@ -39,7 +25,7 @@ /* CONTROL REGISTER 1 BITS */ #define PC1_OFF 0x7F #define PC1_ON (1 << 7) -/* Data ready funtion enable bit: set during probe if using irq mode */ +/* Data ready function enable bit: set during probe if using irq mode */ #define DRDYE (1 << 5) /* DATA CONTROL REGISTER BITS */ #define ODR12_5F 0 @@ -84,9 +70,6 @@ struct kxtj9_data { struct i2c_client *client; struct kxtj9_platform_data pdata; struct input_dev *input_dev; -#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE - struct input_polled_dev *poll_dev; -#endif unsigned int last_poll_interval; u8 shift; u8 ctrl_reg1; @@ -295,50 +278,6 @@ static void kxtj9_input_close(struct input_dev *dev) kxtj9_disable(tj9); } -static void kxtj9_init_input_device(struct kxtj9_data *tj9, - struct input_dev *input_dev) -{ - __set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); - input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); - input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); - - input_dev->name = "kxtj9_accel"; - input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &tj9->client->dev; -} - -static int kxtj9_setup_input_device(struct kxtj9_data *tj9) -{ - struct input_dev *input_dev; - int err; - - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&tj9->client->dev, "input device allocate failed\n"); - return -ENOMEM; - } - - tj9->input_dev = input_dev; - - input_dev->open = kxtj9_input_open; - input_dev->close = kxtj9_input_close; - input_set_drvdata(input_dev, tj9); - - kxtj9_init_input_device(tj9, input_dev); - - err = input_register_device(tj9->input_dev); - if (err) { - dev_err(&tj9->client->dev, - "unable to register input polled device %s: %d\n", - tj9->input_dev->name, err); - input_free_device(tj9->input_dev); - return err; - } - - return 0; -} - /* * When IRQ mode is selected, we need to provide an interface to allow the user * to change the output data rate of the part. For consistency, we are using @@ -375,9 +314,8 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, return error; /* Lock the device to prevent races with open/close (and itself) */ - mutex_lock(&input_dev->mutex); - - disable_irq(client->irq); + guard(mutex)(&input_dev->mutex); + guard(disable_irq)(&client->irq); /* * Set current interval to the greater of the minimum interval or @@ -387,29 +325,35 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, kxtj9_update_odr(tj9, tj9->last_poll_interval); - enable_irq(client->irq); - mutex_unlock(&input_dev->mutex); - return count; } static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll); -static struct attribute *kxtj9_attributes[] = { +static struct attribute *kxtj9_attrs[] = { &dev_attr_poll.attr, NULL }; -static struct attribute_group kxtj9_attribute_group = { - .attrs = kxtj9_attributes -}; +static umode_t kxtj9_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + return client->irq ? attr->mode : 0; +} -#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE -static void kxtj9_poll(struct input_polled_dev *dev) +static struct attribute_group kxtj9_group = { + .attrs = kxtj9_attrs, + .is_visible = kxtj9_attr_is_visible, +}; +__ATTRIBUTE_GROUPS(kxtj9); + +static void kxtj9_poll(struct input_dev *input) { - struct kxtj9_data *tj9 = dev->private; - unsigned int poll_interval = dev->poll_interval; + struct kxtj9_data *tj9 = input_get_drvdata(input); + unsigned int poll_interval = input_get_poll_interval(input); kxtj9_report_acceleration_data(tj9); @@ -419,72 +363,14 @@ static void kxtj9_poll(struct input_polled_dev *dev) } } -static void kxtj9_polled_input_open(struct input_polled_dev *dev) -{ - struct kxtj9_data *tj9 = dev->private; - - kxtj9_enable(tj9); -} - -static void kxtj9_polled_input_close(struct input_polled_dev *dev) -{ - struct kxtj9_data *tj9 = dev->private; - - kxtj9_disable(tj9); -} - -static int kxtj9_setup_polled_device(struct kxtj9_data *tj9) +static void kxtj9_platform_exit(void *data) { - int err; - struct input_polled_dev *poll_dev; - poll_dev = input_allocate_polled_device(); - - if (!poll_dev) { - dev_err(&tj9->client->dev, - "Failed to allocate polled device\n"); - return -ENOMEM; - } - - tj9->poll_dev = poll_dev; - tj9->input_dev = poll_dev->input; - - poll_dev->private = tj9; - poll_dev->poll = kxtj9_poll; - poll_dev->open = kxtj9_polled_input_open; - poll_dev->close = kxtj9_polled_input_close; - - kxtj9_init_input_device(tj9, poll_dev->input); - - err = input_register_polled_device(poll_dev); - if (err) { - dev_err(&tj9->client->dev, - "Unable to register polled device, err=%d\n", err); - input_free_polled_device(poll_dev); - return err; - } - - return 0; -} + struct kxtj9_data *tj9 = data; -static void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) -{ - input_unregister_polled_device(tj9->poll_dev); - input_free_polled_device(tj9->poll_dev); -} - -#else - -static inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9) -{ - return -ENOSYS; -} - -static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) -{ + if (tj9->pdata.exit) + tj9->pdata.exit(); } -#endif - static int kxtj9_verify(struct kxtj9_data *tj9) { int retval; @@ -506,12 +392,12 @@ out: return retval; } -static int kxtj9_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int kxtj9_probe(struct i2c_client *client) { const struct kxtj9_platform_data *pdata = dev_get_platdata(&client->dev); struct kxtj9_data *tj9; + struct input_dev *input_dev; int err; if (!i2c_check_functionality(client->adapter, @@ -525,7 +411,7 @@ static int kxtj9_probe(struct i2c_client *client, return -EINVAL; } - tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL); + tj9 = devm_kzalloc(&client->dev, sizeof(*tj9), GFP_KERNEL); if (!tj9) { dev_err(&client->dev, "failed to allocate memory for module data\n"); @@ -538,13 +424,17 @@ static int kxtj9_probe(struct i2c_client *client, if (pdata->init) { err = pdata->init(); if (err < 0) - goto err_free_mem; + return err; } + err = devm_add_action_or_reset(&client->dev, kxtj9_platform_exit, tj9); + if (err) + return err; + err = kxtj9_verify(tj9); if (err < 0) { dev_err(&client->dev, "device not recognized\n"); - goto err_pdata_exit; + return err; } i2c_set_clientdata(client, tj9); @@ -552,115 +442,102 @@ static int kxtj9_probe(struct i2c_client *client, tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range; tj9->last_poll_interval = tj9->pdata.init_interval; - if (client->irq) { - /* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */ - tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL; - tj9->ctrl_reg1 |= DRDYE; + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) { + dev_err(&client->dev, "input device allocate failed\n"); + return -ENOMEM; + } - err = kxtj9_setup_input_device(tj9); - if (err) - goto err_pdata_exit; + input_set_drvdata(input_dev, tj9); + tj9->input_dev = input_dev; - err = request_threaded_irq(client->irq, NULL, kxtj9_isr, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "kxtj9-irq", tj9); - if (err) { - dev_err(&client->dev, "request irq failed: %d\n", err); - goto err_destroy_input; - } + input_dev->name = "kxtj9_accel"; + input_dev->id.bustype = BUS_I2C; - err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group); - if (err) { - dev_err(&client->dev, "sysfs create failed: %d\n", err); - goto err_free_irq; - } + input_dev->open = kxtj9_input_open; + input_dev->close = kxtj9_input_close; - } else { - err = kxtj9_setup_polled_device(tj9); + input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + if (client->irq <= 0) { + err = input_setup_polling(input_dev, kxtj9_poll); if (err) - goto err_pdata_exit; + return err; } - return 0; - -err_free_irq: - free_irq(client->irq, tj9); -err_destroy_input: - input_unregister_device(tj9->input_dev); -err_pdata_exit: - if (tj9->pdata.exit) - tj9->pdata.exit(); -err_free_mem: - kfree(tj9); - return err; -} - -static int kxtj9_remove(struct i2c_client *client) -{ - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - - if (client->irq) { - sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group); - free_irq(client->irq, tj9); - input_unregister_device(tj9->input_dev); - } else { - kxtj9_teardown_polled_device(tj9); + err = input_register_device(input_dev); + if (err) { + dev_err(&client->dev, + "unable to register input polled device %s: %d\n", + input_dev->name, err); + return err; } - if (tj9->pdata.exit) - tj9->pdata.exit(); + if (client->irq) { + /* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */ + tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL; + tj9->ctrl_reg1 |= DRDYE; - kfree(tj9); + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, kxtj9_isr, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "kxtj9-irq", tj9); + if (err) { + dev_err(&client->dev, "request irq failed: %d\n", err); + return err; + } + } return 0; } -static int __maybe_unused kxtj9_suspend(struct device *dev) +static int kxtj9_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct kxtj9_data *tj9 = i2c_get_clientdata(client); struct input_dev *input_dev = tj9->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) kxtj9_disable(tj9); - mutex_unlock(&input_dev->mutex); return 0; } -static int __maybe_unused kxtj9_resume(struct device *dev) +static int kxtj9_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct kxtj9_data *tj9 = i2c_get_clientdata(client); struct input_dev *input_dev = tj9->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) kxtj9_enable(tj9); - mutex_unlock(&input_dev->mutex); return 0; } -static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); static const struct i2c_device_id kxtj9_id[] = { - { NAME, 0 }, - { }, + { NAME }, + { } }; MODULE_DEVICE_TABLE(i2c, kxtj9_id); static struct i2c_driver kxtj9_driver = { .driver = { - .name = NAME, - .pm = &kxtj9_pm_ops, + .name = NAME, + .dev_groups = kxtj9_groups, + .pm = pm_sleep_ptr(&kxtj9_pm_ops), }, .probe = kxtj9_probe, - .remove = kxtj9_remove, .id_table = kxtj9_id, }; |
