[alsa-devel] [RFC][PATCH] ASoC: Add max98090 codec driver
Kuninori Morimoto
kuninori.morimoto.gx at renesas.com
Tue Nov 20 11:00:54 CET 2012
This patch adds the max98090 codec prototype driver.
It supports Headphone only at this point.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
---
> Mark
I created this driver but I didn't/couldn't test it,
because we still don't have board which has max98090 chip at this point.
We will get it soon if hardware is on-schedule,
and then, we would like to use a upstreamed driver.
So, I send this driver as [RFC] now.
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/max98090.c | 489 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 495 insertions(+)
create mode 100644 sound/soc/codecs/max98090.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0e368d4..3a84782 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_LM4857 if I2C
select SND_SOC_LM49453 if I2C
select SND_SOC_MAX98088 if I2C
+ select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
@@ -267,6 +268,9 @@ config SND_SOC_LM49453
config SND_SOC_MAX98088
tristate
+config SND_SOC_MAX98090
+ tristate
+
config SND_SOC_MAX98095
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aa56312..f6e8e36 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -34,6 +34,7 @@ snd-soc-lm4857-objs := lm4857.o
snd-soc-lm49453-objs := lm49453.o
snd-soc-max9768-objs := max9768.o
snd-soc-max98088-objs := max98088.o
+snd-soc-max98090-objs := max98090.o
snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o
snd-soc-mc13783-objs := mc13783.o
@@ -157,6 +158,7 @@ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
new file mode 100644
index 0000000..1de396e
--- /dev/null
+++ b/sound/soc/codecs/max98090.c
@@ -0,0 +1,489 @@
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ * based on Rev0p81 datasheet
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
+ *
+ * Based on
+ *
+ * max98095.c
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * https://github.com/hardkernel/linux/commit/\
+ * 3417d7166b17113b3b33b0a337c74d1c7cc313df#sound/soc/codecs/max98090.c
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+/*
+ *
+ * MAX98090 Registers Definition
+ *
+ */
+
+/* RESET / STATUS / INTERRUPT REGISTERS */
+#define M98090_0x00_SW_RESET 0x00
+#define M98090_0x01_INT_STS 0x01
+#define M98090_0x02_JACK_STS 0x02
+#define M98090_0x03_INT_MASK 0x03
+
+/* QUICK SETUP REGISTERS */
+#define M98090_0x04_SYS_CLK 0x04
+#define M98090_0x05_SAMPLE_RATE 0x05
+#define M98090_0x06_DAI_IF 0x06
+#define M98090_0x07_DAC_PATH 0x07
+#define M98090_0x08_MIC_TO_ADC 0x08
+#define M98090_0x09_LINE_TO_ADC 0x09
+#define M98090_0x0A_ANALOG_MIC_LOOP 0x0A
+#define M98090_0x0B_ANALOG_LINE_LOOP 0x0B
+
+/* ANALOG INPUT CONFIGURATION REGISTERS */
+#define M98090_0x0D_INPUT_CONFIG 0x0D
+#define M98090_0x0E_LINE_IN_LVL 0x0E
+#define M98090_0x0F_LINI_IN_CFG 0x0F
+#define M98090_0x10_MIC1_IN_LVL 0x10
+#define M98090_0x11_MIC2_IN_LVL 0x11
+
+/* MICROPHONE CONFIGURATION REGISTERS */
+#define M98090_0x12_MIC_BIAS_VOL 0x12
+#define M98090_0x13_DIGITAL_MIC_CFG 0x13
+#define M98090_0x14_DIGITAL_MIC_MODE 0x14
+
+/* ADC PATH AND CONFIGURATION REGISTERS */
+#define M98090_0x15_L_ADC_MIX 0x15
+#define M98090_0x16_R_ADC_MIX 0x16
+#define M98090_0x17_L_ADC_LVL 0x17
+#define M98090_0x18_R_ADC_LVL 0x18
+#define M98090_0x19_ADC_BIQUAD_LVL 0x19
+#define M98090_0x1A_ADC_SIDETONE 0x1A
+
+/* CLOCK CONFIGURATION REGISTERS */
+#define M98090_0x1B_SYS_CLK 0x1B
+#define M98090_0x1C_CLK_MODE 0x1C
+#define M98090_0x1D_ANY_CLK1 0x1D
+#define M98090_0x1E_ANY_CLK2 0x1E
+#define M98090_0x1F_ANY_CLK3 0x1F
+#define M98090_0x20_ANY_CLK4 0x20
+#define M98090_0x21_MASTER_MODE 0x21
+
+/* INTERFACE CONTROL REGISTERS */
+#define M98090_0x22_DAI_IF_FMT 0x22
+#define M98090_0x23_DAI_TDM_FMT1 0x23
+#define M98090_0x24_DAI_TDM_FMT2 0x24
+#define M98090_0x25_DAI_IO_CFG 0x25
+#define M98090_0x26_FILTER_CFG 0x26
+#define M98090_0x27_DAI_PLAYBACK_LVL 0x27
+#define M98090_0x28_EQ_PLAYBACK_LVL 0x28
+
+/* HEADPHONE CONTROL REGISTERS */
+#define M98090_0x29_L_HP_MIX 0x29
+#define M98090_0x2A_R_HP_MIX 0x2A
+#define M98090_0x2B_HP_CTR 0x2B
+#define M98090_0x2C_L_HP_VOL 0x2C
+#define M98090_0x2D_R_HP_VOL 0x2D
+
+/* SPEAKER CONFIGURATION REGISTERS */
+#define M98090_0x2E_L_SPK_MIX 0x2E
+#define M98090_0x2F_R_SPK_MIX 0x2F
+#define M98090_0x30_SPK_CTR 0x30
+#define M98090_0x31_L_SPK_VOL 0x31
+#define M98090_0x32_R_SPK_VOL 0x32
+
+/* ALC CONFIGURATION REGISTERS */
+#define M98090_0x33_ALC_TIMING 0x33
+#define M98090_0x34_ALC_COMPRESSOR 0x34
+#define M98090_0x35_ALC_EXPANDER 0x35
+#define M98090_0x36_ALC_GAIN 0x36
+
+/* RECEIVER AND LINE_OUTPUT REGISTERS */
+#define M98090_0x37_RCV_LOUT_L_MIX 0x37
+#define M98090_0x38_RCV_LOUT_L_CNTL 0x38
+#define M98090_0x39_RCV_LOUT_L_VOL 0x39
+#define M98090_0x3A_LOUT_R_MIX 0x3A
+#define M98090_0x3B_LOUT_R_CNTL 0x3B
+#define M98090_0x3C_LOUT_R_VOL 0x3C
+
+/* JACK DETECT AND ENABLE REGISTERS */
+#define M98090_0x3D_JACK_DETECT 0x3D
+#define M98090_0x3E_IN_ENABLE 0x3E
+#define M98090_0x3F_OUT_ENABLE 0x3F
+#define M98090_0x40_LVL_CTR 0x40
+#define M98090_0x41_DSP_FILTER_ENABLE 0x41
+
+/* BIAS AND POWER MODE CONFIGURATION REGISTERS */
+#define M98090_0x42_BIAS_CTR 0x42
+#define M98090_0x43_DAC_CTR 0x43
+#define M98090_0x44_ADC_CTR 0x44
+#define M98090_0x45_DEV_SHUTDOWN 0x45
+
+/* REVISION ID REGISTER */
+#define M98090_0xFF_REV_ID 0xFF
+
+#define M98090_REG_MAX_CACHED 0x45
+
+
+/*
+ *
+ * MAX98090 Registers Bit Fields
+ *
+ */
+
+/* M98090_0x06_DAI_IF */
+#define M98090_RJ_M (1 << 5)
+#define M98090_RJ_S (1 << 4)
+#define M98090_LJ_M (1 << 3)
+#define M98090_LJ_S (1 << 2)
+#define M98090_I2S_M (1 << 1)
+#define M98090_I2S_S (1 << 0)
+
+/* M98090_0x45_DEV_SHUTDOWN */
+#define M98090_SHDNRUN (1 << 7)
+
+static const u8 max98090_reg[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0x00 - 0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, /* 0x08 - 0x0F */
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, /* 0x10 - 0x17 */
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 - 0x1F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 0x20 - 0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x00, /* 0x28 - 0x2F */
+ 0x00, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 - 0x37 */
+ 0x00, 0x15, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, /* 0x38 - 0x3F */
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, /* 0x40 - 0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48 - 0x4F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 - 0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 - 0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68 - 0x6F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80 - 0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88 - 0x8F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90 - 0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98 - 0x9F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0 - 0xA7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8 - 0xAF */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0 - 0xB7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8 - 0xBF */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0 - 0xC7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8 - 0xCF */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0 - 0xD7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8 - 0xDF */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0 - 0xE7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8 - 0xEF */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0 - 0xF7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, /* 0xF8 - 0xFF */
+};
+
+struct max98090_priv {
+};
+
+static const unsigned int max98090_hp_tlv[] = {
+ TLV_DB_RANGE_HEAD(5),
+ 0x0, 0x6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+ 0x7, 0xE, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+ 0xF, 0x15, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+ 0x16, 0x1B, TLV_DB_SCALE_ITEM(-400, 100, 0),
+ 0x1C, 0x1F, TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static struct snd_kcontrol_new max98090_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("Headphone Volume", M98090_0x2C_L_HP_VOL,
+ M98090_0x2D_R_HP_VOL, 0, 31, 0, max98090_hp_tlv),
+};
+
+/* Left HeadPhone Mixer Switch */
+static struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACR Switch", M98090_0x29_L_HP_MIX, 1, 1, 0),
+ SOC_DAPM_SINGLE("DACL Switch", M98090_0x29_L_HP_MIX, 0, 1, 0),
+};
+
+/* Right HeadPhone Mixer Switch */
+static struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACR Switch", M98090_0x2A_R_HP_MIX, 1, 1, 0),
+ SOC_DAPM_SINGLE("DACL Switch", M98090_0x2A_R_HP_MIX, 0, 1, 0),
+};
+
+static struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
+ /* Output */
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+
+ /* PGA */
+ SND_SOC_DAPM_PGA("HPL Out", M98090_0x3F_OUT_ENABLE, 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HPR Out", M98090_0x3F_OUT_ENABLE, 6, 0, NULL, 0),
+
+ /* Mixer */
+ SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+ max98090_left_hp_mixer_controls,
+ ARRAY_SIZE(max98090_left_hp_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+ max98090_right_hp_mixer_controls,
+ ARRAY_SIZE(max98090_right_hp_mixer_controls)),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC("DACL", "Hifi Playback", M98090_0x3F_OUT_ENABLE, 0, 0),
+ SND_SOC_DAPM_DAC("DACR", "Hifi Playback", M98090_0x3F_OUT_ENABLE, 1, 0),
+};
+
+static struct snd_soc_dapm_route max98090_audio_map[] = {
+ /* Output */
+ {"HPL", NULL, "HPL Out"},
+ {"HPR", NULL, "HPR Out"},
+
+ /* PGA */
+ {"HPL Out", NULL, "HPL Mixer"},
+ {"HPR Out", NULL, "HPR Mixer"},
+
+ /* Mixer*/
+ {"HPL Mixer", "DACR Switch", "DACR"},
+ {"HPL Mixer", "DACL Switch", "DACL"},
+
+ {"HPR Mixer", "DACR Switch", "DACR"},
+ {"HPR Mixer", "DACL Switch", "DACL"},
+};
+
+static int max98090_volatile(struct snd_soc_codec *codec, unsigned int reg)
+{
+ if ((reg == M98090_0x01_INT_STS) ||
+ (reg == M98090_0x02_JACK_STS) ||
+ (reg > M98090_REG_MAX_CACHED))
+ return 1;
+
+ return 0;
+}
+
+static int max98090_dai_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;
+
+ switch (params_rate(params)) {
+ case 96000:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 5));
+ break;
+ case 32000:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 4));
+ break;
+ case 48000:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 3));
+ break;
+ case 44100:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 2));
+ break;
+ case 16000:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 1));
+ break;
+ case 8000:
+ snd_soc_write(codec, M98090_0x05_SAMPLE_RATE, (1 << 0));
+ break;
+ default:
+ dev_err(codec->dev, "unsupported rate\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int shdn;
+
+ shdn = snd_soc_read(codec, M98090_0x45_DEV_SHUTDOWN);
+ if (shdn & M98090_SHDNRUN)
+ snd_soc_write(codec, M98090_0x45_DEV_SHUTDOWN, 0);
+
+ switch (freq) {
+ case 26000000:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 7));
+ break;
+ case 19200000:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 6));
+ break;
+ case 13000000:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 5));
+ break;
+ case 12288000:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 4));
+ break;
+ case 12000000:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 3));
+ break;
+ case 11289600:
+ snd_soc_write(codec, M98090_0x04_SYS_CLK, (1 << 2));
+ break;
+ default:
+ dev_err(codec->dev, "Invalid master clock frequency\n");
+ return -EINVAL;
+ }
+
+ if (shdn & M98090_SHDNRUN)
+ snd_soc_write(codec, M98090_0x45_DEV_SHUTDOWN, M98090_SHDNRUN);
+
+ dev_dbg(dai->dev, "sysclk is %uHz\n", freq);
+
+ return 0;
+}
+
+static int max98090_dai_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int is_master;
+ u8 val;
+
+ /* master/slave mode */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ is_master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ is_master = 0;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported clock\n");
+ return -EINVAL;
+ }
+
+ /* format */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val = (is_master) ? M98090_I2S_M : M98090_I2S_S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val = (is_master) ? M98090_RJ_M : M98090_RJ_S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ val = (is_master) ? M98090_LJ_M : M98090_LJ_S;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, M98090_0x06_DAI_IF, val);
+
+ return 0;
+}
+
+#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98090_dai_ops = {
+ .set_sysclk = max98090_dai_set_sysclk,
+ .set_fmt = max98090_dai_set_fmt,
+ .hw_params = max98090_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98090_dai = {
+ .name = "max98090-Hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98090_RATES,
+ .formats = MAX98090_FORMATS,
+ },
+ .ops = &max98090_dai_ops,
+};
+
+static int max98090_probe(struct snd_soc_codec *codec)
+{
+ struct device *dev = codec->dev;
+ int ret;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_read(codec, M98090_0xFF_REV_ID);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read device revision: %d\n", ret);
+ return ret;
+ }
+ dev_info(dev, "revision 0x%02x\n", ret);
+
+ /* Device active */
+ snd_soc_write(codec, M98090_0x45_DEV_SHUTDOWN, M98090_SHDNRUN);
+
+ snd_soc_add_codec_controls(codec, max98090_snd_controls,
+ ARRAY_SIZE(max98090_snd_controls));
+
+ return 0;
+}
+
+static int max98090_remove(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98090 = {
+ .probe = max98090_probe,
+ .remove = max98090_remove,
+ .reg_cache_default = max98090_reg,
+ .reg_cache_size = ARRAY_SIZE(max98090_reg),
+ .reg_word_size = sizeof(u8),
+ .volatile_register = max98090_volatile,
+ .dapm_widgets = max98090_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets),
+ .dapm_routes = max98090_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98090_audio_map),
+};
+
+static int max98090_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max98090_priv *priv;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(struct max98090_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, priv);
+
+ return snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max98090,
+ &max98090_dai, 1);
+}
+
+static int max98090_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id max98090_i2c_id[] = {
+ { "max98090", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
+
+static struct i2c_driver max98090_i2c_driver = {
+ .driver = {
+ .name = "max98090",
+ .owner = THIS_MODULE,
+ },
+ .probe = max98090_i2c_probe,
+ .remove = max98090_i2c_remove,
+ .id_table = max98090_i2c_id,
+};
+module_i2c_driver(max98090_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98090 driver");
+MODULE_AUTHOR("Peter Hsiang, Kuninori Morimoto");
+MODULE_LICENSE("GPL");
--
1.7.9.5
More information about the Alsa-devel
mailing list