xref: /openbsd/sys/dev/fdt/graphaudio.c (revision 771fbea0)
1 /*	$OpenBSD: graphaudio.c,v 1.1 2021/04/07 17:12:22 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
4  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/malloc.h>
23 
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_misc.h>
28 
29 #include <sys/audioio.h>
30 #include <dev/audio_if.h>
31 #include <dev/midi_if.h>
32 
33 struct graphaudio_softc {
34 	struct device		sc_dev;
35 	int			sc_node;
36 
37 	uint32_t		sc_mclk_fs;
38 
39 	struct dai_device	*sc_dai_cpu;
40 	struct dai_device	*sc_dai_codec;
41 };
42 
43 int	graphaudio_match(struct device *, void *, void *);
44 void	graphaudio_attach(struct device *, struct device *, void *);
45 void	graphaudio_attach_deferred(struct device *);
46 void	graphaudio_set_format(struct graphaudio_softc *, uint32_t,
47 	    uint32_t, uint32_t);
48 
49 int	graphaudio_open(void *, int);
50 void	graphaudio_close(void *);
51 int	graphaudio_set_params(void *, int, int,
52 	    struct audio_params *, struct audio_params *);
53 void	*graphaudio_allocm(void *, int, size_t, int, int);
54 void	graphaudio_freem(void *, void *, int);
55 int	graphaudio_set_port(void *, mixer_ctrl_t *);
56 int	graphaudio_get_port(void *, mixer_ctrl_t *);
57 int	graphaudio_query_devinfo(void *, mixer_devinfo_t *);
58 int	graphaudio_get_props(void *);
59 int	graphaudio_round_blocksize(void *, int);
60 size_t	graphaudio_round_buffersize(void *, int, size_t);
61 int	graphaudio_trigger_output(void *, void *, void *, int,
62 	    void (*)(void *), void *, struct audio_params *);
63 int	graphaudio_trigger_input(void *, void *, void *, int,
64 	    void (*)(void *), void *, struct audio_params *);
65 int	graphaudio_halt_output(void *);
66 int	graphaudio_halt_input(void *);
67 
68 struct audio_hw_if graphaudio_hw_if = {
69 	.open = graphaudio_open,
70 	.close = graphaudio_close,
71 	.set_params = graphaudio_set_params,
72 	.allocm = graphaudio_allocm,
73 	.freem = graphaudio_freem,
74 	.set_port = graphaudio_set_port,
75 	.get_port = graphaudio_get_port,
76 	.query_devinfo = graphaudio_query_devinfo,
77 	.get_props = graphaudio_get_props,
78 	.round_blocksize = graphaudio_round_blocksize,
79 	.round_buffersize = graphaudio_round_buffersize,
80 	.trigger_output = graphaudio_trigger_output,
81 	.trigger_input = graphaudio_trigger_input,
82 	.halt_output = graphaudio_halt_output,
83 	.halt_input = graphaudio_halt_input,
84 };
85 
86 struct cfattach graphaudio_ca = {
87 	sizeof(struct graphaudio_softc), graphaudio_match, graphaudio_attach
88 };
89 
90 struct cfdriver graphaudio_cd = {
91 	NULL, "graphaudio", DV_DULL
92 };
93 
94 int
95 graphaudio_match(struct device *parent, void *match, void *aux)
96 {
97 	struct fdt_attach_args *faa = aux;
98 
99 	return OF_is_compatible(faa->fa_node, "audio-graph-card");
100 }
101 
102 void
103 graphaudio_attach(struct device *parent, struct device *self, void *aux)
104 {
105 	struct graphaudio_softc *sc = (struct graphaudio_softc *)self;
106 	struct fdt_attach_args *faa = aux;
107 
108 	printf("\n");
109 
110 	sc->sc_node = faa->fa_node;
111 	config_defer(self, graphaudio_attach_deferred);
112 }
113 
114 void
115 graphaudio_attach_deferred(struct device *self)
116 {
117 	struct graphaudio_softc *sc = (struct graphaudio_softc *)self;
118 	char format[16] = { 0 };
119 	uint32_t fmt, pol, clk;
120 	uint32_t dais;
121 	struct device_ports *dp;
122 	struct endpoint *ep, *rep;
123 
124 	dais = OF_getpropint(sc->sc_node, "dais", 0);
125 	dp = device_ports_byphandle(dais);
126 	if (dp == NULL)
127 		return;
128 
129 	ep = endpoint_byreg(dp, -1, -1);
130 	if (ep == NULL)
131 		return;
132 
133 	rep = endpoint_remote(ep);
134 	if (rep == NULL)
135 		return;
136 
137 	sc->sc_mclk_fs = OF_getpropint(ep->ep_node, "mclk-fs", 0);
138 
139 	sc->sc_dai_cpu = endpoint_get_cookie(ep);
140 	sc->sc_dai_codec = endpoint_get_cookie(rep);
141 
142 	if (sc->sc_dai_cpu == NULL || sc->sc_dai_codec == NULL)
143 		return;
144 
145 	OF_getprop(ep->ep_node, "dai-format", format, sizeof(format));
146 	if (!strcmp(format, "i2s"))
147 		fmt = DAI_FORMAT_I2S;
148 	else if (!strcmp(format, "right_j"))
149 		fmt = DAI_FORMAT_RJ;
150 	else if (!strcmp(format, "left_j"))
151 		fmt = DAI_FORMAT_LJ;
152 	else if (!strcmp(format, "dsp_a"))
153 		fmt = DAI_FORMAT_DSPA;
154 	else if (!strcmp(format, "dsp_b"))
155 		fmt = DAI_FORMAT_DSPB;
156 	else if (!strcmp(format, "ac97"))
157 		fmt = DAI_FORMAT_AC97;
158 	else if (!strcmp(format, "pdm"))
159 		fmt = DAI_FORMAT_PDM;
160 	else if (!strcmp(format, "msb"))
161 		fmt = DAI_FORMAT_MSB;
162 	else if (!strcmp(format, "lsb"))
163 		fmt = DAI_FORMAT_LSB;
164 	else
165 		return;
166 
167 	pol = 0;
168 	if (OF_getproplen(ep->ep_node, "frame-inversion") == 0)
169 		pol |= DAI_POLARITY_IF;
170 	else
171 		pol |= DAI_POLARITY_NF;
172 	if (OF_getproplen(ep->ep_node, "bitclock-inversion") == 0)
173 		pol |= DAI_POLARITY_IB;
174 	else
175 		pol |= DAI_POLARITY_NB;
176 
177 	clk = 0;
178 	if (OF_getproplen(ep->ep_node, "frame-master") == 0)
179 		clk |= DAI_CLOCK_CFM;
180 	else
181 		clk |= DAI_CLOCK_CFS;
182 	if (OF_getproplen(ep->ep_node, "bitclock-master") == 0)
183 		clk |= DAI_CLOCK_CBM;
184 	else
185 		clk |= DAI_CLOCK_CBS;
186 
187 	graphaudio_set_format(sc, fmt, pol, clk);
188 
189 	audio_attach_mi(&graphaudio_hw_if, sc, &sc->sc_dev);
190 }
191 
192 void
193 graphaudio_set_format(struct graphaudio_softc *sc, uint32_t fmt, uint32_t pol,
194     uint32_t clk)
195 {
196 	if (sc->sc_dai_cpu->dd_set_format)
197 		sc->sc_dai_cpu->dd_set_format(sc->sc_dai_cpu->dd_cookie,
198 		    fmt, pol, clk);
199 	if (sc->sc_dai_codec->dd_set_format)
200 		sc->sc_dai_codec->dd_set_format(sc->sc_dai_codec->dd_cookie,
201 		    fmt, pol, clk);
202 }
203 
204 int
205 graphaudio_open(void *cookie, int flags)
206 {
207 	struct graphaudio_softc *sc = cookie;
208 	struct dai_device *dai;
209 	struct audio_hw_if *hwif;
210 	int error;
211 
212 	dai = sc->sc_dai_cpu;
213 	hwif = dai->dd_hw_if;
214 	if (hwif->open) {
215 		error = hwif->open(dai->dd_cookie, flags);
216 		if (error) {
217 			graphaudio_close(cookie);
218 			return error;
219 		}
220 	}
221 
222 	dai = sc->sc_dai_codec;
223 	hwif = dai->dd_hw_if;
224 	if (hwif->open) {
225 		error = hwif->open(dai->dd_cookie, flags);
226 		if (error) {
227 			graphaudio_close(cookie);
228 			return error;
229 		}
230 	}
231 
232 	return 0;
233 }
234 
235 void
236 graphaudio_close(void *cookie)
237 {
238 	struct graphaudio_softc *sc = cookie;
239 	struct dai_device *dai;
240 	struct audio_hw_if *hwif;
241 
242 	dai = sc->sc_dai_codec;
243 	hwif = dai->dd_hw_if;
244 	if (hwif->close)
245 		hwif->close(dai->dd_cookie);
246 
247 	dai = sc->sc_dai_cpu;
248 	hwif = dai->dd_hw_if;
249 	if (hwif->close)
250 		hwif->close(dai->dd_cookie);
251 }
252 
253 int
254 graphaudio_set_params(void *cookie, int setmode, int usemode,
255     struct audio_params *play, struct audio_params *rec)
256 {
257 	struct graphaudio_softc *sc = cookie;
258 	struct dai_device *dai;
259 	struct audio_hw_if *hwif;
260 	uint32_t rate;
261 	int error;
262 
263 	if (sc->sc_mclk_fs) {
264 		if (setmode & AUMODE_PLAY)
265 			rate = play->sample_rate * sc->sc_mclk_fs;
266 		else
267 			rate = rec->sample_rate * sc->sc_mclk_fs;
268 
269 		dai = sc->sc_dai_codec;
270 		if (dai->dd_set_sysclk) {
271 			error = dai->dd_set_sysclk(dai->dd_cookie, rate);
272 			if (error)
273 				return error;
274 		}
275 
276 		dai = sc->sc_dai_cpu;
277 		if (dai->dd_set_sysclk) {
278 			error = dai->dd_set_sysclk(dai->dd_cookie, rate);
279 			if (error)
280 				return error;
281 		}
282 	}
283 
284 	dai = sc->sc_dai_cpu;
285 	hwif = dai->dd_hw_if;
286 	if (hwif->set_params) {
287 		error = hwif->set_params(dai->dd_cookie,
288 		    setmode, usemode, play, rec);
289 		if (error)
290 			return error;
291 	}
292 
293 	dai = sc->sc_dai_codec;
294 	hwif = dai->dd_hw_if;
295 	if (hwif->set_params) {
296 		error = hwif->set_params(dai->dd_cookie,
297 		    setmode, usemode, play, rec);
298 		if (error)
299 			return error;
300 	}
301 
302 	return 0;
303 }
304 
305 void *
306 graphaudio_allocm(void *cookie, int direction, size_t size, int type,
307     int flags)
308 {
309 	struct graphaudio_softc *sc = cookie;
310 	struct dai_device *dai = sc->sc_dai_cpu;
311 	struct audio_hw_if *hwif = dai->dd_hw_if;
312 
313 	if (hwif->allocm)
314 		return hwif->allocm(dai->dd_cookie,
315 		    direction, size, type, flags);
316 
317 	return NULL;
318 }
319 
320 void
321 graphaudio_freem(void *cookie, void *addr, int type)
322 {
323 	struct graphaudio_softc *sc = cookie;
324 	struct dai_device *dai = sc->sc_dai_cpu;
325 	struct audio_hw_if *hwif = dai->dd_hw_if;
326 
327 	if (hwif->freem)
328 		hwif->freem(dai->dd_cookie, addr, type);
329 }
330 
331 int
332 graphaudio_set_port(void *cookie, mixer_ctrl_t *cp)
333 {
334 	struct graphaudio_softc *sc = cookie;
335 	struct dai_device *dai = sc->sc_dai_codec;
336 	struct audio_hw_if *hwif = dai->dd_hw_if;
337 
338 	if (hwif->set_port)
339 		return hwif->set_port(dai->dd_cookie, cp);
340 
341 	return ENXIO;
342 }
343 
344 int
345 graphaudio_get_port(void *cookie, mixer_ctrl_t *cp)
346 {
347 	struct graphaudio_softc *sc = cookie;
348 	struct dai_device *dai = sc->sc_dai_codec;
349 	struct audio_hw_if *hwif = dai->dd_hw_if;
350 
351 	if (hwif->get_port)
352 		return hwif->get_port(dai->dd_cookie, cp);
353 
354 	return ENXIO;
355 }
356 
357 int
358 graphaudio_query_devinfo(void *cookie, mixer_devinfo_t *dip)
359 {
360 	struct graphaudio_softc *sc = cookie;
361 	struct dai_device *dai = sc->sc_dai_codec;
362 	struct audio_hw_if *hwif = dai->dd_hw_if;
363 
364 	if (hwif->query_devinfo)
365 		return hwif->query_devinfo(dai->dd_cookie, dip);
366 
367 	return ENXIO;
368 }
369 
370 int
371 graphaudio_get_props(void *cookie)
372 {
373 	struct graphaudio_softc *sc = cookie;
374 	struct dai_device *dai = sc->sc_dai_cpu;
375 	struct audio_hw_if *hwif = dai->dd_hw_if;
376 
377 	if (hwif->get_props)
378 		return hwif->get_props(dai->dd_cookie);
379 
380 	return 0;
381 }
382 
383 int
384 graphaudio_round_blocksize(void *cookie, int block)
385 {
386 	struct graphaudio_softc *sc = cookie;
387 	struct dai_device *dai = sc->sc_dai_cpu;
388 	struct audio_hw_if *hwif = dai->dd_hw_if;
389 
390 	if (hwif->round_blocksize)
391 		return hwif->round_blocksize(dai->dd_cookie, block);
392 
393 	return block;
394 }
395 
396 size_t
397 graphaudio_round_buffersize(void *cookie, int direction, size_t bufsize)
398 {
399 	struct graphaudio_softc *sc = cookie;
400 	struct dai_device *dai = sc->sc_dai_cpu;
401 	struct audio_hw_if *hwif = dai->dd_hw_if;
402 
403 	if (hwif->round_buffersize)
404 		return hwif->round_buffersize(dai->dd_cookie,
405 		    direction, bufsize);
406 
407 	return bufsize;
408 }
409 
410 int
411 graphaudio_trigger_output(void *cookie, void *start, void *end, int blksize,
412     void (*intr)(void *), void *arg, struct audio_params *param)
413 {
414 	struct graphaudio_softc *sc = cookie;
415 	struct dai_device *dai;
416 	struct audio_hw_if *hwif;
417 	int error;
418 
419 	dai = sc->sc_dai_codec;
420 	hwif = dai->dd_hw_if;
421 	if (hwif->trigger_output) {
422 		error = hwif->trigger_output(dai->dd_cookie,
423 		    start, end, blksize, intr, arg, param);
424 		if (error) {
425 			graphaudio_halt_output(cookie);
426 			return error;
427 		}
428 	}
429 
430 	dai = sc->sc_dai_cpu;
431 	hwif = dai->dd_hw_if;
432 	if (hwif->trigger_output) {
433 		error = hwif->trigger_output(dai->dd_cookie,
434 		    start, end, blksize, intr, arg, param);
435 		if (error) {
436 			graphaudio_halt_output(cookie);
437 			return error;
438 		}
439 	}
440 
441 	return 0;
442 }
443 
444 int
445 graphaudio_trigger_input(void *cookie, void *start, void *end, int blksize,
446     void (*intr)(void *), void *arg, struct audio_params *param)
447 {
448 	struct graphaudio_softc *sc = cookie;
449 	struct dai_device *dai;
450 	struct audio_hw_if *hwif;
451 	int error;
452 
453 	dai = sc->sc_dai_codec;
454 	hwif = dai->dd_hw_if;
455 	if (hwif->trigger_input) {
456 		error = hwif->trigger_input(dai->dd_cookie,
457 		    start, end, blksize, intr, arg, param);
458 		if (error) {
459 			graphaudio_halt_input(cookie);
460 			return error;
461 		}
462 	}
463 
464 	dai = sc->sc_dai_cpu;
465 	hwif = dai->dd_hw_if;
466 	if (hwif->trigger_input) {
467 		error = hwif->trigger_input(dai->dd_cookie,
468 		    start, end, blksize, intr, arg, param);
469 		if (error) {
470 			graphaudio_halt_input(cookie);
471 			return error;
472 		}
473 	}
474 
475 	return 0;
476 }
477 
478 int
479 graphaudio_halt_output(void *cookie)
480 {
481 	struct graphaudio_softc *sc = cookie;
482 	struct dai_device *dai;
483 	struct audio_hw_if *hwif;
484 
485 	dai = sc->sc_dai_codec;
486 	hwif = dai->dd_hw_if;
487 	if (hwif->halt_output)
488 		hwif->halt_output(dai->dd_cookie);
489 
490 	dai = sc->sc_dai_cpu;
491 	hwif = dai->dd_hw_if;
492 	if (hwif->halt_output)
493 		hwif->halt_output(dai->dd_cookie);
494 
495 	return 0;
496 }
497 
498 int
499 graphaudio_halt_input(void *cookie)
500 {
501 	struct graphaudio_softc *sc = cookie;
502 	struct dai_device *dai;
503 	struct audio_hw_if *hwif;
504 
505 	dai = sc->sc_dai_codec;
506 	hwif = dai->dd_hw_if;
507 	if (hwif->halt_input)
508 		hwif->halt_input(dai->dd_cookie);
509 
510 	dai = sc->sc_dai_cpu;
511 	hwif = dai->dd_hw_if;
512 	if (hwif->halt_input)
513 		hwif->halt_input(dai->dd_cookie);
514 
515 	return 0;
516 }
517