From a6171bfad4671fe525ae2c8cddd4f6a7f739e346 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Sun, 4 Mar 2007 17:00:59 +0000 Subject: [PATCH] Add initial ASoC SMDK2440 support. Signed-off-by: Ben Dooks Signed-off-by: Graeme Gregory Signed-off-by: Liam Girdwood --- sound/soc/s3c24xx/Kconfig | 7 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/smdk2440.c | 320 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+), 0 deletions(-) create mode 100644 sound/soc/s3c24xx/smdk2440.c diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index c414886..99fe902 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -21,5 +21,12 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 Say Y if you want to add support for SoC audio on smdk2440 with the WM8753. +config SND_S3C24XX_SOC_SMDK2440 + tristate "SoC I2S Audio support for SMDK2440" + depends on SND_S3C24XX_SOC && MACH_SMDK + select SND_S3C24XX_SOC_I2S + help + Say Y if you want to add support for SoC audio on SMDK2440 + endmenu diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 7b5c6fe..b991052 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -7,5 +7,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o # S3C24XX Machine Support snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o +snd-soc-smdk2440-objs := smdk2440.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o +obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2440) += snd-soc-smdk2440.o diff --git a/sound/soc/s3c24xx/smdk2440.c b/sound/soc/s3c24xx/smdk2440.c new file mode 100644 index 0000000..9885a5e --- /dev/null +++ b/sound/soc/s3c24xx/smdk2440.c @@ -0,0 +1,320 @@ +/* + * smdk2440.c -- ALSA Soc Audio Layer + * + * (c) 2006 Wolfson Microelectronics PLC. + * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * (c) 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. + * + * This module is a modified version of the s3c24xx I2S driver supplied by + * Ben Dooks of Simtec and rejigged to the ASoC style at Wolfson Microelectronics + * + * Revision history + * 11th Dec 2006 Merged with Simtec driver + * 10th Nov 2006 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/uda1380.h" +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" + +#define SMDK2440_DEBUG 0 +#if SMDK2440_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) +#endif + +/* audio clock in Hz */ +#define SMDK_CLOCK_SOURCE S3C24XX_CLKSRC_MPLL +#define SMDK_CRYSTAL_CLOCK 16934400 + +static int smdk2440_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + DBG("Entered smdk2440_startup\n"); + + return 0; +} + +static int smdk2440_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + DBG("Entered smdk2440_shutdown\n"); + + return 0; +} + +static int smdk2440_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_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; + unsigned long iis_clkrate; + int div, div256, div384, diff256, diff384, bclk, mclk; + int ret; + unsigned int rate=params_rate(params); + + DBG("Entered %s\n",__FUNCTION__); + + iis_clkrate = s3c24xx_i2s_get_clockrate(); + + /* Using PCLK doesnt seem to suit audio particularly well on these cpu's + */ + + div256 = iis_clkrate / (rate * 256); + div384 = iis_clkrate / (rate * 384); + + if (((iis_clkrate / div256) - (rate * 256)) < + ((rate * 256) - (iis_clkrate / (div256 + 1)))) { + diff256 = (iis_clkrate / div256) - (rate * 256); + } else { + div256++; + diff256 = (iis_clkrate / div256) - (rate * 256); + } + + if (((iis_clkrate / div384) - (rate * 384)) < + ((rate * 384) - (iis_clkrate / (div384 + 1)))) { + diff384 = (iis_clkrate / div384) - (rate * 384); + } else { + div384++; + diff384 = (iis_clkrate / div384) - (rate * 384); + } + + DBG("diff256 %d, diff384 %d\n", diff256, diff384); + + if (diff256<=diff384) { + DBG("Selected 256FS\n"); + div = div256 - 1; + bclk = S3C2410_IISMOD_256FS; + } else { + DBG("Selected 384FS\n"); + div = div384 - 1; + bclk = S3C2410_IISMOD_384FS; + } + + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the audio system clock for DAC and ADC */ + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, + rate, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + /* set MCLK division for sample rate */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, S3C2410_IISMOD_32FS ); + if (ret < 0) + return ret; + + /* set BCLK division for sample rate */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, bclk); + if (ret < 0) + return ret; + + /* set prescaler division for sample rate */ + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(div,div)); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops smdk2440_ops = { + .startup = smdk2440_startup, + .shutdown = smdk2440_shutdown, + .hw_params = smdk2440_hw_params, +}; + +/* smdk2440 machine dapm widgets */ +static const struct snd_soc_dapm_widget smdk2440_dapm_widgets[] = { +SND_SOC_DAPM_HP("Headphone Jack", NULL), +SND_SOC_DAPM_MIC("Mic Jack", NULL), +SND_SOC_DAPM_LINE("Line Jack", NULL), +}; + +/* smdk2440 machine audio map (connections to the codec pins) */ +static const char* audio_map[][3] = { + /* headphone connected to HPOUT */ + {"Headphone Jack", NULL, "HPOUT"}, + + /* mic is connected to MICIN (via right channel of headphone jack) */ + {"MICIN", NULL, "Mic Jack"}, + {"MICIN", NULL, "Line Jack"}, + + {NULL, NULL, NULL}, +}; + +/* + * Logic for a UDA1341 as attached to SMDK2440 + */ +static int smdk2440_uda1341_init(struct snd_soc_codec *codec) +{ + int i, err; + + DBG("Staring smdk2440 init\n"); + + /* Add smdk2440 specific widgets */ + for(i = 0; i < ARRAY_SIZE(smdk2440_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &smdk2440_dapm_widgets[i]); + } + + /* Set up smdk2440 specific audio path audio_mapnects */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); + + DBG("Ending smdk2440 init\n"); + + return 0; +} + +/* s3c24xx digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link s3c24xx_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &s3c24xx_i2s_dai, + .codec_dai = &uda1380_dai, + .init = smdk2440_uda1341_init, + .ops = &smdk2440_ops, +}; + +/* smdk2440 audio machine driver */ +static struct snd_soc_machine snd_soc_machine_smdk2440 = { + .name = "SMDK2440", + .dai_link = &s3c24xx_dai, + .num_links = 1, +}; + +static struct uda1380_setup_data smdk2440_uda1380_setup = { + .i2c_address = 0x00, +}; + +/* s3c24xx audio subsystem */ +static struct snd_soc_device s3c24xx_snd_devdata = { + .machine = &snd_soc_machine_smdk2440, + .platform = &s3c24xx_soc_platform, + .codec_dev = &soc_codec_dev_uda1380, + .codec_data = &smdk2440_uda1380_setup, +}; + +static struct platform_device *s3c24xx_snd_device; + +struct smdk2440_spi_device { + struct device *dev; +}; + +static struct smdk2440_spi_device smdk2440_spi_devdata = { +}; + +struct s3c2410_spigpio_info smdk2440_spi_devinfo = { + .pin_clk = S3C2410_GPF4, + .pin_mosi = S3C2410_GPF5, + .pin_miso = S3C2410_GPF6, + //.board_size, + //.board_info, + .chip_select=NULL, +}; + +static struct platform_device *smdk2440_spi_device; + +static int __init smdk2440_init(void) +{ + int ret; + + if (!machine_is_smdk2440() && !machine_is_s3c2440()) { + DBG("%d\n",machine_arch_type); + DBG("Not a SMDK2440\n"); + return -ENODEV; + } + + s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); + if (!s3c24xx_snd_device) { + DBG("platform_dev_alloc failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(s3c24xx_snd_device, &s3c24xx_snd_devdata); + s3c24xx_snd_devdata.dev = &s3c24xx_snd_device->dev; + ret = platform_device_add(s3c24xx_snd_device); + + if (ret) + platform_device_put(s3c24xx_snd_device); + + // Create a bitbanged SPI device + + smdk2440_spi_device = platform_device_alloc("s3c24xx-spi-gpio",-1); + if (!smdk2440_spi_device) { + DBG("smdk2440_spi_device : platform_dev_alloc failed\n"); + return -ENOMEM; + } + DBG("Return Code %d\n",ret); + + platform_set_drvdata(smdk2440_spi_device, &smdk2440_spi_devdata); + smdk2440_spi_devdata.dev = &smdk2440_spi_device->dev; + smdk2440_spi_devdata.dev->platform_data = &smdk2440_spi_devinfo; + ret = platform_device_add(smdk2440_spi_device); + + if (ret) + platform_device_put(smdk2440_spi_device); + + return ret; +} + +static void __exit smdk2440_exit(void) +{ + platform_device_unregister(s3c24xx_snd_device); +} + +module_init(smdk2440_init); +module_exit(smdk2440_exit); + +/* Module information */ +MODULE_AUTHOR("Ben Dooks, "); +MODULE_DESCRIPTION("ALSA SoC SMDK2440"); +MODULE_LICENSE("GPL"); -- 1.5.0.3