2016-04-07 16:04:20

by Frieder Schrempf

[permalink] [raw]
Subject: [PATCH 1/1] input: pwm-beeper: add feature to set volume via sysfs

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 <[email protected]>
---
.../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 <[email protected]>
+ *
+ * Copyright (C) 2016, Frieder Schrempf <[email protected]>
+ * (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


2016-04-11 15:22:02

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 1/1] input: pwm-beeper: add feature to set volume via sysfs

On Thu, Apr 07, 2016 at 03:58:40PM +0000, Schrempf Frieder wrote:
> 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.

It is preferred that bindings be a separate patch. Also, this is 2
independent features: the sysfs interface and DT properties. So that is
probably 3 patches.

Also, sysfs interfaces are supposed to be documented.

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

You need to test with something not 3 years old...

>
> Signed-off-by: Frieder Schrempf <[email protected]>
> ---
> .../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).

Where does the scale of 0-500 come from? It is tenth of a percent?

How many array entries?

> + 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>;
> + };

2016-10-07 09:07:41

by Frieder Schrempf

[permalink] [raw]
Subject: Re: [PATCH 1/1] input: pwm-beeper: add feature to set volume via sysfs

Thank you Rob for looking at my first kernel contribution.
I come back to it now, as I had some time to process your comments.

On 11.04.2016 17:21, Rob Herring wrote:
> On Thu, Apr 07, 2016 at 03:58:40PM +0000, Schrempf Frieder wrote:
>> 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.
>
> It is preferred that bindings be a separate patch. Also, this is 2
> independent features: the sysfs interface and DT properties. So that is
> probably 3 patches.
>
> Also, sysfs interfaces are supposed to be documented.

I have splitted this into 3 patches and will send them soon as v2.
I also added documentation for the sysfs interface.

>
>>
>> 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.
>
> You need to test with something not 3 years old...

I tested the v2 patches with Linux 4.7.4 now.

>
>>
>> Signed-off-by: Frieder Schrempf <[email protected]>
>> ---
>> .../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).
>
> Where does the scale of 0-500 come from? It is tenth of a percent?

I used tenth of a percent because this is needed to define low volume
levels with pwm duty cycles in the range of <1%.
This is necessary because of the highly non-linear relation between duty
cycle and actual perceived volume.

The upper limit of 500 therefore results from 50% being the duty cycle
with maximum volume.

>
> How many array entries?

The array size and therefore the number of volume levels is dynamic and
only defined by the number of entries in the volume-levels property.

>
>> + 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>;
>> + };

2016-10-07 09:08:21

by Frieder Schrempf

[permalink] [raw]
Subject: [PATCH v2 0/3] input: pwm-beeper: add feature to set volume level

Make the driver accept switching 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).

The volume adjustment is done by changing the duty cycle of
the pwm signal.

Changes in v2:
- split into 3 separate patches
- make volume devicetree properties optional
- tested with Linux 4.7.4

Frieder Schrempf (3):
input: pwm-beeper: add feature to set volume via sysfs
input: pwm-beeper: add documentation for volume devicetree bindings
input: pwm-beeper: add devicetree bindings to set volume levels

.../ABI/testing/sysfs-class-input-pwm-beeper | 17 +++
.../devicetree/bindings/input/pwm-beeper.txt | 22 ++++
drivers/input/misc/pwm-beeper.c | 118 ++++++++++++++++++++-
3 files changed, 155 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-input-pwm-beeper

--
1.9.1

2016-10-07 09:08:32

by Frieder Schrempf

[permalink] [raw]
Subject: [PATCH v2 1/3] input: pwm-beeper: add feature to set volume via sysfs

Make the driver accept switching 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 volume adjustment is done by changing the duty cycle of
the pwm signal.

This patch adds the sysfs interface with 5 default volume
levels (0 - mute, 4 - max. volume).

Signed-off-by: Frieder Schrempf <[email protected]>
---
Changes in v2:
- split into 3 separate patches

.../ABI/testing/sysfs-class-input-pwm-beeper | 17 ++++++
drivers/input/misc/pwm-beeper.c | 71 +++++++++++++++++++++-
2 files changed, 87 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-input-pwm-beeper

diff --git a/Documentation/ABI/testing/sysfs-class-input-pwm-beeper b/Documentation/ABI/testing/sysfs-class-input-pwm-beeper
new file mode 100644
index 0000000..bcf8d8b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-input-pwm-beeper
@@ -0,0 +1,17 @@
+What: /sys/class/input/input(x)/volume
+Date: April 2016
+KernelVersion:
+Contact: Frieder Schrempf <[email protected]>
+Description:
+ Control the volume of this pwm-beeper. Values
+ are between 0 and max_volume_level. This file will also
+ show the current volume level stored in the driver.
+
+What: /sys/class/input/input(x)/max_volume_level
+Date: April 2016
+KernelVersion:
+Contact: Frieder Schrempf <[email protected]>
+Description:
+ This file shows the maximum volume level that can be
+ assigned to volume.
+
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 5f9655d..3ed21da 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 <[email protected]>
+ *
+ * Copyright (C) 2016, Frieder Schrempf <[email protected]>
+ * (volume support)
+ *
* PWM beeper driver
*
* This program is free software; you can redistribute it and/or modify it
@@ -27,16 +31,77 @@ struct pwm_beeper {
struct pwm_device *pwm;
struct work_struct work;
unsigned long period;
+ unsigned int volume;
+ unsigned int volume_levels[] = {0, 8, 20, 40, 500};
+ 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 void __pwm_beeper_set(struct pwm_beeper *beeper)
{
unsigned long period = beeper->period;

if (period) {
- pwm_config(beeper->pwm, period / 2, period);
+ pwm_config(beeper->pwm,
+ period / 1000 * beeper->volume_levels[beeper->volume],
+ period);
pwm_enable(beeper->pwm);
} else
pwm_disable(beeper->pwm);
@@ -123,6 +188,8 @@ static int pwm_beeper_probe(struct platform_device *pdev)

INIT_WORK(&beeper->work, pwm_beeper_work);

+ beeper->max_volume_level = ARRAY_SIZE(beeper->volume_levels) - 1;
+
beeper->input = input_allocate_device();
if (!beeper->input) {
dev_err(&pdev->dev, "Failed to allocate input device\n");
@@ -146,6 +213,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);
--
1.9.1

2016-10-07 09:08:44

by Frieder Schrempf

[permalink] [raw]
Subject: [PATCH v2 3/3] input: pwm-beeper: add devicetree bindings to set volume levels

This patch adds the devicetree bindings to set the volume levels
and the default volume level.

Signed-off-by: Frieder Schrempf <[email protected]>
---
Changes in v2:
- split into 3 separate patches
- make volume properties optional

drivers/input/misc/pwm-beeper.c | 49 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 3ed21da..a7f9d70 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -32,7 +32,7 @@ struct pwm_beeper {
struct work_struct work;
unsigned long period;
unsigned int volume;
- unsigned int volume_levels[] = {0, 8, 20, 40, 500};
+ unsigned int *volume_levels;
unsigned int max_volume_level;
};

@@ -161,8 +161,11 @@ static void pwm_beeper_close(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)
@@ -188,7 +191,47 @@ static int pwm_beeper_probe(struct platform_device *pdev)

INIT_WORK(&beeper->work, pwm_beeper_work);

- beeper->max_volume_level = ARRAY_SIZE(beeper->volume_levels) - 1;
+ /* determine the number of volume levels */
+ prop = of_find_property(np, "volume-levels", &length);
+ if (!prop) {
+ dev_dbg(&pdev->dev, "no volume levels specified, using max volume\n");
+ beeper->max_volume_level = 1;
+ } else
+ 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;
+
+ if (prop) {
+ error = of_property_read_u32_array(np, "volume-levels",
+ beeper->volume_levels,
+ beeper->max_volume_level);
+
+ if (error < 0)
+ return error;
+
+ error = of_property_read_u32(np, "default-volume-level",
+ &value);
+
+ if (error < 0) {
+ dev_dbg(&pdev->dev, "no default volume specified, using max volume\n");
+ value = beeper->max_volume_level - 1;
+ }
+ } else {
+ beeper->volume_levels[0] = 500;
+ value = 0;
+ }
+
+ beeper->volume = value;
+ beeper->max_volume_level--;
+ }

beeper->input = input_allocate_device();
if (!beeper->input) {
--
1.9.1

2016-10-07 09:08:54

by Frieder Schrempf

[permalink] [raw]
Subject: [PATCH v2 2/3] input: pwm-beeper: add documentation for volume devicetree bindings

This patch adds the documentation for the devicetree bindings to set
the volume levels.

Signed-off-by: Frieder Schrempf <[email protected]>
---
Changes in v2:
- split into 3 separate patches
- make volume properties optional

.../devicetree/bindings/input/pwm-beeper.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
index be332ae..6d8ba4e 100644
--- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
+++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt
@@ -5,3 +5,25 @@ Registers a PWM device as beeper.
Required properties:
- compatible: should be "pwm-beeper"
- pwms: phandle to the physical PWM device
+
+Optional properties:
+- 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>;
+ };
--
1.9.1

2016-10-10 15:38:44

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] input: pwm-beeper: add documentation for volume devicetree bindings

On Fri, Oct 07, 2016 at 09:08:17AM +0000, Schrempf Frieder wrote:
> This patch adds the documentation for the devicetree bindings to set
> the volume levels.
>
> Signed-off-by: Frieder Schrempf <[email protected]>
> ---
> Changes in v2:
> - split into 3 separate patches
> - make volume properties optional
>
> .../devicetree/bindings/input/pwm-beeper.txt | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
> index be332ae..6d8ba4e 100644
> --- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
> +++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt
> @@ -5,3 +5,25 @@ Registers a PWM device as beeper.
> Required properties:
> - compatible: should be "pwm-beeper"
> - pwms: phandle to the physical PWM device
> +
> +Optional properties:
> +- 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).

What does the index correspond to? The linear volume?

> +- 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>;
> + };
> --
> 1.9.1

2016-10-11 08:18:03

by Frieder Schrempf

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] input: pwm-beeper: add documentation for volume devicetree bindings

On 10.10.2016 17:20, Rob Herring wrote:
> On Fri, Oct 07, 2016 at 09:08:17AM +0000, Schrempf Frieder wrote:
>> This patch adds the documentation for the devicetree bindings to set
>> the volume levels.
>>
>> Signed-off-by: Frieder Schrempf <[email protected]>
>> ---
>> Changes in v2:
>> - split into 3 separate patches
>> - make volume properties optional
>>
>> .../devicetree/bindings/input/pwm-beeper.txt | 22 ++++++++++++++++++++++
>> 1 file changed, 22 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
>> index be332ae..6d8ba4e 100644
>> --- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
>> +++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt
>> @@ -5,3 +5,25 @@ Registers a PWM device as beeper.
>> Required properties:
>> - compatible: should be "pwm-beeper"
>> - pwms: phandle to the physical PWM device
>> +
>> +Optional properties:
>> +- 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).
>
> What does the index correspond to? The linear volume?

In most cases users probably need linear volume levels (e.g. 0%, 25%,
50%, 75%, 100%) and in this case the index would indeed correspond to
the linear perceived volume.

But also non-linear relations are possible (e.g. 0%, 20%, 100%), if the
user needs for example "mute", "low", "high" as volume levels.

The linearization (defining the corresponding duty cycle for each index)
depends on the beeper and the perception of the user.

For the example array definition below, I tried different duty cycles
and found values of 0.8%, 2%, 4%, 50% to be approximately correspondent
to perceived volume levels of 25%, 50%, 75%, 100% in my case.

>
>> +- 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>;
>> + };
>> --
>> 1.9.1

2016-10-11 13:40:26

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] input: pwm-beeper: add documentation for volume devicetree bindings

On Tue, Oct 11, 2016 at 3:17 AM, Schrempf Frieder
<[email protected]> wrote:
> On 10.10.2016 17:20, Rob Herring wrote:
>> On Fri, Oct 07, 2016 at 09:08:17AM +0000, Schrempf Frieder wrote:
>>> This patch adds the documentation for the devicetree bindings to set
>>> the volume levels.
>>>
>>> Signed-off-by: Frieder Schrempf <[email protected]>
>>> ---
>>> Changes in v2:
>>> - split into 3 separate patches
>>> - make volume properties optional
>>>
>>> .../devicetree/bindings/input/pwm-beeper.txt | 22 ++++++++++++++++++++++
>>> 1 file changed, 22 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
>>> index be332ae..6d8ba4e 100644
>>> --- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
>>> +++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt
>>> @@ -5,3 +5,25 @@ Registers a PWM device as beeper.
>>> Required properties:
>>> - compatible: should be "pwm-beeper"
>>> - pwms: phandle to the physical PWM device
>>> +
>>> +Optional properties:
>>> +- 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).
>>
>> What does the index correspond to? The linear volume?
>
> In most cases users probably need linear volume levels (e.g. 0%, 25%,
> 50%, 75%, 100%) and in this case the index would indeed correspond to
> the linear perceived volume.
>
> But also non-linear relations are possible (e.g. 0%, 20%, 100%), if the
> user needs for example "mute", "low", "high" as volume levels.

Exclude off/mute and this is still linear. Also, the user exposed
levels could be a subset of the defined h/w levels. That should be
independent of DT.

> The linearization (defining the corresponding duty cycle for each index)
> depends on the beeper and the perception of the user.

This has to be a consistent interface across h/w to have a userspace
that can work across h/w. For that, you have to define the binding as
linear. Of course, it's all measured by perception and not completely
accurate which is fine.

> For the example array definition below, I tried different duty cycles
> and found values of 0.8%, 2%, 4%, 50% to be approximately correspondent
> to perceived volume levels of 25%, 50%, 75%, 100% in my case.
>
>>
>>> +- 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.

Also, drop this. Not relevant to the binding.

Rob