Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8c82b6a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull input fixes from Dmitry Torokhov:

 - tweaks to Elan drivers (both PS/2 and I2C) to support new devices.
   Also revert of one of IDs as that device should really be driven by
   i2c-hid + hid-multitouch

 - a few drivers have been switched to set_brightness_blocking() call
   because they either were sleeping the their set_brightness()
   implementation or used workqueue but were not canceling it on unbind.

 - ps2-gpio and matrix_keypad needed to [properly] flush their works to
   avoid potential use-after-free on unbind.

 - other miscellaneous fixes.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: elan_i2c - add ACPI ID for touchpad in Lenovo V330-15ISK
  Input: st-keyscan - fix potential zalloc NULL dereference
  Input: apanel - switch to using brightness_set_blocking()
  Revert "Input: elan_i2c - add ACPI ID for touchpad in ASUS Aspire F5-573G"
  Input: qt2160 - switch to using brightness_set_blocking()
  Input: matrix_keypad - use flush_delayed_work()
  Input: ps2-gpio - flush TX work when closing port
  Input: cap11xx - switch to using set_brightness_blocking()
  Input: elantech - enable 3rd button support on Fujitsu CELSIUS H780
  Input: bma150 - register input device after setting private data
  Input: pwm-vibra - stop regulator after disabling pwm, not before
  Input: pwm-vibra - prevent unbalanced regulator
  Input: snvs_pwrkey - allow selecting driver for i.MX 7D
parents ed0a0ec9 7ad222b3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -420,7 +420,7 @@ config KEYBOARD_MPR121

config KEYBOARD_SNVS_PWRKEY
	tristate "IMX SNVS Power Key Driver"
	depends on SOC_IMX6SX
	depends on SOC_IMX6SX || SOC_IMX7D
	depends on OF
	help
	  This is the snvs powerkey driver for the Freescale i.MX application
+11 −24
Original line number Diff line number Diff line
@@ -75,9 +75,7 @@
struct cap11xx_led {
	struct cap11xx_priv *priv;
	struct led_classdev cdev;
	struct work_struct work;
	u32 reg;
	enum led_brightness new_brightness;
};
#endif

@@ -233,30 +231,21 @@ static void cap11xx_input_close(struct input_dev *idev)
}

#ifdef CONFIG_LEDS_CLASS
static void cap11xx_led_work(struct work_struct *work)
static int cap11xx_led_set(struct led_classdev *cdev,
			    enum led_brightness value)
{
	struct cap11xx_led *led = container_of(work, struct cap11xx_led, work);
	struct cap11xx_led *led = container_of(cdev, struct cap11xx_led, cdev);
	struct cap11xx_priv *priv = led->priv;
	int value = led->new_brightness;

	/*
	 * All LEDs share the same duty cycle as this is a HW limitation.
	 * Brightness levels per LED are either 0 (OFF) and 1 (ON).
	 * All LEDs share the same duty cycle as this is a HW
	 * limitation. Brightness levels per LED are either
	 * 0 (OFF) and 1 (ON).
	 */
	regmap_update_bits(priv->regmap, CAP11XX_REG_LED_OUTPUT_CONTROL,
				BIT(led->reg), value ? BIT(led->reg) : 0);
}

static void cap11xx_led_set(struct led_classdev *cdev,
			   enum led_brightness value)
{
	struct cap11xx_led *led = container_of(cdev, struct cap11xx_led, cdev);

	if (led->new_brightness == value)
		return;

	led->new_brightness = value;
	schedule_work(&led->work);
	return regmap_update_bits(priv->regmap,
				  CAP11XX_REG_LED_OUTPUT_CONTROL,
				  BIT(led->reg),
				  value ? BIT(led->reg) : 0);
}

static int cap11xx_init_leds(struct device *dev,
@@ -299,7 +288,7 @@ static int cap11xx_init_leds(struct device *dev,
		led->cdev.default_trigger =
			of_get_property(child, "linux,default-trigger", NULL);
		led->cdev.flags = 0;
		led->cdev.brightness_set = cap11xx_led_set;
		led->cdev.brightness_set_blocking = cap11xx_led_set;
		led->cdev.max_brightness = 1;
		led->cdev.brightness = LED_OFF;

@@ -312,8 +301,6 @@ static int cap11xx_init_leds(struct device *dev,
		led->reg = reg;
		led->priv = priv;

		INIT_WORK(&led->work, cap11xx_led_work);

		error = devm_led_classdev_register(dev, &led->cdev);
		if (error) {
			of_node_put(child);
+1 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ static void matrix_keypad_stop(struct input_dev *dev)
	keypad->stopped = true;
	spin_unlock_irq(&keypad->lock);

	flush_work(&keypad->work.work);
	flush_delayed_work(&keypad->work);
	/*
	 * matrix_keypad_scan() will leave IRQs enabled;
	 * we should disable them now.
+27 −42
Original line number Diff line number Diff line
@@ -58,10 +58,9 @@ static unsigned char qt2160_key2code[] = {
struct qt2160_led {
	struct qt2160_data *qt2160;
	struct led_classdev cdev;
	struct work_struct work;
	char name[32];
	int id;
	enum led_brightness new_brightness;
	enum led_brightness brightness;
};
#endif

@@ -74,7 +73,6 @@ struct qt2160_data {
	u16 key_matrix;
#ifdef CONFIG_LEDS_CLASS
	struct qt2160_led leds[QT2160_NUM_LEDS_X];
	struct mutex led_lock;
#endif
};

@@ -83,25 +81,24 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);

#ifdef CONFIG_LEDS_CLASS

static void qt2160_led_work(struct work_struct *work)
static int qt2160_led_set(struct led_classdev *cdev,
			  enum led_brightness value)
{
	struct qt2160_led *led = container_of(work, struct qt2160_led, work);
	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
	struct qt2160_data *qt2160 = led->qt2160;
	struct i2c_client *client = qt2160->client;
	int value = led->new_brightness;
	u32 drive, pwmen;

	mutex_lock(&qt2160->led_lock);

	if (value != led->brightness) {
		drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
		pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
		if (value != LED_OFF) {
		drive |= (1 << led->id);
		pwmen |= (1 << led->id);
			drive |= BIT(led->id);
			pwmen |= BIT(led->id);

		} else {
		drive &= ~(1 << led->id);
		pwmen &= ~(1 << led->id);
			drive &= ~BIT(led->id);
			pwmen &= ~BIT(led->id);
		}
		qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
		qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
@@ -113,16 +110,10 @@ static void qt2160_led_work(struct work_struct *work)
		if (value != LED_OFF)
			qt2160_write(client, QT2160_CMD_PWM_DUTY, value);

	mutex_unlock(&qt2160->led_lock);
		led->brightness = value;
	}

static void qt2160_led_set(struct led_classdev *cdev,
			   enum led_brightness value)
{
	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);

	led->new_brightness = value;
	schedule_work(&led->work);
	return 0;
}

#endif /* CONFIG_LEDS_CLASS */
@@ -293,20 +284,16 @@ static int qt2160_register_leds(struct qt2160_data *qt2160)
	int ret;
	int i;

	mutex_init(&qt2160->led_lock);

	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
		struct qt2160_led *led = &qt2160->leds[i];

		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
		led->cdev.name = led->name;
		led->cdev.brightness_set = qt2160_led_set;
		led->cdev.brightness_set_blocking = qt2160_led_set;
		led->cdev.brightness = LED_OFF;
		led->id = i;
		led->qt2160 = qt2160;

		INIT_WORK(&led->work, qt2160_led_work);

		ret = led_classdev_register(&client->dev, &led->cdev);
		if (ret < 0)
			return ret;
@@ -324,10 +311,8 @@ static void qt2160_unregister_leds(struct qt2160_data *qt2160)
{
	int i;

	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
	for (i = 0; i < QT2160_NUM_LEDS_X; i++)
		led_classdev_unregister(&qt2160->leds[i].cdev);
		cancel_work_sync(&qt2160->leds[i].work);
	}
}

#else
+2 −2
Original line number Diff line number Diff line
@@ -153,6 +153,8 @@ static int keyscan_probe(struct platform_device *pdev)

	input_dev->id.bustype = BUS_HOST;

	keypad_data->input_dev = input_dev;

	error = keypad_matrix_key_parse_dt(keypad_data);
	if (error)
		return error;
@@ -168,8 +170,6 @@ static int keyscan_probe(struct platform_device *pdev)

	input_set_drvdata(input_dev, keypad_data);

	keypad_data->input_dev = input_dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(keypad_data->base))
Loading