2023-01-30 13:57:16

by Manuel Traut

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

This implements volume control for the pwm-beeper via sysfs.

The first patch changes the devicetree documentation from txt to yaml.

The original author of the volume support patches is Frieder Schrempf.
I picked them from this [0] LKML thread from 2017. Since it looks like
his email address changed in the meantime I changed it in the Author
and Signed-off-by, as well as in the copyright statements.
I did some minor changes on the patches that they apply and work with
the current kernel.

checkpatch still reports warnings regarding the changes:
* from txt to yaml of the devicetree documentation:
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
WARNING: DT binding docs and includes should be a separate patch.
* and the introduction of Documentation/ABI/testing/sysfs-devices-pwm-beeper:
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
I am not sure how to fix these warnings. So any suggestion would be helpful.

Changes since v8 [1]:
* yaml devicetree doc:
* reordered patches to introduce dt-bindings before usage
* drop quotes from $id and $schema references
* amp-supply: simplify description
* examples: remove unneeded amp device node
* use -bp suffix for volume-levels and default-volume
* specify default-volume as value instead of pointer into volume-array

* fixup to work with new dt-binding specification
* squash patches as suggested by Frieder

Changes since v7 [2]:
* yaml devicetree doc:
* Use shorter subject
* Fix indent
* Use units
* 'make dt_binding_check' succeeds
* 'make dtbs_check' does not report new errors

* Reworded commit messages avoiding 'this patch' phrase
* Fix wrong indent in [PATCH 5/5 v7] input: pwm-beeper: handle module unloading properly
* Use current date in Documentation/ABI/testing/sysfs-devices-pwm-beeper

* Hopefully fixed my setup that
* mails are CC'ed correctly
* patches are sent as replies to the cover letter

Changes since v6 [3]:
* Convert devicetree binding documentation from txt to yaml
* Use DEVICE_ATTR_[RO|RW] properly
* Change Frieders Mail address
* Added Signed-off and Tested-by statements
* Fix module unloading


Frieder Schrempf (2):
input: pwm-beeper: add feature to set volume via sysfs
input: pwm-beeper: set volume levels by devicetree

Manuel Traut (2):
dt-bindings: input: pwm-beeper: Convert txt bindings to yaml
dt-bindings: input: pwm-beeper: add volume

.../ABI/testing/sysfs-devices-pwm-beeper | 17 +++
.../devicetree/bindings/input/pwm-beeper.txt | 24 ----
.../devicetree/bindings/input/pwm-beeper.yaml | 56 ++++++++
drivers/input/misc/pwm-beeper.c | 135 +++++++++++++++++-
4 files changed, 206 insertions(+), 26 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-devices-pwm-beeper
delete mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.txt
create mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.yaml

[0] https://lore.kernel.org/all/[email protected]/
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/all/Y9AIq3cSNzI9T%[email protected]/
[3] https://lkml.org/lkml/2023/1/24/379


--
2.39.0



2023-01-30 13:57:19

by Manuel Traut

[permalink] [raw]
Subject: [PATCH v9 1/4] dt-bindings: input: pwm-beeper: Convert txt bindings to yaml

Converts txt binding to new YAML format.

Signed-off-by: Manuel Traut <[email protected]>
---
.../devicetree/bindings/input/pwm-beeper.txt | 24 ------------
.../devicetree/bindings/input/pwm-beeper.yaml | 39 +++++++++++++++++++
2 files changed, 39 insertions(+), 24 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.txt
create mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.yaml

diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
deleted file mode 100644
index 8fc0e48c20db..000000000000
--- a/Documentation/devicetree/bindings/input/pwm-beeper.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-* PWM beeper device tree bindings
-
-Registers a PWM device as beeper.
-
-Required properties:
-- compatible: should be "pwm-beeper"
-- pwms: phandle to the physical PWM device
-
-Optional properties:
-- amp-supply: phandle to a regulator that acts as an amplifier for the beeper
-- beeper-hz: bell frequency in Hz
-
-Example:
-
-beeper_amp: amplifier {
- compatible = "fixed-regulator";
- gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
-};
-
-beeper {
- compatible = "pwm-beeper";
- pwms = <&pwm0>;
- amp-supply = <&beeper_amp>;
-};
diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.yaml b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
new file mode 100644
index 000000000000..1ebc3a46d934
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/pwm-beeper.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM beeper
+
+maintainers:
+ - Dmitry Torokhov <[email protected]>
+
+description: Registers a PWM device as beeper.
+
+properties:
+ compatible:
+ const: pwm-beeper
+
+ pwms:
+ maxItems: 1
+
+ amp-supply:
+ description: >
+ regulator that acts as an amplifier for the beeper
+
+ beeper-hz:
+ description: bell frequency in Hz
+
+required:
+ - compatible
+ - pwms
+
+additionalProperties: false
+
+examples:
+ - |
+ beeper {
+ compatible = "pwm-beeper";
+ pwms = <&pwm0>;
+ };
--
2.39.0


2023-01-30 13:57:21

by Manuel Traut

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

From: Frieder Schrempf <[email protected]>

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.

Add a sysfs interface with 5 default volume levels:
0 - mute
..
4 - max. volume

Signed-off-by: Frieder Schrempf <[email protected]>
Signed-off-by: Manuel Traut <[email protected]>
Tested-by: Manuel Traut <[email protected]>
---
.../ABI/testing/sysfs-devices-pwm-beeper | 17 ++++
drivers/input/misc/pwm-beeper.c | 96 ++++++++++++++++++-
2 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-devices-pwm-beeper

diff --git a/Documentation/ABI/testing/sysfs-devices-pwm-beeper b/Documentation/ABI/testing/sysfs-devices-pwm-beeper
new file mode 100644
index 000000000000..d2a22516f31d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-pwm-beeper
@@ -0,0 +1,17 @@
+What: /sys/devices/.../pwm-beeper/volume
+Date: January 2023
+KernelVersion:
+Contact: Frieder Schrempf <[email protected]>
+Description:
+ Control the volume of this pwm-beeper. Values
+ are between 0 and max_volume. This file will also
+ show the current volume level stored in the driver.
+
+What: /sys/devices/.../pwm-beeper/max_volume
+Date: February 2023
+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 d6b12477748a..214d3fa0a06d 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -1,9 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
+ *
+ * Copyright (C) 2016, Frieder Schrempf <[email protected]>
+ * (volume support)
+ *
* PWM beeper driver
*/

+#include <linux/device.h>
#include <linux/input.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
@@ -24,10 +29,61 @@ struct pwm_beeper {
unsigned int bell_frequency;
bool suspended;
bool amplifier_on;
+ unsigned int volume;
+ unsigned int *volume_levels;
+ unsigned int max_volume;
};

#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))

+static ssize_t volume_show(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 max_volume_show(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);
+}
+
+static ssize_t volume_store(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;
+
+ if (volume > beeper->max_volume)
+ return -EINVAL;
+ pr_debug("set volume to %u\n", volume);
+ beeper->volume = volume;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(volume);
+static DEVICE_ATTR_RO(max_volume);
+
+static struct attribute *pwm_beeper_attributes[] = {
+ &dev_attr_volume.attr,
+ &dev_attr_max_volume.attr,
+ NULL,
+};
+
+static struct attribute_group pwm_beeper_attribute_group = {
+ .attrs = pwm_beeper_attributes,
+};
+
static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
{
struct pwm_state state;
@@ -37,7 +93,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)

state.enabled = true;
state.period = period;
- pwm_set_relative_duty_cycle(&state, 50, 100);
+ pwm_set_relative_duty_cycle(&state, beeper->volume_levels[beeper->volume], 1000);

error = pwm_apply_state(beeper->pwm, &state);
if (error)
@@ -126,6 +182,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
struct pwm_state state;
u32 bell_frequency;
int error;
+ size_t size;

beeper = devm_kzalloc(dev, sizeof(*beeper), GFP_KERNEL);
if (!beeper)
@@ -171,6 +228,24 @@ static int pwm_beeper_probe(struct platform_device *pdev)

beeper->bell_frequency = bell_frequency;

+ beeper->max_volume = 4;
+
+ size = sizeof(*beeper->volume_levels) *
+ (beeper->max_volume + 1);
+
+ beeper->volume_levels = devm_kzalloc(&(pdev->dev), size,
+ GFP_KERNEL);
+ if (!beeper->volume_levels)
+ return -ENOMEM;
+
+ beeper->volume_levels[0] = 0;
+ beeper->volume_levels[1] = 80;
+ beeper->volume_levels[2] = 200;
+ beeper->volume_levels[3] = 400;
+ beeper->volume_levels[4] = 5000;
+
+ beeper->volume = beeper->max_volume;
+
beeper->input = devm_input_allocate_device(dev);
if (!beeper->input) {
dev_err(dev, "Failed to allocate input device\n");
@@ -192,8 +267,15 @@ static int pwm_beeper_probe(struct platform_device *pdev)

input_set_drvdata(beeper->input, beeper);

+ error = sysfs_create_group(&pdev->dev.kobj, &pwm_beeper_attribute_group);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", error);
+ return error;
+ }
+
error = input_register_device(beeper->input);
if (error) {
+ sysfs_remove_group(&pdev->dev.kobj, &pwm_beeper_attribute_group);
dev_err(dev, "Failed to register input device: %d\n", error);
return error;
}
@@ -203,6 +285,17 @@ static int pwm_beeper_probe(struct platform_device *pdev)
return 0;
}

+static int pwm_beeper_remove(struct platform_device *pdev)
+{
+ struct pwm_beeper *beeper;
+
+ beeper = platform_get_drvdata(pdev);
+ input_unregister_device(beeper->input);
+ sysfs_remove_group(&pdev->dev.kobj, &pwm_beeper_attribute_group);
+
+ return 0;
+}
+
static int __maybe_unused pwm_beeper_suspend(struct device *dev)
{
struct pwm_beeper *beeper = dev_get_drvdata(dev);
@@ -248,6 +341,7 @@ MODULE_DEVICE_TABLE(of, pwm_beeper_match);

static struct platform_driver pwm_beeper_driver = {
.probe = pwm_beeper_probe,
+ .remove = pwm_beeper_remove,
.driver = {
.name = "pwm-beeper",
.pm = &pwm_beeper_pm_ops,
--
2.39.0


2023-01-30 13:57:25

by Manuel Traut

[permalink] [raw]
Subject: [PATCH v9 3/4] dt-bindings: input: pwm-beeper: add volume

Adds an array of supported volume levels and a default volume level.

Signed-off-by: Manuel Traut <[email protected]>
---
.../devicetree/bindings/input/pwm-beeper.yaml | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.yaml b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
index 1ebc3a46d934..ca9efab7efbf 100644
--- a/Documentation/devicetree/bindings/input/pwm-beeper.yaml
+++ b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
@@ -25,6 +25,21 @@ properties:
beeper-hz:
description: bell frequency in Hz

+ volume-levels-bp:
+ description: >
+ Array of PWM duty cycle values that correspond to
+ linear volume levels. These need to be in the range of
+ 0 to 5000, while 0 means 0% duty cycle (mute) and 5000
+ 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 10 to 300 (0.1-3%
+ duty cycle).
+
+ default-volume-level-bp:
+ description: >
+ The default volume level.
+
required:
- compatible
- pwms
@@ -36,4 +51,6 @@ examples:
beeper {
compatible = "pwm-beeper";
pwms = <&pwm0>;
+ volume-levels = <0 8 20 40 500>;
+ default-volume-level = <4>;
};
--
2.39.0


2023-01-30 13:57:35

by Manuel Traut

[permalink] [raw]
Subject: [PATCH v9 4/4] input: pwm-beeper: set volume levels by devicetree

From: Frieder Schrempf <[email protected]>

Add devicetree bindings to define supported volume levels and the
default volume level.

Signed-off-by: Frieder Schrempf <[email protected]>
Signed-off-by: Manuel Traut <[email protected]>
Tested-by: Manuel Traut <[email protected]>
---
drivers/input/misc/pwm-beeper.c | 73 +++++++++++++++++++++++++--------
1 file changed, 55 insertions(+), 18 deletions(-)

diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 214d3fa0a06d..fc367a249490 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -93,7 +93,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)

state.enabled = true;
state.period = period;
- pwm_set_relative_duty_cycle(&state, beeper->volume_levels[beeper->volume], 1000);
+ pwm_set_relative_duty_cycle(&state, beeper->volume_levels[beeper->volume], 10000);

error = pwm_apply_state(beeper->pwm, &state);
if (error)
@@ -181,8 +181,9 @@ static int pwm_beeper_probe(struct platform_device *pdev)
struct pwm_beeper *beeper;
struct pwm_state state;
u32 bell_frequency;
- int error;
+ int error, i, length;
size_t size;
+ u32 value;

beeper = devm_kzalloc(dev, sizeof(*beeper), GFP_KERNEL);
if (!beeper)
@@ -228,23 +229,59 @@ static int pwm_beeper_probe(struct platform_device *pdev)

beeper->bell_frequency = bell_frequency;

- beeper->max_volume = 4;
-
- size = sizeof(*beeper->volume_levels) *
- (beeper->max_volume + 1);
-
- beeper->volume_levels = devm_kzalloc(&(pdev->dev), size,
- GFP_KERNEL);
- if (!beeper->volume_levels)
- return -ENOMEM;
-
- beeper->volume_levels[0] = 0;
- beeper->volume_levels[1] = 80;
- beeper->volume_levels[2] = 200;
- beeper->volume_levels[3] = 400;
- beeper->volume_levels[4] = 5000;
+ /* determine the number of volume levels */
+ length = device_property_read_u32_array(&pdev->dev, "volume-levels-bp", NULL, 0);
+ if (length <= 0) {
+ dev_dbg(&pdev->dev, "no volume levels specified, using max volume\n");
+ beeper->max_volume = 1;
+ } else
+ beeper->max_volume = length;
+
+ /* read volume levels from DT property */
+ if (beeper->max_volume > 0) {
+ size = sizeof(*beeper->volume_levels) * beeper->max_volume;
+
+ beeper->volume_levels = devm_kzalloc(&(pdev->dev), size,
+ GFP_KERNEL);
+ if (!beeper->volume_levels)
+ return -ENOMEM;
+
+ if (length > 0) {
+ error = device_property_read_u32_array(&pdev->dev, "volume-levels-bp",
+ beeper->volume_levels,
+ beeper->max_volume);
+
+ if (error < 0)
+ return error;
+
+ error = device_property_read_u32(&pdev->dev, "default-volume-level-bp",
+ &value);
+
+ if (error < 0) {
+ dev_dbg(&pdev->dev, "no default volume specified, using max volume\n");
+ value = beeper->max_volume - 1;
+ } else {
+ for (i = 0; i < length; i++) {
+ if (beeper->volume_levels[i] == value) {
+ value = i;
+ break;
+ }
+ }
+ if (value != i) {
+ dev_dbg(&pdev->dev,
+ "default-volume-level-bp %d invalid, using %d\n",
+ value, beeper->max_volume - 1);
+ value = beeper->max_volume - 1;
+ }
+ }
+ } else {
+ beeper->volume_levels[0] = 5000;
+ value = 0;
+ }

- beeper->volume = beeper->max_volume;
+ beeper->volume = value;
+ beeper->max_volume--;
+ }

beeper->input = devm_input_allocate_device(dev);
if (!beeper->input) {
--
2.39.0


2023-01-30 15:29:08

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v9 3/4] dt-bindings: input: pwm-beeper: add volume


On Mon, 30 Jan 2023 14:56:49 +0100, Manuel Traut wrote:
> Adds an array of supported volume levels and a default volume level.
>
> Signed-off-by: Manuel Traut <[email protected]>
> ---
> .../devicetree/bindings/input/pwm-beeper.yaml | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/input/pwm-beeper.example.dtb: beeper: 'default-volume-level', 'volume-levels' do not match any of the regexes: 'pinctrl-[0-9]+'
From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/input/pwm-beeper.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


2023-01-30 23:09:35

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v9 1/4] dt-bindings: input: pwm-beeper: Convert txt bindings to yaml


On Mon, 30 Jan 2023 14:56:47 +0100, Manuel Traut wrote:
> Converts txt binding to new YAML format.
>
> Signed-off-by: Manuel Traut <[email protected]>
> ---
> .../devicetree/bindings/input/pwm-beeper.txt | 24 ------------
> .../devicetree/bindings/input/pwm-beeper.yaml | 39 +++++++++++++++++++
> 2 files changed, 39 insertions(+), 24 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.txt
> create mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.yaml
>

Reviewed-by: Rob Herring <[email protected]>

2023-02-01 08:37:29

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v9 3/4] dt-bindings: input: pwm-beeper: add volume

On 30/01/2023 14:56, Manuel Traut wrote:
> Adds an array of supported volume levels and a default volume level.
>
> Signed-off-by: Manuel Traut <[email protected]>
> ---
> .../devicetree/bindings/input/pwm-beeper.yaml | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.yaml b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
> index 1ebc3a46d934..ca9efab7efbf 100644
> --- a/Documentation/devicetree/bindings/input/pwm-beeper.yaml
> +++ b/Documentation/devicetree/bindings/input/pwm-beeper.yaml
> @@ -25,6 +25,21 @@ properties:
> beeper-hz:
> description: bell frequency in Hz
>
> + volume-levels-bp:
> + description: >

Does not look like you tested the bindings. Please run `make
dt_binding_check` (see
Documentation/devicetree/bindings/writing-schema.rst for instructions).

Best regards,
Krzysztof