summaryrefslogtreecommitdiffstats
path: root/qemu/roms/u-boot/drivers/sound
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/u-boot/drivers/sound')
-rw-r--r--qemu/roms/u-boot/drivers/sound/Makefile13
-rw-r--r--qemu/roms/u-boot/drivers/sound/max98095.c591
-rw-r--r--qemu/roms/u-boot/drivers/sound/max98095.h317
-rw-r--r--qemu/roms/u-boot/drivers/sound/samsung-i2s.c371
-rw-r--r--qemu/roms/u-boot/drivers/sound/sandbox.c23
-rw-r--r--qemu/roms/u-boot/drivers/sound/sound-i2s.c208
-rw-r--r--qemu/roms/u-boot/drivers/sound/sound.c37
-rw-r--r--qemu/roms/u-boot/drivers/sound/wm8994.c915
-rw-r--r--qemu/roms/u-boot/drivers/sound/wm8994.h69
-rw-r--r--qemu/roms/u-boot/drivers/sound/wm8994_registers.h326
10 files changed, 2870 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/sound/Makefile b/qemu/roms/u-boot/drivers/sound/Makefile
new file mode 100644
index 000000000..981ed614b
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/Makefile
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2012 Samsung Electronics
+# R. Chandrasekar <rcsekar@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_SOUND) += sound.o
+obj-$(CONFIG_I2S) += sound-i2s.o
+obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
+obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
+obj-$(CONFIG_SOUND_WM8994) += wm8994.o
+obj-$(CONFIG_SOUND_MAX98095) += max98095.o
diff --git a/qemu/roms/u-boot/drivers/sound/max98095.c b/qemu/roms/u-boot/drivers/sound/max98095.c
new file mode 100644
index 000000000..febf4195b
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/max98095.c
@@ -0,0 +1,591 @@
+/*
+ * max98095.c -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * Modified for uboot by R. Chandrasekar (rcsekar@samsung.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <div64.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <sound.h>
+#include "i2s.h"
+#include "max98095.h"
+
+enum max98095_type {
+ MAX98095,
+};
+
+struct max98095_priv {
+ enum max98095_type devtype;
+ unsigned int sysclk;
+ unsigned int rate;
+ unsigned int fmt;
+};
+
+static struct sound_codec_info g_codec_info;
+struct max98095_priv g_max98095_info;
+unsigned int g_max98095_i2c_dev_addr;
+
+/* Index 0 is reserved. */
+int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+ 88200, 96000};
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param reg reg number to be write
+ * @param data data to be writen to the above registor
+ *
+ * @return int value 1 for change, 0 for no change or negative error code.
+ */
+static int max98095_i2c_write(unsigned int reg, unsigned char data)
+{
+ debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
+ __func__, reg, data);
+ return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1);
+}
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param reg reg number to be read
+ * @param data address of read data to be stored
+ *
+ * @return int value 0 for success, -1 in case of error.
+ */
+static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data)
+{
+ int ret;
+
+ ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1);
+ if (ret != 0) {
+ debug("%s: Error while reading register %#04x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * update device register bits through i2c
+ *
+ * @param reg codec register
+ * @param mask register mask
+ * @param value new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+static int max98095_update_bits(unsigned int reg, unsigned char mask,
+ unsigned char value)
+{
+ int change, ret = 0;
+ unsigned char old, new;
+
+ if (max98095_i2c_read(reg, &old) != 0)
+ return -1;
+ new = (old & ~mask) | (value & mask);
+ change = (old != new) ? 1 : 0;
+ if (change)
+ ret = max98095_i2c_write(reg, new);
+ if (ret < 0)
+ return ret;
+
+ return change;
+}
+
+/*
+ * codec mclk clock divider coefficients based on sampling rate
+ *
+ * @param rate sampling rate
+ * @param value address of indexvalue to be stored
+ *
+ * @return 0 for success or negative error code.
+ */
+static int rate_value(int rate, u8 *value)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i] >= rate) {
+ *value = i;
+ return 0;
+ }
+ }
+ *value = 1;
+
+ return -1;
+}
+
+/*
+ * Sets hw params for max98095
+ *
+ * @param max98095 max98095 information pointer
+ * @param rate Sampling rate
+ * @param bits_per_sample Bits per sample
+ *
+ * @return -1 for error and 0 Success.
+ */
+static int max98095_hw_params(struct max98095_priv *max98095,
+ enum en_max_audio_interface aif_id,
+ unsigned int rate, unsigned int bits_per_sample)
+{
+ u8 regval;
+ int error;
+ unsigned short M98095_DAI_CLKMODE;
+ unsigned short M98095_DAI_FORMAT;
+ unsigned short M98095_DAI_FILTERS;
+
+ if (aif_id == AIF1) {
+ M98095_DAI_CLKMODE = M98095_027_DAI1_CLKMODE;
+ M98095_DAI_FORMAT = M98095_02A_DAI1_FORMAT;
+ M98095_DAI_FILTERS = M98095_02E_DAI1_FILTERS;
+ } else {
+ M98095_DAI_CLKMODE = M98095_031_DAI2_CLKMODE;
+ M98095_DAI_FORMAT = M98095_034_DAI2_FORMAT;
+ M98095_DAI_FILTERS = M98095_038_DAI2_FILTERS;
+ }
+
+ switch (bits_per_sample) {
+ case 16:
+ error = max98095_update_bits(M98095_DAI_FORMAT,
+ M98095_DAI_WS, 0);
+ break;
+ case 24:
+ error = max98095_update_bits(M98095_DAI_FORMAT,
+ M98095_DAI_WS, M98095_DAI_WS);
+ break;
+ default:
+ debug("%s: Illegal bits per sample %d.\n",
+ __func__, bits_per_sample);
+ return -1;
+ }
+
+ if (rate_value(rate, &regval)) {
+ debug("%s: Failed to set sample rate to %d.\n",
+ __func__, rate);
+ return -1;
+ }
+ max98095->rate = rate;
+
+ error |= max98095_update_bits(M98095_DAI_CLKMODE,
+ M98095_CLKMODE_MASK, regval);
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ error |= max98095_update_bits(M98095_DAI_FILTERS,
+ M98095_DAI_DHF, 0);
+ else
+ error |= max98095_update_bits(M98095_DAI_FILTERS,
+ M98095_DAI_DHF, M98095_DAI_DHF);
+
+ if (error < 0) {
+ debug("%s: Error setting hardware params.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Configures Audio interface system clock for the given frequency
+ *
+ * @param max98095 max98095 information
+ * @param freq Sampling frequency in Hz
+ *
+ * @return -1 for error and 0 success.
+ */
+static int max98095_set_sysclk(struct max98095_priv *max98095,
+ unsigned int freq)
+{
+ int error = 0;
+
+ /* Requested clock frequency is already setup */
+ if (freq == max98095->sysclk)
+ return 0;
+
+ /* Setup clocks for slave mode, and using the PLL
+ * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+ * 0x02 (when master clk is 20MHz to 40MHz)..
+ * 0x03 (when master clk is 40MHz to 60MHz)..
+ */
+ if ((freq >= 10000000) && (freq < 20000000)) {
+ error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
+ } else if ((freq >= 20000000) && (freq < 40000000)) {
+ error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
+ } else if ((freq >= 40000000) && (freq < 60000000)) {
+ error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
+ } else {
+ debug("%s: Invalid master clock frequency\n", __func__);
+ return -1;
+ }
+
+ debug("%s: Clock at %uHz\n", __func__, freq);
+
+ if (error < 0)
+ return -1;
+
+ max98095->sysclk = freq;
+ return 0;
+}
+
+/*
+ * Sets Max98095 I2S format
+ *
+ * @param max98095 max98095 information
+ * @param fmt i2S format - supports a subset of the options defined
+ * in i2s.h.
+ *
+ * @return -1 for error and 0 Success.
+ */
+static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
+ enum en_max_audio_interface aif_id)
+{
+ u8 regval = 0;
+ int error = 0;
+ unsigned short M98095_DAI_CLKCFG_HI;
+ unsigned short M98095_DAI_CLKCFG_LO;
+ unsigned short M98095_DAI_FORMAT;
+ unsigned short M98095_DAI_CLOCK;
+
+ if (fmt == max98095->fmt)
+ return 0;
+
+ max98095->fmt = fmt;
+
+ if (aif_id == AIF1) {
+ M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI;
+ M98095_DAI_CLKCFG_LO = M98095_029_DAI1_CLKCFG_LO;
+ M98095_DAI_FORMAT = M98095_02A_DAI1_FORMAT;
+ M98095_DAI_CLOCK = M98095_02B_DAI1_CLOCK;
+ } else {
+ M98095_DAI_CLKCFG_HI = M98095_032_DAI2_CLKCFG_HI;
+ M98095_DAI_CLKCFG_LO = M98095_033_DAI2_CLKCFG_LO;
+ M98095_DAI_FORMAT = M98095_034_DAI2_FORMAT;
+ M98095_DAI_CLOCK = M98095_035_DAI2_CLOCK;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave mode PLL */
+ error |= max98095_i2c_write(M98095_DAI_CLKCFG_HI,
+ 0x80);
+ error |= max98095_i2c_write(M98095_DAI_CLKCFG_LO,
+ 0x00);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ regval |= M98095_DAI_MAS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ debug("%s: Clock mode unsupported\n", __func__);
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ regval |= M98095_DAI_DLY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ debug("%s: Unrecognized format.\n", __func__);
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ regval |= M98095_DAI_WCI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ regval |= M98095_DAI_BCI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ regval |= M98095_DAI_BCI | M98095_DAI_WCI;
+ break;
+ default:
+ debug("%s: Unrecognized inversion settings.\n", __func__);
+ return -1;
+ }
+
+ error |= max98095_update_bits(M98095_DAI_FORMAT,
+ M98095_DAI_MAS | M98095_DAI_DLY |
+ M98095_DAI_BCI | M98095_DAI_WCI,
+ regval);
+
+ error |= max98095_i2c_write(M98095_DAI_CLOCK,
+ M98095_DAI_BSEL64);
+
+ if (error < 0) {
+ debug("%s: Error setting i2s format.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * resets the audio codec
+ *
+ * @return -1 for error and 0 success.
+ */
+static int max98095_reset(void)
+{
+ int i, ret;
+
+ /*
+ * Gracefully reset the DSP core and the codec hardware in a proper
+ * sequence.
+ */
+ ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
+ if (ret != 0) {
+ debug("%s: Failed to reset DSP: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = max98095_i2c_write(M98095_097_PWR_SYS, 0);
+ if (ret != 0) {
+ debug("%s: Failed to reset codec: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /*
+ * Reset to hardware default for registers, as there is not a soft
+ * reset hardware control register.
+ */
+ for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
+ ret = max98095_i2c_write(i, 0);
+ if (ret < 0) {
+ debug("%s: Failed to reset: %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Intialise max98095 codec device
+ *
+ * @param max98095 max98095 information
+ *
+ * @returns -1 for error and 0 Success.
+ */
+static int max98095_device_init(struct max98095_priv *max98095,
+ enum en_max_audio_interface aif_id)
+{
+ unsigned char id;
+ int error = 0;
+
+ /* reset the codec, the DSP core, and disable all interrupts */
+ error = max98095_reset();
+ if (error != 0) {
+ debug("Reset\n");
+ return error;
+ }
+
+ /* initialize private data */
+ max98095->sysclk = -1U;
+ max98095->rate = -1U;
+ max98095->fmt = -1U;
+
+ error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
+ if (error < 0) {
+ debug("%s: Failure reading hardware revision: %d\n",
+ __func__, id);
+ goto err_access;
+ }
+ debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
+
+ error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
+
+ /*
+ * initialize registers to hardware default configuring audio
+ * interface2 to DAC
+ */
+ if (aif_id == AIF1)
+ error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+ M98095_DAI1L_TO_DACL |
+ M98095_DAI1R_TO_DACR);
+ else
+ error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+ M98095_DAI2M_TO_DACL |
+ M98095_DAI2M_TO_DACR);
+
+ error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
+ M98095_SPK_SPREADSPECTRUM);
+ error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
+ if (aif_id == AIF1)
+ error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
+ M98095_S1NORMAL | M98095_SDATA);
+ else
+ error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
+ M98095_S2NORMAL | M98095_SDATA);
+
+ /* take the codec out of the shut down */
+ error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN,
+ M98095_SHDNRUN);
+ /* route DACL and DACR output to HO and Spekers */
+ error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */
+ error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */
+ error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01); /* DACL */
+ error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */
+
+ /* power Enable */
+ error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
+
+ /* set Volume */
+ error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15);
+ error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15);
+ error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16);
+ error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16);
+
+ /* Enable DAIs */
+ error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
+ if (aif_id == AIF1)
+ error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01);
+ else
+ error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
+
+err_access:
+ if (error < 0)
+ return -1;
+
+ return 0;
+}
+
+static int max98095_do_init(struct sound_codec_info *pcodec_info,
+ enum en_max_audio_interface aif_id,
+ int sampling_rate, int mclk_freq,
+ int bits_per_sample)
+{
+ int ret = 0;
+
+ /* Enable codec clock */
+ set_xclkout();
+
+ /* shift the device address by 1 for 7 bit addressing */
+ g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
+
+ if (pcodec_info->codec_type == CODEC_MAX_98095) {
+ g_max98095_info.devtype = MAX98095;
+ } else {
+ debug("%s: Codec id [%d] not defined\n", __func__,
+ pcodec_info->codec_type);
+ return -1;
+ }
+
+ ret = max98095_device_init(&g_max98095_info, aif_id);
+ if (ret < 0) {
+ debug("%s: max98095 codec chip init failed\n", __func__);
+ return ret;
+ }
+
+ ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
+ if (ret < 0) {
+ debug("%s: max98095 codec set sys clock failed\n", __func__);
+ return ret;
+ }
+
+ ret = max98095_hw_params(&g_max98095_info, aif_id, sampling_rate,
+ bits_per_sample);
+
+ if (ret == 0) {
+ ret = max98095_set_fmt(&g_max98095_info,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ aif_id);
+ }
+
+ return ret;
+}
+
+static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
+ const void *blob)
+{
+ int error = 0;
+#ifdef CONFIG_OF_CONTROL
+ enum fdt_compat_id compat;
+ int node;
+ int parent;
+
+ /* Get the node from FDT for codec */
+ node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC);
+ if (node <= 0) {
+ debug("EXYNOS_SOUND: No node for codec in device tree\n");
+ debug("node = %d\n", node);
+ return -1;
+ }
+
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Cannot find node parent\n", __func__);
+ return -1;
+ }
+
+ compat = fdtdec_lookup(blob, parent);
+ switch (compat) {
+ case COMPAT_SAMSUNG_S3C2440_I2C:
+ pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
+ error |= pcodec_info->i2c_bus;
+ debug("i2c bus = %d\n", pcodec_info->i2c_bus);
+ pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
+ "reg", 0);
+ error |= pcodec_info->i2c_dev_addr;
+ debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr);
+ break;
+ default:
+ debug("%s: Unknown compat id %d\n", __func__, compat);
+ return -1;
+ }
+#else
+ pcodec_info->i2c_bus = AUDIO_I2C_BUS;
+ pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
+ debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
+#endif
+ pcodec_info->codec_type = CODEC_MAX_98095;
+ if (error == -1) {
+ debug("fail to get max98095 codec node properties\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* max98095 Device Initialisation */
+int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
+ int sampling_rate, int mclk_freq,
+ int bits_per_sample)
+{
+ int ret;
+ int old_bus = i2c_get_bus_num();
+ struct sound_codec_info *pcodec_info = &g_codec_info;
+
+ if (get_max98095_codec_values(pcodec_info, blob) < 0) {
+ debug("FDT Codec values failed\n");
+ return -1;
+ }
+
+ i2c_set_bus_num(pcodec_info->i2c_bus);
+ ret = max98095_do_init(pcodec_info, aif_id, sampling_rate, mclk_freq,
+ bits_per_sample);
+ i2c_set_bus_num(old_bus);
+
+ return ret;
+}
diff --git a/qemu/roms/u-boot/drivers/sound/max98095.h b/qemu/roms/u-boot/drivers/sound/max98095.h
new file mode 100644
index 000000000..44b1e3a97
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/max98095.h
@@ -0,0 +1,317 @@
+/*
+ * max98095.h -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98095_H
+#define _MAX98095_H
+
+/* Available audio interface ports in wm8994 codec */
+enum en_max_audio_interface {
+ AIF1 = 1,
+ AIF2,
+};
+
+/*
+ * MAX98095 Registers Definition
+ */
+
+#define M98095_000_HOST_DATA 0x00
+#define M98095_001_HOST_INT_STS 0x01
+#define M98095_002_HOST_RSP_STS 0x02
+#define M98095_003_HOST_CMD_STS 0x03
+#define M98095_004_CODEC_STS 0x04
+#define M98095_005_DAI1_ALC_STS 0x05
+#define M98095_006_DAI2_ALC_STS 0x06
+#define M98095_007_JACK_AUTO_STS 0x07
+#define M98095_008_JACK_MANUAL_STS 0x08
+#define M98095_009_JACK_VBAT_STS 0x09
+#define M98095_00A_ACC_ADC_STS 0x0A
+#define M98095_00B_MIC_NG_AGC_STS 0x0B
+#define M98095_00C_SPK_L_VOLT_STS 0x0C
+#define M98095_00D_SPK_R_VOLT_STS 0x0D
+#define M98095_00E_TEMP_SENSOR_STS 0x0E
+#define M98095_00F_HOST_CFG 0x0F
+#define M98095_010_HOST_INT_CFG 0x10
+#define M98095_011_HOST_INT_EN 0x11
+#define M98095_012_CODEC_INT_EN 0x12
+#define M98095_013_JACK_INT_EN 0x13
+#define M98095_014_JACK_INT_EN 0x14
+#define M98095_015_DEC 0x15
+#define M98095_016_RESERVED 0x16
+#define M98095_017_RESERVED 0x17
+#define M98095_018_KEYCODE3 0x18
+#define M98095_019_KEYCODE2 0x19
+#define M98095_01A_KEYCODE1 0x1A
+#define M98095_01B_KEYCODE0 0x1B
+#define M98095_01C_OEMCODE1 0x1C
+#define M98095_01D_OEMCODE0 0x1D
+#define M98095_01E_XCFG1 0x1E
+#define M98095_01F_XCFG2 0x1F
+#define M98095_020_XCFG3 0x20
+#define M98095_021_XCFG4 0x21
+#define M98095_022_XCFG5 0x22
+#define M98095_023_XCFG6 0x23
+#define M98095_024_XGPIO 0x24
+#define M98095_025_XCLKCFG 0x25
+#define M98095_026_SYS_CLK 0x26
+#define M98095_027_DAI1_CLKMODE 0x27
+#define M98095_028_DAI1_CLKCFG_HI 0x28
+#define M98095_029_DAI1_CLKCFG_LO 0x29
+#define M98095_02A_DAI1_FORMAT 0x2A
+#define M98095_02B_DAI1_CLOCK 0x2B
+#define M98095_02C_DAI1_IOCFG 0x2C
+#define M98095_02D_DAI1_TDM 0x2D
+#define M98095_02E_DAI1_FILTERS 0x2E
+#define M98095_02F_DAI1_LVL1 0x2F
+#define M98095_030_DAI1_LVL2 0x30
+#define M98095_031_DAI2_CLKMODE 0x31
+#define M98095_032_DAI2_CLKCFG_HI 0x32
+#define M98095_033_DAI2_CLKCFG_LO 0x33
+#define M98095_034_DAI2_FORMAT 0x34
+#define M98095_035_DAI2_CLOCK 0x35
+#define M98095_036_DAI2_IOCFG 0x36
+#define M98095_037_DAI2_TDM 0x37
+#define M98095_038_DAI2_FILTERS 0x38
+#define M98095_039_DAI2_LVL1 0x39
+#define M98095_03A_DAI2_LVL2 0x3A
+#define M98095_03B_DAI3_CLKMODE 0x3B
+#define M98095_03C_DAI3_CLKCFG_HI 0x3C
+#define M98095_03D_DAI3_CLKCFG_LO 0x3D
+#define M98095_03E_DAI3_FORMAT 0x3E
+#define M98095_03F_DAI3_CLOCK 0x3F
+#define M98095_040_DAI3_IOCFG 0x40
+#define M98095_041_DAI3_TDM 0x41
+#define M98095_042_DAI3_FILTERS 0x42
+#define M98095_043_DAI3_LVL1 0x43
+#define M98095_044_DAI3_LVL2 0x44
+#define M98095_045_CFG_DSP 0x45
+#define M98095_046_DAC_CTRL1 0x46
+#define M98095_047_DAC_CTRL2 0x47
+#define M98095_048_MIX_DAC_LR 0x48
+#define M98095_049_MIX_DAC_M 0x49
+#define M98095_04A_MIX_ADC_LEFT 0x4A
+#define M98095_04B_MIX_ADC_RIGHT 0x4B
+#define M98095_04C_MIX_HP_LEFT 0x4C
+#define M98095_04D_MIX_HP_RIGHT 0x4D
+#define M98095_04E_CFG_HP 0x4E
+#define M98095_04F_MIX_RCV 0x4F
+#define M98095_050_MIX_SPK_LEFT 0x50
+#define M98095_051_MIX_SPK_RIGHT 0x51
+#define M98095_052_MIX_SPK_CFG 0x52
+#define M98095_053_MIX_LINEOUT1 0x53
+#define M98095_054_MIX_LINEOUT2 0x54
+#define M98095_055_MIX_LINEOUT_CFG 0x55
+#define M98095_056_LVL_SIDETONE_DAI12 0x56
+#define M98095_057_LVL_SIDETONE_DAI3 0x57
+#define M98095_058_LVL_DAI1_PLAY 0x58
+#define M98095_059_LVL_DAI1_EQ 0x59
+#define M98095_05A_LVL_DAI2_PLAY 0x5A
+#define M98095_05B_LVL_DAI2_EQ 0x5B
+#define M98095_05C_LVL_DAI3_PLAY 0x5C
+#define M98095_05D_LVL_ADC_L 0x5D
+#define M98095_05E_LVL_ADC_R 0x5E
+#define M98095_05F_LVL_MIC1 0x5F
+#define M98095_060_LVL_MIC2 0x60
+#define M98095_061_LVL_LINEIN 0x61
+#define M98095_062_LVL_LINEOUT1 0x62
+#define M98095_063_LVL_LINEOUT2 0x63
+#define M98095_064_LVL_HP_L 0x64
+#define M98095_065_LVL_HP_R 0x65
+#define M98095_066_LVL_RCV 0x66
+#define M98095_067_LVL_SPK_L 0x67
+#define M98095_068_LVL_SPK_R 0x68
+#define M98095_069_MICAGC_CFG 0x69
+#define M98095_06A_MICAGC_THRESH 0x6A
+#define M98095_06B_SPK_NOISEGATE 0x6B
+#define M98095_06C_DAI1_ALC1_TIME 0x6C
+#define M98095_06D_DAI1_ALC1_COMP 0x6D
+#define M98095_06E_DAI1_ALC1_EXPN 0x6E
+#define M98095_06F_DAI1_ALC1_GAIN 0x6F
+#define M98095_070_DAI1_ALC2_TIME 0x70
+#define M98095_071_DAI1_ALC2_COMP 0x71
+#define M98095_072_DAI1_ALC2_EXPN 0x72
+#define M98095_073_DAI1_ALC2_GAIN 0x73
+#define M98095_074_DAI1_ALC3_TIME 0x74
+#define M98095_075_DAI1_ALC3_COMP 0x75
+#define M98095_076_DAI1_ALC3_EXPN 0x76
+#define M98095_077_DAI1_ALC3_GAIN 0x77
+#define M98095_078_DAI2_ALC1_TIME 0x78
+#define M98095_079_DAI2_ALC1_COMP 0x79
+#define M98095_07A_DAI2_ALC1_EXPN 0x7A
+#define M98095_07B_DAI2_ALC1_GAIN 0x7B
+#define M98095_07C_DAI2_ALC2_TIME 0x7C
+#define M98095_07D_DAI2_ALC2_COMP 0x7D
+#define M98095_07E_DAI2_ALC2_EXPN 0x7E
+#define M98095_07F_DAI2_ALC2_GAIN 0x7F
+#define M98095_080_DAI2_ALC3_TIME 0x80
+#define M98095_081_DAI2_ALC3_COMP 0x81
+#define M98095_082_DAI2_ALC3_EXPN 0x82
+#define M98095_083_DAI2_ALC3_GAIN 0x83
+#define M98095_084_HP_NOISE_GATE 0x84
+#define M98095_085_AUX_ADC 0x85
+#define M98095_086_CFG_LINE 0x86
+#define M98095_087_CFG_MIC 0x87
+#define M98095_088_CFG_LEVEL 0x88
+#define M98095_089_JACK_DET_AUTO 0x89
+#define M98095_08A_JACK_DET_MANUAL 0x8A
+#define M98095_08B_JACK_KEYSCAN_DBC 0x8B
+#define M98095_08C_JACK_KEYSCAN_DLY 0x8C
+#define M98095_08D_JACK_KEY_THRESH 0x8D
+#define M98095_08E_JACK_DC_SLEW 0x8E
+#define M98095_08F_JACK_TEST_CFG 0x8F
+#define M98095_090_PWR_EN_IN 0x90
+#define M98095_091_PWR_EN_OUT 0x91
+#define M98095_092_PWR_EN_OUT 0x92
+#define M98095_093_BIAS_CTRL 0x93
+#define M98095_094_PWR_DAC_21 0x94
+#define M98095_095_PWR_DAC_03 0x95
+#define M98095_096_PWR_DAC_CK 0x96
+#define M98095_097_PWR_SYS 0x97
+
+#define M98095_0FF_REV_ID 0xFF
+
+#define M98095_REG_CNT (0xFF+1)
+#define M98095_REG_MAX_CACHED 0X97
+
+/* MAX98095 Registers Bit Fields */
+
+/* M98095_00F_HOST_CFG */
+#define M98095_SEG (1<<0)
+#define M98095_XTEN (1<<1)
+#define M98095_MDLLEN (1<<2)
+
+/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
+#define M98095_CLKMODE_MASK 0xFF
+
+/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
+#define M98095_DAI_MAS (1<<7)
+#define M98095_DAI_WCI (1<<6)
+#define M98095_DAI_BCI (1<<5)
+#define M98095_DAI_DLY (1<<4)
+#define M98095_DAI_TDM (1<<2)
+#define M98095_DAI_FSW (1<<1)
+#define M98095_DAI_WS (1<<0)
+
+/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
+#define M98095_DAI_BSEL64 (1<<0)
+#define M98095_DAI_DOSR_DIV2 (0<<5)
+#define M98095_DAI_DOSR_DIV4 (1<<5)
+
+/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
+#define M98095_S1NORMAL (1<<6)
+#define M98095_S2NORMAL (2<<6)
+#define M98095_S3NORMAL (3<<6)
+#define M98095_SDATA (3<<0)
+
+/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
+#define M98095_DAI_DHF (1<<3)
+
+/* M98095_045_DSP_CFG */
+#define M98095_DSPNORMAL (5<<4)
+
+/* M98095_048_MIX_DAC_LR */
+#define M98095_DAI1L_TO_DACR (1<<7)
+#define M98095_DAI1R_TO_DACR (1<<6)
+#define M98095_DAI2M_TO_DACR (1<<5)
+#define M98095_DAI1L_TO_DACL (1<<3)
+#define M98095_DAI1R_TO_DACL (1<<2)
+#define M98095_DAI2M_TO_DACL (1<<1)
+#define M98095_DAI3M_TO_DACL (1<<0)
+
+/* M98095_049_MIX_DAC_M */
+#define M98095_DAI1L_TO_DACM (1<<3)
+#define M98095_DAI1R_TO_DACM (1<<2)
+#define M98095_DAI2M_TO_DACM (1<<1)
+#define M98095_DAI3M_TO_DACM (1<<0)
+
+/* M98095_04E_MIX_HP_CFG */
+#define M98095_HPNORMAL (3<<4)
+
+/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
+#define M98095_MICPRE_MASK (3<<5)
+#define M98095_MICPRE_SHIFT 5
+
+/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
+#define M98095_HP_MUTE (1<<7)
+
+/* M98095_066_LVL_RCV */
+#define M98095_REC_MUTE (1<<7)
+
+/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
+#define M98095_SP_MUTE (1<<7)
+
+/* M98095_087_CFG_MIC */
+#define M98095_MICSEL_MASK (3<<0)
+#define M98095_DIGMIC_L (1<<2)
+#define M98095_DIGMIC_R (1<<3)
+#define M98095_DIGMIC2L (1<<4)
+#define M98095_DIGMIC2R (1<<5)
+
+/* M98095_088_CFG_LEVEL */
+#define M98095_VSEN (1<<6)
+#define M98095_ZDEN (1<<5)
+#define M98095_BQ2EN (1<<3)
+#define M98095_BQ1EN (1<<2)
+#define M98095_EQ2EN (1<<1)
+#define M98095_EQ1EN (1<<0)
+
+/* M98095_090_PWR_EN_IN */
+#define M98095_INEN (1<<7)
+#define M98095_MB2EN (1<<3)
+#define M98095_MB1EN (1<<2)
+#define M98095_MBEN (3<<2)
+#define M98095_ADREN (1<<1)
+#define M98095_ADLEN (1<<0)
+
+/* M98095_091_PWR_EN_OUT */
+#define M98095_HPLEN (1<<7)
+#define M98095_HPREN (1<<6)
+#define M98095_SPLEN (1<<5)
+#define M98095_SPREN (1<<4)
+#define M98095_RECEN (1<<3)
+#define M98095_DALEN (1<<1)
+#define M98095_DAREN (1<<0)
+
+/* M98095_092_PWR_EN_OUT */
+#define M98095_SPK_FIXEDSPECTRUM (0<<4)
+#define M98095_SPK_SPREADSPECTRUM (1<<4)
+
+/* M98095_097_PWR_SYS */
+#define M98095_SHDNRUN (1<<7)
+#define M98095_PERFMODE (1<<3)
+#define M98095_HPPLYBACK (1<<2)
+#define M98095_PWRSV8K (1<<1)
+#define M98095_PWRSV (1<<0)
+
+#define M98095_COEFS_PER_BAND 5
+
+/* Equalizer filter coefficients */
+#define M98095_110_DAI1_EQ_BASE 0x10
+#define M98095_142_DAI2_EQ_BASE 0x42
+
+/* Biquad filter coefficients */
+#define M98095_174_DAI1_BQ_BASE 0x74
+#define M98095_17E_DAI2_BQ_BASE 0x7E
+
+/* function prototype */
+
+/*
+ * intialise max98095 sound codec device for the given configuration
+ *
+ * @param blob FDT node for codec values
+ * @param sampling_rate Sampling rate (Hz)
+ * @param mclk_freq MCLK Frequency (Hz)
+ * @param bits_per_sample bits per Sample (must be 16 or 24)
+ *
+ * @returns -1 for error and 0 Success.
+ */
+int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
+ int sampling_rate, int mclk_freq, int bits_per_sample);
+
+#endif
diff --git a/qemu/roms/u-boot/drivers/sound/samsung-i2s.c b/qemu/roms/u-boot/drivers/sound/samsung-i2s.c
new file mode 100644
index 000000000..47f155f85
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/samsung-i2s.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/arch/clk.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/i2s-regs.h>
+#include <asm/io.h>
+#include <common.h>
+#include <sound.h>
+#include <i2s.h>
+
+#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
+#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
+#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
+#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
+#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
+
+#define TIMEOUT_I2S_TX 100 /* i2s transfer timeout */
+
+/*
+ * Sets the frame size for I2S LR clock
+ *
+ * @param i2s_reg i2s regiter address
+ * @param rfs Frame Size
+ */
+static void i2s_set_lr_framesize(struct i2s_reg *i2s_reg, unsigned int rfs)
+{
+ unsigned int mod = readl(&i2s_reg->mod);
+
+ mod &= ~MOD_RCLK_MASK;
+
+ switch (rfs) {
+ case 768:
+ mod |= MOD_RCLK_768FS;
+ break;
+ case 512:
+ mod |= MOD_RCLK_512FS;
+ break;
+ case 384:
+ mod |= MOD_RCLK_384FS;
+ break;
+ default:
+ mod |= MOD_RCLK_256FS;
+ break;
+ }
+
+ writel(mod, &i2s_reg->mod);
+}
+
+/*
+ * Sets the i2s transfer control
+ *
+ * @param i2s_reg i2s regiter address
+ * @param on 1 enable tx , 0 disable tx transfer
+ */
+static void i2s_txctrl(struct i2s_reg *i2s_reg, int on)
+{
+ unsigned int con = readl(&i2s_reg->con);
+ unsigned int mod = readl(&i2s_reg->mod) & ~MOD_MASK;
+
+ if (on) {
+ con |= CON_ACTIVE;
+ con &= ~CON_TXCH_PAUSE;
+ } else {
+ con |= CON_TXCH_PAUSE;
+ con &= ~CON_ACTIVE;
+ }
+
+ writel(mod, &i2s_reg->mod);
+ writel(con, &i2s_reg->con);
+}
+
+/*
+ * set the bit clock frame size (in multiples of LRCLK)
+ *
+ * @param i2s_reg i2s regiter address
+ * @param bfs bit Frame Size
+ */
+static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs)
+{
+ unsigned int mod = readl(&i2s_reg->mod);
+
+ mod &= ~MOD_BCLK_MASK;
+
+ switch (bfs) {
+ case 48:
+ mod |= MOD_BCLK_48FS;
+ break;
+ case 32:
+ mod |= MOD_BCLK_32FS;
+ break;
+ case 24:
+ mod |= MOD_BCLK_24FS;
+ break;
+ case 16:
+ mod |= MOD_BCLK_16FS;
+ break;
+ default:
+ return;
+ }
+ writel(mod, &i2s_reg->mod);
+}
+
+/*
+ * flushes the i2stx fifo
+ *
+ * @param i2s_reg i2s regiter address
+ * @param flush Tx fifo flush command (0x00 - do not flush
+ * 0x80 - flush tx fifo)
+ */
+void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
+{
+ /* Flush the FIFO */
+ setbits_le32(&i2s_reg->fic, flush);
+ clrbits_le32(&i2s_reg->fic, flush);
+}
+
+/*
+ * Set System Clock direction
+ *
+ * @param i2s_reg i2s regiter address
+ * @param dir Clock direction
+ *
+ * @return int value 0 for success, -1 in case of error
+ */
+int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
+{
+ unsigned int mod = readl(&i2s_reg->mod);
+
+ if (dir == SND_SOC_CLOCK_IN)
+ mod |= MOD_CDCLKCON;
+ else
+ mod &= ~MOD_CDCLKCON;
+
+ writel(mod, &i2s_reg->mod);
+
+ return 0;
+}
+
+/*
+ * Sets I2S Clcok format
+ *
+ * @param fmt i2s clock properties
+ * @param i2s_reg i2s regiter address
+ *
+ * @return int value 0 for success, -1 in case of error
+ */
+int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
+{
+ unsigned int mod = readl(&i2s_reg->mod);
+ unsigned int tmp = 0;
+ unsigned int ret = 0;
+
+ /* Format is priority */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_MSB;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ tmp |= MOD_LR_RLOW;
+ tmp |= MOD_SDF_LSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ tmp |= MOD_SDF_IIS;
+ break;
+ default:
+ debug("%s: Invalid format priority [0x%x]\n", __func__,
+ (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
+ return -1;
+ }
+
+ /*
+ * INV flag is relative to the FORMAT flag - if set it simply
+ * flips the polarity specified by the Standard
+ */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ if (tmp & MOD_LR_RLOW)
+ tmp &= ~MOD_LR_RLOW;
+ else
+ tmp |= MOD_LR_RLOW;
+ break;
+ default:
+ debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
+ (fmt & SND_SOC_DAIFMT_INV_MASK));
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ tmp |= MOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set default source clock in Master mode */
+ ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
+ if (ret != 0) {
+ debug("%s:set i2s clock direction failed\n", __func__);
+ return -1;
+ }
+ break;
+ default:
+ debug("%s: Invalid master selection [0x%x]\n", __func__,
+ (fmt & SND_SOC_DAIFMT_MASTER_MASK));
+ return -1;
+ }
+
+ mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+ mod |= tmp;
+ writel(mod, &i2s_reg->mod);
+
+ return 0;
+}
+
+/*
+ * Sets the sample width in bits
+ *
+ * @param blc samplewidth (size of sample in bits)
+ * @param i2s_reg i2s regiter address
+ *
+ * @return int value 0 for success, -1 in case of error
+ */
+int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
+{
+ unsigned int mod = readl(&i2s_reg->mod);
+
+ mod &= ~MOD_BLCP_MASK;
+ mod &= ~MOD_BLC_MASK;
+
+ switch (blc) {
+ case 8:
+ mod |= MOD_BLCP_8BIT;
+ mod |= MOD_BLC_8BIT;
+ break;
+ case 16:
+ mod |= MOD_BLCP_16BIT;
+ mod |= MOD_BLC_16BIT;
+ break;
+ case 24:
+ mod |= MOD_BLCP_24BIT;
+ mod |= MOD_BLC_24BIT;
+ break;
+ default:
+ debug("%s: Invalid sample size input [0x%x]\n",
+ __func__, blc);
+ return -1;
+ }
+ writel(mod, &i2s_reg->mod);
+
+ return 0;
+}
+
+int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
+ unsigned long data_size)
+{
+ int i;
+ int start;
+ struct i2s_reg *i2s_reg =
+ (struct i2s_reg *)pi2s_tx->base_address;
+
+ if (data_size < FIFO_LENGTH) {
+ debug("%s : Invalid data size\n", __func__);
+ return -1; /* invalid pcm data size */
+ }
+
+ /* fill the tx buffer before stating the tx transmit */
+ for (i = 0; i < FIFO_LENGTH; i++)
+ writel(*data++, &i2s_reg->txd);
+
+ data_size -= FIFO_LENGTH;
+ i2s_txctrl(i2s_reg, I2S_TX_ON);
+
+ while (data_size > 0) {
+ start = get_timer(0);
+ if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
+ writel(*data++, &i2s_reg->txd);
+ data_size--;
+ } else {
+ if (get_timer(start) > TIMEOUT_I2S_TX) {
+ i2s_txctrl(i2s_reg, I2S_TX_OFF);
+ debug("%s: I2S Transfer Timeout\n", __func__);
+ return -1;
+ }
+ }
+ }
+ i2s_txctrl(i2s_reg, I2S_TX_OFF);
+
+ return 0;
+}
+
+int i2s_tx_init(struct i2stx_info *pi2s_tx)
+{
+ int ret;
+ struct i2s_reg *i2s_reg =
+ (struct i2s_reg *)pi2s_tx->base_address;
+ if (pi2s_tx->id == 0) {
+ /* Initialize GPIO for I2S-0 */
+ exynos_pinmux_config(PERIPH_ID_I2S0, 0);
+
+ /* Set EPLL Clock */
+ ret = set_epll_clk(pi2s_tx->samplingrate * pi2s_tx->rfs * 4);
+ } else if (pi2s_tx->id == 1) {
+ /* Initialize GPIO for I2S-1 */
+ exynos_pinmux_config(PERIPH_ID_I2S1, 0);
+
+ /* Set EPLL Clock */
+ ret = set_epll_clk(pi2s_tx->audio_pll_clk);
+ } else {
+ debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
+ return -1;
+ }
+
+ if (ret != 0) {
+ debug("%s: epll clock set rate failed\n", __func__);
+ return -1;
+ }
+
+ /* Select Clk Source for Audio 0 or 1 */
+ ret = set_i2s_clk_source(pi2s_tx->id);
+ if (ret == -1) {
+ debug("%s: unsupported clock for i2s-%d\n", __func__,
+ pi2s_tx->id);
+ return -1;
+ }
+
+ if (pi2s_tx->id == 0) {
+ /*Reset the i2s module */
+ writel(CON_RESET, &i2s_reg->con);
+
+ writel(MOD_OP_CLK | MOD_RCLKSRC, &i2s_reg->mod);
+ /* set i2s prescaler */
+ writel(PSREN | PSVAL, &i2s_reg->psr);
+ } else {
+ /* Set Prescaler to get MCLK */
+ ret = set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk,
+ (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
+ pi2s_tx->id);
+ }
+ if (ret == -1) {
+ debug("%s: unsupported prescalar for i2s-%d\n", __func__,
+ pi2s_tx->id);
+ return -1;
+ }
+
+ /* Configure I2s format */
+ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM));
+ if (ret == 0) {
+ i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
+ ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
+ if (ret != 0) {
+ debug("%s:set sample rate failed\n", __func__);
+ return -1;
+ }
+
+ i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
+ /* disable i2s transfer flag and flush the fifo */
+ i2s_txctrl(i2s_reg, I2S_TX_OFF);
+ i2s_fifo(i2s_reg, FIC_TXFLUSH);
+ } else {
+ debug("%s: failed\n", __func__);
+ }
+
+ return ret;
+}
diff --git a/qemu/roms/u-boot/drivers/sound/sandbox.c b/qemu/roms/u-boot/drivers/sound/sandbox.c
new file mode 100644
index 000000000..fe5c9e9b3
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/sandbox.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/sound.h>
+#include <asm/sdl.h>
+
+int sound_play(uint32_t msec, uint32_t frequency)
+{
+ sandbox_sdl_sound_start(frequency);
+ mdelay(msec);
+ sandbox_sdl_sound_stop();
+
+ return 0;
+}
+
+int sound_init(const void *blob)
+{
+ return sandbox_sdl_sound_init();
+}
diff --git a/qemu/roms/u-boot/drivers/sound/sound-i2s.c b/qemu/roms/u-boot/drivers/sound/sound-i2s.c
new file mode 100644
index 000000000..749bbbd03
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/sound-i2s.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <malloc.h>
+#include <common.h>
+#include <asm/io.h>
+#include <libfdt.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/arch/sound.h>
+#include "wm8994.h"
+#include "max98095.h"
+
+/* defines */
+#define SOUND_400_HZ 400
+#define SOUND_BITS_IN_BYTE 8
+
+static struct i2stx_info g_i2stx_pri;
+
+/*
+ * get_sound_i2s_values gets values for i2s parameters
+ *
+ * @param i2stx_info i2s transmitter transfer param structure
+ * @param blob FDT blob if enabled else NULL
+ */
+static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)
+{
+ int node;
+ int error = 0;
+ int base;
+
+ node = fdt_path_offset(blob, "i2s");
+ if (node <= 0) {
+ debug("EXYNOS_SOUND: No node for sound in device tree\n");
+ return -1;
+ }
+
+ /*
+ * Get the pre-defined sound specific values from FDT.
+ * All of these are expected to be correct otherwise
+ * wrong register values in i2s setup parameters
+ * may result in no sound play.
+ */
+ base = fdtdec_get_addr(blob, node, "reg");
+ if (base == FDT_ADDR_T_NONE) {
+ debug("%s: Missing i2s base\n", __func__);
+ return -1;
+ }
+ i2s->base_address = base;
+
+ i2s->audio_pll_clk = fdtdec_get_int(blob,
+ node, "samsung,i2s-epll-clock-frequency", -1);
+ error |= i2s->audio_pll_clk;
+ debug("audio_pll_clk = %d\n", i2s->audio_pll_clk);
+ i2s->samplingrate = fdtdec_get_int(blob,
+ node, "samsung,i2s-sampling-rate", -1);
+ error |= i2s->samplingrate;
+ debug("samplingrate = %d\n", i2s->samplingrate);
+ i2s->bitspersample = fdtdec_get_int(blob,
+ node, "samsung,i2s-bits-per-sample", -1);
+ error |= i2s->bitspersample;
+ debug("bitspersample = %d\n", i2s->bitspersample);
+ i2s->channels = fdtdec_get_int(blob,
+ node, "samsung,i2s-channels", -1);
+ error |= i2s->channels;
+ debug("channels = %d\n", i2s->channels);
+ i2s->rfs = fdtdec_get_int(blob,
+ node, "samsung,i2s-lr-clk-framesize", -1);
+ error |= i2s->rfs;
+ debug("rfs = %d\n", i2s->rfs);
+ i2s->bfs = fdtdec_get_int(blob,
+ node, "samsung,i2s-bit-clk-framesize", -1);
+ error |= i2s->bfs;
+ debug("bfs = %d\n", i2s->bfs);
+
+ i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1);
+ error |= i2s->id;
+ debug("id = %d\n", i2s->id);
+
+ if (error == -1) {
+ debug("fail to get sound i2s node properties\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Init codec
+ *
+ * @param blob FDT blob
+ * @param pi2s_tx i2s parameters required by codec
+ * @return int value, 0 for success
+ */
+static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
+{
+ int ret;
+ const char *codectype;
+ int node;
+
+ /* Get the node from FDT for sound */
+ node = fdt_path_offset(blob, "i2s");
+ if (node <= 0) {
+ debug("EXYNOS_SOUND: No node for sound in device tree\n");
+ debug("node = %d\n", node);
+ return -1;
+ }
+
+ /*
+ * Get the pre-defined sound codec specific values from FDT.
+ * All of these are expected to be correct otherwise sound
+ * can not be played
+ */
+ codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL);
+ debug("device = %s\n", codectype);
+ if (!strcmp(codectype, "wm8994")) {
+ /* Check the codec type and initialise the same */
+ ret = wm8994_init(blob, pi2s_tx->id + 1,
+ pi2s_tx->samplingrate,
+ (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
+ pi2s_tx->bitspersample, pi2s_tx->channels);
+ } else if (!strcmp(codectype, "max98095")) {
+ ret = max98095_init(blob, pi2s_tx->id + 1,
+ pi2s_tx->samplingrate,
+ (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
+ pi2s_tx->bitspersample);
+ } else {
+ debug("%s: Unknown codec type %s\n", __func__, codectype);
+ return -1;
+ }
+
+ if (ret) {
+ debug("%s: Codec init failed\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int sound_init(const void *blob)
+{
+ int ret;
+ struct i2stx_info *pi2s_tx = &g_i2stx_pri;
+
+ /* Get the I2S Values */
+ if (get_sound_i2s_values(pi2s_tx, blob) < 0) {
+ debug(" FDT I2S values failed\n");
+ return -1;
+ }
+
+ if (codec_init(blob, pi2s_tx) < 0) {
+ debug(" Codec init failed\n");
+ return -1;
+ }
+
+ ret = i2s_tx_init(pi2s_tx);
+ if (ret) {
+ debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
+ ret);
+ return ret;
+ }
+
+
+ return ret;
+}
+
+int sound_play(uint32_t msec, uint32_t frequency)
+{
+ unsigned int *data;
+ unsigned long data_size;
+ unsigned int ret = 0;
+
+ /*Buffer length computation */
+ data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
+ data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
+ data = malloc(data_size);
+
+ if (data == NULL) {
+ debug("%s: malloc failed\n", __func__);
+ return -1;
+ }
+
+ sound_create_square_wave((unsigned short *)data,
+ data_size / sizeof(unsigned short),
+ frequency);
+
+ while (msec >= 1000) {
+ ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
+ (data_size / sizeof(int)));
+ msec -= 1000;
+ }
+ if (msec) {
+ unsigned long size =
+ (data_size * msec) / (sizeof(int) * 1000);
+
+ ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size);
+ }
+
+ free(data);
+
+ return ret;
+}
diff --git a/qemu/roms/u-boot/drivers/sound/sound.c b/qemu/roms/u-boot/drivers/sound/sound.c
new file mode 100644
index 000000000..9dda2dba8
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/sound.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <sound.h>
+
+void sound_create_square_wave(unsigned short *data, int size, uint32_t freq)
+{
+ const int sample = 48000;
+ const unsigned short amplitude = 16000; /* between 1 and 32767 */
+ const int period = freq ? sample / freq : 0;
+ const int half = period / 2;
+
+ assert(freq);
+
+ /* Make sure we don't overflow our buffer */
+ if (size % 2)
+ size--;
+
+ while (size) {
+ int i;
+ for (i = 0; size && i < half; i++) {
+ size -= 2;
+ *data++ = amplitude;
+ *data++ = amplitude;
+ }
+ for (i = 0; size && i < period - half; i++) {
+ size -= 2;
+ *data++ = -amplitude;
+ *data++ = -amplitude;
+ }
+ }
+}
diff --git a/qemu/roms/u-boot/drivers/sound/wm8994.c b/qemu/roms/u-boot/drivers/sound/wm8994.c
new file mode 100644
index 000000000..f8e9a6ead
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/wm8994.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <common.h>
+#include <div64.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/arch/sound.h>
+#include "wm8994.h"
+#include "wm8994_registers.h"
+
+/* defines for wm8994 system clock selection */
+#define SEL_MCLK1 0x00
+#define SEL_MCLK2 0x08
+#define SEL_FLL1 0x10
+#define SEL_FLL2 0x18
+
+/* fll config to configure fll */
+struct wm8994_fll_config {
+ int src; /* Source */
+ int in; /* Input frequency in Hz */
+ int out; /* output frequency in Hz */
+};
+
+/* codec private data */
+struct wm8994_priv {
+ enum wm8994_type type; /* codec type of wolfson */
+ int revision; /* Revision */
+ int sysclk[WM8994_MAX_AIF]; /* System clock frequency in Hz */
+ int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */
+ int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */
+ struct wm8994_fll_config fll[2]; /* fll config to configure fll */
+};
+
+/* wm 8994 supported sampling rate values */
+static unsigned int src_rate[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 88200, 96000
+};
+
+/* op clock divisions */
+static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+
+/* lr clock frame size ratio */
+static int fs_ratios[] = {
+ 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
+};
+
+/* bit clock divisors */
+static int bclk_divs[] = {
+ 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480,
+ 640, 880, 960, 1280, 1760, 1920
+};
+
+static struct wm8994_priv g_wm8994_info;
+static unsigned char g_wm8994_i2c_dev_addr;
+static struct sound_codec_info g_codec_info;
+
+/*
+ * Initialise I2C for wm 8994
+ *
+ * @param bus no i2c bus number in which wm8994 is connected
+ */
+static void wm8994_i2c_init(int bus_no)
+{
+ i2c_set_bus_num(bus_no);
+}
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param reg reg number to be write
+ * @param data data to be writen to the above registor
+ *
+ * @return int value 1 for change, 0 for no change or negative error code.
+ */
+static int wm8994_i2c_write(unsigned int reg, unsigned short data)
+{
+ unsigned char val[2];
+
+ val[0] = (unsigned char)((data >> 8) & 0xff);
+ val[1] = (unsigned char)(data & 0xff);
+ debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data);
+
+ return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+}
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param reg reg number to be read
+ * @param data address of read data to be stored
+ *
+ * @return int value 0 for success, -1 in case of error.
+ */
+static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
+{
+ unsigned char val[2];
+ int ret;
+
+ ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+ if (ret != 0) {
+ debug("%s: Error while reading register %#04x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ *data = val[0];
+ *data <<= 8;
+ *data |= val[1];
+
+ return 0;
+}
+
+/*
+ * update device register bits through i2c
+ *
+ * @param reg codec register
+ * @param mask register mask
+ * @param value new value
+ *
+ * @return int value 1 if change in the register value,
+ * 0 for no change or negative error code.
+ */
+static int wm8994_update_bits(unsigned int reg, unsigned short mask,
+ unsigned short value)
+{
+ int change , ret = 0;
+ unsigned short old, new;
+
+ if (wm8994_i2c_read(reg, &old) != 0)
+ return -1;
+ new = (old & ~mask) | (value & mask);
+ change = (old != new) ? 1 : 0;
+ if (change)
+ ret = wm8994_i2c_write(reg, new);
+ if (ret < 0)
+ return ret;
+
+ return change;
+}
+
+/*
+ * Sets i2s set format
+ *
+ * @param aif_id Interface ID
+ * @param fmt i2S format
+ *
+ * @return -1 for error and 0 Success.
+ */
+int wm8994_set_fmt(int aif_id, unsigned int fmt)
+{
+ int ms_reg;
+ int aif_reg;
+ int ms = 0;
+ int aif = 0;
+ int aif_clk = 0;
+ int error = 0;
+
+ switch (aif_id) {
+ case 1:
+ ms_reg = WM8994_AIF1_MASTER_SLAVE;
+ aif_reg = WM8994_AIF1_CONTROL_1;
+ aif_clk = WM8994_AIF1_CLOCKING_1;
+ break;
+ case 2:
+ ms_reg = WM8994_AIF2_MASTER_SLAVE;
+ aif_reg = WM8994_AIF2_CONTROL_1;
+ aif_clk = WM8994_AIF2_CLOCKING_1;
+ break;
+ default:
+ debug("%s: Invalid audio interface selection\n", __func__);
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ms = WM8994_AIF1_MSTR;
+ break;
+ default:
+ debug("%s: Invalid i2s master selection\n", __func__);
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_B:
+ aif |= WM8994_AIF1_LRCLK_INV;
+ case SND_SOC_DAIFMT_DSP_A:
+ aif |= 0x18;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ aif |= 0x10;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aif |= 0x8;
+ break;
+ default:
+ debug("%s: Invalid i2s format selection\n", __func__);
+ return -1;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ /* frame inversion not valid for DSP modes */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif |= WM8994_AIF1_BCLK_INV;
+ break;
+ default:
+ debug("%s: Invalid i2s frame inverse selection\n",
+ __func__);
+ return -1;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ aif |= WM8994_AIF1_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ aif |= WM8994_AIF1_LRCLK_INV;
+ break;
+ default:
+ debug("%s: Invalid i2s clock polarity selection\n",
+ __func__);
+ return -1;
+ }
+ break;
+ default:
+ debug("%s: Invalid i2s format selection\n", __func__);
+ return -1;
+ }
+
+ error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
+ WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
+
+ error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms);
+ error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK,
+ WM8994_AIF1CLK_ENA);
+ if (error < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Sets hw params FOR WM8994
+ *
+ * @param wm8994 wm8994 information pointer
+ * @param aif_id Audio interface ID
+ * @param sampling_rate Sampling rate
+ * @param bits_per_sample Bits per sample
+ * @param Channels Channels in the given audio input
+ *
+ * @return -1 for error and 0 Success.
+ */
+static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
+ unsigned int sampling_rate, unsigned int bits_per_sample,
+ unsigned int channels)
+{
+ int aif1_reg;
+ int aif2_reg;
+ int bclk_reg;
+ int bclk = 0;
+ int rate_reg;
+ int aif1 = 0;
+ int aif2 = 0;
+ int rate_val = 0;
+ int id = aif_id - 1;
+ int i, cur_val, best_val, bclk_rate, best;
+ unsigned short reg_data;
+ int ret = 0;
+
+ switch (aif_id) {
+ case 1:
+ aif1_reg = WM8994_AIF1_CONTROL_1;
+ aif2_reg = WM8994_AIF1_CONTROL_2;
+ bclk_reg = WM8994_AIF1_BCLK;
+ rate_reg = WM8994_AIF1_RATE;
+ break;
+ case 2:
+ aif1_reg = WM8994_AIF2_CONTROL_1;
+ aif2_reg = WM8994_AIF2_CONTROL_2;
+ bclk_reg = WM8994_AIF2_BCLK;
+ rate_reg = WM8994_AIF2_RATE;
+ break;
+ default:
+ return -1;
+ }
+
+ bclk_rate = sampling_rate * 32;
+ switch (bits_per_sample) {
+ case 16:
+ bclk_rate *= 16;
+ break;
+ case 20:
+ bclk_rate *= 20;
+ aif1 |= 0x20;
+ break;
+ case 24:
+ bclk_rate *= 24;
+ aif1 |= 0x40;
+ break;
+ case 32:
+ bclk_rate *= 32;
+ aif1 |= 0x60;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Try to find an appropriate sample rate; look for an exact match. */
+ for (i = 0; i < ARRAY_SIZE(src_rate); i++)
+ if (src_rate[i] == sampling_rate)
+ break;
+
+ if (i == ARRAY_SIZE(src_rate)) {
+ debug("%s: Could not get the best matching samplingrate\n",
+ __func__);
+ return -1;
+ }
+
+ rate_val |= i << WM8994_AIF1_SR_SHIFT;
+
+ /* AIFCLK/fs ratio; look for a close match in either direction */
+ best = 0;
+ best_val = abs((fs_ratios[0] * sampling_rate)
+ - wm8994->aifclk[id]);
+
+ for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
+ cur_val = abs((fs_ratios[i] * sampling_rate)
+ - wm8994->aifclk[id]);
+ if (cur_val >= best_val)
+ continue;
+ best = i;
+ best_val = cur_val;
+ }
+
+ rate_val |= best;
+
+ /*
+ * We may not get quite the right frequency if using
+ * approximate clocks so look for the closest match that is
+ * higher than the target (we need to ensure that there enough
+ * BCLKs to clock out the samples).
+ */
+ best = 0;
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+ if (cur_val < 0) /* BCLK table is sorted */
+ break;
+ best = i;
+ }
+
+ if (i == ARRAY_SIZE(bclk_divs)) {
+ debug("%s: Could not get the best matching bclk division\n",
+ __func__);
+ return -1;
+ }
+
+ bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+ bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
+
+ if (wm8994_i2c_read(aif1_reg, &reg_data) != 0) {
+ debug("%s: AIF1 register read Failed\n", __func__);
+ return -1;
+ }
+
+ if ((channels == 1) && ((reg_data & 0x18) == 0x18))
+ aif2 |= WM8994_AIF1_MONO;
+
+ if (wm8994->aifclk[id] == 0) {
+ debug("%s:Audio interface clock not set\n", __func__);
+ return -1;
+ }
+
+ ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+ ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2);
+ ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
+ ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK |
+ WM8994_AIF1CLK_RATE_MASK, rate_val);
+
+ debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
+
+ if (ret < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Configures Audio interface Clock
+ *
+ * @param wm8994 wm8994 information pointer
+ * @param aif Audio Interface ID
+ *
+ * @return -1 for error and 0 Success.
+ */
+static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
+{
+ int rate;
+ int reg1 = 0;
+ int offset;
+ int ret;
+
+ /* AIF(1/0) register adress offset calculated */
+ if (aif-1)
+ offset = 4;
+ else
+ offset = 0;
+
+ switch (wm8994->sysclk[aif-1]) {
+ case WM8994_SYSCLK_MCLK1:
+ reg1 |= SEL_MCLK1;
+ rate = wm8994->mclk[0];
+ break;
+
+ case WM8994_SYSCLK_MCLK2:
+ reg1 |= SEL_MCLK2;
+ rate = wm8994->mclk[1];
+ break;
+
+ case WM8994_SYSCLK_FLL1:
+ reg1 |= SEL_FLL1;
+ rate = wm8994->fll[0].out;
+ break;
+
+ case WM8994_SYSCLK_FLL2:
+ reg1 |= SEL_FLL2;
+ rate = wm8994->fll[1].out;
+ break;
+
+ default:
+ debug("%s: Invalid input clock selection [%d]\n",
+ __func__, wm8994->sysclk[aif-1]);
+ return -1;
+ }
+
+ /* if input clock frequenct is more than 135Mhz then divide */
+ if (rate >= WM8994_MAX_INPUT_CLK_FREQ) {
+ rate /= 2;
+ reg1 |= WM8994_AIF1CLK_DIV;
+ }
+
+ wm8994->aifclk[aif-1] = rate;
+
+ ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,
+ WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+ reg1);
+
+ if (aif == WM8994_AIF1)
+ ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+ WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK,
+ WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
+ else if (aif == WM8994_AIF2)
+ ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+ WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
+ WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
+ WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
+
+ if (ret < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Configures Audio interface for the given frequency
+ *
+ * @param wm8994 wm8994 information
+ * @param aif_id Audio Interface
+ * @param clk_id Input Clock ID
+ * @param freq Sampling frequency in Hz
+ *
+ * @return -1 for error and 0 success.
+ */
+static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
+ int clk_id, unsigned int freq)
+{
+ int i;
+ int ret = 0;
+
+ wm8994->sysclk[aif_id - 1] = clk_id;
+
+ switch (clk_id) {
+ case WM8994_SYSCLK_MCLK1:
+ wm8994->mclk[0] = freq;
+ if (aif_id == 2) {
+ ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
+ WM8994_AIF2DAC_DIV_MASK , 0);
+ }
+ break;
+
+ case WM8994_SYSCLK_MCLK2:
+ /* TODO: Set GPIO AF */
+ wm8994->mclk[1] = freq;
+ break;
+
+ case WM8994_SYSCLK_FLL1:
+ case WM8994_SYSCLK_FLL2:
+ break;
+
+ case WM8994_SYSCLK_OPCLK:
+ /*
+ * Special case - a division (times 10) is given and
+ * no effect on main clocking.
+ */
+ if (freq) {
+ for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
+ if (opclk_divs[i] == freq)
+ break;
+ if (i == ARRAY_SIZE(opclk_divs)) {
+ debug("%s frequency divisor not found\n",
+ __func__);
+ return -1;
+ }
+ ret = wm8994_update_bits(WM8994_CLOCKING_2,
+ WM8994_OPCLK_DIV_MASK, i);
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+ } else {
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA, 0);
+ }
+
+ default:
+ debug("%s Invalid input clock selection [%d]\n",
+ __func__, clk_id);
+ return -1;
+ }
+
+ ret |= configure_aif_clock(wm8994, aif_id);
+
+ if (ret < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Initializes Volume for AIF2 to HP path
+ *
+ * @returns -1 for error and 0 Success.
+ *
+ */
+static int wm8994_init_volume_aif2_dac1(void)
+{
+ int ret;
+
+ /* Unmute AIF2DAC */
+ ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
+ WM8994_AIF2DAC_MUTE_MASK, 0);
+
+
+ ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME,
+ WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
+ WM8994_AIF2DAC_VU | 0xff);
+
+ ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME,
+ WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
+ WM8994_AIF2DAC_VU | 0xff);
+
+
+ ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
+ WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+ WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+
+ ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
+ WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+ WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+ /* Head Phone Volume */
+ ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+ ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+
+ if (ret < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Initializes Volume for AIF1 to HP path
+ *
+ * @returns -1 for error and 0 Success.
+ *
+ */
+static int wm8994_init_volume_aif1_dac1(void)
+{
+ int ret = 0;
+
+ /* Unmute AIF1DAC */
+ ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000);
+
+ ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
+ WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+ WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+
+ ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
+ WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+ WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+ /* Head Phone Volume */
+ ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+ ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+
+ if (ret < 0) {
+ debug("%s: codec register access error\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Intialise wm8994 codec device
+ *
+ * @param wm8994 wm8994 information
+ *
+ * @returns -1 for error and 0 Success.
+ */
+static int wm8994_device_init(struct wm8994_priv *wm8994,
+ enum en_audio_interface aif_id)
+{
+ const char *devname;
+ unsigned short reg_data;
+ int ret;
+
+ wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
+
+ ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, &reg_data);
+ if (ret < 0) {
+ debug("Failed to read ID register\n");
+ goto err;
+ }
+
+ if (reg_data == WM8994_ID) {
+ devname = "WM8994";
+ debug("Device registered as type %d\n", wm8994->type);
+ wm8994->type = WM8994;
+ } else {
+ debug("Device is not a WM8994, ID is %x\n", ret);
+ ret = -1;
+ goto err;
+ }
+
+ ret = wm8994_i2c_read(WM8994_CHIP_REVISION, &reg_data);
+ if (ret < 0) {
+ debug("Failed to read revision register: %d\n", ret);
+ goto err;
+ }
+ wm8994->revision = reg_data;
+ debug("%s revision %c\n", devname, 'A' + wm8994->revision);
+
+ /* VMID Selection */
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
+ WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
+
+ /* Charge Pump Enable */
+ ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
+ WM8994_CP_ENA);
+
+ /* Head Phone Power Enable */
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
+ WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
+
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
+ WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
+
+ if (aif_id == WM8994_AIF1) {
+ ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2,
+ WM8994_TSHUT_ENA | WM8994_MIXINL_ENA |
+ WM8994_MIXINR_ENA | WM8994_IN2L_ENA |
+ WM8994_IN2R_ENA);
+
+ ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_4,
+ WM8994_ADCL_ENA | WM8994_ADCR_ENA |
+ WM8994_AIF1ADC1R_ENA |
+ WM8994_AIF1ADC1L_ENA);
+
+ /* Power enable for AIF1 and DAC1 */
+ ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_5,
+ WM8994_AIF1DACL_ENA |
+ WM8994_AIF1DACR_ENA |
+ WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
+ } else if (aif_id == WM8994_AIF2) {
+ /* Power enable for AIF2 and DAC1 */
+ ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5,
+ WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK |
+ WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK,
+ WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
+ WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
+ }
+ /* Head Phone Initialisation */
+ ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+ WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
+ WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
+
+ ret |= wm8994_update_bits(WM8994_DC_SERVO_1,
+ WM8994_DCS_ENA_CHAN_0_MASK |
+ WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
+ WM8994_DCS_ENA_CHAN_1);
+
+ ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+ WM8994_HPOUT1L_DLY_MASK |
+ WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
+ WM8994_HPOUT1R_OUTP_MASK |
+ WM8994_HPOUT1L_RMV_SHORT_MASK |
+ WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY |
+ WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP |
+ WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT |
+ WM8994_HPOUT1R_RMV_SHORT);
+
+ /* MIXER Config DAC1 to HP */
+ ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1,
+ WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L);
+
+ ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2,
+ WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R);
+
+ if (aif_id == WM8994_AIF1) {
+ /* Routing AIF1 to DAC1 */
+ ret |= wm8994_i2c_write(WM8994_DAC1_LEFT_MIXER_ROUTING,
+ WM8994_AIF1DAC1L_TO_DAC1L);
+
+ ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
+ WM8994_AIF1DAC1R_TO_DAC1R);
+
+ /* GPIO Settings for AIF1 */
+ ret |= wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT
+ | WM8994_GPIO_FUNCTION_I2S_CLK
+ | WM8994_GPIO_INPUT_DEBOUNCE);
+
+ ret |= wm8994_init_volume_aif1_dac1();
+ } else if (aif_id == WM8994_AIF2) {
+ /* Routing AIF2 to DAC1 */
+ ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING,
+ WM8994_AIF2DACL_TO_DAC1L_MASK,
+ WM8994_AIF2DACL_TO_DAC1L);
+
+ ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
+ WM8994_AIF2DACR_TO_DAC1R_MASK,
+ WM8994_AIF2DACR_TO_DAC1R);
+
+ /* GPIO Settings for AIF2 */
+ /* B CLK */
+ ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
+ WM8994_GPIO_FUNCTION_MASK ,
+ WM8994_GPIO_DIR_OUTPUT);
+
+ /* LR CLK */
+ ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
+ WM8994_GPIO_FUNCTION_MASK,
+ WM8994_GPIO_DIR_OUTPUT);
+
+ /* DATA */
+ ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
+ WM8994_GPIO_FUNCTION_MASK,
+ WM8994_GPIO_DIR_OUTPUT);
+
+ ret |= wm8994_init_volume_aif2_dac1();
+ }
+
+ if (ret < 0)
+ goto err;
+
+ debug("%s: Codec chip init ok\n", __func__);
+ return 0;
+err:
+ debug("%s: Codec chip init error\n", __func__);
+ return -1;
+}
+
+/*
+ * Gets fdt values for wm8994 config parameters
+ *
+ * @param pcodec_info codec information structure
+ * @param blob FDT blob
+ * @return int value, 0 for success
+ */
+static int get_codec_values(struct sound_codec_info *pcodec_info,
+ const void *blob)
+{
+ int error = 0;
+#ifdef CONFIG_OF_CONTROL
+ enum fdt_compat_id compat;
+ int node;
+ int parent;
+
+ /* Get the node from FDT for codec */
+ node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC);
+ if (node <= 0) {
+ debug("EXYNOS_SOUND: No node for codec in device tree\n");
+ debug("node = %d\n", node);
+ return -1;
+ }
+
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Cannot find node parent\n", __func__);
+ return -1;
+ }
+
+ compat = fdtdec_lookup(blob, parent);
+ switch (compat) {
+ case COMPAT_SAMSUNG_S3C2440_I2C:
+ pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
+ error |= pcodec_info->i2c_bus;
+ debug("i2c bus = %d\n", pcodec_info->i2c_bus);
+ pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
+ "reg", 0);
+ error |= pcodec_info->i2c_dev_addr;
+ debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
+ break;
+ default:
+ debug("%s: Unknown compat id %d\n", __func__, compat);
+ return -1;
+ }
+#else
+ pcodec_info->i2c_bus = AUDIO_I2C_BUS;
+ pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
+ debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
+#endif
+
+ pcodec_info->codec_type = CODEC_WM_8994;
+
+ if (error == -1) {
+ debug("fail to get wm8994 codec node properties\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* WM8994 Device Initialisation */
+int wm8994_init(const void *blob, enum en_audio_interface aif_id,
+ int sampling_rate, int mclk_freq,
+ int bits_per_sample, unsigned int channels)
+{
+ int ret = 0;
+ struct sound_codec_info *pcodec_info = &g_codec_info;
+
+ /* Get the codec Values */
+ if (get_codec_values(pcodec_info, blob) < 0) {
+ debug("FDT Codec values failed\n");
+ return -1;
+ }
+
+ /* shift the device address by 1 for 7 bit addressing */
+ g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr;
+ wm8994_i2c_init(pcodec_info->i2c_bus);
+
+ if (pcodec_info->codec_type == CODEC_WM_8994) {
+ g_wm8994_info.type = WM8994;
+ } else {
+ debug("%s: Codec id [%d] not defined\n", __func__,
+ pcodec_info->codec_type);
+ return -1;
+ }
+
+ ret = wm8994_device_init(&g_wm8994_info, aif_id);
+ if (ret < 0) {
+ debug("%s: wm8994 codec chip init failed\n", __func__);
+ return ret;
+ }
+
+ ret = wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1,
+ mclk_freq);
+ if (ret < 0) {
+ debug("%s: wm8994 codec set sys clock failed\n", __func__);
+ return ret;
+ }
+
+ ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
+ bits_per_sample, channels);
+
+ if (ret == 0) {
+ ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ }
+ return ret;
+}
diff --git a/qemu/roms/u-boot/drivers/sound/wm8994.h b/qemu/roms/u-boot/drivers/sound/wm8994.h
new file mode 100644
index 000000000..6d0c7ca27
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/wm8994.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chadrasekar <rcsekar@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __WM8994_H__
+#define __WM8994_H__
+
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
+#define WM8994_SYSCLK_MCLK1 1
+#define WM8994_SYSCLK_MCLK2 2
+#define WM8994_SYSCLK_FLL1 3
+#define WM8994_SYSCLK_FLL2 4
+
+/* Avilable audi interface ports in wm8994 codec */
+enum en_audio_interface {
+ WM8994_AIF1 = 1,
+ WM8994_AIF2,
+ WM8994_AIF3
+};
+
+/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */
+#define WM8994_SYSCLK_OPCLK 5
+
+#define WM8994_FLL1 1
+#define WM8994_FLL2 2
+
+#define WM8994_FLL_SRC_MCLK1 1
+#define WM8994_FLL_SRC_MCLK2 2
+#define WM8994_FLL_SRC_LRCLK 3
+#define WM8994_FLL_SRC_BCLK 4
+
+/* maximum available digital interfac in the dac to configure */
+#define WM8994_MAX_AIF 2
+
+#define WM8994_MAX_INPUT_CLK_FREQ 13500000
+#define WM8994_ID 0x8994
+
+enum wm8994_vmid_mode {
+ WM8994_VMID_NORMAL,
+ WM8994_VMID_FORCE,
+};
+
+/* wm 8994 family devices */
+enum wm8994_type {
+ WM8994 = 0,
+ WM8958 = 1,
+ WM1811 = 2,
+};
+
+/*
+ * intialise wm8994 sound codec device for the given configuration
+ *
+ * @param blob FDT node for codec values
+ * @param aif_id enum value of codec interface port in which
+ * soc i2s is connected
+ * @param sampling_rate Sampling rate ranges between from 8khz to 96khz
+ * @param mclk_freq Master clock frequency.
+ * @param bits_per_sample bits per Sample can be 16 or 24
+ * @param channels Number of channnels, maximum 2
+ *
+ * @returns -1 for error and 0 Success.
+ */
+int wm8994_init(const void *blob, enum en_audio_interface aif_id,
+ int sampling_rate, int mclk_freq,
+ int bits_per_sample, unsigned int channels);
+#endif /*__WM8994_H__ */
diff --git a/qemu/roms/u-boot/drivers/sound/wm8994_registers.h b/qemu/roms/u-boot/drivers/sound/wm8994_registers.h
new file mode 100644
index 000000000..0aba2fdfd
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/sound/wm8994_registers.h
@@ -0,0 +1,326 @@
+/*
+ * (C) Copyright 2012 Samsung Electronics
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __WM8994_REGISTERS_H__
+#define __WM8994_REGISTERS_H__
+
+/*
+ * Register values.
+ */
+#define WM8994_SOFTWARE_RESET 0x00
+#define WM8994_POWER_MANAGEMENT_1 0x01
+#define WM8994_POWER_MANAGEMENT_2 0x02
+#define WM8994_POWER_MANAGEMENT_4 0x04
+#define WM8994_POWER_MANAGEMENT_5 0x05
+#define WM8994_LEFT_OUTPUT_VOLUME 0x1C
+#define WM8994_RIGHT_OUTPUT_VOLUME 0x1D
+#define WM8994_OUTPUT_MIXER_1 0x2D
+#define WM8994_OUTPUT_MIXER_2 0x2E
+#define WM8994_CHARGE_PUMP_1 0x4C
+#define WM8994_DC_SERVO_1 0x54
+#define WM8994_ANALOGUE_HP_1 0x60
+#define WM8994_CHIP_REVISION 0x100
+#define WM8994_AIF1_CLOCKING_1 0x200
+#define WM8994_AIF1_CLOCKING_2 0x201
+#define WM8994_AIF2_CLOCKING_1 0x204
+#define WM8994_CLOCKING_1 0x208
+#define WM8994_CLOCKING_2 0x209
+#define WM8994_AIF1_RATE 0x210
+#define WM8994_AIF2_RATE 0x211
+#define WM8994_RATE_STATUS 0x212
+#define WM8994_AIF1_CONTROL_1 0x300
+#define WM8994_AIF1_CONTROL_2 0x301
+#define WM8994_AIF1_MASTER_SLAVE 0x302
+#define WM8994_AIF1_BCLK 0x303
+#define WM8994_AIF2_CONTROL_1 0x310
+#define WM8994_AIF2_CONTROL_2 0x311
+#define WM8994_AIF2_MASTER_SLAVE 0x312
+#define WM8994_AIF2_BCLK 0x313
+#define WM8994_AIF1_DAC_FILTERS_1 0x420
+#define WM8994_AIF2_DAC_LEFT_VOLUME 0x502
+#define WM8994_AIF2_DAC_RIGHT_VOLUME 0x503
+#define WM8994_AIF2_DAC_FILTERS_1 0x520
+#define WM8994_DAC1_LEFT_MIXER_ROUTING 0x601
+#define WM8994_DAC1_RIGHT_MIXER_ROUTING 0x602
+#define WM8994_DAC1_LEFT_VOLUME 0x610
+#define WM8994_DAC1_RIGHT_VOLUME 0x611
+#define WM8994_GPIO_1 0x700
+#define WM8994_GPIO_3 0x702
+#define WM8994_GPIO_4 0x703
+#define WM8994_GPIO_5 0x704
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+/* SW_RESET */
+#define WM8994_SW_RESET 1
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+/* HPOUT1L_ENA */
+#define WM8994_HPOUT1L_ENA 0x0200
+/* HPOUT1L_ENA */
+#define WM8994_HPOUT1L_ENA_MASK 0x0200
+/* HPOUT1R_ENA */
+#define WM8994_HPOUT1R_ENA 0x0100
+/* HPOUT1R_ENA */
+#define WM8994_HPOUT1R_ENA_MASK 0x0100
+/* VMID_SEL - [2:1] */
+#define WM8994_VMID_SEL_MASK 0x0006
+/* BIAS_ENA */
+#define WM8994_BIAS_ENA 0x0001
+/* BIAS_ENA */
+#define WM8994_BIAS_ENA_MASK 0x0001
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+/* OPCLK_ENA */
+#define WM8994_OPCLK_ENA 0x0800
+
+#define WM8994_TSHUT_ENA 0x4000
+#define WM8994_MIXINL_ENA 0x0200
+#define WM8994_MIXINR_ENA 0x0100
+#define WM8994_IN2L_ENA 0x0080
+#define WM8994_IN2R_ENA 0x0020
+
+/*
+ * R5 (0x04) - Power Management (4)
+ */
+#define WM8994_ADCL_ENA 0x0001
+#define WM8994_ADCR_ENA 0x0002
+#define WM8994_AIF1ADC1R_ENA 0x0100
+#define WM8994_AIF1ADC1L_ENA 0x0200
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+/* AIF2DACL_ENA */
+#define WM8994_AIF2DACL_ENA 0x2000
+#define WM8994_AIF2DACL_ENA_MASK 0x2000
+/* AIF2DACR_ENA */
+#define WM8994_AIF2DACR_ENA 0x1000
+#define WM8994_AIF2DACR_ENA_MASK 0x1000
+/* AIF1DACL_ENA */
+#define WM8994_AIF1DACL_ENA 0x0200
+#define WM8994_AIF1DACL_ENA_MASK 0x0200
+/* AIF1DACR_ENA */
+#define WM8994_AIF1DACR_ENA 0x0100
+#define WM8994_AIF1DACR_ENA_MASK 0x0100
+/* DAC1L_ENA */
+#define WM8994_DAC1L_ENA 0x0002
+#define WM8994_DAC1L_ENA_MASK 0x0002
+/* DAC1R_ENA */
+#define WM8994_DAC1R_ENA 0x0001
+#define WM8994_DAC1R_ENA_MASK 0x0001
+
+/*
+ * R45 (0x2D) - Output Mixer (1)
+ */
+/* DAC1L_TO_HPOUT1L */
+#define WM8994_DAC1L_TO_HPOUT1L 0x0100
+#define WM8994_DAC1L_TO_HPOUT1L_MASK 0x0100
+
+/*
+ * R46 (0x2E) - Output Mixer (2)
+ */
+/* DAC1R_TO_HPOUT1R */
+#define WM8994_DAC1R_TO_HPOUT1R 0x0100
+#define WM8994_DAC1R_TO_HPOUT1R_MASK 0x0100
+
+/*
+ * R76 (0x4C) - Charge Pump (1)
+ */
+/* CP_ENA */
+#define WM8994_CP_ENA 0x8000
+#define WM8994_CP_ENA_MASK 0x8000
+/*
+ * R84 (0x54) - DC Servo (1)
+ */
+/* DCS_ENA_CHAN_1 */
+#define WM8994_DCS_ENA_CHAN_1 0x0002
+#define WM8994_DCS_ENA_CHAN_1_MASK 0x0002
+/* DCS_ENA_CHAN_0 */
+#define WM8994_DCS_ENA_CHAN_0 0x0001
+#define WM8994_DCS_ENA_CHAN_0_MASK 0x0001
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+/* HPOUT1L_RMV_SHORT */
+#define WM8994_HPOUT1L_RMV_SHORT 0x0080
+#define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080
+/* HPOUT1L_OUTP */
+#define WM8994_HPOUT1L_OUTP 0x0040
+#define WM8994_HPOUT1L_OUTP_MASK 0x0040
+/* HPOUT1L_DLY */
+#define WM8994_HPOUT1L_DLY 0x0020
+#define WM8994_HPOUT1L_DLY_MASK 0x0020
+/* HPOUT1R_RMV_SHORT */
+#define WM8994_HPOUT1R_RMV_SHORT 0x0008
+#define WM8994_HPOUT1R_RMV_SHORT_MASK 0x0008
+/* HPOUT1R_OUTP */
+#define WM8994_HPOUT1R_OUTP 0x0004
+#define WM8994_HPOUT1R_OUTP_MASK 0x0004
+/* HPOUT1R_DLY */
+#define WM8994_HPOUT1R_DLY 0x0002
+#define WM8994_HPOUT1R_DLY_MASK 0x0002
+
+/*
+ * R512 (0x200) - AIF1 Clocking (1)
+ */
+/* AIF1CLK_SRC - [4:3] */
+#define WM8994_AIF1CLK_SRC_MASK 0x0018
+/* AIF1CLK_DIV */
+#define WM8994_AIF1CLK_DIV 0x0002
+/* AIF1CLK_ENA */
+#define WM8994_AIF1CLK_ENA 0x0001
+#define WM8994_AIF1CLK_ENA_MASK 0x0001
+
+/*
+ * R517 (0x205) - AIF2 Clocking (2)
+ */
+/* AIF2DAC_DIV - [5:3] */
+#define WM8994_AIF2DAC_DIV_MASK 0x0038
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+/* AIF1DSPCLK_ENA */
+#define WM8994_AIF1DSPCLK_ENA 0x0008
+#define WM8994_AIF1DSPCLK_ENA_MASK 0x0008
+/* AIF2DSPCLK_ENA */
+#define WM8994_AIF2DSPCLK_ENA 0x0004
+#define WM8994_AIF2DSPCLK_ENA_MASK 0x0004
+/* SYSDSPCLK_ENA */
+#define WM8994_SYSDSPCLK_ENA 0x0002
+#define WM8994_SYSDSPCLK_ENA_MASK 0x0002
+/* SYSCLK_SRC */
+#define WM8994_SYSCLK_SRC 0x0001
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+/* OPCLK_DIV - [2:0] */
+#define WM8994_OPCLK_DIV_MASK 0x0007
+
+/*
+ * R528 (0x210) - AIF1 Rate
+ */
+/* AIF1_SR - [7:4] */
+#define WM8994_AIF1_SR_MASK 0x00F0
+#define WM8994_AIF1_SR_SHIFT 4
+/* AIF1CLK_RATE - [3:0] */
+#define WM8994_AIF1CLK_RATE_MASK 0x000F
+
+/*
+ * R768 (0x300) - AIF1 Control (1)
+ */
+/* AIF1_BCLK_INV */
+#define WM8994_AIF1_BCLK_INV 0x0100
+/* AIF1_LRCLK_INV */
+#define WM8994_AIF1_LRCLK_INV 0x0080
+#define WM8994_AIF1_LRCLK_INV_MASK 0x0080
+/* AIF1_WL - [6:5] */
+#define WM8994_AIF1_WL_MASK 0x0060
+/* AIF1_FMT - [4:3] */
+#define WM8994_AIF1_FMT_MASK 0x0018
+
+/*
+ * R769 (0x301) - AIF1 Control (2)
+ */
+/* AIF1_MONO */
+#define WM8994_AIF1_MONO 0x0100
+
+/*
+ * R770 (0x302) - AIF1 Master/Slave
+ */
+/* AIF1_MSTR */
+#define WM8994_AIF1_MSTR 0x4000
+#define WM8994_AIF1_MSTR_MASK 0x4000
+
+/*
+ * R771 (0x303) - AIF1 BCLK
+ */
+/* AIF1_BCLK_DIV - [8:4] */
+#define WM8994_AIF1_BCLK_DIV_MASK 0x01F0
+#define WM8994_AIF1_BCLK_DIV_SHIFT 4
+
+/*
+ * R1282 (0x502) - AIF2 DAC Left Volume
+ */
+/* AIF2DAC_VU */
+#define WM8994_AIF2DAC_VU 0x0100
+#define WM8994_AIF2DAC_VU_MASK 0x0100
+/* AIF2DACL_VOL - [7:0] */
+#define WM8994_AIF2DACL_VOL_MASK 0x00FF
+
+/*
+ * R1283 (0x503) - AIF2 DAC Right Volume
+ */
+/* AIF2DACR_VOL - [7:0] */
+#define WM8994_AIF2DACR_VOL_MASK 0x00FF
+
+/*
+ * R1312 (0x520) - AIF2 DAC Filters (1)
+ */
+/* AIF2DAC_MUTE */
+#define WM8994_AIF2DAC_MUTE_MASK 0x0200
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+/* AIF2DACL_TO_DAC1L */
+#define WM8994_AIF2DACL_TO_DAC1L 0x0004
+#define WM8994_AIF2DACL_TO_DAC1L_MASK 0x0004
+/* AIF1DAC1L_TO_DAC1L */
+#define WM8994_AIF1DAC1L_TO_DAC1L 0x0001
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+/* AIF2DACR_TO_DAC1R */
+#define WM8994_AIF2DACR_TO_DAC1R 0x0004
+#define WM8994_AIF2DACR_TO_DAC1R_MASK 0x0004
+/* AIF1DAC1R_TO_DAC1R */
+#define WM8994_AIF1DAC1R_TO_DAC1R 0x0001
+
+/*
+ * R1552 (0x610) - DAC1 Left Volume
+ */
+/* DAC1L_MUTE */
+#define WM8994_DAC1L_MUTE_MASK 0x0200
+/* DAC1_VU */
+#define WM8994_DAC1_VU 0x0100
+#define WM8994_DAC1_VU_MASK 0x0100
+/* DAC1L_VOL - [7:0] */
+#define WM8994_DAC1L_VOL_MASK 0x00FF
+
+/*
+ * R1553 (0x611) - DAC1 Right Volume
+ */
+/* DAC1R_MUTE */
+#define WM8994_DAC1R_MUTE_MASK 0x0200
+/* DAC1R_VOL - [7:0] */
+#define WM8994_DAC1R_VOL_MASK 0x00FF
+
+/*
+ * GPIO
+ */
+/* OUTPUT PIN */
+#define WM8994_GPIO_DIR_OUTPUT 0x8000
+/* GPIO PIN MASK */
+#define WM8994_GPIO_DIR_MASK 0xFFE0
+/* I2S CLK */
+#define WM8994_GPIO_FUNCTION_I2S_CLK 0x0001
+#define WM8994_GPIO_INPUT_DEBOUNCE 0x0100
+/* GPn FN */
+#define WM8994_GPIO_FUNCTION_MASK 0x001F
+#endif