0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/timer.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/gpio/consumer.h>
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/soc.h>
0021
0022 #include <asm/mach-types.h>
0023 #include "../codecs/wm8750.h"
0024 #include "pxa2xx-i2s.h"
0025
0026 #define SPITZ_HP 0
0027 #define SPITZ_MIC 1
0028 #define SPITZ_LINE 2
0029 #define SPITZ_HEADSET 3
0030 #define SPITZ_HP_OFF 4
0031 #define SPITZ_SPK_ON 0
0032 #define SPITZ_SPK_OFF 1
0033
0034
0035 #define SPITZ_AUDIO_CLOCK 12288000
0036
0037 static int spitz_jack_func;
0038 static int spitz_spk_func;
0039 static struct gpio_desc *gpiod_mic, *gpiod_mute_l, *gpiod_mute_r;
0040
0041 static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
0042 {
0043 snd_soc_dapm_mutex_lock(dapm);
0044
0045 if (spitz_spk_func == SPITZ_SPK_ON)
0046 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
0047 else
0048 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
0049
0050
0051 switch (spitz_jack_func) {
0052 case SPITZ_HP:
0053
0054 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
0055 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
0056 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
0057 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
0058 gpiod_set_value(gpiod_mute_l, 1);
0059 gpiod_set_value(gpiod_mute_r, 1);
0060 break;
0061 case SPITZ_MIC:
0062
0063 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
0064 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
0065 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
0066 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
0067 gpiod_set_value(gpiod_mute_l, 0);
0068 gpiod_set_value(gpiod_mute_r, 0);
0069 break;
0070 case SPITZ_LINE:
0071
0072 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
0073 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
0074 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
0075 snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
0076 gpiod_set_value(gpiod_mute_l, 0);
0077 gpiod_set_value(gpiod_mute_r, 0);
0078 break;
0079 case SPITZ_HEADSET:
0080
0081 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
0082 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
0083 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
0084 snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
0085 gpiod_set_value(gpiod_mute_l, 0);
0086 gpiod_set_value(gpiod_mute_r, 1);
0087 break;
0088 case SPITZ_HP_OFF:
0089
0090
0091 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
0092 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
0093 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
0094 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
0095 gpiod_set_value(gpiod_mute_l, 0);
0096 gpiod_set_value(gpiod_mute_r, 0);
0097 break;
0098 }
0099
0100 snd_soc_dapm_sync_unlocked(dapm);
0101
0102 snd_soc_dapm_mutex_unlock(dapm);
0103 }
0104
0105 static int spitz_startup(struct snd_pcm_substream *substream)
0106 {
0107 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0108
0109
0110 spitz_ext_control(&rtd->card->dapm);
0111
0112 return 0;
0113 }
0114
0115 static int spitz_hw_params(struct snd_pcm_substream *substream,
0116 struct snd_pcm_hw_params *params)
0117 {
0118 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0119 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0120 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0121 unsigned int clk = 0;
0122 int ret = 0;
0123
0124 switch (params_rate(params)) {
0125 case 8000:
0126 case 16000:
0127 case 48000:
0128 case 96000:
0129 clk = 12288000;
0130 break;
0131 case 11025:
0132 case 22050:
0133 case 44100:
0134 clk = 11289600;
0135 break;
0136 }
0137
0138
0139 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
0140 SND_SOC_CLOCK_IN);
0141 if (ret < 0)
0142 return ret;
0143
0144
0145 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
0146 SND_SOC_CLOCK_IN);
0147 if (ret < 0)
0148 return ret;
0149
0150 return 0;
0151 }
0152
0153 static const struct snd_soc_ops spitz_ops = {
0154 .startup = spitz_startup,
0155 .hw_params = spitz_hw_params,
0156 };
0157
0158 static int spitz_get_jack(struct snd_kcontrol *kcontrol,
0159 struct snd_ctl_elem_value *ucontrol)
0160 {
0161 ucontrol->value.enumerated.item[0] = spitz_jack_func;
0162 return 0;
0163 }
0164
0165 static int spitz_set_jack(struct snd_kcontrol *kcontrol,
0166 struct snd_ctl_elem_value *ucontrol)
0167 {
0168 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0169
0170 if (spitz_jack_func == ucontrol->value.enumerated.item[0])
0171 return 0;
0172
0173 spitz_jack_func = ucontrol->value.enumerated.item[0];
0174 spitz_ext_control(&card->dapm);
0175 return 1;
0176 }
0177
0178 static int spitz_get_spk(struct snd_kcontrol *kcontrol,
0179 struct snd_ctl_elem_value *ucontrol)
0180 {
0181 ucontrol->value.enumerated.item[0] = spitz_spk_func;
0182 return 0;
0183 }
0184
0185 static int spitz_set_spk(struct snd_kcontrol *kcontrol,
0186 struct snd_ctl_elem_value *ucontrol)
0187 {
0188 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0189
0190 if (spitz_spk_func == ucontrol->value.enumerated.item[0])
0191 return 0;
0192
0193 spitz_spk_func = ucontrol->value.enumerated.item[0];
0194 spitz_ext_control(&card->dapm);
0195 return 1;
0196 }
0197
0198 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
0199 struct snd_kcontrol *k, int event)
0200 {
0201 gpiod_set_value_cansleep(gpiod_mic, SND_SOC_DAPM_EVENT_ON(event));
0202 return 0;
0203 }
0204
0205
0206 static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
0207 SND_SOC_DAPM_HP("Headphone Jack", NULL),
0208 SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
0209 SND_SOC_DAPM_SPK("Ext Spk", NULL),
0210 SND_SOC_DAPM_LINE("Line Jack", NULL),
0211
0212
0213 SND_SOC_DAPM_HP("Headset Jack", NULL),
0214 };
0215
0216
0217 static const struct snd_soc_dapm_route spitz_audio_map[] = {
0218
0219
0220 {"Headphone Jack", NULL, "LOUT1"},
0221 {"Headphone Jack", NULL, "ROUT1"},
0222
0223
0224 {"Headset Jack", NULL, "ROUT1"},
0225
0226
0227 {"Ext Spk", NULL, "ROUT2"},
0228 {"Ext Spk", NULL, "LOUT2"},
0229
0230
0231 {"LINPUT1", NULL, "Mic Bias"},
0232 {"Mic Bias", NULL, "Mic Jack"},
0233
0234
0235 {"LINPUT1", NULL, "Line Jack"},
0236 };
0237
0238 static const char * const jack_function[] = {"Headphone", "Mic", "Line",
0239 "Headset", "Off"};
0240 static const char * const spk_function[] = {"On", "Off"};
0241 static const struct soc_enum spitz_enum[] = {
0242 SOC_ENUM_SINGLE_EXT(5, jack_function),
0243 SOC_ENUM_SINGLE_EXT(2, spk_function),
0244 };
0245
0246 static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
0247 SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
0248 spitz_set_jack),
0249 SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
0250 spitz_set_spk),
0251 };
0252
0253
0254 SND_SOC_DAILINK_DEFS(wm8750,
0255 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
0256 DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
0257 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
0258
0259 static struct snd_soc_dai_link spitz_dai = {
0260 .name = "wm8750",
0261 .stream_name = "WM8750",
0262 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0263 SND_SOC_DAIFMT_CBS_CFS,
0264 .ops = &spitz_ops,
0265 SND_SOC_DAILINK_REG(wm8750),
0266 };
0267
0268
0269 static struct snd_soc_card snd_soc_spitz = {
0270 .name = "Spitz",
0271 .owner = THIS_MODULE,
0272 .dai_link = &spitz_dai,
0273 .num_links = 1,
0274
0275 .controls = wm8750_spitz_controls,
0276 .num_controls = ARRAY_SIZE(wm8750_spitz_controls),
0277 .dapm_widgets = wm8750_dapm_widgets,
0278 .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
0279 .dapm_routes = spitz_audio_map,
0280 .num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
0281 .fully_routed = true,
0282 };
0283
0284 static int spitz_probe(struct platform_device *pdev)
0285 {
0286 struct snd_soc_card *card = &snd_soc_spitz;
0287 int ret;
0288
0289 gpiod_mic = devm_gpiod_get(&pdev->dev, "mic", GPIOD_OUT_LOW);
0290 if (IS_ERR(gpiod_mic))
0291 return PTR_ERR(gpiod_mic);
0292 gpiod_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_LOW);
0293 if (IS_ERR(gpiod_mute_l))
0294 return PTR_ERR(gpiod_mute_l);
0295 gpiod_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_LOW);
0296 if (IS_ERR(gpiod_mute_r))
0297 return PTR_ERR(gpiod_mute_r);
0298
0299 card->dev = &pdev->dev;
0300
0301 ret = devm_snd_soc_register_card(&pdev->dev, card);
0302 if (ret)
0303 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
0304 ret);
0305
0306 return ret;
0307 }
0308
0309 static int spitz_remove(struct platform_device *pdev)
0310 {
0311 return 0;
0312 }
0313
0314 static struct platform_driver spitz_driver = {
0315 .driver = {
0316 .name = "spitz-audio",
0317 .pm = &snd_soc_pm_ops,
0318 },
0319 .probe = spitz_probe,
0320 .remove = spitz_remove,
0321 };
0322
0323 module_platform_driver(spitz_driver);
0324
0325 MODULE_AUTHOR("Richard Purdie");
0326 MODULE_DESCRIPTION("ALSA SoC Spitz");
0327 MODULE_LICENSE("GPL");
0328 MODULE_ALIAS("platform:spitz-audio");