summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-12-14 14:18:47 -0500
committerTom Rini <trini@konsulko.com>2018-12-14 14:18:47 -0500
commit8fc26fce41592175ae004514e431e68a9dd60671 (patch)
tree9d4f5d9b057a749742e9dcead3cfa41c4ddae5ea /drivers
parentd117d8f19b0625f88309e47a8a32c2faa384dddc (diff)
parentf987177db9c988142032ed8142a093cce2378a90 (diff)
downloadu-boot-8fc26fce41592175ae004514e431e68a9dd60671.tar.gz
u-boot-8fc26fce41592175ae004514e431e68a9dd60671.tar.xz
u-boot-8fc26fce41592175ae004514e431e68a9dd60671.zip
Merge tag 'dm-pull-14dec18' of git://git.denx.de/u-boot-dm
Complete conversion of sound to driver model
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/read.c23
-rw-r--r--drivers/sound/Kconfig8
-rw-r--r--drivers/sound/Makefile8
-rw-r--r--drivers/sound/codec-uclass.c26
-rw-r--r--drivers/sound/i2s-uclass.c25
-rw-r--r--drivers/sound/max98090.c377
-rw-r--r--drivers/sound/max98090.h663
-rw-r--r--drivers/sound/max98095.c411
-rw-r--r--drivers/sound/max98095.h9
-rw-r--r--drivers/sound/maxim_codec.c87
-rw-r--r--drivers/sound/maxim_codec.h67
-rw-r--r--drivers/sound/samsung-i2s.c157
-rw-r--r--drivers/sound/samsung_sound.c104
-rw-r--r--drivers/sound/sandbox.c180
-rw-r--r--drivers/sound/sound-i2s.c208
-rw-r--r--drivers/sound/sound-uclass.c127
-rw-r--r--drivers/sound/sound.c11
-rw-r--r--drivers/sound/wm8994.c470
-rw-r--r--drivers/sound/wm8994.h2
19 files changed, 2180 insertions, 783 deletions
diff --git a/drivers/core/read.c b/drivers/core/read.c
index cdd78be03e..3c46b3674e 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -21,6 +21,29 @@ int dev_read_u32_default(struct udevice *dev, const char *propname, int def)
return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
}
+int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp)
+{
+ return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp);
+}
+
+int dev_read_s32_default(struct udevice *dev, const char *propname, int def)
+{
+ return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp)
+{
+ u32 val;
+ int ret;
+
+ ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+ if (ret)
+ return ret;
+ *outp = val;
+
+ return 0;
+}
+
const char *dev_read_string(struct udevice *dev, const char *propname)
{
return ofnode_read_string(dev_ofnode(dev), propname);
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 5de86c05c6..c0d97cca33 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -31,6 +31,14 @@ config I2S_SAMSUNG
option provides an implementation for sound_init() and
sound_play().
+config SOUND_MAX98090
+ bool "Support Maxim max98090 audio codec"
+ depends on I2S_SAMSUNG
+ help
+ Enable the max98090 audio codec. This is connected via I2S for
+ audio data and I2C for codec control. At present it only works
+ with the Samsung I2S driver.
+
config SOUND_MAX98095
bool "Support Maxim max98095 audio codec"
depends on I2S_SAMSUNG
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 696c5aecbe..1de4346ec7 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -4,8 +4,12 @@
# R. Chandrasekar <rcsekar@samsung.com>
obj-$(CONFIG_SOUND) += sound.o
-obj-$(CONFIG_I2S) += sound-i2s.o
+obj-$(CONFIG_SOUND) += codec-uclass.o
+obj-$(CONFIG_SOUND) += i2s-uclass.o
+obj-$(CONFIG_SOUND) += sound-uclass.o
obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
+obj-$(CONFIG_I2S_SAMSUNG) += samsung_sound.o
obj-$(CONFIG_SOUND_WM8994) += wm8994.o
-obj-$(CONFIG_SOUND_MAX98095) += max98095.o
+obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o
+obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o
diff --git a/drivers/sound/codec-uclass.c b/drivers/sound/codec-uclass.c
new file mode 100644
index 0000000000..1ec77acfc1
--- /dev/null
+++ b/drivers/sound/codec-uclass.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <audio_codec.h>
+
+int audio_codec_set_params(struct udevice *dev, int interface, int rate,
+ int mclk_freq, int bits_per_sample, uint channels)
+{
+ struct audio_codec_ops *ops = audio_codec_get_ops(dev);
+
+ if (!ops->set_params)
+ return -ENOSYS;
+
+ return ops->set_params(dev, interface, rate, mclk_freq, bits_per_sample,
+ channels);
+}
+
+UCLASS_DRIVER(audio_codec) = {
+ .id = UCLASS_AUDIO_CODEC,
+ .name = "audio-codec",
+};
diff --git a/drivers/sound/i2s-uclass.c b/drivers/sound/i2s-uclass.c
new file mode 100644
index 0000000000..b741e3952d
--- /dev/null
+++ b/drivers/sound/i2s-uclass.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+
+int i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+ struct i2s_ops *ops = i2s_get_ops(dev);
+
+ if (!ops->tx_data)
+ return -ENOSYS;
+
+ return ops->tx_data(dev, data, data_size);
+}
+
+UCLASS_DRIVER(i2s) = {
+ .id = UCLASS_I2S,
+ .name = "i2s",
+ .per_device_auto_alloc_size = sizeof(struct i2s_uc_priv),
+};
diff --git a/drivers/sound/max98090.c b/drivers/sound/max98090.c
new file mode 100644
index 0000000000..346ff5ffbe
--- /dev/null
+++ b/drivers/sound/max98090.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <div64.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+#include "max98090.h"
+
+/*
+ * Sets hw params for max98090
+ *
+ * @priv: max98090 information pointer
+ * @rate: Sampling rate
+ * @bits_per_sample: Bits per sample
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_hw_params(struct maxim_priv *priv, unsigned int rate,
+ unsigned int bits_per_sample)
+{
+ int error;
+ unsigned char value;
+
+ switch (bits_per_sample) {
+ case 16:
+ maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+ error = maxim_bic_or(priv, M98090_REG_INTERFACE_FORMAT,
+ M98090_WS_MASK, 0);
+ maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+ break;
+ default:
+ debug("%s: Illegal bits per sample %d.\n",
+ __func__, bits_per_sample);
+ return -1;
+ }
+
+ /* Update filter mode */
+ if (rate < 240000)
+ error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+ M98090_MODE_MASK, 0);
+ else
+ error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+ M98090_MODE_MASK, M98090_MODE_MASK);
+
+ /* Update sample rate mode */
+ if (rate < 50000)
+ error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+ M98090_DHF_MASK, 0);
+ else
+ error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+ M98090_DHF_MASK, M98090_DHF_MASK);
+
+ if (error < 0) {
+ debug("%s: Error setting hardware params.\n", __func__);
+ return -EIO;
+ }
+ priv->rate = rate;
+
+ return 0;
+}
+
+/*
+ * Configures Audio interface system clock for the given frequency
+ *
+ * @priv: max98090 information
+ * @freq: Sampling frequency in Hz
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_sysclk(struct maxim_priv *priv, unsigned int freq)
+{
+ int error = 0;
+
+ /* Requested clock frequency is already setup */
+ if (freq == priv->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 = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+ M98090_PSCLK_DIV1);
+ } else if (freq >= 20000000 && freq < 40000000) {
+ error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+ M98090_PSCLK_DIV2);
+ } else if (freq >= 40000000 && freq < 60000000) {
+ error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+ M98090_PSCLK_DIV4);
+ } else {
+ debug("%s: Invalid master clock frequency\n", __func__);
+ return -1;
+ }
+
+ debug("%s: Clock at %uHz\n", __func__, freq);
+
+ if (error < 0)
+ return -1;
+
+ priv->sysclk = freq;
+
+ return 0;
+}
+
+/*
+ * Sets Max98090 I2S format
+ *
+ * @priv: max98090 information
+ * @fmt: i2S format - supports a subset of the options defined in i2s.h.
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_fmt(struct maxim_priv *priv, int fmt)
+{
+ u8 regval = 0;
+ int error = 0;
+
+ if (fmt == priv->fmt)
+ return 0;
+
+ priv->fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Set to slave mode PLL - MAS mode off */
+ error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB,
+ 0x00);
+ error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB,
+ 0x00);
+ error |= maxim_bic_or(priv, M98090_REG_CLOCK_MODE,
+ M98090_USE_M1_MASK, 0);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Set to master mode */
+ debug("Master mode not supported\n");
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ default:
+ debug("%s: Clock mode unsupported\n", __func__);
+ return -EINVAL;
+ }
+
+ error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, regval);
+
+ regval = 0;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ regval |= M98090_DLY_MASK;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ regval |= M98090_RJ_MASK;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* Not supported mode */
+ default:
+ debug("%s: Unrecognized format.\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ regval |= M98090_WCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ regval |= M98090_BCI_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ regval |= M98090_BCI_MASK | M98090_WCI_MASK;
+ break;
+ default:
+ debug("%s: Unrecognized inversion settings.\n", __func__);
+ return -EINVAL;
+ }
+
+ error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, regval);
+
+ if (error < 0) {
+ debug("%s: Error setting i2s format.\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * resets the audio codec
+ *
+ * @priv: max98090 information
+ * @return -EIO for error, 0 for success.
+ */
+static int max98090_reset(struct maxim_priv *priv)
+{
+ int ret;
+
+ /*
+ * Gracefully reset the DSP core and the codec hardware in a proper
+ * sequence.
+ */
+ ret = maxim_i2c_write(priv, M98090_REG_SOFTWARE_RESET,
+ M98090_SWRESET_MASK);
+ if (ret != 0) {
+ debug("%s: Failed to reset DSP: %d\n", __func__, ret);
+ return ret;
+ }
+ mdelay(20);
+
+ return 0;
+}
+
+/*
+ * Initialise max98090 codec device
+ *
+ * @priv: max98090 information
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_device_init(struct maxim_priv *priv)
+{
+ unsigned char id;
+ int error = 0;
+
+ /* Enable codec clock */
+ set_xclkout();
+
+ /* reset the codec, the DSP core, and disable all interrupts */
+ error = max98090_reset(priv);
+ if (error != 0) {
+ debug("Reset\n");
+ return error;
+ }
+
+ /* initialize private data */
+ priv->sysclk = -1U;
+ priv->rate = -1U;
+ priv->fmt = -1U;
+
+ error = maxim_i2c_read(priv, M98090_REG_REVISION_ID, &id);
+ if (error < 0) {
+ debug("%s: Failure reading hardware revision: %d\n",
+ __func__, id);
+ return -EIO;
+ }
+ debug("%s: Hardware revision: %d\n", __func__, id);
+
+ return 0;
+}
+
+static int max98090_setup_interface(struct maxim_priv *priv)
+{
+ unsigned char id;
+ int error;
+
+ /* Reading interrupt status to clear them */
+ error = maxim_i2c_read(priv, M98090_REG_DEVICE_STATUS, &id);
+
+ error |= maxim_i2c_write(priv, M98090_REG_DAC_CONTROL,
+ M98090_DACHP_MASK);
+ error |= maxim_i2c_write(priv, M98090_REG_BIAS_CONTROL,
+ M98090_VCM_MODE_MASK);
+
+ error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_MIXER, 0x1);
+ error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_MIXER, 0x2);
+
+ error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_VOLUME, 0x25);
+ error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_VOLUME, 0x25);
+
+ error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB, 0x0);
+ error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB, 0x0);
+ error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, 0x0);
+ error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, 0x0);
+ error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+ M98090_SDIEN_MASK);
+ error |= maxim_i2c_write(priv, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK);
+ error |= maxim_i2c_write(priv, M98090_REG_OUTPUT_ENABLE,
+ M98090_HPREN_MASK | M98090_HPLEN_MASK |
+ M98090_SPREN_MASK | M98090_SPLEN_MASK |
+ M98090_DAREN_MASK | M98090_DALEN_MASK);
+ error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+ M98090_SDOEN_MASK | M98090_SDIEN_MASK);
+
+ if (error < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int max98090_do_init(struct maxim_priv *priv, int sampling_rate,
+ int mclk_freq, int bits_per_sample)
+{
+ int ret = 0;
+
+ ret = max98090_setup_interface(priv);
+ if (ret < 0) {
+ debug("%s: max98090 setup interface failed\n", __func__);
+ return ret;
+ }
+
+ ret = max98090_set_sysclk(priv, mclk_freq);
+ if (ret < 0) {
+ debug("%s: max98090 codec set sys clock failed\n", __func__);
+ return ret;
+ }
+
+ ret = max98090_hw_params(priv, sampling_rate, bits_per_sample);
+
+ if (ret == 0) {
+ ret = max98090_set_fmt(priv, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ }
+
+ return ret;
+}
+
+static int max98090_set_params(struct udevice *dev, int interface, int rate,
+ int mclk_freq, int bits_per_sample,
+ uint channels)
+{
+ struct maxim_priv *priv = dev_get_priv(dev);
+
+ return max98090_do_init(priv, rate, mclk_freq, bits_per_sample);
+}
+
+static int max98090_probe(struct udevice *dev)
+{
+ struct maxim_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->dev = dev;
+ ret = max98090_device_init(priv);
+ if (ret < 0) {
+ debug("%s: max98090 codec chip init failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct audio_codec_ops max98090_ops = {
+ .set_params = max98090_set_params,
+};
+
+static const struct udevice_id max98090_ids[] = {
+ { .compatible = "maxim,max98090" },
+ { }
+};
+
+U_BOOT_DRIVER(max98090) = {
+ .name = "max98090",
+ .id = UCLASS_AUDIO_CODEC,
+ .of_match = max98090_ids,
+ .probe = max98090_probe,
+ .ops = &max98090_ops,
+ .priv_auto_alloc_size = sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98090.h b/drivers/sound/max98090.h
new file mode 100644
index 0000000000..3a6983b8e2
--- /dev/null
+++ b/drivers/sound/max98090.h
@@ -0,0 +1,663 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * max98090.h -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#ifndef _MAX98090_H
+#define _MAX98090_H
+
+#include "maxim_codec.h"
+
+/* MAX98090 Registers Definition */
+
+#define M98090_REG_SOFTWARE_RESET 0x00
+#define M98090_REG_DEVICE_STATUS 0x01
+
+#define M98090_REG_QUICK_SAMPLE_RATE 0x05
+#define M98090_REG_DAI_INTERFACE 0x06
+#define M98090_REG_DAC_PATH 0x07
+
+#define M98090_REG_MIC_BIAS_VOLTAGE 0x12
+#define M98090_REG_DIGITAL_MIC_ENABLE 0x13
+#define M98090_REG_DIGITAL_MIC_CONFIG 0x14
+#define M98090_REG_SYSTEM_CLOCK 0x1B
+#define M98090_REG_CLOCK_RATIO_NI_MSB 0x1D
+#define M98090_REG_CLOCK_MODE 0x1C
+#define M98090_REG_CLOCK_RATIO_NI_LSB 0x1E
+
+#define M98090_REG_MASTER_MODE 0x21
+#define M98090_REG_INTERFACE_FORMAT 0x22
+#define M98090_REG_IO_CONFIGURATION 0x25
+#define M98090_REG_FILTER_CONFIG 0x26
+
+#define M98090_REG_LEFT_HP_MIXER 0x29
+#define M98090_REG_RIGHT_HP_MIXER 0x2a
+#define M98090_REG_HP_CONTROL 0x2b
+#define M98090_REG_LEFT_HP_VOLUME 0x2c
+#define M98090_REG_RIGHT_HP_VOLUME 0x2d
+#define M98090_REG_LEFT_SPK_MIXER 0x2e
+#define M98090_REG_RIGHT_SPK_MIXER 0x2f
+#define M98090_REG_SPK_CONTROL 0x30
+#define M98090_REG_LEFT_SPK_VOLUME 0x31
+#define M98090_REG_RIGHT_SPK_VOLUME 0x32
+
+#define M98090_REG_RCV_LOUTL_CONTROL 0x38
+#define M98090_REG_RCV_LOUTL_VOLUME 0x39
+#define M98090_REG_LOUTR_MIXER 0x3a
+#define M98090_REG_LOUTR_CONTROL 0x3b
+#define M98090_REG_LOUTR_VOLUME 0x3c
+#define M98090_REG_JACK_DETECT 0x3d
+#define M98090_REG_INPUT_ENABLE 0x3e
+#define M98090_REG_OUTPUT_ENABLE 0x3f
+#define M98090_REG_LEVEL_CONTROL 0x40
+#define M98090_REG_DSP_FILTER_ENABLE 0x41
+#define M98090_REG_BIAS_CONTROL 0x42
+#define M98090_REG_DAC_CONTROL 0x43
+#define M98090_REG_ADC_CONTROL 0x44
+#define M98090_REG_DEVICE_SHUTDOWN 0x45
+
+#define M98090_REG_REVISION_ID 0xff
+
+#define M98090_REG_CNT (0xff + 1)
+#define M98090_REG_MAX_CACHed 0x45
+
+/* MAX98090 Registers Bit Fields */
+
+/*
+ * M98090_REG_SOFTWARE_RESET 0x00
+ */
+#define M98090_SWRESET_MASK BIT(7)
+
+/*
+ * M98090_REG_QUICK_SAMPLE_RATE 0x05
+ */
+#define M98090_SR_96K_MASK BIT(5)
+#define M98090_SR_96K_SHIFT 5
+#define M98090_SR_96K_WIDTH 1
+#define M98090_SR_32K_MASK BIT(4)
+#define M98090_SR_32K_SHIFT 4
+#define M98090_SR_32K_WIDTH 1
+#define M98090_SR_48K_MASK BIT(3)
+#define M98090_SR_48K_SHIFT 3
+#define M98090_SR_48K_WIDTH 1
+#define M98090_SR_44K1_MASK BIT(2)
+#define M98090_SR_44K1_SHIFT 2
+#define M98090_SR_44K1_WIDTH 1
+#define M98090_SR_16K_MASK BIT(1)
+#define M98090_SR_16K_SHIFT 1
+#define M98090_SR_16K_WIDTH 1
+#define M98090_SR_8K_MASK BIT(0)
+#define M98090_SR_8K_SHIFT 0
+#define M98090_SR_8K_WIDTH 1
+#define M98090_SR_MASK 0x3F
+#define M98090_SR_ALL_SHIFT 0
+#define M98090_SR_ALL_WIDTH 8
+#define M98090_SR_ALL_NUM BIT(M98090_SR_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAI_INTERFACE 0x06
+ */
+#define M98090_RJ_M_MASK BIT(5)
+#define M98090_RJ_M_SHIFT 5
+#define M98090_RJ_M_WIDTH 1
+#define M98090_RJ_S_MASK BIT(4)
+#define M98090_RJ_S_SHIFT 4
+#define M98090_RJ_S_WIDTH 1
+#define M98090_LJ_M_MASK BIT(3)
+#define M98090_LJ_M_SHIFT 3
+#define M98090_LJ_M_WIDTH 1
+#define M98090_LJ_S_MASK BIT(2)
+#define M98090_LJ_S_SHIFT 2
+#define M98090_LJ_S_WIDTH 1
+#define M98090_I2S_M_MASK BIT(1)
+#define M98090_I2S_M_SHIFT 1
+#define M98090_I2S_M_WIDTH 1
+#define M98090_I2S_S_MASK BIT(0)
+#define M98090_I2S_S_SHIFT 0
+#define M98090_I2S_S_WIDTH 1
+#define M98090_DAI_ALL_SHIFT 0
+#define M98090_DAI_ALL_WIDTH 8
+#define M98090_DAI_ALL_NUM BIT(M98090_DAI_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAC_PATH 0x07
+ */
+#define M98090_DIG2_HP_MASK BIT(7)
+#define M98090_DIG2_HP_SHIFT 7
+#define M98090_DIG2_HP_WIDTH 1
+#define M98090_DIG2_EAR_MASK BIT(6)
+#define M98090_DIG2_EAR_SHIFT 6
+#define M98090_DIG2_EAR_WIDTH 1
+#define M98090_DIG2_SPK_MASK BIT(5)
+#define M98090_DIG2_SPK_SHIFT 5
+#define M98090_DIG2_SPK_WIDTH 1
+#define M98090_DIG2_LOUT_MASK BIT(4)
+#define M98090_DIG2_LOUT_SHIFT 4
+#define M98090_DIG2_LOUT_WIDTH 1
+#define M98090_DIG2_ALL_SHIFT 0
+#define M98090_DIG2_ALL_WIDTH 8
+#define M98090_DIG2_ALL_NUM BIT(M98090_DIG2_ALL_WIDTH)
+
+/*
+ * M98090_REG_MIC_BIAS_VOLTAGE 0x12
+ */
+#define M98090_MBVSEL_MASK (3 << 0)
+#define M98090_MBVSEL_SHIFT 0
+#define M98090_MBVSEL_WIDTH 2
+#define M98090_MBVSEL_2V8 (3 << 0)
+#define M98090_MBVSEL_2V55 (2 << 0)
+#define M98090_MBVSEL_2V4 BIT(0)
+#define M98090_MBVSEL_2V2 (0 << 0)
+
+/*
+ * M98090_REG_DIGITAL_MIC_ENABLE 0x13
+ */
+#define M98090_MICCLK_MASK (7 << 4)
+#define M98090_MICCLK_SHIFT 4
+#define M98090_MICCLK_WIDTH 3
+#define M98090_DIGMIC4_MASK BIT(3)
+#define M98090_DIGMIC4_SHIFT 3
+#define M98090_DIGMIC4_WIDTH 1
+#define M98090_DIGMIC4_NUM BIT(M98090_DIGMIC4_WIDTH)
+#define M98090_DIGMIC3_MASK BIT(2)
+#define M98090_DIGMIC3_SHIFT 2
+#define M98090_DIGMIC3_WIDTH 1
+#define M98090_DIGMIC3_NUM BIT(M98090_DIGMIC3_WIDTH)
+#define M98090_DIGMICR_MASK BIT(1)
+#define M98090_DIGMICR_SHIFT 1
+#define M98090_DIGMICR_WIDTH 1
+#define M98090_DIGMICR_NUM BIT(M98090_DIGMICR_WIDTH)
+#define M98090_DIGMICL_MASK BIT(0)
+#define M98090_DIGMICL_SHIFT 0
+#define M98090_DIGMICL_WIDTH 1
+#define M98090_DIGMICL_NUM BIT(M98090_DIGMICL_WIDTH)
+
+/*
+ * M98090_REG_DIGITAL_MIC_CONFIG 0x14
+ */
+#define M98090_DMIC_COMP_MASK (15 << 4)
+#define M98090_DMIC_COMP_SHIFT 4
+#define M98090_DMIC_COMP_WIDTH 4
+#define M98090_DMIC_COMP_NUM BIT(M98090_DMIC_COMP_WIDTH)
+#define M98090_DMIC_FREQ_MASK (3 << 0)
+#define M98090_DMIC_FREQ_SHIFT 0
+#define M98090_DMIC_FREQ_WIDTH 2
+
+/*
+ * M98090_REG_CLOCK_MODE 0x1B
+ */
+#define M98090_PSCLK_MASK (3 << 4)
+#define M98090_PSCLK_SHIFT 4
+#define M98090_PSCLK_WIDTH 2
+#define M98090_PSCLK_DISABLED (0 << 4)
+#define M98090_PSCLK_DIV1 BIT(4)
+#define M98090_PSCLK_DIV2 (2 << 4)
+#define M98090_PSCLK_DIV4 (3 << 4)
+
+/*
+ * M98090_REG_INTERFACE_FORMAT 0x22
+ */
+#define M98090_RJ_MASK BIT(5)
+#define M98090_RJ_SHIFT 5
+#define M98090_RJ_WIDTH 1
+#define M98090_WCI_MASK BIT(4)
+#define M98090_WCI_SHIFT 4
+#define M98090_WCI_WIDTH 1
+#define M98090_BCI_MASK BIT(3)
+#define M98090_BCI_SHIFT 3
+#define M98090_BCI_WIDTH 1
+#define M98090_DLY_MASK BIT(2)
+#define M98090_DLY_SHIFT 2
+#define M98090_DLY_WIDTH 1
+#define M98090_WS_MASK (3 << 0)
+#define M98090_WS_SHIFT 0
+#define M98090_WS_WIDTH 2
+#define M98090_WS_NUM BIT(M98090_WS_WIDTH)
+
+/* M98090_REG_IO_CONFIGURATION 0x25 */
+#define M98090_LTEN_MASK BIT(5)
+#define M98090_LTEN_SHIFT 5
+#define M98090_LTEN_WIDTH 1
+#define M98090_LTEN_NUM BIT(M98090_LTEN_WIDTH)
+#define M98090_LBEN_MASK BIT(4)
+#define M98090_LBEN_SHIFT 4
+#define M98090_LBEN_WIDTH 1
+#define M98090_LBEN_NUM BIT(M98090_LBEN_WIDTH)
+#define M98090_DMONO_MASK BIT(3)
+#define M98090_DMONO_SHIFT 3
+#define M98090_DMONO_WIDTH 1
+#define M98090_DMONO_NUM BIT(M98090_DMONO_WIDTH)
+#define M98090_HIZOFF_MASK BIT(2)
+#define M98090_HIZOFF_SHIFT 2
+#define M98090_HIZOFF_WIDTH 1
+#define M98090_HIZOFF_NUM BIT(M98090_HIZOFF_WIDTH)
+#define M98090_SDOEN_MASK BIT(1)
+#define M98090_SDOEN_SHIFT 1
+#define M98090_SDOEN_WIDTH 1
+#define M98090_SDOEN_NUM BIT(M98090_SDOEN_WIDTH)
+#define M98090_SDIEN_MASK BIT(0)
+#define M98090_SDIEN_SHIFT 0
+#define M98090_SDIEN_WIDTH 1
+#define M98090_SDIEN_NUM BIT(M98090_SDIEN_WIDTH)
+
+/*
+ * M98090_REG_FILTER_CONFIG 0x26
+ */
+#define M98090_MODE_MASK BIT(7)
+#define M98090_MODE_SHIFT 7
+#define M98090_MODE_WIDTH 1
+#define M98090_AHPF_MASK BIT(6)
+#define M98090_AHPF_SHIFT 6
+#define M98090_AHPF_WIDTH 1
+#define M98090_AHPF_NUM BIT(M98090_AHPF_WIDTH)
+#define M98090_DHPF_MASK BIT(5)
+#define M98090_DHPF_SHIFT 5
+#define M98090_DHPF_WIDTH 1
+#define M98090_DHPF_NUM BIT(M98090_DHPF_WIDTH)
+#define M98090_DHF_MASK BIT(4)
+#define M98090_DHF_SHIFT 4
+#define M98090_DHF_WIDTH 1
+#define M98090_FLT_DMIC34MODE_MASK BIT(3)
+#define M98090_FLT_DMIC34MODE_SHIFT 3
+#define M98090_FLT_DMIC34MODE_WIDTH 1
+#define M98090_FLT_DMIC34HPF_MASK BIT(2)
+#define M98090_FLT_DMIC34HPF_SHIFT 2
+#define M98090_FLT_DMIC34HPF_WIDTH 1
+#define M98090_FLT_DMIC34HPF_NUM BIT(M98090_FLT_DMIC34HPF_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_MODE
+ */
+#define M98090_FREQ_MASK (15 << 4)
+#define M98090_FREQ_SHIFT 4
+#define M98090_FREQ_WIDTH 4
+#define M98090_USE_M1_MASK BIT(0)
+#define M98090_USE_M1_SHIFT 0
+#define M98090_USE_M1_WIDTH 1
+#define M98090_USE_M1_NUM BIT(M98090_USE_M1_WIDTH)
+
+/*
+ * M98090_REG_LEFT_HP_MIXER 0x29
+ */
+#define M98090_MIXHPL_MIC2_MASK BIT(5)
+#define M98090_MIXHPL_MIC2_SHIFT 5
+#define M98090_MIXHPL_MIC2_WIDTH 1
+#define M98090_MIXHPL_MIC1_MASK BIT(4)
+#define M98090_MIXHPL_MIC1_SHIFT 4
+#define M98090_MIXHPL_MIC1_WIDTH 1
+#define M98090_MIXHPL_LINEB_MASK BIT(3)
+#define M98090_MIXHPL_LINEB_SHIFT 3
+#define M98090_MIXHPL_LINEB_WIDTH 1
+#define M98090_MIXHPL_LINEA_MASK BIT(2)
+#define M98090_MIXHPL_LINEA_SHIFT 2
+#define M98090_MIXHPL_LINEA_WIDTH 1
+#define M98090_MIXHPL_DACR_MASK BIT(1)
+#define M98090_MIXHPL_DACR_SHIFT 1
+#define M98090_MIXHPL_DACR_WIDTH 1
+#define M98090_MIXHPL_DACL_MASK BIT(0)
+#define M98090_MIXHPL_DACL_SHIFT 0
+#define M98090_MIXHPL_DACL_WIDTH 1
+#define M98090_MIXHPL_MASK (63 << 0)
+#define M98090_MIXHPL_SHIFT 0
+#define M98090_MIXHPL_WIDTH 6
+
+/*
+ * M98090_REG_RIGHT_HP_MIXER 0x2A
+ */
+#define M98090_MIXHPR_MIC2_MASK BIT(5)
+#define M98090_MIXHPR_MIC2_SHIFT 5
+#define M98090_MIXHPR_MIC2_WIDTH 1
+#define M98090_MIXHPR_MIC1_MASK BIT(4)
+#define M98090_MIXHPR_MIC1_SHIFT 4
+#define M98090_MIXHPR_MIC1_WIDTH 1
+#define M98090_MIXHPR_LINEB_MASK BIT(3)
+#define M98090_MIXHPR_LINEB_SHIFT 3
+#define M98090_MIXHPR_LINEB_WIDTH 1
+#define M98090_MIXHPR_LINEA_MASK BIT(2)
+#define M98090_MIXHPR_LINEA_SHIFT 2
+#define M98090_MIXHPR_LINEA_WIDTH 1
+#define M98090_MIXHPR_DACR_MASK BIT(1)
+#define M98090_MIXHPR_DACR_SHIFT 1
+#define M98090_MIXHPR_DACR_WIDTH 1
+#define M98090_MIXHPR_DACL_MASK BIT(0)
+#define M98090_MIXHPR_DACL_SHIFT 0
+#define M98090_MIXHPR_DACL_WIDTH 1
+#define M98090_MIXHPR_MASK (63 << 0)
+#define M98090_MIXHPR_SHIFT 0
+#define M98090_MIXHPR_WIDTH 6
+
+/*
+ * M98090_REG_LEFT_HP_VOLUME 0x2C
+ */
+#define M98090_HPLM_MASK BIT(7)
+#define M98090_HPLM_SHIFT 7
+#define M98090_HPLM_WIDTH 1
+#define M98090_HPVOLL_MASK (31 << 0)
+#define M98090_HPVOLL_SHIFT 0
+#define M98090_HPVOLL_WIDTH 5
+#define M98090_HPVOLL_NUM BIT(M98090_HPVOLL_WIDTH)
+
+/*
+ * M98090_REG_RIGHT_HP_VOLUME 0x2D
+ */
+#define M98090_HPRM_MASK BIT(7)
+#define M98090_HPRM_SHIFT 7
+#define M98090_HPRM_WIDTH 1
+#define M98090_HPVOLR_MASK (31 << 0)
+#define M98090_HPVOLR_SHIFT 0
+#define M98090_HPVOLR_WIDTH 5
+#define M98090_HPVOLR_NUM BIT(M98090_HPVOLR_WIDTH)
+
+/*
+ * M98090_REG_LEFT_SPK_MIXER 0x2E
+ */
+#define M98090_MIXSPL_MIC2_MASK BIT(5)
+#define M98090_MIXSPL_MIC2_SHIFT 5
+#define M98090_MIXSPL_MIC2_WIDTH 1
+#define M98090_MIXSPL_MIC1_MASK BIT(4)
+#define M98090_MIXSPL_MIC1_SHIFT 4
+#define M98090_MIXSPL_MIC1_WIDTH 1
+#define M98090_MIXSPL_LINEB_MASK BIT(3)
+#define M98090_MIXSPL_LINEB_SHIFT 3
+#define M98090_MIXSPL_LINEB_WIDTH 1
+#define M98090_MIXSPL_LINEA_MASK BIT(2)
+#define M98090_MIXSPL_LINEA_SHIFT 2
+#define M98090_MIXSPL_LINEA_WIDTH 1
+#define M98090_MIXSPL_DACR_MASK BIT(1)
+#define M98090_MIXSPL_DACR_SHIFT 1
+#define M98090_MIXSPL_DACR_WIDTH 1
+#define M98090_MIXSPL_DACL_MASK BIT(0)
+#define M98090_MIXSPL_DACL_SHIFT 0
+#define M98090_MIXSPL_DACL_WIDTH 1
+#define M98090_MIXSPL_MASK (63 << 0)
+#define M98090_MIXSPL_SHIFT 0
+#define M98090_MIXSPL_WIDTH 6
+#define M98090_MIXSPR_DACR_MASK BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT 1
+#define M98090_MIXSPR_DACR_WIDTH 1
+
+/*
+ * M98090_REG_RIGHT_SPK_MIXER 0x2F
+ */
+#define M98090_SPK_SLAVE_MASK BIT(6)
+#define M98090_SPK_SLAVE_SHIFT 6
+#define M98090_SPK_SLAVE_WIDTH 1
+#define M98090_MIXSPR_MIC2_MASK BIT(5)
+#define M98090_MIXSPR_MIC2_SHIFT 5
+#define M98090_MIXSPR_MIC2_WIDTH 1
+#define M98090_MIXSPR_MIC1_MASK BIT(4)
+#define M98090_MIXSPR_MIC1_SHIFT 4
+#define M98090_MIXSPR_MIC1_WIDTH 1
+#define M98090_MIXSPR_LINEB_MASK BIT(3)
+#define M98090_MIXSPR_LINEB_SHIFT 3
+#define M98090_MIXSPR_LINEB_WIDTH 1
+#define M98090_MIXSPR_LINEA_MASK BIT(2)
+#define M98090_MIXSPR_LINEA_SHIFT 2
+#define M98090_MIXSPR_LINEA_WIDTH 1
+#define M98090_MIXSPR_DACR_MASK BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT 1
+#define M98090_MIXSPR_DACR_WIDTH 1
+#define M98090_MIXSPR_DACL_MASK BIT(0)
+#define M98090_MIXSPR_DACL_SHIFT 0
+#define M98090_MIXSPR_DACL_WIDTH 1
+#define M98090_MIXSPR_MASK (63 << 0)
+#define M98090_MIXSPR_SHIFT 0
+#define M98090_MIXSPR_WIDTH 6
+
+/*
+ * M98090_REG_LEFT_SPK_VOLUME 0x31
+ */
+#define M98090_SPLM_MASK BIT(7)
+#define M98090_SPLM_SHIFT 7
+#define M98090_SPLM_WIDTH 1
+#define M98090_SPVOLL_MASK (63 << 0)
+#define M98090_SPVOLL_SHIFT 0
+#define M98090_SPVOLL_WIDTH 6
+#define M98090_SPVOLL_NUM 40
+
+/*
+ * M98090_REG_RIGHT_SPK_VOLUME 0x32
+ */
+#define M98090_SPRM_MASK BIT(7)
+#define M98090_SPRM_SHIFT 7
+#define M98090_SPRM_WIDTH 1
+#define M98090_SPVOLR_MASK (63 << 0)
+#define M98090_SPVOLR_SHIFT 0
+#define M98090_SPVOLR_WIDTH 6
+#define M98090_SPVOLR_NUM 40
+
+/*
+ * M98090_REG_RCV_LOUTL_MIXER 0x37
+ */
+#define M98090_MIXRCVL_MIC2_MASK BIT(5)
+#define M98090_MIXRCVL_MIC2_SHIFT 5
+#define M98090_MIXRCVL_MIC2_WIDTH 1
+#define M98090_MIXRCVL_MIC1_MASK BIT(4)
+#define M98090_MIXRCVL_MIC1_SHIFT 4
+#define M98090_MIXRCVL_MIC1_WIDTH 1
+#define M98090_MIXRCVL_LINEB_MASK BIT(3)
+#define M98090_MIXRCVL_LINEB_SHIFT 3
+#define M98090_MIXRCVL_LINEB_WIDTH 1
+#define M98090_MIXRCVL_LINEA_MASK BIT(2)
+#define M98090_MIXRCVL_LINEA_SHIFT 2
+#define M98090_MIXRCVL_LINEA_WIDTH 1
+#define M98090_MIXRCVL_DACR_MASK BIT(1)
+#define M98090_MIXRCVL_DACR_SHIFT 1
+#define M98090_MIXRCVL_DACR_WIDTH 1
+#define M98090_MIXRCVL_DACL_MASK BIT(0)
+#define M98090_MIXRCVL_DACL_SHIFT 0
+#define M98090_MIXRCVL_DACL_WIDTH 1
+#define M98090_MIXRCVL_MASK (63 << 0)
+#define M98090_MIXRCVL_SHIFT 0
+#define M98090_MIXRCVL_WIDTH 6
+
+/*
+ * M98090_REG_RCV_LOUTL_CONTROL 0x38
+ */
+#define M98090_MIXRCVLG_MASK (3 << 0)
+#define M98090_MIXRCVLG_SHIFT 0
+#define M98090_MIXRCVLG_WIDTH 2
+#define M98090_MIXRCVLG_NUM BIT(M98090_MIXRCVLG_WIDTH)
+
+/*
+ * M98090_REG_RCV_LOUTL_VOLUME 0x39
+ */
+#define M98090_RCVLM_MASK BIT(7)
+#define M98090_RCVLM_SHIFT 7
+#define M98090_RCVLM_WIDTH 1
+#define M98090_RCVLVOL_MASK (31 << 0)
+#define M98090_RCVLVOL_SHIFT 0
+#define M98090_RCVLVOL_WIDTH 5
+#define M98090_RCVLVOL_NUM BIT(M98090_RCVLVOL_WIDTH)
+
+/*
+ * M98090_REG_LOUTR_MIXER 0x3A
+ */
+#define M98090_LINMOD_MASK BIT(7)
+#define M98090_LINMOD_SHIFT 7
+#define M98090_LINMOD_WIDTH 1
+#define M98090_MIXRCVR_MIC2_MASK BIT(5)
+#define M98090_MIXRCVR_MIC2_SHIFT 5
+#define M98090_MIXRCVR_MIC2_WIDTH 1
+#define M98090_MIXRCVR_MIC1_MASK BIT(4)
+#define M98090_MIXRCVR_MIC1_SHIFT 4
+#define M98090_MIXRCVR_MIC1_WIDTH 1
+#define M98090_MIXRCVR_LINEB_MASK BIT(3)
+#define M98090_MIXRCVR_LINEB_SHIFT 3
+#define M98090_MIXRCVR_LINEB_WIDTH 1
+#define M98090_MIXRCVR_LINEA_MASK BIT(2)
+#define M98090_MIXRCVR_LINEA_SHIFT 2
+#define M98090_MIXRCVR_LINEA_WIDTH 1
+#define M98090_MIXRCVR_DACR_MASK BIT(1)
+#define M98090_MIXRCVR_DACR_SHIFT 1
+#define M98090_MIXRCVR_DACR_WIDTH 1
+#define M98090_MIXRCVR_DACL_MASK BIT(0)
+#define M98090_MIXRCVR_DACL_SHIFT 0
+#define M98090_MIXRCVR_DACL_WIDTH 1
+#define M98090_MIXRCVR_MASK (63 << 0)
+#define M98090_MIXRCVR_SHIFT 0
+#define M98090_MIXRCVR_WIDTH 6
+
+/*
+ * M98090_REG_LOUTR_VOLUME 0x3C
+ */
+#define M98090_RCVRM_MASK BIT(7)
+#define M98090_RCVRM_SHIFT 7
+#define M98090_RCVRM_WIDTH 1
+#define M98090_RCVRVOL_MASK (31 << 0)
+#define M98090_RCVRVOL_SHIFT 0
+#define M98090_RCVRVOL_WIDTH 5
+#define M98090_RCVRVOL_NUM BIT(M98090_RCVRVOL_WIDTH)
+
+/*
+ * M98090_REG_JACK_DETECT 0x3D
+ */
+#define M98090_JDETEN_MASK BIT(7)
+#define M98090_JDETEN_SHIFT 7
+#define M98090_JDETEN_WIDTH 1
+#define M98090_JDWK_MASK BIT(6)
+#define M98090_JDWK_SHIFT 6
+#define M98090_JDWK_WIDTH 1
+#define M98090_JDEB_MASK (3 << 0)
+#define M98090_JDEB_SHIFT 0
+#define M98090_JDEB_WIDTH 2
+#define M98090_JDEB_25MS (0 << 0)
+#define M98090_JDEB_50MS BIT(0)
+#define M98090_JDEB_100MS (2 << 0)
+#define M98090_JDEB_200MS (3 << 0)
+
+/*
+ * M98090_REG_INPUT_ENABLE 0x3E
+ */
+#define M98090_MBEN_MASK BIT(4)
+#define M98090_MBEN_SHIFT 4
+#define M98090_MBEN_WIDTH 1
+#define M98090_LINEAEN_MASK BIT(3)
+#define M98090_LINEAEN_SHIFT 3
+#define M98090_LINEAEN_WIDTH 1
+#define M98090_LINEBEN_MASK BIT(2)
+#define M98090_LINEBEN_SHIFT 2
+#define M98090_LINEBEN_WIDTH 1
+#define M98090_ADREN_MASK BIT(1)
+#define M98090_ADREN_SHIFT 1
+#define M98090_ADREN_WIDTH 1
+#define M98090_ADLEN_MASK BIT(0)
+#define M98090_ADLEN_SHIFT 0
+#define M98090_ADLEN_WIDTH 1
+
+/*
+ * M98090_REG_OUTPUT_ENABLE 0x3F
+ */
+#define M98090_HPREN_MASK BIT(7)
+#define M98090_HPREN_SHIFT 7
+#define M98090_HPREN_WIDTH 1
+#define M98090_HPLEN_MASK BIT(6)
+#define M98090_HPLEN_SHIFT 6
+#define M98090_HPLEN_WIDTH 1
+#define M98090_SPREN_MASK BIT(5)
+#define M98090_SPREN_SHIFT 5
+#define M98090_SPREN_WIDTH 1
+#define M98090_SPLEN_MASK BIT(4)
+#define M98090_SPLEN_SHIFT 4
+#define M98090_SPLEN_WIDTH 1
+#define M98090_RCVLEN_MASK BIT(3)
+#define M98090_RCVLEN_SHIFT 3
+#define M98090_RCVLEN_WIDTH 1
+#define M98090_RCVREN_MASK BIT(2)
+#define M98090_RCVREN_SHIFT 2
+#define M98090_RCVREN_WIDTH 1
+#define M98090_DAREN_MASK BIT(1)
+#define M98090_DAREN_SHIFT 1
+#define M98090_DAREN_WIDTH 1
+#define M98090_DALEN_MASK BIT(0)
+#define M98090_DALEN_SHIFT 0
+#define M98090_DALEN_WIDTH 1
+
+/*
+ * M98090_REG_LEVEL_CONTROL 0x40
+ */
+#define M98090_ZDENN_MASK BIT(2)
+#define M98090_ZDENN_SHIFT 2
+#define M98090_ZDENN_WIDTH 1
+#define M98090_ZDENN_NUM BIT(M98090_ZDENN_WIDTH)
+#define M98090_VS2ENN_MASK BIT(1)
+#define M98090_VS2ENN_SHIFT 1
+#define M98090_VS2ENN_WIDTH 1
+#define M98090_VS2ENN_NUM BIT(M98090_VS2ENN_WIDTH)
+#define M98090_VSENN_MASK BIT(0)
+#define M98090_VSENN_SHIFT 0
+#define M98090_VSENN_WIDTH 1
+#define M98090_VSENN_NUM BIT(M98090_VSENN_WIDTH)
+
+/*
+ * M98090_REG_BIAS_CONTROL 0x42
+ */
+#define M98090_VCM_MODE_MASK BIT(0)
+#define M98090_VCM_MODE_SHIFT 0
+#define M98090_VCM_MODE_WIDTH 1
+#define M98090_VCM_MODE_NUM BIT(M98090_VCM_MODE_WIDTH)
+
+/*
+ * M98090_REG_DAC_CONTROL 0x43
+ */
+#define M98090_PERFMODE_MASK BIT(1)
+#define M98090_PERFMODE_SHIFT 1
+#define M98090_PERFMODE_WIDTH 1
+#define M98090_PERFMODE_NUM BIT(M98090_PERFMODE_WIDTH)
+#define M98090_DACHP_MASK BIT(0)
+#define M98090_DACHP_SHIFT 0
+#define M98090_DACHP_WIDTH 1
+#define M98090_DACHP_NUM BIT(M98090_DACHP_WIDTH)
+
+/*
+ * M98090_REG_ADC_CONTROL 0x44
+ */
+#define M98090_OSR128_MASK BIT(2)
+#define M98090_OSR128_SHIFT 2
+#define M98090_OSR128_WIDTH 1
+#define M98090_ADCDITHER_MASK BIT(1)
+#define M98090_ADCDITHER_SHIFT 1
+#define M98090_ADCDITHER_WIDTH 1
+#define M98090_ADCDITHER_NUM BIT(M98090_ADCDITHER_WIDTH)
+#define M98090_ADCHP_MASK BIT(0)
+#define M98090_ADCHP_SHIFT 0
+#define M98090_ADCHP_WIDTH 1
+#define M98090_ADCHP_NUM BIT(M98090_ADCHP_WIDTH)
+
+/*
+ * M98090_REG_DEVICE_SHUTDOWN 0x45
+ */
+#define M98090_SHDNN_MASK BIT(7)
+#define M98090_SHDNN_SHIFT 7
+#define M98090_SHDNN_WIDTH 1
+
+/*
+ * M98090_REG_REVISION_ID 0xFF
+ */
+#define M98090_REVID_MASK (255 << 0)
+#define M98090_REVID_SHIFT 0
+#define M98090_REVID_WIDTH 8
+#define M98090_REVID_NUM BIT(M98090_REVID_WIDTH)
+
+/* function prototype */
+
+/*
+ * initialise max98090 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 max98090_init(const void *blob, int sampling_rate, int mclk_freq,
+ int bits_per_sample);
+int max98090_set_sysclk(struct maxim_priv *max98090, uint freq);
+int max98090_hw_params(struct maxim_priv *max98090, uint rate,
+ uint bits_per_sample);
+int max98090_device_init(struct maxim_priv *max98090);
+int max98090_set_fmt(struct maxim_priv *max98090, int fmt);
+#endif
diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c
index 7c37bd0701..99c0e996b4 100644
--- a/drivers/sound/max98095.c
+++ b/drivers/sound/max98095.c
@@ -1,113 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* 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.
+ * Modified for U-Boot by R. Chandrasekar (rcsekar@samsung.com)
*/
#include <common.h>
-#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 <audio_codec.h>
+#include <dm.h>
#include <div64.h>
#include <fdtdec.h>
#include <i2c.h>
#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.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
@@ -127,19 +46,19 @@ static int rate_value(int rate, u8 *value)
}
*value = 1;
- return -1;
+ return -EINVAL;
}
/*
* Sets hw params for max98095
*
- * @param max98095 max98095 information pointer
+ * @param priv max98095 information pointer
* @param rate Sampling rate
* @param bits_per_sample Bits per sample
*
- * @return -1 for error and 0 Success.
+ * @return 0 for success or negative error code.
*/
-static int max98095_hw_params(struct max98095_priv *max98095,
+static int max98095_hw_params(struct maxim_priv *priv,
enum en_max_audio_interface aif_id,
unsigned int rate, unsigned int bits_per_sample)
{
@@ -161,40 +80,39 @@ static int max98095_hw_params(struct max98095_priv *max98095,
switch (bits_per_sample) {
case 16:
- error = max98095_update_bits(M98095_DAI_FORMAT,
- M98095_DAI_WS, 0);
+ error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS, 0);
break;
case 24:
- error = max98095_update_bits(M98095_DAI_FORMAT,
- M98095_DAI_WS, M98095_DAI_WS);
+ error = maxim_bic_or(priv, 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;
+ return -EINVAL;
}
if (rate_value(rate, &regval)) {
debug("%s: Failed to set sample rate to %d.\n",
__func__, rate);
- return -1;
+ return -EINVAL;
}
- max98095->rate = rate;
+ priv->rate = rate;
- error |= max98095_update_bits(M98095_DAI_CLKMODE,
- M98095_CLKMODE_MASK, regval);
+ error |= maxim_bic_or(priv, 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);
+ error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+ M98095_DAI_DHF, 0);
else
- error |= max98095_update_bits(M98095_DAI_FILTERS,
- M98095_DAI_DHF, M98095_DAI_DHF);
+ error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+ M98095_DAI_DHF, M98095_DAI_DHF);
if (error < 0) {
debug("%s: Error setting hardware params.\n", __func__);
- return -1;
+ return -EIO;
}
return 0;
@@ -203,18 +121,17 @@ static int max98095_hw_params(struct max98095_priv *max98095,
/*
* Configures Audio interface system clock for the given frequency
*
- * @param max98095 max98095 information
+ * @param priv max98095 information
* @param freq Sampling frequency in Hz
*
- * @return -1 for error and 0 success.
+ * @return 0 for success or negative error code.
*/
-static int max98095_set_sysclk(struct max98095_priv *max98095,
- unsigned int freq)
+static int max98095_set_sysclk(struct maxim_priv *priv, unsigned int freq)
{
int error = 0;
/* Requested clock frequency is already setup */
- if (freq == max98095->sysclk)
+ if (freq == priv->sysclk)
return 0;
/* Setup clocks for slave mode, and using the PLL
@@ -223,35 +140,35 @@ static int max98095_set_sysclk(struct max98095_priv *max98095,
* 0x03 (when master clk is 40MHz to 60MHz)..
*/
if ((freq >= 10000000) && (freq < 20000000)) {
- error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
+ error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x10);
} else if ((freq >= 20000000) && (freq < 40000000)) {
- error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
+ error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x20);
} else if ((freq >= 40000000) && (freq < 60000000)) {
- error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
+ error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x30);
} else {
debug("%s: Invalid master clock frequency\n", __func__);
- return -1;
+ return -EINVAL;
}
debug("%s: Clock at %uHz\n", __func__, freq);
if (error < 0)
- return -1;
+ return -EIO;
- max98095->sysclk = freq;
+ priv->sysclk = freq;
return 0;
}
/*
* Sets Max98095 I2S format
*
- * @param max98095 max98095 information
+ * @param priv max98095 information
* @param fmt i2S format - supports a subset of the options defined
* in i2s.h.
*
- * @return -1 for error and 0 Success.
+ * @return 0 for success or negative error code.
*/
-static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
+static int max98095_set_fmt(struct maxim_priv *priv, int fmt,
enum en_max_audio_interface aif_id)
{
u8 regval = 0;
@@ -261,10 +178,10 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
unsigned short M98095_DAI_FORMAT;
unsigned short M98095_DAI_CLOCK;
- if (fmt == max98095->fmt)
+ if (fmt == priv->fmt)
return 0;
- max98095->fmt = fmt;
+ priv->fmt = fmt;
if (aif_id == AIF1) {
M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI;
@@ -281,10 +198,8 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
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);
+ error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_HI, 0x80);
+ error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_LO, 0x00);
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* Set to master mode */
@@ -294,7 +209,7 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
case SND_SOC_DAIFMT_CBM_CFS:
default:
debug("%s: Clock mode unsupported\n", __func__);
- return -1;
+ return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -305,7 +220,7 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
break;
default:
debug("%s: Unrecognized format.\n", __func__);
- return -1;
+ return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -322,20 +237,18 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
break;
default:
debug("%s: Unrecognized inversion settings.\n", __func__);
- return -1;
+ return -EINVAL;
}
- error |= max98095_update_bits(M98095_DAI_FORMAT,
- M98095_DAI_MAS | M98095_DAI_DLY |
- M98095_DAI_BCI | M98095_DAI_WCI,
- regval);
+ error |= maxim_bic_or(priv, 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);
+ error |= maxim_i2c_write(priv, M98095_DAI_CLOCK, M98095_DAI_BSEL64);
if (error < 0) {
debug("%s: Error setting i2s format.\n", __func__);
- return -1;
+ return -EIO;
}
return 0;
@@ -344,9 +257,10 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
/*
* resets the audio codec
*
- * @return -1 for error and 0 success.
+ * @param priv Private data for driver
+ * @return 0 for success or negative error code.
*/
-static int max98095_reset(void)
+static int max98095_reset(struct maxim_priv *priv)
{
int i, ret;
@@ -354,13 +268,13 @@ static int max98095_reset(void)
* Gracefully reset the DSP core and the codec hardware in a proper
* sequence.
*/
- ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
+ ret = maxim_i2c_write(priv, 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);
+ ret = maxim_i2c_write(priv, M98095_097_PWR_SYS, 0);
if (ret != 0) {
debug("%s: Failed to reset codec: %d\n", __func__, ret);
return ret;
@@ -371,7 +285,7 @@ static int max98095_reset(void)
* reset hardware control register.
*/
for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
- ret = max98095_i2c_write(i, 0);
+ ret = maxim_i2c_write(priv, i, 0);
if (ret < 0) {
debug("%s: Failed to reset: %d\n", __func__, ret);
return ret;
@@ -384,132 +298,128 @@ static int max98095_reset(void)
/*
* Intialise max98095 codec device
*
- * @param max98095 max98095 information
- *
- * @returns -1 for error and 0 Success.
+ * @param priv max98095 information
+ * @return 0 for success or negative error code.
*/
-static int max98095_device_init(struct max98095_priv *max98095,
- enum en_max_audio_interface aif_id)
+static int max98095_device_init(struct maxim_priv *priv)
{
unsigned char id;
- int error = 0;
+ int ret;
+
+ /* Enable codec clock */
+ set_xclkout();
/* reset the codec, the DSP core, and disable all interrupts */
- error = max98095_reset();
- if (error != 0) {
+ ret = max98095_reset(priv);
+ if (ret != 0) {
debug("Reset\n");
- return error;
+ return ret;
}
/* initialize private data */
- max98095->sysclk = -1U;
- max98095->rate = -1U;
- max98095->fmt = -1U;
+ priv->sysclk = -1U;
+ priv->rate = -1U;
+ priv->fmt = -1U;
- error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
- if (error < 0) {
+ ret = maxim_i2c_read(priv, M98095_0FF_REV_ID, &id);
+ if (ret < 0) {
debug("%s: Failure reading hardware revision: %d\n",
__func__, id);
- goto err_access;
+ return ret;
}
debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
- error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
+ return 0;
+}
+
+static int max98095_setup_interface(struct maxim_priv *priv,
+ enum en_max_audio_interface aif_id)
+{
+ int error;
+
+ error = maxim_i2c_write(priv, 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,
+ error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
M98095_DAI1L_TO_DACL |
M98095_DAI1R_TO_DACR);
else
- error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+ error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
M98095_DAI2M_TO_DACL |
M98095_DAI2M_TO_DACR);
- error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
+ error |= maxim_i2c_write(priv, M98095_092_PWR_EN_OUT,
M98095_SPK_SPREADSPECTRUM);
- error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
+ error |= maxim_i2c_write(priv, M98095_04E_CFG_HP, M98095_HPNORMAL);
if (aif_id == AIF1)
- error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
+ error |= maxim_i2c_write(priv, M98095_02C_DAI1_IOCFG,
M98095_S1NORMAL | M98095_SDATA);
else
- error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
+ error |= maxim_i2c_write(priv, 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 */
+ error |= maxim_bic_or(priv, M98095_097_PWR_SYS, M98095_SHDNRUN,
+ M98095_SHDNRUN);
+ /*
+ * route DACL and DACR output to HO and Speakers
+ * Ordering: DACL, DACR, DACL, DACR
+ */
+ error |= maxim_i2c_write(priv, M98095_050_MIX_SPK_LEFT, 0x01);
+ error |= maxim_i2c_write(priv, M98095_051_MIX_SPK_RIGHT, 0x01);
+ error |= maxim_i2c_write(priv, M98095_04C_MIX_HP_LEFT, 0x01);
+ error |= maxim_i2c_write(priv, M98095_04D_MIX_HP_RIGHT, 0x01);
/* power Enable */
- error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
+ error |= maxim_i2c_write(priv, 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);
+ error |= maxim_i2c_write(priv, M98095_064_LVL_HP_L, 15);
+ error |= maxim_i2c_write(priv, M98095_065_LVL_HP_R, 15);
+ error |= maxim_i2c_write(priv, M98095_067_LVL_SPK_L, 16);
+ error |= maxim_i2c_write(priv, M98095_068_LVL_SPK_R, 16);
/* Enable DAIs */
- error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
+ error |= maxim_i2c_write(priv, M98095_093_BIAS_CTRL, 0x30);
if (aif_id == AIF1)
- error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01);
+ error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x01);
else
- error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
+ error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x07);
-err_access:
if (error < 0)
- return -1;
+ return -EIO;
return 0;
}
-static int max98095_do_init(struct sound_codec_info *pcodec_info,
+static int max98095_do_init(struct maxim_priv *priv,
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);
+ ret = max98095_setup_interface(priv, aif_id);
if (ret < 0) {
- debug("%s: max98095 codec chip init failed\n", __func__);
+ debug("%s: max98095 setup interface failed\n", __func__);
return ret;
}
- ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
+ ret = max98095_set_sysclk(priv, 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,
+ ret = max98095_hw_params(priv, aif_id, sampling_rate,
bits_per_sample);
if (ret == 0) {
- ret = max98095_set_fmt(&g_max98095_info,
- SND_SOC_DAIFMT_I2S |
+ ret = max98095_set_fmt(priv, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
aif_id);
@@ -518,76 +428,45 @@ static int max98095_do_init(struct sound_codec_info *pcodec_info,
return ret;
}
-static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
- const void *blob)
+static int max98095_set_params(struct udevice *dev, int interface, int rate,
+ int mclk_freq, int bits_per_sample,
+ uint channels)
{
- int error = 0;
-#if CONFIG_IS_ENABLED(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;
- }
+ struct maxim_priv *priv = dev_get_priv(dev);
- 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;
+ return max98095_do_init(priv, interface, rate, mclk_freq,
+ bits_per_sample);
}
-/* 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)
+static int max98095_probe(struct udevice *dev)
{
+ struct maxim_priv *priv = dev_get_priv(dev);
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;
+ priv->dev = dev;
+ ret = max98095_device_init(priv);
+ if (ret < 0) {
+ debug("%s: max98095 codec chip init failed\n", __func__);
+ return ret;
}
- 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;
+ return 0;
}
+
+static const struct audio_codec_ops max98095_ops = {
+ .set_params = max98095_set_params,
+};
+
+static const struct udevice_id max98095_ids[] = {
+ { .compatible = "maxim,max98095" },
+ { }
+};
+
+U_BOOT_DRIVER(max98095) = {
+ .name = "max98095",
+ .id = UCLASS_AUDIO_CODEC,
+ .of_match = max98095_ids,
+ .probe = max98095_probe,
+ .ops = &max98095_ops,
+ .priv_auto_alloc_size = sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h
index 44b1e3a97b..1521f3f02f 100644
--- a/drivers/sound/max98095.h
+++ b/drivers/sound/max98095.h
@@ -1,19 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* 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
+#include "maxim_codec.h"
+
/* Available audio interface ports in wm8994 codec */
enum en_max_audio_interface {
- AIF1 = 1,
+ AIF1,
AIF2,
};
diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c
new file mode 100644
index 0000000000..dcaf081988
--- /dev/null
+++ b/drivers/sound/maxim_codec.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * maxim_codec.c -- MAXIM CODEC Common driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv Private data for driver
+ * @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.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+ unsigned char data)
+{
+ debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
+ __func__, reg, data);
+ return dm_i2c_write(priv->dev, reg, &data, 1);
+}
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv Private data for driver
+ * @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.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+ unsigned char *data)
+{
+ int ret;
+
+ return dm_i2c_read(priv->dev, reg, 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 priv Private data for driver
+ * @param reg codec register
+ * @param mask register mask
+ * @param value new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+ unsigned char value)
+{
+ int change, ret = 0;
+ unsigned char old, new;
+
+ if (maxim_i2c_read(priv, reg, &old) != 0)
+ return -1;
+ new = (old & ~mask) | (value & mask);
+ change = (old != new) ? 1 : 0;
+ if (change)
+ ret = maxim_i2c_write(priv, reg, new);
+ if (ret < 0)
+ return ret;
+
+ return change;
+}
diff --git a/drivers/sound/maxim_codec.h b/drivers/sound/maxim_codec.h
new file mode 100644
index 0000000000..a3128e0bb7
--- /dev/null
+++ b/drivers/sound/maxim_codec.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * maxim_codec.h -- MAXIM codec common interface file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * D Krishna Mohan <krishna.md@samsung.com>
+ */
+
+#ifndef __MAXIM_COMMON_H__
+#define __MAXIM_COMMON_H__
+
+enum maxim_codec_type {
+ MAX98095,
+ MAX98090,
+};
+
+struct maxim_priv {
+ enum maxim_codec_type devtype;
+ unsigned int sysclk;
+ unsigned int rate;
+ unsigned int fmt;
+ struct udevice *dev;
+};
+
+#define MAXIM_AUDIO_I2C_BUS 7
+#define MAXIM_AUDIO_I2C_REG_98095 0x22
+
+#define MAXIM_AUDIO_I2C_REG MAXIM_AUDIO_I2C_REG_98095
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv Private data for driver
+ * @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.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+ unsigned char data);
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv Private data for driver
+ * @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.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+ unsigned char *data);
+
+/*
+ * update device register bits through i2c
+ *
+ * @param priv Private data for driver
+ * @param reg codec register
+ * @param mask register mask
+ * @param value new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+ unsigned char value);
+
+#endif /* __MAXIM_COMMON_H__ */
diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c
index f39abf5e2a..c19e08e7e3 100644
--- a/drivers/sound/samsung-i2s.c
+++ b/drivers/sound/samsung-i2s.c
@@ -4,13 +4,14 @@
* R. Chandrasekar <rcsekar@samsung.com>
*/
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
#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)
@@ -111,7 +112,7 @@ static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs)
* @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)
+static void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
{
/* Flush the FIFO */
setbits_le32(&i2s_reg->fic, flush);
@@ -126,7 +127,7 @@ void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
*
* @return int value 0 for success, -1 in case of error
*/
-int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
+static int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
{
unsigned int mod = readl(&i2s_reg->mod);
@@ -148,7 +149,7 @@ int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
*
* @return int value 0 for success, -1 in case of error
*/
-int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
+static int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
{
unsigned int mod = readl(&i2s_reg->mod);
unsigned int tmp = 0;
@@ -170,7 +171,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
default:
debug("%s: Invalid format priority [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
- return -1;
+ return -ERANGE;
}
/*
@@ -189,7 +190,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
default:
debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_INV_MASK));
- return -1;
+ return -ERANGE;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -201,13 +202,13 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
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;
+ return ret;
}
break;
default:
debug("%s: Invalid master selection [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_MASTER_MASK));
- return -1;
+ return -ERANGE;
}
mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
@@ -225,7 +226,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
*
* @return int value 0 for success, -1 in case of error
*/
-int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
+static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
{
unsigned int mod = readl(&i2s_reg->mod);
@@ -248,43 +249,43 @@ int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
default:
debug("%s: Invalid sample size input [0x%x]\n",
__func__, blc);
- return -1;
+ return -ERANGE;
}
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 i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+ uint data_size)
{
+ struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+ u32 *ptr;
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 */
+ return -ENODATA; /* 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);
+ for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
+ writel(*ptr++, &i2s_reg->txd);
- data_size -= FIFO_LENGTH;
+ data_size -= sizeof(*ptr) * 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--;
+ writel(*ptr++, &i2s_reg->txd);
+ data_size -= sizeof(*ptr);
} else {
if (get_timer(start) > TIMEOUT_I2S_TX) {
i2s_txctrl(i2s_reg, I2S_TX_OFF);
debug("%s: I2S Transfer Timeout\n", __func__);
- return -1;
+ return -ETIMEDOUT;
}
}
}
@@ -293,11 +294,11 @@ int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
return 0;
}
-int i2s_tx_init(struct i2stx_info *pi2s_tx)
+int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
{
int ret;
- struct i2s_reg *i2s_reg =
- (struct i2s_reg *)pi2s_tx->base_address;
+ 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);
@@ -312,20 +313,20 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
ret = set_epll_clk(pi2s_tx->audio_pll_clk);
} else {
debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
- return -1;
+ return -ERANGE;
}
- if (ret != 0) {
+ if (ret) {
debug("%s: epll clock set rate failed\n", __func__);
- return -1;
+ return ret;
}
/* Select Clk Source for Audio 0 or 1 */
ret = set_i2s_clk_source(pi2s_tx->id);
- if (ret == -1) {
+ if (ret) {
debug("%s: unsupported clock for i2s-%d\n", __func__,
pi2s_tx->id);
- return -1;
+ return ret;
}
if (pi2s_tx->id == 0) {
@@ -341,21 +342,21 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
pi2s_tx->id);
}
- if (ret == -1) {
+ if (ret) {
debug("%s: unsupported prescalar for i2s-%d\n", __func__,
pi2s_tx->id);
- return -1;
+ return ret;
}
/* Configure I2s format */
- ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM));
+ 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;
+ return ret;
}
i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
@@ -368,3 +369,87 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
return ret;
}
+
+static int samsung_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+ return i2s_transfer_tx_data(priv, data, data_size);
+}
+
+static int samsung_i2s_probe(struct udevice *dev)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+ return i2s_tx_init(priv);
+}
+
+static int samsung_i2s_ofdata_to_platdata(struct udevice *dev)
+{
+ struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+ ulong base;
+
+ /*
+ * 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 = dev_read_addr(dev);
+ if (base == FDT_ADDR_T_NONE) {
+ debug("%s: Missing i2s base\n", __func__);
+ return -EINVAL;
+ }
+ priv->base_address = base;
+
+ if (dev_read_u32u(dev, "samsung,i2s-epll-clock-frequency",
+ &priv->audio_pll_clk))
+ goto err;
+ debug("audio_pll_clk = %d\n", priv->audio_pll_clk);
+ if (dev_read_u32u(dev, "samsung,i2s-sampling-rate",
+ &priv->samplingrate))
+ goto err;
+ debug("samplingrate = %d\n", priv->samplingrate);
+ if (dev_read_u32u(dev, "samsung,i2s-bits-per-sample",
+ &priv->bitspersample))
+ goto err;
+ debug("bitspersample = %d\n", priv->bitspersample);
+ if (dev_read_u32u(dev, "samsung,i2s-channels", &priv->channels))
+ goto err;
+ debug("channels = %d\n", priv->channels);
+ if (dev_read_u32u(dev, "samsung,i2s-lr-clk-framesize", &priv->rfs))
+ goto err;
+ debug("rfs = %d\n", priv->rfs);
+ if (dev_read_u32u(dev, "samsung,i2s-bit-clk-framesize", &priv->bfs))
+ goto err;
+ debug("bfs = %d\n", priv->bfs);
+
+ if (dev_read_u32u(dev, "samsung,i2s-id", &priv->id))
+ goto err;
+ debug("id = %d\n", priv->id);
+
+ return 0;
+
+err:
+ debug("fail to get sound i2s node properties\n");
+
+ return -EINVAL;
+}
+
+static const struct i2s_ops samsung_i2s_ops = {
+ .tx_data = samsung_i2s_tx_data,
+};
+
+static const struct udevice_id samsung_i2s_ids[] = {
+ { .compatible = "samsung,s5pv210-i2s" },
+ { }
+};
+
+U_BOOT_DRIVER(samsung_i2s) = {
+ .name = "samsung_i2s",
+ .id = UCLASS_I2S,
+ .of_match = samsung_i2s_ids,
+ .probe = samsung_i2s_probe,
+ .ofdata_to_platdata = samsung_i2s_ofdata_to_platdata,
+ .ops = &samsung_i2s_ops,
+};
diff --git a/drivers/sound/samsung_sound.c b/drivers/sound/samsung_sound.c
new file mode 100644
index 0000000000..1d711c8732
--- /dev/null
+++ b/drivers/sound/samsung_sound.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+
+static int samsung_sound_setup(struct udevice *dev)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
+ int ret;
+
+ if (uc_priv->setup_done)
+ return -EALREADY;
+ ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
+ i2c_priv->samplingrate,
+ i2c_priv->samplingrate * i2c_priv->rfs,
+ i2c_priv->bitspersample,
+ i2c_priv->channels);
+ if (ret)
+ return ret;
+ uc_priv->setup_done = true;
+
+ return 0;
+}
+
+static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int samsung_sound_probe(struct udevice *dev)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ofnode_phandle_args args;
+ struct gpio_desc en_gpio;
+ ofnode node;
+ int ret;
+
+ ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+ /* Turn on the GPIO which connects to the codec's "enable" line. */
+ if (!ret)
+ gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
+
+ ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+ "samsung,audio-codec",
+ &uc_priv->codec);
+ if (ret) {
+ debug("Failed to probe audio codec\n");
+ return ret;
+ }
+ node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+ if (!ofnode_valid(node)) {
+ debug("Failed to find /cpu subnode\n");
+ return -EINVAL;
+ }
+ ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+ "#sound-dai-cells", 0, 0, &args);
+ if (ret) {
+ debug("Cannot find phandle: %d\n", ret);
+ return ret;
+ }
+ ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+ if (ret) {
+ debug("Cannot find i2s: %d\n", ret);
+ return ret;
+ }
+ debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+ uc_priv->codec->name, uc_priv->i2s->name);
+
+ return 0;
+}
+
+static const struct sound_ops samsung_sound_ops = {
+ .setup = samsung_sound_setup,
+ .play = samsung_sound_play,
+};
+
+static const struct udevice_id samsung_sound_ids[] = {
+ { .compatible = "google,snow-audio-max98095" },
+ { .compatible = "google,spring-audio-max98095" },
+ { .compatible = "samsung,smdk5420-audio-wm8994" },
+ { .compatible = "google,peach-audio-max98090" },
+ { }
+};
+
+U_BOOT_DRIVER(samsung_sound) = {
+ .name = "samsung_sound",
+ .id = UCLASS_SOUND,
+ .of_match = samsung_sound_ids,
+ .probe = samsung_sound_probe,
+ .ops = &samsung_sound_ops,
+};
diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c
index 94eff54282..b0b07f3239 100644
--- a/drivers/sound/sandbox.c
+++ b/drivers/sound/sandbox.c
@@ -4,19 +4,185 @@
*/
#include <common.h>
-#include <asm/sound.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
#include <asm/sdl.h>
-int sound_play(uint32_t msec, uint32_t frequency)
+struct sandbox_codec_priv {
+ int interface;
+ int rate;
+ int mclk_freq;
+ int bits_per_sample;
+ uint channels;
+};
+
+struct sandbox_i2s_priv {
+ int sum; /* Use to sum the provided audio data */
+};
+
+struct sandbox_sound_priv {
+ int setup_called;
+ int sum; /* Use to sum the provided audio data */
+};
+
+void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
+ int *mclk_freqp, int *bits_per_samplep,
+ uint *channelsp)
+{
+ struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+ *interfacep = priv->interface;
+ *ratep = priv->rate;
+ *mclk_freqp = priv->mclk_freq;
+ *bits_per_samplep = priv->bits_per_sample;
+ *channelsp = priv->channels;
+}
+
+int sandbox_get_i2s_sum(struct udevice *dev)
+{
+ struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+
+ return priv->sum;
+}
+
+int sandbox_get_setup_called(struct udevice *dev)
+{
+ struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+ return priv->setup_called;
+}
+
+int sandbox_get_sound_sum(struct udevice *dev)
+{
+ struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+ return priv->sum;
+}
+
+static int sandbox_codec_set_params(struct udevice *dev, int interface,
+ int rate, int mclk_freq,
+ int bits_per_sample, uint channels)
+{
+ struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+ priv->interface = interface;
+ priv->rate = rate;
+ priv->mclk_freq = mclk_freq;
+ priv->bits_per_sample = bits_per_sample;
+ priv->channels = channels;
+
+ return 0;
+}
+
+static int sandbox_i2s_tx_data(struct udevice *dev, void *data,
+ uint data_size)
+{
+ struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < data_size; i++)
+ priv->sum += ((uint8_t *)data)[i];
+
+ return sandbox_sdl_sound_play(data, data_size);
+}
+
+static int sandbox_i2s_probe(struct udevice *dev)
{
- sandbox_sdl_sound_start(frequency);
- mdelay(msec);
- sandbox_sdl_sound_stop();
+ struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Use hard-coded values here */
+ uc_priv->rfs = 256;
+ uc_priv->bfs = 32;
+ uc_priv->audio_pll_clk = 192000000;
+ uc_priv->samplingrate = 48000;
+ uc_priv->bitspersample = 16;
+ uc_priv->channels = 2;
+ uc_priv->id = 1;
+
+ /* Ignore any error here - we'll just have no sound */
+ sandbox_sdl_sound_init(uc_priv->samplingrate, uc_priv->channels);
return 0;
}
-int sound_init(const void *blob)
+static int sandbox_sound_setup(struct udevice *dev)
+{
+ struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+ priv->setup_called++;
+
+ return 0;
+}
+
+static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct sandbox_sound_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < data_size; i++)
+ priv->sum += ((uint8_t *)data)[i];
+
+ return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int sandbox_sound_probe(struct udevice *dev)
{
- return sandbox_sdl_sound_init();
+ return sound_find_codec_i2s(dev);
}
+
+static const struct audio_codec_ops sandbox_codec_ops = {
+ .set_params = sandbox_codec_set_params,
+};
+
+static const struct udevice_id sandbox_codec_ids[] = {
+ { .compatible = "sandbox,audio-codec" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_codec) = {
+ .name = "sandbox_codec",
+ .id = UCLASS_AUDIO_CODEC,
+ .of_match = sandbox_codec_ids,
+ .ops = &sandbox_codec_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_codec_priv),
+};
+
+static const struct i2s_ops sandbox_i2s_ops = {
+ .tx_data = sandbox_i2s_tx_data,
+};
+
+static const struct udevice_id sandbox_i2s_ids[] = {
+ { .compatible = "sandbox,i2s" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2s) = {
+ .name = "sandbox_i2s",
+ .id = UCLASS_I2S,
+ .of_match = sandbox_i2s_ids,
+ .ops = &sandbox_i2s_ops,
+ .probe = sandbox_i2s_probe,
+ .priv_auto_alloc_size = sizeof(struct sandbox_i2s_priv),
+};
+
+static const struct sound_ops sandbox_sound_ops = {
+ .setup = sandbox_sound_setup,
+ .play = sandbox_sound_play,
+};
+
+static const struct udevice_id sandbox_sound_ids[] = {
+ { .compatible = "sandbox,sound" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_sound) = {
+ .name = "sandbox_sound",
+ .id = UCLASS_SOUND,
+ .of_match = sandbox_sound_ids,
+ .ops = &sandbox_sound_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_sound_priv),
+ .probe = sandbox_sound_probe,
+};
diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c
deleted file mode 100644
index f0f0b79bc5..0000000000
--- a/drivers/sound/sound-i2s.c
+++ /dev/null
@@ -1,208 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2012 Samsung Electronics
- * R. Chandrasekar <rcsekar@samsung.com>
- */
-
-#include <malloc.h>
-#include <common.h>
-#include <asm/io.h>
-#include <linux/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(g_i2stx_pri.samplingrate,
- (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/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c
new file mode 100644
index 0000000000..2b83626889
--- /dev/null
+++ b/drivers/sound/sound-uclass.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+
+#define SOUND_BITS_IN_BYTE 8
+
+int sound_setup(struct udevice *dev)
+{
+ struct sound_ops *ops = sound_get_ops(dev);
+
+ if (!ops->setup)
+ return -ENOSYS;
+
+ return ops->setup(dev);
+}
+
+int sound_play(struct udevice *dev, void *data, uint data_size)
+{
+ struct sound_ops *ops = sound_get_ops(dev);
+
+ if (!ops->play)
+ return -ENOSYS;
+
+ return ops->play(dev, data, data_size);
+}
+
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
+ unsigned short *data;
+ uint data_size;
+ int ret;
+
+ ret = sound_setup(dev);
+ if (ret && ret != -EALREADY)
+ return ret;
+
+ /* Buffer length computation */
+ data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
+ data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
+ data = malloc(data_size);
+ if (!data) {
+ debug("%s: malloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
+ frequency_hz, i2s_uc_priv->channels);
+
+ while (msecs >= 1000) {
+ ret = sound_play(dev, data, data_size);
+ msecs -= 1000;
+ }
+ if (msecs) {
+ unsigned long size =
+ (data_size * msecs) / (sizeof(int) * 1000);
+
+ ret = sound_play(dev, data, size);
+ }
+
+ free(data);
+
+ return ret;
+}
+
+int sound_find_codec_i2s(struct udevice *dev)
+{
+ struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ofnode_phandle_args args;
+ ofnode node;
+ int ret;
+
+ /* First the codec */
+ node = ofnode_find_subnode(dev_ofnode(dev), "codec");
+ if (!ofnode_valid(node)) {
+ debug("Failed to find /cpu subnode\n");
+ return -EINVAL;
+ }
+ ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+ "#sound-dai-cells", 0, 0, &args);
+ if (ret) {
+ debug("Cannot find phandle: %d\n", ret);
+ return ret;
+ }
+ ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node,
+ &uc_priv->codec);
+ if (ret) {
+ debug("Cannot find codec: %d\n", ret);
+ return ret;
+ }
+
+ /* Now the i2s */
+ node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+ if (!ofnode_valid(node)) {
+ debug("Failed to find /cpu subnode\n");
+ return -EINVAL;
+ }
+ ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+ "#sound-dai-cells", 0, 0, &args);
+ if (ret) {
+ debug("Cannot find phandle: %d\n", ret);
+ return ret;
+ }
+ ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+ if (ret) {
+ debug("Cannot find i2s: %d\n", ret);
+ return ret;
+ }
+ debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+ uc_priv->codec->name, uc_priv->i2s->name);
+
+ return 0;
+}
+
+UCLASS_DRIVER(sound) = {
+ .id = UCLASS_SOUND,
+ .name = "sound",
+ .per_device_auto_alloc_size = sizeof(struct sound_uc_priv),
+};
diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c
index 4f0ad0d8f0..dd3f9db4f7 100644
--- a/drivers/sound/sound.c
+++ b/drivers/sound/sound.c
@@ -8,7 +8,7 @@
#include <sound.h>
void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
- uint freq)
+ uint freq, uint channels)
{
const unsigned short amplitude = 16000; /* between 1 and 32767 */
const int period = freq ? sample_rate / freq : 0;
@@ -21,14 +21,17 @@ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
size--;
while (size) {
- int i;
+ int i, j;
+
for (i = 0; size && i < half; i++) {
size -= 2;
- *data++ = amplitude;
+ for (j = 0; j < channels; j++)
+ *data++ = amplitude;
}
for (i = 0; size && i < period - half; i++) {
size -= 2;
- *data++ = -amplitude;
+ for (j = 0; j < channels; j++)
+ *data++ = -amplitude;
}
}
}
diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c
index aaaa3241aa..b290c4e879 100644
--- a/drivers/sound/wm8994.c
+++ b/drivers/sound/wm8994.c
@@ -4,15 +4,17 @@
* R. Chandrasekar <rcsekar@samsung.com>
*/
#include <common.h>
-#include <asm/arch/clk.h>
-#include <asm/arch/cpu.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+#include <audio_codec.h>
+#include <dm.h>
#include <div64.h>
#include <fdtdec.h>
#include <i2c.h>
#include <i2s.h>
#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
#include <asm/arch/sound.h>
#include "wm8994.h"
#include "wm8994_registers.h"
@@ -38,6 +40,7 @@ struct wm8994_priv {
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 */
+ struct udevice *dev;
};
/* wm 8994 supported sampling rate values */
@@ -60,29 +63,17 @@ static int bclk_divs[] = {
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 priv Private data for driver
* @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)
+static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
+ unsigned short data)
{
unsigned char val[2];
@@ -90,23 +81,25 @@ static int wm8994_i2c_write(unsigned int reg, unsigned short data)
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);
+ return dm_i2c_write(priv->dev, reg, val, 2);
}
/*
* Read a value from a device register through i2c
*
+ * @param priv Private data for driver
* @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)
+static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
+ unsigned short *data)
{
unsigned char val[2];
int ret;
- ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+ ret = dm_i2c_read(priv->dev, reg, val, 1);
if (ret != 0) {
debug("%s: Error while reading register %#04x\n",
__func__, reg);
@@ -123,6 +116,7 @@ static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
/*
* update device register bits through i2c
*
+ * @param priv Private data for driver
* @param reg codec register
* @param mask register mask
* @param value new value
@@ -130,18 +124,18 @@ static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
* @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)
+static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg,
+ unsigned short mask, unsigned short value)
{
int change , ret = 0;
unsigned short old, new;
- if (wm8994_i2c_read(reg, &old) != 0)
+ if (wm8994_i2c_read(priv, reg, &old) != 0)
return -1;
new = (old & ~mask) | (value & mask);
change = (old != new) ? 1 : 0;
if (change)
- ret = wm8994_i2c_write(reg, new);
+ ret = wm8994_i2c_write(priv, reg, new);
if (ret < 0)
return ret;
@@ -151,12 +145,13 @@ static int wm8994_update_bits(unsigned int reg, unsigned short mask,
/*
* Sets i2s set format
*
+ * @param priv wm8994 information
* @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)
+static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt)
{
int ms_reg;
int aif_reg;
@@ -254,12 +249,13 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
return -1;
}
- error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
- WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
+ error = wm8994_bic_or(priv, 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);
+ error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms);
+ error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK,
+ WM8994_AIF1CLK_ENA);
if (error < 0) {
debug("%s: codec register access error\n", __func__);
return -1;
@@ -271,7 +267,7 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
/*
* Sets hw params FOR WM8994
*
- * @param wm8994 wm8994 information pointer
+ * @param priv wm8994 information pointer
* @param aif_id Audio interface ID
* @param sampling_rate Sampling rate
* @param bits_per_sample Bits per sample
@@ -279,9 +275,9 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
*
* @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)
+static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id,
+ uint sampling_rate, uint bits_per_sample,
+ uint channels)
{
int aif1_reg;
int aif2_reg;
@@ -349,12 +345,10 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
/* AIFCLK/fs ratio; look for a close match in either direction */
best = 0;
- best_val = abs((fs_ratios[0] * sampling_rate)
- - wm8994->aifclk[id]);
+ best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]);
for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
- cur_val = abs((fs_ratios[i] * sampling_rate)
- - wm8994->aifclk[id]);
+ cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]);
if (cur_val >= best_val)
continue;
best = i;
@@ -371,7 +365,7 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
*/
best = 0;
for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
- cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+ cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
if (cur_val < 0) /* BCLK table is sorted */
break;
best = i;
@@ -383,10 +377,10 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
return -1;
}
- bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+ bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best];
bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
- if (wm8994_i2c_read(aif1_reg, &reg_data) != 0) {
+ if (wm8994_i2c_read(priv, aif1_reg, &reg_data) != 0) {
debug("%s: AIF1 register read Failed\n", __func__);
return -1;
}
@@ -394,16 +388,17 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
if ((channels == 1) && ((reg_data & 0x18) == 0x18))
aif2 |= WM8994_AIF1_MONO;
- if (wm8994->aifclk[id] == 0) {
+ if (priv->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);
+ ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+ ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2);
+ ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK,
+ bclk);
+ ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK |
+ WM8994_AIF1CLK_RATE_MASK, rate_val);
debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
@@ -418,12 +413,12 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
/*
* Configures Audio interface Clock
*
- * @param wm8994 wm8994 information pointer
+ * @param priv 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)
+static int configure_aif_clock(struct wm8994_priv *priv, int aif)
{
int rate;
int reg1 = 0;
@@ -436,30 +431,30 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
else
offset = 0;
- switch (wm8994->sysclk[aif-1]) {
+ switch (priv->sysclk[aif - 1]) {
case WM8994_SYSCLK_MCLK1:
reg1 |= SEL_MCLK1;
- rate = wm8994->mclk[0];
+ rate = priv->mclk[0];
break;
case WM8994_SYSCLK_MCLK2:
reg1 |= SEL_MCLK2;
- rate = wm8994->mclk[1];
+ rate = priv->mclk[1];
break;
case WM8994_SYSCLK_FLL1:
reg1 |= SEL_FLL1;
- rate = wm8994->fll[0].out;
+ rate = priv->fll[0].out;
break;
case WM8994_SYSCLK_FLL2:
reg1 |= SEL_FLL2;
- rate = wm8994->fll[1].out;
+ rate = priv->fll[1].out;
break;
default:
debug("%s: Invalid input clock selection [%d]\n",
- __func__, wm8994->sysclk[aif-1]);
+ __func__, priv->sysclk[aif - 1]);
return -1;
}
@@ -469,18 +464,18 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
reg1 |= WM8994_AIF1CLK_DIV;
}
- wm8994->aifclk[aif-1] = rate;
+ priv->aifclk[aif - 1] = rate;
- ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,
- WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
- reg1);
+ ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset,
+ WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+ reg1);
if (aif == WM8994_AIF1)
- ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+ ret |= wm8994_bic_or(priv, 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,
+ ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
@@ -496,33 +491,33 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
/*
* Configures Audio interface for the given frequency
*
- * @param wm8994 wm8994 information
+ * @param priv 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)
+static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id,
+ unsigned int freq)
{
int i;
int ret = 0;
- wm8994->sysclk[aif_id - 1] = clk_id;
+ priv->sysclk[aif_id - 1] = clk_id;
switch (clk_id) {
case WM8994_SYSCLK_MCLK1:
- wm8994->mclk[0] = freq;
+ priv->mclk[0] = freq;
if (aif_id == 2) {
- ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
- WM8994_AIF2DAC_DIV_MASK , 0);
+ ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2,
+ WM8994_AIF2DAC_DIV_MASK, 0);
}
break;
case WM8994_SYSCLK_MCLK2:
/* TODO: Set GPIO AF */
- wm8994->mclk[1] = freq;
+ priv->mclk[1] = freq;
break;
case WM8994_SYSCLK_FLL1:
@@ -543,13 +538,14 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
__func__);
return -1;
}
- ret = wm8994_update_bits(WM8994_CLOCKING_2,
+ ret = wm8994_bic_or(priv, WM8994_CLOCKING_2,
WM8994_OPCLK_DIV_MASK, i);
- ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
- WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+ ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA,
+ WM8994_OPCLK_ENA);
} else {
- ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
- WM8994_OPCLK_ENA, 0);
+ ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA, 0);
}
default:
@@ -558,7 +554,7 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
return -1;
}
- ret |= configure_aif_clock(wm8994, aif_id);
+ ret |= configure_aif_clock(priv, aif_id);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
@@ -571,37 +567,38 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
/*
* Initializes Volume for AIF2 to HP path
*
+ * @param priv wm8994 information
* @returns -1 for error and 0 Success.
*
*/
-static int wm8994_init_volume_aif2_dac1(void)
+static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv)
{
int ret;
/* Unmute AIF2DAC */
- ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
- WM8994_AIF2DAC_MUTE_MASK, 0);
+ ret = wm8994_bic_or(priv, 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_bic_or(priv, 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_bic_or(priv, 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_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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);
+ ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+ ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
@@ -614,26 +611,27 @@ static int wm8994_init_volume_aif2_dac1(void)
/*
* Initializes Volume for AIF1 to HP path
*
+ * @param priv wm8994 information
* @returns -1 for error and 0 Success.
*
*/
-static int wm8994_init_volume_aif1_dac1(void)
+static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv)
{
int ret = 0;
/* Unmute AIF1DAC */
- ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000);
+ ret |= wm8994_i2c_write(priv, 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_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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);
+ ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+ ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
@@ -646,93 +644,99 @@ static int wm8994_init_volume_aif1_dac1(void)
/*
* Intialise wm8994 codec device
*
- * @param wm8994 wm8994 information
+ * @param priv wm8994 information
*
* @returns -1 for error and 0 Success.
*/
-static int wm8994_device_init(struct wm8994_priv *wm8994,
- enum en_audio_interface aif_id)
+static int wm8994_device_init(struct wm8994_priv *priv)
{
const char *devname;
unsigned short reg_data;
int ret;
- wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
+ wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET);
- ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, &reg_data);
+ ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, &reg_data);
if (ret < 0) {
debug("Failed to read ID register\n");
- goto err;
+ return ret;
}
if (reg_data == WM8994_ID) {
devname = "WM8994";
- debug("Device registered as type %d\n", wm8994->type);
- wm8994->type = WM8994;
+ debug("Device registered as type %d\n", priv->type);
+ priv->type = WM8994;
} else {
debug("Device is not a WM8994, ID is %x\n", ret);
- ret = -1;
- goto err;
+ return -ENXIO;
}
- ret = wm8994_i2c_read(WM8994_CHIP_REVISION, &reg_data);
+ ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, &reg_data);
if (ret < 0) {
debug("Failed to read revision register: %d\n", ret);
- goto err;
+ return ret;
}
- wm8994->revision = reg_data;
- debug("%s revision %c\n", devname, 'A' + wm8994->revision);
+ priv->revision = reg_data;
+ debug("%s revision %c\n", devname, 'A' + priv->revision);
+
+ return 0;
+}
+
+static int wm8994_setup_interface(struct wm8994_priv *priv,
+ enum en_audio_interface aif_id)
+{
+ int ret;
/* VMID Selection */
- ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
- WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
+ ret = wm8994_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+ WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
if (aif_id == WM8994_AIF1) {
- ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2,
+ ret |= wm8994_i2c_write(priv, 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,
+ ret |= wm8994_i2c_write(priv, 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,
+ ret |= wm8994_i2c_write(priv, 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,
+ ret |= wm8994_bic_or(priv, 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,
+ ret |= wm8994_bic_or(priv, 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,
+ ret |= wm8994_bic_or(priv, 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,
+ ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
WM8994_HPOUT1L_DLY_MASK |
WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
WM8994_HPOUT1R_OUTP_MASK |
@@ -743,172 +747,130 @@ static int wm8994_device_init(struct wm8994_priv *wm8994,
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_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
+ WM8994_AIF1DAC1L_TO_DAC1L);
- ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
+ ret |= wm8994_i2c_write(priv, 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_i2c_write(priv, WM8994_GPIO_1,
+ WM8994_GPIO_DIR_OUTPUT |
+ WM8994_GPIO_FUNCTION_I2S_CLK |
+ WM8994_GPIO_INPUT_DEBOUNCE);
- ret |= wm8994_init_volume_aif1_dac1();
+ ret |= wm8994_init_volume_aif1_dac1(priv);
} 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_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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);
+ ret |= wm8994_bic_or(priv, 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_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
+ WM8994_GPIO_FUNCTION_MASK,
+ WM8994_GPIO_DIR_OUTPUT);
- ret |= wm8994_init_volume_aif2_dac1();
+ ret |= wm8994_init_volume_aif2_dac1(priv);
}
if (ret < 0)
goto err;
- debug("%s: Codec chip init ok\n", __func__);
+ debug("%s: Codec chip setup ok\n", __func__);
return 0;
err:
- debug("%s: Codec chip init error\n", __func__);
+ debug("%s: Codec chip setup 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)
+static int _wm8994_init(struct wm8994_priv *priv,
+ enum en_audio_interface aif_id, int sampling_rate,
+ int mclk_freq, int bits_per_sample,
+ unsigned int channels)
{
- int error = 0;
-#if CONFIG_IS_ENABLED(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;
- }
+ int ret;
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
- debug("%s: Cannot find node parent\n", __func__);
- return -1;
+ ret = wm8994_setup_interface(priv, aif_id);
+ if (ret < 0) {
+ debug("%s: wm8994 codec chip init failed\n", __func__);
+ return ret;
}
- 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;
+ ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
+ if (ret < 0) {
+ debug("%s: wm8994 codec set sys clock failed\n", __func__);
+ return ret;
}
-#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;
+ ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample,
+ channels);
- if (error == -1) {
- debug("fail to get wm8994 codec node properties\n");
- return -1;
+ if (ret == 0) {
+ ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
}
- return 0;
+ return ret;
}
-/* 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)
+static int wm8994_set_params(struct udevice *dev, int interface, int rate,
+ int mclk_freq, int bits_per_sample, uint channels)
{
- int ret = 0;
- struct sound_codec_info *pcodec_info = &g_codec_info;
+ struct wm8994_priv *priv = dev_get_priv(dev);
- /* 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);
+ return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
+ channels);
+}
- 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;
- }
+static int wm8994_probe(struct udevice *dev)
+{
+ struct wm8994_priv *priv = dev_get_priv(dev);
- ret = wm8994_device_init(&g_wm8994_info, aif_id);
- if (ret < 0) {
- debug("%s: wm8994 codec chip init failed\n", __func__);
- return ret;
- }
+ priv->dev = dev;
+ return wm8994_device_init(priv);
+}
- 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;
- }
+static const struct audio_codec_ops wm8994_ops = {
+ .set_params = wm8994_set_params,
+};
- ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
- bits_per_sample, channels);
+static const struct udevice_id wm8994_ids[] = {
+ { .compatible = "wolfson,wm8994" },
+ { }
+};
- 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;
-}
+U_BOOT_DRIVER(wm8994) = {
+ .name = "wm8994",
+ .id = UCLASS_AUDIO_CODEC,
+ .of_match = wm8994_ids,
+ .probe = wm8994_probe,
+ .ops = &wm8994_ops,
+ .priv_auto_alloc_size = sizeof(struct wm8994_priv),
+};
diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h
index ef2878f87c..e36e6269f0 100644
--- a/drivers/sound/wm8994.h
+++ b/drivers/sound/wm8994.h
@@ -15,7 +15,7 @@
/* Avilable audi interface ports in wm8994 codec */
enum en_audio_interface {
- WM8994_AIF1 = 1,
+ WM8994_AIF1,
WM8994_AIF2,
WM8994_AIF3
};