1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2013 Google, Inc
4 */
5
6#define LOG_CATEGORY UCLASS_SOUND
7
8#include <common.h>
9#include <audio_codec.h>
10#include <dm.h>
11#include <i2s.h>
12#include <log.h>
13#include <sound.h>
14#include <asm/sdl.h>
15
16struct sandbox_codec_priv {
17	int interface;
18	int rate;
19	int mclk_freq;
20	int bits_per_sample;
21	uint channels;
22};
23
24struct sandbox_i2s_priv {
25	int sum;	/* Use to sum the provided audio data */
26	bool silent;	/* Sound is silent, don't use SDL */
27};
28
29struct sandbox_sound_priv {
30	int setup_called;	/* Incremented when setup() method is called */
31	bool active;		/* TX data is being sent */
32	int count;		/* Use to count the provided audio data */
33	int sum;		/* Use to sum the provided audio data */
34	bool allow_beep;	/* true to allow the start_beep() interface */
35	int frequency_hz;	/* Beep frequency if active, else 0 */
36};
37
38void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
39			      int *mclk_freqp, int *bits_per_samplep,
40			      uint *channelsp)
41{
42	struct sandbox_codec_priv *priv = dev_get_priv(dev);
43
44	*interfacep = priv->interface;
45	*ratep = priv->rate;
46	*mclk_freqp = priv->mclk_freq;
47	*bits_per_samplep = priv->bits_per_sample;
48	*channelsp = priv->channels;
49}
50
51int sandbox_get_i2s_sum(struct udevice *dev)
52{
53	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
54
55	return priv->sum;
56}
57
58int sandbox_get_setup_called(struct udevice *dev)
59{
60	struct sandbox_sound_priv *priv = dev_get_priv(dev);
61
62	return priv->setup_called;
63}
64
65int sandbox_get_sound_active(struct udevice *dev)
66{
67	struct sandbox_sound_priv *priv = dev_get_priv(dev);
68
69	return priv->active;
70}
71
72int sandbox_get_sound_count(struct udevice *dev)
73{
74	struct sandbox_sound_priv *priv = dev_get_priv(dev);
75
76	return priv->count;
77}
78
79int sandbox_get_sound_sum(struct udevice *dev)
80{
81	struct sandbox_sound_priv *priv = dev_get_priv(dev);
82
83	return priv->sum;
84}
85
86void sandbox_set_allow_beep(struct udevice *dev, bool allow)
87{
88	struct sandbox_sound_priv *priv = dev_get_priv(dev);
89
90	priv->allow_beep = allow;
91}
92
93int sandbox_get_beep_frequency(struct udevice *dev)
94{
95	struct sandbox_sound_priv *priv = dev_get_priv(dev);
96
97	return priv->frequency_hz;
98}
99
100static int sandbox_codec_set_params(struct udevice *dev, int interface,
101				    int rate, int mclk_freq,
102				    int bits_per_sample, uint channels)
103{
104	struct sandbox_codec_priv *priv = dev_get_priv(dev);
105
106	priv->interface = interface;
107	priv->rate = rate;
108	priv->mclk_freq = mclk_freq;
109	priv->bits_per_sample = bits_per_sample;
110	priv->channels = channels;
111
112	return 0;
113}
114
115static int sandbox_i2s_tx_data(struct udevice *dev, void *data,
116			       uint data_size)
117{
118	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
119	int i;
120
121	for (i = 0; i < data_size; i++)
122		priv->sum += ((uint8_t *)data)[i];
123
124	if (!priv->silent) {
125		int ret;
126
127		ret = sandbox_sdl_sound_play(data, data_size);
128		if (ret)
129			return ret;
130	}
131
132	return 0;
133}
134
135static int sandbox_i2s_probe(struct udevice *dev)
136{
137	struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev);
138	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
139
140	/* Use hard-coded values here */
141	uc_priv->rfs = 256;
142	uc_priv->bfs = 32;
143	uc_priv->audio_pll_clk = 192000000;
144	uc_priv->samplingrate = 48000;
145	uc_priv->bitspersample = 16;
146	uc_priv->channels = 2;
147	uc_priv->id = 1;
148
149	priv->silent = dev_read_bool(dev, "sandbox,silent");
150
151	if (priv->silent) {
152		log_warning("Sound is silenced\n");
153	} else if (sandbox_sdl_sound_init(uc_priv->samplingrate,
154					  uc_priv->channels)) {
155		/* Ignore any error here - we'll just have no sound */
156		priv->silent = true;
157	}
158
159	return 0;
160}
161
162static int sandbox_sound_setup(struct udevice *dev)
163{
164	struct sandbox_sound_priv *priv = dev_get_priv(dev);
165
166	priv->setup_called++;
167
168	return 0;
169}
170
171static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
172{
173	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
174	struct sandbox_sound_priv *priv = dev_get_priv(dev);
175	int i;
176
177	for (i = 0; i < data_size; i++)
178		priv->sum += ((uint8_t *)data)[i];
179	priv->count += data_size;
180
181	return i2s_tx_data(uc_priv->i2s, data, data_size);
182}
183
184static int sandbox_sound_stop_play(struct udevice *dev)
185{
186	struct sandbox_sound_priv *priv = dev_get_priv(dev);
187
188	sandbox_sdl_sound_stop();
189	priv->active = false;
190
191	return 0;
192}
193
194int sandbox_sound_start_beep(struct udevice *dev, int frequency_hz)
195{
196	struct sandbox_sound_priv *priv = dev_get_priv(dev);
197
198	if (!priv->allow_beep)
199		return -ENOSYS;
200	priv->frequency_hz = frequency_hz;
201
202	return 0;
203}
204
205int sandbox_sound_stop_beep(struct udevice *dev)
206{
207	struct sandbox_sound_priv *priv = dev_get_priv(dev);
208
209	if (!priv->allow_beep)
210		return -ENOSYS;
211	priv->frequency_hz = 0;
212
213	return 0;
214}
215
216static int sandbox_sound_probe(struct udevice *dev)
217{
218	return sound_find_codec_i2s(dev);
219}
220
221static const struct audio_codec_ops sandbox_codec_ops = {
222	.set_params	= sandbox_codec_set_params,
223};
224
225static const struct udevice_id sandbox_codec_ids[] = {
226	{ .compatible = "sandbox,audio-codec" },
227	{ }
228};
229
230U_BOOT_DRIVER(sandbox_codec) = {
231	.name		= "sandbox_codec",
232	.id		= UCLASS_AUDIO_CODEC,
233	.of_match	= sandbox_codec_ids,
234	.ops		= &sandbox_codec_ops,
235	.priv_auto	= sizeof(struct sandbox_codec_priv),
236};
237
238static const struct i2s_ops sandbox_i2s_ops = {
239	.tx_data	= sandbox_i2s_tx_data,
240};
241
242static const struct udevice_id sandbox_i2s_ids[] = {
243	{ .compatible = "sandbox,i2s" },
244	{ }
245};
246
247U_BOOT_DRIVER(sandbox_i2s) = {
248	.name		= "sandbox_i2s",
249	.id		= UCLASS_I2S,
250	.of_match	= sandbox_i2s_ids,
251	.ops		= &sandbox_i2s_ops,
252	.probe		= sandbox_i2s_probe,
253	.priv_auto	= sizeof(struct sandbox_i2s_priv),
254};
255
256static const struct sound_ops sandbox_sound_ops = {
257	.setup		= sandbox_sound_setup,
258	.play		= sandbox_sound_play,
259	.stop_play	= sandbox_sound_stop_play,
260	.start_beep	= sandbox_sound_start_beep,
261	.stop_beep	= sandbox_sound_stop_beep,
262};
263
264static const struct udevice_id sandbox_sound_ids[] = {
265	{ .compatible = "sandbox,sound" },
266	{ }
267};
268
269U_BOOT_DRIVER(sandbox_sound) = {
270	.name		= "sandbox_sound",
271	.id		= UCLASS_SOUND,
272	.of_match	= sandbox_sound_ids,
273	.ops		= &sandbox_sound_ops,
274	.priv_auto	= sizeof(struct sandbox_sound_priv),
275	.probe		= sandbox_sound_probe,
276};
277