Title: [9622] trunk/sound/soc/codecs: task[#6322] driver:codec add adau1701 driver
Revision
9622
Author
cliff
Date
2011-02-19 06:48:04 -0500 (Sat, 19 Feb 2011)

Log Message

task[#6322] driver:codec add adau1701 driver

Modified Paths

Added Paths

Diff

Modified: trunk/sound/soc/codecs/Kconfig (9621 => 9622)


--- trunk/sound/soc/codecs/Kconfig	2011-02-18 05:07:13 UTC (rev 9621)
+++ trunk/sound/soc/codecs/Kconfig	2011-02-19 11:48:04 UTC (rev 9622)
@@ -22,6 +22,7 @@
 	select SND_SOC_ADAU1381 if I2C
 	select SND_SOC_ADAU1761 if I2C
 	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+	select SND_SOC_ADAU1701 if I2C
 	select SND_SOC_ADS117X
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
@@ -137,6 +138,9 @@
 config SND_SOC_ADAV80X
 	tristate
 
+config SND_SOC_ADAU1701
+	tristate
+
 config SND_SOC_ADS117X
 	tristate
 

Modified: trunk/sound/soc/codecs/Makefile (9621 => 9622)


--- trunk/sound/soc/codecs/Makefile	2011-02-18 05:07:13 UTC (rev 9621)
+++ trunk/sound/soc/codecs/Makefile	2011-02-19 11:48:04 UTC (rev 9622)
@@ -9,6 +9,7 @@
 snd-soc-adau1381-objs := adau1381.o
 snd-soc-adau1761-objs := adau1761.o
 snd-soc-adav80x-objs := adav80x.o
+snd-soc-adau1701-objs := adau1701.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
@@ -89,6 +90,7 @@
 obj-$(CONFIG_SND_SOC_ADAU1381)	+= snd-soc-adau1381.o
 obj-$(CONFIG_SND_SOC_ADAU1761)	+= snd-soc-adau1761.o
 obj-$(CONFIG_SND_SOC_ADAV80X)	+= snd-soc-adav80x.o
+obj-$(CONFIG_SND_SOC_ADAU1701)	+= snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o

Added: trunk/sound/soc/codecs/adau1701.c (0 => 9622)


--- trunk/sound/soc/codecs/adau1701.c	                        (rev 0)
+++ trunk/sound/soc/codecs/adau1701.c	2011-02-19 11:48:04 UTC (rev 9622)
@@ -0,0 +1,463 @@
+/*
+ * Driver for ADAU1701 sound codec
+ *
+ * Copyright 2011 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/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/sigma.h>
+#include <linux/sysfs.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 "adau1701.h"
+
+#define AUDIO_NAME "adau1701"
+#define ADAU1701_VERSION "0.10"
+#define ADAU1701_FIRMWARE "SigmaDSP_fw.bin"
+
+static const u16 adau1701_reg_defaults[] = {
+	0x0000,     /* R0 */
+	0x0000,     /* R1 */
+	0x0000,     /* R2 */
+	0x0000,     /* R3 */
+	0x0000,     /* R4 */
+	0x0000,     /* R5 */
+	0x0000,     /* R6 */
+	0x0000,     /* R7 */
+	0x0000,     /* R8 */
+	0x0000,     /* R9 */
+	0x0000,     /* R10 */
+	0x0000,     /* R11 */
+	0x0000,     /* R12 */
+	0x0000,     /* R13 */
+	0x0000,     /* R14 */
+	0x0000,     /* R15 */
+	0x0000,     /* R16 */
+	0x0000,     /* R17 */
+	0x0000,     /* R18 */
+	0x0000,     /* R19 */
+	0x0000,     /* R20 */
+	0x0000,     /* R21 */
+	0x0000,     /* R22 */
+	0x0000,     /* R23 */
+	0x0000,     /* R24 */
+	0x0000,     /* R25 */
+	0x0000,     /* R26 */
+	0x0000,     /* R27 */
+	0x0000,     /* R28  - DSP Core Control */
+	0x0000,     /* R29 */
+	0x0000,     /* R30  - Serial Output Control */
+	0x0000,     /* R31  - Serial Input Control*/
+	0x0000,     /* R32 */
+	0x0000,     /* R33 */
+	0x0000,     /* R34  - Auxiliary ADC and Power Control */
+	0x0000,     /* R35 */
+	0x0000,     /* R36  - Auxiliary ADC Enable*/
+	0x0000,     /* R37  - DAC Setup */
+};
+
+/* codec private data */
+struct adau1701_priv {
+	struct snd_soc_codec *codec;
+};
+
+/*
+ * write register cache
+ */
+static inline int adau1701_write_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+
+	if (reg < ADAU1701_FIRSTREG)
+		reg = reg + ADAU1701_FIRSTREG;
+
+	if ((reg < ADAU1701_FIRSTREG) || (reg > ADAU1701_LASTREG))
+		return -1;
+
+	cache[reg - ADAU1701_FIRSTREG] = value;
+
+	return 0;
+}
+
+/*
+ * write a multibyte ADAU1701 register
+ */
+static int adau1701_write_reg_block(struct snd_soc_codec *codec,
+	unsigned int reg, u8 length, u8 *values)
+{
+	int count = length + 2; /*data plus 16bit register address*/
+	u8 buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+	buf[0] = (u8)(reg >> 8);
+	buf[1] = (u8)(reg & 0xFF);
+
+	if (length > 0)
+		memcpy(&buf[2], values, length);
+
+	if (codec->hw_write(codec->control_data, buf, count) == count)
+		return 0;
+	else {
+		dev_err(codec->dev, "address block write failed.");
+		return -EIO;
+	}
+}
+
+/*
+ * read ADAU1701 hw register and update cache
+ */
+static int adau1701_read_reg_byte(struct snd_soc_codec *codec,
+	u16 reg)
+{
+	u8 addr[2];
+	u8 buf[1] = {0};
+
+	if (reg < ADAU1701_FIRSTREG)
+		reg = reg + ADAU1701_FIRSTREG;
+
+	if ((reg < ADAU1701_FIRSTREG) || (reg > ADAU1701_LASTREG))
+		return -EIO;
+
+	addr[0] = (u8)(reg >> 8);
+	addr[1] = (u8)(reg & 0xFF);
+
+	/* write the 2byte read address */
+	if (codec->hw_write(codec->control_data, addr, 2) != 2) {
+		printk(KERN_ERR "read_reg_byte:address write failed.");
+		return -EIO;
+	}
+
+	if (i2c_master_recv(codec->control_data, buf, 1) != 1)
+		return -EIO;
+
+	return buf[0];
+}
+
+static int adau1701_setprogram(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+
+	ret = process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE);
+
+	return ret;
+}
+
+static int adau1701_pcm_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int ret = 0;
+
+	snd_soc_write(codec, ADAU1701_OSCIPOW, 0x0);
+
+	return ret;
+}
+
+static void adau1701_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	snd_soc_write(codec, ADAU1701_OSCIPOW, 0x02);
+
+}
+
+static int adau1701_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 reg = 0;
+	if (mute) {
+		/* mute inputs/outputs */
+		reg = snd_soc_read(codec, ADAU1701_AUXNPOW);
+		reg |= AUXNPOW_AAPD | AUXNPOW_D1PD | AUXNPOW_D0PD;
+		snd_soc_write(codec, ADAU1701_AUXNPOW, reg);
+	} else {
+		/* unmute inputs/outputs */
+		reg = snd_soc_read(codec, ADAU1701_AUXNPOW);
+		reg &= ~(AUXNPOW_AAPD | AUXNPOW_D1PD | AUXNPOW_D0PD);
+		snd_soc_write(codec, ADAU1701_AUXNPOW, reg);
+	}
+
+	return 0;
+}
+
+static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 reg = 0;
+
+	reg = adau1701_read_reg_byte(codec, (u16)ADAU1701_SERITL1);
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg |= SERITL1_LEFTJ;
+		break;
+	/* TODO: support TDM */
+	default:
+		return 0;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	/* TODO: support signal inversions */
+	default:
+		return 0;
+	}
+
+	/* set I2S iface format*/
+	adau1701_write_reg_block(codec, ADAU1701_SERITL1, 1, &reg);
+	return 0;
+}
+
+static int adau1701_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		reg = snd_soc_read(codec, ADAU1701_AUXNPOW);
+		reg &= ~(AUXNPOW_AAPD | AUXNPOW_D1PD | AUXNPOW_D0PD |\
+			AUXNPOW_VBPD | AUXNPOW_VRPD);
+		snd_soc_write(codec, ADAU1701_AUXNPOW, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_write(codec, ADAU1701_OSCIPOW, 0x02);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_write(codec, ADAU1701_OSCIPOW, 0x02);
+		reg = snd_soc_read(codec, ADAU1701_AUXNPOW);
+		reg |= AUXNPOW_AAPD | AUXNPOW_D1PD | AUXNPOW_D0PD |\
+			AUXNPOW_VBPD | AUXNPOW_VRPD;
+		snd_soc_write(codec, ADAU1701_AUXNPOW, reg);
+		break;
+
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define ADAU1701_RATES SNDRV_PCM_RATE_48000
+
+#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops adau1701_dai_ops = {
+	.prepare	= adau1701_pcm_prepare,
+	.shutdown	= adau1701_shutdown,
+	.digital_mute	= adau1701_mute,
+	.set_fmt	= adau1701_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver adau1701_dai = {
+	.name = "ADAU1701",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ADAU1701_RATES,
+		.formats = ADAU1701_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ADAU1701_RATES,
+		.formats = ADAU1701_FORMATS,
+	},
+	.ops = &adau1701_dai_ops,
+};
+EXPORT_SYMBOL_GPL(adau1701_dai);
+
+static int adau1701_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	adau1701_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int adau1701_resume(struct snd_soc_codec *codec)
+{
+	adau1701_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static ssize_t adau1371_dsp_load(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret = 0;
+	struct adau1701_priv *adau1701 = dev_get_drvdata(dev);
+	struct snd_soc_codec *codec = adau1701->codec;
+	ret = adau1701_setprogram(codec);
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+static DEVICE_ATTR(dsp, 0644, NULL, adau1371_dsp_load);
+
+static int adau1701_reg_init(struct snd_soc_codec *codec)
+{
+	u16 reg16;
+	u8 reg[3];
+
+	reg16 = DSPCTRL_DAM | DSPCTRL_ADM;
+	snd_soc_write(codec, ADAU1701_DSPCTRL, reg16);
+	/* Load default program */
+	adau1701_setprogram(codec);
+	reg16 = DSPCTRL_DAM | DSPCTRL_ADM;
+	snd_soc_write(codec, ADAU1701_DSPCTRL, reg16);
+	reg[0] = 0x80;
+	adau1701_write_reg_block(codec, ADAU1701_DSPRES, 1, &reg[0]);
+	snd_soc_write(codec, ADAU1701_SEROCTL, 0);
+	/* PLLMODE1 = 1, PLLMODE0 = 0, 256*fs */
+	snd_soc_write(codec, ADAU1701_SEROCTL, 0x0d00);
+	reg[0] = 0;
+	adau1701_write_reg_block(codec, ADAU1701_SERITL1, 1, &reg[0]);
+	reg[0] = MPCONF_SDATAP | MPCONF_SDATAP << 4;
+	reg[1] = 0;
+	reg[2] = MPCONF_SDATAP;
+	adau1701_write_reg_block(codec, ADAU1701_MPCONF0, 3, &reg[0]);
+	adau1701_write_reg_block(codec, ADAU1701_MPCONF1, 3, &reg[0]);
+	snd_soc_write(codec, ADAU1701_AUXNPOW, 0);
+	reg16 = AUXADCE_AAEN;
+	snd_soc_write(codec, ADAU1701_AUXADCE, reg16);
+	reg16 = DACSET_DACEN;
+	snd_soc_write(codec, ADAU1701_DACSET, reg16);
+	reg16 = DSPCTRL_DAM | DSPCTRL_ADM | DSPCTRL_CR;
+	snd_soc_write(codec, ADAU1701_DSPCTRL, reg16);
+	/* power-down oscillator */
+	snd_soc_write(codec, ADAU1701_OSCIPOW, 0x02);
+
+	return 0;
+}
+
+static int adau1701_probe(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+
+	struct adau1701_priv *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+	adau1701->codec = codec;
+	ret = adau1701_reg_init(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to initialize\n");
+		return ret;
+	}
+	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+	ret = device_create_file(codec->dev, &dev_attr_dsp);
+	if (ret)
+		dev_err(codec->dev, "device_create_file() failed\n");
+
+	return ret;
+}
+
+/* remove everything here */
+static int adau1701_remove(struct snd_soc_codec *codec)
+{
+	adau1701_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+struct snd_soc_codec_driver soc_codec_dev_adau1701 = {
+	.probe =	adau1701_probe,
+	.remove =	adau1701_remove,
+	.suspend =	adau1701_suspend,
+	.resume =	adau1701_resume,
+	.set_bias_level = adau1701_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(adau1701_reg_defaults),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = adau1701_reg_defaults,
+};
+
+static __devinit int adau1701_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct adau1701_priv *adau1701;
+	int ret = 0;
+
+	adau1701 = kzalloc(sizeof(struct adau1701_priv), GFP_KERNEL);
+	if (adau1701 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, adau1701);
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_adau1701, &adau1701_dai, 1);
+	if (ret < 0)
+		kfree(adau1701);
+
+	return ret;
+}
+
+static __devexit int adau1701_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 adau1701_i2c_id[] = {
+	{ "adau1701", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
+
+/* corgi i2c codec control layer */
+static struct i2c_driver adau1701_i2c_driver = {
+	.driver = {
+		.name = "adau1701",
+		.owner = THIS_MODULE,
+	},
+	.probe    = adau1701_i2c_probe,
+	.remove   = __devexit_p(adau1701_i2c_remove),
+	.id_table = adau1701_i2c_id,
+};
+
+static int __init adau1701_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&adau1701_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register adau1701 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(adau1701_modinit);
+
+static void __exit adau1701_exit(void)
+{
+	i2c_del_driver(&adau1701_i2c_driver);
+}
+module_exit(adau1701_exit);
+
+MODULE_DESCRIPTION("ASoC ADAU1701 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");

Added: trunk/sound/soc/codecs/adau1701.h (0 => 9622)


--- trunk/sound/soc/codecs/adau1701.h	                        (rev 0)
+++ trunk/sound/soc/codecs/adau1701.h	2011-02-19 11:48:04 UTC (rev 9622)
@@ -0,0 +1,100 @@
+/*
+ * header file for adau1701 SigmaDSP processor
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADAU1701_H
+#define _ADAU1701_H
+
+/*
+ * Register definition.
+ */
+#define ADAU1701_FIRSTREG	0x0800
+#define ADAU1701_LASTREG	0x0827
+#define ADAU1701_IFACE0		0x0800
+#define ADAU1701_IFACE1		0x0801
+#define ADAU1701_IFACE2		0x0802
+#define ADAU1701_IFACE3		0x0803
+#define ADAU1701_IFACE4		0x0804
+#define ADAU1701_IFACE5		0x0805
+#define ADAU1701_IFACE6		0x0806
+#define ADAU1701_IFACE7		0x0807
+
+#define ADAU1701_GPIOSET	0x0808
+#define ADAU1701_AUXADC0	0x0809
+#define ADAU1701_AUXADC1	0x080A
+#define ADAU1701_AUXADC2	0x080B
+#define ADAU1701_AUXADC3	0x080C
+
+#define ADAU1701_SAFELD0	0x0810
+#define ADAU1701_SAFELD1	0x0811
+#define ADAU1701_SAFELD2	0x0812
+#define ADAU1701_SAFELD3	0x0813
+#define ADAU1701_SAFELD4	0x0814
+
+#define ADAU1701_SLDADD0	0x0815
+#define ADAU1701_SLDADD1	0x0816
+#define ADAU1701_SLDADD2	0x0817
+#define ADAU1701_SLDADD3	0x0818
+#define ADAU1701_SLDADD4	0x0819
+
+#define ADAU1701_DATCAP0	0x081A
+#define ADAU1701_DATCAP1	0x081B
+
+#define ADAU1701_DSPCTRL	0x081C
+#define ADAU1701_DSPRES		0x081D
+#define ADAU1701_SEROCTL	0x081E
+#define ADAU1701_SERITL1	0x081F
+
+#define ADAU1701_MPCONF0	0x0820
+#define ADAU1701_MPCONF1	0x0821
+
+#define ADAU1701_AUXNPOW	0x0822
+#define ADAU1701_AUXADCE	0x0824
+
+#define ADAU1701_OSCIPOW	0x0826
+#define ADAU1701_DACSET		0x0827
+
+
+#define ADAU1701_NUMCACHEREG	0x29
+
+/* Bit fields */
+#define DSPCTRL_CR		(1 << 2)
+#define DSPCTRL_DAM		(1 << 3)
+#define DSPCTRL_ADM		(1 << 4)
+#define DSPCTRL_IST		(1 << 5)
+#define DSPCTRL_IFCW		(1 << 6)
+#define DSPCTRL_GPCW		(1 << 7)
+#define DSPCTRL_AACW		(1 << 8)
+
+#define MPCONF_GPIOIDE		(0)
+#define MPCONF_GPIOINDE		(1)
+#define MPCONF_GPIOOPT		(2)
+#define MPCONF_OCOPT		(3)
+#define MPCONF_SDATAP		(4)
+#define MPCONF_GPIOIDEI		(8)
+#define MPCONF_GPIOINDEI	(9)
+#define MPCONF_GPIOOPTI		(0xA)
+#define MPCONF_OCOPTI		(0xB)
+#define MPCONF_SDATAPI		(0xC)
+#define MPCONF_AUXADC		(0xF)
+
+#define AUXNPOW_AAPD		(0x80)
+#define AUXNPOW_VBPD		(0x40)
+#define AUXNPOW_VRPD		(0x20)
+#define AUXNPOW_D3PD		(0x1)
+#define AUXNPOW_D2PD		(0x2)
+#define AUXNPOW_D1PD		(0x4)
+#define AUXNPOW_D0PD		(0x8)
+
+#define SERITL1_LEFTJ		(1)
+#define SERITL1_TDM		(2)
+
+#define	AUXADCE_AAEN		(1 << 15)
+
+#define	DACSET_DACEN		(1)
+
+#endif
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to