Title: [8608] trunk/sound/soc: [!no_src_qa!]
Revision
8608
Author
adamliyi
Date
2010-04-06 01:12:46 -0400 (Tue, 06 Apr 2010)

Log Message

[!no_src_qa!]

Initial version of adav801/adav803 driver.

Ignore the warning:

WARNING: EXPORT_SYMBOL(foo); should immediately follow its function/variable
#468: FILE: sound/soc/codecs/adav80x.c:229:
+EXPORT_SYMBOL_GPL(adav80x_dai);

WARNING: EXPORT_SYMBOL(foo); should immediately follow its function/variable
#519: FILE: sound/soc/codecs/adav80x.c:280:
+EXPORT_SYMBOL_GPL(soc_codec_dev_adav80x);

Modified Paths

Added Paths

Diff

Modified: trunk/sound/soc/blackfin/Kconfig (8607 => 8608)


--- trunk/sound/soc/blackfin/Kconfig	2010-04-06 04:17:08 UTC (rev 8607)
+++ trunk/sound/soc/blackfin/Kconfig	2010-04-06 05:12:46 UTC (rev 8608)
@@ -68,6 +68,14 @@
 	help
 	  Say Y if you want to add support for ADAU1381 SoC audio.
 
+config SND_BF5XX_SOC_ADAV80X
+	tristate "SoC ADAV801/3 Audio support"
+	depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+	select SND_BF5XX_SOC_I2S
+	select SND_SOC_ADAV80X
+	help
+	  Say Y if you want to add support for ADAV80X SoC audio.
+
 config SND_BFIN_AD73311_SE
 	int "PF pin for AD73311L Chip Select"
 	depends on SND_BF5XX_SOC_AD73311

Modified: trunk/sound/soc/blackfin/Makefile (8607 => 8608)


--- trunk/sound/soc/blackfin/Makefile	2010-04-06 04:17:08 UTC (rev 8607)
+++ trunk/sound/soc/blackfin/Makefile	2010-04-06 05:12:46 UTC (rev 8608)
@@ -25,6 +25,7 @@
 snd-adau1761-objs := bf5xx-adau1761.o
 snd-adau1361-objs := bf5xx-adau1361.o
 snd-adau1381-objs := bf5xx-adau1381.o
+snd-adav80x-objs := bf5xx-adav80x.o
 
 obj-$(CONFIG_SND_BF5XX_SOC_AD183X) += snd-ad183x.o
 obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o

Added: trunk/sound/soc/blackfin/bf5xx-adav80x.c (0 => 8608)


--- trunk/sound/soc/blackfin/bf5xx-adav80x.c	                        (rev 0)
+++ trunk/sound/soc/blackfin/bf5xx-adav80x.c	2010-04-06 05:12:46 UTC (rev 8608)
@@ -0,0 +1,159 @@
+/*
+ * File:         sound/soc/blackfin/bf5xx-adav80x.c
+ * Author:       Yi Li <[email protected]>
+ *
+ * Created:      Tue June 06 2010
+ * Description:  board driver for ADAV80X sound chip
+ *
+ * Modified:
+ *               Copyright 2010 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/portmux.h>
+#include <linux/gpio.h>
+#include "../codecs/adav80x.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+static struct snd_soc_card bf5xx_adav80x;
+
+static int bf5xx_adav80x_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+		params_format(params));
+	/*
+	 * If you are using a crystal source which frequency is not 12MHz
+	 * then modify the below case statement with frequency of the crystal.
+	 *
+	 * If you are using the SPORT to generate clocking then this is
+	 * where to do it.
+	 */
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 12000000;
+		break;
+	}
+
+	/*
+	 * CODEC is master for BCLK and LRC in this configuration.
+	 */
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+/*
+	ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+*/
+	return 0;
+}
+
+static struct snd_soc_ops bf5xx_adav80x_ops = {
+	.hw_params = bf5xx_adav80x_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_adav80x_dai = {
+	.name = "adav80x",
+	.stream_name = "ADAV80X",
+	.cpu_dai = &bf5xx_i2s_dai,
+	.codec_dai = &adav80x_dai,
+	.ops = &bf5xx_adav80x_ops,
+};
+
+static struct snd_soc_card bf5xx_adav80x = {
+	.name = "bf5xx_adav80x",
+	.platform = &bf5xx_i2s_soc_platform,
+	.dai_link = &bf5xx_adav80x_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_adav80x_snd_devdata = {
+	.card = &bf5xx_adav80x,
+	.codec_dev = &soc_codec_dev_adav80x,
+};
+
+static struct platform_device *bf5xx_adav80x_snd_device;
+
+static int __init bf5xx_adav80x_init(void)
+{
+	int ret;
+
+	bf5xx_adav80x_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!bf5xx_adav80x_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(bf5xx_adav80x_snd_device,
+				&bf5xx_adav80x_snd_devdata);
+	bf5xx_adav80x_snd_devdata.dev = &bf5xx_adav80x_snd_device->dev;
+	ret = platform_device_add(bf5xx_adav80x_snd_device);
+
+	if (ret)
+		platform_device_put(bf5xx_adav80x_snd_device);
+
+	return ret;
+}
+
+static void __exit bf5xx_adav80x_exit(void)
+{
+	platform_device_unregister(bf5xx_adav80x_snd_device);
+}
+
+module_init(bf5xx_adav80x_init);
+module_exit(bf5xx_adav80x_exit);
+
+/* Module information */
+MODULE_AUTHOR("Yi Li");
+MODULE_DESCRIPTION("ALSA SoC ADAV80X Blackfin Board");
+MODULE_LICENSE("GPL");

Modified: trunk/sound/soc/codecs/Kconfig (8607 => 8608)


--- trunk/sound/soc/codecs/Kconfig	2010-04-06 04:17:08 UTC (rev 8607)
+++ trunk/sound/soc/codecs/Kconfig	2010-04-06 05:12:46 UTC (rev 8608)
@@ -21,6 +21,7 @@
 	select SND_SOC_ADAU1761 if I2C
 	select SND_SOC_ADAU1361 if I2C
 	select SND_SOC_ADAU1381 if I2C
+	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_AK4642 if I2C
@@ -115,6 +116,9 @@
 config SND_SOC_ADAU1381
 	tristate
 
+config SND_SOC_ADAV80X
+	tristate
+
 config SND_SOC_AK4104
 	tristate
 

Modified: trunk/sound/soc/codecs/Makefile (8607 => 8608)


--- trunk/sound/soc/codecs/Makefile	2010-04-06 04:17:08 UTC (rev 8607)
+++ trunk/sound/soc/codecs/Makefile	2010-04-06 05:12:46 UTC (rev 8608)
@@ -7,6 +7,7 @@
 snd-soc-adau1371-objs := adau1371.o
 snd-soc-adau1381-objs := adau1381.o
 snd-soc-adau1761-objs := adau1761.o
+snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o

Added: trunk/sound/soc/codecs/adav80x.c (0 => 8608)


--- trunk/sound/soc/codecs/adav80x.c	                        (rev 0)
+++ trunk/sound/soc/codecs/adav80x.c	2010-04-06 05:12:46 UTC (rev 8608)
@@ -0,0 +1,504 @@
+/*
+ * ADAV80X Audio Codec driver supporting ADAV801, ADAV803
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include "adav80x.h"
+
+
+struct adav80x_priv {
+	struct snd_soc_codec codec;
+	u16 reg_cache[ADAV80X_NUM_REGS];
+};
+
+static struct snd_soc_codec *adav80x_codec;
+struct snd_soc_codec_device soc_codec_dev_adav80x;
+static int adav80x_register(struct adav80x_priv *adav80x, int bus_type);
+static void adav80x_unregister(struct adav80x_priv *adav80x);
+
+static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", ADAV80X_DAC_CTRL1, 7, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", ADAV80X_ADC_CTRL1, 5, 1),
+	SND_SOC_DAPM_SUPPLY("PLL_PWR", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "DAC", NULL, "PLL_PWR" },
+	{ "ADC", NULL, "PLL_PWR" },
+};
+
+/*
+ * ADAV80X volume/mute/de-emphasis etc. controls
+ */
+static const char *adav80x_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
+
+static const struct soc_enum adav80x_deemp_enum =
+SOC_ENUM_SINGLE(ADAV80X_DAC_CTRL2, 0, 4, adav80x_deemp);
+
+static const struct snd_kcontrol_new adav80x_snd_controls[] = {
+	/* DAC volume control */
+	SOC_DOUBLE_R("DAC Volume", ADAV80X_DAC_L_VOL,
+			ADAV80X_DAC_R_VOL, 0, 0xFF, 0),
+	/* DAC peak volume detect, read clears it */
+	SOC_DOUBLE_R("DAC Peak Volume", ADAV80X_DAC_L_PEAK_VOL,
+			ADAV80X_DAC_R_PEAK_VOL, 0, 0x3F, 0),
+
+	/* ADC volume control */
+	SOC_DOUBLE_R("ADC Volume", ADAV80X_ADC_L_VOL,
+			ADAV80X_ADC_R_VOL, 0, 0xFF, 0),
+	/* ADC peak volume detect */
+	SOC_DOUBLE_R("ADC Peak Volume", ADAV80X_ADC_L_PEAK_VOL,
+			ADAV80X_ADC_R_PEAK_VOL, 0, 0x3F, 0),
+
+	/* ADC mute */
+	SOC_DOUBLE("ADC Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1),
+
+	/* DAC mute */
+	SOC_DOUBLE("DAC Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 1),
+
+	/* ADC high-pass filter */
+	SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0),
+
+	/* DAC de-emphasis */
+	SOC_ENUM("Playback Deemphasis", adav80x_deemp_enum),
+};
+
+/*
+ * DAI ops entries
+ */
+
+static int adav80x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 rec_ctl = 0, playback_ctl = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* use internal clock 1 */
+		playback_ctl |= 0x10;
+		rec_ctl |= 0x20;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	/* DAC word length depends on input, ADC need to set word length */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		playback_ctl |= 0x1;
+		rec_ctl |= 0x1;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		playback_ctl |= 0x4;
+		rec_ctl |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	/* Use default - seems no polarity setting */
+	/* DAC control reg 1: CHSEL[1:0], POL[1:0] ? */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_write(codec, ADAV80X_PLAYBACK_CTRL, playback_ctl);
+	snd_soc_write(codec, ADAV80X_REC_CTRL, rec_ctl);
+
+	return 0;
+}
+
+static int adav80x_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	int word_len = 0;
+
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		word_len = 3;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		word_len = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		word_len = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		word_len = 0;
+		break;
+	}
+
+
+	/* Playback port does not need to set word length? */
+
+	/* Record Port Control */
+	snd_soc_update_bits(codec, ADAV80X_REC_CTRL, 0x3<<2, word_len<<2);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int adav80x_soc_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	return 0;
+}
+
+static int adav80x_soc_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+#else
+#define adav80x_soc_suspend NULL
+#define adav80x_soc_resume  NULL
+#endif
+
+static int adav80x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int reg;
+
+	reg = snd_soc_read(codec, ADAV80X_DAC_CTRL1);
+	reg = (mute > 0) ? reg & ~0x3 : reg | 0x3;
+	snd_soc_write(codec, ADAV80X_DAC_CTRL1, reg);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops adav80x_dai_ops = {
+	.hw_params = adav80x_hw_params,
+	.set_fmt = adav80x_set_dai_fmt,
+	.digital_mute = adav80x_mute,
+};
+
+/* codec DAI instance */
+/* DAC sample rates: 32/44.1/48/96/192kHz, ADC sample reate: 48/96kHz - TBD */
+struct snd_soc_dai adav80x_dai = {
+	.name = "ADAV80X",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.ops = &adav80x_dai_ops,
+};
+EXPORT_SYMBOL_GPL(adav80x_dai);
+
+
+static int adav80x_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (adav80x_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = adav80x_codec;
+	codec = adav80x_codec;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto pcm_err;
+	}
+
+	snd_soc_add_controls(codec, adav80x_snd_controls,
+				ARRAY_SIZE(adav80x_snd_controls));
+	snd_soc_dapm_new_controls(codec, adav80x_dapm_widgets,
+				  ARRAY_SIZE(adav80x_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+
+pcm_err:
+	return ret;
+}
+
+/* power down chip */
+static int adav80x_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_adav80x = {
+	.probe =	adav80x_probe,
+	.remove =	adav80x_remove,
+	.suspend =	adav80x_soc_suspend,
+	.resume =	adav80x_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_adav80x);
+
+static int adav80x_register(struct adav80x_priv *adav80x, int bus_type)
+{
+	int ret;
+	struct snd_soc_codec *codec = &adav80x->codec;
+
+	if (adav80x_codec) {
+		dev_err(codec->dev, "Another adav80x is registered\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&codec->mutex);
+	codec->private_data = adav80x;
+	codec->reg_cache = adav80x->reg_cache;
+	codec->reg_cache_size = ADAV80X_NUM_REGS;
+	codec->name = "ADAV80X";
+	codec->owner = THIS_MODULE;
+	codec->dai = &adav80x_dai;
+	codec->num_dai = 1;
+
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	adav80x_dai.dev = codec->dev;
+	adav80x_codec = codec;
+
+
+	if (bus_type == SND_SOC_I2C)
+		/* addr(7-bit left shifted 1), data(8bit)*/
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
+	else
+		/* register format: addr(7bit), data(9bit) */
+		/* set spi bits_per_word to 8 instead of 16,
+		   since addr need to be transfer before data */
+		ret = snd_soc_codec_set_cache_io(codec, 7, 9, bus_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to set cache I/O: %d\n",
+				ret);
+		kfree(adav80x);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		kfree(adav80x);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&adav80x_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+		snd_soc_unregister_codec(codec);
+		kfree(adav80x);
+		return ret;
+	}
+
+	/* default setting for adav80x */
+
+	/* These should be set on board level? */
+	/* DAC, ADC, ICLK clock source - XIN */
+	snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x0);
+	snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x0);
+
+	/* Power up XTAL oscillator */
+	snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0xC);
+	/* Power down SYSCLK output, power down S/PDIF receiver */
+	snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x27);
+
+	/* Disable S/PDIF transmitter */
+	snd_soc_write(codec, ADAV80X_TX_CTRL, 0x0);
+
+	/* Datapath: ADC->record, AUX_IN->SRC->AUX_OUT */
+	snd_soc_write(codec, ADAV80X_DPATH_CTRL1, 0xC4);
+	/* Datapath: playback->DAC, DIR->DIT */
+	snd_soc_write(codec, ADAV80X_DPATH_CTRL2, 0x11);
+
+	/* Soft-mute SRC output */
+	snd_soc_write(codec, ADAV80X_GDELAY_MUTE, 0x80);
+
+	/* DAC: de-emphasis: none, MCLCK divider: 1, MCLK=256xFs */
+	snd_soc_write(codec, ADAV80X_DAC_CTRL2, 0x0);
+	/* Disable DAC zero flag */
+	snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
+	/* DAC: volume */
+	snd_soc_write(codec, ADAV80X_DAC_L_VOL, 0xFF);
+	snd_soc_write(codec, ADAV80X_DAC_R_VOL, 0xFF);
+
+	/* ADC: power up, unmute adc channles */
+	snd_soc_write(codec, ADAV80X_ADC_CTRL1, 0x0);
+	/* MCLCK divider: 1 */
+	snd_soc_write(codec, ADAV80X_ADC_CTRL2, 0x0);
+	/* ADC: volumn */
+	snd_soc_write(codec, ADAV80X_ADC_L_VOL, 0xFF);
+	snd_soc_write(codec, ADAV80X_ADC_R_VOL, 0xFF);
+
+	/* Disable ALC */
+	snd_soc_write(codec, ADAV80X_ALC_CTRL1, 0x0);
+
+	return 0;
+}
+
+static void adav80x_unregister(struct adav80x_priv *adav80x)
+{
+	snd_soc_unregister_dai(&adav80x_dai);
+	snd_soc_unregister_codec(&adav80x->codec);
+	kfree(adav80x);
+	adav80x_codec = NULL;
+}
+
+static int __devinit adav80x_bus_probe(struct device *dev, void *ctrl_data,
+		int bus_type)
+{
+	struct snd_soc_codec *codec;
+	struct adav80x_priv *adav80x;
+
+	adav80x = kzalloc(sizeof(struct adav80x_priv), GFP_KERNEL);
+	if (adav80x == NULL)
+		return -ENOMEM;
+
+	codec = &adav80x->codec;
+	codec->control_data = ctrl_data;
+	codec->dev = dev;
+
+	dev_set_drvdata(dev, adav80x);
+
+	return adav80x_register(adav80x, bus_type);
+}
+
+int adav80x_bus_remove(struct device *dev)
+{
+	struct adav80x_priv *adav80x = dev_get_drvdata(dev);
+
+	adav80x_unregister(adav80x);
+	return 0;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit adav80x_spi_probe(struct spi_device *spi)
+{
+	return adav80x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+}
+
+static int __devexit adav80x_spi_remove(struct spi_device *spi)
+{
+	return adav80x_bus_remove(&spi->dev);
+}
+
+static struct spi_driver adav80x_spi_driver = {
+	.driver = {
+		.name	= "adav80x",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= adav80x_spi_probe,
+	.remove		= __devexit_p(adav80x_spi_remove),
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct i2c_device_id adav80x_id[] = {
+	{ "adav803", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adav80x_id);
+
+static int __devinit adav80x_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	return adav80x_bus_probe(&client->dev, client, SND_SOC_I2C);
+}
+
+static int __devexit adav80x_i2c_remove(struct i2c_client *client)
+{
+	return adav80x_bus_remove(&client->dev);
+}
+
+static struct i2c_driver adav80x_i2c_driver = {
+	.driver = {
+		.name = "adav80x",
+	},
+	.probe    = adav80x_i2c_probe,
+	.remove   = __devexit_p(adav80x_i2c_remove),
+	.id_table = adav80x_id,
+};
+#endif
+
+static int __init adav80x_init(void)
+{
+	int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret =  i2c_add_driver(&adav80x_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register ADAV80X I2C driver: %d\n",
+				ret);
+	}
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&adav80x_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register ADAV80X SPI driver: %d\n",
+				ret);
+	}
+#endif
+	return ret;
+}
+module_init(adav80x_init);
+
+static void __exit adav80x_exit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&adav80x_spi_driver);
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&adav80x_i2c_driver);
+#endif
+}
+module_exit(adav80x_exit);
+
+MODULE_DESCRIPTION("ASoC adav80x driver");
+MODULE_AUTHOR("Yi Li");
+MODULE_LICENSE("GPL");
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to