1*ede47d01Sisaki /* $NetBSD: zaudio.c,v 1.23 2019/06/08 08:02:37 isaki Exp $ */
2953d3b5bSober /* $OpenBSD: zaurus_audio.c,v 1.8 2005/08/18 13:23:02 robert Exp $ */
3953d3b5bSober
4953d3b5bSober /*
5953d3b5bSober * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org>
6953d3b5bSober *
7953d3b5bSober * Permission to use, copy, modify, and distribute this software for any
8953d3b5bSober * purpose with or without fee is hereby granted, provided that the above
9953d3b5bSober * copyright notice and this permission notice appear in all copies.
10953d3b5bSober *
11953d3b5bSober * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12953d3b5bSober * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13953d3b5bSober * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14953d3b5bSober * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15953d3b5bSober * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16953d3b5bSober * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17953d3b5bSober * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18953d3b5bSober */
19953d3b5bSober
2053f7d89dSnonaka /*-
217e1e52beSnonaka * Copyright (C) 2009 NONAKA Kimihiro <nonaka@netbsd.org>
2253f7d89dSnonaka * All rights reserved.
2353f7d89dSnonaka *
2453f7d89dSnonaka * Redistribution and use in source and binary forms, with or without
2553f7d89dSnonaka * modification, are permitted provided that the following conditions
2653f7d89dSnonaka * are met:
2753f7d89dSnonaka * 1. Redistributions of source code must retain the above copyright
2853f7d89dSnonaka * notice, this list of conditions and the following disclaimer.
2953f7d89dSnonaka * 2. Redistributions in binary form must reproduce the above copyright
3053f7d89dSnonaka * notice, this list of conditions and the following disclaimer in the
3153f7d89dSnonaka * documentation and/or other materials provided with the distribution.
3253f7d89dSnonaka *
337e1e52beSnonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
347e1e52beSnonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
357e1e52beSnonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
367e1e52beSnonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
377e1e52beSnonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
387e1e52beSnonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
397e1e52beSnonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
407e1e52beSnonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
417e1e52beSnonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
427e1e52beSnonaka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4353f7d89dSnonaka */
4453f7d89dSnonaka
45953d3b5bSober /*
46953d3b5bSober * TODO:
47953d3b5bSober * - powerhooks (currently only works until first suspend)
48953d3b5bSober */
49953d3b5bSober
5094ff29c8Snonaka #include "opt_cputypes.h"
51003bdf4cSnonaka
52953d3b5bSober #include <sys/cdefs.h>
53*ede47d01Sisaki __KERNEL_RCSID(0, "$NetBSD: zaudio.c,v 1.23 2019/06/08 08:02:37 isaki Exp $");
54953d3b5bSober
55953d3b5bSober #include <sys/param.h>
56953d3b5bSober #include <sys/systm.h>
5794ff29c8Snonaka #include <sys/audioio.h>
58953d3b5bSober #include <sys/callout.h>
59953d3b5bSober #include <sys/device.h>
60003bdf4cSnonaka #include <sys/mutex.h>
61953d3b5bSober
62e622eac4Sisaki #include <dev/audio/audio_if.h>
63003bdf4cSnonaka
64003bdf4cSnonaka #include <dev/i2c/i2cvar.h>
65953d3b5bSober
66953d3b5bSober #include <arm/xscale/pxa2x0reg.h>
67953d3b5bSober #include <arm/xscale/pxa2x0var.h>
68953d3b5bSober #include <arm/xscale/pxa2x0_i2s.h>
69953d3b5bSober
70003bdf4cSnonaka #include <zaurus/zaurus/zaurus_var.h>
7194ff29c8Snonaka #include <zaurus/dev/zaudiovar.h>
7294ff29c8Snonaka #if defined(CPU_XSCALE_PXA270)
7394ff29c8Snonaka #include <zaurus/dev/wm8750var.h>
7494ff29c8Snonaka #endif
7594ff29c8Snonaka #if defined(CPU_XSCALE_PXA250)
7694ff29c8Snonaka #include <zaurus/dev/wm8731var.h>
7794ff29c8Snonaka #endif
78003bdf4cSnonaka
79003bdf4cSnonaka static int zaudio_match(device_t, cfdata_t, void *);
80003bdf4cSnonaka static void zaudio_attach(device_t, device_t, void *);
81003bdf4cSnonaka
821a686006Snonaka CFATTACH_DECL_NEW(zaudio, sizeof(struct zaudio_softc),
83664df27bSnonaka zaudio_match, zaudio_attach, NULL, NULL);
84953d3b5bSober
85e622eac4Sisaki static const struct audio_format zaudio_formats[] = {
86e622eac4Sisaki {
87e622eac4Sisaki .mode = AUMODE_PLAY | AUMODE_RECORD,
88e622eac4Sisaki .encoding = AUDIO_ENCODING_SLINEAR_LE,
89e622eac4Sisaki .validbits = 16,
90e622eac4Sisaki .precision = 16,
91e622eac4Sisaki .channels = 2,
92e622eac4Sisaki .channel_mask = AUFMT_STEREO,
93e622eac4Sisaki .frequency_type = 6,
94e622eac4Sisaki .frequency = { 8000, 11025, 16000, 22050, 44100, 48000 },
95e622eac4Sisaki }
96e622eac4Sisaki };
97e622eac4Sisaki #define ZAUDIO_NFORMATS __arraycount(zaudio_formats)
98e622eac4Sisaki
99953d3b5bSober static int
zaudio_match(device_t parent,cfdata_t cf,void * aux)1001a686006Snonaka zaudio_match(device_t parent, cfdata_t cf, void *aux)
101953d3b5bSober {
102003bdf4cSnonaka struct i2c_attach_args *ia = aux;
103953d3b5bSober
10494ff29c8Snonaka if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
10594ff29c8Snonaka #if defined(CPU_XSCALE_PXA270)
10694ff29c8Snonaka return wm8750_match(parent, cf, ia);
10794ff29c8Snonaka #endif
10894ff29c8Snonaka } else if (ZAURUS_ISC860) {
10994ff29c8Snonaka #if defined(CPU_XSCALE_PXA250)
11094ff29c8Snonaka return wm8731_match(parent, cf, ia);
11194ff29c8Snonaka #endif
112003bdf4cSnonaka }
113003bdf4cSnonaka return 0;
114953d3b5bSober }
115953d3b5bSober
116953d3b5bSober static void
zaudio_attach(device_t parent,device_t self,void * aux)1171a686006Snonaka zaudio_attach(device_t parent, device_t self, void *aux)
118953d3b5bSober {
1191a686006Snonaka struct zaudio_softc *sc = device_private(self);
120003bdf4cSnonaka struct i2c_attach_args *ia = aux;
121953d3b5bSober
12294ff29c8Snonaka sc->sc_dev = self;
123003bdf4cSnonaka sc->sc_i2c = ia->ia_tag;
12494ff29c8Snonaka
1258a962f23Sjmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1268a962f23Sjmcneill mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
12794ff29c8Snonaka callout_init(&sc->sc_to, 0);
1281a686006Snonaka
129003bdf4cSnonaka sc->sc_i2s.sc_iot = &pxa2x0_bs_tag;
130003bdf4cSnonaka sc->sc_i2s.sc_dmat = &pxa2x0_bus_dma_tag;
131953d3b5bSober sc->sc_i2s.sc_size = PXA2X0_I2S_SIZE;
1328a962f23Sjmcneill sc->sc_i2s.sc_intr_lock = &sc->sc_intr_lock;
133953d3b5bSober if (pxa2x0_i2s_attach_sub(&sc->sc_i2s)) {
134003bdf4cSnonaka aprint_error_dev(self, "unable to attach I2S\n");
135953d3b5bSober return;
136953d3b5bSober }
137953d3b5bSober
13894ff29c8Snonaka if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
13994ff29c8Snonaka #if defined(CPU_XSCALE_PXA270)
14094ff29c8Snonaka wm8750_attach(parent, self, ia);
141003bdf4cSnonaka #endif
14294ff29c8Snonaka } else if (ZAURUS_ISC860) {
14394ff29c8Snonaka #if defined(CPU_XSCALE_PXA250)
14494ff29c8Snonaka wm8731_attach(parent, self, ia);
14594ff29c8Snonaka #endif
146003bdf4cSnonaka }
147003bdf4cSnonaka
148953d3b5bSober return;
149953d3b5bSober }
150953d3b5bSober
151f19ed1a8Speter /*
152f19ed1a8Speter * audio operation functions.
153f19ed1a8Speter */
15494ff29c8Snonaka int
zaudio_open(void * hdl,int flags)155953d3b5bSober zaudio_open(void *hdl, int flags)
156953d3b5bSober {
157953d3b5bSober struct zaudio_softc *sc = hdl;
158953d3b5bSober
159953d3b5bSober /* Power on the I2S bus and codec */
160953d3b5bSober pxa2x0_i2s_open(&sc->sc_i2s);
161953d3b5bSober
162953d3b5bSober return 0;
163953d3b5bSober }
164953d3b5bSober
16594ff29c8Snonaka void
zaudio_close(void * hdl)166953d3b5bSober zaudio_close(void *hdl)
167953d3b5bSober {
168953d3b5bSober struct zaudio_softc *sc = hdl;
169953d3b5bSober
170953d3b5bSober /* Power off the I2S bus and codec */
171953d3b5bSober pxa2x0_i2s_close(&sc->sc_i2s);
172953d3b5bSober }
173953d3b5bSober
17494ff29c8Snonaka int
zaudio_query_format(void * hdl,audio_format_query_t * afp)175e622eac4Sisaki zaudio_query_format(void *hdl, audio_format_query_t *afp)
176e622eac4Sisaki {
177e622eac4Sisaki
178e622eac4Sisaki return audio_query_format(zaudio_formats, ZAUDIO_NFORMATS, afp);
179e622eac4Sisaki }
180e622eac4Sisaki
181e622eac4Sisaki int
zaudio_set_format(void * hdl,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)182e622eac4Sisaki zaudio_set_format(void *hdl, int setmode,
183e622eac4Sisaki const audio_params_t *play, const audio_params_t *rec,
184e622eac4Sisaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
185e622eac4Sisaki {
186e622eac4Sisaki struct zaudio_softc *sc = hdl;
187e622eac4Sisaki
188e622eac4Sisaki /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
189e622eac4Sisaki
190e622eac4Sisaki if (setmode == AUMODE_RECORD)
191e622eac4Sisaki pxa2x0_i2s_setspeed(&sc->sc_i2s, rec->sample_rate);
192e622eac4Sisaki else
193e622eac4Sisaki pxa2x0_i2s_setspeed(&sc->sc_i2s, play->sample_rate);
194e622eac4Sisaki
195e622eac4Sisaki return 0;
196e622eac4Sisaki }
197e622eac4Sisaki
198e622eac4Sisaki int
zaudio_round_blocksize(void * hdl,int bs,int mode,const audio_params_t * param)199f19ed1a8Speter zaudio_round_blocksize(void *hdl, int bs, int mode, const audio_params_t *param)
200953d3b5bSober {
201953d3b5bSober struct zaudio_softc *sc = hdl;
202953d3b5bSober
203f19ed1a8Speter return pxa2x0_i2s_round_blocksize(&sc->sc_i2s, bs, mode, param);
204953d3b5bSober }
205953d3b5bSober
20694ff29c8Snonaka void *
zaudio_allocm(void * hdl,int direction,size_t size)2078a962f23Sjmcneill zaudio_allocm(void *hdl, int direction, size_t size)
208f19ed1a8Speter {
209f19ed1a8Speter struct zaudio_softc *sc = hdl;
210f19ed1a8Speter
2118a962f23Sjmcneill return pxa2x0_i2s_allocm(&sc->sc_i2s, direction, size);
212f19ed1a8Speter }
213f19ed1a8Speter
21494ff29c8Snonaka void
zaudio_freem(void * hdl,void * ptr,size_t size)2158a962f23Sjmcneill zaudio_freem(void *hdl, void *ptr, size_t size)
216f19ed1a8Speter {
217f19ed1a8Speter struct zaudio_softc *sc = hdl;
218f19ed1a8Speter
2198a962f23Sjmcneill return pxa2x0_i2s_freem(&sc->sc_i2s, ptr, size);
220f19ed1a8Speter }
221f19ed1a8Speter
22294ff29c8Snonaka size_t
zaudio_round_buffersize(void * hdl,int direction,size_t bufsize)223f19ed1a8Speter zaudio_round_buffersize(void *hdl, int direction, size_t bufsize)
224f19ed1a8Speter {
225f19ed1a8Speter struct zaudio_softc *sc = hdl;
226f19ed1a8Speter
227f19ed1a8Speter return pxa2x0_i2s_round_buffersize(&sc->sc_i2s, direction, bufsize);
228f19ed1a8Speter }
229f19ed1a8Speter
23094ff29c8Snonaka int
zaudio_get_props(void * hdl)231953d3b5bSober zaudio_get_props(void *hdl)
232953d3b5bSober {
233f19ed1a8Speter
234*ede47d01Sisaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE;
235953d3b5bSober }
236953d3b5bSober
23794ff29c8Snonaka void
zaudio_get_locks(void * hdl,kmutex_t ** intr,kmutex_t ** thread)2388a962f23Sjmcneill zaudio_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread)
2398a962f23Sjmcneill {
2408a962f23Sjmcneill struct zaudio_softc *sc = hdl;
2418a962f23Sjmcneill
2428a962f23Sjmcneill *intr = &sc->sc_intr_lock;
2438a962f23Sjmcneill *thread = &sc->sc_lock;
2448a962f23Sjmcneill }
245