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