[alsa-devel] JIVE: Add ASoC audio support
Add support for the Jive's WM8750 codec attached to the S3C2412 IIS controller.
Signed-off-by: Ben Dooks ben-linux@fluff.org
Index: linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/Kconfig =================================================================== --- linux-2.6.26-rc5-quilt2.orig/sound/soc/s3c24xx/Kconfig 2008-06-10 12:31:40.000000000 +0100 +++ linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/Kconfig 2008-06-12 11:07:04.000000000 +0100 @@ -28,6 +28,15 @@ 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_JIVE_WM8750 + tristate "SoC I2S Audio support for Jive" + depends on SND_S3C24XX_SOC && MACH_JIVE + select SND_SOC_WM8750 + select SND_SOC_WM8750_SPI + select SND_S3C2412_SOC_I2S + help + Sat Y if you want to add support for SoC audio on the Jive. + config SND_S3C24XX_SOC_SMDK2443_WM9710 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" depends on SND_S3C24XX_SOC && MACH_SMDK2443 Index: linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/Makefile =================================================================== --- linux-2.6.26-rc5-quilt2.orig/sound/soc/s3c24xx/Makefile 2008-06-10 12:31:40.000000000 +0100 +++ linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/Makefile 2008-06-12 11:07:04.000000000 +0100 @@ -10,10 +10,12 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += sn obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
# S3C24XX Machine Support +snd-soc-jive-wm8750-objs := jive_wm8750.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.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 obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o Index: linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/jive_wm8750.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/jive_wm8750.c 2008-06-12 11:07:04.000000000 +0100 @@ -0,0 +1,266 @@ +/* sound/soc/s3c24xx/jive_wm8705.c + * + * Copyright 2007 Simtec Electronics + * + * Based on sound/soc/pxa/spitz.c + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/mach-types.h> + +#include "s3c24xx-pcm.h" +#include "s3c2412-i2s.h" + +#include "../codecs/wm8750.h" + +static const char *audio_map[][2] = { + [0] = { "Headphone Jack", "LOUT1" }, + [1] = { "Headphone Jack", "ROUT1" }, + [2] = { "Internal Speaker", "LOUT2" }, + [3] = { "Internal Speaker", "ROUT2" }, + [4] = { "LINPUT1", "Line Input" }, + [5] = { "RINPUT1", "Line Input" }, + [6] = { NULL, NULL }, +}; + +static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Internal Speaker", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static int jive_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); + snd_soc_dapm_set_endpoint(codec, "Internal Speaker", 1); + snd_soc_dapm_set_endpoint(codec, "Line In", 1); + + snd_soc_dapm_sync_endpoints(codec); + + return 0; +} + +static inline int codec_set_dai_fmt(struct snd_soc_codec_dai *dai, + unsigned int format) +{ + return dai->dai_ops.set_fmt(dai, format); +} + +static inline int codec_set_dai_sysclk(struct snd_soc_codec_dai *dai, + unsigned int clk, + unsigned int arg, + unsigned int arg2) +{ + return dai->dai_ops.set_sysclk(dai, clk, arg, arg2); +} + +static inline int cpu_set_dai_fmt(struct snd_soc_cpu_dai *dai, + unsigned int format) +{ + return dai->dai_ops.set_fmt(dai, format); +} + +static inline int cpu_set_dai_sysclk(struct snd_soc_cpu_dai *dai, + unsigned int clk, + unsigned int arg, + unsigned int arg2) +{ + return dai->dai_ops.set_sysclk(dai, clk, arg, arg2); +} + +static inline int cpu_set_dai_clkdiv(struct snd_soc_cpu_dai *dai, + unsigned int clk, + unsigned int arg) +{ + return dai->dai_ops.set_clkdiv(dai, clk, arg); +} + + + +static int jive_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_codec_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + struct s3c2412_rate_calc div; + unsigned int clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + s3c2412_iis_calc_rate(&div, NULL, params_rate(params), + s3c2412_get_iisclk()); + + /* set codec DAI configuration */ + ret = codec_set_dai_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_set_dai_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_set_dai_sysclk(codec_dai, WM8750_SYSCLK, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = cpu_set_dai_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); + if (ret < 0) + return ret; + + ret = cpu_set_dai_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, div.clk_div - 1); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops jive_ops = { + .startup = jive_startup, + .hw_params = jive_hw_params, +}; + +static const struct snd_kcontrol_new wm8750_jive_controls[] = { + +}; + +static int jive_wm8750_init(struct snd_soc_codec *codec) +{ + int i, err; + + /* These endpoints are not being used. */ + snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); + snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); + snd_soc_dapm_set_endpoint(codec, "OUT3", 0); + snd_soc_dapm_set_endpoint(codec, "MONO", 0); + + /* Add jive specific controls */ + for (i = 0; i < ARRAY_SIZE(wm8750_jive_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8750_jive_controls[i], codec, NULL)); + if (err < 0) + return err; + } + + /* Add jive specific widgets */ + for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); + } + + /* Set up jive specific audio path audio_map */ + for (i = 0; audio_map[i][0] != NULL; i++) { + printk(KERN_INFO "mapping %s => %s\n", audio_map[i][0], audio_map[i][1]); + snd_soc_dapm_connect_input(codec, audio_map[i][0], NULL, + audio_map[i][1]); + } + + snd_soc_dapm_sync_endpoints(codec); + return 0; +} + +static struct snd_soc_dai_link jive_dai = { + .name = "wm8750", + .stream_name = "WM8750", + .cpu_dai = &s3c2412_i2s_dai, + .codec_dai = &wm8750_dai, + .init = jive_wm8750_init, + .ops = &jive_ops, +}; + +/* jive audio machine driver */ +static struct snd_soc_machine snd_soc_machine_jive = { + .name = "Jive", + .dai_link = &jive_dai, + .num_links = 1, +}; + +/* jive audio private data */ +static struct wm8750_setup_data jive_wm8750_setup = { +}; + +/* jive audio subsystem */ +static struct snd_soc_device jive_snd_devdata = { + .machine = &snd_soc_machine_jive, + .platform = &s3c24xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8750_spi, + .codec_data = &jive_wm8750_setup, +}; + +static struct platform_device *jive_snd_device; + +static int __init jive_init(void) +{ + int ret; + + printk("JIVE WM8750 Audio support\n"); + + if (!machine_is_jive()) + return 0; + + jive_snd_device = platform_device_alloc("soc-audio", -1); + if (!jive_snd_device) + return -ENOMEM; + + platform_set_drvdata(jive_snd_device, &jive_snd_devdata); + jive_snd_devdata.dev = &jive_snd_device->dev; + ret = platform_device_add(jive_snd_device); + + if (ret) + platform_device_put(jive_snd_device); + + return ret; +} + +static void __exit jive_exit(void) +{ + platform_device_unregister(jive_snd_device); +} + +module_init(jive_init); +module_exit(jive_exit); + +MODULE_AUTHOR("Ben Dooks ben@simtec.co.uk"); +MODULE_DESCRIPTION("ALSA SoC Jive"); +MODULE_LICENSE("GPL");
On Mon, Jun 23, 2008 at 12:54:23PM +0100, Ben Dooks wrote:
This looks mostly good - a few nits:
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.26-rc5-quilt2/sound/soc/s3c24xx/jive_wm8750.c 2008-06-12 11:07:04.000000000 +0100 @@ -0,0 +1,266 @@ +/* sound/soc/s3c24xx/jive_wm8705.c
Typo :)
+static inline int codec_set_dai_fmt(struct snd_soc_codec_dai *dai,
unsigned int format)
+{
- return dai->dai_ops.set_fmt(dai, format);
+}
These functions are a good idea - the equivalents are already in ASoC v2 but haven't been backported into mainline yet - but they should be in the ASoC core rather than in a machine driver. Please either remove them or integrate them into the core (obviously the latter would be nice but the former is less work).
+static const struct snd_kcontrol_new wm8750_jive_controls[] = {
+};
This (and the code to process it) could go since it's empty.
- /* Add jive specific widgets */
- for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) {
snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
- }
These should all be updated to use the new bulk registration APIs (these were added to the ASoC core this year, after the driver appears to have been written). Here the equivalent is snd_soc_dapm_new_controls().
- /* Set up jive specific audio path audio_map */
- for (i = 0; audio_map[i][0] != NULL; i++) {
printk(KERN_INFO "mapping %s => %s\n", audio_map[i][0], audio_map[i][1]);
snd_soc_dapm_connect_input(codec, audio_map[i][0], NULL,
audio_map[i][1]);
- }
Here it's snd_soc_dapm_add_routes().
+static int __init jive_init(void) +{
- int ret;
- printk("JIVE WM8750 Audio support\n");
This should have a KERN_INFO?
participants (2)
-
Ben Dooks
-
Mark Brown