Browse Source

Merge remote-tracking branches 'asoc/topic/sigmadsp', 'asoc/topic/sirf', 'asoc/topic/spdif', 'asoc/topic/tas2552' and 'asoc/topic/tas5086' into asoc-next

Mark Brown 11 years ago

+ 27 - 0
Documentation/devicetree/bindings/sound/sirf-usp.txt

@@ -0,0 +1,27 @@
+* SiRF SoC USP module
+
+Required properties:
+- compatible: "sirf,prima2-usp-pcm"
+- reg: Base address and size entries:
+- dmas: List of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: Identifier string for each DMA request line in the dmas property.
+  These strings correspond 1:1 with the ordered pairs in dmas.
+
+  One of the DMA channels will be responsible for transmission (should be
+  named "tx") and one for reception (should be named "rx").
+
+- clocks: USP controller clock source
+- pinctrl-names: Must contain a "default" entry.
+- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
+
+Example:
+usp0: usp@b0080000 {
+	compatible = "sirf,prima2-usp-pcm";
+	reg = <0xb0080000 0x10000>;
+	clocks = <&clks 28>;
+	dmas = <&dmac1 1>, <&dmac1 2>;
+	dma-names = "rx", "tx";
+	pinctrl-names = "default";
+	pinctrl-0 = <&usp0_only_utfs_pins_a>;
+};
+

+ 26 - 0
Documentation/devicetree/bindings/sound/tas2552.txt

@@ -0,0 +1,26 @@
+Texas Instruments - tas2552 Codec module
+
+The tas2552 serial control bus communicates through I2C protocols
+
+Required properties:
+	- compatible - One of:
+		"ti,tas2552" - TAS2552
+	- reg -  I2C slave address
+	- supply-*: Required supply regulators are:
+		"vbat"		battery voltage
+		"iovdd"		I/O Voltage
+		"avdd"		Analog DAC Voltage
+
+Optional properties:
+	- enable-gpio - gpio pin to enable/disable the device
+
+Example:
+
+tas2552: tas2552@41 {
+	compatible = "ti,tas2552";
+	reg = <0x41>;
+	enable-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
+};
+
+For more product information please see the link below:
+http://www.ti.com/product/TAS2552

+ 5 - 0
Documentation/devicetree/bindings/sound/ti,tas5086.txt

@@ -31,6 +31,9 @@ Optional properties:
 
 			Most systems should not set any of these properties.
 
+ - avdd-supply:         Power supply for AVDD, providing 3.3V
+ - dvdd-supply:         Power supply for DVDD, providing 3.3V
+
 Examples:
 
 	i2c_bus {
@@ -39,5 +42,7 @@ Examples:
 			reg = <0x1b>;
 			reset-gpio = <&gpio 23 0>;
 			ti,charge-period = <156000>;
+			avdd-supply = <&vdd_3v3_reg>;
+			dvdd-supply = <&vdd_3v3_reg>;
 		};
 	};

+ 25 - 0
include/sound/tas2552-plat.h

@@ -0,0 +1,25 @@
+/*
+ * TAS2552 driver platform header
+ *
+ * Copyright (C) 2014 Texas Instruments Inc.
+ *
+ * Author: Dan Murphy <dmurphy@ti.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.
+ *
+ * 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.
+ */
+
+#ifndef TAS2552_PLAT_H
+#define TAS2552_PLAT_H
+
+struct tas2552_platform_data {
+	int enable_gpio;
+};
+
+#endif

+ 5 - 0
sound/soc/codecs/Kconfig

@@ -94,6 +94,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_STA350 if I2C
 	select SND_SOC_STA529 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+	select SND_SOC_TAS2552 if I2C
 	select SND_SOC_TAS5086 if I2C
 	select SND_SOC_TLV320AIC23_I2C if I2C
 	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
@@ -539,6 +540,10 @@ config SND_SOC_STA529
 config SND_SOC_STAC9766
 	tristate
 
+config SND_SOC_TAS2552
+	tristate "Texas Instruments TAS2552 Mono Audio amplifier"
+	depends on I2C
+
 config SND_SOC_TAS5086
 	tristate "Texas Instruments TAS5086 speaker amplifier"
 	depends on I2C

+ 2 - 0
sound/soc/codecs/Makefile

@@ -165,6 +165,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
+snd-soc-tas2552-objs := tas2552.o
 
 obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o
@@ -261,6 +262,7 @@ obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o

+ 2 - 2
sound/soc/codecs/sirf-audio-codec.c

@@ -471,8 +471,8 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, mem_res);
-	if (base == NULL)
-		return -ENOMEM;
+	if (IS_ERR(base))
+		return PTR_ERR(base);
 
 	sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
 					    &sirf_audio_codec_regmap_config);

+ 1 - 1
sound/soc/codecs/spdif_transmitter.c

@@ -24,7 +24,7 @@
 
 #define DRV_NAME "spdif-dit"
 
-#define STUB_RATES	SNDRV_PCM_RATE_8000_96000
+#define STUB_RATES	SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE)

+ 544 - 0
sound/soc/codecs/tas2552.c

@@ -0,0 +1,544 @@
+/*
+ * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/tas2552-plat.h>
+
+#include "tas2552.h"
+
+static struct reg_default tas2552_reg_defs[] = {
+	{TAS2552_CFG_1, 0x22},
+	{TAS2552_CFG_3, 0x80},
+	{TAS2552_DOUT, 0x00},
+	{TAS2552_OUTPUT_DATA, 0xc0},
+	{TAS2552_PDM_CFG, 0x01},
+	{TAS2552_PGA_GAIN, 0x00},
+	{TAS2552_BOOST_PT_CTRL, 0x0f},
+	{TAS2552_RESERVED_0D, 0x00},
+	{TAS2552_LIMIT_RATE_HYS, 0x08},
+	{TAS2552_CFG_2, 0xef},
+	{TAS2552_SER_CTRL_1, 0x00},
+	{TAS2552_SER_CTRL_2, 0x00},
+	{TAS2552_PLL_CTRL_1, 0x10},
+	{TAS2552_PLL_CTRL_2, 0x00},
+	{TAS2552_PLL_CTRL_3, 0x00},
+	{TAS2552_BTIP, 0x8f},
+	{TAS2552_BTS_CTRL, 0x80},
+	{TAS2552_LIMIT_RELEASE, 0x04},
+	{TAS2552_LIMIT_INT_COUNT, 0x00},
+	{TAS2552_EDGE_RATE_CTRL, 0x40},
+	{TAS2552_VBAT_DATA, 0x00},
+};
+
+#define TAS2552_NUM_SUPPLIES	3
+static const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = {
+	"vbat",		/* vbat voltage */
+	"iovdd",	/* I/O Voltage */
+	"avdd",		/* Analog DAC Voltage */
+};
+
+struct tas2552_data {
+	struct snd_soc_codec *codec;
+	struct regmap *regmap;
+	struct i2c_client *tas2552_client;
+	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
+	struct gpio_desc *enable_gpio;
+	unsigned char regs[TAS2552_VBAT_DATA];
+	unsigned int mclk;
+};
+
+static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
+{
+	u8 cfg1_reg;
+
+	if (sw_shutdown)
+		cfg1_reg = 0;
+	else
+		cfg1_reg = TAS2552_SWS_MASK;
+
+	snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
+						 TAS2552_SWS_MASK, cfg1_reg);
+}
+
+static int tas2552_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 tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	int sample_rate, pll_clk;
+	int d;
+	u8 p, j;
+
+	/* Turn on Class D amplifier */
+	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK,
+						TAS2552_CLASSD_EN);
+
+	if (!tas2552->mclk)
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
+
+	if (tas2552->mclk == TAS2552_245MHZ_CLK ||
+		tas2552->mclk == TAS2552_225MHZ_CLK) {
+		/* By pass the PLL configuration */
+		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
+				    TAS2552_PLL_BYPASS_MASK,
+				    TAS2552_PLL_BYPASS);
+	} else {
+		/* Fill in the PLL control registers for J & D
+		 * PLL_CLK = (.5 * freq * J.D) / 2^p
+		 * Need to fill in J and D here based on incoming freq
+		 */
+		p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
+		p = (p >> 7);
+		sample_rate = params_rate(params);
+
+		if (sample_rate == 48000)
+			pll_clk = TAS2552_245MHZ_CLK;
+		else if (sample_rate == 44100)
+			pll_clk = TAS2552_225MHZ_CLK;
+		else {
+			dev_vdbg(codec->dev, "Substream sample rate is not found %i\n",
+					params_rate(params));
+			return -EINVAL;
+		}
+
+		j = (pll_clk * 2 * (1 << p)) / tas2552->mclk;
+		d = (pll_clk * 2 * (1 << p)) % tas2552->mclk;
+
+		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
+				TAS2552_PLL_J_MASK, j);
+		snd_soc_write(codec, TAS2552_PLL_CTRL_2,
+					(d >> 7) & TAS2552_PLL_D_UPPER_MASK);
+		snd_soc_write(codec, TAS2552_PLL_CTRL_3,
+				d & TAS2552_PLL_D_LOWER_MASK);
+
+	}
+
+	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
+						TAS2552_PLL_ENABLE);
+
+	return 0;
+}
+
+static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u8 serial_format;
+	u8 serial_control_mask;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		serial_format = 0x00;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		serial_format = TAS2552_WORD_CLK_MASK;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		serial_format = TAS2552_BIT_CLK_MASK;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK);
+		break;
+	default:
+		dev_vdbg(codec->dev, "DAI Format master is not found\n");
+		return -EINVAL;
+	}
+
+	serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		serial_format &= TAS2552_DAIFMT_I2S_MASK;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		serial_format |= TAS2552_DAIFMT_DSP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		serial_format |= TAS2552_DAIFMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		serial_format |= TAS2552_DAIFMT_LEFT_J;
+		break;
+	default:
+		dev_vdbg(codec->dev, "DAI Format is not found\n");
+		return -EINVAL;
+	}
+
+	if (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
+		serial_control_mask |= TAS2552_DATA_FORMAT_MASK;
+
+	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask,
+						serial_format);
+
+	return 0;
+}
+
+static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+
+	tas2552->mclk = freq;
+
+	return 0;
+}
+
+static int tas2552_mute(struct snd_soc_dai *dai, int mute)
+{
+	u8 cfg1_reg;
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute)
+		cfg1_reg = TAS2552_MUTE_MASK;
+	else
+		cfg1_reg = ~TAS2552_MUTE_MASK;
+
+	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int tas2552_runtime_suspend(struct device *dev)
+{
+	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+
+	tas2552_sw_shutdown(tas2552, 0);
+
+	regcache_cache_only(tas2552->regmap, true);
+	regcache_mark_dirty(tas2552->regmap);
+
+	if (tas2552->enable_gpio)
+		gpiod_set_value(tas2552->enable_gpio, 0);
+
+	return 0;
+}
+
+static int tas2552_runtime_resume(struct device *dev)
+{
+	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+
+	if (tas2552->enable_gpio)
+		gpiod_set_value(tas2552->enable_gpio, 1);
+
+	tas2552_sw_shutdown(tas2552, 1);
+
+	regcache_cache_only(tas2552->regmap, false);
+	regcache_sync(tas2552->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops tas2552_pm = {
+	SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume,
+			   NULL)
+};
+
+static void tas2552_shutdown(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
+}
+
+static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
+	.hw_params	= tas2552_hw_params,
+	.set_sysclk	= tas2552_set_dai_sysclk,
+	.set_fmt	= tas2552_set_dai_fmt,
+	.shutdown	= tas2552_shutdown,
+	.digital_mute = tas2552_mute,
+};
+
+/* Formats supported by TAS2552 driver. */
+#define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/* TAS2552 dai structure. */
+static struct snd_soc_dai_driver tas2552_dai[] = {
+	{
+		.name = "tas2552-amplifier",
+		.playback = {
+			.stream_name = "Speaker",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = TAS2552_FORMATS,
+		},
+		.ops = &tas2552_speaker_dai_ops,
+	},
+};
+
+/*
+ * DAC digital volumes. From -7 to 24 dB in 1 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24);
+
+static const struct snd_kcontrol_new tas2552_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
+			 TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
+};
+
+static const struct reg_default tas2552_init_regs[] = {
+	{ TAS2552_RESERVED_0D, 0xc0 },
+};
+
+static int tas2552_codec_probe(struct snd_soc_codec *codec)
+{
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	tas2552->codec = codec;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
+				    tas2552->supplies);
+
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (tas2552->enable_gpio)
+		gpiod_set_value(tas2552->enable_gpio, 1);
+
+	ret = pm_runtime_get_sync(codec->dev);
+	if (ret < 0) {
+		dev_err(codec->dev, "Enabling device failed: %d\n",
+			ret);
+		goto probe_fail;
+	}
+
+	snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK |
+				TAS2552_PLL_SRC_BCLK);
+	snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
+				TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
+	snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
+	snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
+	snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL);
+	snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
+				TAS2552_APT_THRESH_2_1_7);
+
+	ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs,
+					    ARRAY_SIZE(tas2552_init_regs));
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to write init registers: %d\n",
+			ret);
+		goto patch_fail;
+	}
+
+	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN |
+				  TAS2552_BOOST_EN | TAS2552_APT_EN |
+				  TAS2552_LIM_EN);
+	return 0;
+
+patch_fail:
+	pm_runtime_put(codec->dev);
+probe_fail:
+	if (tas2552->enable_gpio)
+		gpiod_set_value(tas2552->enable_gpio, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
+					tas2552->supplies);
+	return -EIO;
+}
+
+static int tas2552_codec_remove(struct snd_soc_codec *codec)
+{
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+
+	pm_runtime_put(codec->dev);
+
+	if (tas2552->enable_gpio)
+		gpiod_set_value(tas2552->enable_gpio, 0);
+
+	return 0;
+};
+
+#ifdef CONFIG_PM
+static int tas2552_suspend(struct snd_soc_codec *codec)
+{
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
+					tas2552->supplies);
+
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to disable supplies: %d\n",
+			ret);
+	return 0;
+}
+
+static int tas2552_resume(struct snd_soc_codec *codec)
+{
+	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
+				    tas2552->supplies);
+
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable supplies: %d\n",
+			ret);
+	}
+
+	return 0;
+}
+#else
+#define tas2552_suspend NULL
+#define tas2552_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
+	.probe = tas2552_codec_probe,
+	.remove = tas2552_codec_remove,
+	.suspend =	tas2552_suspend,
+	.resume = tas2552_resume,
+	.controls = tas2552_snd_controls,
+	.num_controls = ARRAY_SIZE(tas2552_snd_controls),
+};
+
+static const struct regmap_config tas2552_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = TAS2552_MAX_REG,
+	.reg_defaults = tas2552_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(tas2552_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int tas2552_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct device *dev;
+	struct tas2552_data *data;
+	int ret;
+	int i;
+
+	dev = &client->dev;
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	data->enable_gpio = devm_gpiod_get(dev, "enable");
+	if (IS_ERR(data->enable_gpio)) {
+		ret = PTR_ERR(data->enable_gpio);
+		if (ret != -ENOENT && ret != -ENOSYS)
+			return ret;
+
+		data->enable_gpio = NULL;
+	} else {
+		gpiod_direction_output(data->enable_gpio, 0);
+	}
+
+	data->tas2552_client = client;
+	data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		ret = PTR_ERR(data->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+		data->supplies[i].supply = tas2552_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+				      data->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_enable(&client->dev);
+	pm_runtime_mark_last_busy(&client->dev);
+	pm_runtime_put_sync_autosuspend(&client->dev);
+
+	dev_set_drvdata(&client->dev, data);
+
+	ret = snd_soc_register_codec(&client->dev,
+				      &soc_codec_dev_tas2552,
+				      tas2552_dai, ARRAY_SIZE(tas2552_dai));
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+
+	return ret;
+}
+
+static int tas2552_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id tas2552_id[] = {
+	{ "tas2552", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas2552_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tas2552_of_match[] = {
+	{ .compatible = "ti,tas2552", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tas2552_of_match);
+#endif
+
+static struct i2c_driver tas2552_i2c_driver = {
+	.driver = {
+		.name = "tas2552",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(tas2552_of_match),
+		.pm = &tas2552_pm,
+	},
+	.probe = tas2552_probe,
+	.remove = tas2552_i2c_remove,
+	.id_table = tas2552_id,
+};
+
+module_i2c_driver(tas2552_i2c_driver);
+
+MODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>");
+MODULE_DESCRIPTION("TAS2552 Audio amplifier driver");
+MODULE_LICENSE("GPL");

+ 129 - 0
sound/soc/codecs/tas2552.h

@@ -0,0 +1,129 @@
+/*
+ * tas2552.h - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.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.
+ *
+ * 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.
+ */
+
+#ifndef __TAS2552_H__
+#define __TAS2552_H__
+
+/* Register Address Map */
+#define TAS2552_DEVICE_STATUS	0x00
+#define TAS2552_CFG_1			0x01
+#define TAS2552_CFG_2			0x02
+#define TAS2552_CFG_3			0x03
+#define TAS2552_DOUT			0x04
+#define TAS2552_SER_CTRL_1		0x05
+#define TAS2552_SER_CTRL_2		0x06
+#define TAS2552_OUTPUT_DATA		0x07
+#define TAS2552_PLL_CTRL_1		0x08
+#define TAS2552_PLL_CTRL_2		0x09
+#define TAS2552_PLL_CTRL_3		0x0a
+#define TAS2552_BTIP			0x0b
+#define TAS2552_BTS_CTRL		0x0c
+#define TAS2552_RESERVED_0D		0x0d
+#define TAS2552_LIMIT_RATE_HYS	0x0e
+#define TAS2552_LIMIT_RELEASE	0x0f
+#define TAS2552_LIMIT_INT_COUNT	0x10
+#define TAS2552_PDM_CFG			0x11
+#define TAS2552_PGA_GAIN		0x12
+#define TAS2552_EDGE_RATE_CTRL	0x13
+#define TAS2552_BOOST_PT_CTRL	0x14
+#define TAS2552_VER_NUM			0x16
+#define TAS2552_VBAT_DATA		0x19
+#define TAS2552_MAX_REG			0x20
+
+/* CFG1 Register Masks */
+#define TAS2552_MUTE_MASK		(1 << 2)
+#define TAS2552_SWS_MASK		(1 << 1)
+#define TAS2552_WCLK_MASK		0x07
+#define TAS2552_CLASSD_EN_MASK	(1 << 7)
+
+/* CFG2 Register Masks */
+#define TAS2552_CLASSD_EN		(1 << 7)
+#define TAS2552_BOOST_EN		(1 << 6)
+#define TAS2552_APT_EN			(1 << 5)
+#define TAS2552_PLL_ENABLE		(1 << 3)
+#define TAS2552_LIM_EN			(1 << 2)
+#define TAS2552_IVSENSE_EN		(1 << 1)
+
+/* CFG3 Register Masks */
+#define TAS2552_WORD_CLK_MASK		(1 << 7)
+#define TAS2552_BIT_CLK_MASK		(1 << 6)
+#define TAS2552_DATA_FORMAT_MASK	(0x11 << 2)
+
+#define TAS2552_DAIFMT_I2S_MASK		0xf3
+#define TAS2552_DAIFMT_DSP			(1 << 3)
+#define TAS2552_DAIFMT_RIGHT_J		(1 << 4)
+#define TAS2552_DAIFMT_LEFT_J		(0x11 << 3)
+
+#define TAS2552_PLL_SRC_MCLK	0x00
+#define TAS2552_PLL_SRC_BCLK	(1 << 3)
+#define TAS2552_PLL_SRC_IVCLKIN	(1 << 4)
+#define TAS2552_PLL_SRC_1_8_FIXED (0x11 << 3)
+
+#define TAS2552_DIN_SRC_SEL_MUTED	0x00
+#define TAS2552_DIN_SRC_SEL_LEFT	(1 << 4)
+#define TAS2552_DIN_SRC_SEL_RIGHT	(1 << 5)
+#define TAS2552_DIN_SRC_SEL_AVG_L_R	(0x11 << 4)
+
+#define TAS2552_PDM_IN_SEL		(1 << 5)
+#define TAS2552_I2S_OUT_SEL		(1 << 6)
+#define TAS2552_ANALOG_IN_SEL	(1 << 7)
+
+/* CFG3 WCLK Dividers */
+#define TAS2552_8KHZ		0x00
+#define TAS2552_11_12KHZ	(1 << 1)
+#define TAS2552_16KHZ		(1 << 2)
+#define TAS2552_22_24KHZ	(1 << 3)
+#define TAS2552_32KHZ		(1 << 4)
+#define TAS2552_44_48KHZ	(1 << 5)
+#define TAS2552_88_96KHZ	(1 << 6)
+#define TAS2552_176_192KHZ	(1 << 7)
+
+/* OUTPUT_DATA register */
+#define TAS2552_PDM_DATA_I		0x00
+#define TAS2552_PDM_DATA_V		(1 << 6)
+#define TAS2552_PDM_DATA_I_V	(1 << 7)
+#define TAS2552_PDM_DATA_V_I	(0x11 << 6)
+
+/* PDM CFG Register */
+#define TAS2552_PDM_DATA_ES_RISE 0x4
+
+#define TAS2552_PDM_PLL_CLK_SEL 0x00
+#define TAS2552_PDM_IV_CLK_SEL	(1 << 1)
+#define TAS2552_PDM_BCLK_SEL	(1 << 2)
+#define TAS2552_PDM_MCLK_SEL	(1 << 3)
+
+/* Boost pass-through register */
+#define TAS2552_APT_DELAY_50	0x00
+#define TAS2552_APT_DELAY_75	(1 << 1)
+#define TAS2552_APT_DELAY_125	(1 << 2)
+#define TAS2552_APT_DELAY_200	(1 << 3)
+
+#define TAS2552_APT_THRESH_2_5		0x00
+#define TAS2552_APT_THRESH_1_7		(1 << 3)
+#define TAS2552_APT_THRESH_1_4_1_1	(1 << 4)
+#define TAS2552_APT_THRESH_2_1_7	(0x11 << 2)
+
+/* PLL Control Register */
+#define TAS2552_245MHZ_CLK			24576000
+#define TAS2552_225MHZ_CLK			22579200
+#define TAS2552_PLL_J_MASK			0x7f
+#define TAS2552_PLL_D_UPPER_MASK	0x3f
+#define TAS2552_PLL_D_LOWER_MASK	0xff
+#define TAS2552_PLL_BYPASS_MASK		0x80
+#define TAS2552_PLL_BYPASS			0x80
+
+#endif

+ 58 - 9
sound/soc/codecs/tas5086.c

@@ -36,6 +36,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -240,6 +241,10 @@ static int tas5086_reg_read(void *context, unsigned int reg,
 	return 0;
 }
 
+static const char * const supply_names[] = {
+	"dvdd", "avdd"
+};
+
 struct tas5086_private {
 	struct regmap	*regmap;
 	unsigned int	mclk, sclk;
@@ -251,6 +256,7 @@ struct tas5086_private {
 	int		rate;
 	/* GPIO driving Reset pin, if any */
 	int		gpio_nreset;
+	struct		regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
 static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
@@ -773,6 +779,8 @@ static int tas5086_soc_suspend(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
 	return 0;
 }
 
@@ -781,6 +789,10 @@ static int tas5086_soc_resume(struct snd_soc_codec *codec)
 	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 	int ret;
 
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0)
+		return ret;
+
 	tas5086_reset(priv);
 	regcache_mark_dirty(priv->regmap);
 
@@ -812,6 +824,12 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 	int i, ret;
 
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
 	priv->pwm_start_mid_z = 0;
 	priv->charge_period = 1300000; /* hardware default is 1300 ms */
 
@@ -832,16 +850,22 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 		}
 	}
 
+	tas5086_reset(priv);
 	ret = tas5086_init(codec->dev, priv);
 	if (ret < 0)
-		return ret;
+		goto exit_disable_regulators;
 
 	/* set master volume to 0 dB */
 	ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
 	if (ret < 0)
-		return ret;
+		goto exit_disable_regulators;
 
 	return 0;
+
+exit_disable_regulators:
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
+	return ret;
 }
 
 static int tas5086_remove(struct snd_soc_codec *codec)
@@ -852,6 +876,8 @@ static int tas5086_remove(struct snd_soc_codec *codec)
 		/* Set codec to the reset state */
 		gpio_set_value(priv->gpio_nreset, 0);
 
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
 	return 0;
 };
 
@@ -900,6 +926,16 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
 	if (!priv)
 		return -ENOMEM;
 
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+				      priv->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
 	priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);
 	if (IS_ERR(priv->regmap)) {
 		ret = PTR_ERR(priv->regmap);
@@ -919,21 +955,34 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
 			gpio_nreset = -EINVAL;
 
 	priv->gpio_nreset = gpio_nreset;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
 	tas5086_reset(priv);
 
 	/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
 	ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
-	if (ret < 0)
-		return ret;
-
-	if (i != 0x3) {
+	if (ret == 0 && i != 0x3) {
 		dev_err(dev,
 			"Failed to identify TAS5086 codec (got %02x)\n", i);
-		return -ENODEV;
+		ret = -ENODEV;
 	}
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
-		&tas5086_dai, 1);
+	/*
+	 * The chip has been identified, so we can turn off the power
+	 * again until the dai link is set up.
+	 */
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
+	if (ret == 0)
+		ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
+					     &tas5086_dai, 1);
+
+	return ret;
 }
 
 static int tas5086_i2c_remove(struct i2c_client *i2c)

+ 6 - 0
sound/soc/sirf/Kconfig

@@ -12,3 +12,9 @@ config SND_SOC_SIRF_AUDIO
 config SND_SOC_SIRF_AUDIO_PORT
 	select REGMAP_MMIO
 	tristate
+
+config SND_SOC_SIRF_USP
+	tristate "SoC Audio (I2S protocol) for SiRF SoC USP interface"
+	depends on SND_SOC_SIRF
+	select REGMAP_MMIO
+	tristate

+ 2 - 0
sound/soc/sirf/Makefile

@@ -1,5 +1,7 @@
 snd-soc-sirf-audio-objs := sirf-audio.o
 snd-soc-sirf-audio-port-objs := sirf-audio-port.o
+snd-soc-sirf-usp-objs := sirf-usp.o
 
 obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
 obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
+obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o

+ 415 - 0
sound/soc/sirf/sirf-usp.c

@@ -0,0 +1,415 @@
+/*
+ * SiRF USP in I2S/DSP mode
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-usp.h"
+
+struct sirf_usp {
+	struct regmap *regmap;
+	struct clk *clk;
+	u32 mode1_reg;
+	u32 mode2_reg;
+	int daifmt_format;
+	struct snd_dmaengine_dai_dma_data playback_dma_data;
+	struct snd_dmaengine_dai_dma_data capture_dma_data;
+};
+
+static void sirf_usp_tx_enable(struct sirf_usp *usp)
+{
+	regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
+		USP_TX_FIFO_RESET, USP_TX_FIFO_RESET);
+	regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
+
+	regmap_update_bits(usp->regmap, USP_TX_FIFO_OP,
+		USP_TX_FIFO_START, USP_TX_FIFO_START);
+
+	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
+		USP_TX_ENA, USP_TX_ENA);
+}
+
+static void sirf_usp_tx_disable(struct sirf_usp *usp)
+{
+	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
+		USP_TX_ENA, ~USP_TX_ENA);
+	/* FIFO stop */
+	regmap_write(usp->regmap, USP_TX_FIFO_OP, 0);
+}
+
+static void sirf_usp_rx_enable(struct sirf_usp *usp)
+{
+	regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
+		USP_RX_FIFO_RESET, USP_RX_FIFO_RESET);
+	regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
+
+	regmap_update_bits(usp->regmap, USP_RX_FIFO_OP,
+		USP_RX_FIFO_START, USP_RX_FIFO_START);
+
+	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
+		USP_RX_ENA, USP_RX_ENA);
+}
+
+static void sirf_usp_rx_disable(struct sirf_usp *usp)
+{
+	regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE,
+		USP_RX_ENA, ~USP_RX_ENA);
+	/* FIFO stop */
+	regmap_write(usp->regmap, USP_RX_FIFO_OP, 0);
+}
+
+static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
+{
+	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
+	snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data,
+			&usp->capture_dma_data);
+	return 0;
+}
+
+static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
+		unsigned int fmt)
+{
+	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		dev_err(dai->dev, "Only CBM and CFM supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_DSP_A:
+		usp->daifmt_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		break;
+	default:
+		dev_err(dai->dev, "Only I2S and DSP_A format supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void sirf_usp_i2s_init(struct sirf_usp *usp)
+{
+	/* Configure RISC mode */
+	regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE,
+		USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL);
+
+	/*
+	 * Configure DMA IO Length register
+	 * Set no limit, USP can receive data continuously until it is diabled
+	 */
+	regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0);
+	regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0);
+
+	/* Configure Mode2 register */
+	regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) |
+		(0 << USP_TXD_DELAY_LEN_OFFSET) |
+		USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE);
+
+	/* Configure Mode1 register */
+	regmap_write(usp->regmap, USP_MODE1,
+		USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING |
+		USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 |
+		USP_TX_UFLOW_REPEAT_ZERO | USP_CLOCK_MODE_SLAVE);
+
+	/* Configure RX DMA IO Control register */
+	regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0);
+
+	/* Congiure RX FIFO Control register */
+	regmap_write(usp->regmap, USP_RX_FIFO_CTRL,
+		(USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) |
+		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET));
+
+	/* Congiure RX FIFO Level Check register */
+	regmap_write(usp->regmap, USP_RX_FIFO_LEVEL_CHK,
+		RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B));
+
+	/* Configure TX DMA IO Control register*/
+	regmap_write(usp->regmap, USP_TX_DMA_IO_CTRL, 0);
+
+	/* Configure TX FIFO Control register */
+	regmap_write(usp->regmap, USP_TX_FIFO_CTRL,
+		(USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) |
+		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET));
+	/* Congiure TX FIFO Level Check register */
+	regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK,
+		TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04));
+}
+
+static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
+	u32 data_len, frame_len, shifter_len;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		data_len = 16;
+		frame_len = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		data_len = 24;
+		frame_len = 32;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		data_len = 24;
+		frame_len = 24;
+		break;
+	default:
+		dev_err(dai->dev, "Format unsupported\n");
+		return -EINVAL;
+	}
+
+	shifter_len = data_len;
+
+	switch (usp->daifmt_format) {
+	case SND_SOC_DAIFMT_I2S:
+		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
+			USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
+			USP_I2S_SYNC_CHG, 0);
+		frame_len = data_len * params_channels(params);
+		data_len = frame_len;
+		break;
+	default:
+		dev_err(dai->dev, "Only support I2S and DSP_A mode\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
+			USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
+			| USP_TXC_SHIFTER_LEN_MASK | USP_TXC_SLAVE_CLK_SAMPLE,
+			((data_len - 1) << USP_TXC_DATA_LEN_OFFSET)
+			| ((frame_len - 1) << USP_TXC_FRAME_LEN_OFFSET)
+			| ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET)
+			| USP_TXC_SLAVE_CLK_SAMPLE);
+	else
+		regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
+			USP_RXC_DATA_LEN_MASK | USP_RXC_FRAME_LEN_MASK
+			| USP_RXC_SHIFTER_LEN_MASK | USP_SINGLE_SYNC_MODE,
+			((data_len - 1) << USP_RXC_DATA_LEN_OFFSET)
+			| ((frame_len - 1) << USP_RXC_FRAME_LEN_OFFSET)
+			| ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET)
+			| USP_SINGLE_SYNC_MODE);
+
+	return 0;
+}
+
+static int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sirf_usp_tx_enable(usp);
+		else
+			sirf_usp_rx_enable(usp);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sirf_usp_tx_disable(usp);
+		else
+			sirf_usp_rx_disable(usp);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = {
+	.trigger = sirf_usp_pcm_trigger,
+	.set_fmt = sirf_usp_pcm_set_dai_fmt,
+	.hw_params = sirf_usp_pcm_hw_params,
+};
+
+static struct snd_soc_dai_driver sirf_usp_pcm_dai = {
+	.probe = sirf_usp_pcm_dai_probe,
+	.name = "sirf-usp-pcm",
+	.id = 0,
+	.playback = {
+		.stream_name = "SiRF USP PCM Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S24_3LE,
+	},
+	.capture = {
+		.stream_name = "SiRF USP PCM Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S24_3LE,
+	},
+	.ops = &sirf_usp_pcm_dai_ops,
+};
+
+static int sirf_usp_pcm_runtime_suspend(struct device *dev)
+{
+	struct sirf_usp *usp = dev_get_drvdata(dev);
+	clk_disable_unprepare(usp->clk);
+	return 0;
+}
+
+static int sirf_usp_pcm_runtime_resume(struct device *dev)
+{
+	struct sirf_usp *usp = dev_get_drvdata(dev);
+	int ret;
+	ret = clk_prepare_enable(usp->clk);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+	sirf_usp_i2s_init(usp);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_usp_pcm_suspend(struct device *dev)
+{
+	struct sirf_usp *usp = dev_get_drvdata(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		regmap_read(usp->regmap, USP_MODE1, &usp->mode1_reg);
+		regmap_read(usp->regmap, USP_MODE2, &usp->mode2_reg);
+		sirf_usp_pcm_runtime_suspend(dev);
+	}
+	return 0;
+}
+
+static int sirf_usp_pcm_resume(struct device *dev)
+{
+	struct sirf_usp *usp = dev_get_drvdata(dev);
+	int ret;
+
+	if (!pm_runtime_status_suspended(dev)) {
+		ret = sirf_usp_pcm_runtime_resume(dev);
+		if (ret)
+			return ret;
+		regmap_write(usp->regmap, USP_MODE1, usp->mode1_reg);
+		regmap_write(usp->regmap, USP_MODE2, usp->mode2_reg);
+	}
+	return 0;
+}
+#endif
+
+static const struct snd_soc_component_driver sirf_usp_component = {
+	.name		= "sirf-usp",
+};
+
+static const struct regmap_config sirf_usp_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = USP_RX_FIFO_DATA,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sirf_usp_pcm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sirf_usp *usp;
+	void __iomem *base;
+	struct resource *mem_res;
+
+	usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp),
+			GFP_KERNEL);
+	if (!usp)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, usp);
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap(&pdev->dev, mem_res->start,
+		resource_size(mem_res));
+	if (base == NULL)
+		return -ENOMEM;
+	usp->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					    &sirf_usp_regmap_config);
+	if (IS_ERR(usp->regmap))
+		return PTR_ERR(usp->regmap);
+
+	usp->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(usp->clk)) {
+		dev_err(&pdev->dev, "Get clock failed.\n");
+		return PTR_ERR(usp->clk);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = sirf_usp_pcm_runtime_resume(&pdev->dev);
+		if (ret)
+			return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component,
+		&sirf_usp_pcm_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
+		return ret;
+	}
+	return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+}
+
+static int sirf_usp_pcm_remove(struct platform_device *pdev)
+{
+	if (!pm_runtime_enabled(&pdev->dev))
+		sirf_usp_pcm_runtime_suspend(&pdev->dev);
+	else
+		pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id sirf_usp_pcm_of_match[] = {
+	{ .compatible = "sirf,prima2-usp-pcm", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_usp_pcm_of_match);
+
+static const struct dev_pm_ops sirf_usp_pcm_pm_ops = {
+	SET_RUNTIME_PM_OPS(sirf_usp_pcm_runtime_suspend,
+		sirf_usp_pcm_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(sirf_usp_pcm_suspend, sirf_usp_pcm_resume)
+};
+
+static struct platform_driver sirf_usp_pcm_driver = {
+	.driver = {
+		.name = "sirf-usp-pcm",
+		.owner = THIS_MODULE,
+		.of_match_table = sirf_usp_pcm_of_match,
+		.pm = &sirf_usp_pcm_pm_ops,
+	},
+	.probe = sirf_usp_pcm_probe,
+	.remove = sirf_usp_pcm_remove,
+};
+
+module_platform_driver(sirf_usp_pcm_driver);
+
+MODULE_DESCRIPTION("SiRF SoC USP PCM bus driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");

+ 293 - 0
sound/soc/sirf/sirf-usp.h

@@ -0,0 +1,293 @@
+/*
+ * arch/arm/mach-prima2/include/mach/sirfsoc_usp.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_USP_H
+#define _SIRF_USP_H
+
+/* USP Registers */
+#define USP_MODE1		0x00
+#define USP_MODE2		0x04
+#define USP_TX_FRAME_CTRL	0x08
+#define USP_RX_FRAME_CTRL	0x0C
+#define USP_TX_RX_ENABLE	0x10
+#define USP_INT_ENABLE		0x14
+#define USP_INT_STATUS		0x18
+#define USP_PIN_IO_DATA		0x1C
+#define USP_RISC_DSP_MODE	0x20
+#define USP_AYSNC_PARAM_REG	0x24
+#define USP_IRDA_X_MODE_DIV	0x28
+#define USP_SM_CFG		0x2C
+#define USP_TX_DMA_IO_CTRL	0x100
+#define USP_TX_DMA_IO_LEN	0x104
+#define USP_TX_FIFO_CTRL	0x108
+#define USP_TX_FIFO_LEVEL_CHK	0x10C
+#define USP_TX_FIFO_OP		0x110
+#define USP_TX_FIFO_STATUS	0x114
+#define USP_TX_FIFO_DATA	0x118
+#define USP_RX_DMA_IO_CTRL	0x120
+#define USP_RX_DMA_IO_LEN	0x124
+#define USP_RX_FIFO_CTRL	0x128
+#define USP_RX_FIFO_LEVEL_CHK	0x12C
+#define USP_RX_FIFO_OP		0x130
+#define USP_RX_FIFO_STATUS	0x134
+#define USP_RX_FIFO_DATA	0x138
+
+/* USP MODE register-1 */
+#define USP_SYNC_MODE			0x00000001
+#define USP_CLOCK_MODE_SLAVE		0x00000002
+#define USP_LOOP_BACK_EN		0x00000004
+#define USP_HPSIR_EN			0x00000008
+#define USP_ENDIAN_CTRL_LSBF		0x00000010
+#define USP_EN				0x00000020
+#define USP_RXD_ACT_EDGE_FALLING	0x00000040
+#define USP_TXD_ACT_EDGE_FALLING	0x00000080
+#define USP_RFS_ACT_LEVEL_LOGIC1	0x00000100
+#define USP_TFS_ACT_LEVEL_LOGIC1	0x00000200
+#define USP_SCLK_IDLE_MODE_TOGGLE	0x00000400
+#define USP_SCLK_IDLE_LEVEL_LOGIC1	0x00000800
+#define USP_SCLK_PIN_MODE_IO	0x00001000
+#define USP_RFS_PIN_MODE_IO	0x00002000
+#define USP_TFS_PIN_MODE_IO	0x00004000
+#define USP_RXD_PIN_MODE_IO	0x00008000
+#define USP_TXD_PIN_MODE_IO	0x00010000
+#define USP_SCLK_IO_MODE_INPUT	0x00020000
+#define USP_RFS_IO_MODE_INPUT	0x00040000
+#define USP_TFS_IO_MODE_INPUT	0x00080000
+#define USP_RXD_IO_MODE_INPUT	0x00100000
+#define USP_TXD_IO_MODE_INPUT	0x00200000
+#define USP_IRDA_WIDTH_DIV_MASK	0x3FC00000
+#define USP_IRDA_WIDTH_DIV_OFFSET	0
+#define USP_IRDA_IDLE_LEVEL_HIGH	0x40000000
+#define USP_TX_UFLOW_REPEAT_ZERO	0x80000000
+#define USP_TX_ENDIAN_MODE		0x00000020
+#define USP_RX_ENDIAN_MODE		0x00000020
+
+/* USP Mode Register-2 */
+#define USP_RXD_DELAY_LEN_MASK		0x000000FF
+#define USP_RXD_DELAY_LEN_OFFSET	0
+
+#define USP_TXD_DELAY_LEN_MASK		0x0000FF00
+#define USP_TXD_DELAY_LEN_OFFSET	8
+
+#define USP_ENA_CTRL_MODE		0x00010000
+#define USP_FRAME_CTRL_MODE		0x00020000
+#define USP_TFS_SOURCE_MODE             0x00040000
+#define USP_TFS_MS_MODE                 0x00080000
+#define USP_CLK_DIVISOR_MASK		0x7FE00000
+#define USP_CLK_DIVISOR_OFFSET		21
+
+#define USP_TFS_CLK_SLAVE_MODE		(1<<20)
+#define USP_RFS_CLK_SLAVE_MODE		(1<<19)
+
+#define USP_IRDA_DATA_WIDTH		0x80000000
+
+/* USP Transmit Frame Control Register */
+
+#define USP_TXC_DATA_LEN_MASK		0x000000FF
+#define USP_TXC_DATA_LEN_OFFSET		0
+
+#define USP_TXC_SYNC_LEN_MASK		0x0000FF00
+#define USP_TXC_SYNC_LEN_OFFSET		8
+
+#define USP_TXC_FRAME_LEN_MASK		0x00FF0000
+#define USP_TXC_FRAME_LEN_OFFSET	16
+
+#define USP_TXC_SHIFTER_LEN_MASK	0x1F000000
+#define USP_TXC_SHIFTER_LEN_OFFSET	24
+
+#define USP_TXC_SLAVE_CLK_SAMPLE	0x20000000
+
+#define USP_TXC_CLK_DIVISOR_MASK	0xC0000000
+#define USP_TXC_CLK_DIVISOR_OFFSET	30
+
+/* USP Receive Frame Control Register */
+
+#define USP_RXC_DATA_LEN_MASK		0x000000FF
+#define USP_RXC_DATA_LEN_OFFSET		0
+
+#define USP_RXC_FRAME_LEN_MASK		0x0000FF00
+#define USP_RXC_FRAME_LEN_OFFSET	8
+
+#define USP_RXC_SHIFTER_LEN_MASK	0x001F0000
+#define USP_RXC_SHIFTER_LEN_OFFSET	16
+
+#define USP_START_EDGE_MODE	0x00800000
+#define USP_I2S_SYNC_CHG	0x00200000
+
+#define USP_RXC_CLK_DIVISOR_MASK	0x0F000000
+#define USP_RXC_CLK_DIVISOR_OFFSET	24
+#define USP_SINGLE_SYNC_MODE		0x00400000
+
+/* Tx - RX Enable Register */
+
+#define USP_RX_ENA		0x00000001
+#define USP_TX_ENA		0x00000002
+
+/* USP Interrupt Enable and status Register */
+#define USP_RX_DONE_INT			0x00000001
+#define USP_TX_DONE_INT			0x00000002
+#define USP_RX_OFLOW_INT		0x00000004
+#define USP_TX_UFLOW_INT		0x00000008
+#define USP_RX_IO_DMA_INT		0x00000010
+#define USP_TX_IO_DMA_INT		0x00000020
+#define USP_RXFIFO_FULL_INT		0x00000040
+#define USP_TXFIFO_EMPTY_INT		0x00000080
+#define USP_RXFIFO_THD_INT		0x00000100
+#define USP_TXFIFO_THD_INT		0x00000200
+#define USP_UART_FRM_ERR_INT		0x00000400
+#define USP_RX_TIMEOUT_INT		0x00000800
+#define USP_TX_ALLOUT_INT		0x00001000
+#define USP_RXD_BREAK_INT		0x00008000
+
+/* All possible TX interruots */
+#define USP_TX_INTERRUPT		(USP_TX_DONE_INT|USP_TX_UFLOW_INT|\
+					USP_TX_IO_DMA_INT|\
+					USP_TXFIFO_EMPTY_INT|\
+					USP_TXFIFO_THD_INT)
+/* All possible RX interruots */
+#define USP_RX_INTERRUPT		(USP_RX_DONE_INT|USP_RX_OFLOW_INT|\
+					USP_RX_IO_DMA_INT|\
+					USP_RXFIFO_FULL_INT|\
+					USP_RXFIFO_THD_INT|\
+					USP_RXFIFO_THD_INT|USP_RX_TIMEOUT_INT)
+
+#define USP_INT_ALL        0x1FFF
+
+/* USP Pin I/O Data Register */
+
+#define USP_RFS_PIN_VALUE_MASK	0x00000001
+#define USP_TFS_PIN_VALUE_MASK	0x00000002
+#define USP_RXD_PIN_VALUE_MASK	0x00000004
+#define USP_TXD_PIN_VALUE_MASK	0x00000008
+#define USP_SCLK_PIN_VALUE_MASK	0x00000010
+
+/* USP RISC/DSP Mode Register */
+#define USP_RISC_DSP_SEL	0x00000001
+
+/* USP ASYNC PARAMETER Register*/
+
+#define USP_ASYNC_TIMEOUT_MASK	0x0000FFFF
+#define USP_ASYNC_TIMEOUT_OFFSET	0
+#define USP_ASYNC_TIMEOUT(x)	(((x)&USP_ASYNC_TIMEOUT_MASK) \
+				<<USP_ASYNC_TIMEOUT_OFFSET)
+
+#define USP_ASYNC_DIV2_MASK		0x003F0000
+#define USP_ASYNC_DIV2_OFFSET		16
+
+/* USP TX DMA I/O MODE Register */
+#define USP_TX_MODE_IO			0x00000001
+
+/* USP TX DMA I/O Length Register */
+#define USP_TX_DATA_LEN_MASK		0xFFFFFFFF
+#define USP_TX_DATA_LEN_OFFSET		0
+
+/* USP TX FIFO Control Register */
+#define USP_TX_FIFO_WIDTH_MASK		0x00000003
+#define USP_TX_FIFO_WIDTH_OFFSET	0
+
+#define USP_TX_FIFO_THD_MASK		0x000001FC
+#define USP_TX_FIFO_THD_OFFSET		2
+
+/* USP TX FIFO Level Check Register */
+#define USP_TX_FIFO_LEVEL_CHECK_MASK	0x1F
+#define USP_TX_FIFO_SC_OFFSET	0
+#define USP_TX_FIFO_LC_OFFSET	10
+#define USP_TX_FIFO_HC_OFFSET	20
+
+#define TX_FIFO_SC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_TX_FIFO_HC_OFFSET)
+
+/* USP TX FIFO Operation Register */
+#define USP_TX_FIFO_RESET		0x00000001
+#define USP_TX_FIFO_START		0x00000002
+
+/* USP TX FIFO Status Register */
+#define USP_TX_FIFO_LEVEL_MASK		0x0000007F
+#define USP_TX_FIFO_LEVEL_OFFSET	0
+
+#define USP_TX_FIFO_FULL		0x00000080
+#define USP_TX_FIFO_EMPTY		0x00000100
+
+/* USP TX FIFO Data Register */
+#define USP_TX_FIFO_DATA_MASK		0xFFFFFFFF
+#define USP_TX_FIFO_DATA_OFFSET		0
+
+/* USP RX DMA I/O MODE Register */
+#define USP_RX_MODE_IO			0x00000001
+#define USP_RX_DMA_FLUSH		0x00000004
+
+/* USP RX DMA I/O Length Register */
+#define USP_RX_DATA_LEN_MASK		0xFFFFFFFF
+#define USP_RX_DATA_LEN_OFFSET		0
+
+/* USP RX FIFO Control Register */
+#define USP_RX_FIFO_WIDTH_MASK		0x00000003
+#define USP_RX_FIFO_WIDTH_OFFSET	0
+
+#define USP_RX_FIFO_THD_MASK		0x000001FC
+#define USP_RX_FIFO_THD_OFFSET		2
+
+/* USP RX FIFO Level Check Register */
+
+#define USP_RX_FIFO_LEVEL_CHECK_MASK	0x1F
+#define USP_RX_FIFO_SC_OFFSET	0
+#define USP_RX_FIFO_LC_OFFSET	10
+#define USP_RX_FIFO_HC_OFFSET	20
+
+#define RX_FIFO_SC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< USP_RX_FIFO_HC_OFFSET)
+
+/* USP RX FIFO Operation Register */
+#define USP_RX_FIFO_RESET		0x00000001
+#define USP_RX_FIFO_START		0x00000002
+
+/* USP RX FIFO Status Register */
+
+#define USP_RX_FIFO_LEVEL_MASK		0x0000007F
+#define USP_RX_FIFO_LEVEL_OFFSET	0
+
+#define USP_RX_FIFO_FULL		0x00000080
+#define USP_RX_FIFO_EMPTY		0x00000100
+
+/* USP RX FIFO Data Register */
+
+#define USP_RX_FIFO_DATA_MASK		0xFFFFFFFF
+#define USP_RX_FIFO_DATA_OFFSET		0
+
+/*
+ * When rx thd irq occur, sender just disable tx empty irq,
+ * Remaining data in tx fifo wil also be sent out.
+ */
+#define USP_FIFO_SIZE			128
+#define USP_TX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
+#define USP_RX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
+
+/* FIFO_WIDTH for the USP_TX_FIFO_CTRL and USP_RX_FIFO_CTRL registers */
+#define USP_FIFO_WIDTH_BYTE  0x00
+#define USP_FIFO_WIDTH_WORD  0x01
+#define USP_FIFO_WIDTH_DWORD 0x02
+
+#define USP_ASYNC_DIV2          16
+
+#define USP_PLUGOUT_RETRY_CNT	2
+
+#define USP_TX_RX_FIFO_WIDTH_DWORD    2
+
+#define SIRF_USP_DIV_MCLK	0
+
+#define SIRF_USP_I2S_TFS_SYNC	0
+#define SIRF_USP_I2S_RFS_SYNC	1
+#endif