diff options
Diffstat (limited to 'drivers/input/misc')
| -rw-r--r-- | drivers/input/misc/adxl34x-i2c.c | 5 | ||||
| -rw-r--r-- | drivers/input/misc/atlas_btns.c | 22 | ||||
| -rw-r--r-- | drivers/input/misc/aw86927.c | 66 | ||||
| -rw-r--r-- | drivers/input/misc/drv260x.c | 50 | ||||
| -rw-r--r-- | drivers/input/misc/ims-pcu.c | 32 | ||||
| -rw-r--r-- | drivers/input/misc/keyspan_remote.c | 22 | ||||
| -rw-r--r-- | drivers/input/misc/rb532_button.c | 35 | ||||
| -rw-r--r-- | drivers/input/misc/uinput.c | 35 |
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); |
