summaryrefslogtreecommitdiff
path: root/drivers/input/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/adxl34x-i2c.c5
-rw-r--r--drivers/input/misc/atlas_btns.c22
-rw-r--r--drivers/input/misc/aw86927.c66
-rw-r--r--drivers/input/misc/drv260x.c50
-rw-r--r--drivers/input/misc/ims-pcu.c32
-rw-r--r--drivers/input/misc/keyspan_remote.c22
-rw-r--r--drivers/input/misc/rb532_button.c35
-rw-r--r--drivers/input/misc/uinput.c35
8 files changed, 196 insertions, 71 deletions
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index c05d898898e8..5ea0ce42a507 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -77,11 +77,8 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
static int adxl34x_i2c_probe(struct i2c_client *client)
{
struct adxl34x *ac;
- int error;
- error = i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA);
- if (!error) {
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
return -EIO;
}
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 5b9be2957746..47b31725e850 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/types.h>
#include <linux/acpi.h>
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
#define ACPI_ATLAS_NAME "Atlas ACPI"
@@ -57,8 +58,9 @@ static acpi_status acpi_atlas_button_handler(u32 function,
return status;
}
-static int atlas_acpi_button_add(struct acpi_device *device)
+static int atlas_acpi_button_probe(struct platform_device *pdev)
{
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
acpi_status status;
int i;
int err;
@@ -106,8 +108,9 @@ static int atlas_acpi_button_add(struct acpi_device *device)
return err;
}
-static void atlas_acpi_button_remove(struct acpi_device *device)
+static void atlas_acpi_button_remove(struct platform_device *pdev)
{
+ struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
acpi_status status;
status = acpi_remove_address_space_handler(device->handle,
@@ -124,16 +127,15 @@ static const struct acpi_device_id atlas_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
-static struct acpi_driver atlas_acpi_driver = {
- .name = ACPI_ATLAS_NAME,
- .class = ACPI_ATLAS_CLASS,
- .ids = atlas_device_ids,
- .ops = {
- .add = atlas_acpi_button_add,
- .remove = atlas_acpi_button_remove,
+static struct platform_driver atlas_acpi_driver = {
+ .probe = atlas_acpi_button_probe,
+ .remove = atlas_acpi_button_remove,
+ .driver = {
+ .name = ACPI_ATLAS_NAME,
+ .acpi_match_table = atlas_device_ids,
},
};
-module_acpi_driver(atlas_acpi_driver);
+module_platform_driver(atlas_acpi_driver);
MODULE_AUTHOR("Jaya Kumar");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c
index 8ad361239cfe..f53b8f004cb3 100644
--- a/drivers/input/misc/aw86927.c
+++ b/drivers/input/misc/aw86927.c
@@ -43,6 +43,12 @@
#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0)
#define AW86927_PLAYCFG1_BST_8500MV 0x50
+#define AW86938_PLAYCFG1_REG 0x06
+#define AW86938_PLAYCFG1_BST_MODE_MASK GENMASK(5, 5)
+#define AW86938_PLAYCFG1_BST_MODE_BYPASS 0
+#define AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(4, 0)
+#define AW86938_PLAYCFG1_BST_7000MV 0x11
+
#define AW86927_PLAYCFG2_REG 0x07
#define AW86927_PLAYCFG3_REG 0x08
@@ -140,6 +146,7 @@
#define AW86927_CHIPIDH_REG 0x57
#define AW86927_CHIPIDL_REG 0x58
#define AW86927_CHIPID 0x9270
+#define AW86938_CHIPID 0x9380
#define AW86927_TMCFG_REG 0x5b
#define AW86927_TMCFG_UNLOCK 0x7d
@@ -173,14 +180,20 @@ enum aw86927_work_mode {
AW86927_RAM_MODE,
};
+enum aw86927_model {
+ AW86927,
+ AW86938,
+};
+
struct aw86927_data {
+ enum aw86927_model model;
struct work_struct play_work;
struct device *dev;
struct input_dev *input_dev;
struct i2c_client *client;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
- bool running;
+ u16 level;
};
static const struct regmap_config aw86927_regmap_config = {
@@ -325,11 +338,12 @@ static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_eff
if (!level)
level = effect->u.rumble.weak_magnitude;
- /* If already running, don't restart playback */
- if (haptics->running && level)
+ /* If level does not change, don't restart playback */
+ if (haptics->level == level)
return 0;
- haptics->running = level;
+ haptics->level = level;
+
schedule_work(&haptics->play_work);
return 0;
@@ -376,8 +390,7 @@ static int aw86927_play_sine(struct aw86927_data *haptics)
if (err)
return err;
- /* set gain to value lower than 0x80 to avoid distorted playback */
- err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
+ err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, haptics->level * 0x80 / 0xffff);
if (err)
return err;
@@ -409,7 +422,7 @@ static void aw86927_haptics_play_work(struct work_struct *work)
struct device *dev = &haptics->client->dev;
int err;
- if (haptics->running)
+ if (haptics->level)
err = aw86927_play_sine(haptics);
else
err = aw86927_stop(haptics);
@@ -565,13 +578,26 @@ static int aw86927_haptic_init(struct aw86927_data *haptics)
if (err)
return err;
- err = regmap_update_bits(haptics->regmap,
- AW86927_PLAYCFG1_REG,
- AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
- FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
- AW86927_PLAYCFG1_BST_8500MV));
- if (err)
- return err;
+ switch (haptics->model) {
+ case AW86927:
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PLAYCFG1_REG,
+ AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ AW86927_PLAYCFG1_BST_8500MV));
+ if (err)
+ return err;
+ break;
+ case AW86938:
+ err = regmap_update_bits(haptics->regmap,
+ AW86938_PLAYCFG1_REG,
+ AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ FIELD_PREP(AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ AW86938_PLAYCFG1_BST_7000MV));
+ if (err)
+ return err;
+ break;
+ }
err = regmap_update_bits(haptics->regmap,
AW86927_PLAYCFG3_REG,
@@ -599,6 +625,9 @@ static int aw86927_ram_init(struct aw86927_data *haptics)
FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
AW86927_SYSCTRL3_EN_RAMINIT_ON));
+ /* AW86938 wants a 1ms delay here */
+ usleep_range(1000, 1500);
+
/* Set base address for the start of the SRAM waveforms */
err = regmap_write(haptics->regmap,
AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL);
@@ -717,7 +746,14 @@ static int aw86927_detect(struct aw86927_data *haptics)
chip_id = be16_to_cpu(read_buf);
- if (chip_id != AW86927_CHIPID) {
+ switch (chip_id) {
+ case AW86927_CHIPID:
+ haptics->model = AW86927;
+ break;
+ case AW86938_CHIPID:
+ haptics->model = AW86938;
+ break;
+ default:
dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
return -ENODEV;
}
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 96cd6a078c8a..e2089d6ac850 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -7,14 +7,16 @@
* Copyright: (C) 2014 Texas Instruments, Inc.
*/
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/device/devres.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <dt-bindings/input/ti-drv260x.h>
@@ -165,6 +167,12 @@
#define DRV260X_AUTOCAL_TIME_500MS (2 << 4)
#define DRV260X_AUTOCAL_TIME_1000MS (3 << 4)
+/*
+ * Timeout for waiting for the GO status bit, in seconds. Should be reasonably
+ * large to wait for a auto-calibration cycle completion.
+ */
+#define DRV260X_GO_TIMEOUT_S 5
+
/**
* struct drv260x_data -
* @input_dev: Pointer to the input device
@@ -308,6 +316,7 @@ static int drv260x_init(struct drv260x_data *haptics)
{
int error;
unsigned int cal_buf;
+ unsigned long timeout;
error = regmap_write(haptics->regmap,
DRV260X_RATED_VOLT, haptics->rated_voltage);
@@ -397,6 +406,7 @@ static int drv260x_init(struct drv260x_data *haptics)
return error;
}
+ timeout = jiffies + DRV260X_GO_TIMEOUT_S * HZ;
do {
usleep_range(15000, 15500);
error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
@@ -406,6 +416,11 @@ static int drv260x_init(struct drv260x_data *haptics)
error);
return error;
}
+ if (time_after(jiffies, timeout)) {
+ dev_err(&haptics->client->dev,
+ "Calibration timeout. The device cannot be used.\n");
+ return -ETIMEDOUT;
+ }
} while (cal_buf == DRV260X_GO_BIT);
return 0;
@@ -419,6 +434,13 @@ static const struct regmap_config drv260x_regmap_config = {
.cache_type = REGCACHE_NONE,
};
+static void drv260x_power_off(void *data)
+{
+ struct drv260x_data *haptics = data;
+
+ regulator_disable(haptics->regulator);
+}
+
static int drv260x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -484,6 +506,16 @@ static int drv260x_probe(struct i2c_client *client)
return error;
}
+ error = regulator_enable(haptics->regulator);
+ if (error) {
+ dev_err(dev, "Failed to enable regulator: %d\n", error);
+ return error;
+ }
+
+ error = devm_add_action_or_reset(dev, drv260x_power_off, haptics);
+ if (error)
+ return error;
+
haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(haptics->enable_gpio))
@@ -598,11 +630,22 @@ static int drv260x_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
+ { "drv2604" },
+ { "drv2604l" },
+ { "drv2605" },
{ "drv2605l" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv260x_id);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id drv260x_acpi_match[] = {
+ { "DRV2604" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, drv260x_acpi_match);
+#endif
+
static const struct of_device_id drv260x_of_match[] = {
{ .compatible = "ti,drv2604", },
{ .compatible = "ti,drv2604l", },
@@ -616,6 +659,7 @@ static struct i2c_driver drv260x_driver = {
.probe = drv260x_probe,
.driver = {
.name = "drv260x-haptics",
+ .acpi_match_table = ACPI_PTR(drv260x_acpi_match),
.of_match_table = drv260x_of_match,
.pm = pm_sleep_ptr(&drv260x_pm_ops),
},
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index f69de9762c4e..4c022a36dbe8 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -438,6 +438,14 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu)
}
}
+static void ims_pcu_reset_packet(struct ims_pcu *pcu)
+{
+ pcu->have_stx = true;
+ pcu->have_dle = false;
+ pcu->read_pos = 0;
+ pcu->check_sum = 0;
+}
+
static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
{
int i;
@@ -450,6 +458,14 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
continue;
if (pcu->have_dle) {
+ if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
+ dev_warn(pcu->dev,
+ "Packet too long (%d bytes), discarding\n",
+ pcu->read_pos);
+ ims_pcu_reset_packet(pcu);
+ continue;
+ }
+
pcu->have_dle = false;
pcu->read_buf[pcu->read_pos++] = data;
pcu->check_sum += data;
@@ -462,10 +478,8 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
dev_warn(pcu->dev,
"Unexpected STX at byte %d, discarding old data\n",
pcu->read_pos);
+ ims_pcu_reset_packet(pcu);
pcu->have_stx = true;
- pcu->have_dle = false;
- pcu->read_pos = 0;
- pcu->check_sum = 0;
break;
case IMS_PCU_PROTOCOL_DLE:
@@ -485,12 +499,18 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
ims_pcu_handle_response(pcu);
}
- pcu->have_stx = false;
- pcu->have_dle = false;
- pcu->read_pos = 0;
+ ims_pcu_reset_packet(pcu);
break;
default:
+ if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
+ dev_warn(pcu->dev,
+ "Packet too long (%d bytes), discarding\n",
+ pcu->read_pos);
+ ims_pcu_reset_packet(pcu);
+ continue;
+ }
+
pcu->read_buf[pcu->read_pos++] = data;
pcu->check_sum += data;
break;
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index 152633bd2266..70cd6586459e 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -420,24 +420,6 @@ static void keyspan_close(struct input_dev *dev)
usb_kill_urb(remote->irq_urb);
}
-static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
-{
-
- struct usb_endpoint_descriptor *endpoint;
- int i;
-
- for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
- endpoint = &iface->endpoint[i].desc;
-
- if (usb_endpoint_is_int_in(endpoint)) {
- /* we found our interrupt in endpoint */
- return endpoint;
- }
- }
-
- return NULL;
-}
-
/*
* Routine that sets up the driver to handle a specific USB device detected on the bus.
*/
@@ -449,8 +431,8 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
struct input_dev *input_dev;
int i, error;
- endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
- if (!endpoint)
+ error = usb_find_int_in_endpoint(interface->cur_altsetting, &endpoint);
+ if (error)
return -ENODEV;
remote = kzalloc_obj(*remote);
diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c
index 190a80e1e2c1..40173bf7a235 100644
--- a/drivers/input/misc/rb532_button.c
+++ b/drivers/input/misc/rb532_button.c
@@ -8,7 +8,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <asm/mach-rc32434/gpio.h>
#include <asm/mach-rc32434/rb.h>
@@ -18,6 +18,14 @@
#define RB532_BTN_RATE 100 /* msec */
#define RB532_BTN_KSYM BTN_0
+/**
+ * struct rb532_button - RB532 button information
+ * @gpio: GPIO connected to the button
+ */
+struct rb532_button {
+ struct gpio_desc *gpio;
+};
+
/* The S1 button state is provided by GPIO pin 1. But as this
* pin is also used for uart input as alternate function, the
* operational modes must be switched first:
@@ -31,35 +39,48 @@
* The GPIO value occurs to be inverted, so pin high means
* button is not pressed.
*/
-static bool rb532_button_pressed(void)
+static bool rb532_button_pressed(struct rb532_button *button)
{
int val;
set_latch_u5(0, LO_FOFF);
- gpio_direction_input(GPIO_BTN_S1);
+ gpiod_direction_input(button->gpio);
- val = gpio_get_value(GPIO_BTN_S1);
+ val = gpiod_get_value(button->gpio);
rb532_gpio_set_func(GPIO_BTN_S1);
set_latch_u5(LO_FOFF, 0);
- return !val;
+ return val;
}
static void rb532_button_poll(struct input_dev *input)
{
- input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed());
+ struct rb532_button *button = input_get_drvdata(input);
+
+ input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed(button));
input_sync(input);
}
static int rb532_button_probe(struct platform_device *pdev)
{
+ struct rb532_button *button;
struct input_dev *input;
int error;
+ button = devm_kzalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
+ if (!button)
+ return -ENOMEM;
+
+ button->gpio = devm_gpiod_get(&pdev->dev, "button", GPIOD_IN);
+ if (IS_ERR(button->gpio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(button->gpio),
+ "error getting button GPIO\n");
+
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
+ input_set_drvdata(input, button);
input->name = "rb532 button";
input->phys = "rb532/button0";
@@ -77,6 +98,8 @@ static int rb532_button_probe(struct platform_device *pdev)
if (error)
return error;
+ platform_set_drvdata(pdev, button);
+
return 0;
}
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index e589060db280..d32fa4b508fc 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -25,8 +25,10 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/lockdep.h>
#include <linux/miscdevice.h>
#include <linux/overflow.h>
+#include <linux/spinlock.h>
#include <linux/input/mt.h>
#include "../input-compat.h"
@@ -57,6 +59,7 @@ struct uinput_device {
struct input_dev *dev;
struct mutex mutex;
enum uinput_state state;
+ spinlock_t state_lock;
wait_queue_head_t waitq;
unsigned char ready;
unsigned char head;
@@ -75,6 +78,8 @@ static int uinput_dev_event(struct input_dev *dev,
struct uinput_device *udev = input_get_drvdata(dev);
struct timespec64 ts;
+ lockdep_assert_held(&dev->event_lock);
+
ktime_get_ts64(&ts);
udev->buff[udev->head] = (struct input_event) {
@@ -146,27 +151,26 @@ static void uinput_request_release_slot(struct uinput_device *udev,
static int uinput_request_send(struct uinput_device *udev,
struct uinput_request *request)
{
- int retval;
+ unsigned long flags;
+ int retval = 0;
- retval = mutex_lock_interruptible(&udev->mutex);
- if (retval)
- return retval;
+ spin_lock(&udev->state_lock);
if (udev->state != UIST_CREATED) {
retval = -ENODEV;
goto out;
}
- init_completion(&request->done);
-
/*
* Tell our userspace application about this new request
* by queueing an input event.
*/
+ spin_lock_irqsave(&udev->dev->event_lock, flags);
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+ spin_unlock_irqrestore(&udev->dev->event_lock, flags);
out:
- mutex_unlock(&udev->mutex);
+ spin_unlock(&udev->state_lock);
return retval;
}
@@ -175,6 +179,13 @@ static int uinput_request_submit(struct uinput_device *udev,
{
int retval;
+ /*
+ * Initialize completion before allocating the request slot.
+ * Once the slot is allocated, uinput_flush_requests() may
+ * complete it at any time, so it must be initialized first.
+ */
+ init_completion(&request->done);
+
retval = uinput_request_reserve_slot(udev, request);
if (retval)
return retval;
@@ -289,7 +300,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
struct input_dev *dev = udev->dev;
enum uinput_state old_state = udev->state;
+ /*
+ * Update state under state_lock so that concurrent
+ * uinput_request_send() sees the state change before we
+ * flush pending requests and tear down the device.
+ */
+ spin_lock(&udev->state_lock);
udev->state = UIST_NEW_DEVICE;
+ spin_unlock(&udev->state_lock);
if (dev) {
name = dev->name;
@@ -366,7 +384,9 @@ static int uinput_create_device(struct uinput_device *udev)
if (error)
goto fail2;
+ spin_lock(&udev->state_lock);
udev->state = UIST_CREATED;
+ spin_unlock(&udev->state_lock);
return 0;
@@ -384,6 +404,7 @@ static int uinput_open(struct inode *inode, struct file *file)
return -ENOMEM;
mutex_init(&newdev->mutex);
+ spin_lock_init(&newdev->state_lock);
spin_lock_init(&newdev->requests_lock);
init_waitqueue_head(&newdev->requests_waitq);
init_waitqueue_head(&newdev->waitq);