All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Mack <zonque@gmail.com>
To: alsa-devel@alsa-project.org
Cc: Sven Neumann <s.neumann@raumfeld.com>,
	linux-arm-kernel@lists.infradead.org, zonque@gmail.com
Subject: [PATCH v2] ARM: pxa: add support for Raumfeld DDX
Date: Tue,  8 Nov 2011 11:16:09 +0100	[thread overview]
Message-ID: <1320747369-12141-1-git-send-email-zonque@gmail.com> (raw)

This new product features a STA32x codec. To support it, some rework
of the regulator initialization for the Raumfeld platform is necessary.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Cc: Mark Brown <broonie at opensource.wolfsonmicro.com>
Cc: Liam Girdwood <lrg at ti.com>
Cc: Eric Miao <eric.y.miao at gmail.com>
Cc: Sven Neumann <s.neumann@raumfeld.com>
Cc: Johannes Stezenbach <js@sig21.net>
---

 v2 of this patch has clocking fixes and superseeds the older version.

 As there are more changes in sound/soc than in arch/arm, I think it
 should best go through Mark's AsoC tree.

 arch/arm/mach-pxa/raumfeld.c |  119 +++++++++++++++++---
 sound/soc/pxa/Kconfig        |    2 +
 sound/soc/pxa/raumfeld.c     |  247 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 336 insertions(+), 32 deletions(-)

diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 7856fe4..22366ff 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -850,7 +850,7 @@ struct regulator_init_data audio_va_initdata = {
 	},
 };
 
-static struct fixed_voltage_config audio_va_config = {
+static struct fixed_voltage_config cs4270_va_config = {
 	.supply_name		= "audio_va",
 	.microvolts		= 5000000,
 	.gpio			= GPIO_AUDIO_VA_ENABLE,
@@ -859,47 +859,114 @@ static struct fixed_voltage_config audio_va_config = {
 	.init_data		= &audio_va_initdata,
 };
 
-static struct platform_device audio_va_device = {
+static struct platform_device cs4270_va_device = {
 	.name	= "reg-fixed-voltage",
 	.id	= 0,
 	.dev	= {
-		.platform_data = &audio_va_config,
+		.platform_data = &cs4270_va_config,
 	},
 };
 
 /* Dummy supplies for Codec's VD/VLC */
 
-static struct regulator_consumer_supply audio_dummy_supplies[] = {
+static struct regulator_consumer_supply cs4270_dummy_supplies[] = {
 	REGULATOR_SUPPLY("vd", "0-0048"),
 	REGULATOR_SUPPLY("vlc", "0-0048"),
 };
 
-struct regulator_init_data audio_dummy_initdata = {
-	.consumer_supplies = audio_dummy_supplies,
-	.num_consumer_supplies = ARRAY_SIZE(audio_dummy_supplies),
+struct regulator_init_data cs4270_dummy_initdata = {
+	.consumer_supplies = cs4270_dummy_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(cs4270_dummy_supplies),
 	.constraints = {
 		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 	},
 };
 
-static struct fixed_voltage_config audio_dummy_config = {
-	.supply_name		= "audio_vd",
+static struct fixed_voltage_config cs4270_dummy_config = {
+	.supply_name		= "cs4270_vd",
 	.microvolts		= 3300000,
 	.gpio			= -1,
-	.init_data		= &audio_dummy_initdata,
+	.init_data		= &cs4270_dummy_initdata,
 };
 
-static struct platform_device audio_supply_dummy_device = {
+static struct platform_device cs4270_supply_dummy_device = {
 	.name	= "reg-fixed-voltage",
 	.id	= 1,
 	.dev	= {
-		.platform_data = &audio_dummy_config,
+		.platform_data = &cs4270_dummy_config,
 	},
 };
 
-static struct platform_device *audio_regulator_devices[] = {
-	&audio_va_device,
-	&audio_supply_dummy_device,
+static struct platform_device *cs4270_regulator_devices[] = {
+	&cs4270_va_device,
+	&cs4270_supply_dummy_device,
+};
+
+/* Fixed regulator for sta32x Vdda supply
+ * 0-001a maps to the sta32x codec devname (derived from i2c bus num + addr)
+ */
+
+static struct regulator_consumer_supply sta32x_va_consumer_supply =
+	REGULATOR_SUPPLY("Vdda", "0-001a");
+
+struct regulator_init_data sta32x_va_initdata = {
+	.consumer_supplies = &sta32x_va_consumer_supply,
+	.num_consumer_supplies = 1,
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+static struct fixed_voltage_config sta32x_va_config = {
+	.supply_name		= "audio_va",
+	.microvolts		= 3300000,
+	.gpio			= GPIO_AUDIO_VA_ENABLE,
+	.enable_high		= 1,
+	.enabled_at_boot	= 0,
+	.init_data		= &sta32x_va_initdata,
+};
+
+static struct platform_device sta32x_va_device = {
+	.name	= "reg-fixed-voltage",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &sta32x_va_config,
+	},
+};
+
+/* Dummy supplies for sta32x codec's Vdd3/Vcc */
+
+static struct regulator_consumer_supply sta32x_dummy_supplies[] = {
+	REGULATOR_SUPPLY("Vdd3", "0-001a"),
+	REGULATOR_SUPPLY("Vcc", "0-001a"),
+};
+
+struct regulator_init_data sta32x_dummy_initdata = {
+	.consumer_supplies = sta32x_dummy_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(sta32x_dummy_supplies),
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+static struct fixed_voltage_config sta32x_dummy_config = {
+	.supply_name	    = "audio_vd",
+	.microvolts	     = 3300000,
+	.gpio		   = -1,
+	.init_data	      = &sta32x_dummy_initdata,
+};
+
+static struct platform_device sta32x_supply_dummy_device = {
+	.name   = "reg-fixed-voltage",
+	.id     = 1,
+	.dev    = {
+		.platform_data = &sta32x_dummy_config,
+	},
+};
+
+static struct platform_device *sta32x_regulator_devices[] = {
+	&sta32x_va_device,
+	&sta32x_supply_dummy_device,
 };
 
 /**
@@ -948,6 +1015,11 @@ static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = {
 	.addr	= 0x48,
 };
 
+static struct i2c_board_info raumfeld_ddx_i2c_board_info __initdata = {
+	.type   = "sta326",
+	.addr   = 0x1a,
+};
+
 static struct eeti_ts_platform_data eeti_ts_pdata = {
 	.irq_active_high = 1,
 };
@@ -987,7 +1059,10 @@ static void __init raumfeld_audio_init(void)
 	else
 		gpio_direction_output(GPIO_MCLK_RESET, 1);
 
-	platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices));
+	if ((system_rev & 0xff00) == 0x0400)
+		platform_add_devices(ARRAY_AND_SIZE(sta32x_regulator_devices));
+	else
+		platform_add_devices(ARRAY_AND_SIZE(cs4270_regulator_devices));
 }
 
 static void __init raumfeld_common_init(void)
@@ -1060,7 +1135,11 @@ static void __init raumfeld_connector_init(void)
 {
 	pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_connector_pin_config));
 	spi_register_board_info(ARRAY_AND_SIZE(connector_spi_devices));
-	i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+	if ((system_rev & 0xff00) == 0x0400)
+		i2c_register_board_info(0, &raumfeld_ddx_i2c_board_info, 1);
+	else
+		i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
 
 	platform_device_register(&smc91x_device);
 
@@ -1072,7 +1151,11 @@ static void __init raumfeld_speaker_init(void)
 {
 	pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_speaker_pin_config));
 	spi_register_board_info(ARRAY_AND_SIZE(speaker_spi_devices));
-	i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+	if ((system_rev & 0xff00) == 0x0400)
+		i2c_register_board_info(0, &raumfeld_ddx_i2c_board_info, 1);
+	else
+		i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
 
 	platform_device_register(&smc91x_device);
 	platform_device_register(&rotary_encoder_device);
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 33ebc46..e6db56a 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -152,6 +152,8 @@ config SND_SOC_RAUMFELD
 	select SND_PXA_SOC_SSP
 	select SND_SOC_CS4270
 	select SND_SOC_AK4104
+	select SND_SOC_STA32X
+	select SND_SOC_WM8782
 	help
 	  Say Y if you want to add support for SoC audio on Raumfeld devices
 
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 1a591f1..7d4f1bf 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
@@ -225,6 +226,175 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
 	.hw_params = raumfeld_ak4104_hw_params,
 };
 
+/* STA32X */
+static int raumfeld_sta32x_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* fixed MCLK of 11.2896MHz */
+	snd_pcm_hw_constraint_mask64(substream->runtime,
+				    SNDRV_PCM_HW_PARAM_RATE,
+				    SNDRV_PCM_RATE_44100 |
+				    SNDRV_PCM_RATE_88200 |
+				    SNDRV_PCM_RATE_176400);
+
+	/* PXA DMA cannot do zero extend for 24bit samples,
+	 * thus only 16bit (two samples packet into 32bit word)
+	 * or 32bit samples are possible
+	 */
+	snd_pcm_hw_constraint_mask64(substream->runtime,
+				    SNDRV_PCM_HW_PARAM_FORMAT,
+				    SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE |
+				    SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE);
+
+	/* we have a fixed MCLK, set it here so ALSA knows
+	 * the supported sample rates and can resample if necessary
+	 */
+	return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0);
+}
+
+static void raumfeld_sta32x_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* set freq to 0 to enable all possible codec sample rates */
+	snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
+}
+
+static int raumfeld_sta32x_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int fmt, clk = 0;
+	int ret = 0;
+
+	// fixed MCLK of 11.2896MHz
+	switch (params_rate(params)) {
+	case 44100:
+	case 88200:
+	case 176400:
+		clk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+	case SNDRV_PCM_FORMAT_S32_BE:
+		/* this enables network mode for 2 * 32bit samples */
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 0, 2, 32);
+		if (ret < 0)
+			return ret;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		/* this disables network mode */
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 0, 16);
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fmt = SND_SOC_DAIFMT_I2S |
+	      SND_SOC_DAIFMT_NB_NF |
+	      SND_SOC_DAIFMT_CBS_CFS;
+
+	/* setup the CODEC DAI */
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
+	if (ret < 0)
+		return ret;
+
+	/* setup the CPU DAI */
+	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops raumfeld_sta32x_ops = {
+	.startup = raumfeld_sta32x_startup,
+	.shutdown = raumfeld_sta32x_shutdown,
+	.hw_params = raumfeld_sta32x_hw_params,
+};
+
+/* WM8782 */
+static int raumfeld_wm8782_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int fmt, clk = 0;
+	int ret = 0;
+
+	// fixed MCLK of 11.2896MHz
+	switch (params_rate(params)) {
+	case 44100:
+		clk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fmt = SND_SOC_DAIFMT_I2S |
+	      SND_SOC_DAIFMT_NB_NF |
+	      SND_SOC_DAIFMT_CBS_CFS;
+
+	/* setup the CPU DAI */
+	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops raumfeld_wm8782_ops = {
+	.hw_params = raumfeld_wm8782_hw_params,
+};
+
 #define DAI_LINK_CS4270		\
 {							\
 	.name		= "CS4270",			\
@@ -247,6 +417,28 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
 	.codec_name	= "spi0.0",			\
 }
 
+#define DAI_LINK_STA32X		\
+{							\
+	.name 		= "STA32X",			\
+	.stream_name	= "Playback",			\
+	.cpu_dai_name	= "pxa-ssp-dai.0",		\
+	.platform_name	= "pxa-pcm-audio",		\
+	.codec_dai_name	= "STA32X",			\
+	.ops		= &raumfeld_sta32x_ops,		\
+	.codec_name	= "sta32x.0-001a",	\
+}
+
+#define DAI_LINK_WM8782		\
+{							\
+	.name		= "wm8782",			\
+	.stream_name	= "wm8782",			\
+	.cpu_dai_name	= "pxa-ssp-dai.0",		\
+	.platform_name	= "pxa-pcm-audio",		\
+	.codec_dai_name	= "wm8782",			\
+	.codec_name	= "wm8782.0",		\
+	.ops		= &raumfeld_wm8782_ops,		\
+}
+
 static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] =
 {
 	DAI_LINK_CS4270,
@@ -258,6 +450,12 @@ static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
 	DAI_LINK_CS4270,
 };
 
+static struct snd_soc_dai_link snd_soc_raumfeld_ddx_dai[] =
+{
+	DAI_LINK_STA32X,
+	DAI_LINK_WM8782,
+};
+
 static struct snd_soc_card snd_soc_raumfeld_connector = {
 	.name		= "Raumfeld Connector",
 	.dai_link	= snd_soc_raumfeld_connector_dai,
@@ -274,7 +472,15 @@ static struct snd_soc_card snd_soc_raumfeld_speaker = {
 	.resume_pre	= raumfeld_analog_resume,
 };
 
-static struct platform_device *raumfeld_audio_device;
+static struct snd_soc_card snd_soc_raumfeld_ddx = {
+	.name		= "Raumfeld DDX",
+	.dai_link	= snd_soc_raumfeld_ddx_dai,
+	.num_links	= ARRAY_SIZE(snd_soc_raumfeld_ddx_dai),
+	.suspend_post	= raumfeld_analog_suspend,
+	.resume_pre	= raumfeld_analog_resume,
+};
+
+static struct platform_device *raumfeld_audio_device, *wm8782_device;
 
 static int __init raumfeld_audio_init(void)
 {
@@ -284,26 +490,39 @@ static int __init raumfeld_audio_init(void)
 	    !machine_is_raumfeld_connector())
 		return 0;
 
-	max9486_client = i2c_new_device(i2c_get_adapter(0),
-					&max9486_hwmon_info);
+	if ((system_rev & 0xff00) == 0x0400) {
+		wm8782_device = platform_device_alloc("wm8782", 0);
+		if (!wm8782_device)
+			return -ENOMEM;
 
-	if (!max9486_client)
-		return -ENOMEM;
+		platform_device_add(wm8782_device);
+	} else {
+		max9486_client = i2c_new_device(i2c_get_adapter(0),
+						&max9486_hwmon_info);
+
+		if (!max9486_client)
+			return -ENOMEM;
 
-	set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+		set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+	}
 
-	/* Register analog device */
+	/* Register audio device */
 	raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
 	if (!raumfeld_audio_device)
 		return -ENOMEM;
 
-	if (machine_is_raumfeld_speaker())
+	if ((system_rev & 0xff00) == 0x0400)
 		platform_set_drvdata(raumfeld_audio_device,
-				     &snd_soc_raumfeld_speaker);
-
-	if (machine_is_raumfeld_connector())
-		platform_set_drvdata(raumfeld_audio_device,
-				     &snd_soc_raumfeld_connector);
+				     &snd_soc_raumfeld_ddx);
+	else {
+		if (machine_is_raumfeld_speaker())
+			platform_set_drvdata(raumfeld_audio_device,
+					     &snd_soc_raumfeld_speaker);
+
+		if (machine_is_raumfeld_connector())
+			platform_set_drvdata(raumfeld_audio_device,
+					     &snd_soc_raumfeld_connector);
+	}
 
 	ret = platform_device_add(raumfeld_audio_device);
 	if (ret < 0)
@@ -317,8 +536,8 @@ static void __exit raumfeld_audio_exit(void)
 {
 	raumfeld_enable_audio(false);
 
+	platform_device_unregister(wm8782_device);
 	platform_device_unregister(raumfeld_audio_device);
-
 	i2c_unregister_device(max9486_client);
 
 	gpio_free(GPIO_MCLK_RESET);
-- 
1.7.6.4

WARNING: multiple messages have this Message-ID (diff)
From: zonque@gmail.com (Daniel Mack)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2] ARM: pxa: add support for Raumfeld DDX
Date: Tue,  8 Nov 2011 11:16:09 +0100	[thread overview]
Message-ID: <1320747369-12141-1-git-send-email-zonque@gmail.com> (raw)

This new product features a STA32x codec. To support it, some rework
of the regulator initialization for the Raumfeld platform is necessary.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Liam Girdwood <lrg@ti.com>
Cc: Eric Miao <eric.y.miao@gmail.com>
Cc: Sven Neumann <s.neumann@raumfeld.com>
Cc: Johannes Stezenbach <js@sig21.net>
---

 v2 of this patch has clocking fixes and superseeds the older version.

 As there are more changes in sound/soc than in arch/arm, I think it
 should best go through Mark's AsoC tree.

 arch/arm/mach-pxa/raumfeld.c |  119 +++++++++++++++++---
 sound/soc/pxa/Kconfig        |    2 +
 sound/soc/pxa/raumfeld.c     |  247 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 336 insertions(+), 32 deletions(-)

diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 7856fe4..22366ff 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -850,7 +850,7 @@ struct regulator_init_data audio_va_initdata = {
 	},
 };
 
-static struct fixed_voltage_config audio_va_config = {
+static struct fixed_voltage_config cs4270_va_config = {
 	.supply_name		= "audio_va",
 	.microvolts		= 5000000,
 	.gpio			= GPIO_AUDIO_VA_ENABLE,
@@ -859,47 +859,114 @@ static struct fixed_voltage_config audio_va_config = {
 	.init_data		= &audio_va_initdata,
 };
 
-static struct platform_device audio_va_device = {
+static struct platform_device cs4270_va_device = {
 	.name	= "reg-fixed-voltage",
 	.id	= 0,
 	.dev	= {
-		.platform_data = &audio_va_config,
+		.platform_data = &cs4270_va_config,
 	},
 };
 
 /* Dummy supplies for Codec's VD/VLC */
 
-static struct regulator_consumer_supply audio_dummy_supplies[] = {
+static struct regulator_consumer_supply cs4270_dummy_supplies[] = {
 	REGULATOR_SUPPLY("vd", "0-0048"),
 	REGULATOR_SUPPLY("vlc", "0-0048"),
 };
 
-struct regulator_init_data audio_dummy_initdata = {
-	.consumer_supplies = audio_dummy_supplies,
-	.num_consumer_supplies = ARRAY_SIZE(audio_dummy_supplies),
+struct regulator_init_data cs4270_dummy_initdata = {
+	.consumer_supplies = cs4270_dummy_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(cs4270_dummy_supplies),
 	.constraints = {
 		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 	},
 };
 
-static struct fixed_voltage_config audio_dummy_config = {
-	.supply_name		= "audio_vd",
+static struct fixed_voltage_config cs4270_dummy_config = {
+	.supply_name		= "cs4270_vd",
 	.microvolts		= 3300000,
 	.gpio			= -1,
-	.init_data		= &audio_dummy_initdata,
+	.init_data		= &cs4270_dummy_initdata,
 };
 
-static struct platform_device audio_supply_dummy_device = {
+static struct platform_device cs4270_supply_dummy_device = {
 	.name	= "reg-fixed-voltage",
 	.id	= 1,
 	.dev	= {
-		.platform_data = &audio_dummy_config,
+		.platform_data = &cs4270_dummy_config,
 	},
 };
 
-static struct platform_device *audio_regulator_devices[] = {
-	&audio_va_device,
-	&audio_supply_dummy_device,
+static struct platform_device *cs4270_regulator_devices[] = {
+	&cs4270_va_device,
+	&cs4270_supply_dummy_device,
+};
+
+/* Fixed regulator for sta32x Vdda supply
+ * 0-001a maps to the sta32x codec devname (derived from i2c bus num + addr)
+ */
+
+static struct regulator_consumer_supply sta32x_va_consumer_supply =
+	REGULATOR_SUPPLY("Vdda", "0-001a");
+
+struct regulator_init_data sta32x_va_initdata = {
+	.consumer_supplies = &sta32x_va_consumer_supply,
+	.num_consumer_supplies = 1,
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+static struct fixed_voltage_config sta32x_va_config = {
+	.supply_name		= "audio_va",
+	.microvolts		= 3300000,
+	.gpio			= GPIO_AUDIO_VA_ENABLE,
+	.enable_high		= 1,
+	.enabled_at_boot	= 0,
+	.init_data		= &sta32x_va_initdata,
+};
+
+static struct platform_device sta32x_va_device = {
+	.name	= "reg-fixed-voltage",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &sta32x_va_config,
+	},
+};
+
+/* Dummy supplies for sta32x codec's Vdd3/Vcc */
+
+static struct regulator_consumer_supply sta32x_dummy_supplies[] = {
+	REGULATOR_SUPPLY("Vdd3", "0-001a"),
+	REGULATOR_SUPPLY("Vcc", "0-001a"),
+};
+
+struct regulator_init_data sta32x_dummy_initdata = {
+	.consumer_supplies = sta32x_dummy_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(sta32x_dummy_supplies),
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+static struct fixed_voltage_config sta32x_dummy_config = {
+	.supply_name	    = "audio_vd",
+	.microvolts	     = 3300000,
+	.gpio		   = -1,
+	.init_data	      = &sta32x_dummy_initdata,
+};
+
+static struct platform_device sta32x_supply_dummy_device = {
+	.name   = "reg-fixed-voltage",
+	.id     = 1,
+	.dev    = {
+		.platform_data = &sta32x_dummy_config,
+	},
+};
+
+static struct platform_device *sta32x_regulator_devices[] = {
+	&sta32x_va_device,
+	&sta32x_supply_dummy_device,
 };
 
 /**
@@ -948,6 +1015,11 @@ static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = {
 	.addr	= 0x48,
 };
 
+static struct i2c_board_info raumfeld_ddx_i2c_board_info __initdata = {
+	.type   = "sta326",
+	.addr   = 0x1a,
+};
+
 static struct eeti_ts_platform_data eeti_ts_pdata = {
 	.irq_active_high = 1,
 };
@@ -987,7 +1059,10 @@ static void __init raumfeld_audio_init(void)
 	else
 		gpio_direction_output(GPIO_MCLK_RESET, 1);
 
-	platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices));
+	if ((system_rev & 0xff00) == 0x0400)
+		platform_add_devices(ARRAY_AND_SIZE(sta32x_regulator_devices));
+	else
+		platform_add_devices(ARRAY_AND_SIZE(cs4270_regulator_devices));
 }
 
 static void __init raumfeld_common_init(void)
@@ -1060,7 +1135,11 @@ static void __init raumfeld_connector_init(void)
 {
 	pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_connector_pin_config));
 	spi_register_board_info(ARRAY_AND_SIZE(connector_spi_devices));
-	i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+	if ((system_rev & 0xff00) == 0x0400)
+		i2c_register_board_info(0, &raumfeld_ddx_i2c_board_info, 1);
+	else
+		i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
 
 	platform_device_register(&smc91x_device);
 
@@ -1072,7 +1151,11 @@ static void __init raumfeld_speaker_init(void)
 {
 	pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_speaker_pin_config));
 	spi_register_board_info(ARRAY_AND_SIZE(speaker_spi_devices));
-	i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+	if ((system_rev & 0xff00) == 0x0400)
+		i2c_register_board_info(0, &raumfeld_ddx_i2c_board_info, 1);
+	else
+		i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
 
 	platform_device_register(&smc91x_device);
 	platform_device_register(&rotary_encoder_device);
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 33ebc46..e6db56a 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -152,6 +152,8 @@ config SND_SOC_RAUMFELD
 	select SND_PXA_SOC_SSP
 	select SND_SOC_CS4270
 	select SND_SOC_AK4104
+	select SND_SOC_STA32X
+	select SND_SOC_WM8782
 	help
 	  Say Y if you want to add support for SoC audio on Raumfeld devices
 
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 1a591f1..7d4f1bf 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
@@ -225,6 +226,175 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
 	.hw_params = raumfeld_ak4104_hw_params,
 };
 
+/* STA32X */
+static int raumfeld_sta32x_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* fixed MCLK of 11.2896MHz */
+	snd_pcm_hw_constraint_mask64(substream->runtime,
+				    SNDRV_PCM_HW_PARAM_RATE,
+				    SNDRV_PCM_RATE_44100 |
+				    SNDRV_PCM_RATE_88200 |
+				    SNDRV_PCM_RATE_176400);
+
+	/* PXA DMA cannot do zero extend for 24bit samples,
+	 * thus only 16bit (two samples packet into 32bit word)
+	 * or 32bit samples are possible
+	 */
+	snd_pcm_hw_constraint_mask64(substream->runtime,
+				    SNDRV_PCM_HW_PARAM_FORMAT,
+				    SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE |
+				    SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE);
+
+	/* we have a fixed MCLK, set it here so ALSA knows
+	 * the supported sample rates and can resample if necessary
+	 */
+	return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0);
+}
+
+static void raumfeld_sta32x_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* set freq to 0 to enable all possible codec sample rates */
+	snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
+}
+
+static int raumfeld_sta32x_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int fmt, clk = 0;
+	int ret = 0;
+
+	// fixed MCLK of 11.2896MHz
+	switch (params_rate(params)) {
+	case 44100:
+	case 88200:
+	case 176400:
+		clk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+	case SNDRV_PCM_FORMAT_S32_BE:
+		/* this enables network mode for 2 * 32bit samples */
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 0, 2, 32);
+		if (ret < 0)
+			return ret;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		/* this disables network mode */
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 0, 16);
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fmt = SND_SOC_DAIFMT_I2S |
+	      SND_SOC_DAIFMT_NB_NF |
+	      SND_SOC_DAIFMT_CBS_CFS;
+
+	/* setup the CODEC DAI */
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
+	if (ret < 0)
+		return ret;
+
+	/* setup the CPU DAI */
+	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops raumfeld_sta32x_ops = {
+	.startup = raumfeld_sta32x_startup,
+	.shutdown = raumfeld_sta32x_shutdown,
+	.hw_params = raumfeld_sta32x_hw_params,
+};
+
+/* WM8782 */
+static int raumfeld_wm8782_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int fmt, clk = 0;
+	int ret = 0;
+
+	// fixed MCLK of 11.2896MHz
+	switch (params_rate(params)) {
+	case 44100:
+		clk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fmt = SND_SOC_DAIFMT_I2S |
+	      SND_SOC_DAIFMT_NB_NF |
+	      SND_SOC_DAIFMT_CBS_CFS;
+
+	/* setup the CPU DAI */
+	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops raumfeld_wm8782_ops = {
+	.hw_params = raumfeld_wm8782_hw_params,
+};
+
 #define DAI_LINK_CS4270		\
 {							\
 	.name		= "CS4270",			\
@@ -247,6 +417,28 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
 	.codec_name	= "spi0.0",			\
 }
 
+#define DAI_LINK_STA32X		\
+{							\
+	.name 		= "STA32X",			\
+	.stream_name	= "Playback",			\
+	.cpu_dai_name	= "pxa-ssp-dai.0",		\
+	.platform_name	= "pxa-pcm-audio",		\
+	.codec_dai_name	= "STA32X",			\
+	.ops		= &raumfeld_sta32x_ops,		\
+	.codec_name	= "sta32x.0-001a",	\
+}
+
+#define DAI_LINK_WM8782		\
+{							\
+	.name		= "wm8782",			\
+	.stream_name	= "wm8782",			\
+	.cpu_dai_name	= "pxa-ssp-dai.0",		\
+	.platform_name	= "pxa-pcm-audio",		\
+	.codec_dai_name	= "wm8782",			\
+	.codec_name	= "wm8782.0",		\
+	.ops		= &raumfeld_wm8782_ops,		\
+}
+
 static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] =
 {
 	DAI_LINK_CS4270,
@@ -258,6 +450,12 @@ static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
 	DAI_LINK_CS4270,
 };
 
+static struct snd_soc_dai_link snd_soc_raumfeld_ddx_dai[] =
+{
+	DAI_LINK_STA32X,
+	DAI_LINK_WM8782,
+};
+
 static struct snd_soc_card snd_soc_raumfeld_connector = {
 	.name		= "Raumfeld Connector",
 	.dai_link	= snd_soc_raumfeld_connector_dai,
@@ -274,7 +472,15 @@ static struct snd_soc_card snd_soc_raumfeld_speaker = {
 	.resume_pre	= raumfeld_analog_resume,
 };
 
-static struct platform_device *raumfeld_audio_device;
+static struct snd_soc_card snd_soc_raumfeld_ddx = {
+	.name		= "Raumfeld DDX",
+	.dai_link	= snd_soc_raumfeld_ddx_dai,
+	.num_links	= ARRAY_SIZE(snd_soc_raumfeld_ddx_dai),
+	.suspend_post	= raumfeld_analog_suspend,
+	.resume_pre	= raumfeld_analog_resume,
+};
+
+static struct platform_device *raumfeld_audio_device, *wm8782_device;
 
 static int __init raumfeld_audio_init(void)
 {
@@ -284,26 +490,39 @@ static int __init raumfeld_audio_init(void)
 	    !machine_is_raumfeld_connector())
 		return 0;
 
-	max9486_client = i2c_new_device(i2c_get_adapter(0),
-					&max9486_hwmon_info);
+	if ((system_rev & 0xff00) == 0x0400) {
+		wm8782_device = platform_device_alloc("wm8782", 0);
+		if (!wm8782_device)
+			return -ENOMEM;
 
-	if (!max9486_client)
-		return -ENOMEM;
+		platform_device_add(wm8782_device);
+	} else {
+		max9486_client = i2c_new_device(i2c_get_adapter(0),
+						&max9486_hwmon_info);
+
+		if (!max9486_client)
+			return -ENOMEM;
 
-	set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+		set_max9485_clk(MAX9485_MCLK_FREQ_122880);
+	}
 
-	/* Register analog device */
+	/* Register audio device */
 	raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
 	if (!raumfeld_audio_device)
 		return -ENOMEM;
 
-	if (machine_is_raumfeld_speaker())
+	if ((system_rev & 0xff00) == 0x0400)
 		platform_set_drvdata(raumfeld_audio_device,
-				     &snd_soc_raumfeld_speaker);
-
-	if (machine_is_raumfeld_connector())
-		platform_set_drvdata(raumfeld_audio_device,
-				     &snd_soc_raumfeld_connector);
+				     &snd_soc_raumfeld_ddx);
+	else {
+		if (machine_is_raumfeld_speaker())
+			platform_set_drvdata(raumfeld_audio_device,
+					     &snd_soc_raumfeld_speaker);
+
+		if (machine_is_raumfeld_connector())
+			platform_set_drvdata(raumfeld_audio_device,
+					     &snd_soc_raumfeld_connector);
+	}
 
 	ret = platform_device_add(raumfeld_audio_device);
 	if (ret < 0)
@@ -317,8 +536,8 @@ static void __exit raumfeld_audio_exit(void)
 {
 	raumfeld_enable_audio(false);
 
+	platform_device_unregister(wm8782_device);
 	platform_device_unregister(raumfeld_audio_device);
-
 	i2c_unregister_device(max9486_client);
 
 	gpio_free(GPIO_MCLK_RESET);
-- 
1.7.6.4

             reply	other threads:[~2011-11-08 10:16 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-08 10:16 Daniel Mack [this message]
2011-11-08 10:16 ` [PATCH v2] ARM: pxa: add support for Raumfeld DDX Daniel Mack
2011-11-11 15:09 ` Daniel Mack
2011-11-11 15:09   ` Daniel Mack

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1320747369-12141-1-git-send-email-zonque@gmail.com \
    --to=zonque@gmail.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=s.neumann@raumfeld.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.