[alsa-devel] [PATCH] SMDK64XX I2S: Added machine driver for WM8580
New machine driver for WM8580 I2S i/f on SMDK64XX. By default SoC-Slave is set and WM8580 is configured to use it's PLLA to generate clocks from a 12MHz crystal attached to WM8580.
Signed-off-by: Jassi jassi.brar@samsung.com --- sound/soc/s3c24xx/Kconfig | 8 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/smdk64xx_wm8580.c | 283 +++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 0 deletions(-) create mode 100644 sound/soc/s3c24xx/smdk64xx_wm8580.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 923428f..769697e 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -56,6 +56,14 @@ config SND_S3C24XX_SOC_JIVE_WM8750 help Sat Y if you want to add support for SoC audio on the Jive.
+config SND_S3C64XX_SOC_WM8580 + tristate "SoC I2S Audio support for WM8580 on SMDK64XX" + depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410) + select SND_SOC_WM8580 + select SND_S3C64XX_SOC_I2S + help + Sat Y if you want to add support for SoC audio on the SMDK64XX. + config SND_S3C24XX_SOC_SMDK2443_WM9710 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" depends on SND_S3C24XX_SOC && MACH_SMDK2443 diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 99f5a7d..7790406 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -23,6 +23,7 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o +snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -33,4 +34,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o +obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c new file mode 100644 index 0000000..e4b5e0f --- /dev/null +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -0,0 +1,283 @@ +/* + * smdk64xx_wm8580.c + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh jassi.brar@samsung.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include "../codecs/wm8580.h" +#include "s3c24xx-pcm.h" +#include "s3c64xx-i2s.h" + +#define S3C64XX_I2S_V4 2 + +/* SMDK64XX has a 12MHZ crystal attached to WM8580 */ +#define SMDK64XX_WM8580_FREQ 12000000 + +static int smdk64xx_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->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + unsigned int pll_out; + int bfs, rfs, ret; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + bfs = 16; + break; + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + bfs = 32; + break; + default: + return -EINVAL; + } + + /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. + * This criterion can't be met if we request PLL output + * as {8000x256, 64000x256, 11025x256}Hz. + * As a wayout, we rather change rfs to a minimum value that + * results in (params_rate(params) * rfs), and itself, acceptable + * to both - the CODEC and the CPU. + */ + switch (params_rate(params)) { + case 16000: + case 22050: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + rfs = 256; + break; + case 64000: + rfs = 384; + break; + case 8000: + case 11025: + rfs = 512; + break; + default: + return -EINVAL; + } + pll_out = params_rate(params) * rfs; + + /* Set the Codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* Set the AP DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* We use PCLK for basic ops in SoC-Slave mode */ + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* Set WM8580 to drive MCLK from it's PLLA */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_PLLA); + if (ret < 0) + return ret; + + /* Explicitly set WM8580-DAC to source from MCLK */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL, + WM8580_CLKSRC_MCLK); + if (ret < 0) + return ret; + + /* Assuming the CODEC driver evaluates it's rfs too from this call */ + ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, + SMDK64XX_WM8580_FREQ, pll_out); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs); + if (ret < 0) + return ret; + + return 0; +} + +static int smdk64xx_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + /* disable the PLL */ + return snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, 0); +} + +/* + * SMDK64XX WM8580 DAI operations. + */ +static struct snd_soc_ops smdk64xx_ops = { + .hw_params = smdk64xx_hw_params, + .hw_free = smdk64xx_hw_free, +}; + +/* SMDK64xx Playback widgets */ +static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { + SND_SOC_DAPM_HP("Front-L/R", NULL), + SND_SOC_DAPM_HP("Center/Sub", NULL), + SND_SOC_DAPM_HP("Rear-L/R", NULL), +}; + +/* SMDK64xx Capture widgets */ +static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { + SND_SOC_DAPM_MIC("MicIn", NULL), + SND_SOC_DAPM_LINE("LineIn", NULL), +}; + +/* SMDK-PAIFTX connections */ +static const struct snd_soc_dapm_route audio_map_tx[] = { + /* MicIn feeds AINL */ + {"AINL", NULL, "MicIn"}, + + /* LineIn feeds AINL/R */ + {"AINL", NULL, "LineIn"}, + {"AINR", NULL, "LineIn"}, +}; + +/* SMDK-PAIFRX connections */ +static const struct snd_soc_dapm_route audio_map_rx[] = { + /* Front Left/Right are fed VOUT1L/R */ + {"Front-L/R", NULL, "VOUT1L"}, + {"Front-L/R", NULL, "VOUT1R"}, + + /* Center/Sub are fed VOUT2L/R */ + {"Center/Sub", NULL, "VOUT2L"}, + {"Center/Sub", NULL, "VOUT2R"}, + + /* Rear Left/Right are fed VOUT3L/R */ + {"Rear-L/R", NULL, "VOUT3L"}, + {"Rear-L/R", NULL, "VOUT3R"}, +}; + +static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) +{ + /* Add smdk64xx specific Capture widgets */ + snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt, + ARRAY_SIZE(wm8580_dapm_widgets_cpt)); + + /* Set up PAIFTX audio path */ + snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); + + /* All enabled by default */ + snd_soc_dapm_enable_pin(codec, "MicIn"); + snd_soc_dapm_enable_pin(codec, "LineIn"); + + /* signal a DAPM event */ + snd_soc_dapm_sync(codec); + + return 0; +} + +static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) +{ + /* Add smdk64xx specific Playback widgets */ + snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk, + ARRAY_SIZE(wm8580_dapm_widgets_pbk)); + + /* Set up PAIFRX audio path */ + snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); + + /* All enabled by default */ + snd_soc_dapm_enable_pin(codec, "Front-L/R"); + snd_soc_dapm_enable_pin(codec, "Center/Sub"); + snd_soc_dapm_enable_pin(codec, "Rear-L/R"); + + /* signal a DAPM event */ + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link smdk64xx_dai[] = { +{ /* Primary Playback i/f */ + .name = "WM8580 PAIF RX", + .stream_name = "Playback", + .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], + .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX], + .init = smdk64xx_wm8580_init_paifrx, + .ops = &smdk64xx_ops, +}, +{ /* Primary Capture i/f */ + .name = "WM8580 PAIF TX", + .stream_name = "Capture", + .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], + .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX], + .init = smdk64xx_wm8580_init_paiftx, + .ops = &smdk64xx_ops, +}, +}; + +static struct snd_soc_card smdk64xx = { + .name = "smdk64xx", + .platform = &s3c24xx_soc_platform, + .dai_link = smdk64xx_dai, + .num_links = ARRAY_SIZE(smdk64xx_dai), +}; + +static struct snd_soc_device smdk64xx_snd_devdata = { + .card = &smdk64xx, + .codec_dev = &soc_codec_dev_wm8580, +}; + +static struct platform_device *smdk64xx_snd_device; + +static int __init smdk64xx_audio_init(void) +{ + int ret; + + smdk64xx_snd_device = platform_device_alloc("soc-audio", -1); + if (!smdk64xx_snd_device) + return -ENOMEM; + + platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata); + smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev; + ret = platform_device_add(smdk64xx_snd_device); + + if (ret) + platform_device_put(smdk64xx_snd_device); + + return ret; +} +module_init(smdk64xx_audio_init); + +MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); +MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580"); +MODULE_LICENSE("GPL");
On Sat, Sep 19, 2009 at 09:46:06AM +0900, jassi brar wrote:
New machine driver for WM8580 I2S i/f on SMDK64XX. By default SoC-Slave is set and WM8580 is configured to use it's PLLA to generate clocks from a 12MHz crystal attached to WM8580.
Signed-off-by: Jassi jassi.brar@samsung.com
I've applied this with a couple of additional fixups below. I've added a dependency on BROKEN since the IISv4 support is not yet present so there's no chance of it working yet.
+#define S3C64XX_I2S_V4 2
This should be defined by the DAI driver, every user is going to need it.
+static int smdk64xx_hw_free(struct snd_pcm_substream *substream) +{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, 0);
+}
Doing this will break simultaneous playback and record - whichever of them stops first will stop the PLL, removing the clock from the other. I've removed the hw_free() function as a result.
I also note that you're not submitting and testing against the latest ASoC code since the PLL API has been updated so that this won't build. I've fixed it up this time but please do try to ensure you're working with the latest code when submitting patches.
On Sun, Sep 20, 2009 at 1:08 AM, Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Sat, Sep 19, 2009 at 09:46:06AM +0900, jassi brar wrote:
New machine driver for WM8580 I2S i/f on SMDK64XX. By default SoC-Slave is set and WM8580 is configured to use it's PLLA to generate clocks from a 12MHz crystal attached to WM8580.
Signed-off-by: Jassi jassi.brar@samsung.com
I've applied this with a couple of additional fixups below. I've added a dependency on BROKEN since the IISv4 support is not yet present so there's no chance of it working yet.
well, i sent patches for CPU support also. they are simply put on hold until something is decided. if i were given a suggestion atleast i cud try doing that. anyways, the machine driver will almost remain the same in future when we the CPU support is there.
+static int smdk64xx_hw_free(struct snd_pcm_substream *substream) +{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, 0);
+}
Doing this will break simultaneous playback and record - whichever of them stops first will stop the PLL, removing the clock from the other. I've removed the hw_free() function as a result.
thank you. I didn't check full-duplex.
I also note that you're not submitting and testing against the latest ASoC code since the PLL API has been updated so that this won't build. I've fixed it up this time but please do try to ensure you're working with the latest code when submitting patches.
I did see for-2.6.33 tree but wasn't sure when i shud start submitting against that. It was only 2.6.32 when i started. And i tested playback/capture @ all supported rates in that version.
I am new to the process, please bear this time. Please reject a patch and suggest how to do, if it's too much work for you.
Btw, I understand as soon as i see a newer for-2.6.xx branch i shud start submitting against that. Right?
On Sun, Sep 20, 2009 at 10:49:50AM +0900, jassi brar wrote:
On Sun, Sep 20, 2009 at 1:08 AM, Mark Brown
I've applied this with a couple of additional fixups below. I've added a dependency on BROKEN since the IISv4 support is not yet present so there's no chance of it working yet.
well, i sent patches for CPU support also. they are simply put on hold until something is decided. if i were given a suggestion atleast i cud try doing that. anyways, the machine driver will almost remain the same in future when we the CPU support is there.
I think there was enough feedback on the CPU patches? IIRC the main issues were that the driver will need some way to tell that it's an IISv4 block (which it would be able to do with the existing arch/arm but not with the patches you sent) and that the audio-bus clock has to be idmplemented so that the driver can probe (or the driver will need to be able to carry on if it can't get the clock).
I did see for-2.6.33 tree but wasn't sure when i shud start submitting against that.
As a rule new features should be submitted against the newest branch for a given subsystem - if there's an older branch it will normally be bug fix only.
Btw, I understand as soon as i see a newer for-2.6.xx branch i shud start submitting against that. Right?
For new features, yes. Bug fixes should be done against the version destined for Linus' current tree if the issue applies there.
Let me clarify, just in case, The patch-2/10 http://lists.infradead.org/pipermail/linux-arm-kernel/2009-September/000714.... enables this MACHINE driver to run 2 channels(of the 6 possible) of the I2S-v4 with the extant S3C CPU drivers, which do the job fine. The extant CPU drivers are inadequate only if we want 6channels and h/w mixing support.
On Sun, Sep 20, 2009 at 4:31 PM, Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Sun, Sep 20, 2009 at 10:49:50AM +0900, jassi brar wrote:
On Sun, Sep 20, 2009 at 1:08 AM, Mark Brown
I've applied this with a couple of additional fixups below. I've added a dependency on BROKEN since the IISv4 support is not yet present so there's no chance of it working yet.
well, i sent patches for CPU support also. they are simply put on hold until something is decided. if i were given a suggestion atleast i cud try doing that. anyways, the machine driver will almost remain the same in future when we the CPU support is there.
I think there was enough feedback on the CPU patches? IIRC the main issues were that the driver will need some way to tell that it's an IISv4 block (which it would be able to do with the existing arch/arm but not with the patches you sent)
Is it a bad idea to use only part, shared with I2S-v3, of I2S-v4 controller when the CPU driver doesn't yet support other distinguishing features? If yes, then I shud start writing the 6channel and h/w mixing stuff for the CPU driver. If no, then my patches can be accepted in current or modified form. When 6channel and/or h/w mixing is implemented in the CPU drivers we just enable those features in the controller.
and that the audio-bus clock has to be idmplemented so that the driver can probe (or the driver will need to be able to carry on if it can't get the clock).
somehow i missed emailing that patch. will resend with other parts.
Btw, I understand as soon as i see a newer for-2.6.xx branch i shud start submitting against that. Right?
For new features, yes. Bug fixes should be done against the version destined for Linus' current tree if the issue applies there.
got it. thanks
Another question ... The platform device s3c64xx_device_iisv4 is defined in arch/arm/plat-s3c/dev-audio.c whereas I2S_v4 is available only for S3C6410 and newer SoCs. Shudn't we define it somewhere like arch/arm/plat-s3c64xx/dev-audio.c? I ask because soon I'll be submitting the PCM controller CPU driver for S3C64XX and i wish to define it for s3c64xx specific platform, not the generic s3c. Please suggest.
participants (2)
-
jassi brar
-
Mark Brown