/*
* Copyright (c) 2005 Mark Kettenis
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
switch (mc->dev) {
case AD1843_ADC_SOURCE:
value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
value &= ~(AD1843_LSS_MASK | AD1843_RSS_MASK);
value |= ((mc->un.ord << AD1843_LSS_SHIFT) & AD1843_LSS_MASK);
value |= ((mc->un.ord << AD1843_RSS_SHIFT) & AD1843_RSS_MASK);
ad1843_reg_write(sc, AD1843_ADC_SOURCE_GAIN, value);
break;
case AD1843_ADC_GAIN:
left = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
right = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
value &= ~(AD1843_LIG_MASK | AD1843_RIG_MASK);
value |= ((left >> 4) << AD1843_LIG_SHIFT);
value |= ((right >> 4) << AD1843_RIG_SHIFT);
ad1843_reg_write(sc, AD1843_ADC_SOURCE_GAIN, value);
break;
case AD1843_DAC1_GAIN:
left = AUDIO_MAX_GAIN -
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
right = AUDIO_MAX_GAIN -
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
value &= ~(AD1843_LDA1G_MASK | AD1843_RDA1G_MASK);
value |= ((left >> 2) << AD1843_LDA1G_SHIFT);
value |= ((right >> 2) << AD1843_RDA1G_SHIFT);
ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN, value);
break;
case AD1843_DAC1_MUTE:
value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
if (mc->un.ord == 0)
value &= ~(AD1843_LDA1GM | AD1843_RDA1GM);
else
value |= (AD1843_LDA1GM | AD1843_RDA1GM);
ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN, value);
break;
case AD1843_DAC2_GAIN:
case AD1843_AUX1_GAIN:
case AD1843_AUX2_GAIN:
case AD1843_AUX3_GAIN:
case AD1843_MIC_GAIN:
left = AUDIO_MAX_GAIN -
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
right = AUDIO_MAX_GAIN -
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_GAIN;
value = ad1843_reg_read(sc, reg);
value &= ~(AD1843_LD2M_MASK | AD1843_RD2M_MASK);
value |= ((left >> 3) << AD1843_LD2M_SHIFT);
value |= ((right >> 3) << AD1843_RD2M_SHIFT);
ad1843_reg_write(sc, reg, value);
break;
case AD1843_MONO_GAIN:
left = AUDIO_MAX_GAIN -
mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
value &= ~AD1843_MNM_MASK;
value |= ((left >> 3) << AD1843_MNM_SHIFT);
ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
break;
case AD1843_DAC2_MUTE:
case AD1843_AUX1_MUTE:
case AD1843_AUX2_MUTE:
case AD1843_AUX3_MUTE:
case AD1843_MIC_MUTE:
case AD1843_MONO_MUTE: /* matches left channel */
reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_MUTE;
value = ad1843_reg_read(sc, reg);
if (mc->un.ord == 0)
value &= ~(AD1843_LD2MM | AD1843_RD2MM);
else
value |= (AD1843_LD2MM | AD1843_RD2MM);
ad1843_reg_write(sc, reg, value);
break;
case AD1843_SUM_MUTE:
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
if (mc->un.ord == 0)
value &= ~AD1843_SUMM;
else
value |= AD1843_SUMM;
ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
break;
case AD1843_MNO_MUTE:
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
if (mc->un.ord == 0)
value &= ~AD1843_MNOM;
else
value |= AD1843_MNOM;
ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
break;
case AD1843_HPO_MUTE:
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
if (mc->un.ord == 0)
value &= ~AD1843_HPOM;
else
value |= AD1843_HPOM;
ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
break;
/* XXX We need access to some of the MACE ISA registers. */
if (bus_space_subregion(sc->sc_st, maa->maa_sh, 0, 0,
&sc->sc_isash) != 0) {
printf(": can't map isa i/o space\n");
return;
}
/* Set up DMA structures. */
sc->sc_dmat = maa->maa_dmat;
if (bus_dmamap_create(sc->sc_dmat, 4 * MAVB_ISA_RING_SIZE, 1,
4 * MAVB_ISA_RING_SIZE, 0, 0, &sc->sc_dmamap)) {
printf(": can't create MACE ISA DMA map\n");
return;
}
if (bus_dmamem_alloc(sc->sc_dmat, 4 * MAVB_ISA_RING_SIZE,
MACE_ISA_RING_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
printf(": can't allocate ring buffer\n");
return;
}
if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, 4 * MAVB_ISA_RING_SIZE,
(void *)&sc->sc_ring, BUS_DMA_COHERENT)) {
printf(": can't map ring buffer\n");
return;
}
if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ring,
4 * MAVB_ISA_RING_SIZE, NULL, BUS_DMA_NOWAIT)) {
printf(": can't load MACE ISA DMA map\n");
return;
}
control = bus_space_read_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL);
if (!(control & MAVB_CONTROL_CODEC_PRESENT)) {
printf(": no codec present\n");
return;
}
/* 2. Assert the RESET signal. */
bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL,
MAVB_CONTROL_RESET);
delay(1); /* at least 100 ns */
/* 3. Deassert the RESET signal and enter a wait period to
allow the AD1843 internal clocks and the external
crystal oscillator to stabilize. */
bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL, 0);
delay(800); /* typically 400 us to 800 us */
if (ad1843_reg_read(sc, AD1843_CODEC_STATUS) & AD1843_INIT) {
printf(": codec not ready\n");
return;
}
/* 4. Put the conversion sources into standby. */
value = ad1843_reg_read(sc, AD1843_FUNDAMENTAL_SETTINGS);
ad1843_reg_write(sc, AD1843_FUNDAMENTAL_SETTINGS,
value & ~AD1843_PDNI);
delay (500000); /* approximately 474 ms */
if (ad1843_reg_read(sc, AD1843_CODEC_STATUS) & AD1843_PDNO) {
printf(": can't power up conversion resources\n");
return;
}
/* 5. Power up the clock generators and enable clock output pins. */
value = ad1843_reg_read(sc, AD1843_FUNDAMENTAL_SETTINGS);
ad1843_reg_write(sc, AD1843_FUNDAMENTAL_SETTINGS, value | AD1843_C2EN);
/* 6. Configure conversion resources while they are in standby. */
value = ad1843_reg_read(sc, AD1843_CHANNEL_SAMPLE_RATE);
ad1843_reg_write(sc, AD1843_CHANNEL_SAMPLE_RATE,
value | (2 << AD1843_DA1C_SHIFT));
/* 7. Enable conversion resources. */
value = ad1843_reg_read(sc, AD1843_CHANNEL_POWER_DOWN);
ad1843_reg_write(sc, AD1843_CHANNEL_POWER_DOWN,
value | (AD1843_DA1EN | AD1843_AAMEN));
/* 8. Configure conversion resources while they are enabled. */
value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN,
value & ~(AD1843_LDA1GM | AD1843_RDA1GM));
value = ad1843_reg_read(sc, AD1843_DAC1_DIGITAL_GAIN);
ad1843_reg_write(sc, AD1843_DAC1_DIGITAL_GAIN,
value & ~(AD1843_LDA1AM | AD1843_RDA1AM));
value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
ad1843_reg_write(sc, AD1843_MISC_SETTINGS,
value & ~(AD1843_HPOM | AD1843_MNOM));