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 <p...@xpg.dk> + * + * 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 <p...@xpg.dk> + * + * 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 <p...@xpg.dk> + * + * 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