diff options
author | Robert Hodaszi <robert.hodaszi@digi.com> | 2011-06-09 19:31:44 +0200 |
---|---|---|
committer | Hector Palacios <hector.palacios@digi.com> | 2011-09-01 10:36:33 +0200 |
commit | ccbd372e0b81a18e28e082e5c1895d604e2de714 (patch) | |
tree | d3439e3320fd418571c96760c714b83890a67d3d /sound | |
parent | f346685892b3f72f7896c51c2f799195f677e373 (diff) |
merge: merged audio and touchscreen for CC9M2443 from 2.6.28
Signed-off-by: Robert Hodaszi <robert.hodaszi@digi.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/s3c24xx/Kconfig | 17 | ||||
-rw-r--r-- | sound/soc/s3c24xx/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/s3c24xx/cc9m2443js_wm8753.c | 61 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-dma.c | 72 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.c | 37 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.h | 15 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c2412-i2s.c | 88 |
7 files changed, 257 insertions, 35 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 2a7cc222d098..64e8b2982495 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -70,6 +70,23 @@ config SND_S3C64XX_SOC_WM8580 help Say Y if you want to add support for SoC audio on the SMDK6410. +config SND_S3C24XX_SOC_CC9M2443JS_WM8753 + tristate "SoC I2S Audio support for Digi CC9M2443JS - WM8753" + depends on SND_S3C24XX_SOC && MACH_CC9M2443JS + select I2C_S3C2410 + select SND_S3C2412_SOC_I2S + select SND_SOC_WM8753 + help + Say Y if you want to add support for SoC audio on the Digi CC9M2443 + Jumper Start with the codec WM8753. + +config CC9M2443JS_WM8753_I2C_ADAPTER + int "I2C adapter connected with the WM8753" + depends on SND_S3C24XX_SOC_CC9M2443JS_WM8753 + default 1 + help + This is the adapter/bus number where the WM8753 is connected to. + 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 81d8dc503f87..a32e16dceab2 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -29,6 +29,7 @@ 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 snd-soc-smdk-wm9713-objs := smdk_wm9713.o +snd-soc-cc9m2443js-wm8753-objs := cc9m2443js_wm8753.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 @@ -41,3 +42,4 @@ 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 obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o +obj-$(CONFIG_SND_S3C24XX_SOC_CC9M2443JS_WM8753) += snd-soc-cc9m2443js-wm8753.o diff --git a/sound/soc/s3c24xx/cc9m2443js_wm8753.c b/sound/soc/s3c24xx/cc9m2443js_wm8753.c index 7004fa621cf7..c7a7fe7331a5 100644 --- a/sound/soc/s3c24xx/cc9m2443js_wm8753.c +++ b/sound/soc/s3c24xx/cc9m2443js_wm8753.c @@ -37,16 +37,15 @@ #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> -#include <mach/audio.h> -#include <linux/io.h> +#include <plat/audio.h> #include <mach/spi-gpio.h> #include <sound/pcm_params.h> -#include <asm/plat-s3c24xx/regs-iis.h> +#include <plat/regs-iis.h> #include "../codecs/wm8753.h" #include "lm4857.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c2412-i2s.h" /* Additional info and error messages */ @@ -72,7 +71,7 @@ static int cc9m2443js_hifi_hw_params(struct snd_pcm_substream *substream, unsigned int pll_out = 0, bclk = 0; int ret = 0; unsigned long bitfs, is16bit; - struct s3c2412_rate_calc info; + struct s3c_i2sv2_rate_calc info; switch (params_rate(params)) { case 8000: @@ -106,28 +105,28 @@ static int cc9m2443js_hifi_hw_params(struct snd_pcm_substream *substream, } /* cpu_iis_mclk = iis_clkrate / params_rate(params); */ - s3c2412_iis_calc_rate(&info, NULL, params_rate(params), s3c2412_get_iisclk()); + s3c_i2sv2_iis_calc_rate(&info, NULL, params_rate(params), s3c_i2sv2_get_clock(cpu_dai)); printk_debug("Sample rate %i | Master Clk %lu Hz | FS %u | Clk divisor %u\n", - params_rate(params), clk_get_rate(s3c2412_get_iisclk()), + params_rate(params), clk_get_rate(s3c_i2sv2_get_clock(cpu_dai)), info.fs_div, info.clk_div); /* REQUIRED: Set codec DAI configuration (normal bclk and frm ) and as slave */ - ret = codec_dai->dai_ops.set_fmt(codec_dai, + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* REQUIRED: Set cpu DAI configuration (normal bclk and frm) and CPU as master */ - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* REQUIRED: Set the codec system clock for DAC and ADC */ - ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out, + ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, SND_SOC_CLOCK_OUT); if (ret < 0) { printk_err("set_sysclk() failed (%i)\n", ret); @@ -135,7 +134,7 @@ static int cc9m2443js_hifi_hw_params(struct snd_pcm_substream *substream, } /* REQUIRED: Set MCLK division for sample rate (256, 384, 512, 768) */ - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, info.fs_div); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, info.fs_div); if (ret < 0) return ret; @@ -145,19 +144,31 @@ static int cc9m2443js_hifi_hw_params(struct snd_pcm_substream *substream, * to the table 25-2 of the data sheet of the S3C2443 * @XXX: Define the corresponding macros for the Bit FS selection */ - is16bit = (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) ? 1 : 0; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + is16bit = 0; + break; + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + is16bit = 1; + break; + default: + return -EINVAL; + } + switch (info.fs_div) { case 256: - bitfs = (is16bit) ? 0x0 : 0x2; + bitfs = (is16bit) ? 32 : 16; break; case 512: - bitfs = (is16bit) ? 0x0 : 0x2; + bitfs = (is16bit) ? 32 : 16; break; case 384: - bitfs = (is16bit) ? 0x0 : 0x2; + bitfs = (is16bit) ? 32 : 16; break; case 768: - bitfs = (is16bit) ? 0x0 : 0x2; + bitfs = (is16bit) ? 32 : 16; break; default: printk_err("Unsupported root clock FS %i divisor found\n", info.fs_div); @@ -166,14 +177,14 @@ static int cc9m2443js_hifi_hw_params(struct snd_pcm_substream *substream, break; } - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C2412_DIV_BCLK, bitfs); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_BCLK, bitfs); if (ret) { printk_err("Couldn't set the BLCK, %i\n", ret); return ret; } /* Set the prescaler divisor for the master clock */ - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, info.clk_div); if (ret < 0) { printk_err("Prescaler setting failed, %i\n", ret); @@ -190,7 +201,7 @@ static int cc9m2443js_hifi_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } static int cc9m2443js_hifi_startup(struct snd_pcm_substream *substream) @@ -246,22 +257,16 @@ static struct snd_soc_dai_link cc9m2443js_dai[] = { }; /* This is the machine-structure */ -static struct snd_soc_machine cc9m2443js_snd = { +static struct snd_soc_card cc9m2443js_snd = { .name = "cc9m2443js", + .platform = &s3c24xx_soc_platform, .dai_link = cc9m2443js_dai, .num_links = ARRAY_SIZE(cc9m2443js_dai), }; -static struct wm8753_setup_data cc9m2443js_wm8753_setup = { - .i2c_address = 0x1a, - .i2c_bus = CONFIG_CC9M2443JS_WM8753_I2C_ADAPTER, -}; - static struct snd_soc_device cc9m2443js_snd_devdata = { - .machine = &cc9m2443js_snd, - .platform = &s3c24xx_soc_platform, + .card = &cc9m2443js_snd, .codec_dev = &soc_codec_dev_wm8753, - .codec_data = &cc9m2443js_wm8753_setup, }; static struct platform_device *cc9m2443js_snd_device; diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c index 1b61c23ff300..745ea67f93cb 100644 --- a/sound/soc/s3c24xx/s3c-dma.c +++ b/sound/soc/s3c24xx/s3c-dma.c @@ -63,6 +63,8 @@ struct s3c24xx_runtime_data { dma_addr_t dma_pos; dma_addr_t dma_end; struct s3c_dma_params *params; + + int resumed; }; /* s3c_dma_enqueue @@ -458,11 +460,81 @@ static int s3c_dma_new(struct snd_card *card, return ret; } +/* Enables the support of the Power Management */ +#if defined(CONFIG_PM) +static int s3c_dma_suspend(struct snd_soc_dai_link *dai_link) +{ + struct snd_pcm *pcm = dai_link->pcm; + struct snd_pcm_str *stream = &pcm->streams[0]; + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd; + int retval; + + retval = 0; + if (!runtime) + goto exit_suspend; + + prtd = runtime->private_data; + if (!prtd) + goto exit_suspend; + + prtd->resumed = 0; + +exit_suspend: + return retval; +} + +/* We need to reenable the DMA-channel when coming out from the suspend */ +static int s3c_dma_resume(struct snd_soc_dai_link *dai_link) +{ + struct snd_pcm *pcm = dai_link->pcm; + struct snd_pcm_str *stream = &pcm->streams[0]; + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd; + int retval; + + retval = 0; + if (!runtime) + goto exit_resume; + + prtd = runtime->private_data; + if (!prtd) + goto exit_resume; + + /* Check if a DMA-channel is available and was not already resumed */ + if (prtd->params != NULL && !prtd->resumed) { + + /* + * We must reenable the DMA-channels otherwise they will not work + * after the wakeup-reset + */ + s3c2410_dma_free(prtd->params->channel, prtd->params->client); + retval = s3c2410_dma_request(prtd->params->channel, + prtd->params->client, NULL); + if (retval < 0) + printk(KERN_ERR "s3c24xx-pcm: DMA %u request failed (%i)\n", + prtd->params->channel, retval); + else + prtd->resumed = 1; + } + +exit_resume: + return retval; +} +#else +#define s3c_dma_suspend NULL +#define s3c_dma_resume NULL +#endif /* defined(CONFIG_PM) */ + 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, + .suspend = s3c_dma_suspend, + .resume = s3c_dma_resume, }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 13311c8cf965..6ebb8780ec71 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -32,7 +32,7 @@ #undef S3C_IIS_V2_SUPPORTED -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) || defined(CONFIG_CPU_S3C2443) #define S3C_IIS_V2_SUPPORTED #endif @@ -532,8 +532,9 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, case S3C_I2SV2_DIV_PRESCALER: if (div >= 0) { - writel((div << 8) | S3C2412_IISPSR_PSREN, - i2s->regs + S3C2412_IISPSR); + /* The S3C2443 has different bit fields (Luis Galdos) */ + div = (i2s->cpu_is_s3c2443) ? (div - 1) : (div << 8); + writel(div | S3C2412_IISPSR_PSREN, i2s->regs + S3C2412_IISPSR); } else { writel(0x0, i2s->regs + S3C2412_IISPSR); } @@ -646,6 +647,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev, { struct device *dev = &pdev->dev; unsigned int iismod; + unsigned long regval; i2s->dev = dev; @@ -685,6 +687,14 @@ int s3c_i2sv2_probe(struct platform_device *pdev, clk_enable(i2s->iis_pclk); + /* Stop the DMA-channel if it's already running! */ + regval = readl(i2s->regs + S3C2412_IISCON); + if (regval & S3C2412_IISCON_IIS_ACTIVE) { + printk(KERN_ERR "DMA channel seems to be already active.\n"); + regval &= ~S3C2412_IISCON_IIS_ACTIVE; + writel(regval, i2s->regs + S3C2412_IISCON); + } + /* Mark ourselves as in TXRX mode so we can run through our cleanup * process without warnings. */ iismod = readl(i2s->regs + S3C2412_IISMOD); @@ -697,6 +707,27 @@ int s3c_i2sv2_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); +void s3c_i2sv2_remove(struct platform_device *pdev, + struct snd_soc_dai *dai, + struct s3c_i2sv2_info *i2s, + unsigned long base) +{ + struct resource *res; + + clk_disable(i2s->iis_pclk); + clk_put(i2s->iis_pclk); + i2s->iis_pclk = NULL; + + iounmap(i2s->regs); + i2s->regs = NULL; + + if (!base) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + } +} +EXPORT_SYMBOL_GPL(s3c_i2sv2_remove); + #ifdef CONFIG_PM static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) { diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h index 766f43a13d8b..5dd9c6538b28 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.h +++ b/sound/soc/s3c24xx/s3c-i2s-v2.h @@ -66,6 +66,9 @@ struct s3c_i2sv2_info { u32 suspend_iismod; u32 suspend_iiscon; u32 suspend_iispsr; + + u32 cpu_is_s3c2443; + int counts; }; extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai); @@ -92,6 +95,18 @@ extern int s3c_i2sv2_probe(struct platform_device *pdev, unsigned long base); /** + * s3c_i2sv2_remove - remove for i2s device helper + * @pdev: The platform device supplied to the original probe. + * @dai: The ASoC DAI structure supplied to the original probe. + * @i2s: Our local i2s structure to fill in. + * @base: The base address for the registers. + */ +extern void s3c_i2sv2_remove(struct platform_device *pdev, + struct snd_soc_dai *dai, + struct s3c_i2sv2_info *i2s, + unsigned long base); + +/** * s3c_i2sv2_register_dai - register dai with soc core * @dai: The snd_soc_dai structure to register * diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 709adef9d043..3dfc9e77bfee 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -77,9 +77,15 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, pr_debug("Entered %s\n", __func__); + /* Check if we have already probed the interface */ + + s3c2412_i2s.counts++; + if (s3c2412_i2s.counts > 1) + return 0; + ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS); if (ret) - return ret; + goto exit_err; s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in; s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out; @@ -87,8 +93,8 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); if (s3c2412_i2s.iis_cclk == NULL) { pr_err("failed to get i2sclk clock\n"); - iounmap(s3c2412_i2s.regs); - return -ENODEV; + ret = -ENODEV; + goto exit_iounmap; } /* Set MPLL as the source for IIS CLK */ @@ -105,7 +111,44 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); + printk("I2S %s successfully probed\n", + s3c2412_i2s.cpu_is_s3c2443 ? "S3C2443" : "S3C2412"); + return 0; + +exit_iounmap: + iounmap(s3c2412_i2s.regs); + +exit_err: + s3c2412_i2s.counts -= 1; + return ret; +} + +static int s3c2443_i2s_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + s3c2412_i2s.cpu_is_s3c2443 = 1; + return s3c2412_i2s_probe(pdev, dai); +} + +static void s3c2443_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) +{ + printk("Removing the I2C device: id %i\n", pdev->id); + + /* + * If there is still one device using the interface, skip the complete + * remove of the driver + */ + s3c2412_i2s.counts -= 1; + if (s3c2412_i2s.counts) + return; + + clk_disable(s3c2412_i2s.iis_cclk); + + /* @FIXME: We can't put the clock at this place! (Luis Galdos) */ + /* clk_put(s3c2412_i2s.iis_cclk); */ + + s3c_i2sv2_remove(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS); } static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, @@ -172,14 +215,51 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); +#define S3C2443_I2S_RATES \ + (SNDRV_PCM_RATE_44100) + +static struct snd_soc_dai_ops s3c2443_i2s_dai_ops = { + .hw_params = s3c2412_i2s_hw_params, +}; + +struct snd_soc_dai s3c2443_i2s_dai = { + .name = "s3c2443-i2s", + .id = 0, + .probe = s3c2443_i2s_probe, + .remove = s3c2443_i2s_remove, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C2412_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C2412_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &s3c2443_i2s_dai_ops, +}; +EXPORT_SYMBOL_GPL(s3c2443_i2s_dai); + static int __init s3c2412_i2s_init(void) { - return s3c_i2sv2_register_dai(&s3c2412_i2s_dai); + unsigned int ret; + + ret = s3c_i2sv2_register_dai(&s3c2412_i2s_dai); + if ( ret != 0 ) + s3c_i2sv2_register_dai(&s3c2443_i2s_dai); + else + ret = s3c_i2sv2_register_dai(&s3c2443_i2s_dai); + + return ret; } module_init(s3c2412_i2s_init); static void __exit s3c2412_i2s_exit(void) { + snd_soc_unregister_dai(&s3c2443_i2s_dai); snd_soc_unregister_dai(&s3c2412_i2s_dai); } module_exit(s3c2412_i2s_exit); |