From 85488037bb9b533b064be66412dbe1dbcd2734d9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 5 Sep 2009 18:52:16 +0100 Subject: ASoC: Add source argument to PLL configuration More and more devices feature PLLs and FLLs with the ability to select between multiple input clocks. In order to better support these devices a new argument, source, has been added to the set_pll() configuration API. Using set_clkdiv() is often difficult due to the need to stop the PLL/FLL before any reconfiguration can be done. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 0c52e36ddd87..6ddd1b3b16b3 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, return ret; /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, iis_clkrate / 4, pll_out); if (ret < 0) return ret; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 906709e6dd5f..16009eba9cba 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -137,7 +137,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, return ret; /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, iis_clkrate / 4, pll_out); if (ret < 0) return ret; -- cgit From fd5ad654e665b5c30c8d755a106309c8ea9f3e7b Mon Sep 17 00:00:00 2001 From: Jassi Date: Tue, 15 Sep 2009 19:02:38 +0900 Subject: ASoC: S3C I2S LRCLK polarity option. 1) Explicitly set LRCLK polarity for I2S Vs LSM/MSB modes. 2) Convert from numerical to bit-field values for BCLK selection. 3) Use proper error checking for return value from clk_get Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c-i2s-v2.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index aa7af0b8d421..819c3c086d69 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -308,12 +308,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: + iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_MSB; break; case SND_SOC_DAIFMT_LEFT_J: + iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_LSB; break; case SND_SOC_DAIFMT_I2S: + iismod &= ~S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_IIS; break; default: @@ -463,6 +466,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, switch (div_id) { case S3C_I2SV2_DIV_BCLK: + if (div > 3) { + /* convert value to bit field */ + + switch (div) { + case 16: + div = S3C2412_IISMOD_BCLK_16FS; + break; + + case 32: + div = S3C2412_IISMOD_BCLK_32FS; + break; + + case 24: + div = S3C2412_IISMOD_BCLK_24FS; + break; + + case 48: + div = S3C2412_IISMOD_BCLK_48FS; + break; + + default: + return -EINVAL; + } + } + reg = readl(i2s->regs + S3C2412_IISMOD); reg &= ~S3C2412_IISMOD_BCLK_MASK; writel(reg | div, i2s->regs + S3C2412_IISMOD); @@ -622,7 +650,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev, } i2s->iis_pclk = clk_get(dev, "iis"); - if (i2s->iis_pclk == NULL) { + if (IS_ERR(i2s->iis_pclk)) { dev_err(dev, "failed to get iis_clock\n"); iounmap(i2s->regs); return -ENOENT; -- cgit From 8bb014895547eeeb9aa61a654f24e41e15919304 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 16 Sep 2009 19:38:53 +0100 Subject: ASoC: Add S3C64xx IIS CDCLK source selection CDCLK can either be an output generated by the CPU, intended for use as the CODEC master clock, or an input (probably from the CODEC) providing a master clock for the IIS block. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c64xx-i2s.h | 1 + 2 files changed, 14 insertions(+) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0fb..aaf452096be2 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -99,6 +99,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, iismod |= S3C64XX_IISMOD_IMS_SYSMUX; break; + case S3C64XX_CLKSRC_CDCLK: + switch (dir) { + case SND_SOC_CLOCK_IN: + iismod |= S3C64XX_IISMOD_CDCLKCON; + break; + case SND_SOC_CLOCK_OUT: + iismod &= ~S3C64XX_IISMOD_CDCLKCON; + break; + default: + return -EINVAL; + } + break; + default: return -EINVAL; } diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h index 02148cee2613..abe7253b55fc 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h @@ -25,6 +25,7 @@ struct clk; #define S3C64XX_CLKSRC_PCLK (0) #define S3C64XX_CLKSRC_MUX (1) +#define S3C64XX_CLKSRC_CDCLK (2) extern struct snd_soc_dai s3c64xx_i2s_dai[]; -- cgit From b1cd6b9ec7c749ddfad628c8c12659591ae195e6 Mon Sep 17 00:00:00 2001 From: Jassi Date: Fri, 18 Sep 2009 15:22:27 +0900 Subject: ASoC: Return correct codec clock in s3c64xx-i2s Instead of always returnig pointer to the 'audio-bus' clock, check which clock is used to generate internal clocks and then return it's pointer. Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index aaf452096be2..43fb253a3429 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -124,8 +124,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); + u32 iismod = readl(i2s->regs + S3C2412_IISMOD); - return i2s->iis_cclk; + if (iismod & S3C64XX_IISMOD_IMS_SYSMUX) + return i2s->iis_cclk; + else + return i2s->iis_pclk; } EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); -- cgit From d0f5fa17aa63262685e43b798ca0830d89786235 Mon Sep 17 00:00:00 2001 From: jassi brar Date: Sat, 19 Sep 2009 09:46:06 +0900 Subject: ASoC: Support WM8580 based audio subsystem on SMDK64xx machines 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. [Added dependency on BROKEN since the IISv4 interface hasn't been merged yet, fixed the PLL API usage and removed the disabling of the PLL in the hw_free function since that'll break simultaneous playback and record -- broonie.] Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 9 ++ sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/smdk64xx_wm8580.c | 273 ++++++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 sound/soc/s3c24xx/smdk64xx_wm8580.c (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 923428fc1adb..d7912f1e4627 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -56,6 +56,15 @@ 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) + depends on BROKEN + 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 99f5a7dd3fc6..7790406f90b7 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 000000000000..482aaf10eff6 --- /dev/null +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -0,0 +1,273 @@ +/* + * smdk64xx_wm8580.c + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * + * 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 +#include +#include +#include +#include +#include +#include + +#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, 0, 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; +} + +/* + * SMDK64XX WM8580 DAI operations. + */ +static struct snd_soc_ops smdk64xx_ops = { + .hw_params = smdk64xx_hw_params, +}; + +/* 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"); -- cgit From 140318aaa924ce9664ff59366993228cf1547f1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Oct 2009 08:40:32 +0200 Subject: ASoC: Fix snd_soc_dai_set_pll() calls in neo1973_*.c Fix the missing argument of snd_soc_dai_set_pll() in neo1973_*.c, which was forgotten in the commit 85488037bb. Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 6 +++--- sound/soc/s3c24xx/neo1973_wm8753.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 6ddd1b3b16b3..26409a9cef9e 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } /* @@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params( return ret; /* configue and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) return ret; @@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); } static struct snd_soc_ops neo1973_gta02_voice_ops = { diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 16009eba9cba..c9b794843a70 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -153,7 +153,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } /* @@ -203,7 +203,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, return ret; /* configue and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) return ret; @@ -219,7 +219,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); } static struct snd_soc_ops neo1973_voice_ops = { -- cgit From ed9d040d40942e9c48167f9f37f86fab8e0e5e17 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 12 Oct 2009 21:17:09 +0100 Subject: ASoC: S3C: Remove Remove the include from arch/arm/plat-s3c/include/plat/audio.h as it provides nothing to the current kernel and is not in any future plans for the system. Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Mark Brown --- sound/soc/s3c24xx/neo1973_wm8753.c | 1 - sound/soc/s3c24xx/s3c-i2s-v2.c | 1 - sound/soc/s3c24xx/s3c2412-i2s.c | 1 - sound/soc/s3c24xx/s3c2443-ac97.c | 1 - sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 1 - sound/soc/s3c24xx/s3c64xx-i2s.c | 1 - 7 files changed, 1 insertion(+), 7 deletions(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index c9b794843a70..77de6c5127d2 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 11c45a37c631..28b0ab255096 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -32,7 +32,6 @@ #include -#include #include #include "s3c-i2s-v2.h" diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index a587ec40b449..ac5e47b082fb 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -34,7 +34,6 @@ #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index fc1beb0930b9..b25e9f968df9 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 40e2c4790f0d..c76b8bb214bc 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -32,7 +32,7 @@ #include #include #include -#include + #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 5cbbdc80fde3..27cf097c2b1d 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "s3c24xx-pcm.h" diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 43fb253a3429..b67eed59666a 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include -- cgit From 26d95b6e300c4847be6ec8bfe817dbd531e94d9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 28 Oct 2009 15:47:48 +0000 Subject: ASoC: Minor SMDK64xx WM8580 cleanups Fix up some comments, remove all enable_pin() calls (edge widgets are all enabled by default) and mark the microphone as disabled by default since it requires a resistor fit to connect it. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk64xx_wm8580.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index 482aaf10eff6..cb8a9161b643 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -103,7 +103,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - /* Set WM8580 to drive MCLK from it's PLLA */ + /* Set WM8580 to drive MCLK from its PLLA */ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, WM8580_CLKSRC_PLLA); if (ret < 0) @@ -115,7 +115,6 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, 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, 0, WM8580_PLLA, SMDK64XX_WM8580_FREQ, pll_out); if (ret < 0) @@ -186,9 +185,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) /* 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"); + /* Enabling the microphone requires the fitting of a 0R + * resistor to connect the line from the microphone jack. + */ + snd_soc_dapm_disable_pin(codec, "MicIn"); /* signal a DAPM event */ snd_soc_dapm_sync(codec); @@ -205,11 +205,6 @@ static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) /* 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); -- cgit From ba2b87f5a93659a28cc4fb812ccd7b4146ac3aa9 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 11 Nov 2009 14:02:18 +0900 Subject: ASoC: Fixed arguments passed to SMDK64xx set_pll Corrected the order of 'source' and 'pll_id' arguments. Signed-off-by: Jassi Brar Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk64xx_wm8580.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index cb8a9161b643..216dd1e8e378 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -115,7 +115,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, + ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, SMDK64XX_WM8580_FREQ, pll_out); if (ret < 0) return ret; -- cgit From faa31776e4c799d631d8cd3a13dd50cd95b0875e Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:53:23 +0900 Subject: ASoC: Rename s3c24xx_pcm prefix to s3c_dma The s3c24xx_pcm prefix for the soc_platform is inappropriate when some Samsung SoCs have PCM controllers which will eventually have drivers and hence namespace ambiguities. To resolve naming ambiguities in future the following have been renamed in order 1) s3c24xx_pcm_dma_params -> s3c_dma_params 2) s3c24xx_pcm_preallocate_dma_buffer -> s3c_preallocate_dma_buffer 3) s3c24xx_pcm_dmamask -> s3c_dma_mask 4) s3c24xx_pcm_XXX -> s3c_dma_XXX Signed-off-by: Jassi Brar Acked-by: Ben Dooks Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c-i2s-v2.c | 2 +- sound/soc/s3c24xx/s3c-i2s-v2.h | 4 +-- sound/soc/s3c24xx/s3c2412-i2s.c | 4 +-- sound/soc/s3c24xx/s3c2443-ac97.c | 10 +++--- sound/soc/s3c24xx/s3c24xx-i2s.c | 10 +++--- sound/soc/s3c24xx/s3c24xx-pcm.c | 76 ++++++++++++++++++++-------------------- sound/soc/s3c24xx/s3c24xx-pcm.h | 6 ++-- sound/soc/s3c24xx/s3c64xx-i2s.c | 4 +-- 8 files changed, 58 insertions(+), 58 deletions(-) (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 28b0ab255096..5a442aa8b87b 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -394,7 +394,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; int ret = 0; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h index f66854a77fb2..ecf8eaaed1db 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.h +++ b/sound/soc/s3c24xx/s3c-i2s-v2.h @@ -49,8 +49,8 @@ struct s3c_i2sv2_info { unsigned char master; - struct s3c24xx_pcm_dma_params *dma_playback; - struct s3c24xx_pcm_dma_params *dma_capture; + struct s3c_dma_params *dma_playback; + struct s3c_dma_params *dma_capture; u32 suspend_iismod; u32 suspend_iiscon; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index ac5e47b082fb..23718ea85182 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -50,14 +50,14 @@ static struct s3c2410_dma_client s3c2412_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = { +static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { .client = &s3c2412_dma_client_out, .channel = DMACH_I2S_OUT, .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { +static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { .client = &s3c2412_dma_client_in, .channel = DMACH_I2S_IN, .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index b25e9f968df9..678b1763160b 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -188,21 +188,21 @@ static struct s3c2410_dma_client s3c2443_dma_client_micin = { .name = "AC97 Mic Mono in" }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = { +static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = { .client = &s3c2443_dma_client_out, .channel = DMACH_PCM_OUT, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = { +static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = { .client = &s3c2443_dma_client_in, .channel = DMACH_PCM_IN, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = { +static struct s3c_dma_params s3c2443_ac97_mic_mono_in = { .client = &s3c2443_dma_client_micin, .channel = DMACH_MIC_IN, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, @@ -290,7 +290,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, { u32 ac_glbctrl; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); @@ -339,7 +339,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, { u32 ac_glbctrl; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index c76b8bb214bc..afb4bc9033c8 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -49,14 +49,14 @@ static struct s3c2410_dma_client s3c24xx_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = { +static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { .client = &s3c24xx_dma_client_out, .channel = DMACH_I2S_OUT, .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, .dma_size = 2, }; -static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = { +static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { .client = &s3c24xx_dma_client_in, .channel = DMACH_I2S_IN, .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, @@ -258,12 +258,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod &= ~S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) + ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) + ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; default: @@ -280,7 +280,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { int ret = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 151a69463269..cb49400d8c56 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -32,7 +32,7 @@ #include "s3c24xx-pcm.h" -static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { +static const struct snd_pcm_hardware s3c_dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | @@ -62,15 +62,15 @@ struct s3c24xx_runtime_data { dma_addr_t dma_start; dma_addr_t dma_pos; dma_addr_t dma_end; - struct s3c24xx_pcm_dma_params *params; + struct s3c_dma_params *params; }; -/* s3c24xx_pcm_enqueue +/* s3c_dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) +static void s3c_dma_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -132,19 +132,19 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream); + s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); } -static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, +static int s3c_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; + struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; unsigned long totbytes = params_buffer_bytes(params); int ret = 0; @@ -197,7 +197,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) +static int s3c_dma_hw_free(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; @@ -214,7 +214,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) +static int s3c_dma_prepare(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; @@ -247,12 +247,12 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream); + s3c_dma_enqueue(substream); return ret; } -static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; @@ -287,7 +287,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t -s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) +s3c_dma_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; @@ -322,7 +322,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(substream->runtime, res); } -static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) +static int s3c_dma_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd; @@ -330,7 +330,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); + snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); if (prtd == NULL) @@ -342,7 +342,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) +static int s3c_dma_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; @@ -350,14 +350,14 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); if (!prtd) - pr_debug("s3c24xx_pcm_close called with prtd == NULL\n"); + pr_debug("s3c_dma_close called with prtd == NULL\n"); kfree(prtd); return 0; } -static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, +static int s3c_dma_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -370,23 +370,23 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); } -static struct snd_pcm_ops s3c24xx_pcm_ops = { - .open = s3c24xx_pcm_open, - .close = s3c24xx_pcm_close, +static struct snd_pcm_ops s3c_dma_ops = { + .open = s3c_dma_open, + .close = s3c_dma_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = s3c24xx_pcm_hw_params, - .hw_free = s3c24xx_pcm_hw_free, - .prepare = s3c24xx_pcm_prepare, - .trigger = s3c24xx_pcm_trigger, - .pointer = s3c24xx_pcm_pointer, - .mmap = s3c24xx_pcm_mmap, + .hw_params = s3c_dma_hw_params, + .hw_free = s3c_dma_hw_free, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .pointer = s3c_dma_pointer, + .mmap = s3c_dma_mmap, }; -static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; + size_t size = s3c_dma_hardware.buffer_bytes_max; pr_debug("Entered %s\n", __func__); @@ -401,7 +401,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -424,9 +424,9 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static u64 s3c24xx_pcm_dmamask = DMA_BIT_MASK(32); +static u64 s3c_dma_mask = DMA_BIT_MASK(32); -static int s3c24xx_pcm_new(struct snd_card *card, +static int s3c_dma_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { int ret = 0; @@ -434,19 +434,19 @@ static int s3c24xx_pcm_new(struct snd_card *card, pr_debug("Entered %s\n", __func__); if (!card->dev->dma_mask) - card->dev->dma_mask = &s3c24xx_pcm_dmamask; + card->dev->dma_mask = &s3c_dma_mask; if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = 0xffffffff; if (dai->playback.channels_min) { - ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, + ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } if (dai->capture.channels_min) { - ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, + ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) goto out; @@ -457,9 +457,9 @@ static int s3c24xx_pcm_new(struct snd_card *card, struct snd_soc_platform s3c24xx_soc_platform = { .name = "s3c24xx-audio", - .pcm_ops = &s3c24xx_pcm_ops, - .pcm_new = s3c24xx_pcm_new, - .pcm_free = s3c24xx_pcm_free_dma_buffers, + .pcm_ops = &s3c_dma_ops, + .pcm_new = s3c_dma_new, + .pcm_free = s3c_dma_free_dma_buffers, }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); @@ -476,5 +476,5 @@ static void __exit s3c24xx_soc_platform_exit(void) module_exit(s3c24xx_soc_platform_exit); MODULE_AUTHOR("Ben Dooks, "); -MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); +MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c24xx-pcm.h index 0088c79822ea..8cbc071124c4 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.h +++ b/sound/soc/s3c24xx/s3c24xx-pcm.h @@ -9,13 +9,13 @@ * ALSA PCM interface for the Samsung S3C24xx CPU */ -#ifndef _S3C24XX_PCM_H -#define _S3C24XX_PCM_H +#ifndef _S3C_AUDIO_H +#define _S3C_AUDIO_H #define ST_RUNNING (1<<0) #define ST_OPENED (1<<1) -struct s3c24xx_pcm_dma_params { +struct s3c_dma_params { struct s3c2410_dma_client *client; /* stream identifier */ int channel; /* Channel ID */ dma_addr_t dma_addr; diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index d68cae15561c..719d63c27fdb 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -46,7 +46,7 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { [0] = { .channel = DMACH_I2S0_OUT, .client = &s3c64xx_dma_client_out, @@ -61,7 +61,7 @@ static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { }, }; -static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { [0] = { .channel = DMACH_I2S0_IN, .client = &s3c64xx_dma_client_in, -- cgit From d3ff5a3e610d62d9cdad5b7d53749c9381e244ed Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:53:31 +0900 Subject: ASoC: Rename 's3c24xx-pcm' driver to 's3c-dma' Making room for namespace for the PCM Controller driver the platform driver(s3c24xx-pcm) has been renamed to SoC agnostic name 's3c-dma'. Signed-off-by: Jassi Brar Acked-by: Ben Dooks Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Makefile | 2 +- sound/soc/s3c24xx/jive_wm8750.c | 2 +- sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- sound/soc/s3c24xx/s3c-dma.c | 481 +++++++++++++++++++++++++ sound/soc/s3c24xx/s3c-dma.h | 31 ++ sound/soc/s3c24xx/s3c-i2s-v2.c | 2 +- sound/soc/s3c24xx/s3c2412-i2s.c | 2 +- sound/soc/s3c24xx/s3c2443-ac97.c | 2 +- sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 480 ------------------------ sound/soc/s3c24xx/s3c24xx-pcm.h | 31 -- sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 2 +- sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- sound/soc/s3c24xx/s3c64xx-i2s.c | 2 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +- sound/soc/s3c24xx/smdk64xx_wm8580.c | 2 +- 20 files changed, 528 insertions(+), 527 deletions(-) create mode 100644 sound/soc/s3c24xx/s3c-dma.c create mode 100644 sound/soc/s3c24xx/s3c-dma.h delete mode 100644 sound/soc/s3c24xx/s3c24xx-pcm.c delete mode 100644 sound/soc/s3c24xx/s3c24xx-pcm.h (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 7790406f90b7..ff0a10536efc 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -1,5 +1,5 @@ # S3c24XX Platform Support -snd-soc-s3c24xx-objs := s3c24xx-pcm.o +snd-soc-s3c24xx-objs := s3c-dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c index 93e6c87b7399..59dc2c6b56d9 100644 --- a/sound/soc/s3c24xx/jive_wm8750.c +++ b/sound/soc/s3c24xx/jive_wm8750.c @@ -25,7 +25,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c2412-i2s.h" #include "../codecs/wm8750.h" diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 12c71482d258..d00d359a03e6 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -24,7 +24,7 @@ #include #include "../codecs/ac97.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" static struct snd_soc_card ln2440sbc; diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 26409a9cef9e..dea83d30a5c9 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -32,7 +32,7 @@ #include #include #include "../codecs/wm8753.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" static struct snd_soc_card neo1973_gta02; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 77de6c5127d2..0cb4f86f6d1e 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -36,7 +36,7 @@ #include "../codecs/wm8753.h" #include "lm4857.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" /* define the scenarios */ diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c new file mode 100644 index 000000000000..7725e26d6c91 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-dma.c @@ -0,0 +1,481 @@ +/* + * s3c-dma.c -- ALSA Soc Audio Layer + * + * (c) 2006 Wolfson Microelectronics PLC. + * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * Copyright 2004-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "s3c-dma.h" + +static const struct snd_pcm_hardware s3c_dma_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S8, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 128*1024, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE*2, + .periods_min = 2, + .periods_max = 128, + .fifo_size = 32, +}; + +struct s3c24xx_runtime_data { + spinlock_t lock; + int state; + unsigned int dma_loaded; + unsigned int dma_limit; + unsigned int dma_period; + dma_addr_t dma_start; + dma_addr_t dma_pos; + dma_addr_t dma_end; + struct s3c_dma_params *params; +}; + +/* s3c_dma_enqueue + * + * place a dma buffer onto the queue for the dma system + * to handle. +*/ +static void s3c_dma_enqueue(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + dma_addr_t pos = prtd->dma_pos; + unsigned int limit; + int ret; + + pr_debug("Entered %s\n", __func__); + + if (s3c_dma_has_circular()) + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; + else + limit = prtd->dma_limit; + + pr_debug("%s: loaded %d, limit %d\n", + __func__, prtd->dma_loaded, limit); + + while (prtd->dma_loaded < limit) { + unsigned long len = prtd->dma_period; + + pr_debug("dma_loaded: %d\n", prtd->dma_loaded); + + if ((pos + len) > prtd->dma_end) { + len = prtd->dma_end - pos; + pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", + __func__, len); + } + + ret = s3c2410_dma_enqueue(prtd->params->channel, + substream, pos, len); + + if (ret == 0) { + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; + } else + break; + } + + prtd->dma_pos = pos; +} + +static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, + void *dev_id, int size, + enum s3c2410_dma_buffresult result) +{ + struct snd_pcm_substream *substream = dev_id; + struct s3c24xx_runtime_data *prtd; + + pr_debug("Entered %s\n", __func__); + + if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) + return; + + prtd = substream->runtime->private_data; + + if (substream) + snd_pcm_period_elapsed(substream); + + spin_lock(&prtd->lock); + if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { + prtd->dma_loaded--; + s3c_dma_enqueue(substream); + } + + spin_unlock(&prtd->lock); +} + +static int s3c_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; + unsigned long totbytes = params_buffer_bytes(params); + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!dma) + return 0; + + /* this may get called several times by oss emulation + * with different params -HW */ + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; + + pr_debug("params %p, client %p, channel %d\n", prtd->params, + prtd->params->client, prtd->params->channel); + + ret = s3c2410_dma_request(prtd->params->channel, + prtd->params->client, NULL); + + if (ret < 0) { + printk(KERN_ERR "failed to get dma channel\n"); + return ret; + } + + /* use the circular buffering if we have it available. */ + if (s3c_dma_has_circular()) + s3c2410_dma_setflags(prtd->params->channel, + S3C2410_DMAF_CIRCULAR); + } + + s3c2410_dma_set_buffdone_fn(prtd->params->channel, + s3c24xx_audio_buffdone); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + runtime->dma_bytes = totbytes; + + spin_lock_irq(&prtd->lock); + prtd->dma_loaded = 0; + prtd->dma_limit = runtime->hw.periods_min; + prtd->dma_period = params_period_bytes(params); + prtd->dma_start = runtime->dma_addr; + prtd->dma_pos = prtd->dma_start; + prtd->dma_end = prtd->dma_start + totbytes; + spin_unlock_irq(&prtd->lock); + + return 0; +} + +static int s3c_dma_hw_free(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + + pr_debug("Entered %s\n", __func__); + + /* TODO - do we need to ensure DMA flushed */ + snd_pcm_set_runtime_buffer(substream, NULL); + + if (prtd->params) { + s3c2410_dma_free(prtd->params->channel, prtd->params->client); + prtd->params = NULL; + } + + return 0; +} + +static int s3c_dma_prepare(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!prtd->params) + return 0; + + /* channel needs configuring for mem=>device, increment memory addr, + * sync to pclk, half-word transfers to the IIS-FIFO. */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + s3c2410_dma_devconfig(prtd->params->channel, + S3C2410_DMASRC_MEM, + prtd->params->dma_addr); + } else { + s3c2410_dma_devconfig(prtd->params->channel, + S3C2410_DMASRC_HW, + prtd->params->dma_addr); + } + + s3c2410_dma_config(prtd->params->channel, + prtd->params->dma_size); + + /* flush the DMA channel */ + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); + prtd->dma_loaded = 0; + prtd->dma_pos = prtd->dma_start; + + /* enqueue dma buffers */ + s3c_dma_enqueue(substream); + + return ret; +} + +static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + spin_lock(&prtd->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + prtd->state |= ST_RUNNING; + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->state &= ~ST_RUNNING; + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); + break; + + default: + ret = -EINVAL; + break; + } + + spin_unlock(&prtd->lock); + + return ret; +} + +static snd_pcm_uframes_t +s3c_dma_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + unsigned long res; + dma_addr_t src, dst; + + pr_debug("Entered %s\n", __func__); + + spin_lock(&prtd->lock); + s3c2410_dma_getposition(prtd->params->channel, &src, &dst); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + res = dst - prtd->dma_start; + else + res = src - prtd->dma_start; + + spin_unlock(&prtd->lock); + + pr_debug("Pointer %x %x\n", src, dst); + + /* we seem to be getting the odd error from the pcm library due + * to out-of-bounds pointers. this is maybe due to the dma engine + * not having loaded the new values for the channel before being + * callled... (todo - fix ) + */ + + if (res >= snd_pcm_lib_buffer_bytes(substream)) { + if (res == snd_pcm_lib_buffer_bytes(substream)) + res = 0; + } + + return bytes_to_frames(substream->runtime, res); +} + +static int s3c_dma_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd; + + pr_debug("Entered %s\n", __func__); + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); + + prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + spin_lock_init(&prtd->lock); + + runtime->private_data = prtd; + return 0; +} + +static int s3c_dma_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + + pr_debug("Entered %s\n", __func__); + + if (!prtd) + pr_debug("s3c_dma_close called with prtd == NULL\n"); + + kfree(prtd); + + return 0; +} + +static int s3c_dma_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + pr_debug("Entered %s\n", __func__); + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops s3c_dma_ops = { + .open = s3c_dma_open, + .close = s3c_dma_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = s3c_dma_hw_params, + .hw_free = s3c_dma_hw_free, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .pointer = s3c_dma_pointer, + .mmap = s3c_dma_mmap, +}; + +static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = s3c_dma_hardware.buffer_bytes_max; + + pr_debug("Entered %s\n", __func__); + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + return 0; +} + +static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + pr_debug("Entered %s\n", __func__); + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static u64 s3c_dma_mask = DMA_BIT_MASK(32); + +static int s3c_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + if (!card->dev->dma_mask) + card->dev->dma_mask = &s3c_dma_mask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = s3c_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = s3c_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +struct snd_soc_platform s3c24xx_soc_platform = { + .name = "s3c24xx-audio", + .pcm_ops = &s3c_dma_ops, + .pcm_new = s3c_dma_new, + .pcm_free = s3c_dma_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); + +static int __init s3c24xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&s3c24xx_soc_platform); +} +module_init(s3c24xx_soc_platform_init); + +static void __exit s3c24xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&s3c24xx_soc_platform); +} +module_exit(s3c24xx_soc_platform_exit); + +MODULE_AUTHOR("Ben Dooks, "); +MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h new file mode 100644 index 000000000000..69bb6bf6fc1c --- /dev/null +++ b/sound/soc/s3c24xx/s3c-dma.h @@ -0,0 +1,31 @@ +/* + * s3c-dma.h -- + * + * 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. + * + * ALSA PCM interface for the Samsung S3C24xx CPU + */ + +#ifndef _S3C_AUDIO_H +#define _S3C_AUDIO_H + +#define ST_RUNNING (1<<0) +#define ST_OPENED (1<<1) + +struct s3c_dma_params { + struct s3c2410_dma_client *client; /* stream identifier */ + int channel; /* Channel ID */ + dma_addr_t dma_addr; + int dma_size; /* Size of the DMA transfer */ +}; + +#define S3C24XX_DAI_I2S 0 + +/* platform data */ +extern struct snd_soc_platform s3c24xx_soc_platform; +extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; + +#endif diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 5a442aa8b87b..e994d8374fe6 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -35,7 +35,7 @@ #include #include "s3c-i2s-v2.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #undef S3C_IIS_V2_SUPPORTED diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 23718ea85182..359e59346ba2 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -37,7 +37,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c2412-i2s.h" #define S3C2412_I2S_DEBUG 0 diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 678b1763160b..0191e3acb0b4 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -35,7 +35,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" struct s3c24xx_ac97_info { diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index afb4bc9033c8..0bc5950b9f02 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -38,7 +38,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" static struct s3c2410_dma_client s3c24xx_dma_client_out = { diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c deleted file mode 100644 index cb49400d8c56..000000000000 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * s3c24xx-pcm.c -- ALSA Soc Audio Layer - * - * (c) 2006 Wolfson Microelectronics PLC. - * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * Copyright 2004-2005 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "s3c24xx-pcm.h" - -static const struct snd_pcm_hardware s3c_dma_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 128*1024, - .period_bytes_min = PAGE_SIZE, - .period_bytes_max = PAGE_SIZE*2, - .periods_min = 2, - .periods_max = 128, - .fifo_size = 32, -}; - -struct s3c24xx_runtime_data { - spinlock_t lock; - int state; - unsigned int dma_loaded; - unsigned int dma_limit; - unsigned int dma_period; - dma_addr_t dma_start; - dma_addr_t dma_pos; - dma_addr_t dma_end; - struct s3c_dma_params *params; -}; - -/* s3c_dma_enqueue - * - * place a dma buffer onto the queue for the dma system - * to handle. -*/ -static void s3c_dma_enqueue(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - dma_addr_t pos = prtd->dma_pos; - unsigned int limit; - int ret; - - pr_debug("Entered %s\n", __func__); - - if (s3c_dma_has_circular()) { - limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; - } else - limit = prtd->dma_limit; - - pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); - - while (prtd->dma_loaded < limit) { - unsigned long len = prtd->dma_period; - - pr_debug("dma_loaded: %d\n", prtd->dma_loaded); - - if ((pos + len) > prtd->dma_end) { - len = prtd->dma_end - pos; - pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", - __func__, len); - } - - ret = s3c2410_dma_enqueue(prtd->params->channel, - substream, pos, len); - - if (ret == 0) { - prtd->dma_loaded++; - pos += prtd->dma_period; - if (pos >= prtd->dma_end) - pos = prtd->dma_start; - } else - break; - } - - prtd->dma_pos = pos; -} - -static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, - void *dev_id, int size, - enum s3c2410_dma_buffresult result) -{ - struct snd_pcm_substream *substream = dev_id; - struct s3c24xx_runtime_data *prtd; - - pr_debug("Entered %s\n", __func__); - - if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) - return; - - prtd = substream->runtime->private_data; - - if (substream) - snd_pcm_period_elapsed(substream); - - spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { - prtd->dma_loaded--; - s3c_dma_enqueue(substream); - } - - spin_unlock(&prtd->lock); -} - -static int s3c_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; - unsigned long totbytes = params_buffer_bytes(params); - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!dma) - return 0; - - /* this may get called several times by oss emulation - * with different params -HW */ - if (prtd->params == NULL) { - /* prepare DMA */ - prtd->params = dma; - - pr_debug("params %p, client %p, channel %d\n", prtd->params, - prtd->params->client, prtd->params->channel); - - ret = s3c2410_dma_request(prtd->params->channel, - prtd->params->client, NULL); - - if (ret < 0) { - printk(KERN_ERR "failed to get dma channel\n"); - return ret; - } - - /* use the circular buffering if we have it available. */ - if (s3c_dma_has_circular()) - s3c2410_dma_setflags(prtd->params->channel, - S3C2410_DMAF_CIRCULAR); - } - - s3c2410_dma_set_buffdone_fn(prtd->params->channel, - s3c24xx_audio_buffdone); - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - - runtime->dma_bytes = totbytes; - - spin_lock_irq(&prtd->lock); - prtd->dma_loaded = 0; - prtd->dma_limit = runtime->hw.periods_min; - prtd->dma_period = params_period_bytes(params); - prtd->dma_start = runtime->dma_addr; - prtd->dma_pos = prtd->dma_start; - prtd->dma_end = prtd->dma_start + totbytes; - spin_unlock_irq(&prtd->lock); - - return 0; -} - -static int s3c_dma_hw_free(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - /* TODO - do we need to ensure DMA flushed */ - snd_pcm_set_runtime_buffer(substream, NULL); - - if (prtd->params) { - s3c2410_dma_free(prtd->params->channel, prtd->params->client); - prtd->params = NULL; - } - - return 0; -} - -static int s3c_dma_prepare(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!prtd->params) - return 0; - - /* channel needs configuring for mem=>device, increment memory addr, - * sync to pclk, half-word transfers to the IIS-FIFO. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_MEM, - prtd->params->dma_addr); - } else { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_HW, - prtd->params->dma_addr); - } - - s3c2410_dma_config(prtd->params->channel, - prtd->params->dma_size); - - /* flush the DMA channel */ - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); - prtd->dma_loaded = 0; - prtd->dma_pos = prtd->dma_start; - - /* enqueue dma buffers */ - s3c_dma_enqueue(substream); - - return ret; -} - -static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - spin_lock(&prtd->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - prtd->state |= ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - prtd->state &= ~ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); - break; - - default: - ret = -EINVAL; - break; - } - - spin_unlock(&prtd->lock); - - return ret; -} - -static snd_pcm_uframes_t -s3c_dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - unsigned long res; - dma_addr_t src, dst; - - pr_debug("Entered %s\n", __func__); - - spin_lock(&prtd->lock); - s3c2410_dma_getposition(prtd->params->channel, &src, &dst); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - res = dst - prtd->dma_start; - else - res = src - prtd->dma_start; - - spin_unlock(&prtd->lock); - - pr_debug("Pointer %x %x\n", src, dst); - - /* we seem to be getting the odd error from the pcm library due - * to out-of-bounds pointers. this is maybe due to the dma engine - * not having loaded the new values for the channel before being - * callled... (todo - fix ) - */ - - if (res >= snd_pcm_lib_buffer_bytes(substream)) { - if (res == snd_pcm_lib_buffer_bytes(substream)) - res = 0; - } - - return bytes_to_frames(substream->runtime, res); -} - -static int s3c_dma_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd; - - pr_debug("Entered %s\n", __func__); - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); - - prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - - runtime->private_data = prtd; - return 0; -} - -static int s3c_dma_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - if (!prtd) - pr_debug("s3c_dma_close called with prtd == NULL\n"); - - kfree(prtd); - - return 0; -} - -static int s3c_dma_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - pr_debug("Entered %s\n", __func__); - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -static struct snd_pcm_ops s3c_dma_ops = { - .open = s3c_dma_open, - .close = s3c_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = s3c_dma_hw_params, - .hw_free = s3c_dma_hw_free, - .prepare = s3c_dma_prepare, - .trigger = s3c_dma_trigger, - .pointer = s3c_dma_pointer, - .mmap = s3c_dma_mmap, -}; - -static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = s3c_dma_hardware.buffer_bytes_max; - - pr_debug("Entered %s\n", __func__); - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - if (!buf->area) - return -ENOMEM; - buf->bytes = size; - return 0; -} - -static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - pr_debug("Entered %s\n", __func__); - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -static u64 s3c_dma_mask = DMA_BIT_MASK(32); - -static int s3c_dma_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - if (!card->dev->dma_mask) - card->dev->dma_mask = &s3c_dma_mask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = s3c_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = s3c_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -struct snd_soc_platform s3c24xx_soc_platform = { - .name = "s3c24xx-audio", - .pcm_ops = &s3c_dma_ops, - .pcm_new = s3c_dma_new, - .pcm_free = s3c_dma_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); - -static int __init s3c24xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&s3c24xx_soc_platform); -} -module_init(s3c24xx_soc_platform_init); - -static void __exit s3c24xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&s3c24xx_soc_platform); -} -module_exit(s3c24xx_soc_platform_exit); - -MODULE_AUTHOR("Ben Dooks, "); -MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c24xx-pcm.h deleted file mode 100644 index 8cbc071124c4..000000000000 --- a/sound/soc/s3c24xx/s3c24xx-pcm.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * s3c24xx-pcm.h -- - * - * 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. - * - * ALSA PCM interface for the Samsung S3C24xx CPU - */ - -#ifndef _S3C_AUDIO_H -#define _S3C_AUDIO_H - -#define ST_RUNNING (1<<0) -#define ST_OPENED (1<<1) - -struct s3c_dma_params { - struct s3c2410_dma_client *client; /* stream identifier */ - int channel; /* Channel ID */ - dma_addr_t dma_addr; - int dma_size; /* Size of the DMA transfer */ -}; - -#define S3C24XX_DAI_I2S 0 - -/* platform data */ -extern struct snd_soc_platform s3c24xx_soc_platform; -extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; - -#endif diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c index 1966e0d5652d..507b2ed5d58b 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -21,7 +21,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c index 8346bd96eaf5..bdf8951af8e3 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c @@ -18,7 +18,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c index 25797e096175..185c0acb5ce6 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c @@ -18,7 +18,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index c215d32d6322..052d59659c29 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -24,7 +24,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "../codecs/uda134x.h" diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 719d63c27fdb..cc7edb5f792d 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -35,7 +35,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c64xx-i2s.h" static struct s3c2410_dma_client s3c64xx_dma_client_out = { diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index a2a4f5323c17..12b783b12fcb 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -20,7 +20,7 @@ #include #include "../codecs/ac97.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" static struct snd_soc_card smdk2443; diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index 216dd1e8e378..efe4901213a3 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -19,7 +19,7 @@ #include #include "../codecs/wm8580.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c64xx-i2s.h" #define S3C64XX_I2S_V4 2 -- cgit From 357a1db94ecc5b3d605574b164d288cd7dbf8dbd Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:54:03 +0900 Subject: ASoC: Added the CPU driver for PCM controllers Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 3 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/s3c-pcm.c | 552 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/s3c24xx/s3c-pcm.h | 123 ++++++++++ 4 files changed, 680 insertions(+) create mode 100644 sound/soc/s3c24xx/s3c-pcm.c create mode 100644 sound/soc/s3c24xx/s3c-pcm.h (limited to 'sound/soc/s3c24xx') diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index d7912f1e4627..b489f1ae103d 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -24,6 +24,9 @@ config SND_S3C64XX_SOC_I2S select SND_S3C_I2SV2_SOC select S3C64XX_DMA +config SND_S3C_SOC_PCM + tristate + config SND_S3C2443_SOC_AC97 tristate select S3C2410_DMA diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index ff0a10536efc..b744657733d7 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -5,6 +5,7 @@ snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o +snd-soc-s3c-pcm-objs := s3c-pcm.o obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o @@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o +obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o # S3C24XX Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c new file mode 100644 index 000000000000..9e61a7c2d9ac --- /dev/null +++ b/sound/soc/s3c24xx/s3c-pcm.c @@ -0,0 +1,552 @@ +/* sound/soc/s3c24xx/s3c-pcm.c + * + * ALSA SoC Audio Layer - S3C PCM-Controller driver + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * based upon I2S drivers by Ben Dooks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "s3c-dma.h" +#include "s3c-pcm.h" + +static struct s3c2410_dma_client s3c_pcm_dma_client_out = { + .name = "PCM Stereo out" +}; + +static struct s3c2410_dma_client s3c_pcm_dma_client_in = { + .name = "PCM Stereo in" +}; + +static struct s3c_dma_params s3c_pcm_stereo_out[] = { + [0] = { + .client = &s3c_pcm_dma_client_out, + .dma_size = 4, + }, + [1] = { + .client = &s3c_pcm_dma_client_out, + .dma_size = 4, + }, +}; + +static struct s3c_dma_params s3c_pcm_stereo_in[] = { + [0] = { + .client = &s3c_pcm_dma_client_in, + .dma_size = 4, + }, + [1] = { + .client = &s3c_pcm_dma_client_in, + .dma_size = 4, + }, +}; + +static struct s3c_pcm_info s3c_pcm[2]; + +static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai) +{ + return cpu_dai->private_data; +} + +static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on) +{ + void __iomem *regs = pcm->regs; + u32 ctl, clkctl; + + clkctl = readl(regs + S3C_PCM_CLKCTL); + ctl = readl(regs + S3C_PCM_CTL); + ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK + << S3C_PCM_CTL_TXDIPSTICK_SHIFT); + + if (on) { + ctl |= S3C_PCM_CTL_TXDMA_EN; + ctl |= S3C_PCM_CTL_TXFIFO_EN; + ctl |= S3C_PCM_CTL_ENABLE; + ctl |= (0x20<idleclk) + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + writel(ctl, regs + S3C_PCM_CTL); +} + +static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on) +{ + void __iomem *regs = pcm->regs; + u32 ctl, clkctl; + + ctl = readl(regs + S3C_PCM_CTL); + clkctl = readl(regs + S3C_PCM_CLKCTL); + + if (on) { + ctl |= S3C_PCM_CTL_RXDMA_EN; + ctl |= S3C_PCM_CTL_RXFIFO_EN; + ctl |= S3C_PCM_CTL_ENABLE; + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } else { + ctl &= ~S3C_PCM_CTL_RXDMA_EN; + ctl &= ~S3C_PCM_CTL_RXFIFO_EN; + + if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) { + ctl &= ~S3C_PCM_CTL_ENABLE; + if (!pcm->idleclk) + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + writel(ctl, regs + S3C_PCM_CTL); +} + +static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai); + unsigned long flags; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock_irqsave(&pcm->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + s3c_pcm_snd_rxctrl(pcm, 1); + else + s3c_pcm_snd_txctrl(pcm, 1); + + spin_unlock_irqrestore(&pcm->lock, flags); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&pcm->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + s3c_pcm_snd_rxctrl(pcm, 0); + else + s3c_pcm_snd_txctrl(pcm, 0); + + spin_unlock_irqrestore(&pcm->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *socdai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai = rtd->dai; + struct s3c_pcm_info *pcm = to_info(dai->cpu_dai); + void __iomem *regs = pcm->regs; + struct clk *clk; + int sclk_div, sync_div; + unsigned long flags; + u32 clkctl; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dai->cpu_dai->dma_data = pcm->dma_playback; + else + dai->cpu_dai->dma_data = pcm->dma_capture; + + /* Strictly check for sample size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&pcm->lock, flags); + + /* Get hold of the PCMSOURCE_CLK */ + clkctl = readl(regs + S3C_PCM_CLKCTL); + if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK) + clk = pcm->pclk; + else + clk = pcm->cclk; + + /* Set the SCLK divider */ + sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs / + params_rate(params) / 2 - 1; + + clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK + << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); + clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK) + << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); + + /* Set the SYNC divider */ + sync_div = pcm->sclk_per_fs - 1; + + clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK + << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); + clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK) + << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); + + writel(clkctl, regs + S3C_PCM_CLKCTL); + + spin_unlock_irqrestore(&pcm->lock, flags); + + dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \ + SCLK_DIV=%d SYNC_DIV=%d\n", + clk_get_rate(clk), pcm->sclk_per_fs, + sclk_div, sync_div); + + return 0; +} + +static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + void __iomem *regs = pcm->regs; + unsigned long flags; + int ret = 0; + u32 ctl; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + spin_lock_irqsave(&pcm->lock, flags); + + ctl = readl(regs + S3C_PCM_CTL); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* Nothing to do, NB_NF by default */ + break; + default: + dev_err(pcm->dev, "Unsupported clock inversion!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Nothing to do, Master by default */ + break; + default: + dev_err(pcm->dev, "Unsupported master/slave format!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: + pcm->idleclk = 1; + break; + case SND_SOC_DAIFMT_GATED: + pcm->idleclk = 0; + break; + default: + dev_err(pcm->dev, "Invalid Clock gating request!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC; + ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC; + break; + case SND_SOC_DAIFMT_DSP_B: + ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC; + ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC; + break; + default: + dev_err(pcm->dev, "Unsupported data format!\n"); + ret = -EINVAL; + goto exit; + } + + writel(ctl, regs + S3C_PCM_CTL); + +exit: + spin_unlock_irqrestore(&pcm->lock, flags); + + return ret; +} + +static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + + switch (div_id) { + case S3C_PCM_SCLK_PER_FS: + pcm->sclk_per_fs = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + void __iomem *regs = pcm->regs; + u32 clkctl = readl(regs + S3C_PCM_CLKCTL); + + switch (clk_id) { + case S3C_PCM_CLKSRC_PCLK: + clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK; + break; + + case S3C_PCM_CLKSRC_MUX: + clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK; + + if (clk_get_rate(pcm->cclk) != freq) + clk_set_rate(pcm->cclk, freq); + + break; + + default: + return -EINVAL; + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + + return 0; +} + +static struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + +#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 + +#define S3C_PCM_DECLARE(n) \ +{ \ + .name = "samsung-pcm", \ + .id = (n), \ + .symmetric_rates = 1, \ + .ops = &s3c_pcm_dai_ops, \ + .playback = { \ + .channels_min = 2, \ + .channels_max = 2, \ + .rates = S3C_PCM_RATES, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE, \ + }, \ + .capture = { \ + .channels_min = 2, \ + .channels_max = 2, \ + .rates = S3C_PCM_RATES, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE, \ + }, \ +} + +struct snd_soc_dai s3c_pcm_dai[] = { + S3C_PCM_DECLARE(0), + S3C_PCM_DECLARE(1), +}; +EXPORT_SYMBOL_GPL(s3c_pcm_dai); + +static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) +{ + struct s3c_pcm_info *pcm; + struct snd_soc_dai *dai; + struct resource *mem_res, *dmatx_res, *dmarx_res; + struct s3c_audio_pdata *pcm_pdata; + int ret; + + /* Check for valid device index */ + if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) { + dev_err(&pdev->dev, "id %d out of range\n", pdev->id); + return -EINVAL; + } + + pcm_pdata = pdev->dev.platform_data; + + /* Check for availability of necessary resource */ + dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmatx_res) { + dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n"); + return -ENXIO; + } + + dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!dmarx_res) { + dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n"); + return -ENXIO; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "Unable to get register resource\n"); + return -ENXIO; + } + + if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { + dev_err(&pdev->dev, "Unable to configure gpio\n"); + return -EINVAL; + } + + pcm = &s3c_pcm[pdev->id]; + pcm->dev = &pdev->dev; + + spin_lock_init(&pcm->lock); + + dai = &s3c_pcm_dai[pdev->id]; + dai->dev = &pdev->dev; + + /* Default is 128fs */ + pcm->sclk_per_fs = 128; + + pcm->cclk = clk_get(&pdev->dev, "audio-bus"); + if (IS_ERR(pcm->cclk)) { + dev_err(&pdev->dev, "failed to get audio-bus\n"); + ret = PTR_ERR(pcm->cclk); + goto err1; + } + clk_enable(pcm->cclk); + + /* record our pcm structure for later use in the callbacks */ + dai->private_data = pcm; + + if (!request_mem_region(mem_res->start, + resource_size(mem_res), "samsung-pcm")) { + dev_err(&pdev->dev, "Unable to request register region\n"); + ret = -EBUSY; + goto err2; + } + + pcm->regs = ioremap(mem_res->start, 0x100); + if (pcm->regs == NULL) { + dev_err(&pdev->dev, "cannot ioremap registers\n"); + ret = -ENXIO; + goto err3; + } + + pcm->pclk = clk_get(&pdev->dev, "pcm"); + if (IS_ERR(pcm->pclk)) { + dev_err(&pdev->dev, "failed to get pcm_clock\n"); + ret = -ENOENT; + goto err4; + } + clk_enable(pcm->pclk); + + ret = snd_soc_register_dai(dai); + if (ret != 0) { + dev_err(&pdev->dev, "failed to get pcm_clock\n"); + goto err5; + } + + s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start + + S3C_PCM_RXFIFO; + s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start + + S3C_PCM_TXFIFO; + + s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start; + s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start; + + pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; + pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; + + return 0; + +err5: + clk_disable(pcm->pclk); + clk_put(pcm->pclk); +err4: + iounmap(pcm->regs); +err3: + release_mem_region(mem_res->start, resource_size(mem_res)); +err2: + clk_disable(pcm->cclk); + clk_put(pcm->cclk); +err1: + return ret; +} + +static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) +{ + struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; + struct resource *mem_res; + + iounmap(pcm->regs); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem_res->start, resource_size(mem_res)); + + clk_disable(pcm->cclk); + clk_disable(pcm->pclk); + clk_put(pcm->pclk); + clk_put(pcm->cclk); + + return 0; +} + +static struct platform_driver s3c_pcm_driver = { + .probe = s3c_pcm_dev_probe, + .remove = s3c_pcm_dev_remove, + .driver = { + .name = "samsung-pcm", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c_pcm_init(void) +{ + return platform_driver_register(&s3c_pcm_driver); +} +module_init(s3c_pcm_init); + +static void __exit s3c_pcm_exit(void) +{ + platform_driver_unregister(&s3c_pcm_driver); +} +module_exit(s3c_pcm_exit); + +/* Module information */ +MODULE_AUTHOR("Jaswinder Singh, "); +MODULE_DESCRIPTION("S3C PCM Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h new file mode 100644 index 000000000000..69ff9971692f --- /dev/null +++ b/sound/soc/s3c24xx/s3c-pcm.h @@ -0,0 +1,123 @@ +/* sound/soc/s3c24xx/s3c-pcm.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __S3C_PCM_H +#define __S3C_PCM_H __FILE__ + +/*Register Offsets */ +#define S3C_PCM_CTL (0x00) +#define S3C_PCM_CLKCTL (0x04) +#define S3C_PCM_TXFIFO (0x08) +#define S3C_PCM_RXFIFO (0x0C) +#define S3C_PCM_IRQCTL (0x10) +#define S3C_PCM_IRQSTAT (0x14) +#define S3C_PCM_FIFOSTAT (0x18) +#define S3C_PCM_CLRINT (0x20) + +/* PCM_CTL Bit-Fields */ +#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f) +#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13) +#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7) +#define S3C_PCM_CTL_TXDMA_EN (0x1<<6) +#define S3C_PCM_CTL_RXDMA_EN (0x1<<5) +#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4) +#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3) +#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2) +#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1) +#define S3C_PCM_CTL_ENABLE (0x1<<0) + +/* PCM_CLKCTL Bit-Fields */ +#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19) +#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18) +#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff) +#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff) +#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9) +#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0) + +/* PCM_TXFIFO Bit-Fields */ +#define S3C_PCM_TXFIFO_DVALID (0x1<<16) +#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0) + +/* PCM_RXFIFO Bit-Fields */ +#define S3C_PCM_RXFIFO_DVALID (0x1<<16) +#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0) + +/* PCM_IRQCTL Bit-Fields */ +#define S3C_PCM_IRQCTL_IRQEN (0x1<<14) +#define S3C_PCM_IRQCTL_WRDEN (0x1<<12) +#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11) +#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10) +#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9) +#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8) +#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7) +#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6) +#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5) +#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4) +#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3) +#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2) +#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1) +#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0) + +/* PCM_IRQSTAT Bit-Fields */ +#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13) +#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12) +#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11) +#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10) +#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9) +#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8) +#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7) +#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6) +#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5) +#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4) +#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3) +#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2) +#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1) +#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0) + +/* PCM_FIFOSTAT Bit-Fields */ +#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14) +#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13) +#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12) +#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11) +#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10) +#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4) +#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3) +#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2) +#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1) +#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0) + +#define S3C_PCM_CLKSRC_PCLK 0 +#define S3C_PCM_CLKSRC_MUX 1 + +#define S3C_PCM_SCLK_PER_FS 0 + +/** + * struct s3c_pcm_info - S3C PCM Controller information + * @dev: The parent device passed to use from the probe. + * @regs: The pointer to the device register block. + * @dma_playback: DMA information for playback channel. + * @dma_capture: DMA information for capture channel. + */ +struct s3c_pcm_info { + spinlock_t lock; + struct device *dev; + void __iomem *regs; + + unsigned int sclk_per_fs; + + /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */ + unsigned int idleclk; + + struct clk *pclk; + struct clk *cclk; + + struct s3c_dma_params *dma_playback; + struct s3c_dma_params *dma_capture; +}; + +#endif /* __S3C_PCM_H */ -- cgit