1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2021, Ahmad Fatoum
*/
#include <common.h>
#include <regulator.h>
#include <sound.h>
#include <of.h>
#include <pwm.h>
struct pwm_beeper {
struct pwm_device *pwm;
struct regulator *amplifier;
struct sound_card card;
};
#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
static int pwm_beeper_beep(struct sound_card *card, unsigned freq, unsigned duration)
{
struct pwm_beeper *beeper = container_of(card, struct pwm_beeper, card);
struct pwm_state state;
int error = 0;
if (!freq) {
regulator_disable(beeper->amplifier);
goto pwm_disable;
}
pwm_get_state(beeper->pwm, &state);
state.p_enable = true;
state.period_ns = HZ_TO_NANOSECONDS(freq);
pwm_set_relative_duty_cycle(&state, 50, 100);
error = pwm_apply_state(beeper->pwm, &state);
if (error)
return error;
error = regulator_enable(beeper->amplifier);
if (error)
goto pwm_disable;
return 0;
pwm_disable:
pwm_disable(beeper->pwm);
return error;
}
static int pwm_beeper_probe(struct device_d *dev)
{
struct pwm_beeper *beeper;
struct sound_card *card;
struct pwm_state state;
u32 bell_frequency;
int error;
beeper = xzalloc(sizeof(*beeper));
dev->priv = beeper;
beeper->pwm = of_pwm_request(dev->device_node, NULL);
if (IS_ERR(beeper->pwm)) {
error = PTR_ERR(beeper->pwm);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to request PWM device: %d\n",
error);
return error;
}
/* Sync up PWM state and ensure it is off. */
pwm_init_state(beeper->pwm, &state);
state.p_enable = false;
error = pwm_apply_state(beeper->pwm, &state);
if (error) {
dev_err(dev, "failed to apply initial PWM state: %d\n",
error);
return error;
}
beeper->amplifier = regulator_get(dev, "amp");
if (IS_ERR(beeper->amplifier)) {
error = PTR_ERR(beeper->amplifier);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to get 'amp' regulator: %d\n",
error);
return error;
}
error = of_property_read_u32(dev->device_node, "beeper-hz", &bell_frequency);
if (error) {
bell_frequency = 1000;
dev_dbg(dev, "failed to parse 'beeper-hz' property, using default: %uHz\n",
bell_frequency);
}
card = &beeper->card;
card->name = dev->device_node->full_name;
card->bell_frequency = bell_frequency;
card->beep = pwm_beeper_beep;
return sound_card_register(card);
}
static void pwm_beeper_suspend(struct device_d *dev)
{
struct pwm_beeper *beeper = dev->priv;
pwm_beeper_beep(&beeper->card, 0, 0);
}
static const struct of_device_id pwm_beeper_match[] = {
{ .compatible = "pwm-beeper", },
{ },
};
static struct driver_d pwm_beeper_driver = {
.name = "pwm-beeper",
.probe = pwm_beeper_probe,
.remove = pwm_beeper_suspend,
.of_compatible = pwm_beeper_match,
};
device_platform_driver(pwm_beeper_driver);
|