xref: /netbsd-src/sys/arch/evbarm/mini2440/audio_mini2440.c (revision 7433666e375b3ac4cc764df5a6726be98bc1cdd5)
177b78cdcSnisimura /*-
277b78cdcSnisimura  * Copyright (c) 2012 The NetBSD Foundation, Inc.
377b78cdcSnisimura  * All rights reserved.
477b78cdcSnisimura  *
577b78cdcSnisimura  * This code is derived from software contributed to The NetBSD Foundation
677b78cdcSnisimura  * by Paul Fleischer <paul@xpg.dk>
777b78cdcSnisimura  *
877b78cdcSnisimura  * Redistribution and use in source and binary forms, with or without
977b78cdcSnisimura  * modification, are permitted provided that the following conditions
1077b78cdcSnisimura  * are met:
1177b78cdcSnisimura  * 1. Redistributions of source code must retain the above copyright
1277b78cdcSnisimura  *    notice, this list of conditions and the following disclaimer.
1377b78cdcSnisimura  * 2. Redistributions in binary form must reproduce the above copyright
1477b78cdcSnisimura  *    notice, this list of conditions and the following disclaimer in the
1577b78cdcSnisimura  *    documentation and/or other materials provided with the distribution.
1677b78cdcSnisimura  *
1777b78cdcSnisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1877b78cdcSnisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1977b78cdcSnisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2077b78cdcSnisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2177b78cdcSnisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2277b78cdcSnisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377b78cdcSnisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477b78cdcSnisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2577b78cdcSnisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677b78cdcSnisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2777b78cdcSnisimura  * POSSIBILITY OF SUCH DAMAGE.
2877b78cdcSnisimura  */
2977b78cdcSnisimura 
3077b78cdcSnisimura #include <sys/cdefs.h>
3177b78cdcSnisimura #include <sys/param.h>
3277b78cdcSnisimura #include <sys/device.h>
3377b78cdcSnisimura #include <sys/fcntl.h>
3477b78cdcSnisimura #include <sys/audioio.h>
3577b78cdcSnisimura 
3677b78cdcSnisimura #include <sys/bus.h>
3777b78cdcSnisimura 
38e622eac4Sisaki #include <dev/audio/audio_if.h>
3977b78cdcSnisimura 
4077b78cdcSnisimura 
4177b78cdcSnisimura #include <dev/ic/uda1341var.h>
4277b78cdcSnisimura 
4377b78cdcSnisimura #include <arch/arm/s3c2xx0/s3c2440reg.h>
4477b78cdcSnisimura #include <arch/arm/s3c2xx0/s3c2440var.h>
4577b78cdcSnisimura 
4677b78cdcSnisimura #include <arch/arm/s3c2xx0/s3c2440_dma.h>
4777b78cdcSnisimura #include <arch/arm/s3c2xx0/s3c2440_i2s.h>
4877b78cdcSnisimura 
4977b78cdcSnisimura /*#define AUDIO_MINI2440_DEBUG*/
5077b78cdcSnisimura 
5177b78cdcSnisimura #ifdef AUDIO_MINI2440_DEBUG
5277b78cdcSnisimura #define DPRINTF(x) do {printf x; } while (/*CONSTCOND*/0)
5377b78cdcSnisimura #else
5477b78cdcSnisimura #define DPRINTF(s) do {} while (/*CONSTCOND*/0)
5577b78cdcSnisimura #endif
5677b78cdcSnisimura 
5777b78cdcSnisimura struct uda_softc {
5877b78cdcSnisimura 	device_t		sc_dev;
5977b78cdcSnisimura 	kmutex_t		sc_lock;
6077b78cdcSnisimura 	kmutex_t		sc_intr_lock;
6177b78cdcSnisimura 
6277b78cdcSnisimura 	struct uda1341_softc	sc_uda1341;
6377b78cdcSnisimura 
6477b78cdcSnisimura 	s3c2440_i2s_buf_t	sc_play_buf;
6577b78cdcSnisimura 	s3c2440_i2s_buf_t	sc_rec_buf;
6677b78cdcSnisimura 
6777b78cdcSnisimura 	void			*sc_i2s_handle;
6877b78cdcSnisimura };
6977b78cdcSnisimura 
7077b78cdcSnisimura int	uda_ssio_open(void *, int);
7177b78cdcSnisimura void	uda_ssio_close(void *);
72e622eac4Sisaki int	uda_ssio_query_format(void *, audio_format_query_t *);
73e622eac4Sisaki int	uda_ssio_set_format(void *, int,
74e622eac4Sisaki 		       const audio_params_t *, const audio_params_t *,
75e622eac4Sisaki 		       audio_filter_reg_t *, audio_filter_reg_t *);
7677b78cdcSnisimura int	uda_ssio_start_output(void *, void *, int, void (*)(void *),
7777b78cdcSnisimura 			      void *);
7877b78cdcSnisimura int	uda_ssio_start_input(void *, void *, int, void (*)(void *),
7977b78cdcSnisimura 			      void *);
8077b78cdcSnisimura int	uda_ssio_halt_output(void *);
8177b78cdcSnisimura int	uda_ssio_halt_input(void *);
8277b78cdcSnisimura int	uda_ssio_getdev(void *, struct audio_device *ret);
8377b78cdcSnisimura void*	uda_ssio_allocm(void *, int, size_t);
8477b78cdcSnisimura void	uda_ssio_freem(void *, void *, size_t);
8577b78cdcSnisimura size_t	uda_ssio_round_buffersize(void *, int, size_t);
86*d9a409bdSisaki int	uda_ssio_get_props(void *);
8777b78cdcSnisimura void	uda_ssio_get_locks(void *, kmutex_t**, kmutex_t**);
8877b78cdcSnisimura 
8977b78cdcSnisimura struct audio_hw_if uda1341_hw_if = {
906291b134Sisaki 	.open			= uda_ssio_open,
916291b134Sisaki 	.close			= uda_ssio_close,
92e622eac4Sisaki 	.query_format		= uda_ssio_query_format,
93e622eac4Sisaki 	.set_format		= uda_ssio_set_format,
946291b134Sisaki 	.start_output		= uda_ssio_start_output,
956291b134Sisaki 	.start_input		= uda_ssio_start_input,
966291b134Sisaki 	.halt_output		= uda_ssio_halt_output,
976291b134Sisaki 	.halt_input		= uda_ssio_halt_input,
986291b134Sisaki 	.getdev			= uda_ssio_getdev,
996291b134Sisaki 	.set_port		= uda1341_set_port,
1006291b134Sisaki 	.get_port		= uda1341_get_port,
1016291b134Sisaki 	.query_devinfo		= uda1341_query_devinfo,
1026291b134Sisaki 	.allocm			= uda_ssio_allocm,
1036291b134Sisaki 	.freem			= uda_ssio_freem,
1046291b134Sisaki 	.round_buffersize	= uda_ssio_round_buffersize,
105*d9a409bdSisaki 	.get_props		= uda_ssio_get_props,
1066291b134Sisaki 	.get_locks		= uda_ssio_get_locks
10777b78cdcSnisimura };
10877b78cdcSnisimura 
10977b78cdcSnisimura static struct audio_device uda1341_device = {
11077b78cdcSnisimura 	"MINI2240-UDA1341",
11177b78cdcSnisimura 	"0.1",
11277b78cdcSnisimura 	"uda_ssio"
11377b78cdcSnisimura };
11477b78cdcSnisimura 
115e622eac4Sisaki static const struct audio_format uda_ssio_formats[] =
116e622eac4Sisaki {
117e622eac4Sisaki 	{
118e622eac4Sisaki 		.mode		= AUMODE_PLAY | AUMODE_RECORD,
119e622eac4Sisaki 		.encoding	= AUDIO_ENCODING_SLINEAR_LE,
120e622eac4Sisaki 		.validbits	= 16,
121e622eac4Sisaki 		.precision	= 16,
122e622eac4Sisaki 		.channels	= 2,
123e622eac4Sisaki 		.channel_mask	= AUFMT_STEREO,
124e622eac4Sisaki 		.frequency_type	= 6,
125e622eac4Sisaki 		.frequency	= { 8000, 11025, 22050, 32000, 44100, 48000 },
126e622eac4Sisaki 	}
127e622eac4Sisaki };
128e622eac4Sisaki #define UDA_SSIO_NFORMATS __arraycount(uda_ssio_formats)
129e622eac4Sisaki 
13077b78cdcSnisimura void uda_ssio_l3_write(void *,int mode, int value);
13177b78cdcSnisimura 
13277b78cdcSnisimura int uda_ssio_match(device_t, cfdata_t, void*);
13377b78cdcSnisimura void uda_ssio_attach(device_t, device_t, void*);
13477b78cdcSnisimura 
13577b78cdcSnisimura CFATTACH_DECL_NEW(udassio, sizeof(struct uda_softc),
13677b78cdcSnisimura 	      uda_ssio_match, uda_ssio_attach, NULL, NULL);
13777b78cdcSnisimura 
13877b78cdcSnisimura int
uda_ssio_match(device_t parent,cfdata_t match,void * aux)13977b78cdcSnisimura uda_ssio_match(device_t parent, cfdata_t match, void *aux)
14077b78cdcSnisimura {
14177b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
14277b78cdcSnisimura 	/* Not quite sure how we can detect the UDA1341 chip */
14377b78cdcSnisimura 	return 1;
14477b78cdcSnisimura }
14577b78cdcSnisimura 
14677b78cdcSnisimura void
uda_ssio_attach(device_t parent,device_t self,void * aux)14777b78cdcSnisimura uda_ssio_attach(device_t parent, device_t self, void *aux)
14877b78cdcSnisimura {
14977b78cdcSnisimura 	/*	struct s3c2xx0_attach_args *sa = aux;*/
15077b78cdcSnisimura 	struct uda_softc *sc = device_private(self);
15177b78cdcSnisimura 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
15277b78cdcSnisimura 	struct s3c2440_i2s_attach_args *aa = aux;
15377b78cdcSnisimura 	uint32_t reg;
15477b78cdcSnisimura 
15577b78cdcSnisimura 	sc->sc_dev = self;
15677b78cdcSnisimura 
15777b78cdcSnisimura 	sc->sc_play_buf = NULL;
15877b78cdcSnisimura 	sc->sc_i2s_handle = aa->i2sa_handle;
15977b78cdcSnisimura 
16077b78cdcSnisimura 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
16177b78cdcSnisimura 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
16277b78cdcSnisimura 
16377b78cdcSnisimura 	s3c2440_i2s_set_intr_lock(aa->i2sa_handle, &sc->sc_intr_lock);
16477b78cdcSnisimura 
16577b78cdcSnisimura 	/* arch/arm/s3c2xx0/s3c2440.c initializes the I2S subsystem for us */
16677b78cdcSnisimura 
16777b78cdcSnisimura 	/* Setup GPIO pins to output for L3 communication.
16877b78cdcSnisimura 	   GPB3 (L3DATA) will have to be switched to input when reading
16977b78cdcSnisimura 	   from the L3 bus.
17077b78cdcSnisimura 
17177b78cdcSnisimura 	   GPB2 - L3MODE
17277b78cdcSnisimura 	   GPB3 - L3DATA
17377b78cdcSnisimura 	   GPB4 - L3CLOCK
17477b78cdcSnisimura 	   TODO: Make this configurable
17577b78cdcSnisimura 	*/
17677b78cdcSnisimura 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON);
17777b78cdcSnisimura 	reg = GPIO_SET_FUNC(reg, 2, 1);
17877b78cdcSnisimura 	reg = GPIO_SET_FUNC(reg, 3, 1);
17977b78cdcSnisimura 	reg = GPIO_SET_FUNC(reg, 4, 1);
18077b78cdcSnisimura 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON, reg);
18177b78cdcSnisimura 
18277b78cdcSnisimura 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT);
18377b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, 4, 1);
18477b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, 3, 0);
18577b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, 2, 1);
18677b78cdcSnisimura 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, reg);
18777b78cdcSnisimura 
18877b78cdcSnisimura 	printf("\n");
18977b78cdcSnisimura 
19077b78cdcSnisimura 	/* uda1341_attach resets the uda1341 sc, so it has to be called before
19177b78cdcSnisimura 	   attributes are set on the sc.*/
19277b78cdcSnisimura 	uda1341_attach(&sc->sc_uda1341);
19377b78cdcSnisimura 
19477b78cdcSnisimura 	/* Configure the UDA1341 Codec */
19577b78cdcSnisimura 	sc->sc_uda1341.parent = sc;
19677b78cdcSnisimura 	sc->sc_uda1341.sc_l3_write = uda_ssio_l3_write;
19777b78cdcSnisimura 	sc->sc_uda1341.sc_bus_format = UDA1341_BUS_MSB;
19877b78cdcSnisimura 
19977b78cdcSnisimura 	/* Configure I2S controller */
20077b78cdcSnisimura 	s3c2440_i2s_set_bus_format(sc->sc_i2s_handle, S3C2440_I2S_BUS_MSB);
20177b78cdcSnisimura 	// Attach
20277b78cdcSnisimura 	audio_attach_mi(&uda1341_hw_if, &sc->sc_uda1341, self);
20377b78cdcSnisimura }
20477b78cdcSnisimura 
20577b78cdcSnisimura int
uda_ssio_open(void * handle,int flags)20677b78cdcSnisimura uda_ssio_open(void *handle, int flags)
20777b78cdcSnisimura {
20877b78cdcSnisimura 	int retval;
20977b78cdcSnisimura 
21077b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
21177b78cdcSnisimura 
21277b78cdcSnisimura 	/* We only support write operations */
21377b78cdcSnisimura 	if (!(flags & FREAD) && !(flags & FWRITE))
21477b78cdcSnisimura 		return EINVAL;
21577b78cdcSnisimura 
21677b78cdcSnisimura 	/* We can't do much more at this point than to
21777b78cdcSnisimura 	   ask the UDA1341 codec to initialize itself
21877b78cdcSnisimura 	   (for an unknown system clock)
21977b78cdcSnisimura 	*/
22077b78cdcSnisimura 	retval = uda1341_open(handle, flags);
22177b78cdcSnisimura 	if (retval != 0) {
22277b78cdcSnisimura 		return retval;
22377b78cdcSnisimura 	}
22477b78cdcSnisimura 
22577b78cdcSnisimura 	return 0; /* SUCCESS */
22677b78cdcSnisimura }
22777b78cdcSnisimura 
22877b78cdcSnisimura void
uda_ssio_close(void * handle)22977b78cdcSnisimura uda_ssio_close(void *handle)
23077b78cdcSnisimura {
231e622eac4Sisaki 
23277b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
23377b78cdcSnisimura 
23477b78cdcSnisimura 	uda1341_close(handle);
23577b78cdcSnisimura }
23677b78cdcSnisimura 
23777b78cdcSnisimura int
uda_ssio_query_format(void * handle,audio_format_query_t * afp)238e622eac4Sisaki uda_ssio_query_format(void *handle, audio_format_query_t *afp)
239e622eac4Sisaki {
240e622eac4Sisaki 
241e622eac4Sisaki 	return audio_query_format(uda_ssio_formats, UDA_SSIO_NFORMATS, afp);
242e622eac4Sisaki }
243e622eac4Sisaki 
244e622eac4Sisaki int
uda_ssio_set_format(void * handle,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)245e622eac4Sisaki uda_ssio_set_format(void *handle, int setmode,
246e622eac4Sisaki 		    const audio_params_t *play, const audio_params_t *rec,
247e622eac4Sisaki 		    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
24877b78cdcSnisimura {
24977b78cdcSnisimura 	struct uda1341_softc *uc = handle;
25077b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
25177b78cdcSnisimura 	int retval;
25277b78cdcSnisimura 
25377b78cdcSnisimura 	DPRINTF(("%s: setmode: %d\n", __func__, setmode));
25477b78cdcSnisimura 
255e622eac4Sisaki 	/* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
25677b78cdcSnisimura 
25777b78cdcSnisimura 	DPRINTF(("%s: %dHz, encoding: %d, precision: %d, channels: %d\n",
258e622eac4Sisaki 		 __func__, play->sample_rate, play->encoding, play->precision,
259e622eac4Sisaki 		 play->channels));
26077b78cdcSnisimura 
26177b78cdcSnisimura 	if (setmode == AUMODE_PLAY) {
26277b78cdcSnisimura 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
26377b78cdcSnisimura 					  S3C2440_I2S_TRANSMIT);
26477b78cdcSnisimura 	} else {
26577b78cdcSnisimura 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
26677b78cdcSnisimura 					  S3C2440_I2S_RECEIVE);
26777b78cdcSnisimura 	}
26877b78cdcSnisimura 
269e622eac4Sisaki 	s3c2440_i2s_set_sample_rate(sc->sc_i2s_handle, play->sample_rate);
270e622eac4Sisaki 	s3c2440_i2s_set_sample_width(sc->sc_i2s_handle, 16);
27177b78cdcSnisimura 
27277b78cdcSnisimura 	/* It is vital that sc_system_clock is set PRIOR to calling
273e622eac4Sisaki 	   uda1341_set_format. */
27477b78cdcSnisimura 	switch (s3c2440_i2s_get_master_clock(sc->sc_i2s_handle)) {
27577b78cdcSnisimura 	case 384:
27677b78cdcSnisimura 		uc->sc_system_clock = UDA1341_CLOCK_384;
27777b78cdcSnisimura 		break;
27877b78cdcSnisimura 	case 256:
27977b78cdcSnisimura 		uc->sc_system_clock = UDA1341_CLOCK_256;
28077b78cdcSnisimura 		break;
28177b78cdcSnisimura 	default:
28277b78cdcSnisimura 		return EINVAL;
28377b78cdcSnisimura 	}
28477b78cdcSnisimura 
285e622eac4Sisaki 	retval = uda1341_set_format(handle, setmode, play, rec, pfil, rfil);
28677b78cdcSnisimura 	if (retval != 0) {
28777b78cdcSnisimura 		return retval;
28877b78cdcSnisimura 	}
28977b78cdcSnisimura 
29077b78cdcSnisimura 	/* Setup and enable I2S controller */
29177b78cdcSnisimura 	retval = s3c2440_i2s_commit(sc->sc_i2s_handle);
29277b78cdcSnisimura 	if (retval != 0) {
29377b78cdcSnisimura 		printf("Failed to setup I2S controller\n");
29477b78cdcSnisimura 		return retval;
29577b78cdcSnisimura 	}
29677b78cdcSnisimura 
29777b78cdcSnisimura 	return 0;
29877b78cdcSnisimura }
29977b78cdcSnisimura 
30077b78cdcSnisimura int
uda_ssio_start_output(void * handle,void * block,int bsize,void (* intr)(void *),void * intrarg)30177b78cdcSnisimura uda_ssio_start_output(void *handle, void *block, int bsize,
30277b78cdcSnisimura 		      void (*intr)(void *), void *intrarg)
30377b78cdcSnisimura {
30477b78cdcSnisimura 	struct uda1341_softc *uc = handle;
30577b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
30677b78cdcSnisimura 
30777b78cdcSnisimura 	return s3c2440_i2s_output(sc->sc_play_buf, block, bsize, intr, intrarg);
30877b78cdcSnisimura }
30977b78cdcSnisimura 
31077b78cdcSnisimura int
uda_ssio_start_input(void * handle,void * block,int bsize,void (* intr)(void *),void * intrarg)31177b78cdcSnisimura uda_ssio_start_input(void *handle, void *block, int bsize,
31277b78cdcSnisimura 		     void (*intr)(void *), void *intrarg)
31377b78cdcSnisimura {
31477b78cdcSnisimura 	struct uda1341_softc *uc = handle;
31577b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
31677b78cdcSnisimura 
31777b78cdcSnisimura 	return s3c2440_i2s_input(sc->sc_rec_buf, block, bsize, intr, intrarg);
31877b78cdcSnisimura }
31977b78cdcSnisimura 
32077b78cdcSnisimura int
uda_ssio_halt_output(void * handle)32177b78cdcSnisimura uda_ssio_halt_output(void *handle)
32277b78cdcSnisimura {
32377b78cdcSnisimura 	struct uda1341_softc *uc = handle;
32477b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
32577b78cdcSnisimura 
32677b78cdcSnisimura 	return s3c2440_i2s_halt_output(sc->sc_play_buf);
32777b78cdcSnisimura }
32877b78cdcSnisimura 
32977b78cdcSnisimura int
uda_ssio_halt_input(void * handle)33077b78cdcSnisimura uda_ssio_halt_input(void *handle)
33177b78cdcSnisimura {
33277b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
33377b78cdcSnisimura 	return 0;
33477b78cdcSnisimura }
33577b78cdcSnisimura 
33677b78cdcSnisimura int
uda_ssio_getdev(void * handle,struct audio_device * ret)33777b78cdcSnisimura uda_ssio_getdev(void *handle, struct audio_device *ret)
33877b78cdcSnisimura {
33977b78cdcSnisimura 	*ret = uda1341_device;
34077b78cdcSnisimura 	return 0;
34177b78cdcSnisimura }
34277b78cdcSnisimura 
34377b78cdcSnisimura void *
uda_ssio_allocm(void * handle,int direction,size_t size)34477b78cdcSnisimura uda_ssio_allocm(void *handle, int direction, size_t size)
34577b78cdcSnisimura {
34677b78cdcSnisimura 	struct uda1341_softc *uc = handle;
34777b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
34877b78cdcSnisimura 	void *retval = NULL;
34977b78cdcSnisimura 
35077b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
35177b78cdcSnisimura 
35277b78cdcSnisimura 	if (direction == AUMODE_PLAY ) {
35377b78cdcSnisimura 		if (sc->sc_play_buf != NULL)
35477b78cdcSnisimura 			return NULL;
35577b78cdcSnisimura 
35677b78cdcSnisimura 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_play_buf);
35777b78cdcSnisimura 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_play_buf->i2b_addr));
35877b78cdcSnisimura 		retval = sc->sc_play_buf->i2b_addr;
35977b78cdcSnisimura 	} else if (direction == AUMODE_RECORD) {
36077b78cdcSnisimura 		if (sc->sc_rec_buf != NULL)
36177b78cdcSnisimura 			return NULL;
36277b78cdcSnisimura 
36377b78cdcSnisimura 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_rec_buf);
36477b78cdcSnisimura 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_rec_buf->i2b_addr));
36577b78cdcSnisimura 		retval = sc->sc_rec_buf->i2b_addr;
36677b78cdcSnisimura 	}
36777b78cdcSnisimura 
36877b78cdcSnisimura 	DPRINTF(("buffer: %p", retval));
36977b78cdcSnisimura 
37077b78cdcSnisimura 	return retval;
37177b78cdcSnisimura }
37277b78cdcSnisimura 
37377b78cdcSnisimura void
uda_ssio_freem(void * handle,void * ptr,size_t size)37477b78cdcSnisimura uda_ssio_freem(void *handle, void *ptr, size_t size)
37577b78cdcSnisimura {
37677b78cdcSnisimura 	struct uda1341_softc *uc = handle;
37777b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
37877b78cdcSnisimura 	DPRINTF(("%s\n", __func__));
37977b78cdcSnisimura 
38077b78cdcSnisimura 	if (ptr == sc->sc_play_buf->i2b_addr)
38177b78cdcSnisimura 		s3c2440_i2s_free(sc->sc_play_buf);
38277b78cdcSnisimura 	else if (ptr == sc->sc_rec_buf->i2b_addr)
38377b78cdcSnisimura 		s3c2440_i2s_free(sc->sc_rec_buf);
38477b78cdcSnisimura }
38577b78cdcSnisimura 
38677b78cdcSnisimura size_t
uda_ssio_round_buffersize(void * handle,int direction,size_t bufsize)38777b78cdcSnisimura uda_ssio_round_buffersize(void *handle, int direction, size_t bufsize)
38877b78cdcSnisimura {
38977b78cdcSnisimura 	DPRINTF(("%s: %d\n", __func__, (int)bufsize));
39077b78cdcSnisimura 	return bufsize;
39177b78cdcSnisimura }
39277b78cdcSnisimura 
39377b78cdcSnisimura int
uda_ssio_get_props(void * handle)394*d9a409bdSisaki uda_ssio_get_props(void *handle)
39577b78cdcSnisimura {
39677b78cdcSnisimura 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE;
39777b78cdcSnisimura }
39877b78cdcSnisimura 
39977b78cdcSnisimura void
uda_ssio_get_locks(void * handle,kmutex_t ** intr,kmutex_t ** thread)40077b78cdcSnisimura uda_ssio_get_locks(void *handle, kmutex_t **intr, kmutex_t **thread)
40177b78cdcSnisimura {
40277b78cdcSnisimura 	struct uda1341_softc *uc = handle;
40377b78cdcSnisimura 	struct uda_softc *sc = uc->parent;
40477b78cdcSnisimura 	//struct uda_softc *sc = handle;
40577b78cdcSnisimura 
40677b78cdcSnisimura 	*intr = &sc->sc_intr_lock;
40777b78cdcSnisimura 	*thread = &sc->sc_lock;
40877b78cdcSnisimura }
40977b78cdcSnisimura 
41077b78cdcSnisimura void
uda_ssio_l3_write(void * cookie,int mode,int value)41177b78cdcSnisimura uda_ssio_l3_write(void *cookie, int mode, int value)
41277b78cdcSnisimura {
41377b78cdcSnisimura 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
41477b78cdcSnisimura 	uint32_t reg;
41577b78cdcSnisimura 
41677b78cdcSnisimura 	/* GPB2: L3MODE
41777b78cdcSnisimura 	   GPB3: L2DATA
41877b78cdcSnisimura 	   GPB4: L3CLOCK */
41977b78cdcSnisimura #define L3MODE	2
42077b78cdcSnisimura #define L3DATA	3
42177b78cdcSnisimura #define L3CLOCK 4
42277b78cdcSnisimura #define READ_GPIO() bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT)
42377b78cdcSnisimura #define WRITE_GPIO(val) bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, val)
42477b78cdcSnisimura 
42577b78cdcSnisimura #define DELAY_TIME 1
42677b78cdcSnisimura 
42777b78cdcSnisimura 	reg = READ_GPIO();
42877b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
42977b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3MODE, mode);
43077b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
43177b78cdcSnisimura 	WRITE_GPIO(reg);
43277b78cdcSnisimura 
43377b78cdcSnisimura 	if (mode == 1 ) {
43477b78cdcSnisimura 		reg = READ_GPIO();
43577b78cdcSnisimura 		reg = GPIO_SET_DATA(reg, L3MODE, 1);
43677b78cdcSnisimura 		WRITE_GPIO(reg);
43777b78cdcSnisimura 	}
43877b78cdcSnisimura 
43977b78cdcSnisimura 	DELAY(1); /* L3MODE setup time: min 190ns */
44077b78cdcSnisimura 
44177b78cdcSnisimura 	for(int i = 0; i<8; i++) {
44277b78cdcSnisimura 		char bval = (value >> i) & 0x1;
44377b78cdcSnisimura 
44477b78cdcSnisimura 		reg = READ_GPIO();
44577b78cdcSnisimura 		reg = GPIO_SET_DATA(reg, L3CLOCK, 0);
44677b78cdcSnisimura 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
44777b78cdcSnisimura 		WRITE_GPIO(reg);
44877b78cdcSnisimura 
44977b78cdcSnisimura 		DELAY(DELAY_TIME);
45077b78cdcSnisimura 
45177b78cdcSnisimura 		reg = READ_GPIO();
45277b78cdcSnisimura 		reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
45377b78cdcSnisimura 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
45477b78cdcSnisimura 		WRITE_GPIO(reg);
45577b78cdcSnisimura 
45677b78cdcSnisimura 		DELAY(DELAY_TIME);
45777b78cdcSnisimura 	}
45877b78cdcSnisimura 
45977b78cdcSnisimura 	reg = READ_GPIO();
46077b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3MODE, 1);
46177b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
46277b78cdcSnisimura 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
46377b78cdcSnisimura 	WRITE_GPIO(reg);
46477b78cdcSnisimura 
46577b78cdcSnisimura #undef L3MODE
46677b78cdcSnisimura #undef L3DATA
46777b78cdcSnisimura #undef L3CLOCK
46877b78cdcSnisimura #undef DELAY_TIME
46977b78cdcSnisimura #undef READ_GPIO
47077b78cdcSnisimura #undef WRITE_GPIO
47177b78cdcSnisimura }
472