[PATCH v2] ARM: pxa: add support for Raumfeld DDX
Daniel Mack
zonque at gmail.com
Fri Nov 11 10:09:35 EST 2011
Ping? Does anyone want me to split this into two pieces maybe?
Daniel
On 11/08/2011 11:16 AM, Daniel Mack wrote:
> 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 at 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 at raumfeld.com>
> Cc: Johannes Stezenbach <js at 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);
More information about the linux-arm-kernel
mailing list