1/* sound/soc/s3c24xx/jive_wm8750.c 2 * 3 * Copyright 2007,2008 Simtec Electronics 4 * 5 * Based on sound/soc/pxa/spitz.c 6 * Copyright 2005 Wolfson Microelectronics PLC. 7 * Copyright 2005 Openedhand Ltd. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12*/ 13 14#include <linux/module.h> 15#include <linux/moduleparam.h> 16#include <linux/timer.h> 17#include <linux/interrupt.h> 18#include <linux/platform_device.h> 19#include <linux/clk.h> 20 21#include <sound/core.h> 22#include <sound/pcm.h> 23#include <sound/soc.h> 24#include <sound/soc-dapm.h> 25 26#include <asm/mach-types.h> 27 28#include "s3c-dma.h" 29#include "s3c2412-i2s.h" 30 31#include "../codecs/wm8750.h" 32 33static const struct snd_soc_dapm_route audio_map[] = { 34 { "Headphone Jack", NULL, "LOUT1" }, 35 { "Headphone Jack", NULL, "ROUT1" }, 36 { "Internal Speaker", NULL, "LOUT2" }, 37 { "Internal Speaker", NULL, "ROUT2" }, 38 { "LINPUT1", NULL, "Line Input" }, 39 { "RINPUT1", NULL, "Line Input" }, 40}; 41 42static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { 43 SND_SOC_DAPM_HP("Headphone Jack", NULL), 44 SND_SOC_DAPM_SPK("Internal Speaker", NULL), 45 SND_SOC_DAPM_LINE("Line In", NULL), 46}; 47 48static int jive_hw_params(struct snd_pcm_substream *substream, 49 struct snd_pcm_hw_params *params) 50{ 51 struct snd_soc_pcm_runtime *rtd = substream->private_data; 52 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 53 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 54 struct s3c_i2sv2_rate_calc div; 55 unsigned int clk = 0; 56 int ret = 0; 57 58 switch (params_rate(params)) { 59 case 8000: 60 case 16000: 61 case 48000: 62 case 96000: 63 clk = 12288000; 64 break; 65 case 11025: 66 case 22050: 67 case 44100: 68 clk = 11289600; 69 break; 70 } 71 72 s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), 73 s3c_i2sv2_get_clock(cpu_dai)); 74 75 /* set codec DAI configuration */ 76 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 77 SND_SOC_DAIFMT_NB_NF | 78 SND_SOC_DAIFMT_CBS_CFS); 79 if (ret < 0) 80 return ret; 81 82 /* set cpu DAI configuration */ 83 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 84 SND_SOC_DAIFMT_NB_NF | 85 SND_SOC_DAIFMT_CBS_CFS); 86 if (ret < 0) 87 return ret; 88 89 /* set the codec system clock for DAC and ADC */ 90 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, 91 SND_SOC_CLOCK_IN); 92 if (ret < 0) 93 return ret; 94 95 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); 96 if (ret < 0) 97 return ret; 98 99 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, 100 div.clk_div - 1); 101 if (ret < 0) 102 return ret; 103 104 return 0; 105} 106 107static struct snd_soc_ops jive_ops = { 108 .hw_params = jive_hw_params, 109}; 110 111static int jive_wm8750_init(struct snd_soc_codec *codec) 112{ 113 int err; 114 115 /* These endpoints are not being used. */ 116 snd_soc_dapm_nc_pin(codec, "LINPUT2"); 117 snd_soc_dapm_nc_pin(codec, "RINPUT2"); 118 snd_soc_dapm_nc_pin(codec, "LINPUT3"); 119 snd_soc_dapm_nc_pin(codec, "RINPUT3"); 120 snd_soc_dapm_nc_pin(codec, "OUT3"); 121 snd_soc_dapm_nc_pin(codec, "MONO"); 122 123 /* Add jive specific widgets */ 124 err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, 125 ARRAY_SIZE(wm8750_dapm_widgets)); 126 if (err) { 127 printk(KERN_ERR "%s: failed to add widgets (%d)\n", 128 __func__, err); 129 return err; 130 } 131 132 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 133 snd_soc_dapm_sync(codec); 134 135 return 0; 136} 137 138static struct snd_soc_dai_link jive_dai = { 139 .name = "wm8750", 140 .stream_name = "WM8750", 141 .cpu_dai = &s3c2412_i2s_dai, 142 .codec_dai = &wm8750_dai, 143 .init = jive_wm8750_init, 144 .ops = &jive_ops, 145}; 146 147/* jive audio machine driver */ 148static struct snd_soc_card snd_soc_machine_jive = { 149 .name = "Jive", 150 .platform = &s3c24xx_soc_platform, 151 .dai_link = &jive_dai, 152 .num_links = 1, 153}; 154 155/* jive audio subsystem */ 156static struct snd_soc_device jive_snd_devdata = { 157 .card = &snd_soc_machine_jive, 158 .codec_dev = &soc_codec_dev_wm8750, 159}; 160 161static struct platform_device *jive_snd_device; 162 163static int __init jive_init(void) 164{ 165 int ret; 166 167 if (!machine_is_jive()) 168 return 0; 169 170 printk("JIVE WM8750 Audio support\n"); 171 172 jive_snd_device = platform_device_alloc("soc-audio", -1); 173 if (!jive_snd_device) 174 return -ENOMEM; 175 176 platform_set_drvdata(jive_snd_device, &jive_snd_devdata); 177 jive_snd_devdata.dev = &jive_snd_device->dev; 178 ret = platform_device_add(jive_snd_device); 179 180 if (ret) 181 platform_device_put(jive_snd_device); 182 183 return ret; 184} 185 186static void __exit jive_exit(void) 187{ 188 platform_device_unregister(jive_snd_device); 189} 190 191module_init(jive_init); 192module_exit(jive_exit); 193 194MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 195MODULE_DESCRIPTION("ALSA SoC Jive Audio support"); 196MODULE_LICENSE("GPL"); 197