Add support for the ES8328 audio codec.
---
 sound/soc/codecs/Kconfig  |   4 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/es8328.c | 611 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/es8328.h | 240 ++++++++++++++++++
 4 files changed, 857 insertions(+)
 create mode 100644 sound/soc/codecs/es8328.c
 create mode 100644 sound/soc/codecs/es8328.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087a..2b0a821 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
        select SND_SOC_BT_SCO
+       select SND_SOC_ES8328 if I2C
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
@@ -283,6 +284,9 @@ config SND_SOC_BT_SCO
 config SND_SOC_DMIC
        tristate
 
+config SND_SOC_ES8328
+       tristate
+
 config SND_SOC_ISABELLE
         tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc12676..1b62c93 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -30,6 +30,7 @@ snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-es8328-objs := es8328.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -163,6 +164,7 @@ obj-$(CONFIG_SND_SOC_DA732X)        += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ES8328)    += snd-soc-es8328.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
new file mode 100644
index 0000000..db118f4
--- /dev/null
+++ b/sound/soc/codecs/es8328.c
@@ -0,0 +1,611 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "es8328.h"
+
+/* Run the codec at 22.5792 MHz to support these rates */
+enum es8328_rate {
+       ES8328_RATE_8019,
+       ES8328_RATE_11025,
+       ES8328_RATE_22050,
+       ES8328_RATE_44100,
+};
+
+uint8_t sample_ratios[] = {
+       [ES8328_RATE_8019 ] = 0x9,
+       [ES8328_RATE_11025] = 0x7,
+       [ES8328_RATE_22050] = 0x4,
+       [ES8328_RATE_44100] = 0x2,
+};
+
+#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
+               SNDRV_PCM_RATE_22050 | \
+               SNDRV_PCM_RATE_11025)
+#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+/* codec private data */
+struct es8328_priv {
+       struct regmap *regmap;
+       int sysclk;
+};
+
+static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(cap_tlv, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+
+static const struct snd_kcontrol_new es8328_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Playback Volume",
+               ES8328_DACCONTROL26, ES8328_DACCONTROL27, 0, 0x24, 0, play_tlv),
+SOC_DOUBLE_R_TLV("Headphone Playback Volume",
+               ES8328_DACCONTROL24, ES8328_DACCONTROL25, 0, 0x24, 0, play_tlv),
+
+SOC_DOUBLE_R_TLV("Mic Capture Volume",
+               ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, 0, 0xc0, 1, cap_tlv),
+SOC_DOUBLE_TLV("Mic PGA Volume",
+               ES8328_ADCCONTROL1, 4, 0, 0x08, 0, pga_tlv),
+};
+
+/*
+ * DAPM controls.
+ */
+static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Speaker Volume", "HiFi Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_OUTPUT("VOUTL"),
+       SND_SOC_DAPM_OUTPUT("VOUTR"),
+        SND_SOC_DAPM_INPUT("LINE_IN"),
+        SND_SOC_DAPM_INPUT("MIC_IN"),
+        SND_SOC_DAPM_OUTPUT("HP_OUT"),
+        SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+
+static const struct snd_soc_dapm_route es8328_intercon[] = {
+       {"VOUTL", NULL, "DAC"},
+       {"VOUTR", NULL, "DAC"},
+};
+
+static int es8328_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = snd_soc_read(codec, ES8328_DACCONTROL3);
+
+       if (mute)
+               mute_reg |= ES8328_DACCONTROL3_DACMUTE;
+       else
+               mute_reg &= ~ES8328_DACCONTROL3_DACMUTE;
+       return snd_soc_write(codec, ES8328_DACCONTROL3, mute_reg);
+}
+
+static int es8328_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               u8 dac = snd_soc_read(codec, ES8328_DACCONTROL2);
+               dac &= ~ES8328_DACCONTROL2_RATEMASK;
+
+               switch (params_rate(params)) {
+               case 8000:
+                       dac |= sample_ratios[ES8328_RATE_8019];
+                       break;
+               case 11025:
+                       dac |= sample_ratios[ES8328_RATE_11025];
+                       break;
+               case 22050:
+                       dac |= sample_ratios[ES8328_RATE_22050];
+                       break;
+               case 44100:
+                       dac |= sample_ratios[ES8328_RATE_44100];
+                       break;
+               default:
+                       dev_err(codec->dev, "%s: unknown rate %d\n",
+                                __func__, params_rate(params));
+                       return -EINVAL;
+               }
+               snd_soc_write(codec, ES8328_DACCONTROL2, dac);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               u8 adc = snd_soc_read(codec, ES8328_ADCCONTROL5);
+               adc &= ~ES8328_ADCCONTROL5_RATEMASK;
+
+               switch (params_rate(params)) {
+               case 8000:
+                       adc |= sample_ratios[ES8328_RATE_8019];
+                       break;
+               case 11025:
+                       adc |= sample_ratios[ES8328_RATE_11025];
+                       break;
+               case 22050:
+                       adc |= sample_ratios[ES8328_RATE_22050];
+                       break;
+               case 44100:
+                       adc |= sample_ratios[ES8328_RATE_44100];
+                       break;
+               default:
+                       dev_err(codec->dev, "%s: unknown rate %d\n",
+                                __func__, params_rate(params));
+                       return -EINVAL;
+               }
+               snd_soc_write(codec, ES8328_ADCCONTROL5, adc);
+       }
+
+       return 0;
+}
+
+static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
+               return -EINVAL;
+
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
+               return -EINVAL;
+
+       if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int es8328_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case 0:
+               es8328->sysclk = freq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int es8328_adc_enable(struct snd_soc_codec *codec)
+{
+       u16 reg = snd_soc_read(codec, ES8328_CHIPPOWER);
+       reg &= ~(ES8328_CHIPPOWER_ADCVREF_OFF |
+                ES8328_CHIPPOWER_ADCPLL_OFF |
+                ES8328_CHIPPOWER_ADCSTM_RESET |
+                ES8328_CHIPPOWER_ADCDIG_OFF);
+       snd_soc_write(codec, ES8328_CHIPPOWER, reg);
+
+       /* Set up microphone to be differential input */
+       snd_soc_write(codec, ES8328_ADCCONTROL2, 0xf0);
+
+       /* Set ADC to act as I2S master */
+       snd_soc_write(codec, ES8328_ADCCONTROL3, 0x02);
+
+       /* Set I2S to 16-bit mode */
+       snd_soc_write(codec, ES8328_ADCCONTROL4, 0x18);
+
+       /* Frequency clock of 272 */
+       snd_soc_write(codec, ES8328_ADCCONTROL5, 0x02);
+
+       return 0;
+}
+
+static int es8328_dac_enable(struct snd_soc_codec *codec)
+{
+       u16 old_volumes[4];
+       u16 reg;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               old_volumes[i] = snd_soc_read(codec, i + ES8328_DACCONTROL24);
+               snd_soc_write(codec, i + ES8328_DACCONTROL24, 0);
+       }
+
+       /* Power up LOUT2 ROUT2, and power down xOUT1 */
+       snd_soc_write(codec, ES8328_DACPOWER,
+                       ES8328_DACPOWER_ROUT2_ON |
+                       ES8328_DACPOWER_LOUT2_ON);
+
+       /* Enable click-free power up */
+       snd_soc_write(codec, ES8328_DACCONTROL6, ES8328_DACCONTROL6_CLICKFREE);
+       snd_soc_write(codec, ES8328_DACCONTROL3, 0x36);
+
+       /* Set I2S to 16-bit mode */
+       snd_soc_write(codec, ES8328_DACCONTROL1, ES8328_DACCONTROL1_DACWL_16);
+
+       /* No attenuation */
+       snd_soc_write(codec, ES8328_DACCONTROL4, 0x00);
+       snd_soc_write(codec, ES8328_DACCONTROL5, 0x00);
+
+       /* Set LIN2 for the output mixer */
+       snd_soc_write(codec, ES8328_DACCONTROL16,
+                       ES8328_DACCONTROL16_RMIXSEL_RIN2 |
+                       ES8328_DACCONTROL16_LMIXSEL_LIN2);
+
+       /* Point the left DAC at the left mixer */
+       snd_soc_write(codec, ES8328_DACCONTROL17, ES8328_DACCONTROL17_LD2LO);
+       /* Point the right DAC at the right mixer */
+       snd_soc_write(codec, ES8328_DACCONTROL20, ES8328_DACCONTROL20_RD2RO);
+
+       /* Disable all other outputs */
+       snd_soc_write(codec, ES8328_DACCONTROL18, 0x00);
+       snd_soc_write(codec, ES8328_DACCONTROL19, 0x00);
+
+
+       /* Disable mono mode for DACL, and mute DACR */
+       snd_soc_write(codec, ES8328_DACCONTROL7, 0x00);
+
+       for (i = 0; i < 4; i++)
+               snd_soc_write(codec, i + ES8328_DACCONTROL24, old_volumes[i]);
+
+       reg = snd_soc_read(codec, ES8328_CHIPPOWER);
+       reg &= ~(ES8328_CHIPPOWER_DACVREF_OFF |
+                ES8328_CHIPPOWER_DACPLL_OFF |
+                ES8328_CHIPPOWER_DACSTM_RESET |
+                ES8328_CHIPPOWER_DACDIG_OFF);
+       snd_soc_write(codec, ES8328_CHIPPOWER, reg);
+       snd_soc_write(codec, ES8328_DACCONTROL3, 0x32);
+
+       return 0;
+}
+
+static int es8328_pcm_prepare(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               es8328_dac_enable(codec);
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               es8328_adc_enable(codec);
+
+       return 0;
+}
+
+static void es8328_pcm_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 reg;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* Mute DAC */
+               snd_soc_write(codec, ES8328_DACCONTROL3,
+                               ES8328_DACCONTROL3_DACZEROCROSS |
+                               ES8328_DACCONTROL3_DACSOFTRAMP |
+                               ES8328_DACCONTROL3_DACMUTE);
+
+               /* Power down DAC and disable LOUT/ROUT */
+               snd_soc_write(codec, ES8328_DACPOWER,
+                               ES8328_DACPOWER_LDAC_OFF |
+                               ES8328_DACPOWER_RDAC_OFF);
+
+               /* Power down DEM and STM */
+               reg = snd_soc_read(codec, ES8328_CHIPPOWER);
+               reg |= (ES8328_CHIPPOWER_DACVREF_OFF |
+                       ES8328_CHIPPOWER_DACPLL_OFF |
+                       ES8328_CHIPPOWER_DACDIG_OFF);
+               snd_soc_write(codec, ES8328_CHIPPOWER, reg);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               /* Mute ADC */
+               snd_soc_write(codec, ES8328_ADCCONTROL7,
+                       ES8328_ADCCONTROL7_ADC_LER |
+                       ES8328_ADCCONTROL7_ADC_ZERO_CROSS |
+                       ES8328_ADCCONTROL7_ADC_SOFT_RAMP);
+
+               /* Power down ADC */
+               snd_soc_write(codec, ES8328_ADCPOWER,
+                       ES8328_ADCPOWER_ADC_BIAS_GEN_OFF |
+                       ES8328_ADCPOWER_MIC_BIAS_OFF |
+                       ES8328_ADCPOWER_ADCR_OFF |
+                       ES8328_ADCPOWER_ADCL_OFF |
+                       ES8328_ADCPOWER_AINR_OFF |
+                       ES8328_ADCPOWER_AINL_OFF);
+
+               /* Power down DEM and STM */
+               reg = snd_soc_read(codec, ES8328_CHIPPOWER);
+               reg |= (ES8328_CHIPPOWER_ADCVREF_OFF |
+                       ES8328_CHIPPOWER_ADCPLL_OFF |
+                       ES8328_CHIPPOWER_ADCDIG_OFF);
+               snd_soc_write(codec, ES8328_CHIPPOWER, reg);
+       }
+
+       return;
+}
+
+static int es8328_init(struct snd_soc_codec *codec)
+{
+       /* Master serial port mode */
+       snd_soc_write(codec, ES8328_MASTERMODE,
+                       ES8328_MASTERMODE_MCLKDIV2 |
+                       ES8328_MASTERMODE_MSC);
+
+       /* Power everything down and reset the cip */
+       snd_soc_write(codec, ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACSTM_RESET |
+                       ES8328_CHIPPOWER_ADCSTM_RESET |
+                       ES8328_CHIPPOWER_DACDIG_OFF |
+                       ES8328_CHIPPOWER_ADCDIG_OFF |
+                       ES8328_CHIPPOWER_DACVREF_OFF |
+                       ES8328_CHIPPOWER_ADCVREF_OFF);
+
+       /* Power up.  Set ADC and DAC to use different frequency ratios */
+       snd_soc_write(codec, ES8328_CONTROL1,
+                       ES8328_CONTROL1_VMIDSEL_50k |
+                       ES8328_CONTROL1_ENREF);
+
+       /* Power up more blocks */
+       snd_soc_write(codec, ES8328_CONTROL2,
+                       ES8328_CONTROL2_OVERCURRENT_ON |
+                       ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
+
+
+       /* Power on the chip (but leave VRET off) */
+       /*
+       snd_soc_write(codec, ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACVREF_OFF |
+                       ES8328_CHIPPOWER_ADCVREF_OFF);
+       */
+
+
+       /* Enable muting, and turn on zerocross */
+       snd_soc_write(codec, ES8328_DACCONTROL3,
+                       ES8328_DACCONTROL3_DACZEROCROSS |
+                       ES8328_DACCONTROL3_DACSOFTRAMP |
+                       ES8328_DACCONTROL3_DACMUTE);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops es8328_dai_ops = {
+       .hw_params      = es8328_hw_params,
+       .prepare        = es8328_pcm_prepare,
+       .shutdown       = es8328_pcm_shutdown,
+//     .digital_mute   = es8328_mute,
+       .set_fmt        = es8328_set_dai_fmt,
+       .set_sysclk     = es8328_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver es8328_dai = {
+       .name = "es8328-hifi-analog",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = ES8328_RATES,
+               .formats = ES8328_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = ES8328_RATES,
+               .formats = ES8328_FORMATS,
+       },
+       .ops = &es8328_dai_ops,
+};
+
+static int es8328_suspend(struct snd_soc_codec *codec)
+{
+       return 0;
+}
+
+static int es8328_resume(struct snd_soc_codec *codec)
+{
+       es8328_init(codec);
+       return 0;
+}
+
+static int es8328_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct device *dev = codec->dev;
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(dev, "failed to configure cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* power on device */
+       es8328_init(codec);
+
+       return 0;
+}
+
+static int es8328_remove(struct snd_soc_codec *codec)
+{
+       /* Power everything down and reset the cip */
+       snd_soc_write(codec, ES8328_CHIPPOWER,
+                       ES8328_CHIPPOWER_DACSTM_RESET |
+                       ES8328_CHIPPOWER_ADCSTM_RESET |
+                       ES8328_CHIPPOWER_DACDIG_OFF |
+                       ES8328_CHIPPOWER_ADCDIG_OFF |
+                       ES8328_CHIPPOWER_DACVREF_OFF |
+                       ES8328_CHIPPOWER_ADCVREF_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_es8328 = {
+       .probe =                es8328_probe,
+       .remove =               es8328_remove,
+       .suspend =              es8328_suspend,
+       .resume =               es8328_resume,
+       .controls =             es8328_snd_controls,
+       .num_controls =         ARRAY_SIZE(es8328_snd_controls),
+       .dapm_widgets =         es8328_dapm_widgets,
+       .num_dapm_widgets =     ARRAY_SIZE(es8328_dapm_widgets),
+       .dapm_routes =          es8328_intercon,
+       .num_dapm_routes =      ARRAY_SIZE(es8328_intercon),
+};
+
+static const struct of_device_id es8328_of_match[] = {
+       { .compatible = "everest,es8328", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static const struct regmap_config es8328_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = ES8328_REG_MAX,
+
+       .cache_type = REGCACHE_NONE,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int es8328_spi_probe(struct spi_device *spi)
+{
+       struct es8328_priv *es8328;
+       int ret;
+
+       es8328 = devm_kzalloc(&spi->dev, sizeof(struct es8328_priv),
+                             GFP_KERNEL);
+       if (es8328 == NULL)
+               return -ENOMEM;
+
+       es8328->regmap = devm_regmap_init_spi(spi, &es8328_regmap);
+       if (IS_ERR(es8328->regmap))
+               return PTR_ERR(es8328->regmap);
+
+       spi_set_drvdata(spi, es8328);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_es8328, &es8328_dai, 1);
+       if (ret < 0)
+               dev_err(&spi->dev, "unable to register codec: %d\n", ret);
+
+       return ret;
+}
+
+static int es8328_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+
+       return 0;
+}
+
+static struct spi_driver es8328_spi_driver = {
+       .driver = {
+               .name   = "es8328",
+               .owner  = THIS_MODULE,
+               .of_match_table = es8328_of_match,
+       },
+       .probe          = es8328_spi_probe,
+       .remove         = es8328_spi_remove,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int es8328_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct es8328_priv *es8328;
+       int ret;
+
+       es8328 = devm_kzalloc(&i2c->dev, sizeof(struct es8328_priv),
+                             GFP_KERNEL);
+       if (es8328 == NULL)
+               return -ENOMEM;
+
+       es8328->regmap = devm_regmap_init_i2c(i2c, &es8328_regmap);
+       if (IS_ERR(es8328->regmap))
+               return PTR_ERR(es8328->regmap);
+
+       i2c_set_clientdata(i2c, es8328);
+
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_es8328, &es8328_dai, 1);
+
+       return ret;
+}
+
+static int es8328_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id es8328_i2c_id[] = {
+       { "es8328", 0x11 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, es8328_i2c_id);
+
+static struct i2c_driver es8328_i2c_driver = {
+       .driver = {
+               .name = "es8328-codec",
+               .owner = THIS_MODULE,
+               .of_match_table = es8328_of_match,
+       },
+       .probe =    es8328_i2c_probe,
+       .remove =   es8328_i2c_remove,
+       .id_table = es8328_i2c_id,
+};
+#endif
+
+static int __init es8328_modinit(void)
+{
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&es8328_i2c_driver);
+       if (ret != 0) {
+               pr_err("failed to register es8328 I2C driver: %d\n", ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&es8328_spi_driver);
+       if (ret != 0) {
+               pr_err("Failed to register es8328 SPI driver: %d\n", ret);
+       }
+#endif
+       return ret;
+}
+module_init(es8328_modinit);
+
+static void __exit es8328_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&es8328_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&es8328_spi_driver);
+#endif
+}
+module_exit(es8328_exit);
+
+MODULE_DESCRIPTION("ASoC ES8328 driver");
+MODULE_AUTHOR("Sean Cross <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
new file mode 100644
index 0000000..234a6cb
--- /dev/null
+++ b/sound/soc/codecs/es8328.h
@@ -0,0 +1,240 @@
+/*
+ * es8328.h  --  ES8328 ALSA SoC Audio driver
+ */
+
+#ifndef _ES8328_H
+#define _ES8328_H
+
+#define ES8328_DACLVOL 46
+#define ES8328_DACRVOL 47
+#define ES8328_DACCTL 28
+
+#define ES8328_CONTROL1                0x00
+#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
+#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
+#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
+#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
+#define ES8328_CONTROL1_ENREF (1 << 2)
+#define ES8328_CONTROL1_SEQEN (1 << 3)
+#define ES8328_CONTROL1_SAMEFS (1 << 4)
+#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
+#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
+#define ES8328_CONTROL1_LRCM (1 << 6)
+#define ES8328_CONTROL1_SCP_RESET (1 << 7)
+
+#define ES8328_CONTROL2                0x01
+#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
+#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
+#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
+#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
+#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
+#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
+#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
+#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
+
+#define ES8328_CHIPPOWER       0x02
+#define ES8328_CHIPPOWER_DACVREF_OFF (1 << 0)
+#define ES8328_CHIPPOWER_ADCVREF_OFF (1 << 1)
+#define ES8328_CHIPPOWER_DACPLL_OFF (1 << 2)
+#define ES8328_CHIPPOWER_ADCPLL_OFF (1 << 3)
+#define ES8328_CHIPPOWER_DACSTM_RESET (1 << 4)
+#define ES8328_CHIPPOWER_ADCSTM_RESET (1 << 5)
+#define ES8328_CHIPPOWER_DACDIG_OFF (1 << 6)
+#define ES8328_CHIPPOWER_ADCDIG_OFF (1 << 7)
+
+#define ES8328_ADCPOWER                0x03
+#define ES8328_ADCPOWER_INT1_LOWPOWER (1 << 0)
+#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER (1 << 1)
+#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF (1 << 2)
+#define ES8328_ADCPOWER_MIC_BIAS_OFF (1 << 3)
+#define ES8328_ADCPOWER_ADCR_OFF (1 << 4)
+#define ES8328_ADCPOWER_ADCL_OFF (1 << 5)
+#define ES8328_ADCPOWER_AINR_OFF (1 << 6)
+#define ES8328_ADCPOWER_AINL_OFF (1 << 7)
+
+#define ES8328_DACPOWER                0x04
+#define ES8328_DACPOWER_OUT3_ON (1 << 0)
+#define ES8328_DACPOWER_MONO_ON (1 << 1)
+#define ES8328_DACPOWER_ROUT2_ON (1 << 2)
+#define ES8328_DACPOWER_LOUT2_ON (1 << 3)
+#define ES8328_DACPOWER_ROUT1_ON (1 << 4)
+#define ES8328_DACPOWER_LOUT1_ON (1 << 5)
+#define ES8328_DACPOWER_RDAC_OFF (1 << 6)
+#define ES8328_DACPOWER_LDAC_OFF (1 << 7)
+
+#define ES8328_CHIPLOPOW1      0x05
+#define ES8328_CHIPLOPOW2      0x06
+#define ES8328_ANAVOLMANAG     0x07
+
+#define ES8328_MASTERMODE      0x08
+#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
+#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
+#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
+#define ES8328_MASTERMODE_MSC (1 << 7)
+
+#define ES8328_ADCCONTROL1     0x09
+#define ES8328_ADCCONTROL2     0x0a
+#define ES8328_ADCCONTROL3     0x0b
+#define ES8328_ADCCONTROL4     0x0c
+#define ES8328_ADCCONTROL5     0x0d
+#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
+
+#define ES8328_ADCCONTROL6     0x0e
+
+#define ES8328_ADCCONTROL7     0x0f
+#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
+#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
+#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
+#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
+
+#define ES8328_ADCCONTROL8     0x10
+#define ES8328_ADCCONTROL9     0x11
+#define ES8328_ADCCONTROL10    0x12
+#define ES8328_ADCCONTROL11    0x13
+#define ES8328_ADCCONTROL12    0x14
+#define ES8328_ADCCONTROL13    0x15
+#define ES8328_ADCCONTROL14    0x16
+
+#define ES8328_DACCONTROL1     0x17
+#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
+#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
+#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
+#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
+#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
+#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (0 << 6)
+#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
+
+#define ES8328_DACCONTROL2     0x18
+#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
+
+#define ES8328_DACCONTROL3     0x19
+#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
+#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
+#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
+#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
+#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
+#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
+
+#define ES8328_DACCONTROL4     0x1a
+#define ES8328_DACCONTROL5     0x1b
+
+#define ES8328_DACCONTROL6     0x1c
+#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
+#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
+#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
+
+#define ES8328_DACCONTROL7     0x1d
+#define ES8328_DACCONTROL8     0x1e
+#define ES8328_DACCONTROL9     0x1f
+#define ES8328_DACCONTROL10    0x20
+#define ES8328_DACCONTROL11    0x21
+#define ES8328_DACCONTROL12    0x22
+#define ES8328_DACCONTROL13    0x23
+#define ES8328_DACCONTROL14    0x24
+#define ES8328_DACCONTROL15    0x25
+
+#define ES8328_DACCONTROL16    0x26
+#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
+
+#define ES8328_DACCONTROL17    0x27
+#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL17_LI2LO (1 << 6)
+#define ES8328_DACCONTROL17_LD2LO (1 << 7)
+
+#define ES8328_DACCONTROL18    0x28
+#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL18_RI2LO (1 << 6)
+#define ES8328_DACCONTROL18_RD2LO (1 << 7)
+
+#define ES8328_DACCONTROL19    0x29
+#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL19_LI2RO (1 << 6)
+#define ES8328_DACCONTROL19_LD2RO (1 << 7)
+
+#define ES8328_DACCONTROL20    0x2a
+#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL20_RI2RO (1 << 6)
+#define ES8328_DACCONTROL20_RD2RO (1 << 7)
+
+#define ES8328_DACCONTROL21    0x2b
+#define ES8328_DACCONTROL22    0x2c
+#define ES8328_DACCONTROL23    0x2d
+#define ES8328_DACCONTROL24    0x2e
+#define ES8328_DACCONTROL25    0x2f
+#define ES8328_DACCONTROL26    0x30
+#define ES8328_DACCONTROL27    0x31
+#define ES8328_DACCONTROL28    0x32
+#define ES8328_DACCONTROL29    0x33
+#define ES8328_DACCONTROL30    0x34
+#define ES8328_SYSCLK          0
+
+#define ES8328_REG_MAX         0x35
+
+#define ES8328_PLL1            0
+#define ES8328_PLL2            1
+
+/* clock inputs */
+#define ES8328_MCLK            0
+#define ES8328_PCMCLK          1
+
+/* clock divider id's */
+#define ES8328_PCMDIV          0
+#define ES8328_BCLKDIV         1
+#define ES8328_VXCLKDIV                2
+
+/* PCM clock dividers */
+#define ES8328_PCM_DIV_1       (0 << 6)
+#define ES8328_PCM_DIV_3       (2 << 6)
+#define ES8328_PCM_DIV_5_5     (3 << 6)
+#define ES8328_PCM_DIV_2       (4 << 6)
+#define ES8328_PCM_DIV_4       (5 << 6)
+#define ES8328_PCM_DIV_6       (6 << 6)
+#define ES8328_PCM_DIV_8       (7 << 6)
+
+/* BCLK clock dividers */
+#define ES8328_BCLK_DIV_1      (0 << 7)
+#define ES8328_BCLK_DIV_2      (1 << 7)
+#define ES8328_BCLK_DIV_4      (2 << 7)
+#define ES8328_BCLK_DIV_8      (3 << 7)
+
+/* VXCLK clock dividers */
+#define ES8328_VXCLK_DIV_1     (0 << 6)
+#define ES8328_VXCLK_DIV_2     (1 << 6)
+#define ES8328_VXCLK_DIV_4     (2 << 6)
+#define ES8328_VXCLK_DIV_8     (3 << 6)
+#define ES8328_VXCLK_DIV_16    (4 << 6)
+
+#define ES8328_DAI_HIFI                0
+#define ES8328_DAI_VOICE       1
+
+#define ES8328_1536FS          1536
+#define ES8328_1024FS          1024
+#define ES8328_768FS           768
+#define ES8328_512FS           512
+#define ES8328_384FS           384
+#define ES8328_256FS           256
+#define ES8328_128FS           128
+
+#endif
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to