linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv4 0/3] PWM Vibrator driver
@ 2017-07-14 10:01 Sebastian Reichel
  2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Sebastian Reichel @ 2017-07-14 10:01 UTC (permalink / raw)
  To: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren
  Cc: Rob Herring, linux-input, linux-omap, devicetree, linux-kernel,
	Sebastian Reichel

Hi,

The Motorola Droid 4 has a vibrator, that is connected
to two GPIOs. Motorola's stock kernel names them vib_en
and vib_dir, which probably stand for vibrator_enable
and vibrator_direction. In their stock kernel both GPIOs
are toggled using a hrtimer and a custom vibrator "misc"
device is provided to userspace.

Thankfully the hardware designers the used GPIOs can
also be used from OMAP's dmtimers, so that they can
be driven as PWM output instead saving some CPU cycles
(and code).

The driver is loosely based on an old patch from Dmitry,
that I found in the internet(tm) [0]. Since PATCHv4 the
Droid 4 also uses the generic PWM compatible and the
one specific to Motorola has been dropped.

Also I wrote a small tool to test the vibrator running
at different strength levels, since fftest(1) used a
fixed one.

Changes since PATCHv3:
 * Fix kernel doc comment
 * Use switch for error handling of direction pwm
 * Drop spin_lock_irqsave in suspend/resume handler
 * Drop Droid 4 specific code & binding
 * Add direction-duty-cycle-ns DT property
 * Dropped Tested-by due to restructuring
Changes since PATCHv2:
 * Add Kconfig dependency on INPUT_FF_MEMLESS
 * Add Tested-by from Tiny Lindgren
Changes since PATCHv1:
 * move driver removal code to input->close function
 * mark PM functions __maybe_unused and drop #ifdef CONFIG_PM_SLEEP
 * remove duplicate NULL check for vibrator in probe function
 * cancel work in suspend function

[0] https://lkml.org/lkml/2012/4/10/41
[1] https://git.collabora.com/cgit/user/sre/rumble-test.git/plain/rumble-test.c

-- Sebastian

Sebastian Reichel (3):
  dt-bindings: input: add pwm-vibrator
  Input: pwm-vibra: new driver
  ARM: dts: omap4-droid4: Add vibrator

 .../devicetree/bindings/input/pwm-vibrator.txt     |  66 +++++
 arch/arm/boot/dts/omap4-droid4-xt894.dts           |  40 +++
 drivers/input/misc/Kconfig                         |  12 +
 drivers/input/misc/Makefile                        |   1 +
 drivers/input/misc/pwm-vibra.c                     | 267 +++++++++++++++++++++
 5 files changed, 386 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/pwm-vibrator.txt
 create mode 100644 drivers/input/misc/pwm-vibra.c

-- 
2.13.2

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator
  2017-07-14 10:01 [PATCHv4 0/3] PWM Vibrator driver Sebastian Reichel
@ 2017-07-14 10:01 ` Sebastian Reichel
  2017-07-17 18:54   ` Rob Herring
  2017-07-24 19:20   ` Pavel Machek
  2017-07-14 10:01 ` [PATCHv4 2/3] Input: pwm-vibra: new driver Sebastian Reichel
  2017-07-14 10:01 ` [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator Sebastian Reichel
  2 siblings, 2 replies; 9+ messages in thread
From: Sebastian Reichel @ 2017-07-14 10:01 UTC (permalink / raw)
  To: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren
  Cc: Rob Herring, linux-input, linux-omap, devicetree, linux-kernel,
	Sebastian Reichel

Add DT binding document for PWM controlled vibrator devices.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 .../devicetree/bindings/input/pwm-vibrator.txt     | 66 ++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/pwm-vibrator.txt

diff --git a/Documentation/devicetree/bindings/input/pwm-vibrator.txt b/Documentation/devicetree/bindings/input/pwm-vibrator.txt
new file mode 100644
index 000000000000..09145d18491d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/pwm-vibrator.txt
@@ -0,0 +1,66 @@
+* PWM vibrator device tree bindings
+
+Registers a PWM device as vibrator. It is expected, that the vibrator's
+strength increases based on the duty cycle of the enable PWM channel
+(100% duty cycle meaning strongest vibration, 0% meaning no vibration).
+
+The binding supports an optional direction PWM channel, that can be
+driven at fixed duty cycle. If available this is can be used to increase
+the vibration effect of some devices.
+
+Required properties:
+- compatible: should contain "pwm-vibrator"
+- pwm-names: Should contain "enable" and optionally "direction"
+- pwms: Should contain a PWM handle for each entry in pwm-names
+
+Optional properties:
+- vcc-supply: Phandle for the regulator supplying power
+- direction-duty-cycle-ns: Duty cycle of the direction PWM channel in
+                           nanoseconds, defaults to 50% of the channel's
+			   period.
+
+Example from Motorola Droid 4:
+
+&omap4_pmx_core {
+	vibrator_direction_pin: pinmux_vibrator_direction_pin {
+		pinctrl-single,pins = <
+		OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */
+		>;
+	};
+
+	vibrator_enable_pin: pinmux_vibrator_enable_pin {
+		pinctrl-single,pins = <
+		OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */
+		>;
+	};
+};
+
+/ {
+	pwm8: dmtimer-pwm {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vibrator_direction_pin>;
+
+		compatible = "ti,omap-dmtimer-pwm";
+		#pwm-cells = <3>;
+		ti,timers = <&timer8>;
+		ti,clock-source = <0x01>;
+	};
+
+	pwm9: dmtimer-pwm {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vibrator_enable_pin>;
+
+		compatible = "ti,omap-dmtimer-pwm";
+		#pwm-cells = <3>;
+		ti,timers = <&timer9>;
+		ti,clock-source = <0x01>;
+	};
+
+	vibrator {
+		compatible = "pwm-vibrator";
+		pwms = <&pwm8 0 1000000000 0>,
+		       <&pwm9 0 1000000000 0>;
+		pwm-names = "enable", "direction";
+		direction-duty-cycle-ns = <1000000000>;
+	};
+};
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCHv4 2/3] Input: pwm-vibra: new driver
  2017-07-14 10:01 [PATCHv4 0/3] PWM Vibrator driver Sebastian Reichel
  2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
@ 2017-07-14 10:01 ` Sebastian Reichel
  2017-09-04 19:16   ` Dmitry Torokhov
  2017-07-14 10:01 ` [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator Sebastian Reichel
  2 siblings, 1 reply; 9+ messages in thread
From: Sebastian Reichel @ 2017-07-14 10:01 UTC (permalink / raw)
  To: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren
  Cc: Rob Herring, linux-input, linux-omap, devicetree, linux-kernel,
	Sebastian Reichel

Provide a simple driver for PWM controllable vibrators.
It will be used by Motorola Droid 4.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 drivers/input/misc/Kconfig     |  12 ++
 drivers/input/misc/Makefile    |   1 +
 drivers/input/misc/pwm-vibra.c | 267 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 280 insertions(+)
 create mode 100644 drivers/input/misc/pwm-vibra.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 3872488c3fd7..7bb7285c4722 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -581,6 +581,18 @@ config INPUT_PWM_BEEPER
 	  To compile this driver as a module, choose M here: the module will be
 	  called pwm-beeper.
 
+config INPUT_PWM_VIBRA
+	tristate "PWM vibrator support"
+	depends on PWM
+	depends on INPUT_FF_MEMLESS
+	help
+	  Say Y here to get support for PWM based vibrator devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called pwm-vibra.
+
 config INPUT_GPIO_ROTARY_ENCODER
 	tristate "Rotary encoders connected to GPIO pins"
 	depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b923a9828c88..36ea14997b40 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR)	+= pm8xxx-vibrator.o
 obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
+obj-$(CONFIG_INPUT_PWM_VIBRA)		+= pwm-vibra.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)	+= regulator-haptic.o
 obj-$(CONFIG_INPUT_RETU_PWRBUTTON)	+= retu-pwrbutton.o
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
new file mode 100644
index 000000000000..55da191ae550
--- /dev/null
+++ b/drivers/input/misc/pwm-vibra.c
@@ -0,0 +1,267 @@
+/*
+ *  PWM vibrator driver
+ *
+ *  Copyright (C) 2017 Collabora Ltd.
+ *
+ *  Based on previous work from:
+ *  Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ *
+ *  Based on PWM beeper driver:
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct pwm_vibrator {
+	struct input_dev *input;
+	struct pwm_device *pwm;
+	struct pwm_device *pwm_dir;
+	struct regulator *vcc;
+
+	struct work_struct play_work;
+	u16 level;
+	u32 direction_duty_cycle;
+};
+
+static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
+{
+	struct device *pdev = vibrator->input->dev.parent;
+	struct pwm_state state;
+	int err;
+
+	err = regulator_enable(vibrator->vcc);
+	if (err) {
+		dev_err(pdev, "failed to enable regulator: %d", err);
+		return err;
+	}
+
+	pwm_get_state(vibrator->pwm, &state);
+	pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
+	state.enabled = true;
+
+	err = pwm_apply_state(vibrator->pwm, &state);
+	if (err) {
+		dev_err(pdev, "failed to apply pwm state: %d", err);
+		return err;
+	}
+
+	if (vibrator->pwm_dir) {
+		pwm_get_state(vibrator->pwm_dir, &state);
+		state.duty_cycle = vibrator->direction_duty_cycle;
+		state.enabled = true;
+
+		err = pwm_apply_state(vibrator->pwm_dir, &state);
+		if (err) {
+			dev_err(pdev, "failed to apply dir-pwm state: %d", err);
+			pwm_disable(vibrator->pwm);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
+{
+	regulator_disable(vibrator->vcc);
+
+	if (vibrator->pwm_dir)
+		pwm_disable(vibrator->pwm_dir);
+	pwm_disable(vibrator->pwm);
+}
+
+static void pwm_vibrator_play_work(struct work_struct *work)
+{
+	struct pwm_vibrator *vibrator = container_of(work,
+					struct pwm_vibrator, play_work);
+
+	if (vibrator->level)
+		pwm_vibrator_start(vibrator);
+	else
+		pwm_vibrator_stop(vibrator);
+}
+
+static int pwm_vibrator_play_effect(struct input_dev *dev, void *data,
+				    struct ff_effect *effect)
+{
+	struct pwm_vibrator *vibrator = input_get_drvdata(dev);
+
+	vibrator->level = effect->u.rumble.strong_magnitude;
+	if (!vibrator->level)
+		vibrator->level = effect->u.rumble.weak_magnitude;
+
+	schedule_work(&vibrator->play_work);
+
+	return 0;
+}
+
+static void pwm_vibrator_close(struct input_dev *input)
+{
+	struct pwm_vibrator *vibrator = input_get_drvdata(input);
+
+	cancel_work_sync(&vibrator->play_work);
+	pwm_vibrator_stop(vibrator);
+}
+
+static int pwm_vibrator_probe(struct platform_device *pdev)
+{
+	struct pwm_vibrator *vibrator;
+	struct pwm_state state;
+	int err;
+
+	vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+	if (!vibrator)
+		return -ENOMEM;
+
+	vibrator->input = devm_input_allocate_device(&pdev->dev);
+	if (!vibrator->input)
+		return -ENOMEM;
+
+	vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+	err = PTR_ERR_OR_ZERO(vibrator->vcc);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request regulator: %d",
+				err);
+		return err;
+	}
+
+	vibrator->pwm = devm_pwm_get(&pdev->dev, "enable");
+	err = PTR_ERR_OR_ZERO(vibrator->pwm);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request main pwm: %d",
+				err);
+		return err;
+	}
+
+	INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work);
+
+	/* Sync up PWM state and ensure it is off. */
+	pwm_init_state(vibrator->pwm, &state);
+	state.enabled = false;
+	err = pwm_apply_state(vibrator->pwm, &state);
+	if (err) {
+		dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+			err);
+		return err;
+	}
+
+	vibrator->pwm_dir = devm_pwm_get(&pdev->dev, "direction");
+	err = PTR_ERR_OR_ZERO(vibrator->pwm_dir);
+	switch (err) {
+	case 0:
+		/* Sync up PWM state and ensure it is off. */
+		pwm_init_state(vibrator->pwm_dir, &state);
+		state.enabled = false;
+		err = pwm_apply_state(vibrator->pwm_dir, &state);
+		if (err) {
+			dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+				err);
+			return err;
+		}
+
+		vibrator->direction_duty_cycle =
+			pwm_get_period(vibrator->pwm_dir) / 2;
+		device_property_read_u32(&pdev->dev, "direction-duty-cycle-ns",
+					 &vibrator->direction_duty_cycle);
+		break;
+
+	case -ENODATA:
+		/* Direction PWM is optional */
+		vibrator->pwm_dir = NULL;
+		break;
+
+	default:
+		dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
+		/* Fall through */
+
+	case -EPROBE_DEFER:
+		return err;
+	}
+
+	vibrator->input->name = "pwm-vibrator";
+	vibrator->input->id.bustype = BUS_HOST;
+	vibrator->input->dev.parent = &pdev->dev;
+	vibrator->input->close = pwm_vibrator_close;
+
+	input_set_drvdata(vibrator->input, vibrator);
+	input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+	err = input_ff_create_memless(vibrator->input, NULL,
+				      pwm_vibrator_play_effect);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
+		return err;
+	}
+
+	err = input_register_device(vibrator->input);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
+{
+	struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
+
+	cancel_work_sync(&vibrator->play_work);
+	if (vibrator->level)
+		pwm_vibrator_stop(vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused pwm_vibrator_resume(struct device *dev)
+{
+	struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
+
+	if (vibrator->level)
+		pwm_vibrator_start(vibrator);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
+			 pwm_vibrator_suspend, pwm_vibrator_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pwm_vibra_dt_match_table[] = {
+	{ .compatible = "pwm-vibrator" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pwm_vibra_dt_match_table);
+#endif
+
+static struct platform_driver pwm_vibrator_driver = {
+	.probe	= pwm_vibrator_probe,
+	.driver	= {
+		.name	= "pwm-vibrator",
+		.pm	= &pwm_vibrator_pm_ops,
+		.of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
+	},
+};
+module_platform_driver(pwm_vibrator_driver);
+
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_DESCRIPTION("PWM vibrator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-vibrator");
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator
  2017-07-14 10:01 [PATCHv4 0/3] PWM Vibrator driver Sebastian Reichel
  2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
  2017-07-14 10:01 ` [PATCHv4 2/3] Input: pwm-vibra: new driver Sebastian Reichel
@ 2017-07-14 10:01 ` Sebastian Reichel
  2017-08-10 16:48   ` Tony Lindgren
  2 siblings, 1 reply; 9+ messages in thread
From: Sebastian Reichel @ 2017-07-14 10:01 UTC (permalink / raw)
  To: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren
  Cc: Rob Herring, linux-input, linux-omap, devicetree, linux-kernel,
	Sebastian Reichel

Add vibrator to Droid4's device tree.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 arch/arm/boot/dts/omap4-droid4-xt894.dts | 40 ++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts
index a182f9fb1c7a..25c0f81e9628 100644
--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts
+++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts
@@ -136,6 +136,34 @@
 
 		dais = <&mcbsp2_port>, <&mcbsp3_port>;
 	};
+
+	pwm8: dmtimer-pwm-8 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vibrator_direction_pin>;
+
+		compatible = "ti,omap-dmtimer-pwm";
+		#pwm-cells = <3>;
+		ti,timers = <&timer8>;
+		ti,clock-source = <0x01>;
+	};
+
+	pwm9: dmtimer-pwm-9 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vibrator_enable_pin>;
+
+		compatible = "ti,omap-dmtimer-pwm";
+		#pwm-cells = <3>;
+		ti,timers = <&timer9>;
+		ti,clock-source = <0x01>;
+	};
+
+	vibrator {
+		compatible = "pwm-vibrator";
+		pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>;
+		pwm-names = "enable", "direction";
+		direction-duty-cycle-ns = <10000000>;
+	};
+
 };
 
 &dss {
@@ -517,6 +545,18 @@
 		OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1)	/* abe_mcbsp3_fsx */
 		>;
 	};
+
+	vibrator_direction_pin: pinmux_vibrator_direction_pin {
+		pinctrl-single,pins = <
+		OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1)	/* dmtimer8_pwm_evt (gpio_27) */
+		>;
+	};
+
+	vibrator_enable_pin: pinmux_vibrator_enable_pin {
+		pinctrl-single,pins = <
+		OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1)	/* dmtimer9_pwm_evt (gpio_28) */
+		>;
+	};
 };
 
 &omap4_pmx_wkup {
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator
  2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
@ 2017-07-17 18:54   ` Rob Herring
  2017-07-24 19:20   ` Pavel Machek
  1 sibling, 0 replies; 9+ messages in thread
From: Rob Herring @ 2017-07-17 18:54 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren, linux-input,
	linux-omap, devicetree, linux-kernel

On Fri, Jul 14, 2017 at 12:01:49PM +0200, Sebastian Reichel wrote:
> Add DT binding document for PWM controlled vibrator devices.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
> ---
>  .../devicetree/bindings/input/pwm-vibrator.txt     | 66 ++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/input/pwm-vibrator.txt

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator
  2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
  2017-07-17 18:54   ` Rob Herring
@ 2017-07-24 19:20   ` Pavel Machek
  2017-07-25  8:59     ` Sebastian Reichel
  1 sibling, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2017-07-24 19:20 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Dmitry Torokhov, Tony Lindgren, Rob Herring,
	linux-input, linux-omap, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1688 bytes --]

On Fri 2017-07-14 12:01:49, Sebastian Reichel wrote:
> Add DT binding document for PWM controlled vibrator devices.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Acked-by: Pavel Machek <pavel@ucw.cz>

> index 000000000000..09145d18491d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/pwm-vibrator.txt
> @@ -0,0 +1,66 @@
> +* PWM vibrator device tree bindings
> +
> +Registers a PWM device as vibrator. It is expected, that the vibrator's
> +strength increases based on the duty cycle of the enable PWM channel
> +(100% duty cycle meaning strongest vibration, 0% meaning no vibration).
> +
> +The binding supports an optional direction PWM channel, that can be
> +driven at fixed duty cycle. If available this is can be used to increase
> +the vibration effect of some devices.

Actually what "direction" does would be nice to explain, because I
don't know. Does it make the motor turn the other way around?

> +Required properties:
> +- compatible: should contain "pwm-vibrator"

should->Should.

> +- pwm-names: Should contain "enable" and optionally "direction"
> +- pwms: Should contain a PWM handle for each entry in pwm-names
> +
> +Optional properties:
> +- vcc-supply: Phandle for the regulator supplying power
> +- direction-duty-cycle-ns: Duty cycle of the direction PWM channel in
> +                           nanoseconds, defaults to 50% of the channel's
> +			   period.

Is nanoseconds right unit here? It drives a motor...

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator
  2017-07-24 19:20   ` Pavel Machek
@ 2017-07-25  8:59     ` Sebastian Reichel
  0 siblings, 0 replies; 9+ messages in thread
From: Sebastian Reichel @ 2017-07-25  8:59 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Dmitry Torokhov, Tony Lindgren, Rob Herring, linux-input,
	linux-omap, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2079 bytes --]

Hi,

On Mon, Jul 24, 2017 at 09:20:17PM +0200, Pavel Machek wrote:
> On Fri 2017-07-14 12:01:49, Sebastian Reichel wrote:
> > Add DT binding document for PWM controlled vibrator devices.
> > 
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
> 
> Acked-by: Pavel Machek <pavel@ucw.cz>
> 
> > index 000000000000..09145d18491d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/pwm-vibrator.txt
> > @@ -0,0 +1,66 @@
> > +* PWM vibrator device tree bindings
> > +
> > +Registers a PWM device as vibrator. It is expected, that the vibrator's
> > +strength increases based on the duty cycle of the enable PWM channel
> > +(100% duty cycle meaning strongest vibration, 0% meaning no vibration).
> > +
> > +The binding supports an optional direction PWM channel, that can be
> > +driven at fixed duty cycle. If available this is can be used to increase
> > +the vibration effect of some devices.
> 
> Actually what "direction" does would be nice to explain, because I
> don't know. Does it make the motor turn the other way around?

Yes, at least that's how I understand it. IIUIC this will increase
the imbalance effect and thus the vibration.

> > +Required properties:
> > +- compatible: should contain "pwm-vibrator"
> 
> should->Should.
>
> > +- pwm-names: Should contain "enable" and optionally "direction"
> > +- pwms: Should contain a PWM handle for each entry in pwm-names
> > +
> > +Optional properties:
> > +- vcc-supply: Phandle for the regulator supplying power
> > +- direction-duty-cycle-ns: Duty cycle of the direction PWM channel in
> > +                           nanoseconds, defaults to 50% of the channel's
> > +			   period.
> 
> Is nanoseconds right unit here? It drives a motor...

Yes, for the driving the motor the values will be very big
and we could use milliseconds. But the PWM specifier [0] uses
nanoseconds for the period and I think period and duty cycle
should be described in the same scale.

[0] Documentation/devicetree/bindings/pwm/pwm.txt

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator
  2017-07-14 10:01 ` [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator Sebastian Reichel
@ 2017-08-10 16:48   ` Tony Lindgren
  0 siblings, 0 replies; 9+ messages in thread
From: Tony Lindgren @ 2017-08-10 16:48 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Dmitry Torokhov, Rob Herring, linux-input,
	linux-omap, devicetree, linux-kernel

* Sebastian Reichel <sebastian.reichel@collabora.co.uk> [170714 03:02]:
> Add vibrator to Droid4's device tree.

Since we have Rob's ack for the binding, I'll pick this
patch into omap-for-v4.14/dt thanks.

Tony

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv4 2/3] Input: pwm-vibra: new driver
  2017-07-14 10:01 ` [PATCHv4 2/3] Input: pwm-vibra: new driver Sebastian Reichel
@ 2017-09-04 19:16   ` Dmitry Torokhov
  0 siblings, 0 replies; 9+ messages in thread
From: Dmitry Torokhov @ 2017-09-04 19:16 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sebastian Reichel, Tony Lindgren, Rob Herring, linux-input,
	linux-omap, devicetree, linux-kernel

On Fri, Jul 14, 2017 at 12:01:50PM +0200, Sebastian Reichel wrote:
> Provide a simple driver for PWM controllable vibrators.
> It will be used by Motorola Droid 4.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Applied, thank you.

> ---
>  drivers/input/misc/Kconfig     |  12 ++
>  drivers/input/misc/Makefile    |   1 +
>  drivers/input/misc/pwm-vibra.c | 267 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 280 insertions(+)
>  create mode 100644 drivers/input/misc/pwm-vibra.c
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 3872488c3fd7..7bb7285c4722 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -581,6 +581,18 @@ config INPUT_PWM_BEEPER
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called pwm-beeper.
>  
> +config INPUT_PWM_VIBRA
> +	tristate "PWM vibrator support"
> +	depends on PWM
> +	depends on INPUT_FF_MEMLESS
> +	help
> +	  Say Y here to get support for PWM based vibrator devices.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called pwm-vibra.
> +
>  config INPUT_GPIO_ROTARY_ENCODER
>  	tristate "Rotary encoders connected to GPIO pins"
>  	depends on GPIOLIB || COMPILE_TEST
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index b923a9828c88..36ea14997b40 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -59,6 +59,7 @@ obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR)	+= pm8xxx-vibrator.o
>  obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
>  obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
>  obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
> +obj-$(CONFIG_INPUT_PWM_VIBRA)		+= pwm-vibra.o
>  obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
>  obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)	+= regulator-haptic.o
>  obj-$(CONFIG_INPUT_RETU_PWRBUTTON)	+= retu-pwrbutton.o
> diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
> new file mode 100644
> index 000000000000..55da191ae550
> --- /dev/null
> +++ b/drivers/input/misc/pwm-vibra.c
> @@ -0,0 +1,267 @@
> +/*
> + *  PWM vibrator driver
> + *
> + *  Copyright (C) 2017 Collabora Ltd.
> + *
> + *  Based on previous work from:
> + *  Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
> + *
> + *  Based on PWM beeper driver:
> + *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
> + *
> + *  This program is free software; you can redistribute it and/or modify it
> + *  under  the terms of the GNU General  Public License as published by the
> + *  Free Software Foundation;  either version 2 of the License, or (at your
> + *  option) any later version.
> + */
> +
> +#include <linux/input.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +
> +struct pwm_vibrator {
> +	struct input_dev *input;
> +	struct pwm_device *pwm;
> +	struct pwm_device *pwm_dir;
> +	struct regulator *vcc;
> +
> +	struct work_struct play_work;
> +	u16 level;
> +	u32 direction_duty_cycle;
> +};
> +
> +static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
> +{
> +	struct device *pdev = vibrator->input->dev.parent;
> +	struct pwm_state state;
> +	int err;
> +
> +	err = regulator_enable(vibrator->vcc);
> +	if (err) {
> +		dev_err(pdev, "failed to enable regulator: %d", err);
> +		return err;
> +	}
> +
> +	pwm_get_state(vibrator->pwm, &state);
> +	pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
> +	state.enabled = true;
> +
> +	err = pwm_apply_state(vibrator->pwm, &state);
> +	if (err) {
> +		dev_err(pdev, "failed to apply pwm state: %d", err);
> +		return err;
> +	}
> +
> +	if (vibrator->pwm_dir) {
> +		pwm_get_state(vibrator->pwm_dir, &state);
> +		state.duty_cycle = vibrator->direction_duty_cycle;
> +		state.enabled = true;
> +
> +		err = pwm_apply_state(vibrator->pwm_dir, &state);
> +		if (err) {
> +			dev_err(pdev, "failed to apply dir-pwm state: %d", err);
> +			pwm_disable(vibrator->pwm);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
> +{
> +	regulator_disable(vibrator->vcc);
> +
> +	if (vibrator->pwm_dir)
> +		pwm_disable(vibrator->pwm_dir);
> +	pwm_disable(vibrator->pwm);
> +}
> +
> +static void pwm_vibrator_play_work(struct work_struct *work)
> +{
> +	struct pwm_vibrator *vibrator = container_of(work,
> +					struct pwm_vibrator, play_work);
> +
> +	if (vibrator->level)
> +		pwm_vibrator_start(vibrator);
> +	else
> +		pwm_vibrator_stop(vibrator);
> +}
> +
> +static int pwm_vibrator_play_effect(struct input_dev *dev, void *data,
> +				    struct ff_effect *effect)
> +{
> +	struct pwm_vibrator *vibrator = input_get_drvdata(dev);
> +
> +	vibrator->level = effect->u.rumble.strong_magnitude;
> +	if (!vibrator->level)
> +		vibrator->level = effect->u.rumble.weak_magnitude;
> +
> +	schedule_work(&vibrator->play_work);
> +
> +	return 0;
> +}
> +
> +static void pwm_vibrator_close(struct input_dev *input)
> +{
> +	struct pwm_vibrator *vibrator = input_get_drvdata(input);
> +
> +	cancel_work_sync(&vibrator->play_work);
> +	pwm_vibrator_stop(vibrator);
> +}
> +
> +static int pwm_vibrator_probe(struct platform_device *pdev)
> +{
> +	struct pwm_vibrator *vibrator;
> +	struct pwm_state state;
> +	int err;
> +
> +	vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
> +	if (!vibrator)
> +		return -ENOMEM;
> +
> +	vibrator->input = devm_input_allocate_device(&pdev->dev);
> +	if (!vibrator->input)
> +		return -ENOMEM;
> +
> +	vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
> +	err = PTR_ERR_OR_ZERO(vibrator->vcc);
> +	if (err) {
> +		if (err != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Failed to request regulator: %d",
> +				err);
> +		return err;
> +	}
> +
> +	vibrator->pwm = devm_pwm_get(&pdev->dev, "enable");
> +	err = PTR_ERR_OR_ZERO(vibrator->pwm);
> +	if (err) {
> +		if (err != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Failed to request main pwm: %d",
> +				err);
> +		return err;
> +	}
> +
> +	INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work);
> +
> +	/* Sync up PWM state and ensure it is off. */
> +	pwm_init_state(vibrator->pwm, &state);
> +	state.enabled = false;
> +	err = pwm_apply_state(vibrator->pwm, &state);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
> +			err);
> +		return err;
> +	}
> +
> +	vibrator->pwm_dir = devm_pwm_get(&pdev->dev, "direction");
> +	err = PTR_ERR_OR_ZERO(vibrator->pwm_dir);
> +	switch (err) {
> +	case 0:
> +		/* Sync up PWM state and ensure it is off. */
> +		pwm_init_state(vibrator->pwm_dir, &state);
> +		state.enabled = false;
> +		err = pwm_apply_state(vibrator->pwm_dir, &state);
> +		if (err) {
> +			dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
> +				err);
> +			return err;
> +		}
> +
> +		vibrator->direction_duty_cycle =
> +			pwm_get_period(vibrator->pwm_dir) / 2;
> +		device_property_read_u32(&pdev->dev, "direction-duty-cycle-ns",
> +					 &vibrator->direction_duty_cycle);
> +		break;
> +
> +	case -ENODATA:
> +		/* Direction PWM is optional */
> +		vibrator->pwm_dir = NULL;
> +		break;
> +
> +	default:
> +		dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
> +		/* Fall through */
> +
> +	case -EPROBE_DEFER:
> +		return err;
> +	}
> +
> +	vibrator->input->name = "pwm-vibrator";
> +	vibrator->input->id.bustype = BUS_HOST;
> +	vibrator->input->dev.parent = &pdev->dev;
> +	vibrator->input->close = pwm_vibrator_close;
> +
> +	input_set_drvdata(vibrator->input, vibrator);
> +	input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
> +
> +	err = input_ff_create_memless(vibrator->input, NULL,
> +				      pwm_vibrator_play_effect);
> +	if (err) {
> +		dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
> +		return err;
> +	}
> +
> +	err = input_register_device(vibrator->input);
> +	if (err) {
> +		dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
> +		return err;
> +	}
> +
> +	platform_set_drvdata(pdev, vibrator);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
> +{
> +	struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
> +
> +	cancel_work_sync(&vibrator->play_work);
> +	if (vibrator->level)
> +		pwm_vibrator_stop(vibrator);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused pwm_vibrator_resume(struct device *dev)
> +{
> +	struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
> +
> +	if (vibrator->level)
> +		pwm_vibrator_start(vibrator);
> +
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
> +			 pwm_vibrator_suspend, pwm_vibrator_resume);
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id pwm_vibra_dt_match_table[] = {
> +	{ .compatible = "pwm-vibrator" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, pwm_vibra_dt_match_table);
> +#endif
> +
> +static struct platform_driver pwm_vibrator_driver = {
> +	.probe	= pwm_vibrator_probe,
> +	.driver	= {
> +		.name	= "pwm-vibrator",
> +		.pm	= &pwm_vibrator_pm_ops,
> +		.of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
> +	},
> +};
> +module_platform_driver(pwm_vibrator_driver);
> +
> +MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
> +MODULE_DESCRIPTION("PWM vibrator driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:pwm-vibrator");
> -- 
> 2.13.2
> 

-- 
Dmitry

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-09-04 19:16 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-14 10:01 [PATCHv4 0/3] PWM Vibrator driver Sebastian Reichel
2017-07-14 10:01 ` [PATCHv4 1/3] dt-bindings: input: add pwm-vibrator Sebastian Reichel
2017-07-17 18:54   ` Rob Herring
2017-07-24 19:20   ` Pavel Machek
2017-07-25  8:59     ` Sebastian Reichel
2017-07-14 10:01 ` [PATCHv4 2/3] Input: pwm-vibra: new driver Sebastian Reichel
2017-09-04 19:16   ` Dmitry Torokhov
2017-07-14 10:01 ` [PATCHv4 3/3] ARM: dts: omap4-droid4: Add vibrator Sebastian Reichel
2017-08-10 16:48   ` Tony Lindgren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).