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 Original line Diff line number Diff line
@@ -420,7 +420,7 @@ config KEYBOARD_MPR121


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


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


#ifdef CONFIG_LEDS_CLASS
#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;
	struct cap11xx_priv *priv = led->priv;
	int value = led->new_brightness;


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


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


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


		INIT_WORK(&led->work, cap11xx_led_work);

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


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


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


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


#ifdef CONFIG_LEDS_CLASS
#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 qt2160_data *qt2160 = led->qt2160;
	struct i2c_client *client = qt2160->client;
	struct i2c_client *client = qt2160->client;
	int value = led->new_brightness;
	u32 drive, pwmen;
	u32 drive, pwmen;


	mutex_lock(&qt2160->led_lock);
	if (value != led->brightness) {

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


		} else {
		} else {
		drive &= ~(1 << led->id);
			drive &= ~BIT(led->id);
		pwmen &= ~(1 << led->id);
			pwmen &= ~BIT(led->id);
		}
		}
		qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
		qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
		qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
		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)
		if (value != LED_OFF)
			qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
			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,
	return 0;
			   enum led_brightness value)
{
	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);

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


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


	mutex_init(&qt2160->led_lock);

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


		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
		led->cdev.name = led->name;
		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->cdev.brightness = LED_OFF;
		led->id = i;
		led->id = i;
		led->qt2160 = qt2160;
		led->qt2160 = qt2160;


		INIT_WORK(&led->work, qt2160_led_work);

		ret = led_classdev_register(&client->dev, &led->cdev);
		ret = led_classdev_register(&client->dev, &led->cdev);
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
@@ -324,10 +311,8 @@ static void qt2160_unregister_leds(struct qt2160_data *qt2160)
{
{
	int i;
	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);
		led_classdev_unregister(&qt2160->leds[i].cdev);
		cancel_work_sync(&qt2160->leds[i].work);
	}
}
}


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


	input_dev->id.bustype = BUS_HOST;
	input_dev->id.bustype = BUS_HOST;


	keypad_data->input_dev = input_dev;

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


	input_set_drvdata(input_dev, keypad_data);
	input_set_drvdata(input_dev, keypad_data);


	keypad_data->input_dev = input_dev;

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