diff mbox

[2/2] ASoC: Add support for CS4265 CODEC

Message ID 1400872614-21666-2-git-send-email-Paul.Handrigan@cirrus.com (mailing list archive)
State New, archived
Headers show

Commit Message

Paul Handrigan May 23, 2014, 7:16 p.m. UTC
This patch adds support for the Cirrus Logic Stereo I2C CODEC

Signed-off-by: Paul Handrigan <paul.handrigan@cirrus.com>
---
 include/sound/cs4265.h    |  18 ++
 sound/soc/codecs/Kconfig  |   5 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/cs4265.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/cs4265.h |  64 +++++
 5 files changed, 805 insertions(+)
 create mode 100644 include/sound/cs4265.h
 create mode 100644 sound/soc/codecs/cs4265.c
 create mode 100644 sound/soc/codecs/cs4265.h

Comments

Mark Brown May 23, 2014, 8:39 p.m. UTC | #1
On Fri, May 23, 2014 at 02:16:54PM -0500, Paul Handrigan wrote:
> This patch adds support for the Cirrus Logic Stereo I2C CODEC

This all looks pretty clean and nice, I have got a few comments below
but they're all pretty small things.

> +	SOC_SINGLE("De-emp 44.1kHz", CS4265_DAC_CTL, 1,
> +				1, 0),
> +	SOC_SINGLE("DAC INV", CS4265_DAC_CTL2, 5,
> +				1, 0),
> +	SOC_SINGLE("DAC Zero Cross", CS4265_DAC_CTL2, 6,
> +				1, 0),
> +	SOC_SINGLE("DAC Soft Ramp", CS4265_DAC_CTL2, 7,
> +				1, 0),

All boolean controls should have Switch at the end of the name.

> +	SOC_SINGLE("ADC HPF Disable", CS4265_ADC_CTL, 1,
> +				1, 0),

Invert this one and call it ADC HPF Switch (similarly for other disable
controls).

> +
> +	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
> +		if (clk_map_table[i].rate == rate &&
> +			clk_map_table[i].mclk == mclk)
> +			return i;

Indent the second line of the if condition with the (.

> +static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
> +			unsigned int freq, int dir)
> +{
> +	struct snd_soc_codec *codec = codec_dai->codec;
> +	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
> +		if (clk_map_table[i].mclk == freq) {

It's better to check that clk_id is 0 here, just in case you think of
another clock to control in future (perhaps with a new device that can
share the same driver even if it's not possible for this one).

> +	{
> +		.name = "cs4265-spdif",
> +		.playback = {
> +			.stream_name = "SPDIF Playback",
> +			.channels_min = 1,
> +			.channels_max = 2,
> +			.rates = CS4265_SPDIF_RATES,
> +			.formats = CS4265_FORMATS,
> +		},
> +		.ops = &cs4265_ops,
> +	},

You should have separate operations for the DAC and S/PDIF DAIs and only
mute the relevant interfaces.  If you can't mute the DAC DAIs
independently just don't provide an operation and let the user control
it as they like.  This avoids problems if more than one stream is
running at once.

> +static int cs4265_probe(struct snd_soc_codec *codec)
> +{
> +	return 0;
> +}

Remove empty operations.

> +	} else {
> +		pdata = devm_kzalloc(&i2c_client->dev,
> +				     sizeof(struct cs4265_platform_data),
> +				GFP_KERNEL);
> +		if (!pdata) {
> +			dev_err(&i2c_client->dev, "could not allocate pdata\n");
> +			return -ENOMEM;
> +		}
> +		pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
> +						"reset-gpio", 0);
> +		cs4265->pdata = *pdata;
> +	}

Can you convert this to use the new gpiod_ APIs and directly request by
name?  There's also the -gpios thing I mentioned for the binding.

> +	ret =  snd_soc_register_codec(&i2c_client->dev,
> +			&soc_codec_dev_cs4265, cs4265_dai,
> +			ARRAY_SIZE(cs4265_dai));
> +	return ret;

devm_
Paul Handrigan May 24, 2014, 2:18 p.m. UTC | #2
> On May 23, 2014, at 3:40 PM, "Mark Brown" <broonie@kernel.org> wrote:
> 
>> On Fri, May 23, 2014 at 02:16:54PM -0500, Paul Handrigan wrote:
>> This patch adds support for the Cirrus Logic Stereo I2C CODEC
> 
> This all looks pretty clean and nice, I have got a few comments below
> but they're all pretty small things.
> 
>> +    SOC_SINGLE("De-emp 44.1kHz", CS4265_DAC_CTL, 1,
>> +                1, 0),
>> +    SOC_SINGLE("DAC INV", CS4265_DAC_CTL2, 5,
>> +                1, 0),
>> +    SOC_SINGLE("DAC Zero Cross", CS4265_DAC_CTL2, 6,
>> +                1, 0),
>> +    SOC_SINGLE("DAC Soft Ramp", CS4265_DAC_CTL2, 7,
>> +                1, 0),
> 
> All boolean controls should have Switch at the end of the name.
> 
>> +    SOC_SINGLE("ADC HPF Disable", CS4265_ADC_CTL, 1,
>> +                1, 0),
> 
> Invert this one and call it ADC HPF Switch (similarly for other disable
> controls).
> 
>> +
>> +    for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
>> +        if (clk_map_table[i].rate == rate &&
>> +            clk_map_table[i].mclk == mclk)
>> +            return i;
> 
> Indent the second line of the if condition with the (.
> 
>> +static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
>> +            unsigned int freq, int dir)
>> +{
>> +    struct snd_soc_codec *codec = codec_dai->codec;
>> +    struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
>> +    int i;
>> +
>> +    for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
>> +        if (clk_map_table[i].mclk == freq) {
> 
> It's better to check that clk_id is 0 here, just in case you think of
> another clock to control in future (perhaps with a new device that can
> share the same driver even if it's not possible for this one).
> 
>> +    {
>> +        .name = "cs4265-spdif",
>> +        .playback = {
>> +            .stream_name = "SPDIF Playback",
>> +            .channels_min = 1,
>> +            .channels_max = 2,
>> +            .rates = CS4265_SPDIF_RATES,
>> +            .formats = CS4265_FORMATS,
>> +        },
>> +        .ops = &cs4265_ops,
>> +    },
> 
> You should have separate operations for the DAC and S/PDIF DAIs and only
> mute the relevant interfaces.  If you can't mute the DAC DAIs
> independently just don't provide an operation and let the user control
> it as they like.  This avoids problems if more than one stream is
> running at once.
> 
>> +static int cs4265_probe(struct snd_soc_codec *codec)
>> +{
>> +    return 0;
>> +}
> 
> Remove empty operations.
> 
>> +    } else {
>> +        pdata = devm_kzalloc(&i2c_client->dev,
>> +                     sizeof(struct cs4265_platform_data),
>> +                GFP_KERNEL);
>> +        if (!pdata) {
>> +            dev_err(&i2c_client->dev, "could not allocate pdata\n");
>> +            return -ENOMEM;
>> +        }
>> +        pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
>> +                        "reset-gpio", 0);
>> +        cs4265->pdata = *pdata;
>> +    }
> 
> Can you convert this to use the new gpiod_ APIs and directly request by
> name?  There's also the -gpios thing I mentioned for the binding.
> 
>> +    ret =  snd_soc_register_codec(&i2c_client->dev,
>> +            &soc_codec_dev_cs4265, cs4265_dai,
>> +            ARRAY_SIZE(cs4265_dai));
>> +    return ret;
> 
> devm_
Thanks.  I will make the changes as requested.
Lars-Peter Clausen May 24, 2014, 4:14 p.m. UTC | #3
On 05/23/2014 09:16 PM, Paul Handrigan wrote:
[...]

A couple of trivial bits:

> @@ -300,6 +301,10 @@ config SND_SOC_CS42L73
>   	tristate "Cirrus Logic CS42L73 CODEC"
>   	depends on I2C
>
> +config SND_SOC_CS4265
> +	tristate "Cirrus Logic CS4265 CODEC"
> +	depends on I2C

select REGMAP_I2C

> +
>   # Cirrus Logic CS4270 Codec
>   config SND_SOC_CS4270
>   	tristate "Cirrus Logic CS4270 CODEC"
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 1ccdaf0..b3c6b5f 100644
[...]
> diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
> new file mode 100644
> index 0000000..f7a6be9
> --- /dev/null
> +++ b/sound/soc/codecs/cs4265.c
> @@ -0,0 +1,716 @@
[...]
> +struct cs4265_private {
> +	struct cs4265_platform_data pdata;
> +	struct regmap *regmap;
> +	struct snd_soc_codec *codec;
> +	struct device *dev;

Both the codec and the dev field don't seem to be used.

> +	u8 format;
> +	u32 sysclk;
> +};
> +
[...]
> +
> +static const struct soc_enum digital_input_mux_enum =
> +	SOC_ENUM_SINGLE(CS4265_SIG_SEL, 7,
> +			ARRAY_SIZE(digital_input_mux_text),
> +			digital_input_mux_text);

SOC_ENUM_SINGLE_DECL(), same for the other enums below.

> +
[...]
> +static struct snd_soc_dai_ops cs4265_ops = {

const

> +	.hw_params	= cs4265_pcm_hw_params,
> +	.digital_mute	= cs4265_digital_mute,
> +	.set_fmt	= cs4265_set_fmt,
> +	.set_sysclk	= cs4265_set_sysclk,
> +};
[...]
> +static struct snd_soc_codec_driver soc_codec_dev_cs4265 = {

const

The soc_codec_dev_foobar naming scheme used in some older driver comes from 
a time where there were no CODEC drivers. A better naming scheme for new 
driver is foobar_codec_driver.

> +	.probe = cs4265_probe,
> +	.remove = cs4265_remove,
> +	.set_bias_level = cs4265_set_bias_level,
> +
> +	.dapm_widgets = cs4265_dapm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
> +	.dapm_routes = cs4265_audio_map,
> +	.num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
> +
> +	.controls = cs4265_snd_controls,
> +	.num_controls = ARRAY_SIZE(cs4265_snd_controls),
> +};
> +
> +static struct regmap_config cs4265_regmap = {

const

> +	.reg_bits = 8,
> +	.val_bits = 8,
> +
> +	.max_register = CS4265_MAX_REGISTER,
> +	.reg_defaults = cs4265_reg_defaults,
> +	.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
> +	.readable_reg = cs4265_readable_register,
> +	.volatile_reg = cs4265_volatile_register,
> +	.cache_type = REGCACHE_RBTREE,
> +};
> +
[...]
Paul Handrigan May 27, 2014, 5:09 p.m. UTC | #4

Paul Handrigan May 31, 2014, 10:08 p.m. UTC | #5
> On May 23, 2014, at 3:40 PM, "Mark Brown" <broonie@kernel.org> wrote:
> 
>> On Fri, May 23, 2014 at 02:16:54PM -0500, Paul Handrigan wrote:
>> This patch adds support for the Cirrus Logic Stereo I2C CODEC
> 
> This all looks pretty clean and nice, I have got a few comments below
> but they're all pretty small things.
> 
>> +    SOC_SINGLE("De-emp 44.1kHz", CS4265_DAC_CTL, 1,
>> +                1, 0),
>> +    SOC_SINGLE("DAC INV", CS4265_DAC_CTL2, 5,
>> +                1, 0),
>> +    SOC_SINGLE("DAC Zero Cross", CS4265_DAC_CTL2, 6,
>> +                1, 0),
>> +    SOC_SINGLE("DAC Soft Ramp", CS4265_DAC_CTL2, 7,
>> +                1, 0),
> 
> All boolean controls should have Switch at the end of the name.
> 
>> +    SOC_SINGLE("ADC HPF Disable", CS4265_ADC_CTL, 1,
>> +                1, 0),
> 
> Invert this one and call it ADC HPF Switch (similarly for other disable
> controls).
> 
>> +
>> +    for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
>> +        if (clk_map_table[i].rate == rate &&
>> +            clk_map_table[i].mclk == mclk)
>> +            return i;
> 
> Indent the second line of the if condition with the (.
> 
>> +static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
>> +            unsigned int freq, int dir)
>> +{
>> +    struct snd_soc_codec *codec = codec_dai->codec;
>> +    struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
>> +    int i;
>> +
>> +    for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
>> +        if (clk_map_table[i].mclk == freq) {
> 
> It's better to check that clk_id is 0 here, just in case you think of
> another clock to control in future (perhaps with a new device that can
> share the same driver even if it's not possible for this one).
> 
>> +    {
>> +        .name = "cs4265-spdif",
>> +        .playback = {
>> +            .stream_name = "SPDIF Playback",
>> +            .channels_min = 1,
>> +            .channels_max = 2,
>> +            .rates = CS4265_SPDIF_RATES,
>> +            .formats = CS4265_FORMATS,
>> +        },
>> +        .ops = &cs4265_ops,
>> +    },
> 
> You should have separate operations for the DAC and S/PDIF DAIs and only
> mute the relevant interfaces.  If you can't mute the DAC DAIs
> independently just don't provide an operation and let the user control
> it as they like.  This avoids problems if more than one stream is
> running at once.

I am going to remove the S/PDIF DAI.  Since it is TX only.
> 
>> +static int cs4265_probe(struct snd_soc_codec *codec)
>> +{
>> +    return 0;
>> +}
> 
> Remove empty operations.
> 
>> +    } else {
>> +        pdata = devm_kzalloc(&i2c_client->dev,
>> +                     sizeof(struct cs4265_platform_data),
>> +                GFP_KERNEL);
>> +        if (!pdata) {
>> +            dev_err(&i2c_client->dev, "could not allocate pdata\n");
>> +            return -ENOMEM;
>> +        }
>> +        pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
>> +                        "reset-gpio", 0);
>> +        cs4265->pdata = *pdata;
>> +    }
> 
> Can you convert this to use the new gpiod_ APIs and directly request by
> name?  There's also the -gpios thing I mentioned for the binding.
> 
>> +    ret =  snd_soc_register_codec(&i2c_client->dev,
>> +            &soc_codec_dev_cs4265, cs4265_dai,
>> +            ARRAY_SIZE(cs4265_dai));
>> +    return ret;
> 
> devm_
diff mbox

Patch

diff --git a/include/sound/cs4265.h b/include/sound/cs4265.h
new file mode 100644
index 0000000..90e7e77
--- /dev/null
+++ b/include/sound/cs4265.h
@@ -0,0 +1,18 @@ 
+/*
+ * linux/sound/cs4265.h -- Platform data for CS4265
+ *
+ * Copyright (c) 2014 Cirrus Logic Inc.
+ *
+ * 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.
+ */
+
+#ifndef __CS4265_H
+#define __CS4265_H
+
+struct cs4265_platform_data {
+	unsigned int reset_gpio;
+};
+
+#endif /* __CS4265_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c59943a..1af2a2f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -43,6 +43,7 @@  config SND_SOC_ALL_CODECS
 	select SND_SOC_CS42L52 if I2C && INPUT
 	select SND_SOC_CS42L56 if I2C && INPUT
 	select SND_SOC_CS42L73 if I2C
+	select SND_SOC_CS4265 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_CS42XX8_I2C if I2C
@@ -300,6 +301,10 @@  config SND_SOC_CS42L73
 	tristate "Cirrus Logic CS42L73 CODEC"
 	depends on I2C
 
+config SND_SOC_CS4265
+	tristate "Cirrus Logic CS4265 CODEC"
+	depends on I2C
+
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
 	tristate "Cirrus Logic CS4270 CODEC"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1ccdaf0..b3c6b5f 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -30,6 +30,7 @@  snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
 snd-soc-cs42l52-objs := cs42l52.o
 snd-soc-cs42l56-objs := cs42l56.o
 snd-soc-cs42l73-objs := cs42l73.o
+snd-soc-cs4265-objs := cs4265.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
 snd-soc-cs42xx8-objs := cs42xx8.o
@@ -186,6 +187,7 @@  obj-$(CONFIG_SND_SOC_CS42L51_I2C)	+= snd-soc-cs42l51-i2c.o
 obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o
 obj-$(CONFIG_SND_SOC_CS42L56)	+= snd-soc-cs42l56.o
 obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o
+obj-$(CONFIG_SND_SOC_CS4265)	+= snd-soc-cs4265.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
new file mode 100644
index 0000000..f7a6be9
--- /dev/null
+++ b/sound/soc/codecs/cs4265.c
@@ -0,0 +1,716 @@ 
+/*
+ * cs4265.c -- CS4265 ALSA SoC audio driver
+ *
+ * Copyright 2014 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.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 <sound/tlv.h>
+#include <sound/cs4265.h>
+#include "cs4265.h"
+
+struct cs4265_private {
+	struct cs4265_platform_data pdata;
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+	struct device *dev;
+	u8 format;
+	u32 sysclk;
+};
+
+static const struct reg_default cs4265_reg_defaults[] = {
+	{ CS4265_PWRCTL, 0x0F },
+	{ CS4265_DAC_CTL, 0x08 },
+	{ CS4265_ADC_CTL, 0x00 },
+	{ CS4265_MCLK_FREQ, 0x00 },
+	{ CS4265_SIG_SEL, 0x40 },
+	{ CS4265_CHB_PGA_CTL, 0x00 },
+	{ CS4265_CHA_PGA_CTL, 0x00 },
+	{ CS4265_ADC_CTL2, 0x19 },
+	{ CS4265_DAC_CHA_VOL, 0x00 },
+	{ CS4265_DAC_CHB_VOL, 0x00 },
+	{ CS4265_DAC_CTL2, 0xC0 },
+	{ CS4265_SPDIF_CTL1, 0x00 },
+	{ CS4265_SPDIF_CTL2, 0x00 },
+	{ CS4265_INT_MASK, 0x00 },
+	{ CS4265_STATUS_MODE_MSB, 0x00 },
+	{ CS4265_STATUS_MODE_LSB, 0x00 },
+};
+
+static bool cs4265_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4265_PWRCTL:
+	case CS4265_DAC_CTL:
+	case CS4265_ADC_CTL:
+	case CS4265_MCLK_FREQ:
+	case CS4265_SIG_SEL:
+	case CS4265_CHB_PGA_CTL:
+	case CS4265_CHA_PGA_CTL:
+	case CS4265_ADC_CTL2:
+	case CS4265_DAC_CHA_VOL:
+	case CS4265_DAC_CHB_VOL:
+	case CS4265_DAC_CTL2:
+	case CS4265_SPDIF_CTL1:
+	case CS4265_SPDIF_CTL2:
+	case CS4265_INT_MASK:
+	case CS4265_STATUS_MODE_MSB:
+	case CS4265_STATUS_MODE_LSB:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs4265_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4265_INT_STATUS:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0);
+
+static const char * const digital_input_mux_text[] = {
+	"SDIN1", "SDIN2"
+};
+
+static const struct soc_enum digital_input_mux_enum =
+	SOC_ENUM_SINGLE(CS4265_SIG_SEL, 7,
+			ARRAY_SIZE(digital_input_mux_text),
+			digital_input_mux_text);
+
+static const struct snd_kcontrol_new digital_input_mux =
+	SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum);
+
+static const char * const mic_linein_text[] = {
+	"MIC", "LINEIN"
+};
+
+static const struct soc_enum mic_linein_enum =
+	SOC_ENUM_SINGLE(CS4265_ADC_CTL2, 0,
+		ARRAY_SIZE(mic_linein_text), mic_linein_text);
+
+static const char * const cam_mode_text[] = {
+	"One Byte", "Two Byte"
+};
+
+static const struct soc_enum cam_mode_enum =
+	SOC_ENUM_SINGLE(CS4265_SPDIF_CTL1, 5,
+		ARRAY_SIZE(cam_mode_text), cam_mode_text);
+
+static const char * const cam_mono_stereo_text[] = {
+	"Stereo", "Mono"
+};
+
+static const struct soc_enum spdif_mono_stereo_enum =
+	SOC_ENUM_SINGLE(CS4265_SPDIF_CTL2, 2,
+		ARRAY_SIZE(cam_mono_stereo_text), cam_mono_stereo_text);
+
+static const char * const mono_select_text[] = {
+	"Channel A", "Channel B"
+};
+
+static const struct soc_enum spdif_mono_select_enum =
+	SOC_ENUM_SINGLE(CS4265_SPDIF_CTL2, 0,
+		ARRAY_SIZE(mono_select_text), mono_select_text);
+
+static const struct snd_kcontrol_new mic_linein_mux =
+	SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum);
+
+static const struct snd_kcontrol_new loopback_ctl =
+	SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0);
+
+static const struct snd_kcontrol_new cs4265_snd_controls[] = {
+
+	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL,
+			      CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv),
+	SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL,
+		      CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv),
+	SOC_SINGLE("De-emp 44.1kHz", CS4265_DAC_CTL, 1,
+				1, 0),
+	SOC_SINGLE("DAC INV", CS4265_DAC_CTL2, 5,
+				1, 0),
+	SOC_SINGLE("DAC Zero Cross", CS4265_DAC_CTL2, 6,
+				1, 0),
+	SOC_SINGLE("DAC Soft Ramp", CS4265_DAC_CTL2, 7,
+				1, 0),
+	SOC_SINGLE("ADC HPF Disable", CS4265_ADC_CTL, 1,
+				1, 0),
+	SOC_SINGLE("ADC Zero Cross", CS4265_ADC_CTL2, 3,
+				1, 0),
+	SOC_SINGLE("ADC Soft Ramp", CS4265_ADC_CTL2, 7,
+				1, 0),
+	SOC_SINGLE("E to F Buffer Disable", CS4265_SPDIF_CTL1,
+				6, 1, 0),
+	SOC_ENUM("C Data Access", cam_mode_enum),
+	SOC_SINGLE("Validity Bit Control", CS4265_SPDIF_CTL2,
+				3, 1, 0),
+	SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
+	SOC_SINGLE("MMTLR Data", 0,
+				1, 1, 0),
+	SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
+	SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
+};
+
+static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
+
+	SND_SOC_DAPM_INPUT("LINEINL"),
+	SND_SOC_DAPM_INPUT("LINEINR"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+
+	SND_SOC_DAPM_AIF_OUT("DOUT", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TXOUT", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux),
+
+	SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1),
+	SND_SOC_DAPM_DAC("DAC", NULL, CS4265_PWRCTL, 1, 1),
+	SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3,
+			1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM,
+			 0, 0, &digital_input_mux),
+
+	SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
+			    &loopback_ctl),
+
+	SND_SOC_DAPM_AIF_IN("DIN1", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DIN2", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TXIN", NULL,  0,
+			CS4265_SPDIF_CTL2, 5, 1),
+
+	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+
+};
+
+static const struct snd_soc_dapm_route cs4265_audio_map[] = {
+
+	{"DIN1", NULL, "DAI1 Playback"},
+	{"DIN2", NULL, "DAI2 Playback"},
+	{"SDIN1 Input Mixer", NULL, "DIN1"},
+	{"SDIN2 Input Mixer", NULL, "DIN2"},
+	{"Input Mux", "SDIN1", "SDIN1 Input Mixer"},
+	{"Input Mux", "SDIN2", "SDIN2 Input Mixer"},
+	{"DAC", NULL, "Input Mux"},
+	{"LINEOUTL", NULL, "DAC"},
+	{"LINEOUTR", NULL, "DAC"},
+
+	{"ADC Mux", "LINEIN", "LINEINL"},
+	{"ADC Mux", "LINEIN", "LINEINR"},
+	{"ADC Mux", "MIC", "MICL"},
+	{"ADC Mux", "MIC", "MICR"},
+	{"ADC", NULL, "ADC Mux"},
+	{"DOUT", NULL, "ADC"},
+	{"DAI1 Capture", NULL, "DOUT"},
+	{"DAI2 Capture", NULL, "DOUT"},
+
+	/* Loopback */
+	{"Loopback", "Switch", "ADC"},
+	{"DAC", NULL, "Loopback"},
+
+	{"TXIN", NULL, "SPDIF Playback"},
+	{"SPDIF Transmitter", NULL, "TXIN"},
+	{"TXOUT", NULL, "SPDIF Transmitter"},
+
+};
+
+struct cs4265_clk_para {
+	u32 mclk;
+	u32 rate;
+	u8 fm_mode; /* values 1, 2, or 4 */
+	u8 mclkdiv;
+};
+
+static const struct cs4265_clk_para clk_map_table[] = {
+	/*32k*/
+	{8192000, 32000, 0, 0},
+	{12288000, 32000, 0, 1},
+	{16384000, 32000, 0, 2},
+	{24576000, 32000, 0, 3},
+	{32768000, 32000, 0, 4},
+
+	/*44.1k*/
+	{11289600, 44100, 0, 0},
+	{16934400, 44100, 0, 1},
+	{22579200, 44100, 0, 2},
+	{33868000, 44100, 0, 3},
+	{45158400, 44100, 0, 4},
+
+	/*48k*/
+	{12288000, 48000, 0, 0},
+	{18432000, 48000, 0, 1},
+	{24576000, 48000, 0, 2},
+	{36864000, 48000, 0, 3},
+	{49152000, 48000, 0, 4},
+
+	/*64k*/
+	{8192000, 64000, 1, 0},
+	{1228800, 64000, 1, 1},
+	{1693440, 64000, 1, 2},
+	{2457600, 64000, 1, 3},
+	{3276800, 64000, 1, 4},
+
+	/* 88.2k */
+	{11289600, 88200, 1, 0},
+	{16934400, 88200, 1, 1},
+	{22579200, 88200, 1, 2},
+	{33868000, 88200, 1, 3},
+	{45158400, 88200, 1, 4},
+
+	/* 96k */
+	{12288000, 96000, 1, 0},
+	{18432000, 96000, 1, 1},
+	{24576000, 96000, 1, 2},
+	{36864000, 96000, 1, 3},
+	{49152000, 96000, 1, 4},
+
+	/* 128k */
+	{8192000, 128000, 2, 0},
+	{12288000, 128000, 2, 1},
+	{16934400, 128000, 2, 2},
+	{24576000, 128000, 2, 3},
+	{32768000, 128000, 2, 4},
+
+	/* 176.4k */
+	{11289600, 176400, 2, 0},
+	{16934400, 176400, 2, 1},
+	{22579200, 176400, 2, 2},
+	{33868000, 176400, 2, 3},
+	{49152000, 176400, 2, 4},
+
+	/* 192k */
+	{12288000, 192000, 2, 0},
+	{18432000, 192000, 2, 1},
+	{24576000, 192000, 2, 2},
+	{36864000, 192000, 2, 3},
+	{49152000, 192000, 2, 4},
+};
+
+static int cs4265_get_clk_index(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].rate == rate &&
+			clk_map_table[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+			unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].mclk == freq) {
+			cs4265->sysclk = freq;
+			return 0;
+		}
+	}
+	cs4265->sysclk = 0;
+	dev_err(codec->dev, "Invalid freq parameter %d\n", freq);
+	return -EINVAL;
+}
+
+static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+				CS4265_ADC_MASTER,
+				CS4265_ADC_MASTER);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+				CS4265_ADC_MASTER,
+				0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	 /* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= SND_SOC_DAIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface |= SND_SOC_DAIFMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= SND_SOC_DAIFMT_LEFT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cs4265->format = iface;
+	return 0;
+}
+
+static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute) {
+		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_MUTE,
+			CS4265_DAC_CTL_MUTE);
+		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_MUTE,
+			CS4265_SPDIF_CTL2_MUTE);
+	} else {
+		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_MUTE,
+			0);
+		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_MUTE,
+			0);
+	}
+	return 0;
+}
+
+static int cs4265_pcm_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;
+	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	int index;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+		((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK)
+		== SND_SOC_DAIFMT_RIGHT_J))
+		return -EINVAL;
+
+	index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
+	if (index >= 0) {
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+			CS4265_ADC_FM, clk_map_table[index].fm_mode);
+		snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
+			CS4265_MCLK_FREQ_MASK,
+			clk_map_table[index].mclkdiv);
+
+	} else {
+		dev_err(codec->dev, "can't get correct mclk\n");
+		return -EINVAL;
+	}
+
+	switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_DIF, (1 << 4));
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+			CS4265_ADC_DIF, (1 << 4));
+		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_DIF, (1 << 6));
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		if (params_format(params) & SNDRV_PCM_FORMAT_S16_LE) {
+			snd_soc_update_bits(codec, CS4265_DAC_CTL,
+				CS4265_DAC_CTL_DIF, (1 << 5));
+			snd_soc_update_bits(codec, CS4265_ADC_CTL,
+				CS4265_SPDIF_CTL2_DIF, (1 << 7));
+		} else {
+			snd_soc_update_bits(codec, CS4265_DAC_CTL,
+				CS4265_DAC_CTL_DIF, (3 << 5));
+			snd_soc_update_bits(codec, CS4265_ADC_CTL,
+				CS4265_SPDIF_CTL2_DIF, (1 << 7));
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_DIF, 0);
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+			CS4265_ADC_DIF, 0);
+		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+			CS4265_SPDIF_CTL2_DIF, (1 << 6));
+
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs4265_set_bias_level(struct snd_soc_codec *codec,
+					enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_update_bits(codec, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_update_bits(codec, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN,
+			CS4265_PWRCTL_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN,
+			CS4265_PWRCTL_PDN);
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define CS4265_SPDIF_RATES (SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static struct snd_soc_dai_ops cs4265_ops = {
+	.hw_params	= cs4265_pcm_hw_params,
+	.digital_mute	= cs4265_digital_mute,
+	.set_fmt	= cs4265_set_fmt,
+	.set_sysclk	= cs4265_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs4265_dai[] = {
+	{
+		.name = "cs4265-dai1",
+		.playback = {
+			.stream_name = "DAI1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.capture = {
+			.stream_name = "DAI1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.ops = &cs4265_ops,
+	},
+	{
+		.name = "cs4265-dai2",
+		.playback = {
+			.stream_name = "DAI2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.capture = {
+			.stream_name = "DAI2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.ops = &cs4265_ops,
+	},
+	{
+		.name = "cs4265-spdif",
+		.playback = {
+			.stream_name = "SPDIF Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_SPDIF_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.ops = &cs4265_ops,
+	},
+};
+
+static int cs4265_probe(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static int cs4265_remove(struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs4265 = {
+	.probe = cs4265_probe,
+	.remove = cs4265_remove,
+	.set_bias_level = cs4265_set_bias_level,
+
+	.dapm_widgets = cs4265_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
+	.dapm_routes = cs4265_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
+
+	.controls = cs4265_snd_controls,
+	.num_controls = ARRAY_SIZE(cs4265_snd_controls),
+};
+
+static struct regmap_config cs4265_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS4265_MAX_REGISTER,
+	.reg_defaults = cs4265_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
+	.readable_reg = cs4265_readable_register,
+	.volatile_reg = cs4265_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs4265_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs4265_private *cs4265;
+	struct cs4265_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
+	int ret = 0;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private),
+			       GFP_KERNEL);
+	if (cs4265 == NULL)
+		return -ENOMEM;
+	cs4265->dev = &i2c_client->dev;
+
+	cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
+	if (IS_ERR(cs4265->regmap)) {
+		ret = PTR_ERR(cs4265->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs4265->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev,
+				     sizeof(struct cs4265_platform_data),
+				GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&i2c_client->dev, "could not allocate pdata\n");
+			return -ENOMEM;
+		}
+		pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
+						"reset-gpio", 0);
+		cs4265->pdata = *pdata;
+	}
+
+	i2c_set_clientdata(i2c_client, cs4265);
+
+	if (gpio_is_valid(cs4265->pdata.reset_gpio)) {
+		ret = devm_gpio_request_one(&i2c_client->dev,
+			cs4265->pdata.reset_gpio,
+			GPIOF_OUT_INIT_HIGH, "CS4265 /RST");
+		if (ret < 0) {
+			dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
+				cs4265->pdata.reset_gpio, ret);
+			return ret;
+		}
+		gpio_set_value_cansleep(cs4265->pdata.reset_gpio, 0);
+		gpio_set_value_cansleep(cs4265->pdata.reset_gpio, 1);
+	}
+
+	ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, &reg);
+	devid = reg & CS4265_CHIP_ID_MASK;
+	if (devid != CS4265_CHIP_ID_VAL) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS4265 Device ID (%X). Expected %X\n",
+			devid, CS4265_CHIP_ID);
+		return ret;
+	}
+	dev_info(&i2c_client->dev,
+		"CS4265 Version %x\n",
+			reg & CS4265_REV_ID_MASK);
+
+	regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
+
+	ret =  snd_soc_register_codec(&i2c_client->dev,
+			&soc_codec_dev_cs4265, cs4265_dai,
+			ARRAY_SIZE(cs4265_dai));
+	return ret;
+}
+
+static int cs4265_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct of_device_id cs4265_of_match[] = {
+	{ .compatible = "cirrus,cs4265", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4265_of_match);
+
+static const struct i2c_device_id cs4265_id[] = {
+	{ "cs4265", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs4265_id);
+
+static struct i2c_driver cs4265_i2c_driver = {
+	.driver = {
+		.name = "cs4265",
+		.owner = THIS_MODULE,
+		.of_match_table = cs4265_of_match,
+	},
+	.id_table = cs4265_id,
+	.probe =    cs4265_i2c_probe,
+	.remove =   cs4265_i2c_remove,
+};
+
+module_i2c_driver(cs4265_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS4265 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4265.h b/sound/soc/codecs/cs4265.h
new file mode 100644
index 0000000..0a80a8d
--- /dev/null
+++ b/sound/soc/codecs/cs4265.h
@@ -0,0 +1,64 @@ 
+/*
+ * cs4265.h -- CS4265 ALSA SoC audio driver
+ *
+ * Copyright 2014 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CS4265_H__
+#define __CS4265_H__
+
+#define CS4265_CHIP_ID				0x1
+#define CS4265_CHIP_ID_VAL			0xD0
+#define CS4265_CHIP_ID_MASK			0xF0
+#define CS4265_REV_ID_MASK			0x0F
+
+#define CS4265_PWRCTL				0x02
+#define CS4265_PWRCTL_PDN			1
+
+#define CS4265_DAC_CTL				0x3
+#define CS4265_DAC_CTL_MUTE			(1 << 2)
+#define CS4265_DAC_CTL_DIF			(3 << 4)
+
+#define CS4265_ADC_CTL				0x4
+#define CS4265_ADC_MASTER			1
+#define CS4265_ADC_DIF				(1 << 4)
+#define CS4265_ADC_FM				(3 << 6)
+
+#define CS4265_MCLK_FREQ			0x5
+#define CS4265_MCLK_FREQ_MASK			(7 << 4)
+
+#define CS4265_SIG_SEL				0x6
+#define CS4265_SIG_SEL_LOOP			(1 << 1)
+
+#define CS4265_CHB_PGA_CTL			0x7
+#define CS4265_CHA_PGA_CTL			0x8
+
+#define CS4265_ADC_CTL2				0x9
+
+#define CS4265_DAC_CHA_VOL			0xA
+#define CS4265_DAC_CHB_VOL			0xB
+
+#define CS4265_DAC_CTL2				0xC
+
+#define CS4265_INT_STATUS			0xD
+#define CS4265_INT_MASK				0xE
+#define CS4265_STATUS_MODE_MSB			0xF
+#define CS4265_STATUS_MODE_LSB			0x10
+
+#define CS4265_SPDIF_CTL1			0x11
+
+#define CS4265_SPDIF_CTL2			0x12
+#define CS4265_SPDIF_CTL2_MUTE			(1 << 4)
+#define CS4265_SPDIF_CTL2_DIF			(3 << 6)
+
+#define CS4265_C_DATA_BUFF			0x13
+#define CS4265_MAX_REGISTER			0x2A
+
+#endif