| 
									
										
										
										
											2009-03-04 00:49:27 +00:00
										 |  |  | /* sound/soc/s3c24xx/jive_wm8750.c
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2007,2008 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 version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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/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 struct snd_soc_dapm_route audio_map[] = { | 
					
						
							|  |  |  | 	{ "Headphone Jack", NULL, "LOUT1" }, | 
					
						
							|  |  |  | 	{ "Headphone Jack", NULL, "ROUT1" }, | 
					
						
							|  |  |  | 	{ "Internal Speaker", NULL, "LOUT2" }, | 
					
						
							|  |  |  | 	{ "Internal Speaker", NULL, "ROUT2" }, | 
					
						
							|  |  |  | 	{ "LINPUT1", NULL, "Line Input" }, | 
					
						
							|  |  |  | 	{ "RINPUT1", NULL, "Line Input" }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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_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 *codec_dai = rtd->dai->codec_dai; | 
					
						
							|  |  |  | 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 
					
						
							| 
									
										
										
										
											2009-03-04 00:49:30 +00:00
										 |  |  | 	struct s3c_i2sv2_rate_calc div; | 
					
						
							| 
									
										
										
										
											2009-03-04 00:49:27 +00:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-04 00:49:30 +00:00
										 |  |  | 	s3c_i2sv2_calc_rate(&div, NULL, params_rate(params), | 
					
						
							|  |  |  | 			    s3c2412_get_iisclk()); | 
					
						
							| 
									
										
										
										
											2009-03-04 00:49:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* set codec DAI configuration */ | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set cpu DAI configuration */ | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set the codec system clock for DAC and ADC */ | 
					
						
							|  |  |  | 	ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 
					
						
							|  |  |  | 				     SND_SOC_CLOCK_IN); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, | 
					
						
							|  |  |  | 				     div.clk_div - 1); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct snd_soc_ops jive_ops = { | 
					
						
							|  |  |  | 	.hw_params	= jive_hw_params, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int jive_wm8750_init(struct snd_soc_codec *codec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* These endpoints are not being used. */ | 
					
						
							| 
									
										
										
										
											2009-03-04 20:17:48 +00:00
										 |  |  | 	snd_soc_dapm_nc_pin(codec, "LINPUT2"); | 
					
						
							|  |  |  | 	snd_soc_dapm_nc_pin(codec, "RINPUT2"); | 
					
						
							|  |  |  | 	snd_soc_dapm_nc_pin(codec, "LINPUT3"); | 
					
						
							|  |  |  | 	snd_soc_dapm_nc_pin(codec, "RINPUT3"); | 
					
						
							|  |  |  | 	snd_soc_dapm_nc_pin(codec, "OUT3"); | 
					
						
							|  |  |  | 	snd_soc_dapm_nc_pin(codec, "MONO"); | 
					
						
							| 
									
										
										
										
											2009-03-04 00:49:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Add jive specific widgets */ | 
					
						
							|  |  |  | 	err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | 
					
						
							|  |  |  | 					ARRAY_SIZE(wm8750_dapm_widgets)); | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							|  |  |  | 		printk(KERN_ERR "%s: failed to add widgets (%d)\n", | 
					
						
							|  |  |  | 		       __func__, err); | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 
					
						
							|  |  |  | 	snd_soc_dapm_sync(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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!machine_is_jive()) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk("JIVE WM8750 Audio support\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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 Audio support"); | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); |