Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Add UDA1341TS audio CODEC support. Code is written by



details:   https://anonhg.NetBSD.org/src/rev/87f08ddcf21f
branches:  trunk
changeset: 773118:87f08ddcf21f
user:      nisimura <nisimura%NetBSD.org@localhost>
date:      Sat Jan 28 08:37:22 2012 +0000

description:
Add UDA1341TS audio CODEC support.  Code is written by
Paul Fleischer.

diffstat:

 sys/conf/files          |    6 +-
 sys/dev/ic/uda1341.c    |  762 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ic/uda1341reg.h |  121 +++++++
 sys/dev/ic/uda1341var.h |   95 +++++
 4 files changed, 983 insertions(+), 1 deletions(-)

diffs (truncated from 1010 to 300 lines):

diff -r a111e0a148aa -r 87f08ddcf21f sys/conf/files
--- a/sys/conf/files    Sat Jan 28 08:29:55 2012 +0000
+++ b/sys/conf/files    Sat Jan 28 08:37:22 2012 +0000
@@ -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 @@
 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
diff -r a111e0a148aa -r 87f08ddcf21f sys/dev/ic/uda1341.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/uda1341.c      Sat Jan 28 08:37:22 2012 +0000
@@ -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 <paul%xpg.dk@localhost>
+ *
+ * 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;



Home | Main Index | Thread Index | Old Index