--- /dev/null
+#include "cmi8738.h"
+#include "mixer.h"
+
+/* global value */
+DEV_STRUCT dev;
+aud_sub_dev_conf_t aud_conf[3];
+sub_dev_t sub_dev[3];
+special_file_t special_file[3];
+drv_t drv;
+
+/* internal function */
+static int dev_probe(void);
+static int set_sample_rate(u32_t rate, int num);
+static int set_stereo(u32_t stereo, int num);
+static int set_bits(u32_t bits, int sub_dev);
+static int set_frag_size(u32_t frag_size, int num);
+static int set_sign(u32_t val, int num);
+static int get_frag_size(u32_t *val, int *len, int num);
+static int free_buf(u32_t *val, int *len, int num);
+
+/* developer interface */
+static int dev_reset(u32_t *base);
+static void dev_configure(u32_t *base);
+static void dev_init_mixer(u32_t *base);
+static void dev_set_sample_rate(u32_t *base, u16_t sample_rate);
+static void dev_set_format(u32_t *base, u32_t bits, u32_t sign,
+ u32_t stereo, u32_t sample_count);
+static void dev_start_channel(u32_t *base, int sub_dev);
+static void dev_stop_channel(u32_t *base, int sub_dev);
+static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev);
+static u32_t dev_read_dma_current(u32_t *base, int sub_dev);
+static void dev_pause_dma(u32_t *base, int sub_dev);
+static void dev_resume_dma(u32_t *base, int sub_dev);
+static void dev_intr_other(u32_t *base, u32_t status);
+static u32_t dev_read_clear_intr_status(u32_t *base);
+static void dev_intr_enable(u32_t *base, int flag);
+
+/* ======= Developer implemented function ======= */
+/* ====== Self-defined function ====== */
+void dev_io_set_clear(u32_t base, u32_t reg, u32_t val, int flag) {
+ u32_t data;
+ data = sdr_in32(base, reg);
+ if (flag == 0)
+ data &= ~val;
+ else if (flag == 1)
+ data |= val;
+ sdr_out32(base, reg, data);
+}
+
+/* ====== Mixer handling interface ======*/
+/* Write the data to mixer register (### WRITE_MIXER_REG ###) */
+void dev_mixer_write(u32_t *base, u32_t reg, u32_t val) {
+ u32_t base0 = base[0];
+ sdr_out8(base0, REG_SB_ADDR, reg);
+ sdr_out8(base0, REG_SB_DATA, val);
+}
+
+/* Read the data from mixer register (### READ_MIXER_REG ###) */
+u32_t dev_mixer_read(u32_t *base, u32_t reg) {
+ u32_t base0 = base[0];
+ sdr_out8(base0, REG_SB_ADDR, reg);
+ return sdr_in8(base0, REG_SB_DATA);
+}
+
+/* ====== Developer interface ======*/
+
+/* Reset the device (### RESET_HARDWARE_CAN_FAIL ###)
+ * -- Return OK means success, Others means failure */
+static int dev_reset(u32_t *base) {
+ u32_t data, base0 = base[0];
+ dev_io_set_clear(base0, REG_MISC_CTRL, CMD_POWER_DOWN, 0);
+ dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 1);
+ micro_delay(100);
+ dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 0);
+ return OK;
+}
+
+/* Configure hardware registers (### CONF_HARDWARE ###) */
+static void dev_configure(u32_t *base) {
+ u32_t data, base0 = base[0];
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C0, 0);
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C1, 1);
+ dev_io_set_clear(base0, REG_MISC_CTRL, CMD_N4SPK3D, 1);
+ dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_ENA, 0);
+ dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_LOOP, 0);
+ sdr_out8(base0, REG_EXT_INDEX, 0x03);
+ sdr_out8(base0, REG_MIX_INPUT, 0x0f);
+}
+
+/* Initialize the mixer (### INIT_MIXER ###) */
+static void dev_init_mixer(u32_t *base) {
+ dev_mixer_write(base, 0, 0);
+ dev_mixer_write(base, MIXER_ADCL, 0x1f);
+ dev_mixer_write(base, MIXER_ADCR, 0x7f);
+ dev_mixer_write(base, MIXER_OUT_MUTE, 0x7f);
+}
+
+/* Set DAC and ADC sample rate (### SET_SAMPLE_RATE ###) */
+static void dev_set_sample_rate(u32_t *base, u16_t sample_rate) {
+ int i;
+ u32_t data, rate = 0, base0 = base[0];
+ for (i = 0; i < 8; i++) {
+ if (sample_rate == g_sample_rate[i]) {
+ rate = i;
+ break;
+ }
+ }
+ data = sdr_in32(base0, REG_FUNC_CTRL1);
+ data &=~ (0xe000 | 0x1c00);
+ data |= (rate << 13) & 0xe000;
+ data |= (rate << 10) & 0x1c00;
+ sdr_out32(base0, REG_FUNC_CTRL1, data);
+}
+
+/* Set DAC and ADC format (### SET_FORMAT ###)*/
+static void dev_set_format(u32_t *base, u32_t bits, u32_t sign,
+ u32_t stereo, u32_t sample_count) {
+ u32_t format = 0, data, base0 = base[0];
+ if (stereo == 1)
+ format |= FMT_STEREO;
+ if (bits == 16)
+ format |= FMT_BIT16;
+ data = sdr_in32(base0, REG_FORMAT);
+ data &= ~0x00000003;
+ data |= format << 0;
+ data &= ~0x0000000c;
+ data |= format << 2;
+ sdr_out32(base0, REG_FORMAT, data);
+ dev_io_set_clear(base0, REG_EXT_MISC, 0x10000000, 0);
+ sdr_out16(base0, REG_DAC_SAMPLE_COUNT, sample_count - 1);
+ sdr_out16(base0, REG_ADC_SAMPLE_COUNT, sample_count - 1);
+}
+
+/* Start the channel (### START_CHANNEL ###) */
+static void dev_start_channel(u32_t *base, int sub_dev) {
+ u32_t data, base0 = base[0];
+ if (sub_dev == DAC) {
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 1);
+ }
+ else if (sub_dev == ADC) {
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 1);
+ }
+}
+
+/* Stop the channel (### STOP_CHANNEL ###) */
+static void dev_stop_channel(u32_t *base, int sub_dev) {
+ u32_t data, base0 = base[0];
+ if (sub_dev == DAC) {
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 0);
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 1);
+ micro_delay(100);
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 0);
+ }
+ else if (sub_dev == ADC) {
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 0);
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 1);
+ micro_delay(100);
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 0);
+ }
+}
+
+/* Set DMA address and length (### SET_DMA ###) */
+static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev) {
+ u32_t base0 = base[0];
+ if (sub_dev == DAC) {
+ sdr_out32(base0, REG_DAC_DMA_ADDR, dma);
+ sdr_out16(base0, REG_DAC_DMA_LEN, len - 1);
+ }
+ else if (sub_dev == ADC) {
+ sdr_out32(base0, REG_ADC_DMA_ADDR, dma);
+ sdr_out16(base0, REG_ADC_DMA_LEN, len - 1);
+ }
+}
+
+/* Read current address (### READ_DMA_CURRENT_ADDR ###) */
+static u32_t dev_read_dma_current(u32_t *base, int sub_dev) {
+ u32_t data, base0 = base[0];
+ if (sub_dev == DAC)
+ data = sdr_in16(base0, REG_DAC_CUR_ADDR);
+ else if (sub_dev == ADC)
+ data = sdr_in16(base0, REG_ADC_CUR_ADDR);
+ return data;
+}
+
+/* Pause the DMA (### PAUSE_DMA ###) */
+static void dev_pause_dma(u32_t *base, int sub_dev) {
+ u32_t base0 = base[0];
+ if (sub_dev == DAC)
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 1);
+ else if (sub_dev == ADC)
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 1);
+}
+
+/* Resume the DMA (### RESUME_DMA ###) */
+static void dev_resume_dma(u32_t *base, int sub_dev) {
+ u32_t base0 = base[0];
+ if (sub_dev == DAC)
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 0);
+ else if (sub_dev == ADC)
+ dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 0);
+}
+
+/* Read and clear interrupt status (### READ_CLEAR_INTR_STS ###)
+ * -- Return interrupt status */
+static u32_t dev_read_clear_intr_status(u32_t *base) {
+ u32_t data, base0 = base[0];
+ data = sdr_in32(base0, REG_INTR_STS);
+ dev_intr_enable(base, INTR_DISABLE);
+ dev_intr_enable(base, INTR_ENABLE);
+ return data;
+}
+
+/* Enable or disable interrupt (### INTR_ENBALE_DISABLE ###) */
+static void dev_intr_enable(u32_t *base, int flag) {
+ u32_t data, base0 = base[0];
+ data = sdr_in32(base0, REG_INTR_STS);
+ if (flag == INTR_ENABLE)
+ sdr_out32(base0, REG_INTR_CTRL, data | CMD_INTR_ENABLE);
+ else if (flag == INTR_DISABLE)
+ sdr_out32(base0, REG_INTR_CTRL, data & ~CMD_INTR_ENABLE);
+}
+
+/* ======= Common driver function ======= */
+/* Probe the device */
+static int dev_probe(void) {
+ int devind, i, ioflag;
+ u32_t device, bar, size, base;
+ u16_t vid, did, temp;
+ u8_t *reg;
+
+ pci_init();
+ device = pci_first_dev(&devind, &vid, &did);
+ while (device > 0) {
+ if (vid == VENDOR_ID && did == DEVICE_ID)
+ break;
+ device = pci_next_dev(&devind, &vid, &did);
+ }
+ if (vid != VENDOR_ID || did != DEVICE_ID)
+ return EIO;
+ pci_reserve(devind);
+
+ for (i = 0; i < 6; i++)
+ dev.base[i] = 0;
+#ifdef DMA_BASE_IOMAP
+ for (i = 0; i < 6; i++) {
+ if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) {
+ /* printf("SDR: Fail to get PCI BAR %d\n", i); */
+ continue;
+ }
+ if (ioflag) {
+ /* printf("SDR: PCI BAR %d is not for memory\n", i); */
+ continue;
+ }
+ if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
+ printf("SDR: Fail to map hardware registers from PCI\n");
+ return -EIO;
+ }
+ dev.base[i] = (u32_t)reg;
+ }
+#else
+ /* Get PCI BAR0-5 */
+ for (i = 0; i < 6; i++)
+ dev.base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0;
+#endif
+ dev.name = pci_dev_name(vid, did);
+ dev.irq = pci_attr_r8(devind, PCI_ILR);
+ dev.revision = pci_attr_r8(devind, PCI_REV);
+ dev.did = did;
+ dev.vid = vid;
+ dev.devind = devind;
+ temp = pci_attr_r16(devind, PCI_CR);
+ pci_attr_w16(devind, PCI_CR, temp | 0x105);
+
+#ifdef MY_DEBUG
+ printf("SDR: Hardware name is %s\n", dev.name);
+ for (i = 0; i < 6; i++)
+ printf("SDR: PCI BAR%d is 0x%08x\n", i, dev.base[i]);
+ printf("SDR: IRQ number is 0x%02x\n", dev.irq);
+#endif
+ return OK;
+}
+
+/* Set sample rate in configuration */
+static int set_sample_rate(u32_t rate, int num) {
+ aud_conf[num].sample_rate = rate;
+ return OK;
+}
+
+/* Set stereo in configuration */
+static int set_stereo(u32_t stereo, int num) {
+ aud_conf[num].stereo = stereo;
+ return OK;
+}
+
+/* Set sample bits in configuration */
+static int set_bits(u32_t bits, int num) {
+ aud_conf[num].nr_of_bits = bits;
+ return OK;
+}
+
+/* Set fragment size in configuration */
+static int set_frag_size(u32_t frag_size, int num) {
+ if (frag_size > (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments) ||
+ frag_size < sub_dev[num].MinFragmentSize) {
+ return EINVAL;
+ }
+ aud_conf[num].fragment_size = frag_size;
+ return OK;
+}
+
+/* Set frame sign in configuration */
+static int set_sign(u32_t val, int num) {
+ aud_conf[num].sign = val;
+ return OK;
+}
+
+/* Get maximum fragment size */
+static int get_max_frag_size(u32_t *val, int *len, int num) {
+ *len = sizeof(*val);
+ *val = (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments);
+ return OK;
+}
+
+/* Return 1 if there are free buffers */
+static int free_buf(u32_t *val, int *len, int num) {
+ *len = sizeof(*val);
+ if (sub_dev[num].BufLength == sub_dev[num].NrOfExtraBuffers)
+ *val = 0;
+ else
+ *val = 1;
+ return OK;
+}
+
+/* Get the current sample counter */
+static int get_samples_in_buf(u32_t *result, int *len, int chan) {
+ u32_t res;
+ /* READ_DMA_CURRENT_ADDR */
+ res = dev_read_dma_current(dev.base, chan);
+ *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res;
+ return OK;
+}
+
+/* ======= [Audio interface] Initialize data structure ======= */
+int drv_init(void) {
+ drv.DriverName = DRIVER_NAME;
+ drv.NrOfSubDevices = 3;
+ drv.NrOfSpecialFiles = 3;
+
+ sub_dev[DAC].readable = 0;
+ sub_dev[DAC].writable = 1;
+ sub_dev[DAC].DmaSize = 64 * 1024;
+ sub_dev[DAC].NrOfDmaFragments = 2;
+ sub_dev[DAC].MinFragmentSize = 1024;
+ sub_dev[DAC].NrOfExtraBuffers = 4;
+
+ sub_dev[ADC].readable = 1;
+ sub_dev[ADC].writable = 0;
+ sub_dev[ADC].DmaSize = 64 * 1024;
+ sub_dev[ADC].NrOfDmaFragments = 2;
+ sub_dev[ADC].MinFragmentSize = 1024;
+ sub_dev[ADC].NrOfExtraBuffers = 4;
+
+ sub_dev[MIX].writable = 0;
+ sub_dev[MIX].readable = 0;
+
+ special_file[0].minor_dev_nr = 0;
+ special_file[0].write_chan = DAC;
+ special_file[0].read_chan = NO_CHANNEL;
+ special_file[0].io_ctl = DAC;
+
+ special_file[1].minor_dev_nr = 1;
+ special_file[1].write_chan = NO_CHANNEL;
+ special_file[1].read_chan = ADC;
+ special_file[1].io_ctl = ADC;
+
+ special_file[2].minor_dev_nr = 2;
+ special_file[2].write_chan = NO_CHANNEL;
+ special_file[2].read_chan = NO_CHANNEL;
+ special_file[2].io_ctl = MIX;
+
+ return OK;
+}
+
+/* ======= [Audio interface] Initialize hardware ======= */
+int drv_init_hw(void) {
+ int i;
+
+ /* Match the device */
+ if (dev_probe()) {
+ printf("SDR: No sound card found\n");
+ return EIO;
+ }
+
+ /* Reset the device */
+ /* ### RESET_HARDWARE_CAN_FAIL ### */
+ if (dev_reset(dev.base)) {
+ printf("SDR: Fail to reset the device\n");
+ return EIO;
+ }
+
+ /* Configure the hardware */
+ /* ### CONF_HARDWARE ### */
+ dev_configure(dev.base);
+
+ /* Initialize the mixer */
+ /* ### INIT_MIXER ### */
+ dev_init_mixer(dev.base);
+
+ /* Set default mixer volume */
+ dev_set_default_volume(dev.base);
+
+ /* Initialize subdevice data */
+ for (i = 0; i < drv.NrOfSubDevices; i++) {
+ if (i == MIX)
+ continue;
+ aud_conf[i].busy = 0;
+ aud_conf[i].stereo = 1;
+ aud_conf[i].sample_rate = 44100;
+ aud_conf[i].nr_of_bits = 16;
+ aud_conf[i].sign = 1;
+ aud_conf[i].fragment_size =
+ sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
+ }
+ return OK;
+}
+
+/* ======= [Audio interface] Driver reset =======*/
+int drv_reset(void) {
+ /* ### RESET_HARDWARE_CAN_FAIL ### */
+ return dev_reset(dev.base);
+}
+
+/* ======= [Audio interface] Driver start ======= */
+int drv_start(int sub_dev, int DmaMode) {
+ int sample_count;
+
+ /* Set DAC and ADC sample rate */
+ /* ### SET_SAMPLE_RATE ### */
+ dev_set_sample_rate(dev.base, aud_conf[sub_dev].sample_rate);
+
+ sample_count = aud_conf[sub_dev].fragment_size;
+#ifdef DMA_LENGTH_BY_FRAME
+ sample_count = sample_count / (aud_conf[sub_dev].nr_of_bits * (aud_conf[sub_dev].stereo + 1) / 8);
+#endif
+ /* Set DAC and ADC format */
+ /* ### SET_FORMAT ### */
+ dev_set_format(dev.base, aud_conf[sub_dev].nr_of_bits,
+ aud_conf[sub_dev].sign, aud_conf[sub_dev].stereo, sample_count);
+
+ drv_reenable_int(sub_dev);
+
+ /* Start the channel */
+ /* ### START_CHANNEL ### */
+ dev_start_channel(dev.base, sub_dev);
+ aud_conf[sub_dev].busy = 1;
+
+ return OK;
+}
+
+/* ======= [Audio interface] Driver start ======= */
+int drv_stop(int sub_dev) {
+ u32_t data;
+
+ /* INTR_ENABLE_DISABLE */
+ dev_intr_enable(dev.base, INTR_DISABLE);
+
+ /* ### STOP_CHANNEL ### */
+ dev_stop_channel(dev.base, sub_dev);
+
+ aud_conf[sub_dev].busy = 0;
+ return OK;
+}
+
+/* ======= [Audio interface] Enable interrupt ======= */
+int drv_reenable_int(int chan) {
+ /* INTR_ENABLE_DISABLE */
+ dev_intr_enable(dev.base, INTR_ENABLE);
+ return OK;
+}
+
+/* ======= [Audio interface] I/O control ======= */
+int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) {
+ int status;
+ switch (request) {
+ case DSPIORATE:
+ status = set_sample_rate(*((u32_t *)val), sub_dev);
+ break;
+ case DSPIOSTEREO:
+ status = set_stereo(*((u32_t *)val), sub_dev);
+ break;
+ case DSPIOBITS:
+ status = set_bits(*((u32_t *)val), sub_dev);
+ break;
+ case DSPIOSIZE:
+ status = set_frag_size(*((u32_t *)val), sub_dev);
+ break;
+ case DSPIOSIGN:
+ status = set_sign(*((u32_t *)val), sub_dev);
+ break;
+ case DSPIOMAX:
+ status = get_max_frag_size(val, len, sub_dev);
+ break;
+ case DSPIORESET:
+ status = drv_reset();
+ break;
+ case DSPIOFREEBUF:
+ status = free_buf(val, len, sub_dev);
+ break;
+ case DSPIOSAMPLESINBUF:
+ status = get_samples_in_buf(val, len, sub_dev);
+ break;
+ case DSPIOPAUSE:
+ status = drv_pause(sub_dev);
+ break;
+ case DSPIORESUME:
+ status = drv_resume(sub_dev);
+ break;
+ case MIXIOGETVOLUME:
+ /* ### GET_SET_VOLUME ### */
+ status = get_set_volume(dev.base, val, GET_VOL);
+ break;
+ case MIXIOSETVOLUME:
+ /* ### GET_SET_VOLUME ### */
+ status = get_set_volume(dev.base, val, SET_VOL);
+ break;
+ default:
+ status = EINVAL;
+ break;
+ }
+ return status;
+}
+
+/* ======= [Audio interface] Get request number ======= */
+int drv_get_irq(char *irq) {
+ *irq = dev.irq;
+ return OK;
+}
+
+/* ======= [Audio interface] Get fragment size ======= */
+int drv_get_frag_size(u32_t *frag_size, int sub_dev) {
+ *frag_size = aud_conf[sub_dev].fragment_size;
+ return OK;
+}
+
+/* ======= [Audio interface] Set DMA channel ======= */
+int drv_set_dma(u32_t dma, u32_t length, int chan) {
+#ifdef DMA_LENGTH_BY_FRAME
+ length = length / (aud_conf[chan].nr_of_bits * (aud_conf[chan].stereo + 1) / 8);
+#endif
+ /* ### SET_DMA ### */
+ dev_set_dma(dev.base, dma, length, chan);
+ return OK;
+}
+
+/* ======= [Audio interface] Get interrupt summary status ======= */
+int drv_int_sum(void) {
+ u32_t status;
+ /* ### READ_CLEAR_INTR_STS ### */
+ status = dev_read_clear_intr_status(dev.base);
+ dev.intr_status = status;
+#ifdef MY_DEBUG
+ printf("SDR: Interrupt status is 0x%08x\n", status);
+#endif
+ return (status & (INTR_STS_DAC | INTR_STS_ADC));
+}
+
+/* ======= [Audio interface] Handle interrupt status ======= */
+int drv_int(int sub_dev) {
+ u32_t mask;
+
+ /* ### CHECK_INTR_DAC ### */
+ if (sub_dev == DAC)
+ mask = INTR_STS_DAC;
+ /* ### CHECK_INTR_ADC ### */
+ else if (sub_dev == ADC)
+ mask = INTR_STS_ADC;
+ else
+ return 0;
+
+ return dev.intr_status & mask;
+}
+
+/* ======= [Audio interface] Pause DMA ======= */
+int drv_pause(int sub_dev) {
+ /* ### PAUSE_DMA ### */
+ dev_pause_dma(dev.base, sub_dev);
+ return OK;
+}
+
+/* ======= [Audio interface] Resume DMA ======= */
+int drv_resume(int sub_dev) {
+ /* ### RESUME_DMA ### */
+ dev_resume_dma(dev.base, sub_dev);
+ return OK;
+}
--- /dev/null
+#include "mixer.h"
+
+#ifdef MIXER_AK4531
+u8_t mixer_value[] = {
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
+ 0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x01
+};
+int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
+ int max_level, cmd_left, cmd_right;
+
+ max_level = 0x1f;
+ /* Check device */
+ switch (level->device) {
+ case Master:
+ cmd_left = MASTER_VOLUME_LCH;
+ cmd_right = MASTER_VOLUME_RCH;
+ break;
+ case Dac:
+ return EINVAL;
+ case Fm:
+ cmd_left = FM_VOLUME_LCH;
+ cmd_right = FM_VOLUME_RCH;
+ break;
+ case Cd:
+ cmd_left = CD_AUDIO_VOLUME_LCH;
+ cmd_right = CD_AUDIO_VOLUME_RCH;
+ break;
+ case Line:
+ cmd_left = LINE_VOLUME_LCH;
+ cmd_right = LINE_VOLUME_RCH;
+ break;
+ case Mic:
+ cmd_left = cmd_right = MIC_VOLUME;
+ break;
+ case Speaker:
+ cmd_left = cmd_right = MONO_OUT_VOLUME;
+ max_level = 0x03;
+ break;
+ case Treble:
+ return EINVAL;
+ case Bass:
+ return EINVAL;
+ default:
+ return EINVAL;
+ }
+ /* Set volume */
+ if (flag) {
+ if (level->right < 0)
+ level->right = 0;
+ else if (level->right > max_level)
+ level->right = max_level;
+ if (level->left < 0)
+ level->left = 0;
+ else if (level->left > max_level)
+ level->left = max_level;
+ /* ### WRITE_MIXER_REG ### */
+ dev_mixer_write(base, cmd_left, 0x1f - level->left);
+ /* ### WRITE_MIXER_REG ### */
+ dev_mixer_write(base, cmd_right, 0x1f - level->right);
+ mixer_value[cmd_left] = 0x1f - level->left;
+ mixer_value[cmd_right] = 0x1f - level->right;
+ }
+ /* Get volume (mixer register can not be read in ak4531 codec) */
+ else {
+ /* ### READ_MIXER_REG ### */
+ dev_mixer_read(base, cmd_left);
+ /* ### READ_MIXER_REG ### */
+ dev_mixer_read(base, cmd_right);
+ level->left = 0x1f - mixer_value[cmd_left];
+ level->right = 0x1f - mixer_value[cmd_right];
+ }
+ return OK;
+}
+#endif
+
+#ifdef MIXER_SB16
+int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
+ int max_level, shift, cmd_left, cmd_right;
+
+ max_level = 0x0f;
+ shift = 4;
+ /* Check device */
+ switch (level->device) {
+ case Master:
+ cmd_left = SB16_MASTER_LEFT;
+ cmd_right = SB16_MASTER_RIGHT;
+ break;
+ case Dac:
+ cmd_left = SB16_DAC_LEFT;
+ cmd_right = SB16_DAC_RIGHT;
+ break;
+ case Fm:
+ cmd_left = SB16_FM_LEFT;
+ cmd_right = SB16_FM_RIGHT;
+ break;
+ case Cd:
+ cmd_left = SB16_CD_LEFT;
+ cmd_right = SB16_CD_RIGHT;
+ break;
+ case Line:
+ cmd_left = SB16_LINE_LEFT;
+ cmd_left = SB16_LINE_RIGHT;
+ break;
+ case Mic:
+ cmd_left = cmd_right = SB16_MIC_LEVEL;
+ break;
+ case Speaker:
+ cmd_left = cmd_right = SB16_PC_LEVEL;
+ shift = 6;
+ max_level = 0x03;
+ break;
+ case Treble:
+ cmd_left = SB16_TREBLE_LEFT;
+ cmd_right = SB16_TREBLE_RIGHT;
+ shift = 4;
+ max_level = 0x0f;
+ break;
+ case Bass:
+ cmd_left = SB16_BASS_LEFT;
+ cmd_right = SB16_BASS_RIGHT;
+ shift = 4;
+ max_level = 0x0f;
+ break;
+ default:
+ return EINVAL;
+ }
+ /* Set volume */
+ if (flag) {
+ if (level->right < 0)
+ level->right = 0;
+ else if (level->right > max_level)
+ level->right = max_level;
+ if (level->left < 0)
+ level->left = 0;
+ else if (level->left > max_level)
+ level->left = max_level;
+ /* ### WRITE_MIXER_REG ### */
+ dev_mixer_write(base, cmd_left, level->left << shift);
+ /* ### WRITE_MIXER_REG ### */
+ dev_mixer_write(base, cmd_right, level->right << shift);
+ }
+ /* Get volume */
+ else {
+ /* ### READ_MIXER_REG ### */
+ level->left = dev_mixer_read(base, cmd_left);
+ /* ### READ_MIXER_REG ### */
+ level->right = dev_mixer_read(base, cmd_right);
+ level->left >>= shift;
+ level->right >>= shift;
+ }
+ return OK;
+}
+#endif
+
+#ifdef MIXER_AC97
+int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
+ int max_level, cmd, data;
+
+ max_level = 0x1f;
+ /* Check device */
+ switch (level->device) {
+ case Master:
+ cmd = AC97_MASTER_VOLUME;
+ break;
+ case Dac:
+ return EINVAL;
+ case Fm:
+ cmd = AC97_PCM_OUT_VOLUME;
+ break;
+ case Cd:
+ cmd = AC97_CD_VOLUME;
+ break;
+ case Line:
+ cmd = AC97_LINE_IN_VOLUME;
+ break;
+ case Mic:
+ cmd = AC97_MIC_VOLUME;
+ break;
+ case Speaker:
+ return EINVAL;
+ case Treble:
+ return EINVAL;
+ case Bass:
+ return EINVAL;
+ default:
+ return EINVAL;
+ }
+ /* Set volume */
+ if (flag) {
+ if (level->right < 0)
+ level->right = 0;
+ else if (level->right > max_level)
+ level->right = max_level;
+ if (level->left < 0)
+ level->left = 0;
+ else if (level->left > max_level)
+ level->left = max_level;
+ data = (max_level - level->left) << 8 | (max_level - level->right);
+ /* ### WRITE_MIXER_REG ### */
+ dev_mixer_write(base, cmd, data);
+ }
+ /* Get volume */
+ else {
+ /* ### READ_MIXER_REG ### */
+ data = dev_mixer_read(base, cmd);
+ level->left = (u16_t)(data >> 8);
+ level->right = (u16_t)(data & 0xff);
+ if (level->right < 0)
+ level->right = 0;
+ else if (level->right > max_level)
+ level->right = max_level;
+ if (level->left < 0)
+ level->left = 0;
+ else if (level->left > max_level)
+ level->left = max_level;
+ level->left = max_level - level->left;
+ level->right = max_level - level->right;
+ }
+ return OK;
+}
+#endif
+
+/* Set default mixer volume */
+void dev_set_default_volume(u32_t *base) {
+ int i;
+#ifdef MIXER_AK4531
+ for (i = 0; i <= 0x19; i++)
+ dev_mixer_write(base, i, mixer_value[i]);
+#endif
+#ifdef MIXER_SB16
+ dev_mixer_write(base, SB16_MASTER_LEFT, 0x18 << 3);
+ dev_mixer_write(base, SB16_MASTER_RIGHT, 0x18 << 3);
+ dev_mixer_write(base, SB16_DAC_LEFT, 0x0f << 4);
+ dev_mixer_write(base, SB16_DAC_RIGHT, 0x0f << 4);
+ dev_mixer_write(base, SB16_FM_LEFT, 0x08 << 4);
+ dev_mixer_write(base, SB16_FM_RIGHT, 0x08 << 4);
+ dev_mixer_write(base, SB16_CD_LEFT, 0x08 << 4);
+ dev_mixer_write(base, SB16_CD_RIGHT, 0x08 << 4);
+ dev_mixer_write(base, SB16_LINE_LEFT, 0x08 << 4);
+ dev_mixer_write(base, SB16_LINE_RIGHT, 0x08 << 4);
+ dev_mixer_write(base, SB16_MIC_LEVEL, 0x0f << 4);
+ dev_mixer_write(base, SB16_PC_LEVEL, 0x02 << 6);
+ dev_mixer_write(base, SB16_TREBLE_LEFT, 0x08 << 4);
+ dev_mixer_write(base, SB16_TREBLE_RIGHT, 0x08 << 4);
+ dev_mixer_write(base, SB16_BASS_LEFT, 0x08 << 4);
+ dev_mixer_write(base, SB16_BASS_RIGHT, 0x08 << 4);
+#endif
+
+#ifdef MIXER_AC97
+ dev_mixer_write(base, AC97_POWERDOWN, 0x0000);
+ for (i = 0; i < 50000; i++) {
+ if (dev_mixer_read(base, AC97_POWERDOWN) & 0x03)
+ break;
+ micro_delay(100);
+ }
+ if (i == 50000)
+ printf("SDR: AC97 is not ready\n");
+ dev_mixer_write(base, AC97_MASTER_VOLUME, 0x0000);
+ dev_mixer_write(base, AC97_MONO_VOLUME, 0x8000);
+ dev_mixer_write(base, AC97_PHONE_VOLUME, 0x8008);
+ dev_mixer_write(base, AC97_MIC_VOLUME, 0x0000);
+ dev_mixer_write(base, AC97_LINE_IN_VOLUME, 0x0303);
+ dev_mixer_write(base, AC97_CD_VOLUME, 0x0808);
+ dev_mixer_write(base, AC97_AUX_IN_VOLUME, 0x0808);
+ dev_mixer_write(base, AC97_PCM_OUT_VOLUME, 0x0808);
+ dev_mixer_write(base, AC97_RECORD_GAIN_VOLUME, 0x0000);
+ dev_mixer_write(base, AC97_RECORD_SELECT, 0x0000);
+ dev_mixer_write(base, AC97_GENERAL_PURPOSE, 0x0000);
+#endif
+}