2 * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
4 * Copyright (C) 2010 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com>
6 * Author: Harsha Priya <priya.harsha@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
27 #include <linux/init.h>
28 #include <linux/device.h>
29 #include <linux/slab.h>
31 #include <linux/module.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/soc.h>
35 #include <sound/jack.h>
36 #include "../codecs/sn95031.h"
41 #define MFLD_JACK_INSERT 0x04
43 enum soc_mic_bias_zones {
45 /* mic bias volutage range for Headphones*/
47 /* mic bias volutage range for American Headset*/
49 /* mic bias volutage range for Headset*/
54 static unsigned int hs_switch;
55 static unsigned int lo_dac;
57 struct mfld_mc_private {
58 void __iomem *int_base;
62 struct snd_soc_jack mfld_jack;
64 /*Headset jack detection DAPM pins */
65 static struct snd_soc_jack_pin mfld_jack_pins[] = {
68 .mask = SND_JACK_HEADPHONE,
72 .mask = SND_JACK_MICROPHONE,
76 /* jack detection voltage zones */
77 static struct snd_soc_jack_zone mfld_zones[] = {
78 {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
79 {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
82 /* sound card controls */
83 static const char *headset_switch_text[] = {"Earpiece", "Headset"};
85 static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
87 static const struct soc_enum headset_enum =
88 SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
90 static const struct soc_enum lo_enum =
91 SOC_ENUM_SINGLE_EXT(4, lo_text);
93 static int headset_get_switch(struct snd_kcontrol *kcontrol,
94 struct snd_ctl_elem_value *ucontrol)
96 ucontrol->value.integer.value[0] = hs_switch;
100 static int headset_set_switch(struct snd_kcontrol *kcontrol,
101 struct snd_ctl_elem_value *ucontrol)
103 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
104 struct snd_soc_dapm_context *dapm = &codec->dapm;
106 if (ucontrol->value.integer.value[0] == hs_switch)
109 snd_soc_dapm_mutex_lock(dapm);
111 if (ucontrol->value.integer.value[0]) {
112 pr_debug("hs_set HS path\n");
113 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
114 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
116 pr_debug("hs_set EP path\n");
117 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
118 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
121 snd_soc_dapm_sync_unlocked(dapm);
123 snd_soc_dapm_mutex_unlock(dapm);
125 hs_switch = ucontrol->value.integer.value[0];
130 static void lo_enable_out_pins(struct snd_soc_codec *codec)
132 struct snd_soc_dapm_context *dapm = &codec->dapm;
134 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
135 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
136 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
137 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
138 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
139 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
141 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
142 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
144 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
145 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
149 static int lo_get_switch(struct snd_kcontrol *kcontrol,
150 struct snd_ctl_elem_value *ucontrol)
152 ucontrol->value.integer.value[0] = lo_dac;
156 static int lo_set_switch(struct snd_kcontrol *kcontrol,
157 struct snd_ctl_elem_value *ucontrol)
159 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
160 struct snd_soc_dapm_context *dapm = &codec->dapm;
162 if (ucontrol->value.integer.value[0] == lo_dac)
165 snd_soc_dapm_mutex_lock(dapm);
167 /* we dont want to work with last state of lineout so just enable all
168 * pins and then disable pins not required
170 lo_enable_out_pins(codec);
172 switch (ucontrol->value.integer.value[0]) {
174 pr_debug("set vibra path\n");
175 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
176 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
177 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
181 pr_debug("set hs path\n");
182 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
183 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
184 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
188 pr_debug("set spkr path\n");
189 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
190 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
191 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
195 pr_debug("set null path\n");
196 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
197 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
198 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
202 snd_soc_dapm_sync_unlocked(dapm);
204 snd_soc_dapm_mutex_unlock(dapm);
206 lo_dac = ucontrol->value.integer.value[0];
210 static const struct snd_kcontrol_new mfld_snd_controls[] = {
211 SOC_ENUM_EXT("Playback Switch", headset_enum,
212 headset_get_switch, headset_set_switch),
213 SOC_ENUM_EXT("Lineout Mux", lo_enum,
214 lo_get_switch, lo_set_switch),
217 static const struct snd_soc_dapm_widget mfld_widgets[] = {
218 SND_SOC_DAPM_HP("Headphones", NULL),
219 SND_SOC_DAPM_MIC("Mic", NULL),
222 static const struct snd_soc_dapm_route mfld_map[] = {
223 {"Headphones", NULL, "HPOUTR"},
224 {"Headphones", NULL, "HPOUTL"},
225 {"Mic", NULL, "AMIC1"},
228 static void mfld_jack_check(unsigned int intr_status)
230 struct mfld_jack_data jack_data;
232 jack_data.mfld_jack = &mfld_jack;
233 jack_data.intr_id = intr_status;
235 sn95031_jack_detection(&jack_data);
236 /* TODO: add american headset detection post gpiolib support */
239 static int mfld_init(struct snd_soc_pcm_runtime *runtime)
241 struct snd_soc_codec *codec = runtime->codec;
242 struct snd_soc_dapm_context *dapm = &codec->dapm;
245 /* Add jack sense widgets */
246 snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
249 snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
251 /* always connected */
252 snd_soc_dapm_enable_pin(dapm, "Headphones");
253 snd_soc_dapm_enable_pin(dapm, "Mic");
255 ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
256 ARRAY_SIZE(mfld_snd_controls));
258 pr_err("soc_add_controls failed %d", ret_val);
261 /* default is earpiece pin, userspace sets it explcitly */
262 snd_soc_dapm_disable_pin(dapm, "Headphones");
263 /* default is lineout NC, userspace sets it explcitly */
264 snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
265 snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
268 /* we dont use linein in this so set to NC */
269 snd_soc_dapm_disable_pin(dapm, "LINEINL");
270 snd_soc_dapm_disable_pin(dapm, "LINEINR");
272 /* Headset and button jack detection */
273 ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
274 SND_JACK_HEADSET | SND_JACK_BTN_0 |
275 SND_JACK_BTN_1, &mfld_jack);
277 pr_err("jack creation failed\n");
281 ret_val = snd_soc_jack_add_pins(&mfld_jack,
282 ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
284 pr_err("adding jack pins failed\n");
287 ret_val = snd_soc_jack_add_zones(&mfld_jack,
288 ARRAY_SIZE(mfld_zones), mfld_zones);
290 pr_err("adding jack zones failed\n");
294 /* we want to check if anything is inserted at boot,
295 * so send a fake event to codec and it will read adc
296 * to find if anything is there or not */
297 mfld_jack_check(MFLD_JACK_INSERT);
301 static struct snd_soc_dai_link mfld_msic_dailink[] = {
303 .name = "Medfield Headset",
304 .stream_name = "Headset",
305 .cpu_dai_name = "Headset-cpu-dai",
306 .codec_dai_name = "SN95031 Headset",
307 .codec_name = "sn95031",
308 .platform_name = "sst-platform",
312 .name = "Medfield Speaker",
313 .stream_name = "Speaker",
314 .cpu_dai_name = "Speaker-cpu-dai",
315 .codec_dai_name = "SN95031 Speaker",
316 .codec_name = "sn95031",
317 .platform_name = "sst-platform",
321 .name = "Medfield Vibra",
322 .stream_name = "Vibra1",
323 .cpu_dai_name = "Vibra1-cpu-dai",
324 .codec_dai_name = "SN95031 Vibra1",
325 .codec_name = "sn95031",
326 .platform_name = "sst-platform",
330 .name = "Medfield Haptics",
331 .stream_name = "Vibra2",
332 .cpu_dai_name = "Vibra2-cpu-dai",
333 .codec_dai_name = "SN95031 Vibra2",
334 .codec_name = "sn95031",
335 .platform_name = "sst-platform",
339 .name = "Medfield Compress",
340 .stream_name = "Speaker",
341 .cpu_dai_name = "Compress-cpu-dai",
342 .codec_dai_name = "SN95031 Speaker",
343 .codec_name = "sn95031",
344 .platform_name = "sst-platform",
350 static struct snd_soc_card snd_soc_card_mfld = {
351 .name = "medfield_audio",
352 .owner = THIS_MODULE,
353 .dai_link = mfld_msic_dailink,
354 .num_links = ARRAY_SIZE(mfld_msic_dailink),
357 static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
359 struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
361 memcpy_fromio(&mc_private->interrupt_status,
362 ((void *)(mc_private->int_base)),
364 return IRQ_WAKE_THREAD;
367 static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
369 struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
371 if (mfld_jack.codec == NULL)
373 mfld_jack_check(mc_drv_ctx->interrupt_status);
378 static int snd_mfld_mc_probe(struct platform_device *pdev)
380 int ret_val = 0, irq;
381 struct mfld_mc_private *mc_drv_ctx;
382 struct resource *irq_mem;
384 pr_debug("snd_mfld_mc_probe called\n");
386 /* retrive the irq number */
387 irq = platform_get_irq(pdev, 0);
389 /* audio interrupt base of SRAM location where
390 * interrupts are stored by System FW */
391 mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
393 pr_err("allocation failed\n");
397 irq_mem = platform_get_resource_byname(
398 pdev, IORESOURCE_MEM, "IRQ_BASE");
400 pr_err("no mem resource given\n");
403 mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
404 resource_size(irq_mem));
405 if (!mc_drv_ctx->int_base) {
406 pr_err("Mapping of cache failed\n");
409 /* register for interrupt */
410 ret_val = devm_request_threaded_irq(&pdev->dev, irq,
411 snd_mfld_jack_intr_handler,
412 snd_mfld_jack_detection,
413 IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
415 pr_err("cannot register IRQ\n");
418 /* register the soc card */
419 snd_soc_card_mfld.dev = &pdev->dev;
420 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
422 pr_debug("snd_soc_register_card failed %d\n", ret_val);
425 platform_set_drvdata(pdev, mc_drv_ctx);
426 pr_debug("successfully exited probe\n");
430 static struct platform_driver snd_mfld_mc_driver = {
432 .owner = THIS_MODULE,
433 .name = "msic_audio",
435 .probe = snd_mfld_mc_probe,
438 module_platform_driver(snd_mfld_mc_driver);
440 MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
441 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
442 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
443 MODULE_LICENSE("GPL v2");
444 MODULE_ALIAS("platform:msic-audio");