linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] input: pwm-beeper: add feature to set volume via sysfs
@ 2016-04-07 15:58 Schrempf Frieder
  2016-04-11 15:21 ` Rob Herring
  0 siblings, 1 reply; 35+ messages in thread
From: Schrempf Frieder @ 2016-04-07 15:58 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: robh+dt, pawel.moll, ijc+devicetree, galak, Schrempf Frieder,
	luis, linux-input, devicetree, linux-kernel

Make the driver accept different volume levels via sysfs.
This can be helpful if the beep/bell sound intensity needs
to be adapted to the environment of the device.

The number of volume levels available and their values can
be specified via device tree (similar to pwm-backlight).

This patch was tested with linux-imx 3.10.17 and was
applied to current mainline without any changes.

Signed-off-by: Frieder Schrempf <frieder.schrempf@exceet.de>
---
 .../devicetree/bindings/input/pwm-beeper.txt    |  20 ++++
 drivers/input/misc/pwm-beeper.c                 | 109 ++++++++++++++++++-
 2 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
index be332ae..153cd3f 100644
--- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
+++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt
@@ -5,3 +5,23 @@ Registers a PWM device as beeper.
 Required properties:
 - compatible: should be "pwm-beeper"
 - pwms: phandle to the physical PWM device
+- volume-levels: Array of distinct volume levels. These need to be in the
+      range of 0 to 500, while 0 means 0% duty cycle (mute) and 500 means
+      50% duty cycle (max volume).
+      Please note that the actual volume of most beepers is highly
+      non-linear, which means that low volume levels are probably somewhere
+      in the range of 1 to 30 (0.1-3% duty cycle).
+- default-volume-level: the default volume level (index into the
+      array defined by the "volume-levels" property)
+
+The volume level can be set via sysfs under /sys/class/input/inputX/volume.
+The maximum volume level index can be read from /sys/class/input/inputX/max_volume_level.
+
+Example:
+
+	pwm-beeper {
+		compatible = "pwm-beeper";
+		pwms = <&pwm4 0 5000>;
+		volume-levels = <0 8 20 40 500>;
+		default-volume-level = <4>;
+	};
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index f2261ab..f3eb8f8 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -1,5 +1,9 @@
 /*
  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  Copyright (C) 2016, Frieder Schrempf <frieder.schrempf@exceet.de>
+ *  (volume support)
+ *
  *  PWM beeper driver
  *
  *  This program is free software; you can redistribute it and/or modify it
@@ -25,10 +29,69 @@ struct pwm_beeper {
 	struct input_dev *input;
 	struct pwm_device *pwm;
 	unsigned long period;
+	unsigned int volume;
+	unsigned int *volume_levels;
+	unsigned int max_volume_level;
 };
 
 #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
 
+static ssize_t beeper_show_volume(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", beeper->volume);
+}
+
+static ssize_t beeper_show_max_volume_level(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", beeper->max_volume_level);
+}
+
+static ssize_t beeper_store_volume(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc;
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+	unsigned int volume;
+
+	rc = kstrtouint(buf, 0, &volume);
+	if (rc)
+		return rc;
+
+	rc = -ENXIO;
+	if (volume > beeper->max_volume_level)
+		volume = beeper->max_volume_level;
+	pr_debug("set volume to %u\n", volume);
+	if (beeper->volume != volume)
+		beeper->volume = volume;
+	rc = count;
+
+	return rc;
+}
+
+static DEVICE_ATTR(volume, 0644, beeper_show_volume, beeper_store_volume);
+static DEVICE_ATTR(max_volume_level, 0644, beeper_show_max_volume_level, NULL);
+
+static struct attribute *bp_device_attributes[] = {
+	&dev_attr_volume.attr,
+	&dev_attr_max_volume_level.attr,
+	NULL,
+};
+
+static struct attribute_group bp_device_attr_group = {
+	.attrs = bp_device_attributes,
+};
+
+static const struct attribute_group *bp_device_attr_groups[] = {
+	&bp_device_attr_group,
+	NULL,
+};
+
 static int pwm_beeper_event(struct input_dev *input,
 			    unsigned int type, unsigned int code, int value)
 {
@@ -53,7 +116,9 @@ static int pwm_beeper_event(struct input_dev *input,
 		pwm_disable(beeper->pwm);
 	} else {
 		period = HZ_TO_NANOSECONDS(value);
-		ret = pwm_config(beeper->pwm, period / 2, period);
+		ret = pwm_config(beeper->pwm,
+			period / 1000 * beeper->volume_levels[beeper->volume],
+			period);
 		if (ret)
 			return ret;
 		ret = pwm_enable(beeper->pwm);
@@ -68,8 +133,11 @@ static int pwm_beeper_event(struct input_dev *input,
 static int pwm_beeper_probe(struct platform_device *pdev)
 {
 	unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
 	struct pwm_beeper *beeper;
-	int error;
+	struct property *prop;
+	int error, length;
+	u32 value;
 
 	beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
 	if (!beeper)
@@ -87,6 +155,36 @@ static int pwm_beeper_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
+	/* determine the number of volume levels */
+	prop = of_find_property(np, "volume-levels", &length);
+	if (!prop)
+		return -EINVAL;
+
+	beeper->max_volume_level = length / sizeof(u32);
+
+	/* read volume levels from DT property */
+	if (beeper->max_volume_level > 0) {
+		size_t size = sizeof(*beeper->volume_levels) *
+			beeper->max_volume_level;
+
+		beeper->volume_levels = devm_kzalloc(&(pdev->dev), size,
+			GFP_KERNEL);
+		if (!beeper->volume_levels)
+			return -ENOMEM;
+
+		error = of_property_read_u32_array(np, "volume-levels",
+						 beeper->volume_levels,
+						 beeper->max_volume_level);
+
+		error = of_property_read_u32(np, "default-volume-level",
+					   &value);
+		if (error < 0)
+			return error;
+
+		beeper->volume = value;
+		beeper->max_volume_level--;
+	}
+
 	beeper->input = input_allocate_device();
 	if (!beeper->input) {
 		dev_err(&pdev->dev, "Failed to allocate input device\n");
@@ -109,6 +207,8 @@ static int pwm_beeper_probe(struct platform_device *pdev)
 
 	input_set_drvdata(beeper->input, beeper);
 
+	beeper->input->dev.groups = bp_device_attr_groups;
+
 	error = input_register_device(beeper->input);
 	if (error) {
 		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
@@ -158,7 +258,10 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
 	struct pwm_beeper *beeper = dev_get_drvdata(dev);
 
 	if (beeper->period) {
-		pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+		pwm_config(beeper->pwm,
+			beeper->period / 1000 *
+			beeper->volume_levels[beeper->volume],
+			beeper->period);
 		pwm_enable(beeper->pwm);
 	}
 
-- 
1.9.1

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

end of thread, other threads:[~2017-02-17 10:01 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-07 15:58 [PATCH 1/1] input: pwm-beeper: add feature to set volume via sysfs Schrempf Frieder
2016-04-11 15:21 ` Rob Herring
2016-10-07  9:00   ` Schrempf Frieder
2016-10-07  9:08     ` [PATCH v2 0/3] input: pwm-beeper: add feature to set volume level Schrempf Frieder
2016-10-07  9:08       ` [PATCH v2 1/3] input: pwm-beeper: add feature to set volume via sysfs Schrempf Frieder
2016-10-07  9:08       ` [PATCH v2 2/3] input: pwm-beeper: add documentation for volume devicetree bindings Schrempf Frieder
2016-10-10 15:20         ` Rob Herring
2016-10-11  8:17           ` Schrempf Frieder
2016-10-11 13:39             ` Rob Herring
2017-01-19 14:40               ` Frieder Schrempf
2017-01-19 15:24                 ` [PATCH v3 0/3] input: pwm-beeper: add feature to set volume level Frieder Schrempf
2017-01-19 15:24                   ` [PATCH v3 1/3] input: pwm-beeper: add feature to set volume via sysfs Frieder Schrempf
2017-01-19 21:29                     ` Dmitry Torokhov
2017-02-16 20:37                       ` Frieder Schrempf
2017-01-19 15:24                   ` [PATCH v3 2/3] input: pwm-beeper: add documentation for volume devicetree bindings Frieder Schrempf
2017-01-23 14:40                     ` Rob Herring
2017-01-19 15:24                   ` [PATCH v3 3/3] input: pwm-beeper: add devicetree bindings to set volume levels Frieder Schrempf
2017-01-19 21:30                     ` Dmitry Torokhov
2017-02-16 20:40                       ` Frieder Schrempf
2017-01-19 21:37                   ` [PATCH v3 0/3] input: pwm-beeper: add feature to set volume level Dmitry Torokhov
2017-01-20 19:11                     ` David Lechner
2017-02-16 21:15                       ` Frieder Schrempf
2017-02-16 21:44                         ` David Lechner
2017-02-17 10:01                           ` Frieder Schrempf
2017-02-16 21:08                   ` [PATCH v4 " Frieder Schrempf
2017-02-16 21:08                     ` [PATCH v4 1/3] input: pwm-beeper: add feature to set volume via sysfs Frieder Schrempf
2017-02-16 21:08                     ` [PATCH v4 2/3] input: pwm-beeper: add documentation for volume devicetree bindings Frieder Schrempf
2017-02-16 21:08                     ` [PATCH v4 3/3] input: pwm-beeper: add devicetree bindings to set volume levels Frieder Schrempf
2017-02-16 23:07                       ` kbuild test robot
2017-02-17  0:14                       ` kbuild test robot
2017-02-17  9:54                     ` [PATCH v5 0/3] input: pwm-beeper: add feature to set volume level Frieder Schrempf
2017-02-17  9:54                       ` [PATCH v5 1/3] input: pwm-beeper: add feature to set volume via sysfs Frieder Schrempf
2017-02-17  9:54                       ` [PATCH v5 2/3] input: pwm-beeper: add documentation for volume devicetree bindings Frieder Schrempf
2017-02-17  9:54                       ` [PATCH v5 3/3] input: pwm-beeper: add devicetree bindings to set volume levels Frieder Schrempf
2016-10-07  9:08       ` [PATCH v2 " Schrempf Frieder

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).