Commit 2850266965ade165f913a66f679a0449faf21180
Committed by
Bin Meng
1 parent
e65f9ef9f2
Exists in
smarc_8mq_lf_v2020.04
and in
12 other branches
sound: Add uclass operations for beeping
Some audio codecs such as Intel HDA do not need to use digital data to play sounds, but instead have a way to emit beeps. Add this interface as an option. If the beep interface is not supported, then the sound uclass falls back to the I2S interface. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Showing 5 changed files with 157 additions and 4 deletions Side-by-side Diff
arch/sandbox/include/asm/test.h
... | ... | @@ -162,6 +162,22 @@ |
162 | 162 | int sandbox_get_sound_sum(struct udevice *dev); |
163 | 163 | |
164 | 164 | /** |
165 | + * sandbox_set_allow_beep() - Set whether the 'beep' interface is supported | |
166 | + * | |
167 | + * @dev: Device to update | |
168 | + * @allow: true to allow the start_beep() method, false to disallow it | |
169 | + */ | |
170 | +void sandbox_set_allow_beep(struct udevice *dev, bool allow); | |
171 | + | |
172 | +/** | |
173 | + * sandbox_get_beep_frequency() - Get the frequency of the current beep | |
174 | + * | |
175 | + * @dev: Device to check | |
176 | + * @return frequency of beep, if there is an active beep, else 0 | |
177 | + */ | |
178 | +int sandbox_get_beep_frequency(struct udevice *dev); | |
179 | + | |
180 | +/** | |
165 | 181 | * sandbox_get_pch_spi_protect() - Get the PCI SPI protection status |
166 | 182 | * |
167 | 183 | * @dev: Device to check |
drivers/sound/sandbox.c
... | ... | @@ -24,7 +24,9 @@ |
24 | 24 | |
25 | 25 | struct sandbox_sound_priv { |
26 | 26 | int setup_called; |
27 | - int sum; /* Use to sum the provided audio data */ | |
27 | + int sum; /* Use to sum the provided audio data */ | |
28 | + bool allow_beep; /* true to allow the start_beep() interface */ | |
29 | + int frequency_hz; /* Beep frequency if active, else 0 */ | |
28 | 30 | }; |
29 | 31 | |
30 | 32 | void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep, |
... | ... | @@ -61,6 +63,20 @@ |
61 | 63 | return priv->sum; |
62 | 64 | } |
63 | 65 | |
66 | +void sandbox_set_allow_beep(struct udevice *dev, bool allow) | |
67 | +{ | |
68 | + struct sandbox_sound_priv *priv = dev_get_priv(dev); | |
69 | + | |
70 | + priv->allow_beep = allow; | |
71 | +} | |
72 | + | |
73 | +int sandbox_get_beep_frequency(struct udevice *dev) | |
74 | +{ | |
75 | + struct sandbox_sound_priv *priv = dev_get_priv(dev); | |
76 | + | |
77 | + return priv->frequency_hz; | |
78 | +} | |
79 | + | |
64 | 80 | static int sandbox_codec_set_params(struct udevice *dev, int interface, |
65 | 81 | int rate, int mclk_freq, |
66 | 82 | int bits_per_sample, uint channels) |
... | ... | @@ -128,6 +144,28 @@ |
128 | 144 | return i2s_tx_data(uc_priv->i2s, data, data_size); |
129 | 145 | } |
130 | 146 | |
147 | +int sandbox_sound_start_beep(struct udevice *dev, int frequency_hz) | |
148 | +{ | |
149 | + struct sandbox_sound_priv *priv = dev_get_priv(dev); | |
150 | + | |
151 | + if (!priv->allow_beep) | |
152 | + return -ENOSYS; | |
153 | + priv->frequency_hz = frequency_hz; | |
154 | + | |
155 | + return 0; | |
156 | +} | |
157 | + | |
158 | +int sandbox_sound_stop_beep(struct udevice *dev) | |
159 | +{ | |
160 | + struct sandbox_sound_priv *priv = dev_get_priv(dev); | |
161 | + | |
162 | + if (!priv->allow_beep) | |
163 | + return -ENOSYS; | |
164 | + priv->frequency_hz = 0; | |
165 | + | |
166 | + return 0; | |
167 | +} | |
168 | + | |
131 | 169 | static int sandbox_sound_probe(struct udevice *dev) |
132 | 170 | { |
133 | 171 | return sound_find_codec_i2s(dev); |
... | ... | @@ -169,8 +207,10 @@ |
169 | 207 | }; |
170 | 208 | |
171 | 209 | static const struct sound_ops sandbox_sound_ops = { |
172 | - .setup = sandbox_sound_setup, | |
173 | - .play = sandbox_sound_play, | |
210 | + .setup = sandbox_sound_setup, | |
211 | + .play = sandbox_sound_play, | |
212 | + .start_beep = sandbox_sound_start_beep, | |
213 | + .stop_beep = sandbox_sound_stop_beep, | |
174 | 214 | }; |
175 | 215 | |
176 | 216 | static const struct udevice_id sandbox_sound_ids[] = { |
drivers/sound/sound-uclass.c
... | ... | @@ -31,10 +31,30 @@ |
31 | 31 | return ops->play(dev, data, data_size); |
32 | 32 | } |
33 | 33 | |
34 | +int sound_start_beep(struct udevice *dev, int frequency_hz) | |
35 | +{ | |
36 | + struct sound_ops *ops = sound_get_ops(dev); | |
37 | + | |
38 | + if (!ops->start_beep) | |
39 | + return -ENOSYS; | |
40 | + | |
41 | + return ops->start_beep(dev, frequency_hz); | |
42 | +} | |
43 | + | |
44 | +int sound_stop_beep(struct udevice *dev) | |
45 | +{ | |
46 | + struct sound_ops *ops = sound_get_ops(dev); | |
47 | + | |
48 | + if (!ops->stop_beep) | |
49 | + return -ENOSYS; | |
50 | + | |
51 | + return ops->stop_beep(dev); | |
52 | +} | |
53 | + | |
34 | 54 | int sound_beep(struct udevice *dev, int msecs, int frequency_hz) |
35 | 55 | { |
36 | 56 | struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev); |
37 | - struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s); | |
57 | + struct i2s_uc_priv *i2s_uc_priv; | |
38 | 58 | unsigned short *data; |
39 | 59 | uint data_size; |
40 | 60 | int ret; |
41 | 61 | |
... | ... | @@ -43,7 +63,19 @@ |
43 | 63 | if (ret && ret != -EALREADY) |
44 | 64 | return ret; |
45 | 65 | |
66 | + /* Try using the beep interface if available */ | |
67 | + ret = sound_start_beep(dev, frequency_hz); | |
68 | + if (ret != -ENOSYS) { | |
69 | + if (ret) | |
70 | + return ret; | |
71 | + mdelay(msecs); | |
72 | + ret = sound_stop_beep(dev); | |
73 | + | |
74 | + return ret; | |
75 | + } | |
76 | + | |
46 | 77 | /* Buffer length computation */ |
78 | + i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s); | |
47 | 79 | data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels; |
48 | 80 | data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE); |
49 | 81 | data = malloc(data_size); |
include/sound.h
... | ... | @@ -67,6 +67,28 @@ |
67 | 67 | * @return 0 if OK, -ve on error |
68 | 68 | */ |
69 | 69 | int (*play)(struct udevice *dev, void *data, uint data_size); |
70 | + | |
71 | + /** | |
72 | + * start_beep() - Start beeping (optional) | |
73 | + * | |
74 | + * This tells the sound hardware to start a beep. It will continue until | |
75 | + * stopped by sound_stop_beep(). | |
76 | + * | |
77 | + * @dev: Sound device | |
78 | + * @frequency_hz: Beep frequency in hertz | |
79 | + * @return if OK, -ENOSYS if not supported, -ve on error | |
80 | + */ | |
81 | + int (*start_beep)(struct udevice *dev, int frequency_hz); | |
82 | + | |
83 | + /** | |
84 | + * stop_beep() - Stop beeping (optional) | |
85 | + * | |
86 | + * This tells the sound hardware to stop a previously started beep. | |
87 | + * | |
88 | + * @dev: Sound device | |
89 | + * @return if OK, -ve on error | |
90 | + */ | |
91 | + int (*stop_beep)(struct udevice *dev); | |
70 | 92 | }; |
71 | 93 | |
72 | 94 | #define sound_get_ops(dev) ((struct sound_ops *)(dev)->driver->ops) |
... | ... | @@ -85,6 +107,28 @@ |
85 | 107 | * @return 0 if OK, -ve on error |
86 | 108 | */ |
87 | 109 | int sound_beep(struct udevice *dev, int msecs, int frequency_hz); |
110 | + | |
111 | +/** | |
112 | + * sound_start_beep() - Start beeping | |
113 | + * | |
114 | + * This tells the sound hardware to start a beep. It will continue until stopped | |
115 | + * by sound_stop_beep(). | |
116 | + * | |
117 | + * @dev: Sound device | |
118 | + * @frequency_hz: Beep frequency in hertz | |
119 | + * @return if OK, -ve on error | |
120 | + */ | |
121 | +int sound_start_beep(struct udevice *dev, int frequency_hz); | |
122 | + | |
123 | +/** | |
124 | + * sound_stop_beep() - Stop beeping | |
125 | + * | |
126 | + * This tells the sound hardware to stop a previously started beep. | |
127 | + * | |
128 | + * @dev: Sound device | |
129 | + * @return if OK, -ve on error | |
130 | + */ | |
131 | +int sound_stop_beep(struct udevice *dev); | |
88 | 132 | |
89 | 133 | /** |
90 | 134 | * sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s |
test/dm/sound.c
... | ... | @@ -32,4 +32,25 @@ |
32 | 32 | return 0; |
33 | 33 | } |
34 | 34 | DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); |
35 | + | |
36 | +/* Test of the 'start beep' operations */ | |
37 | +static int dm_test_sound_beep(struct unit_test_state *uts) | |
38 | +{ | |
39 | + struct udevice *dev; | |
40 | + | |
41 | + /* check probe success */ | |
42 | + ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev)); | |
43 | + ut_asserteq(-ENOSYS, sound_start_beep(dev, 100)); | |
44 | + ut_asserteq(0, sandbox_get_beep_frequency(dev)); | |
45 | + | |
46 | + sandbox_set_allow_beep(dev, true); | |
47 | + ut_asserteq(0, sound_start_beep(dev, 100)); | |
48 | + ut_asserteq(100, sandbox_get_beep_frequency(dev)); | |
49 | + | |
50 | + ut_asserteq(0, sound_stop_beep(dev)); | |
51 | + ut_asserteq(0, sandbox_get_beep_frequency(dev)); | |
52 | + | |
53 | + return 0; | |
54 | +} | |
55 | +DM_TEST(dm_test_sound_beep, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); |