* [RFC 0/2] Input: gpio-beeper: drive output by hrtimer
@ 2017-11-29 11:06 Ladislav Michl
2017-11-29 11:07 ` [PATCH 1/2] Input: gpio-beeper: use helper variable to access device info Ladislav Michl
2017-11-29 11:08 ` [PATCH 2/2] Input: gpio-beeper: drive beeper pin by hrtimer Ladislav Michl
0 siblings, 2 replies; 3+ messages in thread
From: Ladislav Michl @ 2017-11-29 11:06 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov
I have board here, where beeper cannot by driven by PWM as its pin
cannot be muxed there. This is an unfortunate result of evolution
and fixing thousands boards in hardware would be too expensive.
So here we are. I'm not pushing for inclusion to mainline, but
parhaps this could be usefull for others. You decide.
In case you'll find it usefull, I'm ready to solve any objections
and comments.
Ladislav Michl (2):
Input: gpio-beeper: use helper variable to access device info
Input: gpio-beeper: drive beeper pin by hrtimer
Documentation/devicetree/bindings/input/gpio-beeper.txt | 5
drivers/input/misc/gpio-beeper.c | 99 +++++++++++++---
2 files changed, 91 insertions(+), 13 deletions(-)
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] Input: gpio-beeper: use helper variable to access device info
2017-11-29 11:06 [RFC 0/2] Input: gpio-beeper: drive output by hrtimer Ladislav Michl
@ 2017-11-29 11:07 ` Ladislav Michl
2017-11-29 11:08 ` [PATCH 2/2] Input: gpio-beeper: drive beeper pin by hrtimer Ladislav Michl
1 sibling, 0 replies; 3+ messages in thread
From: Ladislav Michl @ 2017-11-29 11:07 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov
Using explicit struct device variable makes code a bit more readable.
Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
Note: and it become more usefull one patch later
drivers/input/misc/gpio-beeper.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c
index 16272fffeb7e..409c85da71c3 100644
--- a/drivers/input/misc/gpio-beeper.c
+++ b/drivers/input/misc/gpio-beeper.c
@@ -64,18 +64,19 @@ static void gpio_beeper_close(struct input_dev *input)
static int gpio_beeper_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct gpio_beeper *beep;
struct input_dev *input;
- beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
+ beep = devm_kzalloc(dev, sizeof(*beep), GFP_KERNEL);
if (!beep)
return -ENOMEM;
- beep->desc = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
+ beep->desc = devm_gpiod_get(dev, NULL, GPIOD_OUT_LOW);
if (IS_ERR(beep->desc))
return PTR_ERR(beep->desc);
- input = devm_input_allocate_device(&pdev->dev);
+ input = devm_input_allocate_device(dev);
if (!input)
return -ENOMEM;
--
2.15.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] Input: gpio-beeper: drive beeper pin by hrtimer
2017-11-29 11:06 [RFC 0/2] Input: gpio-beeper: drive output by hrtimer Ladislav Michl
2017-11-29 11:07 ` [PATCH 1/2] Input: gpio-beeper: use helper variable to access device info Ladislav Michl
@ 2017-11-29 11:08 ` Ladislav Michl
1 sibling, 0 replies; 3+ messages in thread
From: Ladislav Michl @ 2017-11-29 11:08 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov
This is poor man's solution for those who cannot use pwm-beeper.
Beeper pin is driven by hrtimer, so hearable jitter is expected,
but should be acceptable for frequencies under 1kHz. This mode
is enabled by adding 'beeper-hz' node property.
Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
.../devicetree/bindings/input/gpio-beeper.txt | 5 ++
drivers/input/misc/gpio-beeper.c | 92 +++++++++++++++++++---
2 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/gpio-beeper.txt b/Documentation/devicetree/bindings/input/gpio-beeper.txt
index a5086e37fce6..855f8cf8af10 100644
--- a/Documentation/devicetree/bindings/input/gpio-beeper.txt
+++ b/Documentation/devicetree/bindings/input/gpio-beeper.txt
@@ -6,6 +6,11 @@ Required properties:
- compatible: Should be "gpio-beeper".
- gpios: From common gpio binding; gpio connection to beeper enable pin.
+Optional properties:
+- beeper-hz: Bell frequency in Hz. This option enables hrtimer driven beeper
+ pin toggle. This is only good for poorly designed hardware
+ where PWM cannot be used as there always be hearable jitter.
+
Example:
beeper: beeper {
compatible = "gpio-beeper";
diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c
index 409c85da71c3..37f22884e967 100644
--- a/drivers/input/misc/gpio-beeper.c
+++ b/drivers/input/misc/gpio-beeper.c
@@ -12,6 +12,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>
+#include <linux/hrtimer.h>
#include <linux/of.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
@@ -20,11 +21,19 @@
struct gpio_beeper {
struct work_struct work;
+ struct hrtimer timer;
struct gpio_desc *desc;
- bool beeping;
+ ktime_t tick;
+ unsigned int bell_freq;
+ int on;
};
-static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
+static void gpio_beeper_toggle(struct gpio_beeper *beep, int on)
+{
+ gpiod_set_value(beep->desc, on);
+}
+
+static void gpio_beeper_toggle_cansleep(struct gpio_beeper *beep, int on)
{
gpiod_set_value_cansleep(beep->desc, on);
}
@@ -33,7 +42,17 @@ static void gpio_beeper_work(struct work_struct *work)
{
struct gpio_beeper *beep = container_of(work, struct gpio_beeper, work);
- gpio_beeper_toggle(beep, beep->beeping);
+ gpio_beeper_toggle_cansleep(beep, beep->on);
+}
+
+static enum hrtimer_restart gpio_beeper_timer(struct hrtimer *timer)
+{
+ struct gpio_beeper *beep = container_of(timer, struct gpio_beeper, timer);
+
+ beep->on = !beep->on;
+ gpio_beeper_toggle(beep, beep->on);
+ hrtimer_forward_now(timer, beep->tick);
+ return HRTIMER_RESTART;
}
static int gpio_beeper_event(struct input_dev *dev, unsigned int type,
@@ -47,19 +66,59 @@ static int gpio_beeper_event(struct input_dev *dev, unsigned int type,
if (value < 0)
return -EINVAL;
- beep->beeping = value;
+ beep->on = value;
/* Schedule work to actually turn the beeper on or off */
schedule_work(&beep->work);
return 0;
}
+static int gpio_beeper_tone_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ struct gpio_beeper *beep = input_get_drvdata(dev);
+
+ if (type != EV_SND)
+ return -ENOTSUPP;
+
+ switch (code) {
+ case SND_BELL:
+ value = value ? beep->bell_freq : 0;
+ break;
+ case SND_TONE:
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (value < 0)
+ return -EINVAL;
+
+ if (value) {
+ beep->tick = ns_to_ktime(1000000000UL / 2 / value);
+ hrtimer_start(&beep->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
+ } else {
+ hrtimer_cancel(&beep->timer);
+ gpio_beeper_toggle(beep, 0);
+ }
+
+ return 0;
+}
+
static void gpio_beeper_close(struct input_dev *input)
{
struct gpio_beeper *beep = input_get_drvdata(input);
cancel_work_sync(&beep->work);
- gpio_beeper_toggle(beep, false);
+ gpio_beeper_toggle_cansleep(beep, 0);
+}
+
+static void gpio_beeper_tone_close(struct input_dev *input)
+{
+ struct gpio_beeper *beep = input_get_drvdata(input);
+
+ hrtimer_cancel(&beep->timer);
+ gpio_beeper_toggle_cansleep(beep, 0);
}
static int gpio_beeper_probe(struct platform_device *pdev)
@@ -80,18 +139,31 @@ static int gpio_beeper_probe(struct platform_device *pdev)
if (!input)
return -ENOMEM;
- INIT_WORK(&beep->work, gpio_beeper_work);
-
input->name = pdev->name;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
- input->close = gpio_beeper_close;
- input->event = gpio_beeper_event;
-
input_set_capability(input, EV_SND, SND_BELL);
+ if (device_property_read_u32(dev, "beeper-hz", &beep->bell_freq)) {
+ input->close = gpio_beeper_close;
+ input->event = gpio_beeper_event;
+
+ INIT_WORK(&beep->work, gpio_beeper_work);
+ } else {
+ dev_dbg(dev,
+ "tone mode enabled using default frequency: %uHz\n",
+ beep->bell_freq);
+
+ input->close = gpio_beeper_tone_close;
+ input->event = gpio_beeper_tone_event;
+ input_set_capability(input, EV_SND, SND_TONE);
+
+ hrtimer_init(&beep->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ beep->timer.function = gpio_beeper_timer;
+ }
+
input_set_drvdata(input, beep);
return input_register_device(input);
--
2.15.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-11-29 11:08 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-11-29 11:06 [RFC 0/2] Input: gpio-beeper: drive output by hrtimer Ladislav Michl
2017-11-29 11:07 ` [PATCH 1/2] Input: gpio-beeper: use helper variable to access device info Ladislav Michl
2017-11-29 11:08 ` [PATCH 2/2] Input: gpio-beeper: drive beeper pin by hrtimer Ladislav Michl
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).