diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/mxc_hdmi.c | 99 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 4 | ||||
-rw-r--r-- | sound/soc/imx/Kconfig | 2 | ||||
-rw-r--r-- | sound/soc/imx/imx-hdmi-dma.c | 13 | ||||
-rw-r--r-- | sound/soc/imx/imx-sgtl5000.c | 30 | ||||
-rw-r--r-- | sound/soc/imx/imx-wm8962.c | 100 | ||||
-rw-r--r-- | sound/usb/card.c | 75 |
7 files changed, 268 insertions, 55 deletions
diff --git a/sound/soc/codecs/mxc_hdmi.c b/sound/soc/codecs/mxc_hdmi.c index 9590181d4647..56dba0194871 100644 --- a/sound/soc/codecs/mxc_hdmi.c +++ b/sound/soc/codecs/mxc_hdmi.c @@ -503,6 +503,81 @@ static int mxc_hdmi_iec_put(struct snd_kcontrol *kcontrol, return 0; } +static int mxc_hdmi_channels_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_channels(); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = playback_constraint_channels.count; + + return 0; +} + +static int mxc_hdmi_channels_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uvalue) +{ + int i; + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_channels(); + + for (i = 0 ; i < playback_constraint_channels.count ; i++) + uvalue->value.integer.value[i] = playback_channels[i]; + + return 0; +} + +static int mxc_hdmi_rates_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_rates(); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = playback_constraint_rates.count; + + return 0; +} + +static int mxc_hdmi_rates_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uvalue) +{ + int i; + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_rates(); + + for (i = 0 ; i < playback_constraint_rates.count ; i++) + uvalue->value.integer.value[i] = playback_rates[i]; + + return 0; +} + +static int mxc_hdmi_formats_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_sample_size(); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = playback_constraint_bits.count; + + return 0; +} + +static int mxc_hdmi_formats_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uvalue) +{ + int i; + hdmi_get_edid_cfg(&edid_cfg); + mxc_hdmi_get_playback_sample_size(); + + for (i = 0 ; i < playback_constraint_bits.count ; i++) + uvalue->value.integer.value[i] = playback_sample_size[i]; + + return 0; +} + static struct snd_kcontrol_new mxc_hdmi_ctrls[] = { /* status cchanel controller */ { @@ -514,6 +589,30 @@ static struct snd_kcontrol_new mxc_hdmi_ctrls[] = { .get = mxc_hdmi_iec_get, .put = mxc_hdmi_iec_put, }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDMI Support Channels", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = mxc_hdmi_channels_info, + .get = mxc_hdmi_channels_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDMI Support Rates", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = mxc_hdmi_rates_info, + .get = mxc_hdmi_rates_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDMI Support Formats", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = mxc_hdmi_formats_info, + .get = mxc_hdmi_formats_get, + }, }; static struct snd_soc_dai_ops mxc_hdmi_codec_dai_ops = { diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 171c1c720d7c..54099fdb413b 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2425,6 +2425,8 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) struct wm8994 *control = codec->control_data; int i, ret; + pm_runtime_disable(codec->dev); + switch (control->type) { case WM8994: snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); @@ -2504,6 +2506,8 @@ static int wm8994_resume(struct snd_soc_codec *codec) break; } + pm_runtime_enable(codec->dev); + return 0; } #else diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index e30ebbe7e131..9b01af01a45d 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -52,7 +52,7 @@ config SND_SOC_PHYCORE_AC97 config SND_SOC_IMX_SGTL5000 tristate "SoC Audio support for i.MX boards with sgtl5000" - depends on I2C && (MACH_MX35_3DS || MACH_MX51_BABBAGE \ + depends on I2C && (MACH_MX35_3DS || MACH_MX51_BABBAGE || MACH_MX53_SMD \ || MACH_MX6Q_SABRELITE || MACH_MX6Q_ARM2) select SND_SOC_SGTL5000 select SND_MXC_SOC_MX2 diff --git a/sound/soc/imx/imx-hdmi-dma.c b/sound/soc/imx/imx-hdmi-dma.c index 84b350386328..c845672be6aa 100644 --- a/sound/soc/imx/imx-hdmi-dma.c +++ b/sound/soc/imx/imx-hdmi-dma.c @@ -578,6 +578,7 @@ static void hdmi_dma_mmap_copy(struct snd_pcm_substream *substream, } } +#ifdef CONFIG_ARCH_MX6 static void hdmi_sdma_isr(void *data) { struct imx_hdmi_dma_runtime_data *rtd = data; @@ -611,7 +612,7 @@ static void hdmi_sdma_isr(void *data) return; } - +#endif static irqreturn_t hdmi_dma_isr(int irq, void *dev_id) { @@ -876,6 +877,7 @@ static int hdmi_dma_copy(struct snd_pcm_substream *substream, int channel, return 0; } +#ifdef CONFIG_ARCH_MX6 static bool hdmi_filter(struct dma_chan *chan, void *param) { @@ -971,8 +973,7 @@ static int hdmi_sdma_config(struct imx_hdmi_dma_runtime_data *params) return 0; } - - +#endif static int hdmi_dma_hw_free(struct snd_pcm_substream *substream) { @@ -990,7 +991,9 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct imx_hdmi_dma_runtime_data *rtd = runtime->private_data; +#ifdef CONFIG_ARCH_MX6 int err; +#endif rtd->buffer_bytes = params_buffer_bytes(params); rtd->periods = params_periods(params); @@ -1021,6 +1024,7 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream, } rtd->dma_period_bytes = rtd->period_bytes * rtd->buffer_ratio; +#ifdef CONFIG_ARCH_MX6 if (hdmi_SDMA_check()) { rtd->sdma_params.buffer_num = rtd->periods; rtd->sdma_params.phyaddr = rtd->phy_hdmi_sdma_t; @@ -1038,6 +1042,7 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream, if (err) return err; } +#endif snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); @@ -1067,8 +1072,6 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!check_hdmi_state()) - return 0; rtd->frame_idx = 0; if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { appl_bytes = frames_to_bytes(runtime, diff --git a/sound/soc/imx/imx-sgtl5000.c b/sound/soc/imx/imx-sgtl5000.c index 9325dc8e346c..c73ab7ec19a4 100644 --- a/sound/soc/imx/imx-sgtl5000.c +++ b/sound/soc/imx/imx-sgtl5000.c @@ -3,7 +3,7 @@ * sgtl5000 codec * * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> - * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. * * 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 @@ -43,6 +43,11 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, }, + { + .pin = "Ext Spk", + .mask = SND_JACK_HEADPHONE, + .invert = 1, + }, }; /* Headphones jack detection gpios */ @@ -195,11 +200,29 @@ static int sgtl5000_set_line_in(struct snd_kcontrol *kcontrol, return 1; } +static int spk_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct imx_sgtl5000_priv *priv = &card_priv; + struct platform_device *pdev = priv->pdev; + struct mxc_audio_platform_data *plat = pdev->dev.platform_data; + + if (plat->amp_enable == NULL) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) + plat->amp_enable(1); + else + plat->amp_enable(0); + + return 0; +} + /* imx_3stack card dapm widgets */ static const struct snd_soc_dapm_widget imx_3stack_dapm_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_LINE("Line In Jack", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_SPK("Ext Spk", spk_amp_event), SND_SOC_DAPM_HP("Headphone Jack", NULL), }; @@ -246,7 +269,8 @@ static int imx_3stack_sgtl5000_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); snd_soc_dapm_disable_pin(&codec->dapm, "Line In Jack"); - snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); snd_soc_dapm_sync(&codec->dapm); if (hs_jack_gpios[0].gpio != -1) { diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c index d6ab88d7d261..fed3a7f1e07d 100644 --- a/sound/soc/imx/imx-wm8962.c +++ b/sound/soc/imx/imx-wm8962.c @@ -27,6 +27,7 @@ #include <linux/fsl_devices.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/switch.h> #include <linux/kthread.h> #include <sound/core.h> #include <sound/pcm.h> @@ -53,6 +54,7 @@ struct imx_priv { int amic_irq; int amic_status; struct platform_device *pdev; + struct switch_dev sdev; struct snd_pcm_substream *first_stream; struct snd_pcm_substream *second_stream; }; @@ -64,7 +66,7 @@ static struct snd_soc_codec *gcodec; static struct snd_soc_jack imx_hp_jack; static struct snd_soc_jack_pin imx_hp_jack_pins[] = { { - .pin = "Ext Spk", + .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, }, }; @@ -317,50 +319,25 @@ static void imx_resume_event(struct work_struct *wor) return; } -static int imx_event_hp(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int hp_jack_status_check(void) { struct imx_priv *priv = &card_priv; struct platform_device *pdev = priv->pdev; struct mxc_audio_platform_data *plat = pdev->dev.platform_data; char *envp[3]; char *buf; + int ret = 0; if (plat->hp_gpio != -1) { priv->hp_status = gpio_get_value(plat->hp_gpio); - buf = kmalloc(32, GFP_ATOMIC); - if (!buf) { - pr_err("%s kmalloc failed\n", __func__); - return -ENOMEM; - } - + /* if headphone is inserted, disable speaker */ if (priv->hp_status != plat->hp_active_low) - snprintf(buf, 32, "STATE=%d", 2); + snd_soc_dapm_nc_pin(&gcodec->dapm, "Ext Spk"); else - snprintf(buf, 32, "STATE=%d", 0); - - envp[0] = "NAME=headphone"; - envp[1] = buf; - envp[2] = NULL; - kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp); - kfree(buf); - } - - return 0; -} - -static int imx_event_mic(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct imx_priv *priv = &card_priv; - struct platform_device *pdev = priv->pdev; - struct mxc_audio_platform_data *plat = pdev->dev.platform_data; - char *envp[3]; - char *buf; + snd_soc_dapm_enable_pin(&gcodec->dapm, "Ext Spk"); - if (plat->mic_gpio != -1) { - priv->amic_status = gpio_get_value(plat->mic_gpio); + snd_soc_dapm_sync(&gcodec->dapm); buf = kmalloc(32, GFP_ATOMIC); if (!buf) { @@ -368,32 +345,30 @@ static int imx_event_mic(struct snd_soc_dapm_widget *w, return -ENOMEM; } - if (priv->amic_status == 0) + if (priv->hp_status != plat->hp_active_low) { + switch_set_state(&priv->sdev, 2); snprintf(buf, 32, "STATE=%d", 2); - else + ret = imx_hp_jack_gpio.report; + } else { + switch_set_state(&priv->sdev, 0); snprintf(buf, 32, "STATE=%d", 0); - - envp[0] = "NAME=amic"; + } + envp[0] = "NAME=headphone"; envp[1] = buf; envp[2] = NULL; kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp); kfree(buf); } - return 0; + return ret; } - -static const struct snd_kcontrol_new controls[] = { - SOC_DAPM_PIN_SWITCH("Ext Spk"), -}; - /* imx card dapm widgets */ static const struct snd_soc_dapm_widget imx_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Ext Spk", imx_event_hp), + SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_MIC("AMIC", NULL), - SND_SOC_DAPM_MIC("DMIC", imx_event_mic), + SND_SOC_DAPM_MIC("DMIC", NULL), }; /* imx machine connections to the codec pins */ @@ -418,6 +393,9 @@ static ssize_t show_headphone(struct device_driver *dev, char *buf) struct platform_device *pdev = priv->pdev; struct mxc_audio_platform_data *plat = pdev->dev.platform_data; + if (plat->hp_gpio == -1) + return 0; + /* determine whether hp is plugged in */ priv->hp_status = gpio_get_value(plat->hp_gpio); @@ -484,12 +462,14 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd) /* Set up imx specific audio path audio_map */ snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); snd_soc_dapm_enable_pin(&codec->dapm, "AMIC"); if (plat->hp_gpio != -1) { imx_hp_jack_gpio.gpio = plat->hp_gpio; - snd_soc_jack_new(codec, "Ext Spk", SND_JACK_LINEOUT, + imx_hp_jack_gpio.jack_status_check = hp_jack_status_check; + + snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &imx_hp_jack); snd_soc_jack_add_pins(&imx_hp_jack, ARRAY_SIZE(imx_hp_jack_pins), @@ -503,6 +483,14 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd) ret = -EINVAL; return ret; } + + priv->hp_status = gpio_get_value(plat->hp_gpio); + + /* if headphone is inserted, disable speaker */ + if (priv->hp_status != plat->hp_active_low) + snd_soc_dapm_nc_pin(&codec->dapm, "Ext Spk"); + else + snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk"); } if (plat->mic_gpio != -1) { @@ -527,6 +515,8 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync(&codec->dapm); + return 0; } @@ -599,6 +589,20 @@ static int __devinit imx_wm8962_probe(struct platform_device *pdev) priv->sysclk = plat->sysclk; + priv->sdev.name = "h2w"; + ret = switch_dev_register(&priv->sdev); + if (ret < 0) { + ret = -EINVAL; + return ret; + } + + if (plat->hp_gpio != -1) { + priv->hp_status = gpio_get_value(plat->hp_gpio); + if (priv->hp_status != plat->hp_active_low) + switch_set_state(&priv->sdev, 2); + else + switch_set_state(&priv->sdev, 0); + } priv->first_stream = NULL; priv->second_stream = NULL; @@ -610,9 +614,13 @@ static int __devexit imx_wm8962_remove(struct platform_device *pdev) struct mxc_audio_platform_data *plat = pdev->dev.platform_data; struct imx_priv *priv = &card_priv; + plat->clock_enable(0); + if (plat->finit) plat->finit(); + switch_dev_unregister(&priv->sdev); + if (priv->hp_irq) free_irq(priv->hp_irq, priv); if (priv->amic_irq) diff --git a/sound/usb/card.c b/sound/usb/card.c index 57a8e2d0139f..1a112d3cf210 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -2,6 +2,7 @@ * (Tentative) USB Audio Driver for ALSA * * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * Copyright (C) 2012 Freescale Semiconductor, Inc. * * Many codes borrowed from audio.c by * Alan Cox (alan@lxorguk.ukuu.org.uk) @@ -47,6 +48,7 @@ #include <linux/mutex.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <linux/switch.h> #include <sound/control.h> #include <sound/core.h> @@ -111,6 +113,15 @@ MODULE_PARM_DESC(ignore_ctl_error, * the all interfaces on the same card as one sound device. */ +struct usb_audio_switch_data { + struct switch_dev sdev; + const char *name_on; + const char *name_off; + const char *state_on; + const char *state_off; +}; + +static struct usb_audio_switch_data *audio_switch_data[SNDRV_CARDS]; static DEFINE_MUTEX(register_mutex); static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; static struct usb_driver usb_audio_driver; @@ -589,16 +600,80 @@ static int usb_audio_probe(struct usb_interface *intf, const struct usb_device_id *id) { void *chip; + struct usb_audio_switch_data *switch_data; + int ret = 0; + struct snd_usb_audio *uchip; + int idx; + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + struct list_head *head; + int state = 0; + chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id); if (chip) { usb_set_intfdata(intf, chip); + uchip = chip; + switch_data = kzalloc(sizeof(struct usb_audio_switch_data), GFP_KERNEL); + if (!switch_data) + return -ENOMEM; + switch_data->sdev.name = "usb_audio"; + ret = switch_dev_register(&switch_data->sdev); + if (ret < 0) + goto err_switch_dev_register; + audio_switch_data[uchip->index] = switch_data; + + list_for_each(head, &uchip->pcm_list) { + as = list_entry(head, struct snd_usb_stream, list); + for (idx = 0; idx < 2; idx++) { + subs = &as->substream[idx]; + if (!subs->num_formats) + continue; + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) + state |= 0x1; + if (subs->direction == SNDRV_PCM_STREAM_CAPTURE) + state |= 0x2; + } + } + switch_set_state(&switch_data->sdev, state); return 0; } else return -EIO; + + +err_switch_dev_register: + kfree(switch_data); + return 0; } static void usb_audio_disconnect(struct usb_interface *intf) { + struct snd_usb_audio *uchip = usb_get_intfdata(intf); + struct usb_audio_switch_data *switch_data; + int idx; + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + struct list_head *head; + + if (uchip == (void *)-1L) + return; + + if (uchip) { + switch_data = audio_switch_data[uchip->index]; + if (switch_data) { + switch_set_state(&switch_data->sdev, 0); + switch_dev_unregister(&switch_data->sdev); + kfree(switch_data); + } + list_for_each(head, &uchip->pcm_list) { + as = list_entry(head, struct snd_usb_stream, list); + for (idx = 0; idx < 2; idx++) { + subs = &as->substream[idx]; + if (subs->running) + snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_DISCONNECTED); + } + } + } + snd_usb_audio_disconnect(interface_to_usbdev(intf), usb_get_intfdata(intf)); } |