summaryrefslogtreecommitdiff
path: root/drivers/input/misc/kxtj9.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc/kxtj9.c')
-rw-r--r--drivers/input/misc/kxtj9.c291
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,
};