Module Name: src
Committed By: nisimura
Date: Sat Jan 28 08:37:22 UTC 2012
Modified Files:
src/sys/conf: files
Added Files:
src/sys/dev/ic: uda1341.c uda1341reg.h uda1341var.h
Log Message:
Add UDA1341TS audio CODEC support. Code is written by
Paul Fleischer.
To generate a diff of this commit:
cvs rdiff -u -r1.1039 -r1.1040 src/sys/conf/files
cvs rdiff -u -r0 -r1.1 src/sys/dev/ic/uda1341.c src/sys/dev/ic/uda1341reg.h \
src/sys/dev/ic/uda1341var.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1039 src/sys/conf/files:1.1040
--- src/sys/conf/files:1.1039 Sun Jan 22 06:44:30 2012
+++ src/sys/conf/files Sat Jan 28 08:37:22 2012
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1039 2012/01/22 06:44:30 christos Exp $
+# $NetBSD: files,v 1.1040 2012/01/28 08:37:22 nisimura Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -913,6 +913,10 @@ file dev/ic/cs4231.c audiocs
define ac97
file dev/ic/ac97.c ac97
+# UDA1341 CODEC support
+define uda1341
+file dev/ic/uda1341.c uda1341
+
# Oki MSM6258 support code
#
define msm6258
Added files:
Index: src/sys/dev/ic/uda1341.c
diff -u /dev/null src/sys/dev/ic/uda1341.c:1.1
--- /dev/null Sat Jan 28 08:37:22 2012
+++ src/sys/dev/ic/uda1341.c Sat Jan 28 08:37:22 2012
@@ -0,0 +1,762 @@
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Fleischer <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/audioio.h>
+#include <sys/fcntl.h>
+
+#include <dev/audio_if.h>
+
+#include <dev/ic/uda1341var.h>
+#include <dev/ic/uda1341reg.h>
+
+/*#define UDA1341_DEBUG*/
+
+#ifdef UDA1341_DEBUG
+#define DPRINTF(x) do {printf x; } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s) do {} while (/*CONSTCOND*/0)
+#endif
+
+const struct audio_format uda1341_formats[UDA1341_NFORMATS] =
+{
+ {NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 8, 8, 2,
+ AUFMT_STEREO, 0, {8000, 48000}
+ },
+ {NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 2,
+ AUFMT_STEREO, 0, {8000, 48000}
+ },
+ {NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8, 2,
+ AUFMT_STEREO, 0, {8000, 48000}
+ },
+ {NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 16, 16, 2,
+ AUFMT_STEREO, 0, {8000, 48000}
+ },
+};
+
+static void uda1341_update_sound_settings(struct uda1341_softc *sc);
+
+
+int
+uda1341_attach(struct uda1341_softc *sc)
+{
+ sc->sc_system_clock = UDA1341_CLOCK_NA;
+ sc->sc_l3_write = NULL;
+ sc->sc_volume = 127;
+ sc->sc_bass = 0;
+ sc->sc_treble = 0;
+ sc->sc_mode = 0;
+ sc->sc_mute = 0;
+ sc->sc_ogain = 0;
+ sc->sc_deemphasis = UDA1341_DEEMPHASIS_AUTO;
+ sc->sc_dac_power = 0;
+ sc->sc_adc_power = 0;
+ sc->sc_inmix1 = 0;
+ sc->sc_inmix2 = 0;
+ sc->sc_micvol = 0;
+ sc->sc_inmode = 0;
+ sc->sc_agc = 0;
+ sc->sc_agc_lvl = 0;
+ sc->sc_ch2_gain = 0;
+
+ return 0;
+}
+
+int
+uda1341_query_encodings(void *handle, audio_encoding_t *ae)
+{
+ switch(ae->index) {
+ case 0:
+ strlcpy(ae->name, AudioEmulaw, sizeof(ae->name));
+ ae->encoding = AUDIO_ENCODING_ULAW;
+ ae->precision = 8;
+ ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 1:
+ strlcpy(ae->name, AudioEslinear_le, sizeof(ae->name));
+ ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ ae->precision = 8;
+ ae->flags = 0;
+ break;
+ case 2:
+ strlcpy(ae->name, AudioEslinear_le, sizeof(ae->name));
+ ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ ae->precision = 16;
+ ae->flags = 0;
+ break;
+ case 3:
+ strlcpy(ae->name, AudioEulinear_le, sizeof(ae->name));
+ ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ ae->precision = 8;
+ ae->flags = 0;
+ break;
+ case 4:
+ strlcpy(ae->name, AudioEulinear_le, sizeof(ae->name));
+ ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ ae->precision = 16;
+ ae->flags = 0;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int
+uda1341_open(void *handle, int flags)
+{
+ struct uda1341_softc *sc = handle;
+
+ /* Reset the UDA1341 */
+ sc->sc_l3_write(sc, 0, UDA1341_L3_ADDR_DEVICE |
+ UDA1341_L3_ADDR_STATUS);
+ sc->sc_l3_write(sc, 1,
+ UDA1341_L3_STATUS0 |
+ UDA1341_L3_STATUS0_RST);
+
+ if (flags & FREAD) {
+ sc->sc_adc_power = 1;
+ }
+ if (flags & FWRITE) {
+ sc->sc_dac_power = 1;
+ }
+
+#if 0
+ /* Power on DAC */
+ sc->sc_l3_write(sc, 1,
+ UDA1341_L3_STATUS1 | UDA1341_L3_STATUS1_PC_DAC);
+#endif
+ uda1341_update_sound_settings(sc);
+
+#if 0
+ /* TODO: Add mixer support */
+ sc->sc_l3_write(sc, 0, 0x14 | 0x0);
+ sc->sc_l3_write(sc, 1, 0x15); /* Volume */
+#endif
+
+ return 0;
+}
+
+void
+uda1341_close(void *handle)
+{
+ struct uda1341_softc *sc = handle;
+ /* Reset the UDA1341 */
+ sc->sc_l3_write(sc, 0, UDA1341_L3_ADDR_DEVICE |
+ UDA1341_L3_ADDR_STATUS);
+
+ /* Power off DAC and ADC*/
+ sc->sc_l3_write(sc, 1,
+ UDA1341_L3_STATUS1);
+
+ sc->sc_dac_power = 0;
+ sc->sc_adc_power = 0;
+}
+
+int
+uda1341_set_params(void *handle, int setmode, int usemode,
+ audio_params_t *play, audio_params_t *rec,
+ stream_filter_list_t *pfil, stream_filter_list_t *rfil)
+{
+ struct uda1341_softc *sc = handle;
+ if (sc->sc_system_clock == UDA1341_CLOCK_NA)
+ panic("uda1341_set_params was called without sc_system_clock set!\n");
+
+ /* Select status register */
+ sc->sc_l3_write(sc, 0, UDA1341_L3_ADDR_DEVICE |
+ UDA1341_L3_ADDR_STATUS);
+
+ sc->sc_l3_write(sc, 1, UDA1341_L3_STATUS0 |
+ sc->sc_system_clock << UDA1341_L3_STATUS0_SC_SHIFT |
+ sc->sc_bus_format << UDA1341_L3_STATUS0_IF_SHIFT
+ );
+
+ if (sc->sc_sample_rate_approx != play->sample_rate) {
+ sc->sc_sample_rate_approx = play->sample_rate;
+ uda1341_update_sound_settings(sc);
+ }
+
+ return 0;
+}
+
+#define AUDIO_LEVELS (AUDIO_MAX_GAIN-AUDIO_MIN_GAIN+1)
+static void
+uda1341_update_sound_settings(struct uda1341_softc *sc)
+{
+ /* TODO: Refactor this function into smaller parts, such that
+ * a volume change does not trigger updates of all the
+ * other -- unrelated -- registers.
+ */
+
+ uint8_t val, volume, bass, treble, deemphasis;
+
+ sc->sc_l3_write(sc, 0, UDA1341_L3_ADDR_DEVICE | UDA1341_L3_ADDR_STATUS);
+ val = UDA1341_L3_STATUS1;
+ if (sc->sc_dac_power)
+ val |= UDA1341_L3_STATUS1_PC_DAC;
+ if (sc->sc_adc_power)
+ val |= UDA1341_L3_STATUS1_PC_ADC;
+ if (sc->sc_ogain)
+ val |= UDA1341_L3_STATUS1_OGS_6DB;
+
+ sc->sc_l3_write(sc, 1, val);
+
+ sc->sc_l3_write(sc, 0, UDA1341_L3_ADDR_DEVICE | UDA1341_L3_ADDR_DATA0);
+
+ /* Update volume */
+ /* On the UDA1341 maximal volume is 0x0,
+ while minimal volume is 0x3f */
+ volume = (0x3f) - ((sc->sc_volume*(0x3f+1)) / (AUDIO_LEVELS));
+
+ val = UDA1341_L3_DATA0_VOLUME;
+ val |= volume & UDA1341_L3_DATA0_VOLUME_MASK;
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Update bass and treble */
+ bass = (sc->sc_bass*(0xf+1)) / AUDIO_LEVELS;
+ treble = (sc->sc_treble*(0x3+1)) / AUDIO_LEVELS;
+ val = UDA1341_L3_DATA0_BASS_TREBLE;
+ val |= (bass << UDA1341_L3_DATA0_BASS_SHIFT) &
+ UDA1341_L3_DATA0_BASS_MASK;
+ val |= (treble << UDA1341_L3_DATA0_TREBLE_SHIFT) &
+ UDA1341_L3_DATA0_TREBLE_MASK;
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Update the remaining output sound controls:
+ * - Peak-detect position
+ * - De-emphasis
+ * - Mute
+ * - Mode Switch
+ * XXX: Only Mode-switch, de-emphasis, and mute is currently supported.
+ */
+ val = UDA1341_L3_DATA0_SOUNDC;
+
+ deemphasis = sc->sc_deemphasis;
+ if( deemphasis == UDA1341_DEEMPHASIS_AUTO) {
+ /* Set deemphasis according to current sample rate */
+ switch (sc->sc_sample_rate_approx) {
+ case 32000:
+ deemphasis = 0x1;
+ break;
+ case 44100:
+ deemphasis = 0x2;
+ break;
+ case 48000:
+ deemphasis = 0x3;
+ break;
+ default:
+ deemphasis = 0x0;
+ }
+ }
+
+ DPRINTF(("Deemphasis: %d\n", deemphasis));
+ val |= (deemphasis << UDA1341_L3_DATA0_SOUNDC_DE_SHIFT) &
+ UDA1341_L3_DATA0_SOUNDC_DE_MASK;
+
+ if (sc->sc_mute)
+ val |= UDA1341_L3_DATA0_SOUNDC_MUTE;
+ val |= sc->sc_mode & UDA1341_L3_DATA0_SOUNDC_MODE_MASK;
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 0: MA */
+ val = UDA1341_L3_DATA0_ED;
+ val |= (sc->sc_inmix1 & UDA1341_L3_DATA0_MA_MASK);
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x0);
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 1: MB */
+ val = UDA1341_L3_DATA0_ED;
+ val |= (sc->sc_inmix2 & UDA1341_L3_DATA0_MB_MASK);
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x01);
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 2: MIC sensitivity and mixer mode */
+ val = UDA1341_L3_DATA0_ED;
+ val |= (sc->sc_micvol << UDA1341_L3_DATA0_MS_SHIFT) &
+ UDA1341_L3_DATA0_MS_MASK;
+ val |= sc->sc_inmode & UDA1341_L3_DATA0_MM_MASK;
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x02);
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 4: AGC and IG (ch2_gain) */
+ val = UDA1341_L3_DATA0_ED;
+
+ val |= (sc->sc_agc << UDA1341_L3_DATA0_AGC_SHIFT) &
+ UDA1341_L3_DATA0_AGC_MASK;
+ val |= (sc->sc_ch2_gain & 0x03) & UDA1341_L3_DATA0_IG_LOW_MASK;
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x04);
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 5: IG (ch2_gain) */
+ val = UDA1341_L3_DATA0_ED;
+ val |= (sc->sc_ch2_gain >> 2 ) & UDA1341_L3_DATA0_IG_HIGH_MASK;
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x05);
+ sc->sc_l3_write(sc, 1, val);
+
+ /* Extended Register 6: AT and AL */
+ /* XXX: Only AL is supported at this point */
+ val = UDA1341_L3_DATA0_ED;
+ val |= sc->sc_agc_lvl & UDA1341_L3_DATA0_AL_MASK;
+ sc->sc_l3_write(sc, 1, UDA1341_L3_DATA0_EA | 0x06);
+ sc->sc_l3_write(sc, 1, val);
+}
+
+#define UDA1341_MIXER_VOL 0
+#define UDA1341_MIXER_BASS 1
+#define UDA1341_MIXER_TREBLE 2
+#define UDA1341_MIXER_MODE 3
+#define UDA1341_MIXER_MUTE 4
+#define UDA1341_MIXER_OGAIN 5
+#define UDA1341_MIXER_DE 6
+#define UDA1341_OUTPUT_CLASS 7
+
+#define UDA1341_MIXER_INMIX1 8
+#define UDA1341_MIXER_INMIX2 9
+#define UDA1341_MIXER_MICVOL 10
+#define UDA1341_MIXER_INMODE 11
+#define UDA1341_MIXER_AGC 12
+#define UDA1341_MIXER_AGC_LVL 13
+#define UDA1341_MIXER_IN_GAIN2 14
+/*#define UDA1341_MIXER_AGC_SETTINGS 15*/
+#define UDA1341_INPUT_CLASS 15
+
+int
+uda1341_query_devinfo(void *handle, mixer_devinfo_t *mi)
+{
+
+ switch(mi->index) {
+ case UDA1341_MIXER_VOL:
+ strlcpy(mi->label.name, AudioNspeaker,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_BASS;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/64;
+ break;
+ case UDA1341_MIXER_BASS:
+ strlcpy(mi->label.name, AudioNbass,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_TREBLE;
+ mi->prev = UDA1341_MIXER_VOL;
+ strlcpy(mi->un.v.units.name, AudioNbass,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/16;
+ break;
+ case UDA1341_MIXER_TREBLE:
+ strlcpy(mi->label.name, AudioNtreble,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_MODE;
+ mi->prev = UDA1341_MIXER_BASS;
+ strlcpy(mi->un.v.units.name, AudioNtreble,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/4;
+ break;
+ case UDA1341_MIXER_MODE:
+ strlcpy(mi->label.name, AudioNmode,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_MUTE;
+ mi->prev = UDA1341_MIXER_TREBLE;
+ mi->un.e.num_mem = 3;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "flat", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "minimum", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+
+ strlcpy(mi->un.e.member[2].label.name,
+ "maximum", sizeof(mi->un.e.member[2].label.name));
+ mi->un.e.member[2].ord = 3;
+
+ break;
+ case UDA1341_MIXER_MUTE:
+ strlcpy(mi->label.name, AudioNmute,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_OGAIN;
+ mi->prev = UDA1341_MIXER_MODE;
+ mi->un.e.num_mem = 2;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "off", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "on", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+ break;
+ case UDA1341_MIXER_OGAIN:
+ strlcpy(mi->label.name, "gain",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = UDA1341_MIXER_DE;
+ mi->prev = UDA1341_MIXER_MUTE;
+ mi->un.e.num_mem = 2;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "off", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "on", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+ break;
+ case UDA1341_MIXER_DE:
+ strlcpy(mi->label.name, "deemphasis",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = UDA1341_MIXER_OGAIN;
+ mi->un.e.num_mem = 5;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "none", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "32KHz", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+
+ strlcpy(mi->un.e.member[2].label.name,
+ "44.1KHz", sizeof(mi->un.e.member[2].label.name));
+ mi->un.e.member[2].ord = 2;
+
+ strlcpy(mi->un.e.member[3].label.name,
+ "48KHz", sizeof(mi->un.e.member[3].label.name));
+ mi->un.e.member[3].ord = 3;
+
+ strlcpy(mi->un.e.member[4].label.name,
+ "auto", sizeof(mi->un.e.member[4].label.name));
+ mi->un.e.member[4].ord = 4;
+
+ break;
+ case UDA1341_OUTPUT_CLASS:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UDA1341_OUTPUT_CLASS;
+ mi->prev = AUDIO_MIXER_LAST;
+ mi->next = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCoutputs,
+ sizeof(mi->label.name));
+ break;
+ case UDA1341_MIXER_INMIX1:
+ strlcpy(mi->label.name, "inmix1",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/64;
+ break;
+ case UDA1341_MIXER_INMIX2:
+ strlcpy(mi->label.name, "inmix2",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/64;
+ break;
+ case UDA1341_MIXER_MICVOL:
+ strlcpy(mi->label.name, AudioNmicrophone,
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/8;
+ break;
+ case UDA1341_MIXER_INMODE:
+ strlcpy(mi->label.name, "inmode",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ mi->un.e.num_mem = 4;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "dd", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "ch1", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+
+ strlcpy(mi->un.e.member[2].label.name,
+ "ch2", sizeof(mi->un.e.member[2].label.name));
+ mi->un.e.member[2].ord = 2;
+
+ strlcpy(mi->un.e.member[3].label.name,
+ "mix", sizeof(mi->un.e.member[3].label.name));
+ mi->un.e.member[3].ord = 3;
+ break;
+ case UDA1341_MIXER_AGC:
+ strlcpy(mi->label.name, "agc",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_ENUM;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ mi->un.e.num_mem = 2;
+
+ strlcpy(mi->un.e.member[0].label.name,
+ "off", sizeof(mi->un.e.member[0].label.name));
+ mi->un.e.member[0].ord = 0;
+
+ strlcpy(mi->un.e.member[1].label.name,
+ "on", sizeof(mi->un.e.member[1].label.name));
+ mi->un.e.member[1].ord = 1;
+ break;
+ case UDA1341_MIXER_AGC_LVL:
+ strlcpy(mi->label.name, "agclevel",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/4;
+ break;
+ case UDA1341_MIXER_IN_GAIN2:
+ strlcpy(mi->label.name, "ch2gain",
+ sizeof(mi->label.name));
+ mi->type = AUDIO_MIXER_VALUE;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->next = AUDIO_MIXER_LAST;
+ mi->prev = AUDIO_MIXER_LAST;
+ strlcpy(mi->un.v.units.name, AudioNvolume,
+ sizeof(mi->un.v.units.name));
+ mi->un.v.num_channels = 1;
+ mi->un.v.delta = 256/128;
+ break;
+ case UDA1341_INPUT_CLASS:
+ mi->type = AUDIO_MIXER_CLASS;
+ mi->mixer_class = UDA1341_INPUT_CLASS;
+ mi->prev = AUDIO_MIXER_LAST;
+ mi->next = AUDIO_MIXER_LAST;
+ strlcpy(mi->label.name, AudioCinputs,
+ sizeof(mi->label.name));
+ break;
+ default:
+ return ENXIO;
+ }
+
+ return 0;
+}
+
+int
+uda1341_get_port(void *handle, mixer_ctrl_t *mixer)
+{
+ struct uda1341_softc *sc = handle;
+
+ switch(mixer->dev) {
+ case UDA1341_MIXER_VOL:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+ if (mixer->un.value.num_channels != 1)
+ return EINVAL;
+ mixer->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
+ sc->sc_volume;
+ break;
+ case UDA1341_MIXER_BASS:
+ if (mixer->type != AUDIO_MIXER_VALUE ||
+ mixer->un.value.num_channels != 1)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_bass;
+ break;
+ case UDA1341_MIXER_TREBLE:
+ if (mixer->type != AUDIO_MIXER_VALUE ||
+ mixer->un.value.num_channels != 1)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_treble;
+ break;
+ case UDA1341_MIXER_MODE:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_mode;
+ break;
+ case UDA1341_MIXER_MUTE:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_mute;
+ break;
+ case UDA1341_MIXER_OGAIN:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_ogain;
+ break;
+ case UDA1341_MIXER_DE:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_deemphasis;
+ break;
+ case UDA1341_MIXER_INMIX1:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_inmix1;
+ break;
+ case UDA1341_MIXER_INMIX2:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_inmix2;
+ break;
+ case UDA1341_MIXER_MICVOL:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_micvol;
+ break;
+ case UDA1341_MIXER_INMODE:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_inmode;
+ break;
+ case UDA1341_MIXER_AGC:
+ if (mixer->type != AUDIO_MIXER_ENUM)
+ return EINVAL;
+
+ mixer->un.ord = sc->sc_agc;
+ break;
+ case UDA1341_MIXER_AGC_LVL:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_agc_lvl;
+ break;
+ case UDA1341_MIXER_IN_GAIN2:
+ if (mixer->type != AUDIO_MIXER_VALUE)
+ return EINVAL;
+
+ mixer->un.value.level[0] = sc->sc_ch2_gain;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int
+uda1341_set_port(void *handle, mixer_ctrl_t *mixer)
+{
+ struct uda1341_softc *sc = handle;
+
+ switch(mixer->dev) {
+ case UDA1341_MIXER_VOL:
+ sc->sc_volume = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_BASS:
+ sc->sc_bass = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_TREBLE:
+ sc->sc_treble = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_MODE:
+ sc->sc_mode = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_MUTE:
+ sc->sc_mute = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_OGAIN:
+ sc->sc_ogain = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_DE:
+ sc->sc_deemphasis = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_INMIX1:
+ sc->sc_inmix1 = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_INMIX2:
+ sc->sc_inmix2 = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_MICVOL:
+ sc->sc_micvol = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_INMODE:
+ sc->sc_inmode = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_AGC:
+ sc->sc_agc = mixer->un.ord;
+ break;
+ case UDA1341_MIXER_AGC_LVL:
+ sc->sc_agc_lvl = mixer->un.value.level[0];
+ break;
+ case UDA1341_MIXER_IN_GAIN2:
+ sc->sc_ch2_gain = mixer->un.value.level[0];
+ break;
+ default:
+ return EINVAL;
+ }
+
+ uda1341_update_sound_settings(sc);
+
+ return 0;
+}
Index: src/sys/dev/ic/uda1341reg.h
diff -u /dev/null src/sys/dev/ic/uda1341reg.h:1.1
--- /dev/null Sat Jan 28 08:37:22 2012
+++ src/sys/dev/ic/uda1341reg.h Sat Jan 28 08:37:22 2012
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Fleischer <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _DEV_IC_UDA1341REG_H_
+#define _DEV_IC_UDA1341REG_H_
+
+#define UDA1341_L3_ADDR_DEVICE 0x14 /* Address of the UDA1341 on the L3 bus */
+#define UDA1341_L3_ADDR_DATA0 0x00
+#define UDA1341_L3_ADDR_DATA1 0x01
+#define UDA1341_L3_ADDR_STATUS 0x02
+
+/* Status address has two "banks", 0 and 1.
+ The bank is selected as bit 7 of the data written.
+ */
+#define UDA1341_L3_STATUS0 (0<<7)
+#define UDA1341_L3_STATUS1 (1<<7)
+
+/** Status bank 0 **/
+#define UDA1341_L3_STATUS0_RST (1<<6)
+
+/* System clock selection (bit 4 and 5) */
+#define UDA1341_L3_STATUS0_SC_512 (0<<4)
+#define UDA1341_L3_STATUS0_SC_384 (1<<4)
+#define UDA1341_L3_STATUS0_SC_256 (2<<4)
+#define UDA1341_L3_STATUS0_SC_NA (3<<4)
+#define UDA1341_L3_STATUS0_SC_SHIFT 4
+
+/* Interface format (bit 1, 2, 3)*/
+#define UDA1341_L3_STATUS0_IF_I2S (0<<1)
+#define UDA1341_L3_STATUS0_IF_LSB16 (1<<1)
+#define UDA1341_L3_STATUS0_IF_LSB18 (2<<1)
+#define UDA1341_L3_STATUS0_IF_LSB20 (3<<1)
+#define UDA1341_L3_STATUS0_IF_MSB (4<<1)
+#define UDA1341_L3_STATUS0_IF_LSB16_MSB (5<<1)
+#define UDA1341_L3_STATUS0_IF_LSB18_MSB (6<<1)
+#define UDA1341_L3_STATUS0_IF_LSB20_MSB (7<<1)
+#define UDA1341_L3_STATUS0_IF_SHIFT 1
+
+/* DC-Filtering */
+#define UDA1341_L3_STATUS0_DC_FILTERING (1<<0)
+
+/** Status bank 1**/
+
+/* Output and Input Gain*/
+#define UDA1341_L3_STATUS1_OGS_6DB (1<<6)
+#define UDA1341_L3_STATUS1_IGS_6DB (1<<5)
+
+/* DAC and ADC polarity inversion */
+#define UDA1341_L3_STATUS1_PAD_INV (1<<4)
+#define UDA1341_L3_STATUS1_PDA_INV (1<<3)
+
+/* Double speed playback */
+#define UDA1341_L3_STATUS1_DS (1<<2)
+
+/* Power Control */
+#define UDA1341_L3_STATUS1_PC_ADC (1<<1)
+#define UDA1341_L3_STATUS1_PC_DAC (1<<0)
+
+/*** DATA0 ***/
+/*
+ * Data0 has five banks: three for direct control, and two for extended access.
+ */
+#define UDA1341_L3_DATA0_VOLUME (0<<6)
+#define UDA1341_L3_DATA0_VOLUME_MASK (0x3F)
+
+#define UDA1341_L3_DATA0_BASS_TREBLE (1<<6)
+#define UDA1341_L3_DATA0_BASS_SHIFT 2
+#define UDA1341_L3_DATA0_BASS_MASK 0x3C
+#define UDA1341_L3_DATA0_TREBLE_SHIFT 0
+#define UDA1341_L3_DATA0_TREBLE_MASK 0x03
+
+#define UDA1341_L3_DATA0_SOUNDC (2<<6)
+#define UDA1341_L3_DATA0_SOUNDC_DE_MASK (0x18)
+#define UDA1341_L3_DATA0_SOUNDC_DE_SHIFT 3
+#define UDA1341_L3_DATA0_SOUNDC_MUTE (1<<2)
+#define UDA1341_L3_DATA0_SOUNDC_MODE_MASK (0x03)
+
+#define UDA1341_L3_DATA0_EA ((3<<6)|0<<5)
+#define UDA1341_L3_DATA0_ED ((3<<6)|1<<5)
+
+#define UDA1341_L3_DATA0_MA_MASK (0x1F)
+#define UDA1341_L3_DATA0_MB_MASK (0x1F)
+
+#define UDA1341_L3_DATA0_MS_MASK (0x1C)
+#define UDA1341_L3_DATA0_MS_SHIFT 2
+
+#define UDA1341_L3_DATA0_MM_MASK (0x03)
+
+#define UDA1341_L3_DATA0_AGC_SHIFT 4
+#define UDA1341_L3_DATA0_AGC_MASK (0x10)
+
+#define UDA1341_L3_DATA0_IG_LOW_MASK (0x03)
+#define UDA1341_L3_DATA0_IG_HIGH_MASK (0x1F)
+
+#define UDA1341_L3_DATA0_AL_MASK (0x03)
+#endif
Index: src/sys/dev/ic/uda1341var.h
diff -u /dev/null src/sys/dev/ic/uda1341var.h:1.1
--- /dev/null Sat Jan 28 08:37:22 2012
+++ src/sys/dev/ic/uda1341var.h Sat Jan 28 08:37:22 2012
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Fleischer <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _DEV_IC_UDA1341VAR_H_
+#define _DEV_IC_UDA1341VAR_H_
+
+#include <sys/device.h>
+#include <sys/audioio.h>
+
+#include <dev/auconv.h>
+
+#define UDA1341_NFORMATS 4
+extern const struct audio_format uda1341_formats[UDA1341_NFORMATS];
+
+struct uda1341_softc {
+ /* Pointer to the driver that holds this sc */
+ void *parent;
+
+ /* Pointer to L3 write function */
+ void (*sc_l3_write)(void *,int,int);
+
+ /* Approximate sample rate at which the codec is currently running */
+ int sc_sample_rate_approx;
+
+ int sc_system_clock;
+#define UDA1341_CLOCK_NA 3
+#define UDA1341_CLOCK_256 2
+#define UDA1341_CLOCK_384 1
+#define UDA1341_CLOCK_512 0
+
+ int sc_bus_format;
+#define UDA1341_BUS_I2S 0
+#define UDA1341_BUS_LSB16 1
+#define UDA1341_BUS_LSB18 2
+#define UDA1341_BUS_LSB20 3
+#define UDA1341_BUS_MSB 4
+#define UDA1341_BUS_LSB16_MSB 5
+#define UDA1341_BUS_LSB18_MSB 6
+#define UDA1341_BUS_LSB20_MSB 7
+
+ uint8_t sc_volume;
+ uint8_t sc_bass;
+ uint8_t sc_treble;
+ uint8_t sc_mode;
+ uint8_t sc_mute;
+ uint8_t sc_ogain;
+ uint8_t sc_dac_power;
+ uint8_t sc_adc_power;
+ uint8_t sc_inmix1;
+ uint8_t sc_inmix2;
+ uint8_t sc_micvol;
+ uint8_t sc_inmode;
+ uint8_t sc_agc;
+ uint8_t sc_agc_lvl;
+ uint8_t sc_ch2_gain;
+
+#define UDA1341_DEEMPHASIS_AUTO 4
+ uint8_t sc_deemphasis;
+
+};
+
+int uda1341_attach(struct uda1341_softc *);
+int uda1341_query_encodings(void *, audio_encoding_t *);
+int uda1341_open(void *, int );
+void uda1341_close(void *);
+int uda1341_set_params(void *, int, int, audio_params_t*, audio_params_t*, stream_filter_list_t *, stream_filter_list_t*);
+int uda1341_query_devinfo(void *, mixer_devinfo_t *);
+int uda1341_get_port(void *, mixer_ctrl_t *);
+int uda1341_set_port(void *, mixer_ctrl_t *);
+#endif