All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ASoC: add SSM2604 codec driver
@ 2010-08-07  5:54 Mike Frysinger
  2010-08-07 12:44 ` Mark Brown
  2011-03-26  9:07 ` [PATCH v2] " Mike Frysinger
  0 siblings, 2 replies; 7+ messages in thread
From: Mike Frysinger @ 2010-08-07  5:54 UTC (permalink / raw)
  To: alsa-devel, Mark Brown; +Cc: uclinux-dist-devel, Cliff Cai

From: Cliff Cai <cliff.cai@analog.com>

Signed-off-by: Cliff Cai <cliff.cai@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
---
 sound/soc/codecs/Kconfig   |    4 +
 sound/soc/codecs/Makefile  |    2 +
 sound/soc/codecs/ssm2604.c |  643 ++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/ssm2604.h |   92 +++++++
 4 files changed, 741 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/ssm2604.c
 create mode 100644 sound/soc/codecs/ssm2604.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 5da30eb..5db82d2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -28,6 +28,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_PCM3008
 	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_SSM2604 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -150,6 +151,9 @@ config SND_SOC_SPDIF
 config SND_SOC_SSM2602
 	tristate
 
+config SND_SOC_SSM2604
+	tristate
+
 config SND_SOC_STAC9766
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429ea..7593eeb 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -16,6 +16,7 @@ snd-soc-l3-objs := l3.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-ssm2604-objs := ssm2604.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
@@ -81,6 +82,7 @@ obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_SSM2604)	+= snd-soc-ssm2604.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
diff --git a/sound/soc/codecs/ssm2604.c b/sound/soc/codecs/ssm2604.c
new file mode 100644
index 0000000..7522586
--- /dev/null
+++ b/sound/soc/codecs/ssm2604.c
@@ -0,0 +1,643 @@
+/*
+ * Driver for ssm2604 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#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/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ssm2604.h"
+
+#define SSM2604_VERSION "0.1"
+
+struct snd_soc_codec_device soc_codec_dev_ssm2604;
+static struct snd_soc_codec *ssm2604_codec;
+/* codec private data */
+struct ssm2604_priv {
+	unsigned int sysclk;
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+	struct snd_soc_codec codec;
+};
+
+/*
+ * ssm2604 register cache
+ * We can't read the ssm2604 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 ssm2604_reg[SSM2604_CACHEREGNUM] = {
+	0x0017, 0x0017, 0x0000, 0x0000,
+	0x0000, 0x000a,	0x0000, 0x0000
+};
+
+#define ssm2604_reset(c)	snd_soc_write(c, SSM2604_RESET, 0)
+
+static const char *ssm2604_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum ssm2604_enum[] = {
+	SOC_ENUM_SINGLE(SSM2604_APDIGI, 1, 4, ssm2604_deemph),
+};
+
+static const struct snd_kcontrol_new ssm2604_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", SSM2604_LINVOL, SSM2604_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", SSM2604_LINVOL, SSM2604_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", SSM2604_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", SSM2604_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Capture Source", ssm2604_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", ssm2604_enum[1]),
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new ssm2604_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", SSM2604_APANA, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2604_PWR, 4, 1,
+	&ssm2604_output_mixer_controls[0],
+	ARRAY_SIZE(ssm2604_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2604_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2604_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2604_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conn[] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	/* outputs */
+	{"ROUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	/* input mux */
+	{"Input Mux", "Line", "Line Input"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+};
+
+static int ssm2604_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, ssm2604_dapm_widgets,
+				  ARRAY_SIZE(ssm2604_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
+
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return i;
+}
+
+static int ssm2604_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	u16 srate;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = codec->control_data;
+	u16 iface = snd_soc_read(codec, SSM2604_IFACE) & 0xfff3;
+	int i = get_coeff(ssm2604->sysclk, params_rate(params));
+
+	if (substream == ssm2604->slave_substream) {
+		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+		return 0;
+	}
+
+	/*no match is found*/
+	if (i == ARRAY_SIZE(coeff_div))
+		return -EINVAL;
+
+	srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	snd_soc_write(codec, SSM2604_ACTIVE, 0);
+	snd_soc_write(codec, SSM2604_SRATE, srate);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+	snd_soc_write(codec, SSM2604_IFACE, iface);
+	snd_soc_write(codec, SSM2604_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+	return 0;
+}
+
+static int ssm2604_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = codec->control_data;
+	struct snd_pcm_runtime *master_runtime;
+
+	/* The DAI has shared clocks so if we already have a playback or
+	 * capture going then constrain this substream to match it.
+	 * TODO: the ssm2604 allows pairs of non-matching PB/REC rates
+	 */
+	if (ssm2604->master_substream) {
+		master_runtime = ssm2604->master_substream->runtime;
+		dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+			master_runtime->sample_bits,
+			master_runtime->rate);
+
+		if (master_runtime->rate != 0)
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+						     SNDRV_PCM_HW_PARAM_RATE,
+						     master_runtime->rate,
+						     master_runtime->rate);
+
+		if (master_runtime->sample_bits != 0)
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+						     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+						     master_runtime->sample_bits,
+						     master_runtime->sample_bits);
+
+		ssm2604->slave_substream = substream;
+	} else
+		ssm2604->master_substream = substream;
+
+	return 0;
+}
+
+static int ssm2604_pcm_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	/* set active */
+	snd_soc_write(codec, SSM2604_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+
+	return 0;
+}
+
+static void ssm2604_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+
+	/* deactivate */
+	if (!codec->active)
+		snd_soc_write(codec, SSM2604_ACTIVE, 0);
+
+	if (ssm2604->master_substream == substream)
+		ssm2604->master_substream = ssm2604->slave_substream;
+
+	ssm2604->slave_substream = NULL;
+}
+
+static int ssm2604_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = snd_soc_read(codec, SSM2604_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+	if (mute)
+		snd_soc_write(codec, SSM2604_APDIGI,
+				mute_reg | APDIGI_ENABLE_DAC_MUTE);
+	else
+		snd_soc_write(codec, SSM2604_APDIGI, mute_reg);
+	return 0;
+}
+
+static int ssm2604_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 ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		ssm2604->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ssm2604_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0013;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0003;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	snd_soc_write(codec, SSM2604_IFACE, iface);
+	return 0;
+}
+
+static int ssm2604_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg = snd_soc_read(codec, SSM2604_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		snd_soc_write(codec, SSM2604_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		snd_soc_write(codec, SSM2604_PWR, reg | PWR_CLK_OUT_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_write(codec, SSM2604_ACTIVE, 0);
+		snd_soc_write(codec, SSM2604_PWR, 0xffff);
+		break;
+
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define SSM2604_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define SSM2604_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops ssm2604_dai_ops = {
+	.startup	= ssm2604_startup,
+	.prepare	= ssm2604_pcm_prepare,
+	.hw_params	= ssm2604_hw_params,
+	.shutdown	= ssm2604_shutdown,
+	.digital_mute	= ssm2604_mute,
+	.set_sysclk	= ssm2604_set_dai_sysclk,
+	.set_fmt	= ssm2604_set_dai_fmt,
+};
+
+struct snd_soc_dai ssm2604_dai = {
+	.name = "SSM2604",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2604_RATES,
+		.formats = SSM2604_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2604_RATES,
+		.formats = SSM2604_FORMATS,},
+	.ops = &ssm2604_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ssm2604_dai);
+
+static int ssm2604_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	ssm2604_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int ssm2604_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+	int i;
+	u8 data[2];
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(ssm2604_reg); i++) {
+		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+		data[1] = cache[i] & 0x00ff;
+		codec->hw_write(codec->control_data, data, 2);
+	}
+	ssm2604_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	ssm2604_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+static int ssm2604_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int reg, ret = 0;
+
+	socdev->card->codec = ssm2604_codec;
+	codec = ssm2604_codec;
+
+	ssm2604_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "ssm2604: failed to create pcms\n");
+		goto pcm_err;
+	}
+	/*power on device*/
+	snd_soc_write(codec, SSM2604_ACTIVE, 0);
+	/* set the update bits */
+	reg = snd_soc_read(codec, SSM2604_LINVOL);
+	snd_soc_write(codec, SSM2604_LINVOL, reg | LINVOL_LRIN_BOTH);
+	reg = snd_soc_read(codec, SSM2604_RINVOL);
+	snd_soc_write(codec, SSM2604_RINVOL, reg | RINVOL_RLIN_BOTH);
+
+	snd_soc_write(codec, SSM2604_APANA, APANA_SELECT_DAC);
+	snd_soc_write(codec, SSM2604_PWR, 0);
+
+	snd_soc_add_controls(codec, ssm2604_snd_controls,
+				ARRAY_SIZE(ssm2604_snd_controls));
+	ssm2604_add_widgets(codec);
+
+	return ret;
+
+pcm_err:
+	return ret;
+}
+
+/* remove everything here */
+static int ssm2604_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ssm2604 = {
+	.probe =	ssm2604_probe,
+	.remove =	ssm2604_remove,
+	.suspend =	ssm2604_suspend,
+	.resume =	ssm2604_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2604);
+
+static int ssm2604_register(struct ssm2604_priv *ssm2604, enum snd_soc_control_type control)
+{
+	struct snd_soc_codec *codec = &ssm2604->codec;
+	int ret = 0;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	codec->name = "SSM2604";
+	codec->owner = THIS_MODULE;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = ssm2604_set_bias_level;
+	codec->dai = &ssm2604_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = sizeof(ssm2604_reg);
+	codec->reg_cache = kmemdup(ssm2604_reg, sizeof(ssm2604_reg),
+					GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&ssm2604_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void ssm2604_unregister(struct ssm2604_priv *ssm2604)
+{
+	struct snd_soc_codec *codec = &ssm2604->codec;
+
+	ssm2604_set_bias_level(&ssm2604->codec, SND_SOC_BIAS_OFF);
+	kfree(codec->reg_cache);
+	snd_soc_unregister_dai(&ssm2604_dai);
+	snd_soc_unregister_codec(&ssm2604->codec);
+	kfree(ssm2604);
+	ssm2604_codec = NULL;
+}
+
+static int ssm2604_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct ssm2604_priv *ssm2604;
+	struct snd_soc_codec *codec;
+
+	ssm2604 = kzalloc(sizeof(struct ssm2604_priv), GFP_KERNEL);
+	if (ssm2604 == NULL)
+		return -ENOMEM;
+	codec = &ssm2604->codec;
+	snd_soc_codec_set_drvdata(codec, ssm2604);
+
+	i2c_set_clientdata(i2c, ssm2604);
+	codec->control_data = i2c;
+
+	codec->dev = &i2c->dev;
+	ssm2604_codec = codec;
+
+	return ssm2604_register(ssm2604, SND_SOC_I2C);
+}
+
+static __devexit int ssm2604_i2c_remove(struct i2c_client *client)
+{
+	struct ssm2604_priv *ssm2604 = i2c_get_clientdata(client);
+	ssm2604_unregister(ssm2604);
+	return 0;
+}
+
+static const struct i2c_device_id ssm2604_i2c_id[] = {
+	{ "ssm2604", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2604_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver ssm2604_i2c_driver = {
+	.driver = {
+		.name = "ssm2604",
+		.owner = THIS_MODULE,
+	},
+	.probe    = ssm2604_i2c_probe,
+	.remove   = __devexit_p(ssm2604_i2c_remove),
+	.id_table = ssm2604_i2c_id,
+};
+
+static int __init ssm2604_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&ssm2604_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register ssm2604 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(ssm2604_modinit);
+
+static void __exit ssm2604_exit(void)
+{
+	i2c_del_driver(&ssm2604_i2c_driver);
+}
+module_exit(ssm2604_exit);
+
+MODULE_DESCRIPTION("ASoC SSM2604 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2604.h b/sound/soc/codecs/ssm2604.h
new file mode 100644
index 0000000..3b24a08
--- /dev/null
+++ b/sound/soc/codecs/ssm2604.h
@@ -0,0 +1,92 @@
+/*
+ * Header for ssm2604 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _SSM2604_H
+#define _SSM2604_H
+
+/* SSM2604 Codec Register definitions */
+
+#define SSM2604_LINVOL   0x00
+#define SSM2604_RINVOL   0x01
+#define SSM2604_APANA    0x04
+#define SSM2604_APDIGI   0x05
+#define SSM2604_PWR      0x06
+#define SSM2604_IFACE    0x07
+#define SSM2604_SRATE    0x08
+#define SSM2604_ACTIVE   0x09
+#define SSM2604_RESET	 0x0f
+
+/* SSM2604 Codec Register Field definitions
+ * (Mask value to extract the corresponding Register field)
+ */
+
+/* Left ADC Volume Control (SSM2604_REG_LEFT_ADC_VOL) */
+#define LINVOL_LIN_VOL          0x01F	/* Left Channel PGA Volume control                    */
+#define LINVOL_LIN_ENABLE_MUTE  0x080	/* Left Channel Input Mute                            */
+#define LINVOL_LRIN_BOTH        0x100	/* Left Channel Line Input Volume update              */
+
+/* Right ADC Volume Control (SSM2604_REG_RIGHT_ADC_VOL) */
+#define RINVOL_RIN_VOL          0x01F	/* Right Channel PGA Volume control                   */
+#define RINVOL_RIN_ENABLE_MUTE  0x080	/* Right Channel Input Mute                           */
+#define RINVOL_RLIN_BOTH        0x100	/* Right Channel Line Input Volume update             */
+
+
+/* Analogue Audio Path Control (SSM2604_REG_ANALOGUE_PATH) */
+#define APANA_ENABLE_BYPASS     0x008	/* Line input bypass to line output                   */
+#define APANA_SELECT_DAC        0x010	/* Select DAC (1=Select DAC, 0=Don't Select DAC)      */
+
+/* Digital Audio Path Control (SSM2604_REG_DIGITAL_PATH) */
+#define APDIGI_ENABLE_ADC_HPF   0x001	/* Enable/Disable ADC Highpass Filter                 */
+#define APDIGI_DE_EMPHASIS      0x006	/* De-Emphasis Control                                */
+#define APDIGI_ENABLE_DAC_MUTE  0x008	/* DAC Mute Control                                   */
+#define APDIGI_STORE_OFFSET     0x010	/* Store/Clear DC offset when HPF is disabled         */
+
+/* Power Down Control (SSM2604_REG_POWER)
+ * (1=Enable PowerDown, 0=Disable PowerDown)
+ */
+#define PWR_LINE_IN_PDN         0x001	/* Line Input Power Down                              */
+#define PWR_ADC_PDN             0x004	/* ADC Power Down                                     */
+#define PWR_DAC_PDN             0x008	/* DAC Power Down                                     */
+#define PWR_OSC_PDN             0x020	/* Oscillator Power Down                              */
+#define PWR_CLK_OUT_PDN         0x040	/* CLKOUT Power Down                                  */
+#define PWR_POWER_OFF           0x080	/* POWEROFF Mode                                      */
+
+/* Digital Audio Interface Format (SSM2604_REG_DIGITAL_IFACE) */
+#define IFACE_IFACE_FORMAT      0x003	/* Digital Audio input format control                 */
+#define IFACE_AUDIO_DATA_LEN    0x00C	/* Audio Data word length control                     */
+#define IFACE_DAC_LR_POLARITY   0x010	/* Polarity Control for clocks in RJ,LJ and I2S modes */
+#define IFACE_DAC_LR_SWAP       0x020	/* Swap DAC data control                              */
+#define IFACE_ENABLE_MASTER     0x040	/* Enable/Disable Master Mode                         */
+#define IFACE_BCLK_INVERT       0x080	/* Bit Clock Inversion control                        */
+
+/* Sampling Control (SSM2604_REG_SAMPLING_CTRL) */
+#define SRATE_ENABLE_USB_MODE   0x001	/* Enable/Disable USB Mode                            */
+#define SRATE_BOS_RATE          0x002	/* Base Over-Sampling rate                            */
+#define SRATE_SAMPLE_RATE       0x03C	/* Clock setting condition (Sampling rate control)    */
+#define SRATE_CORECLK_DIV2      0x040	/* Core Clock divider select                          */
+#define SRATE_CLKOUT_DIV2       0x080	/* Clock Out divider select                           */
+
+/* Active Control (SSM2604_REG_ACTIVE_CTRL) */
+#define ACTIVE_ACTIVATE_CODEC   0x001	/* Activate Codec Digital Audio Interface             */
+
+/*********************************************************************/
+
+#define SSM2604_CACHEREGNUM	9
+
+#define SSM2604_SYSCLK	0
+#define SSM2604_DAI		0
+
+struct ssm2604_setup_data {
+	int i2c_bus;
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai ssm2604_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ssm2604;
+
+#endif
-- 
1.7.2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] ASoC: add SSM2604 codec driver
  2010-08-07  5:54 [PATCH] ASoC: add SSM2604 codec driver Mike Frysinger
@ 2010-08-07 12:44 ` Mark Brown
       [not found]   ` <20100807124416.GB11817-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
  2011-03-26  9:07 ` [PATCH v2] " Mike Frysinger
  1 sibling, 1 reply; 7+ messages in thread
From: Mark Brown @ 2010-08-07 12:44 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: uclinux-dist-devel, alsa-devel, Cliff Cai

On Sat, Aug 07, 2010 at 01:54:07AM -0400, Mike Frysinger wrote:
> From: Cliff Cai <cliff.cai@analog.com>
> 
> Signed-off-by: Cliff Cai <cliff.cai@analog.com>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>

This needs to be updated to the multi-component branch.  There's a few
other issues as well.

> +#define SSM2604_VERSION "0.1"

Drop this, just track the version through git and kernel releases.

> +static const struct soc_enum ssm2604_enum[] = {
> +	SOC_ENUM_SINGLE(SSM2604_APDIGI, 1, 4, ssm2604_deemph),
> +};

Use individual variables for enums rather than stuffing them all in an
array.  The arrays are just hard to read and error prone...

> +SOC_ENUM("Capture Source", ssm2604_enum[0]),
> +
> +SOC_ENUM("Playback De-emphasis", ssm2604_enum[1]),

...are you sure this code runs correctly?  I see only one element in the
array.  It's worth checking this in your other drivers as well.

> +	/* The DAI has shared clocks so if we already have a playback or
> +	 * capture going then constrain this substream to match it.
> +	 * TODO: the ssm2604 allows pairs of non-matching PB/REC rates
> +	 */
> +	if (ssm2604->master_substream) {

Set the symmetric_rates flag on the DAI rather than open coding this.

> +	/* deactivate */
> +	if (!codec->active)
> +		snd_soc_write(codec, SSM2604_ACTIVE, 0);

This probably wants to be managed by DAPM (possibly a supply widget for
the DAC and ADC).

> +#define SSM2604_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
> +		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
> +		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)

SNDRV_PCM_RATE_8000_96000

> +	snd_soc_write(codec, SSM2604_APANA, APANA_SELECT_DAC);

This could use a little explanation?

> +struct ssm2604_setup_data {
> +	int i2c_bus;
> +	unsigned short i2c_address;
> +};

This is definitely not needed, even with the current code.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] ASoC: add SSM2604 codec driver
       [not found]   ` <20100807124416.GB11817-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
@ 2010-08-07 15:21     ` Mike Frysinger
  0 siblings, 0 replies; 7+ messages in thread
From: Mike Frysinger @ 2010-08-07 15:21 UTC (permalink / raw)
  To: Mark Brown
  Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, Cliff Cai

On Sat, Aug 7, 2010 at 08:44, Mark Brown wrote:
> This needs to be updated to the multi-component branch.  There's a few
> other issues as well.

ive logged a tracker item for this stuff
http://blackfin.uclinux.org/gf/tracker/6158
-mike
_______________________________________________
Uclinux-dist-devel mailing list
Uclinux-dist-devel@blackfin.uclinux.org
https://blackfin.uclinux.org/mailman/listinfo/uclinux-dist-devel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2] ASoC: add SSM2604 codec driver
  2010-08-07  5:54 [PATCH] ASoC: add SSM2604 codec driver Mike Frysinger
  2010-08-07 12:44 ` Mark Brown
@ 2011-03-26  9:07 ` Mike Frysinger
  2011-03-26 12:12   ` Mark Brown
  1 sibling, 1 reply; 7+ messages in thread
From: Mike Frysinger @ 2011-03-26  9:07 UTC (permalink / raw)
  To: alsa-devel, Liam Girdwood, Mark Brown; +Cc: Cliff Cai, device-drivers-devel

From: Cliff Cai <cliff.cai@analog.com>

Signed-off-by: Cliff Cai <cliff.cai@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
---
v2
	- update to multi-component
	- touch up style a bit
	- drop dead structs
	- drop rate and sample bits constraints

 sound/soc/codecs/Kconfig   |    4 +
 sound/soc/codecs/Makefile  |    2 +
 sound/soc/codecs/ssm2604.c |  524 ++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/ssm2604.h |   84 +++++++
 4 files changed, 614 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/ssm2604.c
 create mode 100644 sound/soc/codecs/ssm2604.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 74a4629..7de8d8d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_PCM3008
 	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_SSM2604 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -186,6 +187,9 @@ config SND_SOC_SPDIF
 config SND_SOC_SSM2602
 	tristate
 
+config SND_SOC_SSM2604
+	tristate
+
 config SND_SOC_STAC9766
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index cc134ea..8b32b1a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -22,6 +22,7 @@ snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-ssm2604-objs := ssm2604.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
@@ -103,6 +104,7 @@ obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_SSM2604)	+= snd-soc-ssm2604.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
diff --git a/sound/soc/codecs/ssm2604.c b/sound/soc/codecs/ssm2604.c
new file mode 100644
index 0000000..a01c055
--- /dev/null
+++ b/sound/soc/codecs/ssm2604.c
@@ -0,0 +1,524 @@
+/*
+ * Driver for ssm2604 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#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/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ssm2604.h"
+
+/* codec private data */
+struct ssm2604_priv {
+	unsigned int sysclk;
+	u16 pwr_state;
+	enum snd_soc_control_type control_type;
+};
+
+/*
+ * ssm2604 register cache
+ * We can't read the ssm2604 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 ssm2604_reg[SSM2604_CACHEREGNUM] = {
+	0x0017, 0x0017, 0x0000, 0x0000,
+	0x0000, 0x000a,	0x0000, 0x0000
+};
+
+#define ssm2604_reset(c)	snd_soc_write(c, SSM2604_RESET, 0)
+
+static const char *ssm2604_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum ssm2604_enum[] = {
+	SOC_ENUM_SINGLE(SSM2604_APDIGI, 1, 4, ssm2604_deemph),
+};
+
+static const struct snd_kcontrol_new ssm2604_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", SSM2604_LINVOL, SSM2604_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", SSM2604_LINVOL, SSM2604_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", SSM2604_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", SSM2604_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Capture Source", ssm2604_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", ssm2604_enum[1]),
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new ssm2604_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", SSM2604_APANA, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2604_PWR, 4, 1,
+	&ssm2604_output_mixer_controls[0],
+	ARRAY_SIZE(ssm2604_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2604_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2604_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2604_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route audio_conn[] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	/* outputs */
+	{"ROUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	/* input mux */
+	{"Input Mux", "Line", "Line Input"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+};
+
+static int ssm2604_add_widgets(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+				  ARRAY_SIZE(ssm2604_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
+
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return i;
+}
+
+static int ssm2604_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	u16 srate;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	u16 iface = snd_soc_read(codec, SSM2604_IFACE) & 0xfff3;
+	int i = get_coeff(ssm2604->sysclk, params_rate(params));
+
+	/*no match is found*/
+	if (i == ARRAY_SIZE(coeff_div))
+		return -EINVAL;
+
+	srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	snd_soc_write(codec, SSM2604_ACTIVE, 0);
+	snd_soc_write(codec, SSM2604_SRATE, srate);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x0004;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x0008;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x000c;
+		break;
+	}
+	snd_soc_write(codec, SSM2604_IFACE, iface);
+	snd_soc_write(codec, SSM2604_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+	return 0;
+}
+
+static int ssm2604_pcm_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	/* set active */
+	snd_soc_write(codec, SSM2604_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+
+	return 0;
+}
+
+static void ssm2604_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	/* deactivate */
+	if (!codec->active)
+		snd_soc_write(codec, SSM2604_ACTIVE, 0);
+}
+
+static int ssm2604_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = snd_soc_read(codec, SSM2604_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+	if (mute)
+		snd_soc_write(codec, SSM2604_APDIGI,
+				mute_reg | APDIGI_ENABLE_DAC_MUTE);
+	else
+		snd_soc_write(codec, SSM2604_APDIGI, mute_reg);
+	return 0;
+}
+
+static int ssm2604_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 ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		ssm2604->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ssm2604_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0013;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0003;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	snd_soc_write(codec, SSM2604_IFACE, iface);
+	return 0;
+}
+
+static int ssm2604_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg = snd_soc_read(codec, SSM2604_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		snd_soc_write(codec, SSM2604_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		snd_soc_write(codec, SSM2604_PWR, reg | PWR_CLK_OUT_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_write(codec, SSM2604_ACTIVE, 0);
+		snd_soc_write(codec, SSM2604_PWR, 0xffff);
+		break;
+
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define SSM2604_RATES SNDRV_PCM_RATE_8000_96000
+
+#define SSM2604_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops ssm2604_dai_ops = {
+	.prepare	= ssm2604_pcm_prepare,
+	.hw_params	= ssm2604_hw_params,
+	.shutdown	= ssm2604_shutdown,
+	.digital_mute	= ssm2604_mute,
+	.set_sysclk	= ssm2604_set_dai_sysclk,
+	.set_fmt	= ssm2604_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ssm2604_dai = {
+	.name = "ssm2604-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2604_RATES,
+		.formats = SSM2604_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2604_RATES,
+		.formats = SSM2604_FORMATS,},
+	.ops = &ssm2604_dai_ops,
+};
+
+static int ssm2604_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+
+	ssm2604->pwr_state = snd_soc_read(codec, SSM2604_PWR);
+	ssm2604_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int ssm2604_resume(struct snd_soc_codec *codec)
+{
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	int i;
+	u16 *cache = codec->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (i = 0; i < ARRAY_SIZE(ssm2604_reg); i++)
+		snd_soc_write(codec, i, cache[i]);
+
+	ssm2604_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_write(codec, SSM2604_PWR, ssm2604->pwr_state);
+
+	return 0;
+}
+
+static int ssm2604_probe(struct snd_soc_codec *codec)
+{
+	struct ssm2604_priv *ssm2604 = snd_soc_codec_get_drvdata(codec);
+	int reg, ret = 0;
+
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2604->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	ret = ssm2604_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	/*power on device*/
+	snd_soc_write(codec, SSM2604_ACTIVE, 0);
+	/* set the update bits */
+	reg = snd_soc_read(codec, SSM2604_LINVOL);
+	snd_soc_write(codec, SSM2604_LINVOL, reg | LINVOL_LRIN_BOTH);
+	reg = snd_soc_read(codec, SSM2604_RINVOL);
+	snd_soc_write(codec, SSM2604_RINVOL, reg | RINVOL_RLIN_BOTH);
+
+	snd_soc_write(codec, SSM2604_APANA, APANA_SELECT_DAC);
+	snd_soc_write(codec, SSM2604_PWR, 0);
+
+	snd_soc_add_controls(codec, ssm2604_snd_controls,
+				ARRAY_SIZE(ssm2604_snd_controls));
+	ssm2604_add_widgets(codec);
+
+	return 0;
+}
+
+/* remove everything here */
+static int ssm2604_remove(struct snd_soc_codec *codec)
+{
+	ssm2604_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ssm2604 = {
+	.probe =	ssm2604_probe,
+	.remove =	ssm2604_remove,
+	.suspend =	ssm2604_suspend,
+	.resume =	ssm2604_resume,
+	.set_bias_level = ssm2604_set_bias_level,
+	.reg_cache_size = sizeof(ssm2604_reg),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = ssm2604_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static int ssm2604_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct ssm2604_priv *ssm2604;
+	int ret;
+
+	ssm2604 = kzalloc(sizeof(struct ssm2604_priv), GFP_KERNEL);
+	if (ssm2604 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ssm2604);
+	ssm2604->control_type = SND_SOC_I2C;
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_ssm2604, &ssm2604_dai, 1);
+	if (ret < 0)
+		kfree(ssm2604);
+	return ret;
+}
+
+static int ssm2604_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id ssm2604_i2c_id[] = {
+	{ "ssm2604", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2604_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver ssm2604_i2c_driver = {
+	.driver = {
+		.name = "ssm2604-codec",
+		.owner = THIS_MODULE,
+	},
+	.probe    = ssm2604_i2c_probe,
+	.remove   = ssm2604_i2c_remove,
+	.id_table = ssm2604_i2c_id,
+};
+#endif
+
+static int __init ssm2604_modinit(void)
+{
+	int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&ssm2604_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register ssm2604 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(ssm2604_modinit);
+
+static void __exit ssm2604_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&ssm2604_i2c_driver);
+#endif
+}
+module_exit(ssm2604_exit);
+
+MODULE_DESCRIPTION("ASoC SSM2604 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2604.h b/sound/soc/codecs/ssm2604.h
new file mode 100644
index 0000000..410c0dc
--- /dev/null
+++ b/sound/soc/codecs/ssm2604.h
@@ -0,0 +1,84 @@
+/*
+ * Header for ssm2604 sound codec
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _SSM2604_H
+#define _SSM2604_H
+
+/* SSM2604 Codec Register definitions */
+
+#define SSM2604_LINVOL   0x00
+#define SSM2604_RINVOL   0x01
+#define SSM2604_APANA    0x04
+#define SSM2604_APDIGI   0x05
+#define SSM2604_PWR      0x06
+#define SSM2604_IFACE    0x07
+#define SSM2604_SRATE    0x08
+#define SSM2604_ACTIVE   0x09
+#define SSM2604_RESET	 0x0f
+
+/* SSM2604 Codec Register Field definitions
+ * (Mask value to extract the corresponding Register field)
+ */
+
+/* Left ADC Volume Control (SSM2604_REG_LEFT_ADC_VOL) */
+#define LINVOL_LIN_VOL          0x01F	/* Left Channel PGA Volume control                    */
+#define LINVOL_LIN_ENABLE_MUTE  0x080	/* Left Channel Input Mute                            */
+#define LINVOL_LRIN_BOTH        0x100	/* Left Channel Line Input Volume update              */
+
+/* Right ADC Volume Control (SSM2604_REG_RIGHT_ADC_VOL) */
+#define RINVOL_RIN_VOL          0x01F	/* Right Channel PGA Volume control                   */
+#define RINVOL_RIN_ENABLE_MUTE  0x080	/* Right Channel Input Mute                           */
+#define RINVOL_RLIN_BOTH        0x100	/* Right Channel Line Input Volume update             */
+
+
+/* Analogue Audio Path Control (SSM2604_REG_ANALOGUE_PATH) */
+#define APANA_ENABLE_BYPASS     0x008	/* Line input bypass to line output                   */
+#define APANA_SELECT_DAC        0x010	/* Select DAC (1=Select DAC, 0=Don't Select DAC)      */
+
+/* Digital Audio Path Control (SSM2604_REG_DIGITAL_PATH) */
+#define APDIGI_ENABLE_ADC_HPF   0x001	/* Enable/Disable ADC Highpass Filter                 */
+#define APDIGI_DE_EMPHASIS      0x006	/* De-Emphasis Control                                */
+#define APDIGI_ENABLE_DAC_MUTE  0x008	/* DAC Mute Control                                   */
+#define APDIGI_STORE_OFFSET     0x010	/* Store/Clear DC offset when HPF is disabled         */
+
+/* Power Down Control (SSM2604_REG_POWER)
+ * (1=Enable PowerDown, 0=Disable PowerDown)
+ */
+#define PWR_LINE_IN_PDN         0x001	/* Line Input Power Down                              */
+#define PWR_ADC_PDN             0x004	/* ADC Power Down                                     */
+#define PWR_DAC_PDN             0x008	/* DAC Power Down                                     */
+#define PWR_OSC_PDN             0x020	/* Oscillator Power Down                              */
+#define PWR_CLK_OUT_PDN         0x040	/* CLKOUT Power Down                                  */
+#define PWR_POWER_OFF           0x080	/* POWEROFF Mode                                      */
+
+/* Digital Audio Interface Format (SSM2604_REG_DIGITAL_IFACE) */
+#define IFACE_IFACE_FORMAT      0x003	/* Digital Audio input format control                 */
+#define IFACE_AUDIO_DATA_LEN    0x00C	/* Audio Data word length control                     */
+#define IFACE_DAC_LR_POLARITY   0x010	/* Polarity Control for clocks in RJ,LJ and I2S modes */
+#define IFACE_DAC_LR_SWAP       0x020	/* Swap DAC data control                              */
+#define IFACE_ENABLE_MASTER     0x040	/* Enable/Disable Master Mode                         */
+#define IFACE_BCLK_INVERT       0x080	/* Bit Clock Inversion control                        */
+
+/* Sampling Control (SSM2604_REG_SAMPLING_CTRL) */
+#define SRATE_ENABLE_USB_MODE   0x001	/* Enable/Disable USB Mode                            */
+#define SRATE_BOS_RATE          0x002	/* Base Over-Sampling rate                            */
+#define SRATE_SAMPLE_RATE       0x03C	/* Clock setting condition (Sampling rate control)    */
+#define SRATE_CORECLK_DIV2      0x040	/* Core Clock divider select                          */
+#define SRATE_CLKOUT_DIV2       0x080	/* Clock Out divider select                           */
+
+/* Active Control (SSM2604_REG_ACTIVE_CTRL) */
+#define ACTIVE_ACTIVATE_CODEC   0x001	/* Activate Codec Digital Audio Interface             */
+
+/*********************************************************************/
+
+#define SSM2604_CACHEREGNUM	9
+
+#define SSM2604_SYSCLK	0
+#define SSM2604_DAI		0
+
+#endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] ASoC: add SSM2604 codec driver
  2011-03-26  9:07 ` [PATCH v2] " Mike Frysinger
@ 2011-03-26 12:12   ` Mark Brown
  2011-03-27  4:11     ` [Device-drivers-devel] " Mike Frysinger
  0 siblings, 1 reply; 7+ messages in thread
From: Mark Brown @ 2011-03-26 12:12 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: alsa-devel, Cliff Cai, device-drivers-devel, Liam Girdwood

On Sat, Mar 26, 2011 at 05:07:20AM -0400, Mike Frysinger wrote:
> From: Cliff Cai <cliff.cai@analog.com>
> 
> Signed-off-by: Cliff Cai <cliff.cai@analog.com>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>

This mostly looks pretty good, a few issues below many of which are
style things - the namespacing one is the major one that's externally
visible.

> +static int ssm2604_add_widgets(struct snd_soc_codec *codec)
> +{
> +	struct snd_soc_dapm_context *dapm = &codec->dapm;
> +
> +	snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
> +				  ARRAY_SIZE(ssm2604_dapm_widgets));
> +	snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));

This should really use the driver data based initialisation that was
added during the last development cycle.

> +static int ssm2604_pcm_prepare(struct snd_pcm_substream *substream,
> +			       struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_codec *codec = rtd->codec;
> +	/* set active */
> +	snd_soc_write(codec, SSM2604_ACTIVE, ACTIVE_ACTIVATE_CODEC);

This still looks wrong - it won't handle simultaneous playback and
record properly (stopping one will stop the other) for example.  If you
were to make this register bit a DAPM supply for the DAC and ADC then
that'd do the right thing.

If the device can't support simultaneous playback and record there
should be constraints set up telling the application layer about that.

> +	case SND_SOC_BIAS_STANDBY:
> +		/* everything off except vref/vmid, */
> +		snd_soc_write(codec, SSM2604_PWR, reg | PWR_CLK_OUT_PDN);
> +		break;
> +	case SND_SOC_BIAS_OFF:
> +		/* everything off, dac mute, inactive */

These comments have been cut'n'pasted and are I suspect inaccurate.

> +	/* Sync reg_cache with the hardware */
> +	for (i = 0; i < ARRAY_SIZE(ssm2604_reg); i++)
> +		snd_soc_write(codec, i, cache[i]);

There's snd_soc_cache_sync() which will do this for you.  It'll also do
additional stuff like suppress writes of default values which will speed
up resume a bit.

> +	ssm2604_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
> +	snd_soc_write(codec, SSM2604_PWR, ssm2604->pwr_state);

I'm not sure what the pwr_state stuff is doing but shouldn't it be
handled by either DAPM or the bias level functions?

> +/* corgi i2c codec control layer */
> +static struct i2c_driver ssm2604_i2c_driver = {

Another cut'n'paste comment here.

> +	.driver = {
> +		.name = "ssm2604-codec",
> +		.owner = THIS_MODULE,

Drop the -codec from the name, it's not needed.

> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
> +	ret = i2c_add_driver(&ssm2604_i2c_driver);
> +	if (ret != 0) {
> +		printk(KERN_ERR "Failed to register ssm2604 I2C driver: %d\n",
> +		       ret);
> +	}
> +#endif

If the device only supports I2C then there's no need for the ifdefs.

> +/* Left ADC Volume Control (SSM2604_REG_LEFT_ADC_VOL) */
> +#define LINVOL_LIN_VOL          0x01F	/* Left Channel PGA Volume control                    */
> +#define LINVOL_LIN_ENABLE_MUTE  0x080	/* Left Channel Input Mute                            */
> +#define LINVOL_LRIN_BOTH        0x100	/* Left Channel Line Input Volume update              */
> +

Namespace any constants exported in the header - either do that or move
these and the similar constants into the driver code.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Device-drivers-devel] [PATCH v2] ASoC: add SSM2604 codec driver
  2011-03-26 12:12   ` Mark Brown
@ 2011-03-27  4:11     ` Mike Frysinger
  2011-03-27 10:41       ` Mark Brown
  0 siblings, 1 reply; 7+ messages in thread
From: Mike Frysinger @ 2011-03-27  4:11 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Cliff Cai, device-drivers-devel, Liam Girdwood

On Sat, Mar 26, 2011 at 08:12, Mark Brown wrote:
> On Sat, Mar 26, 2011 at 05:07:20AM -0400, Mike Frysinger wrote:
>> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
>> +     ret = i2c_add_driver(&ssm2604_i2c_driver);
>> +     if (ret != 0) {
>> +             printk(KERN_ERR "Failed to register ssm2604 I2C driver: %d\n",
>> +                    ret);
>> +     }
>> +#endif
>
> If the device only supports I2C then there's no need for the ifdefs.

i thought in the past you wanted these things because you wanted to be
able to build codecs regardless of the bus support (for testing iirc?)
-mike
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Device-drivers-devel] [PATCH v2] ASoC: add SSM2604 codec driver
  2011-03-27  4:11     ` [Device-drivers-devel] " Mike Frysinger
@ 2011-03-27 10:41       ` Mark Brown
  0 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2011-03-27 10:41 UTC (permalink / raw)
  To: Mike Frysinger; +Cc: alsa-devel, Cliff Cai, device-drivers-devel, Liam Girdwood

On Sun, Mar 27, 2011 at 12:11:54AM -0400, Mike Frysinger wrote:
> On Sat, Mar 26, 2011 at 08:12, Mark Brown wrote:

> > If the device only supports I2C then there's no need for the ifdefs.

> i thought in the past you wanted these things because you wanted to be
> able to build codecs regardless of the bus support (for testing iirc?)

That has never been the case, SND_SOC_ALL_CODECS has always built things
only if there is a bus for them.  If you support mulitple busses they
should be conditional so that you only need one of them to build but if
there's only one supported this is not relevant.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-03-27 10:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-07  5:54 [PATCH] ASoC: add SSM2604 codec driver Mike Frysinger
2010-08-07 12:44 ` Mark Brown
     [not found]   ` <20100807124416.GB11817-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2010-08-07 15:21     ` Mike Frysinger
2011-03-26  9:07 ` [PATCH v2] " Mike Frysinger
2011-03-26 12:12   ` Mark Brown
2011-03-27  4:11     ` [Device-drivers-devel] " Mike Frysinger
2011-03-27 10:41       ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.